DEADSOFTWARE

players: fix bot state loading
[d2df-sdl.git] / src / game / g_player.pas
index 64e61666557c23ca74ea1011820a08725ee4d525..3025ea549a1fe28480c9588c30c2094a1eee4f39 100644 (file)
@@ -31,11 +31,14 @@ const
   KEY_UP         = 3;
   KEY_DOWN       = 4;
   KEY_FIRE       = 5;
-  KEY_NEXTWEAPON = 6;
-  KEY_PREVWEAPON = 7;
-  KEY_OPEN       = 8;
-  KEY_JUMP       = 9;
-  KEY_CHAT       = 10;
+  KEY_OPEN       = 6;
+  KEY_JUMP       = 7;
+  KEY_CHAT       = 8;
+
+  WP_PREV        = 0;
+  WP_NEXT        = 1;
+  WP_FACT        = WP_PREV;
+  WP_LACT        = WP_NEXT;
 
   R_ITEM_BACKPACK   = 0;
   R_KEY_RED         = 1;
@@ -114,6 +117,7 @@ type
     Kills: Word;
     Color: TRGB;
     Spectator: Boolean;
+    UID: Word;
   end;
 
   TPlayerStatArray = Array of TPlayerStat;
@@ -338,6 +342,7 @@ type
     procedure   NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1);
     procedure   DoLerp(Level: Integer = 2);
     procedure   SetLerp(XTo, YTo: Integer);
+    procedure   ProcessWeaponAction(Action: Byte);
     procedure   QueueWeaponSwitch(Weapon: Byte);
     procedure   RealizeCurrentWeapon();
     procedure   FlamerOn;
@@ -849,148 +854,40 @@ begin
 end;
 
 function g_Player_CreateFromState (st: TStream): Word;
-var
-  a, i: Integer;
-  ok, Bot: Boolean;
-  b: Byte;
+  var a: Integer; ok, Bot: Boolean; pos: Int64;
 begin
-  result := 0;
-  if (st = nil) then exit; //???
+  assert(st <> nil);
 
-  // Ñèãíàòóðà èãðîêà
+  // check signature and entity type
+  pos := st.Position;
   if not utils.checkSign(st, 'PLYR') then raise XStreamError.Create('invalid player signature');
   if (utils.readByte(st) <> PLR_SAVE_VERSION) then raise XStreamError.Create('invalid player version');
-
-  // Áîò èëè ÷åëîâåê:
   Bot := utils.readBool(st);
+  st.Position := pos;
 
+  // find free player slot
   ok := false;
-  a := 0;
-
-  // Åñòü ëè ìåñòî â gPlayers:
-  for a := 0 to High(gPlayers) do if (gPlayers[a] = nil) then begin ok := true; break; end;
+  for a := 0 to High(gPlayers) do
+    if gPlayers[a] = nil then
+    begin
+      ok := true;
+      break;
+    end;
 
-  // Íåò ìåñòà - ðàñøèðÿåì gPlayers
+  // allocate player slot
   if not ok then
   begin
     SetLength(gPlayers, Length(gPlayers)+1);
     a := High(gPlayers);
   end;
 
-  // Ñîçäàåì îáúåêò èãðîêà
+  // create entity and load state
   if Bot then
     gPlayers[a] := TBot.Create()
   else
     gPlayers[a] := TPlayer.Create();
