diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index 8aa0a7df42ca1edaefc70d9a825660cc5e41d8fc..312f186db0e7bca4cd4823bdcec36a7dd2592537 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
{$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
g_base, g_playermodel, g_basic, g_textures,
g_weapons, g_phys, g_sound, g_saveload, MAPDEF,
- g_panel, r_playermodel;
+ g_panel;
const
KEY_LEFT = 1;
TEAM_BLUE = 2;
TEAM_COOP = 3;
- SHELL_BULLET = 0;
- SHELL_SHELL = 1;
- SHELL_DBLSHELL = 2;
-
ANGLE_NONE = Low(SmallInt);
- CORPSE_STATE_REMOVEME = 0;
- CORPSE_STATE_NORMAL = 1;
- CORPSE_STATE_MESS = 2;
-
PLAYER_RECT: TRectWH = (X:15; Y:12; Width:34; Height:52);
PLAYER_RECT_CX = 15+(34 div 2);
PLAYER_RECT_CY = 12+(52 div 2);
- PLAYER_CORPSERECT: TRectWH = (X:15; Y:48; Width:34; Height:16);
PLAYER_HP_SOFT = 100;
PLAYER_HP_LIMIT = 200;
FSavedStateNum: Integer;
FModel: TPlayerModel;
- FPunchAnim: TAnimationState;
+ FPunchAnim: TAnimState;
FActionPrior: Byte;
FActionAnim: Byte;
FActionForce: Boolean;
FIncCamOld: Integer;
FIncCam: Integer;
FSlopeOld: Integer;
- FShellTimer: Integer;
- FShellType: Byte;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer: Integer;
+ FShellType: Byte;
+ {$ENDIF}
FSawSound: TPlayableSound;
FSawSoundIdle: TPlayableSound;
FSawSoundHit: TPlayableSound;
procedure doDamage (v: Integer);
- function refreshCorpse(): Boolean;
-
public
FDamageBuffer: Integer;
FSpawnInvul: Integer;
FHandicap: Integer;
FWaitForFirstSpawn: Boolean; // set to `true` in server, used to spawn a player on first full state request
- FCorpse: Integer;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse: Integer;
+ {$ENDIF}
// debug: viewport offset
viewPortX, viewPortY, viewPortW, viewPortH: Integer;
procedure getMapBox (out x, y, w, h: Integer); inline;
procedure moveBy (dx, dy: Integer); inline;
- function getCameraObj(): TObj;
-
function GetAmmoByWeapon(Weapon: Byte): Word; // private state
public
property Berserk: Integer read FBerserk;
property Pain: Integer read FPain;
property Pickup: Integer read FPickup;
- property PunchAnim: TAnimationState read FPunchAnim write FPunchAnim;
+ property PunchAnim: TAnimState read FPunchAnim write FPunchAnim;
property SpawnInvul: Integer read FSpawnInvul;
property Ghost: Boolean read FGhost;
// set this before assigning something to `eDamage`
property eDamageType: Integer read mEDamageType write mEDamageType;
property eDamage: Integer write doDamage;
+
+ {$IFDEF ENABLE_CORPSES}
+ property Corpse: Integer read FCorpse;
+ {$ENDIF}
end;
TDifficult = record
procedure LoadState (st: TStream); override;
end;
- PGib = ^TGib;
- TGib = record
- alive: Boolean;
- RAngle: Integer;
- Color: TRGB;
- Obj: TObj;
-
- ModelID: Integer;
- GibID: Integer;
-
- procedure getMapBox (out x, y, w, h: Integer); inline;
- procedure moveBy (dx, dy: Integer); inline;
-
- procedure positionChanged (); inline; //WARNING! call this after entity position was changed, or coldet will not work right!
- end;
-
-
- PShell = ^TShell;
- TShell = record
- alive: Boolean;
- SType: Byte;
- RAngle: Integer;
- Timeout: Cardinal;
- Obj: TObj;
-
- procedure getMapBox (out x, y, w, h: Integer); inline;
- procedure moveBy (dx, dy: Integer); inline;
-
- procedure positionChanged (); inline; //WARNING! call this after entity position was changed, or coldet will not work right!
- end;
-
- TCorpse = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
- private
- FMess: Boolean;
- FState: Byte;
- FDamage: Byte;
- FObj: TObj;
- FPlayerUID: Word;
- FModel: TPlayerModel;
-
- public
- constructor Create(X, Y: Integer; ModelName: String; aMess: Boolean);
- destructor Destroy(); override;
- procedure Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
- procedure Update();
- procedure SaveState (st: TStream);
- procedure LoadState (st: TStream);
-
- procedure getMapBox (out x, y, w, h: Integer); inline;
- procedure moveBy (dx, dy: Integer); inline;
-
- procedure positionChanged (); inline; //WARNING! call this after entity position was changed, or coldet will not work right!
-
- function ObjPtr (): PObj; inline;
-
- property Obj: TObj read FObj; // copies object
- property State: Byte read FState;
- property Mess: Boolean read FMess;
- property Model: TPlayerModel read FModel;
- end;
-
TTeamStat = Array [TEAM_RED..TEAM_BLUE] of
record
Score: SmallInt;
var
gPlayers: Array of TPlayer;
- gCorpses: Array of TCorpse;
- gGibs: Array of TGib;
- gShells: Array of TShell;
gTeamStat: TTeamStat;
gFly: Boolean = False;
gAimLine: Boolean = False;
gSpectLatchPID2: Word = 0;
MAX_RUNVEL: Integer = 8;
VEL_JUMP: Integer = 10;
- SHELL_TIMEOUT: Cardinal = 60000;
function Lerp(X, Y, Factor: Integer): Integer;
-procedure g_Gibs_SetMax(Count: Word);
-function g_Gibs_GetMax(): Word;
-procedure g_Corpses_SetMax(Count: Word);
-function g_Corpses_GetMax(): Word;
procedure g_Force_Model_Set(Mode: Word);
function g_Force_Model_Get(): Word;
procedure g_Forced_Model_SetName(Model: String);
function g_Forced_Model_GetName(): String;
-procedure g_Shells_SetMax(Count: Word);
-function g_Shells_GetMax(): Word;
procedure g_Player_Init();
procedure g_Player_Free();
function g_Player_GetCount(): Byte;
function g_Player_GetStats(): TPlayerStatArray;
function g_Player_ValidName(Name: String): Boolean;
-function g_Player_CreateCorpse(Player: TPlayer): Integer;
-procedure g_Player_CreateGibs (fX, fY, mid: Integer; fColor: TRGB);
-procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte);
-procedure g_Player_UpdatePhysicalObjects();
-procedure g_Player_RemoveAllCorpses();
-procedure g_Player_Corpses_SaveState (st: TStream);
-procedure g_Player_Corpses_LoadState (st: TStream);
procedure g_Player_ResetReady();
procedure g_Bot_Add(Team, Difficult: Byte; Handicap: Integer = 100);
procedure g_Bot_AddList(Team: Byte; lname: ShortString; num: Integer = -1; Handicap: Integer = 100);
implementation
uses
-{$IFDEF ENABLE_HOLMES}
- g_holmes,
-{$ENDIF}
- e_log, g_map, g_items, g_console, g_gfx, Math, r_textures, r_animations, r_gfx,
- g_options, g_triggers, g_menu, g_game, g_grid, e_res,
+ {$IFDEF ENABLE_HOLMES}
+ g_holmes,
+ {$ENDIF}
+ {$IFDEF ENABLE_MENU}
+ g_menu,
+ {$ENDIF}
+ {$IFDEF ENABLE_RENDER}
+ r_render,
+ {$ENDIF}
+ {$IFDEF ENABLE_GFX}
+ g_gfx,
+ {$ENDIF}
+ {$IFDEF ENABLE_GIBS}
+ g_gibs,
+ {$ENDIF}
+ {$IFDEF ENABLE_SHELLS}
+ g_shells,
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
+ e_log, g_map, g_items, g_console, Math,
+ g_options, g_triggers, g_game, g_grid, e_res,
wadreader, g_monsters, CONFIG, g_language,
g_net, g_netmsg,
utils, xstreams;
BOTLIST_FILENAME = 'botlist.txt';
var
- MaxGibs: Word = 150;
- MaxCorpses: Word = 20;
- MaxShells: Word = 300;
ForceModel: Word = 0;
ForcedModelName: String = STD_PLAYER_MODEL;
- CurrentGib: Integer = 0;
- CurrentShell: Integer = 0;
BotNames: Array of String;
BotList: Array of TBotProfile;
SavedStates: Array of TPlayerSavedState;
Result := g_Player_Get(UID1).FTeam = g_Player_Get(UID2).FTeam;
end;
-procedure g_Gibs_SetMax(Count: Word);
-begin
- MaxGibs := Count;
- SetLength(gGibs, Count);
-
- if CurrentGib >= Count then
- CurrentGib := 0;
-end;
-
-function g_Gibs_GetMax(): Word;
-begin
- Result := MaxGibs;
-end;
-
-procedure g_Shells_SetMax(Count: Word);
-begin
- MaxShells := Count;
- SetLength(gShells, Count);
-
- if CurrentShell >= Count then
- CurrentShell := 0;
-end;
-
-function g_Shells_GetMax(): Word;
-begin
- Result := MaxShells;
-end;
-
-
-procedure g_Corpses_SetMax(Count: Word);
-begin
- MaxCorpses := Count;
- SetLength(gCorpses, Count);
-end;
-
-function g_Corpses_GetMax(): Word;
-begin
- Result := MaxCorpses;
-end;
-
procedure g_Force_Model_Set(Mode: Word);
begin
ForceModel := Mode;
end;
end;
-function g_Player_CreateCorpse(Player: TPlayer): Integer;
-var
- i: Integer;
- find_id: DWORD;
- ok: Boolean;
-begin
- Result := -1;
-
- if Player.alive then
- Exit;
-
-// Разрываем связь с прежним трупом:
- i := Player.FCorpse;
- if (i >= 0) and (i < Length(gCorpses)) then
- begin
- if (gCorpses[i] <> nil) and (gCorpses[i].FPlayerUID = Player.FUID) then
- gCorpses[i].FPlayerUID := 0;
- end;
-
- if Player.FObj.Y >= gMapInfo.Height+128 then
- Exit;
-
- with Player do
- begin
- if (FHealth >= -50) or (gGibsCount = 0) then
- begin
- if (gCorpses = nil) or (Length(gCorpses) = 0) then
- Exit;
-
- ok := False;
- for find_id := 0 to High(gCorpses) do
- if gCorpses[find_id] = nil then
- begin
- ok := True;
- Break;
- end;
-
- if not ok then
- find_id := Random(Length(gCorpses));
-
- gCorpses[find_id] := TCorpse.Create(FObj.X, FObj.Y, FModel.GetName(), FHealth < -20);
- gCorpses[find_id].FModel.Color := FModel.Color;
- gCorpses[find_id].FObj.Vel := FObj.Vel;
- gCorpses[find_id].FObj.Accel := FObj.Accel;
- gCorpses[find_id].FPlayerUID := FUID;
-
- Result := find_id;
- end
- else
- g_Player_CreateGibs(FObj.X + PLAYER_RECT_CX, FObj.Y + PLAYER_RECT_CY, FModel.id, FModel.Color);
- end;
-end;
-
-procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte);
-begin
- if (gShells = nil) or (Length(gShells) = 0) then
- Exit;
-
- with gShells[CurrentShell] do
- begin
- g_Obj_Init(@Obj);
- Obj.Rect.X := 0;
- Obj.Rect.Y := 0;
- if T = SHELL_BULLET then
- begin
- Obj.Rect.Width := 4;
- Obj.Rect.Height := 2;
- end
- else
- begin
- Obj.Rect.Width := 7;
- Obj.Rect.Height := 3;
- end;
- SType := T;
- alive := True;
- Obj.X := fX;
- Obj.Y := fY;
- g_Obj_Push(@Obj, dX + Random(4)-Random(4), dY-Random(4));
- positionChanged(); // this updates spatial accelerators
- RAngle := Random(360);
- Timeout := gTime + SHELL_TIMEOUT;
-
- if CurrentShell >= High(gShells) then
- CurrentShell := 0
- else
- Inc(CurrentShell);
- end;
-end;
-
-procedure g_Player_CreateGibs (fX, fY, mid: Integer; fColor: TRGB);
-var
- a: Integer;
- GibsArray: TGibsArray;
- Blood: TModelBlood;
-begin
- if mid = -1 then
- Exit;
- if (gGibs = nil) or (Length(gGibs) = 0) then
- Exit;
- if not g_PlayerModel_GetGibs(mid, GibsArray) then
- Exit;
- Blood := PlayerModelsArray[mid].Blood;
-
- for a := 0 to High(GibsArray) do
- with gGibs[CurrentGib] do
- begin
- ModelID := mid;
- GibID := GibsArray[a];
- Color := fColor;
- alive := True;
- g_Obj_Init(@Obj);
- Obj.Rect := r_PlayerModel_GetGibRect(ModelID, GibID);
- Obj.X := fX - Obj.Rect.X - (Obj.Rect.Width div 2);
- Obj.Y := fY - Obj.Rect.Y - (Obj.Rect.Height div 2);
- g_Obj_PushA(@Obj, 25 + Random(10), Random(361));
- positionChanged(); // this updates spatial accelerators
- RAngle := Random(360);
-
- if gBloodCount > 0 then
- g_GFX_Blood(fX, fY, 16*gBloodCount+Random(5*gBloodCount), -16+Random(33), -16+Random(33),
- Random(48), Random(48), Blood.R, Blood.G, Blood.B, Blood.Kind);
-
- if CurrentGib >= High(gGibs) then
- CurrentGib := 0
- else
- Inc(CurrentGib);
- end;
-end;
-
-procedure g_Player_UpdatePhysicalObjects();
-var
- i: Integer;
- vel: TPoint2i;
- mr: Word;
-
- procedure ShellSound_Bounce(X, Y: Integer; T: Byte);
- var
- k: Integer;
- begin
- k := 1 + Random(2);
- if T = SHELL_BULLET then
- g_Sound_PlayExAt('SOUND_PLAYER_CASING' + IntToStr(k), X, Y)
- else
- g_Sound_PlayExAt('SOUND_PLAYER_SHELL' + IntToStr(k), X, Y);
- end;
-
-begin
-// Куски мяса:
- if gGibs <> nil then
- for i := 0 to High(gGibs) do
- if gGibs[i].alive then
- with gGibs[i] do
- begin
- Obj.oldX := Obj.X;
- Obj.oldY := Obj.Y;
-
- vel := Obj.Vel;
- mr := g_Obj_Move(@Obj, True, False, True);
- positionChanged(); // this updates spatial accelerators
-
- if WordBool(mr and MOVE_FALLOUT) then
- begin
- alive := False;
- Continue;
- end;
-
- // Отлетает от удара о стену/потолок/пол:
- if WordBool(mr and MOVE_HITWALL) then
- Obj.Vel.X := -(vel.X div 2);
- if WordBool(mr and (MOVE_HITCEIL or MOVE_HITLAND)) then
- Obj.Vel.Y := -(vel.Y div 2);
-
- if (Obj.Vel.X >= 0) then
- begin // Clockwise
- RAngle := RAngle + Abs(Obj.Vel.X)*6 + Abs(Obj.Vel.Y);
- if RAngle >= 360 then
- RAngle := RAngle mod 360;
- end else begin // Counter-clockwise
- RAngle := RAngle - Abs(Obj.Vel.X)*6 - Abs(Obj.Vel.Y);
- if RAngle < 0 then
- RAngle := (360 - (Abs(RAngle) mod 360)) mod 360;
- end;
-
- // Сопротивление воздуха для куска трупа:
- if gTime mod (GAME_TICK*3) = 0 then
- Obj.Vel.X := z_dec(Obj.Vel.X, 1);
- end;
-
-// Трупы:
- if gCorpses <> nil then
- for i := 0 to High(gCorpses) do
- if gCorpses[i] <> nil then
- if gCorpses[i].State = CORPSE_STATE_REMOVEME then
- begin
- gCorpses[i].Free();
- gCorpses[i] := nil;
- end
- else
- gCorpses[i].Update();
-
-// Гильзы:
- if gShells <> nil then
- for i := 0 to High(gShells) do
- if gShells[i].alive then
- with gShells[i] do
- begin
- Obj.oldX := Obj.X;
- Obj.oldY := Obj.Y;
-
- vel := Obj.Vel;
- mr := g_Obj_Move(@Obj, True, False, True);
- positionChanged(); // this updates spatial accelerators
-
- if WordBool(mr and MOVE_FALLOUT) or (gShells[i].Timeout < gTime) then
- begin
- alive := False;
- Continue;
- end;
-
- // Отлетает от удара о стену/потолок/пол:
- if WordBool(mr and MOVE_HITWALL) then
- begin
- Obj.Vel.X := -(vel.X div 2);
- if not WordBool(mr and MOVE_INWATER) then
- ShellSound_Bounce(Obj.X, Obj.Y, SType);
- end;
- if WordBool(mr and (MOVE_HITCEIL or MOVE_HITLAND)) then
- begin
- Obj.Vel.Y := -(vel.Y div 2);
- if Obj.Vel.X <> 0 then Obj.Vel.X := Obj.Vel.X div 2;
- if (Obj.Vel.X = 0) and (Obj.Vel.Y = 0) then
- begin
- if RAngle mod 90 <> 0 then
- RAngle := (RAngle div 90) * 90;
- end
- else if not WordBool(mr and MOVE_INWATER) then
- ShellSound_Bounce(Obj.X, Obj.Y, SType);
- end;
-
- if (Obj.Vel.X >= 0) then
- begin // Clockwise
- RAngle := RAngle + Abs(Obj.Vel.X)*8 + Abs(Obj.Vel.Y);
- if RAngle >= 360 then
- RAngle := RAngle mod 360;
- end else begin // Counter-clockwise
- RAngle := RAngle - Abs(Obj.Vel.X)*8 - Abs(Obj.Vel.Y);
- if RAngle < 0 then
- RAngle := (360 - (Abs(RAngle) mod 360)) mod 360;
- end;
- end;
-end;
-
-
-procedure TGib.getMapBox (out x, y, w, h: Integer); inline;
-begin
- x := Obj.X+Obj.Rect.X;
- y := Obj.Y+Obj.Rect.Y;
- w := Obj.Rect.Width;
- h := Obj.Rect.Height;
-end;
-
-procedure TGib.moveBy (dx, dy: Integer); inline;
-begin
- if (dx <> 0) or (dy <> 0) then
- begin
- Obj.X += dx;
- Obj.Y += dy;
- positionChanged();
- end;
-end;
-
-
-procedure TShell.getMapBox (out x, y, w, h: Integer); inline;
-begin
- x := Obj.X;
- y := Obj.Y;
- w := Obj.Rect.Width;
- h := Obj.Rect.Height;
-end;
-
-procedure TShell.moveBy (dx, dy: Integer); inline;
-begin
- if (dx <> 0) or (dy <> 0) then
- begin
- Obj.X += dx;
- Obj.Y += dy;
- positionChanged();
- end;
-end;
-
-
-procedure TGib.positionChanged (); inline; begin end;
-procedure TShell.positionChanged (); inline; begin end;
-
-
-procedure g_Player_RemoveAllCorpses();
-var
- i: Integer;
-begin
- gGibs := nil;
- gShells := nil;
- SetLength(gGibs, MaxGibs);
- SetLength(gShells, MaxGibs);
- CurrentGib := 0;
- CurrentShell := 0;
-
- if gCorpses <> nil then
- for i := 0 to High(gCorpses) do
- gCorpses[i].Free();
-
- gCorpses := nil;
- SetLength(gCorpses, MaxCorpses);
-end;
-
-procedure g_Player_Corpses_SaveState (st: TStream);
-var
- count, i: Integer;
-begin
- // Считаем количество существующих трупов
- count := 0;
- for i := 0 to High(gCorpses) do if (gCorpses[i] <> nil) then Inc(count);
-
- // Количество трупов
- utils.writeInt(st, LongInt(count));
-
- if (count = 0) then exit;
-
- // Сохраняем трупы
- for i := 0 to High(gCorpses) do
- begin
- if gCorpses[i] <> nil then
- begin
- // Название модели
- utils.writeStr(st, gCorpses[i].FModel.GetName());
- // Тип смерти
- utils.writeBool(st, gCorpses[i].Mess);
- // Сохраняем данные трупа:
- gCorpses[i].SaveState(st);
- end;
- end;
-end;
-
-
-procedure g_Player_Corpses_LoadState (st: TStream);
-var
- count, i: Integer;
- str: String;
- b: Boolean;
-begin
- assert(st <> nil);
-
- g_Player_RemoveAllCorpses();
-
- // Количество трупов:
- count := utils.readLongInt(st);
- if (count < 0) or (count > Length(gCorpses)) then raise XStreamError.Create('invalid number of corpses');
-
- if (count = 0) then exit;
-
- // Загружаем трупы
- for i := 0 to count-1 do
- begin
- // Название модели:
- str := utils.readStr(st);
- // Тип смерти
- b := utils.readBool(st);
- // Создаем труп
- gCorpses[i] := TCorpse.Create(0, 0, str, b);
- // Загружаем данные трупа
- gCorpses[i].LoadState(st);
- end;
-end;
-
-
{ T P l a y e r : }
function TPlayer.isValidViewPort (): Boolean; inline; begin result := (viewPortW > 0) and (viewPortH > 0); end;
FPing := 0;
FLoss := 0;
FSavedStateNum := -1;
- FShellTimer := -1;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := -1;
+ {$ENDIF}
FFireTime := 0;
FFirePainTime := 0;
FFireAttacker := 0;
FHandicap := 100;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
FActualModelName := 'doomer';
FNetTime := 0;
FWaitForFirstSpawn := false;
- FPunchAnim := TAnimationState.Create(False, 1, 4);
+ FPunchAnim := TAnimState.Create(False, 1, 4);
FPunchAnim.Disable;
resetWeaponQueue();
HIT_BFG, HIT_ROCKET, HIT_SOME: MakeBloodVector(c, vx, vy);
end;
- if t = HIT_WATER then
- begin
- g_GFX_Bubbles(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
- FObj.Y+PLAYER_RECT.Y-4, value div 2, 8, 4);
- if Random(2) = 0
- then g_Sound_PlayExAt('SOUND_GAME_BUBBLE1', FObj.X, FObj.Y)
- else g_Sound_PlayExAt('SOUND_GAME_BUBBLE2', FObj.X, FObj.Y);
- end;
+ {$IFDEF ENABLE_GFX}
+ if t = HIT_WATER then
+ begin
+ g_GFX_Bubbles(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
+ FObj.Y+PLAYER_RECT.Y-4, value div 2, 8, 4);
+ if Random(2) = 0
+ then g_Sound_PlayExAt('SOUND_GAME_BUBBLE1', FObj.X, FObj.Y)
+ else g_Sound_PlayExAt('SOUND_GAME_BUBBLE2', FObj.X, FObj.Y);
+ end;
+ {$ENDIF}
end;
// Буфер урона:
FJetSoundOn.Free();
FJetSoundOff.Free();
FModel.Free();
- FPunchAnim.Free();
+ FPunchAnim.Invalidate;
inherited;
end;
FFireAngle := FAngle;
f := True;
DidFire := True;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_BULLET);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+ {$ENDIF}
end;
WEAPON_SHOTGUN1:
FFireAngle := FAngle;
f := True;
DidFire := True;
- FShellTimer := 10;
- FShellType := SHELL_SHELL;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := 10;
+ FShellType := SHELL_SHELL;
+ {$ENDIF}
end;
WEAPON_SHOTGUN2:
FFireAngle := FAngle;
f := True;
DidFire := True;
- FShellTimer := 13;
- FShellType := SHELL_DBLSHELL;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := 13;
+ FShellType := SHELL_DBLSHELL;
+ {$ENDIF}
end;
WEAPON_CHAINGUN:
FFireAngle := FAngle;
f := True;
DidFire := True;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_BULLET);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+ {$ENDIF}
end;
WEAPON_ROCKETLAUNCHER:
FFireAngle := FAngle;
f := True;
DidFire := True;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_SHELL);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_SHELL);
+ {$ENDIF}
end;
WEAPON_FLAMETHROWER:
FPhysics := True;
FAlive := False;
end;
- FShellTimer := -1;
+
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := -1;
+ {$ENDIF}
if (gGameSettings.MaxLives > 0) and Srv and (gLMSRespawn = LMS_RESPAWN_NONE) then
begin
DropFlag(KillType = K_FALLKILL);
end;
- FCorpse := g_Player_CreateCorpse(Self);
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := g_Corpses_Create(Self);
+ {$ENDIF}
if Srv and (gGameSettings.MaxLives > 0) and FNoRespawn and
(gLMSRespawn = LMS_RESPAWN_NONE) then
end;
procedure TPlayer.MakeBloodSimple(Count: Word);
- var Blood: TModelBlood;
-begin
- Blood := SELF.FModel.GetBlood();
- g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)+8,
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
- Count div 2, 3, -1, 16, (PLAYER_RECT.Height*2 div 3),
- Blood.R, Blood.G, Blood.B, Blood.Kind);
- g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-8,
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
- Count div 2, -3, -1, 16, (PLAYER_RECT.Height*2) div 3,
- Blood.R, Blood.G, Blood.B, Blood.Kind);
+ {$IFDEF ENABLE_GFX}
+ var Blood: TModelBlood;
+ {$ENDIF}
+begin
+ {$IFDEF ENABLE_GFX}
+ Blood := SELF.FModel.GetBlood();
+ g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)+8,
+ FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
+ Count div 2, 3, -1, 16, (PLAYER_RECT.Height*2 div 3),
+ Blood.R, Blood.G, Blood.B, Blood.Kind);
+ g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-8,
+ FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
+ Count div 2, -3, -1, 16, (PLAYER_RECT.Height*2) div 3,
+ Blood.R, Blood.G, Blood.B, Blood.Kind);
+ {$ENDIF}
end;
procedure TPlayer.MakeBloodVector(Count: Word; VelX, VelY: Integer);
- var Blood: TModelBlood;
+ {$IFDEF ENABLE_GFX}
+ var Blood: TModelBlood;
+ {$ENDIF}
begin
- Blood := SELF.FModel.GetBlood();
- g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
- Count, VelX, VelY, 16, (PLAYER_RECT.Height*2) div 3,
- Blood.R, Blood.G, Blood.B, Blood.Kind);
+ {$IFDEF ENABLE_GFX}
+ Blood := SELF.FModel.GetBlood();
+ g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
+ FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
+ Count, VelX, VelY, 16, (PLAYER_RECT.Height*2) div 3,
+ Blood.R, Blood.G, Blood.B, Blood.Kind);
+ {$ENDIF}
end;
procedure TPlayer.ProcessWeaponAction(Action: Byte);
FDeath := 0;
FSecrets := 0;
FSpawnInvul := 0;
- FCorpse := -1;
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
FReady := False;
if FNoRespawn then
begin
FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
- FShellTimer := -1;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := -1;
+ {$ENDIF}
FPain := 0;
FLastHit := 0;
FLastFrag := 0;
FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
- FShellTimer := -1;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := -1;
+ {$ENDIF}
FPain := 0;
FLastHit := 0;
FSpawnInvul := 0;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
if not g_Game_IsServer then
Exit;
FFirePainTime := 0;
FFireAttacker := 0;
-// Анимация возрождения:
- if (not gLoadGameMode) and (not Silent) then
- r_GFX_OnceAnim(
- R_GFX_TELEPORT_FAST,
- FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32,
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32
- );
+ {$IFDEF ENABLE_GFX}
+ // Анимация возрождения:
+ if (not gLoadGameMode) and (not Silent) then
+ begin
+ g_GFX_QueueEffect(
+ R_GFX_TELEPORT_FAST,
+ FObj.X + PLAYER_RECT.X + (PLAYER_RECT.Width div 2) - 32,
+ FObj.Y + PLAYER_RECT.Y + (PLAYER_RECT.Height div 2) - 32
+ );
+ end;
+ {$ENDIF}
FSpectator := False;
FGhost := False;
FPhysics := False;
FWantsInGame := False;
FSpawned := False;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
if FNoRespawn then
begin
end;
procedure TPlayer.Run(Direction: TDirection);
-var
- a, b: Integer;
+ {$IFDEF ENABLE_GIBS}
+ var a, b: Integer;
+ {$ENDIF}
begin
if MAX_RUNVEL > 8 then
FlySmoke();
if FObj.Vel.X < MAX_RUNVEL then
FObj.Vel.X := FObj.Vel.X + (MAX_RUNVEL shr 3);
-// Возможно, пинаем куски:
- if (FObj.Vel.X <> 0) and (gGibs <> nil) then
- begin
- b := Abs(FObj.Vel.X);
- if b > 1 then b := b * (Random(8 div b) + 1);
- for a := 0 to High(gGibs) do
+ {$IFDEF ENABLE_GIBS}
+ // Возможно, пинаем куски:
+ if (FObj.Vel.X <> 0) and (gGibs <> nil) then
begin
- if gGibs[a].alive and
- g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
- FObj.Rect.Width, 8, @gGibs[a].Obj) and (Random(3) = 0) then
+ b := Abs(FObj.Vel.X);
+ if b > 1 then b := b * (Random(8 div b) + 1);
+ for a := 0 to High(gGibs) do
begin
- // Пинаем куски
- if FObj.Vel.X < 0 then
- begin
- g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120) // налево
- end
- else
+ if gGibs[a].alive and
+ g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
+ FObj.Rect.Width, 8, @gGibs[a].Obj) and (Random(3) = 0) then
begin
- g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // направо
+ // Пинаем куски
+ if FObj.Vel.X < 0 then
+ begin
+ g_Obj_PushA(@gGibs[a].Obj, b, Random(61)+120) // налево
+ end
+ else
+ begin
+ g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // направо
+ end;
+ gGibs[a].positionChanged(); // this updates spatial accelerators
end;
- gGibs[a].positionChanged(); // this updates spatial accelerators
end;
end;
- end;
+ {$ENDIF}
SetAction(A_WALK);
end;
if not silent then
begin
g_Sound_PlayExAt('SOUND_GAME_TELEPORT', FObj.X, FObj.Y);
- r_GFX_OnceAnim(
- R_GFX_TELEPORT_FAST,
- FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32,
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32
- );
+ {$IFDEF ENABLE_GFX}
+ g_GFX_QueueEffect(
+ R_GFX_TELEPORT_FAST,
+ FObj.X + PLAYER_RECT.X + (PLAYER_RECT.Width div 2) - 32,
+ FObj.Y + PLAYER_RECT.Y + (PLAYER_RECT.Height div 2) - 32
+ );
+ {$ENDIF}
if g_Game_IsServer and g_Game_IsNet then
MH_SEND_Effect(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32,
FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32, 1,
if not silent then
begin
- r_GFX_OnceAnim(
- R_GFX_TELEPORT_FAST,
- FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32,
- FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32
- );
+ {$IFDEF ENABLE_GFX}
+ g_GFX_QueueEffect(
+ R_GFX_TELEPORT_FAST,
+ FObj.X + PLAYER_RECT.X + (PLAYER_RECT.Width div 2) - 32,
+ FObj.Y + PLAYER_RECT.Y + (PLAYER_RECT.Height div 2) - 32
+ );
+ {$ENDIF}
if g_Game_IsServer and g_Game_IsNet then
MH_SEND_Effect(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32,
FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32, 0,
Result := 1;
end;
-function TPlayer.refreshCorpse(): Boolean;
-var
- i: Integer;
-begin
- Result := False;
- FCorpse := -1;
- if FAlive or FSpectator then
- Exit;
- if (gCorpses = nil) or (Length(gCorpses) = 0) then
- Exit;
- for i := 0 to High(gCorpses) do
- if gCorpses[i] <> nil then
- if gCorpses[i].FPlayerUID = FUID then
- begin
- Result := True;
- FCorpse := i;
- break;
- end;
-end;
-
-function TPlayer.getCameraObj(): TObj;
-begin
- if (not FAlive) and (not FSpectator) and
- (FCorpse >= 0) and (FCorpse < Length(gCorpses)) and
- (gCorpses[FCorpse] <> nil) and (gCorpses[FCorpse].FPlayerUID = FUID) then
- begin
- gCorpses[FCorpse].FObj.slopeUpLeft := FObj.slopeUpLeft;
- Result := gCorpses[FCorpse].FObj;
- end
- else
- begin
- Result := FObj;
- end;
-end;
-
procedure TPlayer.PreUpdate();
begin
FSlopeOld := FObj.slopeUpLeft;
else
Dec(FReloading[b]);
+{$IFDEF ENABLE_SHELLS}
if FShellTimer > -1 then
if FShellTimer = 0 then
begin
if FShellType = SHELL_SHELL then
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+ g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
GameVelX, GameVelY-2, SHELL_SHELL)
else if FShellType = SHELL_DBLSHELL then
begin
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+ g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
GameVelX+1, GameVelY-2, SHELL_SHELL);
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+ g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
GameVelX-1, GameVelY-2, SHELL_SHELL);
end;
FShellTimer := -1;
end else Dec(FShellTimer);
+{$ENDIF}
if (FBFGFireCounter > -1) then
if FBFGFireCounter = 0 then
end
else if (FAir mod 31 = 0) and not blockmon then
begin
- g_GFX_Bubbles(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2), FObj.Y+PLAYER_RECT.Y-4, 5+Random(6), 8, 4);
+ {$IFDEF ENABLE_GFX}
+ g_GFX_Bubbles(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2), FObj.Y+PLAYER_RECT.Y-4, 5+Random(6), 8, 4);
+ {$ENDIF}
if Random(2) = 0
then g_Sound_PlayExAt('SOUND_GAME_BUBBLE1', FObj.X, FObj.Y)
else g_Sound_PlayExAt('SOUND_GAME_BUBBLE2', FObj.X, FObj.Y);
begin
g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', GameX, Gamey);
FFireAngle := FAngle;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_BULLET);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+ {$ENDIF}
end;
WEAPON_SHOTGUN1:
begin
g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey);
FFireAngle := FAngle;
- FShellTimer := 10;
- FShellType := SHELL_SHELL;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := 10;
+ FShellType := SHELL_SHELL;
+ {$ENDIF}
end;
WEAPON_SHOTGUN2:
begin
g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', Gamex, Gamey);
FFireAngle := FAngle;
- FShellTimer := 13;
- FShellType := SHELL_DBLSHELL;
+ {$IFDEF ENABLE_SHELLS}
+ FShellTimer := 13;
+ FShellType := SHELL_DBLSHELL;
+ {$ENDIF}
end;
WEAPON_CHAINGUN:
begin
g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', Gamex, Gamey);
FFireAngle := FAngle;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_BULLET);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+ {$ENDIF}
end;
WEAPON_ROCKETLAUNCHER:
begin
g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey);
FFireAngle := FAngle;
- g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
- GameVelX, GameVelY-2, SHELL_SHELL);
+ {$IFDEF ENABLE_SHELLS}
+ g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_SHELL);
+ {$ENDIF}
end;
WEAPON_FLAMETHROWER:
if BodyInLiquid(0, 0) then
begin
- g_GFX_Bubbles(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)+Random(3)-1,
- Obj.Y+Obj.Rect.Height+8, 1, 8, 4);
+ {$IFDEF ENABLE_GFX}
+ g_GFX_Bubbles(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)+Random(3)-1,
+ Obj.Y+Obj.Rect.Height+8, 1, 8, 4);
+ {$ENDIF}
if Random(2) = 0
then g_Sound_PlayExAt('SOUND_GAME_BUBBLE1', FObj.X, FObj.Y)
else g_Sound_PlayExAt('SOUND_GAME_BUBBLE2', FObj.X, FObj.Y);
for i := 1 to Times do
begin
- r_GFX_OnceAnim(
- R_GFX_SMOKE_TRANS,
- Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(R_GFX_SMOKE_WIDTH div 2),
- Obj.Y+Obj.Rect.Height-4+Random(8+Times*2)
- );
+ {$IFDEF ENABLE_GFX}
+ g_GFX_QueueEffect(
+ R_GFX_SMOKE_TRANS,
+ Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(R_GFX_SMOKE_WIDTH div 2),
+ Obj.Y+Obj.Rect.Height-4+Random(8+Times*2)
+ );
+ {$ENDIF}
end;
end;
for i := 1 to Times do
begin
- r_GFX_OnceAnim(
- R_GFX_FLAME,
- Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(R_GFX_FLAME_WIDTH div 2),
- Obj.Y+8+Random(8+Times*2)
- );
+ {$IFDEF ENABLE_GFX}
+ g_GFX_QueueEffect(
+ R_GFX_FLAME,
+ Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(R_GFX_FLAME_WIDTH div 2),
+ Obj.Y+8+Random(8+Times*2)
+ );
+ {$ENDIF}
end;
end;
FJetSoundOff.Pause(Enable);
end;
-{ T C o r p s e : }
-
-constructor TCorpse.Create(X, Y: Integer; ModelName: String; aMess: Boolean);
-begin
- g_Obj_Init(@FObj);
- FObj.X := X;
- FObj.Y := Y;
- FObj.Rect := PLAYER_CORPSERECT;
- FMess := aMess;
- FModel := g_PlayerModel_Get(ModelName);
-
- if FMess then
- begin
- FState := CORPSE_STATE_MESS;
- FModel.ChangeAnimation(A_DIE2);
- end
- else
- begin
- FState := CORPSE_STATE_NORMAL;
- FModel.ChangeAnimation(A_DIE1);
- end;
-end;
-
-destructor TCorpse.Destroy();
-begin
- FModel.Free;
- inherited;
-end;
-
-function TCorpse.ObjPtr (): PObj; inline; begin result := @FObj; end;
-
-procedure TCorpse.positionChanged (); inline; begin end;
-
-procedure TCorpse.moveBy (dx, dy: Integer); inline;
-begin
- if (dx <> 0) or (dy <> 0) then
- begin
- FObj.X += dx;
- FObj.Y += dy;
- positionChanged();
- end;
-end;
-
-
-procedure TCorpse.getMapBox (out x, y, w, h: Integer); inline;
-begin
- x := FObj.X+PLAYER_CORPSERECT.X;
- y := FObj.Y+PLAYER_CORPSERECT.Y;
- w := PLAYER_CORPSERECT.Width;
- h := PLAYER_CORPSERECT.Height;
-end;
-
-
-procedure TCorpse.Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
- var Blood: TModelBlood;
-begin
- if FState = CORPSE_STATE_REMOVEME then
- Exit;
-
- FDamage := FDamage + Value;
-
- if FDamage > 150 then
- begin
- if FModel <> nil then
- begin
- FState := CORPSE_STATE_REMOVEME;
-
- g_Player_CreateGibs(
- FObj.X + FObj.Rect.X + (FObj.Rect.Width div 2),
- FObj.Y + FObj.Rect.Y + (FObj.Rect.Height div 2),
- FModel.id,
- FModel.Color
- );
-
- // Звук мяса от трупа:
- FModel.PlaySound(MODELSOUND_DIE, 5, FObj.X, FObj.Y);
-
- // Зловещий смех:
- if (gBodyKillEvent <> -1) and gDelayedEvents[gBodyKillEvent].Pending then
- gDelayedEvents[gBodyKillEvent].Pending := False;
- gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, SpawnerUID);
-
- FModel.Free;
- FModel := nil;
- end
- end
- else
- begin
- Blood := FModel.GetBlood();
- FObj.Vel.X := FObj.Vel.X + vx;
- FObj.Vel.Y := FObj.Vel.Y + vy;
- g_GFX_Blood(FObj.X+PLAYER_CORPSERECT.X+(PLAYER_CORPSERECT.Width div 2),
- FObj.Y+PLAYER_CORPSERECT.Y+(PLAYER_CORPSERECT.Height div 2),
- Value, vx, vy, 16, (PLAYER_CORPSERECT.Height*2) div 3,
- Blood.R, Blood.G, Blood.B, Blood.Kind);
- end;
-end;
-
-procedure TCorpse.Update();
-var
- st: Word;
-begin
- if FState = CORPSE_STATE_REMOVEME then
- Exit;
-
- FObj.oldX := FObj.X;
- FObj.oldY := FObj.Y;
-
- if gTime mod (GAME_TICK*2) <> 0 then
- begin
- g_Obj_Move(@FObj, True, True, True);
- positionChanged(); // this updates spatial accelerators
- Exit;
- end;
-
-// Сопротивление воздуха для трупа:
- FObj.Vel.X := z_dec(FObj.Vel.X, 1);
-
- st := g_Obj_Move(@FObj, True, True, True);
- positionChanged(); // this updates spatial accelerators
-
- if WordBool(st and MOVE_FALLOUT) then
- begin
- FState := CORPSE_STATE_REMOVEME;
- Exit;
- end;
-
- if FModel <> nil then
- FModel.Update;
-end;
-
-
-procedure TCorpse.SaveState (st: TStream);
- var anim: Boolean;
-begin
- assert(st <> nil);
-
- // Сигнатура трупа
- utils.writeSign(st, 'CORP');
- utils.writeInt(st, Byte(0));
- // Состояние
- utils.writeInt(st, Byte(FState));
- // Накопленный урон
- utils.writeInt(st, Byte(FDamage));
- // Цвет
- utils.writeInt(st, Byte(FModel.Color.R));
- utils.writeInt(st, Byte(FModel.Color.G));
- utils.writeInt(st, Byte(FModel.Color.B));
- // Объект трупа
- Obj_SaveState(st, @FObj);
- utils.writeInt(st, Word(FPlayerUID));
- // animation
- anim := (FModel <> nil);
- utils.writeBool(st, anim);
- if anim then FModel.AnimState.SaveState(st);
- // animation for mask (same as animation, compat with older saves)
- anim := (FModel <> nil);
- utils.writeBool(st, anim);
- if anim then FModel.AnimState.SaveState(st);
-end;
-
-
-procedure TCorpse.LoadState (st: TStream);
- var anim: Boolean; r, g, b: Byte; stub: TAnimationState;
-begin
- assert(st <> nil);
-
- // Сигнатура трупа
- if not utils.checkSign(st, 'CORP') then raise XStreamError.Create('invalid corpse signature');
- if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid corpse version');
- // Состояние
- FState := utils.readByte(st);
- // Накопленный урон
- FDamage := utils.readByte(st);
- // Цвет
- r := utils.readByte(st);
- g := utils.readByte(st);
- b := utils.readByte(st);
- FModel.SetColor(r, g, b);
- // Объект трупа
- Obj_LoadState(@FObj, st);
- FPlayerUID := utils.readWord(st);
- // animation
- stub := TAnimationState.Create(False, 0, 0);
- anim := utils.readBool(st);
- if anim then
- begin
- stub.LoadState(st);
- FModel.AnimState.CurrentFrame := Min(stub.CurrentFrame, FModel.AnimState.Length);
- end
- else
- begin
- FModel.Free;
- FModel := nil
- end;
- // animation for mask (same as animation, compat with older saves)
- anim := utils.readBool(st);
- if anim then stub.LoadState(st);
- stub.Free;
-end;
-
{ T B o t : }
constructor TBot.Create();