DEADSOFTWARE

survival/lms fixes
authorfgsfds <pvt.fgsfds@gmail.com>
Thu, 27 Feb 2020 17:44:52 +0000 (20:44 +0300)
committerfgsfds <pvt.fgsfds@gmail.com>
Thu, 27 Feb 2020 17:44:52 +0000 (20:44 +0300)
* people joining mid game do not spawn

* warmup time is displayed on both clients and server

* monsters are now intangible during warmup

* clients use the proper spectator mode when dead in survival

* raised protocol version to 185

src/game/g_game.pas
src/game/g_language.pas
src/game/g_monsters.pas
src/game/g_net.pas
src/game/g_netmsg.pas
src/game/g_player.pas

index 4a79f98ebfd67d496271b8ed577b844402f19b2c..94fe8831712df01b6c81f8e557b82f89ce691e2a 100644 (file)
@@ -3769,10 +3769,6 @@ begin
               else gPlayers[i].DrawIndicator(gPlayers[i].GetColor);
     end;
 
-  if p.FSpectator then
-    e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4,
-                         p.GameY + PLAYER_RECT_CY - 4,
-                         'X', gStdFont, 255, 255, 255, 1, True);
   {
   for a := 0 to High(gCollideMap) do
     for b := 0 to High(gCollideMap[a]) do
@@ -4260,10 +4256,7 @@ begin
     if g_Game_IsClient then
     begin
       if NetPlrUID1 > -1 then
-      begin
         MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
-        gPlayer1 := g_Player_Get(NetPlrUID1);
-      end;
       Exit;
     end;
 
@@ -4337,8 +4330,12 @@ begin
       g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
       g_Player_Remove(Pl.UID);
       g_Net_Slist_ServerPlayerLeaves();
-    end else
+    end
+    else
+    begin
+      gSpectLatchPID2 := Pl.UID;
       gPlayer2 := nil;
+    end;
     Exit;
   end;
   Pl := gPlayer1;
@@ -4353,6 +4350,7 @@ begin
       g_Net_Slist_ServerPlayerLeaves();
     end else
     begin
+      gSpectLatchPID1 := Pl.UID;
       gPlayer1 := nil;
       MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
     end;
@@ -4700,6 +4698,11 @@ begin
   // create (or update) map/resource databases
   g_Res_CreateDatabases(true);
 
+  gLMSRespawn := LMS_RESPAWN_NONE;
+  gLMSRespawnTime := 0;
+  gSpectLatchPID1 := 0;
+  gSpectLatchPID2 := 0;
+
 // Ñòàðòóåì êëèåíò
   if not g_Net_Connect(Addr, Port) then
   begin
@@ -4839,9 +4842,6 @@ begin
     Exit;
   end;
 
-  gLMSRespawn := LMS_RESPAWN_NONE;
-  gLMSRespawnTime := 0;
-
   g_Player_Init();
   NetState := NET_STATE_GAME;
   MC_SEND_FullStateRequest;
@@ -4992,8 +4992,8 @@ begin
   NetTimeToUpdate := 1;
   NetTimeToReliable := 0;
   NetTimeToMaster := NetMasterRate;
-  gLMSRespawn := LMS_RESPAWN_NONE;
-  gLMSRespawnTime := 0;
+  gSpectLatchPID1 := 0;
+  gSpectLatchPID2 := 0;
   gMissionFailed := False;
   gNextMap := '';
 
@@ -5011,15 +5011,21 @@ begin
 
   g_Game_SpectateCenterView();
 
-  if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
+  if g_Game_IsServer then
   begin
-    gLMSRespawn := LMS_RESPAWN_WARMUP;
-    gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
-    gLMSSoftSpawn := True;
-    if NetMode = NET_SERVER then
-      MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
+    if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
+    begin
+      gLMSRespawn := LMS_RESPAWN_WARMUP;
+      gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
+      gLMSSoftSpawn := True;
+      if g_Game_IsNet then
+        MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime);
+    end
     else
