The i/j/k/l variables obfuscate the fact that the distance
formula used for generating data in lightblock is using the x
offset with the y component of the tile coordinate and vice-versa.
Mixing x and y this way causes light to move horizontally within
a tile when the light source is moving vertically and vice-versa.
myplr and pnum are used without consistency, thus making a
sanity check for the spell level of the Guardian spell void.
If another connected peer interacts with the Ancient Tome
(then pnum!=myplr), and they have Guardian spell level < 15,
while the local player has Guardian spell level = 15; then
the sanity check is skipped, and the local player gets
Guardian spell level 16
The _pBaseToBlk field of the player struct is never set
if creating a New Game using an existing save (since CreatePlayer
is never invoked in this case).
An incorrect placement of unique monsters was used in set levels
when entering through Town Portal from Tristram (or entering from
a dungeon level with different dungeon type).
To reproduce, use a Town Portal to enter any set level containing unique
monsters (e.g. Skeleton King's Lair or Archbishop Lazarus' Lair).
As LoadGameLevel invokes InitMonsters without first invoking
FillSolidBlockTbls for set levels, the nSolidTable will contain
garbage data (the collision mapping for mini tiles of the _previous_
dungeon type, NOT the current dungeon type).
For consistency, use (mx, my) parameters in call to SetCursorPos.
As all callers of CheckInvCut pass (MouseX, MouseY) as arguments,
this BUGFIX is only for consistency, there is no functional
change.
The Elemental and Bone Spirit spells tries to locate the
closest monster at each logic tick, to update the
direction of the spell. This is done using the FindClosest
function, which returns the monster array index of the
closest monster; or -1 if no monster is located.
The callee of FindClosest checks if `mid > 0`, and as such
does not handle the monster array index 0 case. Since this
case is known to be the Golem of player 1, perhaps this is
intentional. If so, the FindClosest function should instead
be updated to find the closest monster that is NOT a Golem;
as the current code will simply fail to find other monsters
if there is a Golem of player 1 closer. It will also handle
Golems of other players differently than player 1
(regardless of PvP settings).
Scroll of Resurrect occurs twice in the item data list, firstly at
IDI_RESURRECT with IDROP_NEVER, and secondly a regular item with
IDROP_REGULAR.
Since the ri-- logic only checks for spell ID, ri will be decremented
also for IDROP_NEVER; thus unintentionally removing the previously added
valid item ID in Single Player (which is this case is always gold).
Therefore, the chance for gold drop is higher in Multi Player than
Single Player.
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.
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.
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.
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.
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.
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
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.