From e240051b7423a262f7599e1b74117119338e09bb Mon Sep 17 00:00:00 2001 From: KPhoenix Date: Sat, 30 Sep 2023 22:41:59 -0400 Subject: [PATCH 1/4] QoL: Increase playercount to 8 Replace MAXVISION with MAX_PLRS Update base.cpp MAXVISION again? Add 8 player functionality Remove MAXPORTAL Update Update Update Update portal.cpp Add fixed monster tags Update automap.cpp Adjust portal positions Update automap.cpp Use default 200 max monsters Fix errors Fix mistakes --- Source/DiabloUI/multi/selconn.cpp | 6 +++--- Source/automap.cpp | 11 +++++++++- Source/control.cpp | 2 +- Source/dvlnet/base.cpp | 6 +++--- Source/dvlnet/base.h | 2 +- Source/dvlnet/base_protocol.h | 18 ++++++++-------- Source/dvlnet/loopback.cpp | 2 +- Source/dvlnet/tcp_server.cpp | 2 +- Source/dvlnet/tcp_server.h | 2 +- Source/engine/render/scrollrt.cpp | 2 +- Source/lighting.cpp | 4 ++-- Source/lighting.h | 6 +++--- Source/loadsave.cpp | 12 +++++------ Source/monster.cpp | 33 ++++++++++++++++++++++-------- Source/msg.cpp | 8 ++++---- Source/multi.cpp | 21 ++++++++++--------- Source/multi.h | 7 ++++--- Source/nthread.cpp | 10 ++++----- Source/nthread.h | 4 ++-- Source/objects.cpp | 3 ++- Source/player.cpp | 2 +- Source/portal.cpp | 12 ++++++----- Source/portal.h | 4 +--- Source/storm/storm_net.cpp | 2 +- Source/sync.cpp | 4 ++-- assets/data/monstertags.clx | Bin 440 -> 872 bytes 26 files changed, 106 insertions(+), 79 deletions(-) diff --git a/Source/DiabloUI/multi/selconn.cpp b/Source/DiabloUI/multi/selconn.cpp index 5fc96b366a9..aa57609209a 100644 --- a/Source/DiabloUI/multi/selconn.cpp +++ b/Source/DiabloUI/multi/selconn.cpp @@ -106,15 +106,15 @@ void SelconnEsc() void SelconnFocus(size_t value) { - int players = MAX_PLRS; + int players = MaxPlayers; switch (vecConnItems[value]->m_value) { case SELCONN_TCP: CopyUtf8(selconn_Description, _("All computers must be connected to a TCP-compatible network."), sizeof(selconn_Description)); - players = MAX_PLRS; + players = MaxPlayers; break; case SELCONN_ZT: CopyUtf8(selconn_Description, _("All computers must be connected to the internet."), sizeof(selconn_Description)); - players = MAX_PLRS; + players = MaxPlayers; break; case SELCONN_LOOPBACK: CopyUtf8(selconn_Description, _("Play by yourself with no network exposure."), sizeof(selconn_Description)); diff --git a/Source/automap.cpp b/Source/automap.cpp index e46d07f0d92..e4299cb89ca 100644 --- a/Source/automap.cpp +++ b/Source/automap.cpp @@ -38,6 +38,13 @@ Point Automap; enum MapColors : uint8_t { /** color used to draw the player's arrow */ MapColorsPlayer = (PAL8_ORANGE + 1), + MapColorsPlayer2 = (PAL8_YELLOW + 1), + MapColorsPlayer3 = (PAL8_RED + 1), + MapColorsPlayer4 = (PAL8_BLUE + 1), + MapColorsPlayer5 = (PAL16_ORANGE + 1), + MapColorsPlayer6 = (PAL16_BEIGE + 1), + MapColorsPlayer7 = (PAL16_RED + 1), + MapColorsPlayer8 = (PAL16_BLUE + 1), /** color for bright map lines (doors, stairs etc.) */ MapColorsBright = PAL8_YELLOW, /** color for dim map lines/dots */ @@ -153,6 +160,8 @@ struct AutomapTile { } }; +uint8_t playerColors[] { MapColorsPlayer, MapColorsPlayer2, MapColorsPlayer3, MapColorsPlayer4, MapColorsPlayer5, MapColorsPlayer6, MapColorsPlayer7, MapColorsPlayer8 }; + /** * Maps from tile_id to automap type. */ @@ -1319,7 +1328,7 @@ void SearchAutomapItem(const Surface &out, const Displacement &myPlayerOffset, i */ void DrawAutomapPlr(const Surface &out, const Displacement &myPlayerOffset, const Player &player) { - const uint8_t playerColor = MapColorsPlayer + (8 * player.getId()) % 128; + const uint8_t playerColor = playerColors[player.getId()]; Point tile = player.position.tile; diff --git a/Source/control.cpp b/Source/control.cpp index 429bdb63c91..6bf479077d6 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -187,7 +187,7 @@ uint8_t NextTalkSave; char TalkMessage[MAX_SEND_STR_LEN]; bool TalkButtonsDown[3]; int sgbPlrTalkTbl; -bool WhisperList[MAX_PLRS]; +bool WhisperList[MaxPlayers]; int PanelPaddingHeight = 16; TextInputCursorState ChatCursor; diff --git a/Source/dvlnet/base.cpp b/Source/dvlnet/base.cpp index 983fba71e5d..eddf376a5d7 100644 --- a/Source/dvlnet/base.cpp +++ b/Source/dvlnet/base.cpp @@ -181,7 +181,7 @@ bool base::IsConnected(plr_t player) const tl::expected base::RecvLocal(packet &pkt) { - if (pkt.Source() < MAX_PLRS) { + if (pkt.Source() < MaxPlayers) { if (tl::expected result = Connect(pkt.Source()); !result.has_value()) { return result; @@ -225,7 +225,7 @@ bool base::SNetReceiveMessage(uint8_t *sender, void **data, size_t *size) bool base::SNetSendMessage(uint8_t playerId, void *data, size_t size) { - if (playerId != SNPLAYER_OTHERS && playerId >= MAX_PLRS) + if (playerId != SNPLAYER_OTHERS && playerId >= MaxPlayers) abort(); auto *rawMessage = reinterpret_cast(data); buffer_t message(rawMessage, rawMessage + size); @@ -420,7 +420,7 @@ void base::SNetGetProviderCaps(struct _SNETCAPS *caps) caps->flags = 0; // unused caps->maxmessagesize = 512; // capped to 512; underflow if < 24 caps->maxqueuesize = 0; // unused - caps->maxplayers = MAX_PLRS; // capped to 4 + caps->maxplayers = MaxPlayers; // capped to 8 caps->bytessec = 1000000; // ? caps->latencyms = 0; // unused caps->defaultturnssec = 10; // ? diff --git a/Source/dvlnet/base.h b/Source/dvlnet/base.h index afd4b371d50..452208e97b9 100644 --- a/Source/dvlnet/base.h +++ b/Source/dvlnet/base.h @@ -86,7 +86,7 @@ class base : public abstract_net { virtual bool IsGameHost() = 0; private: - std::array playerStateTable_; + std::array playerStateTable_; bool awaitingSequenceNumber_ = true; plr_t GetOwner(); diff --git a/Source/dvlnet/base_protocol.h b/Source/dvlnet/base_protocol.h index 6e4f205c831..9f11922e0ea 100644 --- a/Source/dvlnet/base_protocol.h +++ b/Source/dvlnet/base_protocol.h @@ -55,7 +55,7 @@ class base_protocol : public base { endpoint_t peer; }; ankerl::unordered_dense::map game_list; - std::array peers; + std::array peers; bool isGameHost_; plr_t get_master(); @@ -252,7 +252,7 @@ tl::expected base_protocol

::send(packet &pkt) } return {}; } - if (destination >= MAX_PLRS) + if (destination >= MaxPlayers) return tl::make_unexpected("Invalid player ID"); if (destination == MyPlayerId) return {}; @@ -319,7 +319,7 @@ tl::expected base_protocol

::handle_join_request(packet &in break; } } - if (i >= MAX_PLRS) { + if (i >= MaxPlayers) { // already full return {}; } @@ -358,7 +358,7 @@ template tl::expected base_protocol

::recv_decrypted(packet &pkt, endpoint_t sender) { if (pkt.Source() == PLR_BROADCAST && pkt.Destination() == PLR_MASTER && pkt.Type() == PT_INFO_REPLY) { - size_t neededSize = sizeof(GameData) + (PlayerNameLength * MAX_PLRS); + size_t neededSize = sizeof(GameData) + (PlayerNameLength * MaxPlayers); const tl::expected pktInfo = pkt.Info(); if (!pktInfo.has_value()) return tl::make_unexpected(pktInfo.error()); @@ -405,7 +405,7 @@ tl::expected base_protocol

::recv_ingame(packet &pkt, endpo } else if (pkt.Type() == PT_INFO_REQUEST) { if ((plr_self != PLR_BROADCAST) && (get_master() == plr_self)) { buffer_t buf; - buf.resize(game_init_info.size() + (PlayerNameLength * MAX_PLRS) + gamename.size()); + buf.resize(game_init_info.size() + (PlayerNameLength * MaxPlayers) + gamename.size()); std::memcpy(buf.data(), &game_init_info[0], game_init_info.size()); for (size_t i = 0; i < Players.size(); i++) { if (Players[i].plractive) { @@ -414,7 +414,7 @@ tl::expected base_protocol

::recv_ingame(packet &pkt, endpo std::memset(buf.data() + game_init_info.size() + (i * PlayerNameLength), '\0', PlayerNameLength); } } - std::memcpy(buf.data() + game_init_info.size() + (PlayerNameLength * MAX_PLRS), &gamename[0], gamename.size()); + std::memcpy(buf.data() + game_init_info.size() + (PlayerNameLength * MaxPlayers), &gamename[0], gamename.size()); tl::expected, PacketError> reply = pktfty->make_packet(PLR_BROADCAST, PLR_MASTER, buf); if (!reply.has_value()) { @@ -453,9 +453,9 @@ tl::expected base_protocol

::recv_ingame(packet &pkt, endpo return InitiateHandshake(*newPlayer); return {}; } - if (pkt.Source() >= MAX_PLRS) { + if (pkt.Source() >= MaxPlayers) { // normal packets - LogDebug("Invalid packet: packet source ({}) >= MAX_PLRS", pkt.Source()); + LogDebug("Invalid packet: packet source ({}) >= MaxPlayers", pkt.Source()); return {}; } if (sender == firstpeer && pkt.Type() == PT_JOIN_ACCEPT) { @@ -523,7 +523,7 @@ bool base_protocol

::is_recognized(endpoint_t sender) if (sender == firstpeer) return true; - for (auto player = 0; player <= MAX_PLRS; player++) { + for (auto player = 0; player <= MaxPlayers; player++) { if (sender == peers[player].endpoint) return true; } diff --git a/Source/dvlnet/loopback.cpp b/Source/dvlnet/loopback.cpp index 3d1401e8e45..70ad6e1cef3 100644 --- a/Source/dvlnet/loopback.cpp +++ b/Source/dvlnet/loopback.cpp @@ -62,7 +62,7 @@ void loopback::SNetGetProviderCaps(struct _SNETCAPS *caps) caps->flags = 0; // unused caps->maxmessagesize = 512; // capped to 512; underflow if < 24 caps->maxqueuesize = 0; // unused - caps->maxplayers = MAX_PLRS; // capped to 4 + caps->maxplayers = MaxPlayers; // capped to 8 caps->bytessec = 1000000; // ? caps->latencyms = 0; // unused caps->defaultturnssec = 10; // ? diff --git a/Source/dvlnet/tcp_server.cpp b/Source/dvlnet/tcp_server.cpp index bc39bd4139b..5329b556015 100644 --- a/Source/dvlnet/tcp_server.cpp +++ b/Source/dvlnet/tcp_server.cpp @@ -172,7 +172,7 @@ tl::expected tcp_server::SendPacket(packet &pkt) } return {}; } - if (pkt.Destination() >= MAX_PLRS) + if (pkt.Destination() >= MaxPlayers) return tl::make_unexpected(ServerError()); if (pkt.Destination() == pkt.Source() || !connections[pkt.Destination()]) return {}; diff --git a/Source/dvlnet/tcp_server.h b/Source/dvlnet/tcp_server.h index 4827cbadbfc..470871d6278 100644 --- a/Source/dvlnet/tcp_server.h +++ b/Source/dvlnet/tcp_server.h @@ -66,7 +66,7 @@ class tcp_server { asio::io_context &ioc; packet_factory &pktfty; std::unique_ptr acceptor; - std::array connections; + std::array connections; buffer_t game_init_info; std::optional ioHandlerResult; diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 2f1d50e3d1c..e32a9c2529a 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -744,7 +744,7 @@ void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosit Player *player = PlayerAtPosition(tilePosition); if (player != nullptr) { uint8_t pid = player->getId(); - assert(pid < MAX_PLRS); + assert(pid < MaxPlayers); int playerId = static_cast(pid) + 1; // If sprite is moving southwards or east, we want to draw it offset from the tile it's moving to, so we need negative ID // This respests the order that tiles are drawn. By using the negative id, we ensure that the sprite is drawn with priority diff --git a/Source/lighting.cpp b/Source/lighting.cpp index bcc06cff0b7..ec848c8f898 100644 --- a/Source/lighting.cpp +++ b/Source/lighting.cpp @@ -22,8 +22,8 @@ namespace devilution { -std::array VisionActive; -Light VisionList[MAXVISION]; +std::array VisionActive; +Light VisionList[MaxPlayers]; Light Lights[MAXLIGHTS]; std::array ActiveLights; int ActiveLightCount; diff --git a/Source/lighting.h b/Source/lighting.h index 2a0de57ad7c..484b67063fa 100644 --- a/Source/lighting.h +++ b/Source/lighting.h @@ -14,12 +14,12 @@ #include "engine/displacement.hpp" #include "engine/point.hpp" #include "engine/world_tile.hpp" +#include "multi.h" #include "utils/attributes.h" namespace devilution { #define MAXLIGHTS 32 -#define MAXVISION 4 /** @brief Number of supported light levels */ constexpr size_t NumLightingLevels = 16; #define NO_LIGHT -1 @@ -40,8 +40,8 @@ struct Light { bool hasChanged; }; -extern Light VisionList[MAXVISION]; -extern std::array VisionActive; +extern Light VisionList[MaxPlayers]; +extern std::array VisionActive; extern Light Lights[MAXLIGHTS]; extern std::array ActiveLights; extern int ActiveLightCount; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index b485e2468ff..ce92303b269 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -421,10 +421,10 @@ void LoadPlayer(LoadHelper &file, Player &player) file.Skip(3); // Alignment // Extra hotkeys: to keep single player save compatibility, read only 4 hotkeys here, rely on LoadHotkeys for the rest - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MaxPlayersSp; i++) { player._pSplHotKey[i] = static_cast(file.NextLE()); } - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MaxPlayersSp; i++) { player._pSplTHotKey[i] = static_cast(file.NextLE()); } @@ -1224,10 +1224,10 @@ void SavePlayer(SaveHelper &file, const Player &player) file.Skip(3); // Alignment // Extra hotkeys: to keep single player save compatibility, write only 4 hotkeys here, rely on SaveHotkeys for the rest - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MaxPlayersSp; i++) { file.WriteLE(static_cast(player._pSplHotKey[i])); } - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MaxPlayersSp; i++) { file.WriteLE(static_cast(player._pSplTHotKey[i])); } @@ -2400,7 +2400,7 @@ tl::expected LoadGame(bool firstflag) for (int i = 0; i < giNumberQuests; i++) LoadQuest(&file, i); - for (int i = 0; i < MAXPORTAL; i++) + for (int i = 0; i < MaxPlayersSp; i++) LoadPortal(&file, i); if (gbIsHellfireSaveGame != gbIsHellfire) { @@ -2678,7 +2678,7 @@ void SaveGameData(SaveWriter &saveWriter) for (int i = 0; i < giNumberQuests; i++) SaveQuest(&file, i); - for (int i = 0; i < MAXPORTAL; i++) + for (int i = 0; i < MaxPlayersSp; i++) SavePortal(&file, i); for (int monstkill : MonsterKillCounts) file.WriteBE(monstkill); diff --git a/Source/monster.cpp b/Source/monster.cpp index 78a6890eb1d..c0c45e68c94 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -3262,6 +3262,7 @@ void InitLevelMonsters() ClrAllMonsters(); ActiveMonsterCount = 0; + totalmonsters = MaxMonsters; std::iota(std::begin(ActiveMonsters), std::end(ActiveMonsters), 0u); @@ -3517,7 +3518,9 @@ void WeakenNaKrul() void InitGolems() { if (!setlevel) { - for (int i = 0; i < MAX_PLRS; i++) + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + + for (int i = 0; i < maxPlayers; i++) AddMonster(GolemHoldingCell, Direction::South, 0, false); } } @@ -3551,6 +3554,7 @@ tl::expected InitMonsters() size_t numplacemonsters = na / 30; if (gbIsMultiplayer) numplacemonsters += numplacemonsters / 2; + if (ActiveMonsterCount + numplacemonsters > MaxMonsters - 10) numplacemonsters = MaxMonsters - 10 - ActiveMonsterCount; totalmonsters = ActiveMonsterCount + numplacemonsters; @@ -3586,9 +3590,12 @@ tl::expected InitMonsters() tl::expected SetMapMonsters(const uint16_t *dunData, Point startPosition) { RETURN_IF_ERROR(AddMonsterType(MT_GOLEM, PLACE_SPECIAL)); - if (setlevel) - for (int i = 0; i < MAX_PLRS; i++) + if (setlevel) { + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + + for (int i = 0; i < maxPlayers; i++) AddMonster(GolemHoldingCell, Direction::South, 0, false); + } WorldTileSize size = GetDunSize(dunData); @@ -4011,7 +4018,9 @@ void GolumAi(Monster &golem) void DeleteMonsterList() { - for (int i = 0; i < MAX_PLRS; i++) { + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + + for (int i = 0; i < maxPlayers; i++) { Monster &golem = Monsters[i]; if (!golem.isInvalid) continue; @@ -4022,7 +4031,7 @@ void DeleteMonsterList() golem.isInvalid = false; } - for (size_t i = MAX_PLRS; i < ActiveMonsterCount;) { + for (size_t i = maxPlayers; i < ActiveMonsterCount;) { if (Monsters[ActiveMonsters[i]].isInvalid) { if (pcursmonst == static_cast(ActiveMonsters[i])) // Unselect monster if player highlighted it pcursmonst = -1; @@ -4079,7 +4088,9 @@ void ProcessMonsters() monster.position.last = Monsters[monster.enemy].position.future; monster.enemyPosition = monster.position.last; } else { - assert(monster.enemy >= 0 && monster.enemy < MAX_PLRS); + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + + assert(monster.enemy >= 0 && monster.enemy < maxPlayers); Player &player = Players[monster.enemy]; monster.enemyPosition = player.position.future; if (IsTileVisible(monster.position.tile)) { @@ -4670,21 +4681,25 @@ bool CanTalkToMonst(const Monster &monster) int encode_enemy(Monster &monster) { + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + if ((monster.flags & MFLAG_TARGETS_MONSTER) != 0) - return monster.enemy + MAX_PLRS; + return monster.enemy + maxPlayers; return monster.enemy; } void decode_enemy(Monster &monster, int enemyId) { - if (enemyId < MAX_PLRS) { + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + + if (enemyId < maxPlayers) { monster.flags &= ~MFLAG_TARGETS_MONSTER; monster.enemy = enemyId; monster.enemyPosition = Players[enemyId].position.future; } else { monster.flags |= MFLAG_TARGETS_MONSTER; - enemyId -= MAX_PLRS; + enemyId -= maxPlayers; monster.enemy = enemyId; monster.enemyPosition = Monsters[enemyId].position.future; } diff --git a/Source/msg.cpp b/Source/msg.cpp index 571a03d9f9e..1cb7a63f9f0 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -250,7 +250,7 @@ struct MultiQuests { }; struct DJunk { - DPortal portal[MAXPORTAL]; + DPortal portal[MaxPlayers]; MultiQuests quests[MAXQUESTS]; }; #pragma pack(pop) @@ -629,7 +629,7 @@ std::byte *DeltaExportJunk(std::byte *dst) void DeltaImportJunk(const std::byte *src) { - for (int i = 0; i < MAXPORTAL; i++) { + for (int i = 0; i < MaxPlayers; i++) { if (*src == std::byte { 0xFF }) { memset(&sgJunk.portal[i], 0xFF, sizeof(DPortal)); src++; @@ -1743,7 +1743,7 @@ size_t OnWarp(const TCmd *pCmd, Player &player) if (gbBufferMsgs == 1) { SendPacket(player, &message, sizeof(message)); - } else if (portalIdx < MAXPORTAL) { + } else if (portalIdx < MaxPlayers) { StartWarpLvl(player, portalIdx); } @@ -2591,7 +2591,7 @@ void delta_sync_monster(const TSyncMonster &monsterSync, uint8_t level) void DeltaSyncJunk() { - for (int i = 0; i < MAXPORTAL; i++) { + for (int i = 0; i < MaxPlayers; i++) { if (sgJunk.portal[i].x == 0xFF) { SetPortalStats(i, false, { 0, 0 }, 0, DTYPE_TOWN, false); } else { diff --git a/Source/multi.cpp b/Source/multi.cpp index 7754fbeb21a..aff38a227e7 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -36,17 +36,17 @@ namespace devilution { bool gbSomebodyWonGameKludge; -uint16_t sgwPackPlrOffsetTbl[MAX_PLRS]; -bool sgbPlayerTurnBitTbl[MAX_PLRS]; -bool sgbPlayerLeftGameTbl[MAX_PLRS]; +uint16_t sgwPackPlrOffsetTbl[MaxPlayers]; +bool sgbPlayerTurnBitTbl[MaxPlayers]; +bool sgbPlayerLeftGameTbl[MaxPlayers]; bool shareNextHighPriorityMessage; uint8_t gbActivePlayers; bool gbGameDestroyed; -bool sgbSendDeltaTbl[MAX_PLRS]; +bool sgbSendDeltaTbl[MaxPlayers]; GameData sgGameInitInfo; bool gbSelectProvider; int sglTimeoutStart; -uint32_t sgdwPlayerLeftReasonTbl[MAX_PLRS]; +uint32_t sgdwPlayerLeftReasonTbl[MaxPlayers]; uint32_t sgdwGameLoops; /** * Specifies the maximum number of players in a game, where 1 @@ -59,8 +59,8 @@ std::string GamePassword; bool PublicGame; uint8_t gbDeltaSender; bool sgbNetInited; -uint32_t player_state[MAX_PLRS]; -Uint32 playerInfoTimers[MAX_PLRS]; +uint32_t player_state[MaxPlayers]; +Uint32 playerInfoTimers[MaxPlayers]; bool IsLoopback; /** @@ -225,6 +225,7 @@ void MonsterSeeds() { sgdwGameLoops++; const uint32_t seed = (sgdwGameLoops >> 8) | (sgdwGameLoops << 24); + for (uint32_t i = 0; i < MaxMonsters; i++) Monsters[i].aiSeed = seed + i; } @@ -420,7 +421,7 @@ void HandleEvents(_SNETEVENT *pEvt) sgbSendDeltaTbl[playerId] = false; if (gbDeltaSender == playerId) - gbDeltaSender = MAX_PLRS; + gbDeltaSender = MaxPlayers; } break; case EVENT_TYPE_PLAYER_MESSAGE: { std::string_view data(static_cast(pEvt->data), pEvt->databytes); @@ -475,7 +476,7 @@ bool InitSingle(GameData *gameData) bool InitMulti(GameData *gameData) { - Players.resize(MAX_PLRS); + Players.resize(MaxPlayers); int playerId; @@ -834,7 +835,7 @@ bool NetInit(bool bSinglePlayer) void recv_plrinfo(Player &player, const TCmdPlrInfoHdr &header, bool recv) { - static PlayerNetPack PackedPlayerBuffer[MAX_PLRS]; + static PlayerNetPack PackedPlayerBuffer[MaxPlayers]; if (&player == MyPlayer) { return; diff --git a/Source/multi.h b/Source/multi.h index 7fa38421e27..f8a2a897944 100644 --- a/Source/multi.h +++ b/Source/multi.h @@ -18,7 +18,8 @@ namespace devilution { struct Player; // must be unsigned to generate unsigned comparisons with pnum -#define MAX_PLRS 4 +constexpr int MaxPlayersSp = 4; +constexpr int MaxPlayers = 8; struct GameData { int32_t size; @@ -48,7 +49,7 @@ struct GameInfo { }; extern bool gbSomebodyWonGameKludge; -extern uint16_t sgwPackPlrOffsetTbl[MAX_PLRS]; +extern uint16_t sgwPackPlrOffsetTbl[MaxPlayers]; extern uint8_t gbActivePlayers; extern bool gbGameDestroyed; extern DVL_API_FOR_TEST GameData sgGameInitInfo; @@ -58,7 +59,7 @@ extern std::string GameName; extern std::string GamePassword; extern bool PublicGame; extern uint8_t gbDeltaSender; -extern uint32_t player_state[MAX_PLRS]; +extern uint32_t player_state[MaxPlayers]; extern bool IsLoopback; void InitGameInfo(); diff --git a/Source/nthread.cpp b/Source/nthread.cpp index ebea8a30374..9a727bdce72 100644 --- a/Source/nthread.cpp +++ b/Source/nthread.cpp @@ -20,9 +20,9 @@ namespace devilution { uint8_t sgbNetUpdateRate; -size_t gdwMsgLenTbl[MAX_PLRS]; +size_t gdwMsgLenTbl[MaxPlayers]; uint32_t gdwTurnsInTransit; -uintptr_t glpMsgTbl[MAX_PLRS]; +uintptr_t glpMsgTbl[MaxPlayers]; uint32_t gdwLargestMsgSize; uint32_t gdwNormalMsgSize; int last_tick; @@ -113,7 +113,7 @@ bool nthread_recv_turns(bool *pfSendAsync) last_tick += gnTickDelay; return true; } - if (!SNetReceiveTurns(MAX_PLRS, (char **)glpMsgTbl, gdwMsgLenTbl, &player_state[0])) { + if (!SNetReceiveTurns(MaxPlayers, (char **)glpMsgTbl, gdwMsgLenTbl, &player_state[0])) { sgbTicsOutOfSync = false; sgbSyncCountdown = 1; sgbPacketCountdown = 1; @@ -163,8 +163,8 @@ void nthread_start(bool setTurnUpperBit) gdwNormalMsgSize = caps.bytessec * sgbNetUpdateRate / 20; gdwNormalMsgSize *= 3; gdwNormalMsgSize >>= 2; - if (caps.maxplayers > MAX_PLRS) - caps.maxplayers = MAX_PLRS; + if (caps.maxplayers > MaxPlayers) + caps.maxplayers = MaxPlayers; gdwNormalMsgSize /= caps.maxplayers; while (gdwNormalMsgSize < 0x80) { gdwNormalMsgSize *= 2; diff --git a/Source/nthread.h b/Source/nthread.h index d07fdd03d7e..6687af71fe7 100644 --- a/Source/nthread.h +++ b/Source/nthread.h @@ -13,9 +13,9 @@ namespace devilution { extern uint8_t sgbNetUpdateRate; -extern size_t gdwMsgLenTbl[MAX_PLRS]; +extern size_t gdwMsgLenTbl[MaxPlayers]; extern uint32_t gdwTurnsInTransit; -extern uintptr_t glpMsgTbl[MAX_PLRS]; +extern uintptr_t glpMsgTbl[MaxPlayers]; extern uint32_t gdwLargestMsgSize; extern uint32_t gdwNormalMsgSize; /** @brief the progress as a fraction (see AnimationInfo::baseValueFraction) in time to the next game tick */ diff --git a/Source/objects.cpp b/Source/objects.cpp index 4ccd53f582f..62c4c793d12 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -3132,7 +3132,8 @@ void OperateBookcase(Object &bookcase, bool sendmsg, bool sendLootMsg) CreateTypeItem(bookcase.position, false, ItemType::Misc, IMISC_BOOK, sendLootMsg, false); if (Quests[Q_ZHAR].IsAvailable()) { - Monster &zhar = Monsters[MAX_PLRS]; + uint8_t maxPlayers = gbIsMultiplayer ? MaxPlayers : MaxPlayersSp; + Monster &zhar = Monsters[maxPlayers]; if (zhar.mode == MonsterMode::Stand // prevents playing the "angry" message for the second time if zhar got aggroed by losing vision and talking again && zhar.uniqueType == UniqueMonsterType::Zhar && zhar.activeForTicks == UINT8_MAX diff --git a/Source/player.cpp b/Source/player.cpp index 871a3218127..05d7c513a47 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -3191,7 +3191,7 @@ void SyncInitPlrPos(Player &player) const WorldTileDisplacement offset[9] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 }, { 2, 0 }, { 0, 2 }, { 1, 2 }, { 2, 1 }, { 2, 2 } }; Point position = [&]() { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MaxPlayers; i++) { Point position = player.position.tile + offset[i]; if (PosOkPlayer(player, position)) return position; diff --git a/Source/portal.cpp b/Source/portal.cpp index c206bcf41e4..1ad49acf467 100644 --- a/Source/portal.cpp +++ b/Source/portal.cpp @@ -8,13 +8,11 @@ #include "lighting.h" #include "misdat.h" #include "missiles.h" -#include "multi.h" -#include "player.h" namespace devilution { /** In-game state of portals. */ -Portal Portals[MAXPORTAL]; +Portal Portals[8]; namespace { @@ -22,11 +20,15 @@ namespace { size_t portalindex; /** Coordinate of each player's portal in town. */ -Point PortalTownPosition[MAXPORTAL] = { +Point PortalTownPosition[8] = { { 57, 40 }, { 59, 40 }, { 61, 40 }, { 63, 40 }, + { 65, 40 }, + { 67, 40 }, + { 69, 40 }, + { 55, 40 }, }; } // namespace @@ -62,7 +64,7 @@ void AddPortalMissile(const Player &player, Point position, bool sync) void SyncPortals() { - for (int i = 0; i < MAXPORTAL; i++) { + for (int i = 0; i < MaxPlayers; i++) { if (!Portals[i].open) continue; Player &player = Players[i]; diff --git a/Source/portal.h b/Source/portal.h index 30e05f6a8e0..04e72793e68 100644 --- a/Source/portal.h +++ b/Source/portal.h @@ -13,8 +13,6 @@ namespace devilution { // Defined in player.h, forward declared here to allow for functions which operate in the context of a player. struct Player; -#define MAXPORTAL 4 - struct Portal { bool open; Point position; @@ -23,7 +21,7 @@ struct Portal { bool setlvl; }; -extern Portal Portals[MAXPORTAL]; +extern Portal Portals[8]; void InitPortals(); void SetPortalStats(int i, bool o, Point position, int lvl, dungeon_type lvltype, bool isSetLevel); diff --git a/Source/storm/storm_net.cpp b/Source/storm/storm_net.cpp index 72bf4498bda..b3860c52cf5 100644 --- a/Source/storm/storm_net.cpp +++ b/Source/storm/storm_net.cpp @@ -51,7 +51,7 @@ bool SNetReceiveTurns(int arraysize, char **arraydata, size_t *arraydatabytes, u #ifndef NONET std::lock_guard lg(storm_net_mutex); #endif - if (arraysize != MAX_PLRS) + if (arraysize != MaxPlayers) UNIMPLEMENTED(); return dvlnet_inst->SNetReceiveTurns(arraydata, arraydatabytes, arrayplayerstatus); } diff --git a/Source/sync.cpp b/Source/sync.cpp index abd510ffceb..04807635007 100644 --- a/Source/sync.cpp +++ b/Source/sync.cpp @@ -211,11 +211,11 @@ bool IsEnemyIdValid(const Monster &monster, int enemyId) return false; } - if (enemyId < MAX_PLRS) { + if (enemyId < MaxPlayers) { return Players[enemyId].plractive; } - enemyId -= MAX_PLRS; + enemyId -= MaxPlayers; if (static_cast(enemyId) >= MaxMonsters) { return false; } diff --git a/assets/data/monstertags.clx b/assets/data/monstertags.clx index 0136fa40428d2c51dc4d9aae14accd90da3a2cb1..7799a5127bf2b3f07edfaecfbd673b6a7ab4da0f 100644 GIT binary patch literal 872 zcmajXF=_%q6o>IKi^xV&1#*gE4-MyDnNQ~N%DH!@T{!o|T)P{0#~bIK%S&vhSjF-j ztH!yCEq1|fvYYIJ-TK}7t-Jo$JH0RUar+W)|1-a1^~TdL){JQK_ASg3S&&nolk1cR zyqwO67GJXJ@QLA*F(G^s#)%X@@;SMV3?GdN;jB7*X!vkI2p@()B8B&TPOg2!`vXEa zs}AoO-s=*=d!d_1;T@loYsc_Tmk`dX!}o^ocZBeL*d`z4bCR>%WaxJ7Kbo}LG&NgNk8F_+>5whbm*kuO-1Cn29n1Z$*MHwz(|DZ4 zvGf9g!pR{2P?>N1(WxotqMS`h$V!7?t4N>{otknf%Egp~tTYI=iUcarsVUc@Tun*H ON`qjlNT3p(pYjWSf(l;% From 3f2a6680b40dd3164ba261a1623efebeaf67ffb5 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Sat, 18 Jan 2025 21:31:02 -0500 Subject: [PATCH 2/4] Remove random diffs --- Source/monster.cpp | 2 -- Source/multi.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/Source/monster.cpp b/Source/monster.cpp index c0c45e68c94..571643654d2 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -3262,7 +3262,6 @@ void InitLevelMonsters() ClrAllMonsters(); ActiveMonsterCount = 0; - totalmonsters = MaxMonsters; std::iota(std::begin(ActiveMonsters), std::end(ActiveMonsters), 0u); @@ -3554,7 +3553,6 @@ tl::expected InitMonsters() size_t numplacemonsters = na / 30; if (gbIsMultiplayer) numplacemonsters += numplacemonsters / 2; - if (ActiveMonsterCount + numplacemonsters > MaxMonsters - 10) numplacemonsters = MaxMonsters - 10 - ActiveMonsterCount; totalmonsters = ActiveMonsterCount + numplacemonsters; diff --git a/Source/multi.cpp b/Source/multi.cpp index aff38a227e7..758ecce3787 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -225,7 +225,6 @@ void MonsterSeeds() { sgdwGameLoops++; const uint32_t seed = (sgdwGameLoops >> 8) | (sgdwGameLoops << 24); - for (uint32_t i = 0; i < MaxMonsters; i++) Monsters[i].aiSeed = seed + i; } From 1a7d5147b9797c195f6ad346628d86e67cfa8629 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Sat, 18 Jan 2025 22:04:24 -0500 Subject: [PATCH 3/4] Solve circular header dependency --- Source/diablo.cpp | 1 + Source/interfac.cpp | 1 + Source/loadsave.cpp | 1 + Source/msg.cpp | 1 + Source/msg.h | 1 - Source/multi.cpp | 1 + Source/player.cpp | 1 + Source/portal.cpp | 4 ++-- Source/portal.h | 3 ++- 9 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 2b403b840a9..1427e4bcf7b 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -75,6 +75,7 @@ #include "pfile.h" #include "playerdat.hpp" #include "plrmsg.h" +#include "portal.h" #include "qol/chatlog.h" #include "qol/floatingnumbers.h" #include "qol/itemlabels.h" diff --git a/Source/interfac.cpp b/Source/interfac.cpp index b7b09811e64..862f7cb5892 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -27,6 +27,7 @@ #include "multi.h" #include "pfile.h" #include "plrmsg.h" +#include "portal.h" #include "utils/log.hpp" #include "utils/sdl_geometry.h" #include "utils/sdl_thread.h" diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index ce92303b269..755da85fa54 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -34,6 +34,7 @@ #include "mpq/mpq_common.hpp" #include "pfile.h" #include "playerdat.hpp" +#include "portal.h" #include "qol/stash.h" #include "stores.h" #include "utils/algorithm/container.hpp" diff --git a/Source/msg.cpp b/Source/msg.cpp index 1cb7a63f9f0..5919ad89b92 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -37,6 +37,7 @@ #include "pack.h" #include "pfile.h" #include "plrmsg.h" +#include "portal.h" #include "spells.h" #include "storm/storm_net.hpp" #include "sync.h" diff --git a/Source/msg.h b/Source/msg.h index 2287824c4fb..9343a0b5ba5 100644 --- a/Source/msg.h +++ b/Source/msg.h @@ -11,7 +11,6 @@ #include "items.h" #include "monster.h" #include "objects.h" -#include "portal.h" #include "quests.h" namespace devilution { diff --git a/Source/multi.cpp b/Source/multi.cpp index 758ecce3787..aee2af0299d 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -24,6 +24,7 @@ #include "options.h" #include "pfile.h" #include "plrmsg.h" +#include "portal.h" #include "qol/chatlog.h" #include "storm/storm_net.hpp" #include "sync.h" diff --git a/Source/player.cpp b/Source/player.cpp index 05d7c513a47..b36efd8d389 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -38,6 +38,7 @@ #include "objects.h" #include "options.h" #include "player.h" +#include "portal.h" #include "qol/autopickup.h" #include "qol/floatingnumbers.h" #include "qol/stash.h" diff --git a/Source/portal.cpp b/Source/portal.cpp index 1ad49acf467..cb9aa1b3030 100644 --- a/Source/portal.cpp +++ b/Source/portal.cpp @@ -12,7 +12,7 @@ namespace devilution { /** In-game state of portals. */ -Portal Portals[8]; +Portal Portals[MaxPlayers]; namespace { @@ -20,7 +20,7 @@ namespace { size_t portalindex; /** Coordinate of each player's portal in town. */ -Point PortalTownPosition[8] = { +Point PortalTownPosition[MaxPlayers] = { { 57, 40 }, { 59, 40 }, { 61, 40 }, diff --git a/Source/portal.h b/Source/portal.h index 04e72793e68..45949aa6add 100644 --- a/Source/portal.h +++ b/Source/portal.h @@ -7,6 +7,7 @@ #include "engine/point.hpp" #include "levels/gendung.h" +#include "multi.h" namespace devilution { @@ -21,7 +22,7 @@ struct Portal { bool setlvl; }; -extern Portal Portals[8]; +extern Portal Portals[MaxPlayers]; void InitPortals(); void SetPortalStats(int i, bool o, Point position, int lvl, dungeon_type lvltype, bool isSetLevel); From f11b7bdf1be79b2cfadbaa9d43f4c0b73b94fdf6 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Sun, 19 Jan 2025 01:26:55 -0500 Subject: [PATCH 4/4] Update colors --- Source/automap.cpp | 12 +++++------ Source/engine/render/scrollrt.cpp | 33 +++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Source/automap.cpp b/Source/automap.cpp index e4299cb89ca..6e609e21a9f 100644 --- a/Source/automap.cpp +++ b/Source/automap.cpp @@ -37,14 +37,14 @@ Point Automap; enum MapColors : uint8_t { /** color used to draw the player's arrow */ - MapColorsPlayer = (PAL8_ORANGE + 1), + MapColorsPlayer1 = (PAL8_ORANGE + 1), MapColorsPlayer2 = (PAL8_YELLOW + 1), MapColorsPlayer3 = (PAL8_RED + 1), MapColorsPlayer4 = (PAL8_BLUE + 1), - MapColorsPlayer5 = (PAL16_ORANGE + 1), - MapColorsPlayer6 = (PAL16_BEIGE + 1), - MapColorsPlayer7 = (PAL16_RED + 1), - MapColorsPlayer8 = (PAL16_BLUE + 1), + MapColorsPlayer5 = (PAL16_ORANGE + 2), + MapColorsPlayer6 = (PAL16_BEIGE + 2), + MapColorsPlayer7 = (PAL16_RED + 2), + MapColorsPlayer8 = (PAL16_BLUE + 2), /** color for bright map lines (doors, stairs etc.) */ MapColorsBright = PAL8_YELLOW, /** color for dim map lines/dots */ @@ -160,7 +160,7 @@ struct AutomapTile { } }; -uint8_t playerColors[] { MapColorsPlayer, MapColorsPlayer2, MapColorsPlayer3, MapColorsPlayer4, MapColorsPlayer5, MapColorsPlayer6, MapColorsPlayer7, MapColorsPlayer8 }; +uint8_t playerColors[] { MapColorsPlayer1, MapColorsPlayer2, MapColorsPlayer3, MapColorsPlayer4, MapColorsPlayer5, MapColorsPlayer6, MapColorsPlayer7, MapColorsPlayer8 }; /** * Maps from tile_id to automap type. diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index e32a9c2529a..ac57bb65df2 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -73,6 +73,20 @@ namespace devilution { +enum OutlineColors : uint8_t { + OutlineColorsPlayer1 = (PAL16_ORANGE + 7), + OutlineColorsPlayer2 = (PAL16_YELLOW + 7), + OutlineColorsPlayer3 = (PAL16_RED + 7), + OutlineColorsPlayer4 = (PAL16_BLUE + 7), + OutlineColorsPlayer5 = (PAL16_ORANGE + 5), + OutlineColorsPlayer6 = (PAL16_BEIGE + 5), + OutlineColorsPlayer7 = (PAL16_RED + 5), + OutlineColorsPlayer8 = (PAL16_BLUE + 5), + OutlineColorsObject = (PAL16_YELLOW + 2), + OutlineColorsTowner = (PAL16_BEIGE + 6), + OutlineColorsMonster = (PAL16_RED + 9), +}; + bool AutoMapShowItems; // DevilutionX extension. @@ -402,8 +416,19 @@ void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Po const ClxSprite sprite = player.currentSprite(); Point spriteBufferPosition = targetBufferPosition + player.getRenderingOffset(sprite); + uint8_t playerColor[] = { + OutlineColorsPlayer1, + OutlineColorsPlayer2, + OutlineColorsPlayer3, + OutlineColorsPlayer4, + OutlineColorsPlayer5, + OutlineColorsPlayer6, + OutlineColorsPlayer7, + OutlineColorsPlayer8 + }; + if (&player == PlayerUnderCursor) - ClxDrawOutlineSkipColorZero(out, 165, spriteBufferPosition, sprite); + ClxDrawOutlineSkipColorZero(out, playerColor[player.getId()], spriteBufferPosition, sprite); if (&player == MyPlayer && IsNoneOf(leveltype, DTYPE_NEST, DTYPE_CRYPT)) { ClxDraw(out, spriteBufferPosition, sprite); @@ -456,7 +481,7 @@ void DrawObject(const Surface &out, const Object &objectToDraw, Point tilePositi const Point screenPosition = targetBufferPosition + objectToDraw.getRenderingOffset(sprite, tilePosition); if (&objectToDraw == ObjectUnderCursor) { - ClxDrawOutlineSkipColorZero(out, 194, screenPosition, sprite); + ClxDrawOutlineSkipColorZero(out, OutlineColorsObject, screenPosition, sprite); } if (objectToDraw.applyLighting) { ClxDrawLight(out, screenPosition, sprite, lightTableIndex); @@ -659,7 +684,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe const Point position = targetBufferPosition + towner.getRenderingOffset(); const ClxSprite sprite = towner.currentSprite(); if (mi == pcursmonst) { - ClxDrawOutlineSkipColorZero(out, 166, position, sprite); + ClxDrawOutlineSkipColorZero(out, OutlineColorsTowner, position, sprite); } ClxDraw(out, position, sprite); return; @@ -684,7 +709,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe const Point monsterRenderPosition = targetBufferPosition + offset; if (mi == pcursmonst) { - ClxDrawOutlineSkipColorZero(out, 233, monsterRenderPosition, sprite); + ClxDrawOutlineSkipColorZero(out, OutlineColorsMonster, monsterRenderPosition, sprite); } DrawMonster(out, tilePosition, monsterRenderPosition, monster, lightTableIndex); }