-      g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
+    begin
+      gLMSRespawn := LMS_RESPAWN_NONE;
+      gLMSRespawnTime := 0;
+    end;
   end;
 
   if NetMode = NET_SERVER then
@@ -5168,13 +5174,6 @@ end;
 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
 var
   i, n, nb, nr: Integer;
-
-  function monRespawn (mon: TMonster): Boolean;
-  begin
-    result := false; // don't stop
-    if not mon.FNoRespawn then mon.Respawn();
-  end;
-
 begin
   if not g_Game_IsServer then Exit;
   if gLMSRespawn = LMS_RESPAWN_NONE then Exit;
@@ -5235,17 +5234,14 @@ begin
       gPlayers[i].Frags := 0;
       gPlayers[i].RecallState;
     end;
-    if (gPlayer1 = nil) and (gLMSPID1 > 0) then
-      gPlayer1 := g_Player_Get(gLMSPID1);
-    if (gPlayer2 = nil) and (gLMSPID2 > 0) then
-      gPlayer2 := g_Player_Get(gLMSPID2);
+    if (gPlayer1 = nil) and (gSpectLatchPID1 > 0) then
+      gPlayer1 := g_Player_Get(gSpectLatchPID1);
+    if (gPlayer2 = nil) and (gSpectLatchPID2 > 0) then
+      gPlayer2 := g_Player_Get(gSpectLatchPID2);
   end;
 
   g_Items_RestartRound();
 
-
-  g_Mons_ForEach(monRespawn);
-
   gLMSSoftSpawn := False;
 end;
 
index e17b4c2420bad2b24c77bc48966fa6c511f15353..5a24323de0c66ce0f989a100c9a60672d926c1eb 100644 (file)
@@ -80,6 +80,7 @@ type
     I_GAME_SECRETS,
     I_GAME_MONSTERS_TOTAL,
     I_GAME_SECRETS_TOTAL,
+    I_GAME_WARMUP,
 
     I_GAME_CHEAT_GODMODE,
     I_GAME_CHEAT_WEAPONS,
@@ -764,6 +765,8 @@ const
                                        'Âñåãî ìîíñòðîâ óáèòî:'),
     ('GAME SECRETS TOTAL',             'Total secrets found:',
                                        'Âñåãî ñåêðåòîâ íàéäåíî:'),
+    ('GAME WARMUP',                    'Warmup',
+                                       'Ïîäãîòîâêà'),
 
     ('GAME CHEAT GODMODE',             'MACLEOD',
                                        'ÃÎÐÅÖ'),
index 878d00df54fd550ab129c634a91405857b5b6635..e7ee1d0eb784275870b6aa872acb8158049d3256 100644 (file)
@@ -1993,6 +1993,9 @@ var
 begin
   Result := False;
 
+// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup
+  if (gLMSRespawn = LMS_RESPAWN_WARMUP) then exit;
+
 // Óìèðàåò, óìåð èëè âîñêðåøàåòñÿ => óðîí äåëàòü íåêîìó:
   if (FState = MONSTATE_DEAD) or (FState = MONSTATE_DIE) or (FState = MONSTATE_REVIVE) then
     Exit;
@@ -2450,6 +2453,9 @@ label
 begin
   fall := True;
 
+// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup
+  if (gLMSRespawn = LMS_RESPAWN_WARMUP) then exit;
+
 // Ðûáû "ëåòàþò" òîëüêî â âîäå:
   if FMonsterType = MONSTER_FISH then
     if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then
@@ -3439,6 +3445,10 @@ begin
   sx := 0; // SHUT UP COMPILER
   sy := 0;
   fall := True;
+
+// Ìîíñòð ñòàòè÷åí ïîêà èäåò warmup
+  if (gLMSRespawn = LMS_RESPAWN_WARMUP) then exit;
+
 // Ðûáû "ëåòàþò" òîëüêî â âîäå:
   if FMonsterType = MONSTER_FISH then
     if g_Obj_CollidePanel(@FObj, 0, 0, PANEL_WATER or PANEL_ACID1 or PANEL_ACID2) then
