From 2b0b944afbf9145a4dd57b4100a060584890478f Mon Sep 17 00:00:00 2001 From: obligaron Date: Fri, 20 May 2022 18:49:22 +0200 Subject: [PATCH] Manage friendly mode per player and sync state between clients --- Source/control.cpp | 9 ++++++--- Source/controls/plrctrls.cpp | 4 ++-- Source/diablo.cpp | 6 ++---- Source/diablo.h | 1 - Source/missiles.cpp | 8 ++++---- Source/msg.cpp | 9 +++++++++ Source/msg.h | 4 ++++ Source/multi.cpp | 6 +++++- Source/pack.h | 4 +++- Source/player.cpp | 4 ++-- Source/player.h | 2 ++ Source/track.cpp | 4 ++-- 12 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Source/control.cpp b/Source/control.cpp index 671016853..cc9f9436f 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -611,7 +611,8 @@ void DrawCtrlBtns(const Surface &out) } if (PanelButtonIndex == 8) { CelDrawTo(out, { 87 + PANEL_X, 122 + PANEL_Y }, *multiButtons, PanelButtons[6] ? 1 : 0); - if (gbFriendlyMode) + auto &myPlayer = Players[MyPlayerId]; + if (myPlayer.friendlyMode) CelDrawTo(out, { 527 + PANEL_X, 122 + PANEL_Y }, *multiButtons, PanelButtons[7] ? 3 : 2); else CelDrawTo(out, { 527 + PANEL_X, 122 + PANEL_Y }, *multiButtons, PanelButtons[7] ? 5 : 4); @@ -699,7 +700,8 @@ void CheckPanelInfo() if (i != 7) { InfoString = _(PanBtnStr[i]); } else { - if (gbFriendlyMode) + auto &myPlayer = Players[MyPlayerId]; + if (myPlayer.friendlyMode) InfoString = _("Player friendly"); else InfoString = _("Player attack"); @@ -824,7 +826,8 @@ void CheckBtnUp() control_type_message(); break; case PanelButtonFriendly: - gbFriendlyMode = !gbFriendlyMode; + // Toggle friendly Mode + NetSendCmd(true, CMD_FRIENDLYMODE); break; } } diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index c5cd835f9..8959d5f89 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -365,7 +365,7 @@ void CheckPlayerNearby() auto &myPlayer = Players[MyPlayerId]; int spl = myPlayer._pRSpell; - if (gbFriendlyMode && spl != SPL_RESURRECT && spl != SPL_HEALOTHER) + if (myPlayer.friendlyMode && spl != SPL_RESURRECT && spl != SPL_HEALOTHER) return; for (int i = 0; i < MAX_PLRS; i++) { @@ -512,7 +512,7 @@ void Interact() return; } - if (leveltype != DTYPE_TOWN && pcursplr != -1 && !gbFriendlyMode) { + if (leveltype != DTYPE_TOWN && pcursplr != -1 && !Players[MyPlayerId].friendlyMode) { NetSendCmdParam1(true, Players[MyPlayerId].UsesRangedWeapon() ? CMD_RATTACKPID : CMD_ATTACKPID, pcursplr); LastMouseButtonAction = MouseActionType::AttackPlayerTarget; return; diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 3fac7ac3b..63cbccaca 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -113,8 +113,6 @@ char gszProductName[64] = "DevilutionX vUnknown"; bool DebugDisableNetworkTimeout = false; std::vector DebugCmdsFromCommandLine; #endif -/** Specifies whether players are in non-PvP mode. */ -bool gbFriendlyMode = true; GameLogicStep gGameLogicStep = GameLogicStep::None; QuickMessage QuickMessages[QUICK_MESSAGE_OPTIONS] = { { "QuickMessage1", N_("I need help! Come Here!") }, @@ -254,7 +252,7 @@ void LeftMouseCmd(bool bShift) LastMouseButtonAction = MouseActionType::AttackMonsterTarget; NetSendCmdParam1(true, CMD_RATTACKID, pcursmonst); } - } else if (pcursplr != -1 && !gbFriendlyMode) { + } else if (pcursplr != -1 && !myPlayer.friendlyMode) { LastMouseButtonAction = MouseActionType::AttackPlayerTarget; NetSendCmdParam1(true, CMD_RATTACKPID, pcursplr); } @@ -274,7 +272,7 @@ void LeftMouseCmd(bool bShift) } else if (pcursmonst != -1) { LastMouseButtonAction = MouseActionType::AttackMonsterTarget; NetSendCmdParam1(true, CMD_ATTACKID, pcursmonst); - } else if (pcursplr != -1 && !gbFriendlyMode) { + } else if (pcursplr != -1 && !myPlayer.friendlyMode) { LastMouseButtonAction = MouseActionType::AttackPlayerTarget; NetSendCmdParam1(true, CMD_ATTACKPID, pcursplr); } diff --git a/Source/diablo.h b/Source/diablo.h index db1728ed3..3c4ff28ab 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -118,7 +118,6 @@ struct QuickMessage { constexpr size_t QUICK_MESSAGE_OPTIONS = 4; extern QuickMessage QuickMessages[QUICK_MESSAGE_OPTIONS]; -extern bool gbFriendlyMode; /** * @brief Specifices what game logic step is currently executed */ diff --git a/Source/missiles.cpp b/Source/missiles.cpp index a7e4255b9..6f45d1e76 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -309,14 +309,14 @@ bool MonsterMHit(int pnum, int m, int mindam, int maxdam, int dist, missile_id t bool Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, missile_id mtype, bool shift, bool *blocked) { - if (sgGameInitInfo.bFriendlyFire == 0 && gbFriendlyMode) + auto &player = Players[pnum]; + auto &target = Players[p]; + + if (sgGameInitInfo.bFriendlyFire == 0 && player.friendlyMode) return false; *blocked = false; - auto &player = Players[pnum]; - auto &target = Players[p]; - if (target._pInvincible) { return false; } diff --git a/Source/msg.cpp b/Source/msg.cpp index 51ea1672d..faa857782 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -1882,6 +1882,13 @@ DWORD OnString(const TCmd *pCmd, Player &player) return len + 2; // length of string + nul terminator + sizeof(p->bCmd) } +DWORD OnFriendlyMode(const TCmd *pCmd, Player &player) // NOLINT(misc-unused-parameters) +{ + player.friendlyMode = !player.friendlyMode; + force_redraw = 255; + return sizeof(*pCmd); +} + DWORD OnSyncQuest(const TCmd *pCmd, int pnum) { const auto &message = *reinterpret_cast(pCmd); @@ -2921,6 +2928,8 @@ uint32_t ParseCmd(int pnum, const TCmd *pCmd) return OnSetVitality(pCmd, pnum); case CMD_STRING: return OnString(pCmd, player); + case CMD_FRIENDLYMODE: + return OnFriendlyMode(pCmd, player); case CMD_SYNCQUEST: return OnSyncQuest(pCmd, pnum); case CMD_CHEAT_EXPERIENCE: diff --git a/Source/msg.h b/Source/msg.h index 39534ea00..1d07bd27b 100644 --- a/Source/msg.h +++ b/Source/msg.h @@ -372,6 +372,10 @@ enum _cmd_id : uint8_t { // // body (TCmdString) CMD_STRING, + // Toggles friendly Mode + // + // body (TCmd) + CMD_FRIENDLYMODE, // Set player strength. // // body (TCmdParam1): diff --git a/Source/multi.cpp b/Source/multi.cpp index 5125794d1..248798b48 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -335,7 +335,10 @@ void SendPlayerInfo(int pnum, _cmd_id cmd) static_assert(alignof(PlayerPack) == 1, "Fix pkplr alignment"); std::unique_ptr pkplr { new byte[sizeof(PlayerPack)] }; - PackPlayer(reinterpret_cast(pkplr.get()), Players[MyPlayerId], true, true); + PlayerPack *pPack = reinterpret_cast(pkplr.get()); + auto &myPlayer = Players[MyPlayerId]; + PackPlayer(pPack, myPlayer, true, true); + pPack->friendlyMode = myPlayer.friendlyMode ? 1 : 0; dthread_send_delta(pnum, cmd, std::move(pkplr), sizeof(PlayerPack)); } @@ -831,6 +834,7 @@ void recv_plrinfo(int pnum, const TCmdPlrInfoHdr &header, bool recv) if (!UnPackPlayer(&packedPlayer, player, true)) { return; } + player.friendlyMode = packedPlayer.friendlyMode != 0; if (!recv) { return; diff --git a/Source/pack.h b/Source/pack.h index 1bfcd2e5f..c7dea64ed 100644 --- a/Source/pack.h +++ b/Source/pack.h @@ -75,7 +75,9 @@ struct PlayerPack { uint32_t pDiabloKillLevel; uint32_t pDifficulty; ItemSpecialEffectHf pDamAcFlags; - int32_t dwReserved[5]; // For future use + /**@brief Only used in multiplayer sync (SendPlayerInfo/recv_plrinfo). Never used in save games (single- or multiplayer). */ + uint8_t friendlyMode; + uint8_t dwReserved[19]; // For future use }; #pragma pack(pop) diff --git a/Source/player.cpp b/Source/player.cpp index 914269cd2..58462afce 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1148,7 +1148,7 @@ bool DoAttack(int pnum) m = -(dMonster[dx][dy] + 1); } didhit = PlrHitMonst(pnum, m); - } else if (dPlayer[dx][dy] != 0 && !gbFriendlyMode) { + } else if (dPlayer[dx][dy] != 0 && !player.friendlyMode) { BYTE p = dPlayer[dx][dy]; if (dPlayer[dx][dy] > 0) { p = dPlayer[dx][dy] - 1; @@ -3627,7 +3627,7 @@ void CheckPlrSpell(bool isShiftHeld, spell_id spellID, spell_type spellType) LastMouseButtonAction = MouseActionType::SpellMonsterTarget; sl = GetSpellLevel(MyPlayerId, spellID); NetSendCmdParam4(true, CMD_SPELLID, pcursmonst, spellID, spellType, sl); - } else if (pcursplr != -1 && !isShiftHeld && !gbFriendlyMode) { + } else if (pcursplr != -1 && !isShiftHeld && !myPlayer.friendlyMode) { LastMouseButtonAction = MouseActionType::SpellPlayerTarget; sl = GetSpellLevel(MyPlayerId, spellID); NetSendCmdParam4(true, CMD_SPELLPID, pcursplr, spellID, spellType, sl); diff --git a/Source/player.h b/Source/player.h index d905c0e2a..47a34b977 100644 --- a/Source/player.h +++ b/Source/player.h @@ -347,6 +347,8 @@ struct Player { uint8_t pDiabloKillLevel; _difficulty pDifficulty; ItemSpecialEffectHf pDamAcFlags; + /** @brief Specifies whether players are in non-PvP mode. */ + bool friendlyMode = true; void CalcScrolls(); diff --git a/Source/track.cpp b/Source/track.cpp index da22496d1..f0acff9f9 100644 --- a/Source/track.cpp +++ b/Source/track.cpp @@ -93,7 +93,7 @@ void RepeatMouseAction() NetSendCmdParam1(true, rangedAttack ? CMD_RATTACKID : CMD_ATTACKID, pcursmonst); break; case MouseActionType::AttackPlayerTarget: - if (pcursplr != -1 && !gbFriendlyMode) + if (pcursplr != -1 && !myPlayer.friendlyMode) NetSendCmdParam1(true, rangedAttack ? CMD_RATTACKPID : CMD_ATTACKPID, pcursplr); break; case MouseActionType::Spell: @@ -107,7 +107,7 @@ void RepeatMouseAction() CheckPlrSpell(false); break; case MouseActionType::SpellPlayerTarget: - if (pcursplr != -1 && !gbFriendlyMode) + if (pcursplr != -1 && !myPlayer.friendlyMode) CheckPlrSpell(false); break; case MouseActionType::OperateObject: