From b13c002c148a73271bfe6b672efd42012683aa5f Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 2 Aug 2021 10:27:33 +0200 Subject: [PATCH 01/38] control: add BUGFIX for loop termination in DrawGoldSplit --- Source/control.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/control.cpp b/Source/control.cpp index 0ea632df6..4ed5e0d3f 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -2618,6 +2618,7 @@ void DrawGoldSplit(int amount) PrintGameStr(388, 140, tempstr, COL_WHITE); } if (amount > 0) { + // BUGFIX: loop condition should be `tempstr[i] != 0`, not `i < tempstr[i]`. for (i = 0; i < tempstr[i]; i++) { BYTE c = fontframe[gbFontTransTbl[(BYTE)tempstr[i]]]; screen_x += fontkern[c] + 1; From 1b6196f39bb73be59e28c8adfe683db144a9e1ed Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sun, 4 Jul 2021 20:31:06 +0200 Subject: [PATCH 02/38] Correct missile ring offset Without this the --- Source/missiles.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 5ea577f3d..1f3c7a238 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -4470,8 +4470,8 @@ void mi_fire_ring(int i) lvl = currlevel; dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1; for (j = CrawlTable[b]; j > 0; j--, k += 2) { - tx = missile[i]._miVar1 + CrawlTable[k - 1]; - ty = missile[i]._miVar2 + CrawlTable[k]; + tx = missile[i]._miVar1 + CrawlTable[k]; + ty = missile[i]._miVar2 + CrawlTable[k + 1]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dObject[tx][ty] == 0) { @@ -4501,8 +4501,8 @@ void mi_light_ring(int i) lvl = currlevel; dmg = 16 * (random_(53, 10) + random_(53, 10) + lvl + 2) >> 1; for (j = CrawlTable[b]; j > 0; j--, k += 2) { - tx = missile[i]._miVar1 + CrawlTable[k - 1]; - ty = missile[i]._miVar2 + CrawlTable[k]; + tx = missile[i]._miVar1 + CrawlTable[k]; + ty = missile[i]._miVar2 + CrawlTable[k + 1]; if (tx > 0 && tx < MAXDUNX && ty > 0 && ty < MAXDUNY) { dp = dPiece[tx][ty]; if (!nSolidTable[dp] && dObject[tx][ty] == 0) { From dfcaf3a0325eef5e02953b4c4303d9f3e8e5cce4 Mon Sep 17 00:00:00 2001 From: qndel Date: Mon, 19 Apr 2021 14:45:20 +0200 Subject: [PATCH 03/38] code fix --- Source/objects.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/objects.cpp b/Source/objects.cpp index a7db2c640..440611ae2 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -2126,19 +2126,19 @@ void Obj_BCrossDamage(int i) SyncPlrKill(myplr, 0); } else { if (plr[myplr]._pClass == PC_WARRIOR) { - PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #ifndef SPAWN } else if (plr[myplr]._pClass == PC_ROGUE) { - PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_SORCERER) { - PlaySfxLoc(PS_MAGE68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_MAGE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #ifdef HELLFIRE } else if (plr[myplr]._pClass == PC_MONK) { - PlaySfxLoc(PS_MONK68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_MONK68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_BARD) { - PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? } else if (plr[myplr]._pClass == PC_BARBARIAN) { - PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py); // CODEFIX: isn't using PlaySfxLoc on myplr equal to just using PlaySFX? #endif #endif } @@ -3319,31 +3319,31 @@ void OperateSlainHero(int pnum, int i, DIABOOL sendmsg) if (plr[pnum]._pClass == PC_WARRIOR) { CreateMagicArmor(object[i]._ox, object[i]._oy, ITYPE_HARMOR, ICURS_BREAST_PLATE, FALSE, TRUE); #ifndef SPAWN - PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_ROGUE) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_BOW, ICURS_LONG_WAR_BOW, FALSE, TRUE); #ifndef SPAWN - PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_SORCERER) { CreateSpellBook(object[i]._ox, object[i]._oy, SPL_LIGHTNING, FALSE, TRUE); #ifndef SPAWN - PlaySfxLoc(PS_MAGE9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_MAGE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif #ifdef HELLFIRE } else if (plr[pnum]._pClass == PC_MONK) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_STAFF, ICURS_WAR_STAFF, FALSE, TRUE); - PlaySfxLoc(PS_MONK9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_MONK9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #ifndef SPAWN } else if (plr[pnum]._pClass == PC_BARD) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_SWORD, ICURS_BASTARD_SWORD, FALSE, TRUE); - PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif } else if (plr[pnum]._pClass == PC_BARBARIAN) { CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_AXE, ICURS_BATTLE_AXE, FALSE, TRUE); #ifndef SPAWN - PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); + PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py); // CODEFIX: use pnum instead of myplr or use PlaySFX #endif #endif } From b2e94e2d8a15f239e7be9b221e4aa83c07eb46d0 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 4 Aug 2021 09:28:36 +0200 Subject: [PATCH 04/38] towners: add BUGFIX for Griswold custom towner order animation Issue located by Andi and Anders if my memory serves me right. --- Source/towners.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/towners.cpp b/Source/towners.cpp index f0ec4dcfe..db95cf111 100644 --- a/Source/towners.cpp +++ b/Source/towners.cpp @@ -39,6 +39,7 @@ const int snSFX[3][NUM_CLASSES] = { /* data */ /** Specifies the animation frame sequence of a given NPC. */ char AnimOrder[6][148] = { + // BUGFIX: was `15, 5, 1`, should be `15, 16, 1` in Griswold anim. { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, From 7263aa5f74e1555bf4492cdeaddc6125a54d4297 Mon Sep 17 00:00:00 2001 From: qndel Date: Tue, 29 Jun 2021 19:49:36 +0200 Subject: [PATCH 05/38] bugfix for loading/saving dLight --- Source/loadsave.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 105b0e7a9..28b0a16a8 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -253,7 +253,7 @@ void LoadGame(BOOL firstflag) } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) - dLight[i][j] = BLoad(); + dLight[i][j] = BLoad(); // BUGFIX: dLight got loaded already } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) @@ -505,7 +505,7 @@ void SaveGame() } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) - BSave(dLight[i][j]); + BSave(dLight[i][j]); // BUGFIX: dLight got saved already } for (j = 0; j < MAXDUNY; j++) { for (i = 0; i < MAXDUNX; i++) From 7d536834ce0c6a30bdf4afaa7ea413d2ac2777f0 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 2 Aug 2021 10:29:22 +0200 Subject: [PATCH 06/38] inv: add incorrect enum/off-by-one BUGFIX for UseInvItem --- Source/inv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/inv.cpp b/Source/inv.cpp index 340347ba4..07110af6c 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -2805,7 +2805,7 @@ BOOL UseInvItem(int pnum, int cii) return TRUE; if (stextflag != STORE_NONE) return TRUE; - if (cii <= INVITEM_HAND_RIGHT) + if (cii <= INVITEM_HAND_RIGHT) // BUGFIX: should be `cii < INVITEM_INV_FIRST`, was `cii <= INVITEM_HAND_RIGHT`. return FALSE; if (cii <= INVITEM_INV_LAST) { From 27df8f7aef1853df3e5d7f823af78f9f16974a54 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 2 Aug 2021 15:37:04 +0200 Subject: [PATCH 07/38] monsters: add BUGFIXes for ProcessMonsters, PosOkMonst, PosOkMonst2, PosOkMonst3 Incorrect firewall check and time of access bug related to monster enemy targets. --- Source/monster.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/monster.cpp b/Source/monster.cpp index 5e6c0faa4..f85d7ab7c 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -5566,6 +5566,7 @@ void ProcessMonsters() app_fatal("Illegal enemy monster %d for monster \"%s\"", _menemy, Monst->mName); #endif } + // BUGFIX: enemy target may be dead at time of access, thus reading garbage data from `monster[Monst->_menemy]._mfutx`. Monst->_lastx = monster[Monst->_menemy]._mfutx; Monst->_menemyx = Monst->_lastx; Monst->_lasty = monster[Monst->_menemy]._mfuty; @@ -6254,6 +6255,7 @@ BOOL PosOkMonst(int i, int x, int y) } if (ret && dMissile[x][y] != 0 && i >= 0) { + // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. mi = dMissile[x][y]; if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' @@ -6343,6 +6345,7 @@ BOOL PosOkMonst2(int i, int x, int y) if (ret && dMissile[x][y] != 0 && i >= 0) { mi = dMissile[x][y]; + // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; @@ -6409,6 +6412,7 @@ BOOL PosOkMonst3(int i, int x, int y) } if (ret && dMissile[x][y] != 0 && i >= 0) { mi = dMissile[x][y]; + // BUGFIX: case with multiple missiles being present on (x, y)-coordinate not handled. if (mi > 0) { if (missile[mi]._mitype == MIS_FIREWALL) { // BUGFIX: Change 'mi' to 'mi - 1' fire = TRUE; From 8f936de2c5486f9b15d12744072f45abe403fa0d Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 2 Aug 2021 10:34:13 +0200 Subject: [PATCH 08/38] missiles: add BUGFIXes for MI_LArrow, MI_Arrow, MI_Lightctrl and MI_Weapexp These bugs are related to time of access, where fields of e.g. a player or monster struct is accessed upon missile impact (instead of missile launch), and at this point, the monster may be dead, or the player may have left the game, resulting in accessing garbage data that may have been overwritten by other data (e.g. new monster spawn or new player joining). One way to resolve this issue is to store e.g. the damage in the missile struct when lanuching the missing. This way, the missile would have all information required to know its damage on imact instead of having to rely on outside sources that may no longer be present. --- Source/missiles.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 1f3c7a238..af8e43235 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -3735,6 +3735,7 @@ void MI_LArrow(int i) rst = missiledata[missile[i]._mitype].mResist; if (missile[i]._mitype == MIS_LARROW) { if (p != -1) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pILMinDam; maxd = plr[p]._pILMaxDam; } else { @@ -3746,6 +3747,7 @@ void MI_LArrow(int i) } if (missile[i]._mitype == MIS_FARROW) { if (p != -1) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIFMinDam; maxd = plr[p]._pIFMaxDam; } else { @@ -3764,9 +3766,11 @@ void MI_LArrow(int i) if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIMinDam; maxd = plr[p]._pIMaxDam; } else { + // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. mind = monster[p].mMinDamage; maxd = monster[p].mMaxDamage; } @@ -3818,9 +3822,11 @@ void MI_Arrow(int i) p = missile[i]._misource; if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[p]._pIMinDam; maxd = plr[p]._pIMaxDam; } else { + // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. mind = monster[p].mMinDamage; maxd = monster[p].mMaxDamage; } @@ -3852,9 +3858,11 @@ void MI_Firebolt(int i) if (missile[i]._micaster == TARGET_MONSTERS) { switch (missile[i]._mitype) { case MIS_FIREBOLT: + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. d = random_(75, 10) + (plr[p]._pMagic >> 3) + missile[i]._mispllvl + 1; break; case MIS_FLARE: + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. d = 3 * missile[i]._mispllvl - (plr[p]._pMagic >> 3) + (plr[p]._pMagic >> 1); break; case MIS_BONESPIRIT: @@ -3862,6 +3870,7 @@ void MI_Firebolt(int i) break; } } else { + // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. d = monster[p].mMinDamage + random_(77, monster[p].mMaxDamage - monster[p].mMinDamage + 1); } } else { @@ -4659,8 +4668,10 @@ void MI_Lightctrl(int i) p = missile[i]._misource; if (p != -1) { if (missile[i]._micaster == TARGET_MONSTERS) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. dam = (random_(79, 2) + random_(79, plr[p]._pLevel) + 2) << 6; } else { + // BUGFIX: damage of missile should be encoded in missile struct; monster can be dead before missile arrives. dam = 2 * (monster[p].mMinDamage + random_(80, monster[p].mMaxDamage - monster[p].mMinDamage + 1)); } } else { @@ -5128,10 +5139,12 @@ void MI_Weapexp(int i) missile[i]._mirange--; id = missile[i]._misource; if (missile[i]._miVar2 == 1) { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[id]._pIFMinDam; maxd = plr[id]._pIFMaxDam; missiledata[missile[i]._mitype].mResist = MISR_FIRE; } else { + // BUGFIX: damage of missile should be encoded in missile struct; player can be dead/have left the game before missile arrives. mind = plr[id]._pILMinDam; maxd = plr[id]._pILMaxDam; missiledata[missile[i]._mitype].mResist = MISR_LIGHTNING; From d68181fd91dc287e0f31108872b15bf7d99d0112 Mon Sep 17 00:00:00 2001 From: qndel Date: Wed, 4 Aug 2021 10:16:11 +0200 Subject: [PATCH 09/38] _pIEnAc bugfix --- Source/missiles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index af8e43235..12b49a631 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -683,7 +683,7 @@ BOOL MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, int t, BOOLE hper -= monster[m].mArmorClass; hper -= (dist * dist) >> 1; #ifdef HELLFIRE - hper -= plr[pnum]._pIEnAc; + hper -= plr[pnum]._pIEnAc; // BUGFIX: armor piercing DECREASES hit chance here, probably a 1.04 bug that got fixed in 1.09, go with += #endif #ifndef HELLFIRE hper += plr[pnum]._pIEnAc; From da7ea7b593e57cee9d80d2ee13717543a727a6ba Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 5 Aug 2021 01:45:40 +0200 Subject: [PATCH 10/38] items: add BUGFIX for PrintItemPower (#2241) --- Source/items.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/items.cpp b/Source/items.cpp index e4fb52c8a..503fef273 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -4020,7 +4020,7 @@ void PrintItemPower(char plidx, ItemStruct *x) #else if (x->_iSplLvlAdd == 2) strcpy(tempstr, "spells are increased 2 levels"); - if (x->_iSplLvlAdd < 1) + if (x->_iSplLvlAdd < 1) // BUGFIX: should be `x->_iSplLvlAdd == -1`, not `x->_iSplLvlAdd < 1`. #endif strcpy(tempstr, "spells are decreased 1 level"); #ifdef HELLFIRE From 7bcea607bca8a1a007a9be547ed1a67711e81f51 Mon Sep 17 00:00:00 2001 From: qndel Date: Wed, 18 Aug 2021 21:27:20 +0200 Subject: [PATCH 11/38] golem bugfix --- Source/msg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/msg.cpp b/Source/msg.cpp index d73e2909e..461d134e3 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -2056,7 +2056,7 @@ static DWORD On_KILLGOLEM(TCmd *pCmd, int pnum) else if (pnum != myplr) { if (currlevel == p->wParam1) M_SyncStartKill(pnum, p->x, p->y, pnum); - delta_kill_monster(pnum, p->x, p->y, plr[pnum].plrlevel); + delta_kill_monster(pnum, p->x, p->y, plr[pnum].plrlevel); // BUGFIX: should be p->wParam1, plrlevel will be incorrect if golem is killed because player changed levels } return sizeof(*p); From 1c9256d5d5026537dafc7e3690d49079dd8f2772 Mon Sep 17 00:00:00 2001 From: qndel Date: Sat, 21 Aug 2021 10:04:37 +0200 Subject: [PATCH 12/38] rename SetDead (#2249) * rename SetDead * rename in comparer --- Source/dead.cpp | 2 +- Source/dead.h | 2 +- Source/loadsave.cpp | 2 +- comparer-config/diablo.toml | 2 +- comparer-config/hellfire.toml | 2 +- comparer-config/spawn.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/dead.cpp b/Source/dead.cpp index f01e326dd..303fde2b4 100644 --- a/Source/dead.cpp +++ b/Source/dead.cpp @@ -74,7 +74,7 @@ void AddDead(int dx, int dy, char dv, int ddir) dDead[dx][dy] = (dv & 0x1F) + (ddir << 5); } -void SetDead() +void SyncUniqDead() { int i, mi; int dx, dy; diff --git a/Source/dead.h b/Source/dead.h index e8e55144e..aad513b2f 100644 --- a/Source/dead.h +++ b/Source/dead.h @@ -11,6 +11,6 @@ extern int stonendx; void InitDead(); void AddDead(int dx, int dy, char dv, int ddir); -void SetDead(); +void SyncUniqDead(); #endif /* __DEAD_H__ */ diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 28b0a16a8..788045624 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -646,7 +646,7 @@ void LoadLevel() for (i = 0; i < MAXDUNX; i++) dDead[i][j] = BLoad(); } - SetDead(); + SyncUniqDead(); } nummonsters = WLoad(); diff --git a/comparer-config/diablo.toml b/comparer-config/diablo.toml index e94444af4..3f9ad26b7 100644 --- a/comparer-config/diablo.toml +++ b/comparer-config/diablo.toml @@ -618,7 +618,7 @@ addr = 0x40865C size = 0x21 [[func]] -name = "SetDead" +name = "SyncUniqDead" addr = 0x40867D size = 0x77 diff --git a/comparer-config/hellfire.toml b/comparer-config/hellfire.toml index 42837cac0..f06807c3d 100644 --- a/comparer-config/hellfire.toml +++ b/comparer-config/hellfire.toml @@ -608,7 +608,7 @@ addr = 0x408D88 size = 0x21 [[func]] -name = "SetDead" +name = "SyncUniqDead" addr = 0x408DA9 size = 0x84 diff --git a/comparer-config/spawn.toml b/comparer-config/spawn.toml index a2e7fbe43..6dcd36825 100644 --- a/comparer-config/spawn.toml +++ b/comparer-config/spawn.toml @@ -618,7 +618,7 @@ addr = 0x408622 size = 0x21 [[func]] -name = "SetDead" +name = "SyncUniqDead" addr = 0x408643 size = 0x77 From d76d58bcc2a263a5edddd4c8842c3f69a3d60fee Mon Sep 17 00:00:00 2001 From: qndel Date: Sat, 21 Aug 2021 12:10:23 +0200 Subject: [PATCH 13/38] fix wrong cleanup of farmer value (#2250) --- Source/towners.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/towners.cpp b/Source/towners.cpp index db95cf111..07f87c5d9 100644 --- a/Source/towners.cpp +++ b/Source/towners.cpp @@ -1275,7 +1275,7 @@ else if (towner[t]._ttype == TOWN_FARMER) case 3: qt = TEXT_FARMER4; SpawnRewardItem(IDI_AURIC, towner[t]._tx + 1, towner[t]._ty); - quests[Q_FARMER]._qactive = QUEST_INIT; + quests[Q_FARMER]._qactive = 10; quests[Q_FARMER]._qlog = FALSE; t2 = 1; break; From 0c50c87cf554b008e5d25d20809dd4a69c5d735c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 24 Aug 2021 12:48:27 +0200 Subject: [PATCH 14/38] items: add BUGFIX, item get records not reset when resetting items The item get record array tracks items being recently looted in an effort to prevent the same item from being looted more than once. Prior to this commit, the item get record array (and corresponding item get record array length) variables were not cleared when creating a new game. Therefore, the item get record array of a previous game could remain in between games and prevent an item from being looted (if it was looted in a previous), even if it was never looted in the current game. In practice this almost never shows up, since each item get record is valid for a total of 6 seconds before being cleared. So, you would either have to save a game, quickly loot an item, when load the game and try to loot the same item before 6 seconds pass. OR, you could use the demo replay functionality to run test cases, and speed up execution to run e.g. 10'000'000 logic ticks per second. Both would exhibit the bug and prevent the item from being looted. ref: diasurgical/devilutionX#2691 --- Source/items.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/items.cpp b/Source/items.cpp index 503fef273..002bbacae 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -669,6 +669,8 @@ void InitItems() } uitemflag = FALSE; + + // BUGFIX: item get records not reset when resetting items. } void CalcPlrItemVals(int p, BOOL Loadgfx) From 56fefc89e9c961dbcbfe4231ae7362bd370d23b9 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 25 Aug 2021 23:01:59 +0200 Subject: [PATCH 15/38] objects: add BUGFIX for holy shrine If the random number generator ends up giving X-Y coordinate pairs that always are on bad tiles (e.g. solid, with object or with monster) then after a total of MAXDUNX * MAXDUNY tries, it will still cast phasing to teleport to the bad tile. --- Source/objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/objects.cpp b/Source/objects.cpp index 440611ae2..f16fd46ae 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -3919,6 +3919,7 @@ void OperateShrine(int pnum, int i, int sType) yy = random_(159, MAXDUNY); lv = dPiece[xx][yy]; j++; + // BUGFIX: should not cast phasing if still on bad tile after max amount of tries. if (j > MAXDUNX * MAXDUNY) break; } while (nSolidTable[lv] || dObject[xx][yy] != 0 || dMonster[xx][yy] != 0); From 045cb90dbf74fccd762134c68ee09fa61f37fa30 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 31 Aug 2021 14:06:06 +0200 Subject: [PATCH 16/38] items: add BUGFIX for GetItemRecord when handling quest items When spawing quest items (e.g. blood stone), no unique seed is set for the item. Therefor two quest items may share the same seed, this happens deterministically for the Valor quest, since three blood stones are spawned, each with item seed 0x00000000. For this reason, if two or more such quest items with identical seed are looted within less than 6 seconds, the 2nd, 3rd, etc loot actions are ignored. --- Source/items.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/items.cpp b/Source/items.cpp index 002bbacae..314b3fb25 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -5998,6 +5998,7 @@ BOOL GetItemRecord(int nSeed, WORD wCI, int nIndex) for (i = 0; i < gnNumGetRecords; i++) { if (dwTicks - itemrecord[i].dwTimestamp > 6000) { + // BUGFIX: loot actions for multiple quest items with same seed (e.g. blood stone) performed within less then 6 seconds will be ignored. NextItemRecord(i); i--; } else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) { From 82133085fcb63b05c24d48038458063299ac0f60 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Wed, 4 Aug 2021 09:27:05 +0200 Subject: [PATCH 17/38] themes: add BUGFIX for Theme_Treasure --- Source/themes.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/themes.cpp b/Source/themes.cpp index ded3f1bf6..629979556 100644 --- a/Source/themes.cpp +++ b/Source/themes.cpp @@ -698,6 +698,13 @@ void Theme_Treasure(int t) CreateRndItem(xp, yp, FALSE, FALSE, TRUE); ItemNoFlippy(); } + // BUGFIX: the following code is likely not working as intended. + // + // `rv == 0` has no effect. + // + // `rv >= treasrnd[leveltype - 1] - 2` is not connected to either + // of the item creation branches above, thus the last (unrelated) + // item spawned/dropped on ground would be halved in value. if (rv == 0 || rv >= treasrnd[leveltype - 1] - 2) { i = ItemNoFlippy(); if (rv >= treasrnd[leveltype - 1] - 2 && leveltype != DTYPE_CATHEDRAL) { From 3626759011ec91cacca0c4e03a298f1f54cbc533 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 2 Aug 2021 10:28:33 +0200 Subject: [PATCH 18/38] gendung: update out-of-bounds BUGFIX comment of DRLG_WillThemeRoomFit --- Source/gendung.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/gendung.cpp b/Source/gendung.cpp index 1152fad31..277d5ff5f 100644 --- a/Source/gendung.cpp +++ b/Source/gendung.cpp @@ -798,7 +798,7 @@ BOOL DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, in xCount = 0; yCount = 0; - // BUGFIX: change '&&' to '||' + // BUGFIX: incorrect out-of-bounds check, should check that `dungeon[xx][y + ii]` is not out-of-bounds in loop. if (x > DMAXX - maxSize && y > DMAXY - maxSize) { return FALSE; } From 721460e3752ea8fe0731efc8aad0ffa490034900 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Thu, 29 Apr 2021 00:13:53 +0200 Subject: [PATCH 19/38] missiles: add BUGFIX for PutMissile Prior to this commit, if the player was standing on coodinate with x=0 or y=0, no missile would be created when casting a spell. This is due to an off-by-one when doing bounds-checking. --- Source/missiles.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 12b49a631..be6747cdd 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -462,6 +462,7 @@ void PutMissile(int i) x = missile[i]._mix; y = missile[i]._miy; + // BUGFIX: should be `x < 0 || y < 0`, was `x <= 0 || y <= 0`. if (x <= 0 || y <= 0 || x >= MAXDUNX || y >= MAXDUNY) missile[i]._miDelFlag = TRUE; if (!missile[i]._miDelFlag) { From 4c0a4317f0a81b5dbcaf9ded6d464907e3e749fe Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 16 Oct 2021 08:25:15 +0200 Subject: [PATCH 20/38] Document causing of Scavenger leader getting stuck (#2256) --- Source/monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/monster.cpp b/Source/monster.cpp index f85d7ab7c..7c3209ade 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -4451,7 +4451,7 @@ void MAI_Scav(int i) return; if (Monst->_mhitpoints < (Monst->_mmaxhp >> 1) && Monst->_mgoal != MGOAL_HEALING) { if (Monst->leaderflag != 0) { - monster[Monst->leader].packsize--; + monster[Monst->leader].packsize--; // BUGFIX Check Monst->leaderflag == 1, to not underflow packsize Monst->leaderflag = 0; } Monst->_mgoal = MGOAL_HEALING; From 5d2dad445645341ff142e46acd13b3abd6442149 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Wed, 20 Oct 2021 21:50:30 +0200 Subject: [PATCH 21/38] Remove TravisCI --- .travis.yml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 43cfbbbba..000000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: cpp - -os: - - osx - -osx_image: xcode11.3 - -notifications: - email: - on_failure: change # default: always - -addons: - homebrew: - packages: - - mingw-w64 -env: - - MAKE_BUILD=make - - MAKE_BUILD=debug - -script: - - if [ $MAKE_BUILD = make ]; then make; fi - - if [ $MAKE_BUILD = debug ]; then make debug; fi - -stages: - - test From 5c6b1693b43f0d36e9996e456f74f9bff9a59604 Mon Sep 17 00:00:00 2001 From: qndel Date: Sun, 24 Oct 2021 16:05:06 +0200 Subject: [PATCH 22/38] OOB bugfix --- Source/lighting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/lighting.cpp b/Source/lighting.cpp index 2a060c269..d7ea5d1bb 100644 --- a/Source/lighting.cpp +++ b/Source/lighting.cpp @@ -706,7 +706,7 @@ void DoVision(int nXPos, int nYPos, int nRadius, BOOL doautomap, BOOL visible) int nCrawlX, nCrawlY, nLineLen, nTrans; int j, k, v, x1adj, x2adj, y1adj, y2adj; - if (nXPos >= 0 && nXPos <= MAXDUNX && nYPos >= 0 && nYPos <= MAXDUNY) { + if (nXPos >= 0 && nXPos <= MAXDUNX && nYPos >= 0 && nYPos <= MAXDUNY) { // BUGFIX < MAXDUNX/MAXDUNY or OOB if (doautomap) { if (dFlags[nXPos][nYPos] >= 0) { SetAutomapView(nXPos, nXPos); // BUGFIX - second argument should be nYPos From 529c0e0ae62bf5100352a1469ec4d793ebb8be11 Mon Sep 17 00:00:00 2001 From: Avinal Kumar Date: Thu, 21 Oct 2021 14:30:50 +0530 Subject: [PATCH 23/38] Migrate macOS CI to GitHub Actions Signed-off-by: Avinal Kumar --- .github/workflows/build_mac.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/build_mac.yml diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml new file mode 100644 index 000000000..3c4e4841f --- /dev/null +++ b/.github/workflows/build_mac.yml @@ -0,0 +1,23 @@ +name: macOS Build + +on: + push: + branches: + - master + pull_request: + + +jobs: + xcode: + runs-on: macos-11 + + steps: + - uses: actions/checkout@v2 + + - name: Install dependencies + run: brew install mingw-w64 + + - name: Build + run: make -j8 + + \ No newline at end of file From de6154094d0bc24dcb20e5b8ab479336dd61544c Mon Sep 17 00:00:00 2001 From: qndel Date: Mon, 25 Oct 2021 18:09:02 +0200 Subject: [PATCH 24/38] fix class sounds --- Source/missiles.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index be6747cdd..a6a7a3f61 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -1090,21 +1090,21 @@ BOOL Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, B dam -= (dam * resper) / 100; if (pnum == myplr) NetSendCmdDamage(TRUE, p, dam); - if (plr[pnum]._pClass == PC_WARRIOR) { - PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); + if (plr[pnum]._pClass == PC_WARRIOR) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #ifndef SPAWN - } else if (plr[pnum]._pClass == PC_ROGUE) { - PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); - } else if (plr[pnum]._pClass == PC_SORCERER) { - PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py); + } else if (plr[pnum]._pClass == PC_ROGUE) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum + } else if (plr[pnum]._pClass == PC_SORCERER) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_MAGE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #endif #ifdef HELLFIRE - } else if (plr[pnum]._pClass == PC_MONK) { - PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py); - } else if (plr[pnum]._pClass == PC_BARD) { - PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py); - } else if (plr[pnum]._pClass == PC_BARBARIAN) { - PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py); + } else if (plr[pnum]._pClass == PC_MONK) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_MONK69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum + } else if (plr[pnum]._pClass == PC_BARD) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_ROGUE69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum + } else if (plr[pnum]._pClass == PC_BARBARIAN) {// BUGFIX: should use p instead of pnum + PlaySfxLoc(PS_WARR69, plr[pnum]._px, plr[pnum]._py);// BUGFIX: should use p instead of pnum #endif } return TRUE; From 0db71a197548648bf3575a641d59c11cf80ac7ca Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 15 Nov 2021 00:45:01 +0100 Subject: [PATCH 25/38] monster: add BUGFIX for MAI_Fallen, invalid out-of-bounds check The out-of-bounds check in MAI_Fallen checks whether the relative offset coordinates (x, y) are out of bounds, rather than the absoulte coordinate (xpos, ypos) which is used for array access into dMonster. --- Source/monster.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/monster.cpp b/Source/monster.cpp index 7c3209ade..d6b11f107 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -4206,6 +4206,7 @@ void MAI_Fallen(int i) for (x = -rad; x <= rad; x++) { xpos = Monst->_mx + x; ypos = Monst->_my + y; + // BUGFIX: should check `xpos` and `ypos` for out-of-bounds, was checking `x` and `y`. if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) { m = dMonster[xpos][ypos]; if (m > 0) { From 3df3a81f509c4b7346e1c9ac739b7037c2288266 Mon Sep 17 00:00:00 2001 From: qndel Date: Tue, 7 Sep 2021 16:07:25 +0200 Subject: [PATCH 26/38] golem addmonster bugfix --- Source/monster.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/monster.cpp b/Source/monster.cpp index d6b11f107..c9b174c59 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -1264,10 +1264,11 @@ void SetMapMonsters(BYTE *pMap, int startx, int starty) int mtype; AddMonsterType(MT_GOLEM, PLACE_SPECIAL); - AddMonster(1, 0, 0, 0, FALSE); - AddMonster(1, 0, 0, 0, FALSE); - AddMonster(1, 0, 0, 0, FALSE); - AddMonster(1, 0, 0, 0, FALSE); + // See https://github.com/diasurgical/devilutionX/pull/2822 + AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true + AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true + AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true + AddMonster(1, 0, 0, 0, FALSE); // BUGFIX: add only if setlevel is true if (setlevel && setlvlnum == SL_VILEBETRAYER) { AddMonsterType(UniqMonst[UMT_LAZURUS].mtype, PLACE_UNIQUE); AddMonsterType(UniqMonst[UMT_RED_VEX].mtype, PLACE_UNIQUE); From 3fd926d5442413e5945b77f4d3f7d6432f3a820f Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sat, 20 Nov 2021 19:34:25 +0100 Subject: [PATCH 27/38] BUGFIX: check for dObject OOB --- Source/items.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index 314b3fb25..052465fe6 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1588,14 +1588,14 @@ BOOL ItemSpaceOk(int i, int j) return FALSE; } - if (dObject[i + 1][j + 1] > 0 && object[dObject[i + 1][j + 1] - 1]._oSelFlag != 0) + if (dObject[i + 1][j + 1] > 0 && object[dObject[i + 1][j + 1] - 1]._oSelFlag != 0) /// BUGFIX: check for dObject OOB return FALSE; - if (dObject[i + 1][j + 1] < 0 && object[-(dObject[i + 1][j + 1] + 1)]._oSelFlag != 0) + if (dObject[i + 1][j + 1] < 0 && object[-(dObject[i + 1][j + 1] + 1)]._oSelFlag != 0) /// BUGFIX: check for dObject OOB return FALSE; - if (dObject[i + 1][j] > 0 - && dObject[i][j + 1] > 0 + if (dObject[i + 1][j] > 0 /// BUGFIX: check for dObject OOB + && dObject[i][j + 1] > 0 /// BUGFIX: check for dObject OOB && object[dObject[i + 1][j] - 1]._oSelFlag != 0 && object[dObject[i][j + 1] - 1]._oSelFlag != 0) { return FALSE; From a401471daf37144ec3be3a56c19314f8a844bcb6 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 18 Jan 2022 01:38:37 +0100 Subject: [PATCH 28/38] diablo: add BUGFIX for PressChar; out-of-bounds access to dungeon (#2266) * diablo: add BUGFIX for PressChar; out-of-bounds access to dungeon * diablo: update BUGFIX comment of PressChar, should be dPiece not dungeon Pointed out by @galaxyhaxz in https://github.com/diasurgical/devilution/pull/2266#discussion_r786302976 --- Source/diablo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 48780e7ad..62450c682 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1520,6 +1520,7 @@ static void PressChar(WPARAM vkey) if (debug_mode_key_inverted_v) { sprintf(tempstr, "PX = %i PY = %i", plr[myplr]._px, plr[myplr]._py); NetSendCmdString(1 << myplr, tempstr); + // BUGFIX: out-of-bounds access to dungeon; should be `dPiece[cursmx][cursmy]`, was `dungeon[cursmx][cursmy]`. sprintf(tempstr, "CX = %i CY = %i DP = %i", cursmx, cursmy, dungeon[cursmx][cursmy]); NetSendCmdString(1 << myplr, tempstr); } From a44cb36af6cb755c419e83fa4b3259e001849813 Mon Sep 17 00:00:00 2001 From: DakkJaniels <6080734+DakkJaniels@users.noreply.github.com> Date: Sun, 20 Feb 2022 16:06:47 -0500 Subject: [PATCH 29/38] Fix mlSFX miSFX labeling swapped labels to match structure definition --- Source/misdat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/misdat.cpp b/Source/misdat.cpp index c134652b5..4b0a3ddc4 100644 --- a/Source/misdat.cpp +++ b/Source/misdat.cpp @@ -8,7 +8,7 @@ /** Data related to each missile ID. */ MissileData missiledata[] = { // clang-format off - // mName, mAddProc, mProc, mDraw, mType, mResist, mFileNum, miSFX, mlSFX; + // mName, mAddProc, mProc, mDraw, mType, mResist, mFileNum, mlSFX, miSFX; { MIS_ARROW, &AddArrow, &MI_Arrow, TRUE, 0, MISR_NONE, MFILE_ARROWS, -1, -1 }, { MIS_FIREBOLT, &AddFirebolt, &MI_Firebolt, TRUE, 1, MISR_FIRE, MFILE_FIREBA, LS_FBOLT1, LS_FIRIMP2 }, { MIS_GUARDIAN, &AddGuardian, &MI_Guardian, TRUE, 1, MISR_NONE, MFILE_GUARD, LS_GUARD, LS_GUARDLAN }, From f074a33cc13a87f2cd3e05ca3844ab3f659589c1 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 24 Mar 2022 03:51:47 +0100 Subject: [PATCH 30/38] objects: add BUGFIX for AddShrine (#2272) --- Source/objects.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/objects.cpp b/Source/objects.cpp index f16fd46ae..ddebd604e 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -1438,6 +1438,12 @@ void AddShrine(int i) #else int j; #endif + + // BUGFIX: the seed of shrine objects (object[i]._oRndSeed) was never + // initialized. This lead to undefined behaviour, as the shrine object would + // use whatever value was present in memory (often the seed of an object with + // the same object index of a previous dungeon level). + object[i]._oPreFlag = TRUE; for (j = 0; j < NUM_SHRINETYPE; j++) { if (currlevel < shrinemin[j] || currlevel > shrinemax[j]) { From bc0488382a18317f6c2ac532579f301896928c07 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 9 May 2022 02:30:47 +0200 Subject: [PATCH 31/38] missiles: add BUGFIX for SetMissAnim A buffer overflow is triggered when casting Identify (or any other spell which has mFileNum set to 255). --- Source/missiles.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index a6a7a3f61..68e301216 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -1323,12 +1323,12 @@ void SetMissAnim(int mi, int animtype) int dir = missile[mi]._mimfnum; missile[mi]._miAnimType = animtype; - missile[mi]._miAnimFlags = misfiledata[animtype].mFlags; - missile[mi]._miAnimData = misfiledata[animtype].mAnimData[dir]; - missile[mi]._miAnimDelay = misfiledata[animtype].mAnimDelay[dir]; - missile[mi]._miAnimLen = misfiledata[animtype].mAnimLen[dir]; - missile[mi]._miAnimWidth = misfiledata[animtype].mAnimWidth[dir]; - missile[mi]._miAnimWidth2 = misfiledata[animtype].mAnimWidth2[dir]; + missile[mi]._miAnimFlags = misfiledata[animtype].mFlags; // BUGFIX: buffer overflow for MFILE_NONE (255). + missile[mi]._miAnimData = misfiledata[animtype].mAnimData[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). + missile[mi]._miAnimDelay = misfiledata[animtype].mAnimDelay[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). + missile[mi]._miAnimLen = misfiledata[animtype].mAnimLen[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). + missile[mi]._miAnimWidth = misfiledata[animtype].mAnimWidth[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). + missile[mi]._miAnimWidth2 = misfiledata[animtype].mAnimWidth2[dir]; // BUGFIX: buffer overflow for MFILE_NONE (255). missile[mi]._miAnimCnt = 0; missile[mi]._miAnimFrame = 1; } From ab9b61626f86c98b9ea0bf3165f142df1cc17686 Mon Sep 17 00:00:00 2001 From: qndel Date: Sat, 14 May 2022 02:39:40 +0200 Subject: [PATCH 32/38] add hellfire rune dmg calc (#2270) --- Source/missiles.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 68e301216..c33ce26c0 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -75,6 +75,9 @@ void GetDamageAmt(int i, int *mind, int *maxd) *mind = -1; *maxd = -1; break; +#ifdef HELLFIRE + case SPL_RUNELIGHT: +#endif case SPL_LIGHTNING: *mind = 2; *maxd = plr[myplr]._pLevel + 2; From b86b8fd7c4966385e3a7dbcb29e6d7e05bdab95e Mon Sep 17 00:00:00 2001 From: Robin Date: Sat, 14 May 2022 02:40:18 +0200 Subject: [PATCH 33/38] msg: add BUGFIX for delta_kill_monster (#2261) The monster direction is synced even if the receiving player is not on the same dungeon level as the player killing the monster. Note, this happens, even if one player is in town, and the other kills a monster at e.g. dlvl=1. Then the code will check the monster at index mi even for the player in town, so it will just read garbage data from memory. --- Source/msg.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/msg.cpp b/Source/msg.cpp index 461d134e3..331b97365 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -461,6 +461,7 @@ void delta_kill_monster(int mi, BYTE x, BYTE y, BYTE bLevel) DMonsterStr *pD = &sgLevels[bLevel].monster[mi]; pD->_mx = x; pD->_my = y; + // BUGFIX: should only sync monster direction if bLevel is same as currlevel. pD->_mdir = monster[mi]._mdir; pD->_mhitpoints = 0; } From f06427a1eb030645542156b4887a0d485afc0a99 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 4 Aug 2022 22:47:51 +0200 Subject: [PATCH 34/38] drlg_l1 bugfix notes (#2276) --- Source/drlg_l1.cpp | 6 ++++-- Source/drlg_l2.cpp | 2 +- Source/drlg_l3.cpp | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/drlg_l1.cpp b/Source/drlg_l1.cpp index 2792df67a..ae7c2973d 100644 --- a/Source/drlg_l1.cpp +++ b/Source/drlg_l1.cpp @@ -985,6 +985,7 @@ static int DRLG_PlaceMiniSet(const BYTE *miniset, int tmin, int tmax, int cx, in while (abort == FALSE) { abort = TRUE; + // BUGFIX: This code has no purpose but causes the set piece to never appear in x 0-13 or y 0-13 if (cx != -1 && sx >= cx - sw && sx <= cx + 12) { sx++; abort = FALSE; @@ -2020,13 +2021,14 @@ void drlg_l1_crypt_rndset(const BYTE *miniset, int rndper) if (miniset[ii] != 0 && dungeon[xx + sx][yy + sy] != miniset[ii]) { found = FALSE; } - if (dflags[xx + sx][yy + sy] != 0) { + if (dflags[xx + sx][yy + sy] != 0) { // BUGFIX: Should be L5dflags or it will always be false found = FALSE; } ii++; } } kk = sw * sh + 2; + // BUGFIX: This code is copied from Cave and should not be applied for crypt if (miniset[kk] >= 84 && miniset[kk] <= 100 && found == TRUE) { // BUGFIX: accesses to dungeon can go out of bounds // BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. @@ -2586,7 +2588,7 @@ static void DRLG_L5CornerFix() for (i = 1; i < DMAXX - 1; i++) { if (!(L5dflags[i][j] & DLRG_PROTECTED) && dungeon[i][j] == 17 && dungeon[i - 1][j] == 13 && dungeon[i][j - 1] == 1) { dungeon[i][j] = 16; - L5dflags[i][j - 1] &= DLRG_PROTECTED; + L5dflags[i][j - 1] &= DLRG_PROTECTED; // BUGFIX: Should be |= or it will clear all flags } if (dungeon[i][j] == 202 && dungeon[i + 1][j] == 13 && dungeon[i][j + 1] == 1) { dungeon[i][j] = 8; diff --git a/Source/drlg_l2.cpp b/Source/drlg_l2.cpp index 55a47643c..ed09046bf 100644 --- a/Source/drlg_l2.cpp +++ b/Source/drlg_l2.cpp @@ -1766,7 +1766,7 @@ static void DRLG_L2Subs() for (y = 0; y < DMAXY; y++) { for (x = 0; x < DMAXX; x++) { - if ((x < nSx1 || x > nSx2) && (y < nSy1 || y > nSy2) && random_(0, 4) == 0) { + if ((x < nSx1 || x > nSx2) && (y < nSy1 || y > nSy2) && random_(0, 4) == 0) { // BUGFIX: Should be (x < nSx1 || x > nSx2 || y < nSy1 || y >= nSy2) c = BTYPESL2[dungeon[x][y]]; if (c != 0) { rv = random_(0, 16); diff --git a/Source/drlg_l3.cpp b/Source/drlg_l3.cpp index c53dd10b9..f497d2ef0 100644 --- a/Source/drlg_l3.cpp +++ b/Source/drlg_l3.cpp @@ -1713,6 +1713,7 @@ static void DRLG_L3PlaceRndSet(const BYTE *miniset, int rndper) } } kk = sw * sh + 2; + // BUGFIX: This should not be applied to Nest levels if (miniset[kk] >= 84 && miniset[kk] <= 100 && found == TRUE) { // BUGFIX: accesses to dungeon can go out of bounds // BUGFIX: Comparisons vs 100 should use same tile as comparisons vs 84. From e60d490bc95f2e565de815d807c89131cd8118d8 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 4 Aug 2022 22:49:01 +0200 Subject: [PATCH 35/38] Document bug in DRLG_WillThemeRoomFit (#2277) --- Source/gendung.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/gendung.cpp b/Source/gendung.cpp index 277d5ff5f..77de0be90 100644 --- a/Source/gendung.cpp +++ b/Source/gendung.cpp @@ -813,7 +813,7 @@ BOOL DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, in if (xFlag) { for (xx = x; xx < x + maxSize; xx++) { if (dungeon[xx][y + ii] != floor) { - if (xx >= minSize) { + if (xx >= minSize) { // BUGFIX: This is comparing absolute to relative, should be `xx - x >= minSize` break; } xFlag = FALSE; @@ -829,7 +829,7 @@ BOOL DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, in if (yFlag) { for (yy = y; yy < y + maxSize; yy++) { if (dungeon[x + ii][yy] != floor) { - if (yy >= minSize) { + if (yy >= minSize) { // BUGFIX: This is comparing absolute to relative, should be `yy - y >= minSize` break; } yFlag = FALSE; From aa2ab57539750a8060f8e8ed6ce184f2a7206e8c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Sat, 6 Aug 2022 00:52:51 +0200 Subject: [PATCH 36/38] items: add BUGFIX for SpawnItem, uninitialized use of onlygood --- Source/items.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/items.cpp b/Source/items.cpp index 052465fe6..56082c580 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -2962,6 +2962,7 @@ void SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, BOOL onlygood, void SpawnItem(int m, int x, int y, BOOL sendmsg) { int ii, idx; + // BUGFIX: onlygood may be used uninitialized in call to SetupAllItems. BOOL onlygood; if (monster[m]._uniqtype || ((monster[m].MData->mTreasure & 0x8000) && gbMaxPlayers != 1)) { From fdaabc40c22b61728f911025fd73f9b2862925a5 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 26 Aug 2022 17:27:29 +0200 Subject: [PATCH 37/38] Update LICENSE (#2279) --- LICENSE | 24 ------------------------ LICENSE.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 +- 3 files changed, 55 insertions(+), 25 deletions(-) delete mode 100644 LICENSE create mode 100644 LICENSE.md diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cf1ab25da..000000000 --- a/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..73d9d02c9 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,54 @@ +# Sustainable Use License + +Version 1.0 + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below. + +## Limitations + +You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. +You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. +You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. +If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently. + +## No Liability + +As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim. + +## Definitions + +The “licensor” is the entity offering these terms. + +The “software” is the software the licensor makes available under these terms, including any portion of it. + +“You” refers to the individual or entity agreeing to these terms. + +“Your company” is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. + +“Your license” is the license granted to you for the software under these terms. + +“Use” means anything you do with the software requiring your license. + +“Trademark” means trademarks, service marks, and similar rights. diff --git a/README.md b/README.md index a89ad0de6..ac8799168 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ And a special thanks to all the support and people who work on this project to m [From the beginning until release](docs/CHANGELOG.md) # Legal -Devilution is released to the Public Domain. The documentation and function provided by Devilution may only be utilized with assets provided by ownership of Diablo. +Devilution is made publicly available and released under the Sustainable Use License (see [LICENCE](LICENCE.md)) The source code in this repository is for non-commerical use only. If you use the source code you may not charge others for access to it or any derivative work thereof. From 126f674388f94de6eb02188fd1809499f2925cd5 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 26 Aug 2022 18:23:29 +0200 Subject: [PATCH 38/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac8799168..68157301c 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ And a special thanks to all the support and people who work on this project to m [From the beginning until release](docs/CHANGELOG.md) # Legal -Devilution is made publicly available and released under the Sustainable Use License (see [LICENCE](LICENCE.md)) +Devilution is made publicly available and released under the Sustainable Use License (see [LICENSE](LICENSE.md)) The source code in this repository is for non-commerical use only. If you use the source code you may not charge others for access to it or any derivative work thereof.