index d2bc5a2be06a30cf2111c7189d9e1ad0fed0e78e..6226f00f3d9cc23e084892717c30dd44b7cf3564 100644 (file)
@@ -21,7 +21,7 @@ uses
   e_log, e_msg, utils, ENet, Classes, md5, MAPDEF{$IFDEF USE_MINIUPNPC}, miniupnpc;{$ELSE};{$ENDIF}
 
 const
-  NET_PROTOCOL_VER = 184;
+  NET_PROTOCOL_VER = 185;
 
   NET_MAXCLIENTS = 24;
   NET_CHANS = 12;
index 1fd6f7c5a8d3e7a6be8a0dad2ce9ea3980b2b78c..92c45168c620f9c1f450c3e5ffc650f1b20ad359 100644 (file)
@@ -112,6 +112,7 @@ const
   NET_EV_PLAYER_TOUCH = 18;
   NET_EV_SECRET       = 19;
   NET_EV_INTER_READY  = 20;
+  NET_EV_LMS_NOSPAWN  = 21;
 
   NET_VE_STARTED      = 1;
   NET_VE_PASSED       = 2;
@@ -429,37 +430,26 @@ begin
     Name := PName;
     FClientID := C^.ID;
     // round in progress, don't spawn
-    if (gGameSettings.MaxLives > 0) and (gLMSRespawn = LMS_RESPAWN_NONE) then
-    begin
-      Lives := 0;
-      FNoRespawn := True;
-      Spectate;
-      FWantsInGame := True; // TODO: look into this later
-      C^.WaitForFirstSpawn := true;
-    end
-    else
-    begin
-      e_LogWritefln('*** client #%u (cid #%u) authenticated...', [C.ID, C.Player]);
-      //e_LogWritefln('spawning player with pid #%u...', [PID]);
-      //Respawn(gGameSettings.GameType = GT_SINGLE);
-      //k8: no, do not spawn a player yet, wait for "request full state" packet
-      Lives := 0;
-      Spectate;
-      FNoRespawn := True;
-      // `FWantsInGame` seems to mean "spawn the player on the next occasion".
-      // that is, if we'll set it to `true`, the player can be spawned after
-      // warmup time ran out, for example, regardless of the real player state.
-      // also, this seems to work only for the initial connection. further
-      // map changes could initiate resource downloading, but the player will
-      // be spawned immediately.
-      // the proper solution will require another player state, "ephemeral".
-      // the player should start any map in "ephemeral" state, and turned into
-      // real mobj only when they sent a special "i am ready" packet. this packet
-      // must be sent after receiving the full state, so the player will get a full
-      // map view before going into game.
-      FWantsInGame := false;
-      C^.WaitForFirstSpawn := true;
-    end;
+    e_LogWritefln('*** client #%u (cid #%u) authenticated...', [C.ID, C.Player]);
+    //e_LogWritefln('spawning player with pid #%u...', [PID]);
+    //Respawn(gGameSettings.GameType = GT_SINGLE);
+    //k8: no, do not spawn a player yet, wait for "request full state" packet
+    Lives := 0;
+    Spectate;
+    FNoRespawn := True;
+    // `FWantsInGame` seems to mean "spawn the player on the next occasion".
+    // that is, if we'll set it to `true`, the player can be spawned after
+    // warmup time ran out, for example, regardless of the real player state.
+    // also, this seems to work only for the initial connection. further
+    // map changes could initiate resource downloading, but the player will
+    // be spawned immediately.
+    // the proper solution will require another player state, "ephemeral".
+    // the player should start any map in "ephemeral" state, and turned into
+    // real mobj only when they sent a special "i am ready" packet. this packet
+    // must be sent after receiving the full state, so the player will get a full
+    // map view before going into game.
+    FWantsInGame := false;
+    C^.WaitForFirstSpawn := true;
   end;
 
   //if not C^.WaitForFirstSpawn then
@@ -496,7 +486,18 @@ begin
   C.WaitForFirstSpawn := false;
   plr.FNoRespawn := false;
   plr.FWantsInGame := true; // TODO: look into this later