-  gPlayers[a].FIamBot := Bot;
-  gPlayers[a].FPhysics := True;
-
-  // UID èãðîêà
-  gPlayers[a].FUID := utils.readWord(st);
-  // Èìÿ èãðîêà
-  gPlayers[a].FName := utils.readStr(st);
-  // Êîìàíäà
-  gPlayers[a].FTeam := utils.readByte(st);
-  gPlayers[a].FPreferredTeam := gPlayers[a].FTeam;
-  // Æèâ ëè
-  gPlayers[a].FAlive := utils.readBool(st);
-  // Èçðàñõîäîâàë ëè âñå æèçíè
-  gPlayers[a].FNoRespawn := utils.readBool(st);
-  // Íàïðàâëåíèå
-  b := utils.readByte(st);
-  if b = 1 then gPlayers[a].FDirection := TDirection.D_LEFT else gPlayers[a].FDirection := TDirection.D_RIGHT; // b = 2
-  // Çäîðîâüå
-  gPlayers[a].FHealth := utils.readLongInt(st);
-  // Ôîðà
-  gPlayers[a].FHandicap := utils.readLongInt(st);
-  // Æèçíè
-  gPlayers[a].FLives := utils.readByte(st);
-  // Áðîíÿ
-  gPlayers[a].FArmor := utils.readLongInt(st);
-  // Çàïàñ âîçäóõà
-  gPlayers[a].FAir := utils.readLongInt(st);
-  // Çàïàñ ãîðþ÷åãî
-  gPlayers[a].FJetFuel := utils.readLongInt(st);
-  // Áîëü
-  gPlayers[a].FPain := utils.readLongInt(st);
-  // Óáèë
-  gPlayers[a].FKills := utils.readLongInt(st);
-  // Óáèë ìîíñòðîâ
-  gPlayers[a].FMonsterKills := utils.readLongInt(st);
-  // Ôðàãîâ
-  gPlayers[a].FFrags := utils.readLongInt(st);
-  // Ôðàãîâ ïîäðÿä
-  gPlayers[a].FFragCombo := utils.readByte(st);
-  // Âðåìÿ ïîñëåäíåãî ôðàãà
-  gPlayers[a].FLastFrag := utils.readLongWord(st);
-  // Ñìåðòåé
-  gPlayers[a].FDeath := utils.readLongInt(st);
-  // Êàêîé ôëàã íåñåò
-  gPlayers[a].FFlag := utils.readByte(st);
-  // Íàøåë ñåêðåòîâ
-  gPlayers[a].FSecrets := utils.readLongInt(st);
-  // Òåêóùåå îðóæèå
-  gPlayers[a].FCurrWeap := utils.readByte(st);
-  // Ñëåäóþùåå æåëàåìîå îðóæèå
-  gPlayers[a].FNextWeap := utils.readWord(st);
-  // ...è ïàóçà
-  gPlayers[a].FNextWeapDelay := utils.readByte(st);
-  // Âðåìÿ çàðÿäêè BFG
-  gPlayers[a].FBFGFireCounter := utils.readSmallInt(st);
-  // Áóôåð óðîíà
-  gPlayers[a].FDamageBuffer := utils.readLongInt(st);
-  // Ïîñëåäíèé óäàðèâøèé
-  gPlayers[a].FLastSpawnerUID := utils.readWord(st);
-  // Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà
-  gPlayers[a].FLastHit := utils.readByte(st);
-  // Îáúåêò èãðîêà:
-  Obj_LoadState(@gPlayers[a].FObj, st);
-  // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ
-  for i := A_BULLETS to A_HIGH do gPlayers[a].FAmmo[i] := utils.readWord(st);
-  // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ
-  for i := A_BULLETS to A_HIGH do gPlayers[a].FMaxAmmo[i] := utils.readWord(st);
-  // Íàëè÷èå îðóæèÿ
-  for i := WP_FIRST to WP_LAST do gPlayers[a].FWeapon[i] := utils.readBool(st);
-  // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ
-  for i := WP_FIRST to WP_LAST do gPlayers[a].FReloading[i] := utils.readWord(st);
-  // Íàëè÷èå ðþêçàêà
-  if utils.readBool(st) then Include(gPlayers[a].FRulez, R_ITEM_BACKPACK);
-  // Íàëè÷èå êðàñíîãî êëþ÷à
-  if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_RED);
-  // Íàëè÷èå çåëåíîãî êëþ÷à
-  if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_GREEN);
-  // Íàëè÷èå ñèíåãî êëþ÷à
-  if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_BLUE);
-  // Íàëè÷èå áåðñåðêà
-  if utils.readBool(st) then Include(gPlayers[a].FRulez, R_BERSERK);
-  // Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ
-  for i := MR_SUIT to MR_MAX do gPlayers[a].FMegaRulez[i] := utils.readLongWord(st);
-  // Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà
-  for i := T_RESPAWN to T_FLAGCAP do gPlayers[a].FTime[i] := utils.readLongWord(st);
-
-  // Íàçâàíèå ìîäåëè:
-  gPlayers[a].FActualModelName := utils.readStr(st);
-  // Öâåò ìîäåëè
-  gPlayers[a].FColor.R := utils.readByte(st);
-  gPlayers[a].FColor.G := utils.readByte(st);
-  gPlayers[a].FColor.B := utils.readByte(st);
-  // Îáíîâëÿåì ìîäåëü èãðîêà
-  gPlayers[a].SetModel(gPlayers[a].FActualModelName);
-
-  // Íåò ìîäåëè - ñîçäàíèå íåâîçìîæíî
-  if (gPlayers[a].FModel = nil) then
-  begin
-    gPlayers[a].Free();
-    gPlayers[a] := nil;
-    g_FatalError(Format(_lc[I_GAME_ERROR_MODEL], [gPlayers[a].FActualModelName]));
-    exit;
-  end;
-
-  // Åñëè êîìàíäíàÿ èãðà - êðàñèì ìîäåëü â öâåò êîìàíäû
-  if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
-    gPlayers[a].FModel.Color := TEAMCOLOR[gPlayers[a].FTeam]
-  else
-    gPlayers[a].FModel.Color := gPlayers[a].FColor;
+  gPlayers[a].FPhysics := True; // ???
+  gPlayers[a].LoadState(st);
 
   result := gPlayers[a].FUID;
 end;
@@ -1521,6 +1418,7 @@ begin
         Color := gPlayers[a].FModel.Color;
         Lives := gPlayers[a].FLives;
         Spectator := gPlayers[a].FSpectator;
+        UID := gPlayers[a].FUID;
       end;
     end;
 end;
@@ -3770,6 +3668,15 @@ begin
               FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.Blood.Kind);
 end;
 
+procedure TPlayer.ProcessWeaponAction(Action: Byte);
+begin
+  if g_Game_IsClient then Exit;
+  case Action of
+    WP_PREV: PrevWeapon();
+    WP_NEXT: NextWeapon();
+  end;
+end;
+
 procedure TPlayer.QueueWeaponSwitch(Weapon: Byte);
 begin
   if g_Game_IsClient then Exit;
@@ -5060,10 +4967,6 @@ begin
     FIncCam := FIncCam*i;
   end;
 
-  // no need to do that each second frame, weapon queue will take care of it
-  if FAlive and FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon();
-  if FAlive and FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon();
-
   if gTime mod (GAME_TICK*2) <> 0 then
   begin
     if (FObj.Vel.X = 0) and FAlive then
@@ -5090,8 +4993,6 @@ begin
     // Let alive player do some actions
     if FKeys[KEY_LEFT].Pressed then Run(TDirection.D_LEFT);
     if FKeys[KEY_RIGHT].Pressed then Run(TDirection.D_RIGHT);
-    //if FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon();
-    //if FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon();
     if FKeys[KEY_FIRE].Pressed and AnyServer then Fire()
     else
     begin