X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=4967d75cc5642ca8a583f5890b552dfb81f986ee;hb=bb931202515154fd56edaa5657d0f69f1cce0e75;hp=e2e9e97e645187117633e7b6d47fbeb930d41eeb;hpb=c5684c0c980bb96fd4fd0efae4d48cdeb469c8ff;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index e2e9e97..4967d75 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -74,20 +74,11 @@ const 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; @@ -191,7 +182,7 @@ type FSavedStateNum: Integer; FModel: TPlayerModel; - FPunchAnim: TAnimation; + FPunchAnim: TAnimationState; FActionPrior: Byte; FActionAnim: Byte; FActionForce: Boolean; @@ -201,8 +192,10 @@ type FIncCamOld: Integer; FIncCam: Integer; FSlopeOld: Integer; - FShellTimer: Integer; - FShellType: Byte; + {$IFDEF ENABLE_SHELLS} + FShellTimer: Integer; + FShellType: Byte; + {$ENDIF} FSawSound: TPlayableSound; FSawSoundIdle: TPlayableSound; FSawSoundHit: TPlayableSound; @@ -250,8 +243,6 @@ type procedure doDamage (v: Integer); - function refreshCorpse(): Boolean; - public FDamageBuffer: Integer; @@ -283,7 +274,10 @@ type 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; @@ -355,8 +349,6 @@ type 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 @@ -403,7 +395,7 @@ type property Berserk: Integer read FBerserk; property Pain: Integer read FPain; property Pickup: Integer read FPickup; - property PunchAnim: TAnimation read FPunchAnim write FPunchAnim; + property PunchAnim: TAnimationState read FPunchAnim write FPunchAnim; property SpawnInvul: Integer read FSpawnInvul; property Ghost: Boolean read FGhost; @@ -441,6 +433,10 @@ type // 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 @@ -501,75 +497,6 @@ type procedure LoadState (st: TStream); override; end; - PGib = ^TGib; - TGib = record - alive: Boolean; - ID: DWORD; - MaskID: DWORD; - RAngle: Integer; - Color: TRGB; - 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; - - - PShell = ^TShell; - TShell = record - SpriteID: DWORD; - alive: Boolean; - SType: Byte; - RAngle: Integer; - Timeout: Cardinal; - CX, CY: Integer; - 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 - FModelName: String; - FMess: Boolean; - FState: Byte; - FDamage: Byte; - FColor: TRGB; - FObj: TObj; - FPlayerUID: Word; - FAnimation: TAnimation; - FAnimationMask: TAnimation; - - 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; - - (* internal state *) - property Color: TRGB read FColor; - property Animation: TAnimation read FAnimation; - property AnimationMask: TAnimation read FAnimationMask; - end; - TTeamStat = Array [TEAM_RED..TEAM_BLUE] of record Goals: SmallInt; @@ -577,9 +504,6 @@ type 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; @@ -591,17 +515,9 @@ var 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_Shells_SetMax(Count: Word); -function g_Shells_GetMax(): Word; - procedure g_Player_Init(); procedure g_Player_Free(); function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boolean): Word; @@ -616,13 +532,6 @@ function g_Player_Get(UID: Word): TPlayer; 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: Integer; ModelName: String; 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); @@ -632,13 +541,31 @@ procedure g_Bot_RemoveAll(); implementation uses -{$IFDEF ENABLE_HOLMES} - g_holmes, -{$ENDIF} - e_log, g_map, g_items, g_console, g_gfx, Math, - g_options, g_triggers, g_menu, g_game, g_grid, e_res, - wadreader, g_main, g_monsters, CONFIG, g_language, - g_net, g_netmsg, g_window, + {$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; const PLR_SAVE_VERSION = 0; @@ -708,11 +635,6 @@ const BOTLIST_FILENAME = 'botlist.txt'; var - MaxGibs: Word = 150; - MaxCorpses: Word = 20; - MaxShells: Word = 300; - CurrentGib: Integer = 0; - CurrentShell: Integer = 0; BotNames: Array of String; BotList: Array of TBotProfile; SavedStates: Array of TPlayerSavedState; @@ -738,46 +660,6 @@ begin 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; - function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boolean): Word; var a: Integer; @@ -1528,391 +1410,6 @@ begin 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.Name, FHealth < -20); - gCorpses[find_id].FColor := 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.Name, FModel.Color); - end; -end; - -procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte); -var - SID: DWORD; -begin - if (gShells = nil) or (Length(gShells) = 0) then - Exit; - - with gShells[CurrentShell] do - begin - SpriteID := 0; - g_Obj_Init(@Obj); - Obj.Rect.X := 0; - Obj.Rect.Y := 0; - if T = SHELL_BULLET then - begin - if g_Texture_Get('TEXTURE_SHELL_BULLET', SID) then - SpriteID := SID; - CX := 2; - CY := 1; - Obj.Rect.Width := 4; - Obj.Rect.Height := 2; - end - else - begin - if g_Texture_Get('TEXTURE_SHELL_SHELL', SID) then - SpriteID := SID; - CX := 4; - CY := 2; - 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: Integer; ModelName: string; fColor: TRGB); -var - a: Integer; - GibsArray: TGibsArray; - Blood: TModelBlood; -begin - if (gGibs = nil) or (Length(gGibs) = 0) then - Exit; - if not g_PlayerModel_GetGibs(ModelName, GibsArray) then - Exit; - Blood := g_PlayerModel_GetBlood(ModelName); - - for a := 0 to High(GibsArray) do - with gGibs[CurrentGib] do - begin - Color := fColor; - ID := GibsArray[a].ID; - MaskID := GibsArray[a].MaskID; - alive := True; - g_Obj_Init(@Obj); - Obj.Rect := GibsArray[a].Rect; - Obj.X := fX-GibsArray[a].Rect.X-(GibsArray[a].Rect.Width div 2); - Obj.Y := fY-GibsArray[a].Rect.Y-(GibsArray[a].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].FModelName); - // Тип смерти - 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; @@ -2102,12 +1599,17 @@ begin 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'; @@ -2119,6 +1621,8 @@ begin FNetTime := 0; FWaitForFirstSpawn := false; + FPunchAnim := TAnimationState.Create(False, 1, 4); + FPunchAnim.Disable; resetWeaponQueue(); end; @@ -2202,9 +1706,13 @@ begin HIT_BFG, HIT_ROCKET, HIT_SOME: MakeBloodVector(c, vx, vy); end; - if t = HIT_WATER then - g_GFX_Bubbles(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2), - FObj.Y+PLAYER_RECT.Y-4, value div 2, 8, 4); + {$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); + end; + {$ENDIF} end; // Буфер урона: @@ -2265,31 +1773,15 @@ begin FJetSoundOn.Free(); FJetSoundOff.Free(); FModel.Free(); - if FPunchAnim <> nil then - FPunchAnim.Free(); + FPunchAnim.Free(); inherited; end; procedure TPlayer.DoPunch(); -var - id: DWORD; - st: String; begin - if FPunchAnim <> nil then begin - FPunchAnim.reset(); - FPunchAnim.Free; - FPunchAnim := nil; - end; - st := 'FRAMES_PUNCH'; - if R_BERSERK in FRulez then - st := st + '_BERSERK'; - if FKeys[KEY_UP].Pressed then - st := st + '_UP' - else if FKeys[KEY_DOWN].Pressed then - st := st + '_DN'; - g_Frames_Get(id, st); - FPunchAnim := TAnimation.Create(id, False, 1); + FPunchAnim.Reset; + FPunchAnim.Enable; end; procedure TPlayer.Fire(); @@ -2381,8 +1873,9 @@ begin 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: @@ -2395,8 +1888,10 @@ begin FFireAngle := FAngle; f := True; DidFire := True; - FShellTimer := 10; - FShellType := SHELL_SHELL; + {$IFDEF ENABLE_SHELLS} + FShellTimer := 10; + FShellType := SHELL_SHELL; + {$ENDIF} end; WEAPON_SHOTGUN2: @@ -2408,8 +1903,10 @@ begin FFireAngle := FAngle; f := True; DidFire := True; - FShellTimer := 13; - FShellType := SHELL_DBLSHELL; + {$IFDEF ENABLE_SHELLS} + FShellTimer := 13; + FShellType := SHELL_DBLSHELL; + {$ENDIF} end; WEAPON_CHAINGUN: @@ -2422,8 +1919,9 @@ begin 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: @@ -2468,8 +1966,9 @@ begin 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: @@ -2698,7 +2197,10 @@ begin 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 @@ -2881,7 +2383,9 @@ 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 @@ -3015,23 +2519,35 @@ begin end; procedure TPlayer.MakeBloodSimple(Count: Word); -begin - 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), - FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.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, - FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.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); + {$IFDEF ENABLE_GFX} + var Blood: TModelBlood; + {$ENDIF} begin - 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, - FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.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.QueueWeaponSwitch(Weapon: Byte); @@ -3692,7 +3208,9 @@ begin FDeath := 0; FSecrets := 0; FSpawnInvul := 0; - FCorpse := -1; + {$IFDEF ENABLE_CORPSES} + FCorpse := -1; + {$ENDIF} FReady := False; if FNoRespawn then begin @@ -3716,7 +3234,9 @@ begin FIncCamOld := 0; FIncCam := 0; FBFGFireCounter := -1; - FShellTimer := -1; + {$IFDEF ENABLE_SHELLS} + FShellTimer := -1; + {$ENDIF} FPain := 0; FLastHit := 0; FLastFrag := 0; @@ -3794,18 +3314,21 @@ procedure TPlayer.Respawn(Silent: Boolean; Force: Boolean = False); var RespawnPoint: TRespawnPoint; a, b, c: Byte; - Anim: TAnimation; - ID: DWORD; begin FSlopeOld := 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; @@ -3938,15 +3461,17 @@ begin FFirePainTime := 0; FFireAttacker := 0; -// Анимация возрождения: - if (not gLoadGameMode) and (not Silent) then - if g_Frames_Get(ID, 'FRAMES_TELEPORT') then + {$IFDEF ENABLE_GFX} + // Анимация возрождения: + if (not gLoadGameMode) and (not Silent) then begin - Anim := TAnimation.Create(ID, False, 3); - g_GFX_OnceAnim(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32, - FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32, Anim); - Anim.Free(); + 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; @@ -3988,7 +3513,10 @@ begin FPhysics := False; FWantsInGame := False; FSpawned := False; - FCorpse := -1; + + {$IFDEF ENABLE_CORPSES} + FCorpse := -1; + {$ENDIF} if FNoRespawn then begin @@ -4026,8 +3554,9 @@ 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(); @@ -4042,30 +3571,32 @@ begin 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 + 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)+120) // налево - end - else - 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; @@ -4126,9 +3657,6 @@ begin end; function TPlayer.TeleportTo(X, Y: Integer; silent: Boolean; dir: Byte): Boolean; -var - Anim: TAnimation; - ID: DWORD; begin Result := False; @@ -4142,17 +3670,16 @@ begin FJustTeleported := True; - Anim := nil; if not silent then begin - if g_Frames_Get(ID, 'FRAMES_TELEPORT') then - begin - Anim := TAnimation.Create(ID, False, 3); - end; - g_Sound_PlayExAt('SOUND_GAME_TELEPORT', FObj.X, FObj.Y); - g_GFX_OnceAnim(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32, - FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32, Anim); + {$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, @@ -4198,12 +3725,15 @@ begin end; end; - if not silent and (Anim <> nil) then + if not silent then begin - g_GFX_OnceAnim(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-32, - FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)-32, Anim); - Anim.Free(); - + {$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, @@ -4221,41 +3751,6 @@ begin 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; @@ -4296,8 +3791,10 @@ begin FLoss := 0; end; - if FAlive and (FPunchAnim <> nil) then - FPunchAnim.Update(); + if FAlive then + FPunchAnim.Update; + if FPunchAnim.played then + FPunchAnim.Disable; if FAlive and (gFly or FJetpack) then FlySmoke(); @@ -4538,21 +4035,23 @@ begin 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 @@ -4596,7 +4095,9 @@ begin 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 @@ -4679,14 +4180,13 @@ begin if (FActionAnim = A_PAIN) and (FModel.Animation <> A_PAIN) then begin FModel.ChangeAnimation(FActionAnim, FActionForce); - FModel.GetCurrentAnimation.MinLength := i; - FModel.GetCurrentAnimationMask.MinLength := i; + FModel.AnimState.MinLength := i; end else FModel.ChangeAnimation(FActionAnim, FActionForce and (FModel.Animation <> A_STAND)); - if (FModel.GetCurrentAnimation.Played or ((not FActionChanged) and (FModel.Animation = A_WALK))) + if (FModel.AnimState.Played or ((not FActionChanged) and (FModel.Animation = A_WALK))) then SetAction(A_STAND, True); - if not ((FModel.Animation = A_WALK) and (Abs(FObj.Vel.X) < 4) and not FModel.Fire) then FModel.Update; + if not ((FModel.Animation = A_WALK) and (Abs(FObj.Vel.X) < 4) and not FModel.GetFire()) then FModel.Update; for b := Low(FKeys) to High(FKeys) do if FKeys[b].Time = 0 then FKeys[b].Pressed := False else Dec(FKeys[b].Time); @@ -4869,8 +4369,9 @@ begin g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', GameX, Gamey); FFireAngle := FAngle; f := 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: @@ -4878,8 +4379,10 @@ begin g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey); FFireAngle := FAngle; f := True; - FShellTimer := 10; - FShellType := SHELL_SHELL; + {$IFDEF ENABLE_SHELLS} + FShellTimer := 10; + FShellType := SHELL_SHELL; + {$ENDIF} end; WEAPON_SHOTGUN2: @@ -4887,8 +4390,10 @@ begin g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', Gamex, Gamey); FFireAngle := FAngle; f := True; - FShellTimer := 13; - FShellType := SHELL_DBLSHELL; + {$IFDEF ENABLE_SHELLS} + FShellTimer := 13; + FShellType := SHELL_DBLSHELL; + {$ENDIF} end; WEAPON_CHAINGUN: @@ -4896,8 +4401,9 @@ begin g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', Gamex, Gamey); FFireAngle := FAngle; f := 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: @@ -4926,8 +4432,9 @@ begin g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey); FFireAngle := FAngle; f := 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: @@ -5376,7 +4883,7 @@ begin // Время до повторного респауна, смены оружия, исользования, захвата флага for i := T_RESPAWN to T_FLAGCAP do utils.writeInt(st, LongWord(FTime[i])); // Название модели - utils.writeStr(st, FModel.Name); + utils.writeStr(st, FModel.GetName()); // Цвет модели utils.writeInt(st, Byte(FColor.R)); utils.writeInt(st, Byte(FColor.G)); @@ -5681,17 +5188,17 @@ begin end; procedure TPlayer.FlySmoke(Times: DWORD = 1); -var - id, i: DWORD; - Anim: TAnimation; + var i: DWORD; begin if (Random(5) = 1) and (Times = 1) then Exit; 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 @@ -5699,37 +5206,33 @@ begin Exit; end; - if g_Frames_Get(id, 'FRAMES_SMOKE') then + for i := 1 to Times do begin - for i := 1 to Times do - begin - Anim := TAnimation.Create(id, False, 3); - Anim.Alpha := 150; - g_GFX_OnceAnim(Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(Anim.Width div 2), - Obj.Y+Obj.Rect.Height-4+Random(8+Times*2), Anim, ONCEANIM_SMOKE); - Anim.Free(); - end; + {$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; procedure TPlayer.OnFireFlame(Times: DWORD = 1); -var - id, i: DWORD; - Anim: TAnimation; + var i: DWORD; begin if (Random(10) = 1) and (Times = 1) then Exit; - if g_Frames_Get(id, 'FRAMES_FLAME') then + for i := 1 to Times do begin - for i := 1 to Times do - begin - Anim := TAnimation.Create(id, False, 3); - Anim.Alpha := 0; - g_GFX_OnceAnim(Obj.X+Obj.Rect.X+Random(Obj.Rect.Width+Times*2)-(Anim.Width div 2), - Obj.Y+8+Random(8+Times*2), Anim, ONCEANIM_SMOKE); - Anim.Free(); - end; + {$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; @@ -5747,213 +5250,6 @@ begin 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; - FModelName := ModelName; - FMess := aMess; - - if FMess then - begin - FState := CORPSE_STATE_MESS; - g_PlayerModel_GetAnim(ModelName, A_DIE2, FAnimation, FAnimationMask); - end - else - begin - FState := CORPSE_STATE_NORMAL; - g_PlayerModel_GetAnim(ModelName, A_DIE1, FAnimation, FAnimationMask); - end; -end; - -destructor TCorpse.Destroy(); -begin - FAnimation.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 - pm: TPlayerModel; - Blood: TModelBlood; -begin - if FState = CORPSE_STATE_REMOVEME then - Exit; - - FDamage := FDamage + Value; - - if FDamage > 150 then - begin - if FAnimation <> nil then - begin - FAnimation.Free(); - FAnimation := nil; - - 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), - FModelName, FColor); - // Звук мяса от трупа: - pm := g_PlayerModel_Get(FModelName); - pm.PlaySound(MODELSOUND_DIE, 5, FObj.X, FObj.Y); - pm.Free; - - // Зловещий смех: - if (gBodyKillEvent <> -1) - and gDelayedEvents[gBodyKillEvent].Pending then - gDelayedEvents[gBodyKillEvent].Pending := False; - gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, SpawnerUID); - end; - end - else - begin - Blood := g_PlayerModel_GetBlood(FModelName); - 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 FAnimation <> nil then - FAnimation.Update(); - if FAnimationMask <> nil then - FAnimationMask.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(FColor.R)); - utils.writeInt(st, Byte(FColor.G)); - utils.writeInt(st, Byte(FColor.B)); - // Объект трупа - Obj_SaveState(st, @FObj); - utils.writeInt(st, Word(FPlayerUID)); - // Есть ли анимация - anim := (FAnimation <> nil); - utils.writeBool(st, anim); - // Если есть - сохраняем - if anim then FAnimation.SaveState(st); - // Есть ли маска анимации - anim := (FAnimationMask <> nil); - utils.writeBool(st, anim); - // Если есть - сохраняем - if anim then FAnimationMask.SaveState(st); -end; - - -procedure TCorpse.LoadState (st: TStream); -var - anim: Boolean; -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); - // Цвет - FColor.R := utils.readByte(st); - FColor.G := utils.readByte(st); - FColor.B := utils.readByte(st); - // Объект трупа - Obj_LoadState(@FObj, st); - FPlayerUID := utils.readWord(st); - // Есть ли анимация - anim := utils.readBool(st); - // Если есть - загружаем - if anim then - begin - Assert(FAnimation <> nil, 'TCorpse.LoadState: no FAnimation'); - FAnimation.LoadState(st); - end; - // Есть ли маска анимации - anim := utils.readBool(st); - // Если есть - загружаем - if anim then - begin - Assert(FAnimationMask <> nil, 'TCorpse.LoadState: no FAnimationMask'); - FAnimationMask.LoadState(st); - end; -end; - { T B o t : } constructor TBot.Create();