-  plr.Respawn(False);
+
+  if (gGameSettings.MaxLives > 0) and (gLMSRespawn = LMS_RESPAWN_NONE) then
+  begin
+    plr.Spectate;
+    MH_SEND_GameEvent(NET_EV_LMS_NOSPAWN, 0, 'N', C.ID);
+  end
+  else
+  begin
+    plr.Respawn(False);
+    if gLMSRespawn = LMS_RESPAWN_WARMUP then
+      MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime, 'N', C.ID);
+  end;
 end;
 
 
@@ -593,7 +594,12 @@ begin
     NET_CHEAT_SPECTATE:
     begin
       if Pl.FSpectator then
-        Pl.Respawn(False)
+      begin
+        if (gGameSettings.MaxLives = 0) or (gLMSRespawn = LMS_RESPAWN_WARMUP) then
+          Pl.Respawn(False)
+        else
+          MH_SEND_GameEvent(NET_EV_LMS_NOSPAWN, Pl.UID);
+      end
       else
         Pl.Spectate;
     end;
@@ -815,12 +821,6 @@ begin
 
   if CreatePlayers and (ID >= 0) then NetClients[ID].State := NET_STATE_GAME;
 
-  if gLMSRespawn > LMS_RESPAWN_NONE then
-  begin
-    e_LogWritefln('*** client #%u (cid #%u) WARMUP', [ID, NetClients[ID].Player]);
-    MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000, 'N', ID);
-  end;
-
   g_Net_Flush();
 end;
 
@@ -1768,6 +1768,8 @@ begin
 
   gTime := EvTime;
 
+  e_LogWritefln('EVENT %d %d', [EvType, EvNum]);
+
   if (g_Res_received_map_start <> 0) then
   begin
     if (g_Res_received_map_start < 0) then exit;
@@ -1777,6 +1779,7 @@ begin
       NET_EV_MAPEND: goodCmd := true;
       NET_EV_PLAYER_KICK: goodCmd := true;
       NET_EV_PLAYER_BAN: goodCmd := true;
+      NET_EV_LMS_WARMUP: goodCmd := true;
     end;
     if not goodCmd then exit;
   end;
@@ -1813,6 +1816,8 @@ begin
 
     NET_EV_MAPEND:
     begin
+      gLMSRespawn := LMS_RESPAWN_NONE;
+      gLMSRespawnTime := 0;
       if (g_Res_received_map_start <> 0) then
       begin
         g_Res_received_map_start := -1;
@@ -1857,7 +1862,18 @@ begin
       end;
 
     NET_EV_LMS_WARMUP:
-      g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [EvNum]), True);
+    begin
+      if EvNum > 0 then
+      begin
+        gLMSRespawn := LMS_RESPAWN_WARMUP;
+        gLMSRespawnTime := gTime + EvNum;
+        g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [EvNum div 1000]), True);
+      end
+      else if gPlayer1 = nil then
+      begin
+        g_Console_Add(_lc[I_PLAYER_SPECT4], True);
+      end;
+    end;
 
     NET_EV_LMS_SURVIVOR:
       g_Console_Add('*** ' + _lc[I_MESSAGE_LMS_SURVIVOR] + ' ***', True);
@@ -1943,6 +1959,7 @@ begin
     NET_EV_LMS_START:
     begin
       g_Player_RemoveAllCorpses;
+      gLMSRespawn := LMS_RESPAWN_NONE;
       g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
     end;
 
@@ -1963,6 +1980,9 @@ begin
     NET_EV_LMS_DRAW:
       g_Game_Message(_lc[I_GAME_WIN_DRAW], 144);
 
+    NET_EV_LMS_NOSPAWN:
+      g_Console_Add(_lc[I_PLAYER_SPECT4], True);
+
     NET_EV_KILLCOMBO:
       g_Game_Announce_KillCombo(EvNum);
 
@@ -2328,21 +2348,27 @@ begin
     begin
       if Pl = gPlayer1 then
       begin
