From 01d549d71767db0ab6ae05c748a3d970e59b779b Mon Sep 17 00:00:00 2001 From: Gerald Buttinger Date: Thu, 11 May 2023 22:07:28 +0200 Subject: [PATCH] fix: multiplayer game ending if host is defeated now host will lose all units/structures, become observer and will be kicked to lobby, once other players finish the game. --- src/house.c | 20 ++++++++++++++++++++ src/mods/multiplayer.c | 11 +++++++++++ src/mods/multiplayer.h | 1 + src/net/server.c | 14 ++++++++++++-- src/newui/menubar.c | 34 +++++++++++++++++++++++++++++----- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/house.c b/src/house.c index f5b1fe3b9..84117396d 100644 --- a/src/house.c +++ b/src/house.c @@ -491,6 +491,26 @@ House_Server_ReassignToAI(enum HouseType houseID) } } +void +House_Server_Eliminate(enum HouseType houseID) +{ + House *h = House_Get_ByIndex(houseID); + + PoolFindStruct find; + + for (Structure *s = Structure_FindFirst(&find, houseID, STRUCTURE_INVALID); + s != NULL; + s = Structure_FindNext(&find)) { + Structure_Damage(s, s->o.hitpoints * 2, 0); + } + + for (Unit *u = Unit_FindFirst(&find, houseID, UNIT_INVALID); + u != NULL; + u = Unit_FindNext(&find)) { + Unit_Damage(u, u->o.hitpoints * 2, 0); + } +} + void House_Client_UpdateRadarState(void) { diff --git a/src/mods/multiplayer.c b/src/mods/multiplayer.c index 0d58173f7..d5910788f 100644 --- a/src/mods/multiplayer.c +++ b/src/mods/multiplayer.c @@ -131,6 +131,17 @@ Multiplayer_Prepare(void) } } +bool Multiplayer_IsAnyHouseLeftPlaying(void) +{ + bool houseLeft = false; + for (enum HouseType h = HOUSE_HARKONNEN; h < HOUSE_MAX; h++) { + if (g_multiplayer.state[h] == MP_HOUSE_PLAYING) + houseLeft = true; + } + + return houseLeft; +} + enum MapGeneratorMode Multiplayer_GenerateMap(enum MapGeneratorMode mode) { diff --git a/src/mods/multiplayer.h b/src/mods/multiplayer.h index f771307c3..0629580b0 100644 --- a/src/mods/multiplayer.h +++ b/src/mods/multiplayer.h @@ -44,5 +44,6 @@ extern void Multiplayer_Init(void); extern bool Multiplayer_IsHouseAvailable(enum HouseType houseID); extern bool Multiplayer_GenHouses(struct SkirmishData *sd); extern enum MapGeneratorMode Multiplayer_GenerateMap(enum MapGeneratorMode mode); +extern bool Multiplayer_IsAnyHouseLeftPlaying(void); #endif diff --git a/src/net/server.c b/src/net/server.c index 441b18301..180324412 100644 --- a/src/net/server.c +++ b/src/net/server.c @@ -710,13 +710,14 @@ Server_Send_WinLose(enum HouseType houseID, bool win) g_client_houses &= ~(1 << houseID); if (!win) { - House_Server_ReassignToAI(houseID); + // this is not working: House_Server_ReassignToAI(houseID); + // so we blow up everything instead. + House_Server_Eliminate(houseID); } } if (houseID == g_playerHouseID) { MenuBar_DisplayWinLose(win); - Server_ReturnToLobbyNow(win); } else { unsigned char src[2]; unsigned char *buf = src; @@ -726,6 +727,15 @@ Server_Send_WinLose(enum HouseType houseID, bool win) assert(buf - src == sizeof(src)); Server_BufferGameEvent(1 << houseID, sizeof(src), src); + + // If no other houses are left playing, + // the host might have lost earlier and might + // still be waiting for the game to end. + // So we send him back to the lobby. + if (!Multiplayer_IsAnyHouseLeftPlaying() && g_gameOverlay == GAMEOVERLAY_NONE) { + g_gameMode = GM_LOSE; + GUI_ChangeSelectionType(SELECTIONTYPE_MENTAT); + } } } diff --git a/src/newui/menubar.c b/src/newui/menubar.c index ea23e3d93..dcce59d22 100644 --- a/src/newui/menubar.c +++ b/src/newui/menubar.c @@ -40,6 +40,7 @@ #include "../tools/random_xorshift.h" #include "../video/video.h" #include "../wsa.h" +#include "../mods/multiplayer.h" static enum { RADAR_ANIMATION_NONE, @@ -362,8 +363,19 @@ MenuBar_DisplayWinLose(bool win) Video_UngrabCursor(); Audio_PlayVoice(voiceID); - snprintf(s_modal_message_buf, sizeof(s_modal_message_buf), "%s", - String_Get_ByIndex(stringID)); + + if (!win && g_campaign_selected == CAMPAIGNID_MULTIPLAYER && Net_HasServerRole() && Multiplayer_IsAnyHouseLeftPlaying()) { + snprintf( + s_modal_message_buf, + sizeof(s_modal_message_buf), "%s %s", + String_Get_ByIndex(stringID), + "As host you will become observer until the other players finish the game." + ); + } + else { + snprintf(s_modal_message_buf, sizeof(s_modal_message_buf), "%s", + String_Get_ByIndex(stringID)); + } MenuBar_PrepareModalMessage(SHAPE_INVALID); } @@ -371,9 +383,21 @@ void MenuBar_TickWinLoseOverlay(void) { if (MenuBar_TickModalMessage()) { - g_gameMode = (g_gameOverlay == GAMEOVERLAY_WIN) ? GM_WIN : GM_LOSE; - g_gameOverlay = GAMEOVERLAY_NONE; - GUI_ChangeSelectionType(SELECTIONTYPE_MENTAT); + bool finishMap = true; + + // Multiplayer host can only end map, if all houses have either won or lost. + if (g_campaign_selected == CAMPAIGNID_MULTIPLAYER && Net_HasServerRole() && Multiplayer_IsAnyHouseLeftPlaying()) { + finishMap = false; + } + + if (finishMap) { + g_gameMode = (g_gameOverlay == GAMEOVERLAY_WIN) ? GM_WIN : GM_LOSE; + g_gameOverlay = GAMEOVERLAY_NONE; + GUI_ChangeSelectionType(SELECTIONTYPE_MENTAT); + } + else { + g_gameOverlay = GAMEOVERLAY_NONE; + } } }