diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index c1454c81d7b5a3454b011f716fc2460e87c8d314..89e3deee913bc70cc431c07d9a8c6bdb777b5b16 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
procedure BFGHit();
function GetFlag(Flag: Byte): Boolean;
procedure SetFlag(Flag: Byte);
- function DropFlag(Silent: Boolean = True): Boolean;
+ function DropFlag(Silent: Boolean = True; DoThrow: Boolean = False): Boolean;
+ function TryDropFlag(): Boolean;
procedure AllRulez(Health: Boolean);
procedure RestoreHealthArmor();
procedure FragCombo();
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;
DoLerp(4);
if NetServer then
- if FClientID >= 0 then
+ if (FClientID >= 0) and (NetClients[FClientID].Peer <> nil) then
begin
FPing := NetClients[FClientID].Peer^.lastRoundTripTime;
if NetClients[FClientID].Peer^.packetsSent > 0 then
FModel.SetFlag(FFlag);
end;
-function TPlayer.DropFlag(Silent: Boolean = True): Boolean;
+function TPlayer.TryDropFlag(): Boolean;
+begin
+ if LongBool(gGameSettings.Options and GAME_OPTION_ALLOWDROPFLAG) then
+ Result := DropFlag(False, LongBool(gGameSettings.Options and GAME_OPTION_THROWFLAG))
+ else
+ Result := False;
+end;
+
+function TPlayer.DropFlag(Silent: Boolean = True; DoThrow: Boolean = False): Boolean;
var
s: String;
a: Byte;
+ xv, yv: Integer;
begin
Result := False;
if (not g_Game_IsServer) or (FFlag = FLAG_NONE) then
Direction := FDirection;
State := FLAG_STATE_DROPPED;
Count := FLAG_TIME;
- g_Obj_Push(@Obj, (FObj.Vel.X div 2)-2+Random(5),
- (FObj.Vel.Y div 2)-2+Random(5));
+ if DoThrow then
+ begin
+ xv := FObj.Vel.X + IfThen(Direction = TDirection.D_RIGHT, 10, -10);
+ yv := FObj.Vel.Y - 2;
+ end
+ else
+ begin
+ xv := (FObj.Vel.X div 2);
+ yv := (FObj.Vel.Y div 2) - 2;
+ end;
+ g_Obj_Push(@Obj, xv, yv);
+
positionChanged(); // this updates spatial accelerators
if FFlag = FLAG_RED then