-        gLMSPID1 := UID;
+        gSpectLatchPID1 := UID;
         gPlayer1 := nil;
       end;
       if Pl = gPlayer2 then
       begin
-        gLMSPID2 := UID;
+        gSpectLatchPID2 := UID;
         gPlayer2 := nil;
       end;
     end
     else
     begin
-      if (gPlayer1 = nil) and (gLMSPID1 > 0) then
-        gPlayer1 := g_Player_Get(gLMSPID1);
-      if (gPlayer2 = nil) and (gLMSPID2 > 0) then
-        gPlayer2 := g_Player_Get(gLMSPID2);
+      if (gPlayer1 = nil) and (gSpectLatchPID1 > 0) and (UID = gSpectLatchPID1) then
+      begin
+        gPlayer1 := Pl;
+        gSpectLatchPID1 := 0;
+      end;
+      if (gPlayer2 = nil) and (gSpectLatchPID2 > 0) and (UID = gSpectLatchPID2) then
+      begin
+        gPlayer2 := Pl;
+        gSpectLatchPID2 := 0;
+      end;
     end;
     FGhost := M.ReadByte() <> 0;
     FPhysics := M.ReadByte() <> 0;
index 94ca02efbd7372227be18b606ad975f94c2f0673..d9dd8871a953815a003809dbeacb6d231539f1e7 100644 (file)
@@ -560,8 +560,8 @@ var
   gPlayerIndicator: Integer = 1;
   gPlayerIndicatorStyle: Integer = 0;
   gNumBots: Word = 0;
-  gLMSPID1: Word = 0;
-  gLMSPID2: Word = 0;
+  gSpectLatchPID1: Word = 0;
+  gSpectLatchPID2: Word = 0;
   MAX_RUNVEL: Integer = 8;
   VEL_JUMP: Integer = 10;
   SHELL_TIMEOUT: Cardinal = 60000;
@@ -2766,7 +2766,14 @@ begin
       e_CharFont_PrintEx(gMenuSmallFont, X-16-tw, Y+32, s, _RGB(255, 0, 0));
     end;
 
-    if gShowLives and (gGameSettings.MaxLives > 0) then
+    if gLMSRespawn = LMS_RESPAWN_WARMUP then
+    begin
+      s := _lc[I_GAME_WARMUP];
+      e_CharFont_GetSize(gMenuFont, s, tw, th);
+      s := s + ': ' + IntToStr((gLMSRespawnTime - gTime) div 1000);
+      e_CharFont_PrintEx(gMenuFont, X-64-tw, SY-32, s, _RGB(0, 255, 0));
+    end
+    else if gShowLives and (gGameSettings.MaxLives > 0) then
     begin
       s := IntToStr(Lives);
       e_CharFont_GetSize(gMenuFont, s, tw, th);
@@ -3660,7 +3667,7 @@ begin
     if srv and (OldLR = LMS_RESPAWN_NONE) and (gLMSRespawn > LMS_RESPAWN_NONE) then
     begin
       if NetMode = NET_SERVER then
-        MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
+        MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime)
       else
         g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
     end;
@@ -4706,9 +4713,9 @@ begin
   FSpectatePlayer := -1;
   FSpawned := True;
 
-  if (gPlayer1 = nil) and (gLMSPID1 = FUID) then
+  if (gPlayer1 = nil) and (gSpectLatchPID1 = FUID) then
     gPlayer1 := self;
-  if (gPlayer2 = nil) and (gLMSPID2 = FUID) then
+  if (gPlayer2 = nil) and (gSpectLatchPID2 = FUID) then
     gPlayer2 := self;
 
   if g_Game_IsNet then
@@ -4745,12 +4752,12 @@ begin
   begin
     if Self = gPlayer1 then
     begin
-      gLMSPID1 := FUID;
+      gSpectLatchPID1 := FUID;
       gPlayer1 := nil;
-    end;
-    if Self = gPlayer2 then
+    end
+    else if Self = gPlayer2 then
     begin
-      gLMSPID2 := FUID;
+      gSpectLatchPID2 := FUID;
       gPlayer2 := nil;
     end;
   end;