Browse Source

Fix double casting bug - use separated info for casted and queued spells

pull/5101/head
obligaron 4 years ago committed by Anders Jenbo
parent
commit
1cfd1ca99d
  1. 2
      Source/inv.cpp
  2. 2
      Source/inv.h
  3. 6
      Source/items.cpp
  4. 18
      Source/loadsave.cpp
  5. 46
      Source/msg.cpp
  6. 29
      Source/player.cpp
  7. 18
      Source/player.h
  8. 2
      Source/spells.cpp
  9. 4
      test/inv_test.cpp
  10. 6
      test/player_test.cpp
  11. 6
      test/writehero_test.cpp

2
Source/inv.cpp

@ -1914,7 +1914,7 @@ void UseStaffCharge(Player &player)
{
auto &staff = player.InvBody[INVLOC_HAND_LEFT];
if (!CanUseStaff(staff, player._pSpell))
if (!CanUseStaff(staff, player.executedSpell.spellId))
return;
staff._iCharges--;

2
Source/inv.h

@ -381,7 +381,7 @@ inline bool RemoveInventoryOrBeltItemById(Player &player, _item_indexes id)
*/
inline bool RemoveCurrentSpellScroll(Player &player)
{
const spell_id spellId = player._pSpell;
const spell_id spellId = player.executedSpell.spellId;
return RemoveInventoryOrBeltItem(player, [spellId](const Item &item) {
return item.isScrollOf(spellId);
});

6
Source/items.cpp

@ -3911,9 +3911,9 @@ void UseItem(int pnum, item_misc_id mid, spell_id spl)
NewCursor(CURSOR_TELEPORT);
} else {
ClrPlrPath(player);
player._pSpell = spl;
player._pSplType = RSPLTYPE_INVALID;
player._pSplFrom = 3;
player.queuedSpell.spellId = spl;
player.queuedSpell.spellType = RSPLTYPE_INVALID;
player.queuedSpell.spellFrom = 3;
player.destAction = ACTION_SPELL;
player.destParam1 = cursPosition.x;
player.destParam2 = cursPosition.y;

18
Source/loadsave.cpp

@ -359,9 +359,9 @@ void LoadPlayer(LoadHelper &file, Player &player)
player._plid = file.NextLE<int32_t>();
player._pvid = file.NextLE<int32_t>();
player._pSpell = static_cast<spell_id>(file.NextLE<int32_t>());
player._pSplType = static_cast<spell_type>(file.NextLE<int8_t>());
player._pSplFrom = file.NextLE<int8_t>();
player.queuedSpell.spellId = static_cast<spell_id>(file.NextLE<int32_t>());
player.queuedSpell.spellType = static_cast<spell_type>(file.NextLE<int8_t>());
player.queuedSpell.spellFrom = file.NextLE<int8_t>();
file.Skip(2); // Alignment
player._pTSpell = static_cast<spell_id>(file.NextLE<int32_t>());
file.Skip<int8_t>(); // Skip _pTSplType
@ -444,7 +444,7 @@ void LoadPlayer(LoadHelper &file, Player &player)
player.position.temp.y = static_cast<WorldTileCoord>(tempPositionY);
player.tempDirection = static_cast<Direction>(file.NextLE<int32_t>());
player.spellLevel = file.NextLE<int32_t>();
player.queuedSpell.spellLevel = file.NextLE<int32_t>();
file.Skip<uint32_t>(); // skip _pVar5, was used for storing position of a tile which should have its HorizontalMovingPlayer flag removed after walking
player.position.offset2.deltaX = file.NextLE<int32_t>();
player.position.offset2.deltaY = file.NextLE<int32_t>();
@ -550,6 +550,8 @@ void LoadPlayer(LoadHelper &file, Player &player)
file.Skip(20); // Available bytes
CalcPlrItemVals(player, false);
player.executedSpell = player.queuedSpell; // Ensures backwards compatibility
// Omit pointer _pNData
// Omit pointer _pWData
// Omit pointer _pAData
@ -1128,9 +1130,9 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(player._plid);
file.WriteLE<int32_t>(player._pvid);
file.WriteLE<int32_t>(player._pSpell);
file.WriteLE<int8_t>(player._pSplType);
file.WriteLE<int8_t>(player._pSplFrom);
file.WriteLE<int32_t>(player.queuedSpell.spellId);
file.WriteLE<int8_t>(player.queuedSpell.spellType);
file.WriteLE<int8_t>(player.queuedSpell.spellFrom);
file.Skip(2); // Alignment
file.WriteLE<int32_t>(player._pTSpell);
file.Skip<int8_t>(); // Skip _pTSplType
@ -1214,7 +1216,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(tempPositionY);
file.WriteLE<int32_t>(static_cast<int32_t>(player.tempDirection));
file.WriteLE<int32_t>(player.spellLevel);
file.WriteLE<int32_t>(player.queuedSpell.spellLevel);
file.Skip<int32_t>(); // skip _pVar5, was used for storing position of a tile which should have its HorizontalMovingPlayer flag removed after walking
file.WriteLE<int32_t>(player.position.offset2.deltaX);
file.WriteLE<int32_t>(player.position.offset2.deltaY);

46
Source/msg.cpp

@ -1141,9 +1141,9 @@ size_t OnSpellWall(const TCmd *pCmd, Player &player)
player.destParam2 = position.y;
player.destParam3 = message.wParam3;
player.destParam4 = message.wParam4;
player._pSpell = spell;
player._pSplType = static_cast<spell_type>(message.wParam2);
player._pSplFrom = 0;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = static_cast<spell_type>(message.wParam2);
player.queuedSpell.spellFrom = 0;
return sizeof(message);
}
@ -1179,8 +1179,8 @@ size_t OnSpellTile(const TCmd *pCmd, Player &player)
player.destParam1 = position.x;
player.destParam2 = position.y;
player.destParam3 = message.wParam3;
player._pSpell = spell;
player._pSplType = static_cast<spell_type>(message.wParam2);
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = static_cast<spell_type>(message.wParam2);
return sizeof(message);
}
@ -1210,9 +1210,9 @@ size_t OnTargetSpellTile(const TCmd *pCmd, Player &player)
player.destParam1 = position.x;
player.destParam2 = position.y;
player.destParam3 = message.wParam2;
player._pSpell = spell;
player._pSplType = RSPLTYPE_INVALID;
player._pSplFrom = 2;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = RSPLTYPE_INVALID;
player.queuedSpell.spellFrom = 2;
return sizeof(message);
}
@ -1317,9 +1317,9 @@ size_t OnSpellMonster(const TCmd *pCmd, Player &player)
player.destAction = ACTION_SPELLMON;
player.destParam1 = message.wParam1;
player.destParam2 = message.wParam4;
player._pSpell = spell;
player._pSplType = static_cast<spell_type>(message.wParam3);
player._pSplFrom = 0;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = static_cast<spell_type>(message.wParam3);
player.queuedSpell.spellFrom = 0;
return sizeof(message);
}
@ -1353,9 +1353,9 @@ size_t OnSpellPlayer(const TCmd *pCmd, Player &player)
player.destAction = ACTION_SPELLPLR;
player.destParam1 = message.wParam1;
player.destParam2 = message.wParam4;
player._pSpell = spell;
player._pSplType = static_cast<spell_type>(message.wParam3);
player._pSplFrom = 0;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = static_cast<spell_type>(message.wParam3);
player.queuedSpell.spellFrom = 0;
return sizeof(message);
}
@ -1385,9 +1385,9 @@ size_t OnTargetSpellMonster(const TCmd *pCmd, Player &player)
player.destAction = ACTION_SPELLMON;
player.destParam1 = message.wParam1;
player.destParam2 = message.wParam3;
player._pSpell = spell;
player._pSplType = RSPLTYPE_INVALID;
player._pSplFrom = 2;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = RSPLTYPE_INVALID;
player.queuedSpell.spellFrom = 2;
return sizeof(message);
}
@ -1415,9 +1415,9 @@ size_t OnTargetSpellPlayer(const TCmd *pCmd, Player &player)
player.destAction = ACTION_SPELLPLR;
player.destParam1 = message.wParam1;
player.destParam2 = message.wParam3;
player._pSpell = spell;
player._pSplType = RSPLTYPE_INVALID;
player._pSplFrom = 2;
player.queuedSpell.spellId = spell;
player.queuedSpell.spellType = RSPLTYPE_INVALID;
player.queuedSpell.spellFrom = 2;
return sizeof(message);
}
@ -2020,9 +2020,9 @@ size_t OnNova(const TCmd *pCmd, Player &player)
if (gbBufferMsgs != 1) {
if (player.isOnActiveLevel() && &player != MyPlayer && InDungeonBounds(position)) {
ClrPlrPath(player);
player._pSpell = SPL_NOVA;
player._pSplType = RSPLTYPE_INVALID;
player._pSplFrom = 3;
player.queuedSpell.spellId = SPL_NOVA;
player.queuedSpell.spellType = RSPLTYPE_INVALID;
player.queuedSpell.spellFrom = 3;
player.destAction = ACTION_SPELL;
player.destParam1 = position.x;
player.destParam2 = position.y;

29
Source/player.cpp

@ -384,7 +384,7 @@ void ClearStateVariables(Player &player)
{
player.position.temp = { 0, 0 };
player.tempDirection = Direction::South;
player.spellLevel = 0;
player.queuedSpell.spellLevel = 0;
player.position.offset2 = { 0, 0 };
}
@ -501,9 +501,9 @@ void StartSpell(Player &player, Direction d, WorldTileCoord cx, WorldTileCoord c
auto animationFlags = AnimationDistributionFlags::ProcessAnimationPending;
if (player._pmode == PM_SPELL)
animationFlags = static_cast<AnimationDistributionFlags>(animationFlags | AnimationDistributionFlags::RepeatedAction);
NewPlrAnim(player, GetPlayerGraphicForSpell(player._pSpell), d, player._pSFrames, 1, animationFlags, 0, player._pSFNum);
NewPlrAnim(player, GetPlayerGraphicForSpell(player.queuedSpell.spellId), d, player._pSFrames, 1, animationFlags, 0, player._pSFNum);
PlaySfxLoc(spelldata[player._pSpell].sSFX, player.position.tile);
PlaySfxLoc(spelldata[player.queuedSpell.spellId].sSFX, player.position.tile);
player._pmode = PM_SPELL;
@ -511,7 +511,8 @@ void StartSpell(Player &player, Direction d, WorldTileCoord cx, WorldTileCoord c
SetPlayerOld(player);
player.position.temp = WorldTilePosition { cx, cy };
player.spellLevel = player.GetSpellLevel(player._pSpell);
player.queuedSpell.spellLevel = player.GetSpellLevel(player.queuedSpell.spellId);
player.executedSpell = player.queuedSpell;
}
void RespawnDeadItem(Item &&itm, Point target)
@ -1264,14 +1265,14 @@ bool DoSpell(Player &player)
if (player.AnimInfo.currentFrame == player._pSFNum) {
CastSpell(
player.getId(),
player._pSpell,
player.executedSpell.spellId,
player.position.tile.x,
player.position.tile.y,
player.position.temp.x,
player.position.temp.y,
player.spellLevel);
player.executedSpell.spellLevel);
if (player._pSplFrom == 0) {
if (player.executedSpell.spellFrom == 0) {
EnsureValidReadiedSpell(player);
}
}
@ -1525,22 +1526,22 @@ void CheckNewPath(Player &player, bool pmWillBeCalled)
case ACTION_SPELL:
d = GetDirection(player.position.tile, { player.destParam1, player.destParam2 });
StartSpell(player, d, player.destParam1, player.destParam2);
player.spellLevel = player.destParam3;
player.executedSpell.spellLevel = player.destParam3;
break;
case ACTION_SPELLWALL:
StartSpell(player, static_cast<Direction>(player.destParam3), player.destParam1, player.destParam2);
player.tempDirection = static_cast<Direction>(player.destParam3);
player.spellLevel = player.destParam4;
player.executedSpell.spellLevel = player.destParam4;
break;
case ACTION_SPELLMON:
d = GetDirection(player.position.tile, monster->position.future);
StartSpell(player, d, monster->position.future.x, monster->position.future.y);
player.spellLevel = player.destParam2;
player.executedSpell.spellLevel = player.destParam2;
break;
case ACTION_SPELLPLR:
d = GetDirection(player.position.tile, target->position.future);
StartSpell(player, d, target->position.future.x, target->position.future.y);
player.spellLevel = player.destParam2;
player.executedSpell.spellLevel = player.destParam2;
break;
case ACTION_OPERATE:
if (IsPlayerAdjacentToObject(player, *object)) {
@ -2051,7 +2052,7 @@ player_graphic Player::getGraphic() const
case PM_BLOCK:
return player_graphic::Block;
case PM_SPELL:
switch (spelldata[_pSpell].sType) {
switch (spelldata[executedSpell.spellId].sType) {
case STYPE_FIRE:
return player_graphic::Fire;
case STYPE_LIGHTNING:
@ -2742,8 +2743,8 @@ void InitPlayer(Player &player, bool firstTime)
if (&player == MyPlayer)
LoadHotkeys();
player._pSBkSpell = SPL_INVALID;
player._pSpell = player._pRSpell;
player._pSplType = player._pRSplType;
player.queuedSpell.spellId = player._pRSpell;
player.queuedSpell.spellType = player._pRSplType;
player.pManaShield = false;
player.wReflections = 0;
}

18
Source/player.h

@ -210,6 +210,14 @@ struct PlayerAnimationData {
}
};
struct SpellCastInfo {
spell_id spellId;
spell_type spellType;
int8_t spellFrom; // TODO Create enum
/* @brief Used for spell level */
int spellLevel;
};
struct Player {
Player() = default;
Player(Player &&) noexcept = default;
@ -242,9 +250,10 @@ struct Player {
float progressToNextGameTickWhenPreviewWasSet;
int _plid;
int _pvid;
spell_id _pSpell;
spell_type _pSplType;
int8_t _pSplFrom; // TODO Create enum
/* @brief next queued spell */
SpellCastInfo queuedSpell;
/* @brief the spell that is currently casted */
SpellCastInfo executedSpell;
spell_id _pTSpell;
spell_id _pRSpell;
spell_type _pRSplType;
@ -295,8 +304,7 @@ struct Player {
bool _pInfraFlag;
/** Player's direction when ending movement. Also used for casting direction of SPL_FIREWALL. */
Direction tempDirection;
/** Used for spell level */
int spellLevel;
bool _pLvlVisited[NUMLEVELS];
bool _pSLvlVisited[NUMLEVELS]; // only 10 used
/**

2
Source/spells.cpp

@ -176,7 +176,7 @@ void UseMana(Player &player, spell_id sn)
if (&player != MyPlayer)
return;
switch (player._pSplType) {
switch (player.executedSpell.spellType) {
case RSPLTYPE_SKILL:
case RSPLTYPE_INVALID:
break;

4
test/inv_test.cpp

@ -198,7 +198,7 @@ TEST(Inv, RemoveCurrentSpellScroll_inventory)
// Put a firebolt scroll into the inventory
MyPlayer->_pNumInv = 1;
MyPlayer->_pSpell = static_cast<spell_id>(SPL_FIREBOLT);
MyPlayer->executedSpell.spellId = static_cast<spell_id>(SPL_FIREBOLT);
MyPlayer->InvList[0]._itype = ItemType::Misc;
MyPlayer->InvList[0]._iMiscId = IMISC_SCROLL;
MyPlayer->InvList[0]._iSpell = SPL_FIREBOLT;
@ -216,7 +216,7 @@ TEST(Inv, RemoveCurrentSpellScroll_belt)
MyPlayer->SpdList[i].clear();
}
// Put a firebolt scroll into the belt
MyPlayer->_pSpell = static_cast<spell_id>(SPL_FIREBOLT);
MyPlayer->executedSpell.spellId = static_cast<spell_id>(SPL_FIREBOLT);
MyPlayer->SpdList[3]._itype = ItemType::Misc;
MyPlayer->SpdList[3]._iMiscId = IMISC_SCROLL;
MyPlayer->SpdList[3]._iSpell = SPL_FIREBOLT;

6
test/player_test.cpp

@ -136,9 +136,9 @@ static void AssertPlayer(Player &player)
ASSERT_EQ(player._pmode, 0);
ASSERT_EQ(Count8(player.walkpath, MaxPathLength), 0);
ASSERT_EQ(player._pSpell, 0);
ASSERT_EQ(player._pSplType, 0);
ASSERT_EQ(player._pSplFrom, 0);
ASSERT_EQ(player.queuedSpell.spellId, 0);
ASSERT_EQ(player.queuedSpell.spellType, 0);
ASSERT_EQ(player.queuedSpell.spellFrom, 0);
ASSERT_EQ(player._pTSpell, 0);
ASSERT_EQ(player._pRSpell, 28);
ASSERT_EQ(player._pRSplType, 0);

6
test/writehero_test.cpp

@ -268,9 +268,9 @@ static void AssertPlayer(Player &player)
ASSERT_EQ(player.AnimInfo.tickCounterOfCurrentFrame, 1);
ASSERT_EQ(player.AnimInfo.numberOfFrames, 20);
ASSERT_EQ(player.AnimInfo.currentFrame, 0);
ASSERT_EQ(player._pSpell, -1);
ASSERT_EQ(player._pSplType, 4);
ASSERT_EQ(player._pSplFrom, 0);
ASSERT_EQ(player.queuedSpell.spellId, -1);
ASSERT_EQ(player.queuedSpell.spellType, 4);
ASSERT_EQ(player.queuedSpell.spellFrom, 0);
ASSERT_EQ(player._pTSpell, 0);
ASSERT_EQ(player._pRSpell, -1);
ASSERT_EQ(player._pRSplType, 4);

Loading…
Cancel
Save