diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index dd5378b5162ce6e2fbbf3f67bf5eee90cda9efbb..3025ea549a1fe28480c9588c30c2094a1eee4f39 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
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;
Kills: Word;
Color: TRGB;
Spectator: Boolean;
+ UID: Word;
end;
TPlayerStatArray = Array of TPlayerStat;
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;
public
constructor Create(X, Y: Integer; ModelName: String; aMess: Boolean);
destructor Destroy(); override;
- procedure Damage(Value: Word; vx, vy: Integer);
+ procedure Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
procedure Update();
procedure Draw();
procedure SaveState (st: TStream);
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;
Color := gPlayers[a].FModel.Color;
Lives := gPlayers[a].FLives;
Spectator := gPlayers[a].FSpectator;
+ UID := gPlayers[a].FUID;
end;
end;
end;
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;
// Îäèíî÷íàÿ èãðà/êîîïåðàòèâ
if gGameSettings.GameMode in [GM_COOP, GM_SINGLE] then
begin
- if (Self = gPlayer1) or (Self = gPlayer2) then
+ if Self = gPlayer1 then
begin
- // Òî÷êà ïîÿâëåíèÿ ñâîåãî èãðîêà
- if Self = gPlayer1 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ äðóãîãî èãðîêà
- if Self = gPlayer1 then
- c := RESPAWNPOINT_PLAYER2
- else
- c := RESPAWNPOINT_PLAYER1;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
- end else
+ // player 1 should try to spawn on the player 1 point
+ if g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) > 0 then
+ Exit(RESPAWNPOINT_PLAYER1)
+ else if g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) > 0 then
+ Exit(RESPAWNPOINT_PLAYER2);
+ end
+ else if Self = gPlayer2 then
begin
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà (áîòà)
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
- end;
-
- // Òî÷êà ëþáîé èç êîìàíä
- if Random(2) = 0 then
- c := RESPAWNPOINT_RED
+ // player 2 should try to spawn on the player 2 point
+ if g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) > 0 then
+ Exit(RESPAWNPOINT_PLAYER2)
+ else if g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) > 0 then
+ Exit(RESPAWNPOINT_PLAYER1);
+ end
else
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
+ // other players randomly pick either the first or the second point
+ c := IfThen((Random(2) = 0), RESPAWNPOINT_PLAYER1, RESPAWNPOINT_PLAYER2);
+ if g_Map_GetPointCount(c) > 0 then
+ Exit(c);
+ // try the other one
+ c := IfThen((c = RESPAWNPOINT_PLAYER1), RESPAWNPOINT_PLAYER2, RESPAWNPOINT_PLAYER1);
+ if g_Map_GetPointCount(c) > 0 then
+ Exit(c);
end;
end;
// Ìÿñîïîâàë
if gGameSettings.GameMode = GM_DM then
begin
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ëþáîé èç êîìàíä
- if Random(2) = 0 then
- c := RESPAWNPOINT_RED
- else
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
+ // try DM points first
+ if g_Map_GetPointCount(RESPAWNPOINT_DM) > 0 then
+ Exit(RESPAWNPOINT_DM);
end;
// Êîìàíäíûå
if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
begin
- // Òî÷êà ñâîåé êîìàíäû
- c := RESPAWNPOINT_DM;
- if FTeam = TEAM_RED then
- c := RESPAWNPOINT_RED;
- if FTeam = TEAM_BLUE then
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà äðóãîé êîìàíäû
+ // try team points first
c := RESPAWNPOINT_DM;
if FTeam = TEAM_RED then
+ c := RESPAWNPOINT_RED
+ else if FTeam = TEAM_BLUE then
c := RESPAWNPOINT_BLUE;
- if FTeam = TEAM_BLUE then
- c := RESPAWNPOINT_RED;
if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
+ Exit(c);
end;
+
+ // still haven't found a spawnpoint, try random shit
+ Result := g_Map_GetRandomPointType();
end;
procedure TPlayer.Respawn(Silent: Boolean; Force: Boolean = False);
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
// 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
begin
FXTo := XTo;
FYTo := YTo;
- if NetInterpLevel < 1 then
+ if FJustTeleported or (NetInterpLevel < 1) then
begin
FObj.X := XTo;
FObj.Y := YTo;
+ if FJustTeleported then
+ begin
+ FObj.oldX := FObj.X;
+ FObj.oldY := FObj.Y;
+ end;
end
else
begin
end;
-procedure TCorpse.Damage(Value: Word; vx, vy: Integer);
+procedure TCorpse.Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
var
pm: TPlayerModel;
Blood: TModelBlood;
if (gBodyKillEvent <> -1)
and gDelayedEvents[gBodyKillEvent].Pending then
gDelayedEvents[gBodyKillEvent].Pending := False;
- gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, 0);
+ gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, SpawnerUID);
end;
end
else