summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 55f2017)
raw | patch | inline | side by side (parent: 55f2017)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sat, 29 Jan 2022 14:56:47 +0000 (17:56 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sat, 29 Jan 2022 14:56:47 +0000 (17:56 +0300) |
17 files changed:
src/game/Doom2DF.lpr | patch | blob | history | |
src/game/g_console.pas | patch | blob | history | |
src/game/g_corpses.pas | [new file with mode: 0644] | patch | blob |
src/game/g_game.pas | patch | blob | history | |
src/game/g_gibs.pas | patch | blob | history | |
src/game/g_menu.pas | patch | blob | history | |
src/game/g_monsters.pas | patch | blob | history | |
src/game/g_netmsg.pas | patch | blob | history | |
src/game/g_options.pas | patch | blob | history | |
src/game/g_panel.pas | patch | blob | history | |
src/game/g_player.pas | patch | blob | history | |
src/game/g_saveload.pas | patch | blob | history | |
src/game/g_shells.pas | patch | blob | history | |
src/game/g_weapons.pas | patch | blob | history | |
src/game/opengl/r_game.pas | patch | blob | history | |
src/game/opengl/r_player.pas | patch | blob | history | |
src/shared/a_modes.inc | patch | blob | history |
diff --git a/src/game/Doom2DF.lpr b/src/game/Doom2DF.lpr
index ec2bdfae15a8e46ee34278d1ae5bf357d767c914..28e3b6228ad0c23374b538de64b5130d14508934 100644 (file)
--- a/src/game/Doom2DF.lpr
+++ b/src/game/Doom2DF.lpr
{$IFDEF ENABLE_SHELLS}
g_shells in 'g_shells.pas',
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses in 'g_corpses.pas',
+ {$ENDIF}
g_items in 'g_items.pas',
g_map in 'g_map.pas',
g_monsters in 'g_monsters.pas',
diff --git a/src/game/g_console.pas b/src/game/g_console.pas
index 99335bab48ac31344207cbba3491b32521c31b24..687a412661b7b6fa3ea0b4eeb9b684c26981f734 100644 (file)
--- a/src/game/g_console.pas
+++ b/src/game/g_console.pas
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
g_textures, e_input, g_game, g_player, g_items,
SysUtils, g_basic, g_options, Math, e_res,
g_language, g_net, g_netmsg, e_log, conbuf;
{$IFDEF ENABLE_GIBS}
WriteLn(f, 'g_max_gibs ', g_Gibs_GetMax());
{$ENDIF}
- WriteLn(f, 'g_max_corpses ', g_Corpses_GetMax());
+ {$IFDEF ENABLE_CORPSES}
+ WriteLn(f, 'g_max_corpses ', g_Corpses_GetMax());
+ {$ENDIF}
WriteLn(f, 'sv_intertime ', gDefInterTime);
// gameplay settings
diff --git a/src/game/g_corpses.pas b/src/game/g_corpses.pas
--- /dev/null
+++ b/src/game/g_corpses.pas
@@ -0,0 +1,396 @@
+(* Copyright (C) Doom 2D: Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License ONLY.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
+unit g_corpses;
+
+interface
+
+ uses Classes, g_phys, g_player, g_playermodel, g_base;
+
+ const
+ CORPSE_STATE_REMOVEME = 0;
+ CORPSE_STATE_NORMAL = 1;
+ CORPSE_STATE_MESS = 2;
+
+ PLAYER_CORPSERECT: TRectWH = (X:15; Y:48; Width:34; Height:16);
+
+ DefaultCorpsesMax = 20;
+
+ type
+ 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;
+ property PlayerUID: Word read FPlayerUID;
+ end;
+
+ var
+ gCorpses: Array of TCorpse;
+
+ procedure g_Corpses_SetMax (Count: Word);
+ function g_Corpses_GetMax (): Word;
+
+ function g_Corpses_Create (Player: TPlayer): Integer;
+ procedure g_Corpses_RemoveAll;
+ procedure g_Corpses_Update;
+
+ {$IFNDEF HEADLESS}
+ function g_Corpses_GetCameraObj (Player: TPlayer): TObj;
+ {$ENDIF}
+
+implementation
+
+ uses
+ {$IFDEF ENABLE_GFX}
+ g_gfx,
+ {$ENDIF}
+ {$IFDEF ENABLE_GIBS}
+ g_gibs,
+ {$ENDIF}
+ Math,
+ utils, g_saveload, xstreams,
+ g_game, g_textures, g_map
+ ;
+
+ var
+ MaxCorpses: Word = DefaultCorpsesMax;
+
+ 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);
+ {$IFDEF ENABLE_GFX}
+ var Blood: TModelBlood;
+ {$ENDIF}
+ begin
+ if FState = CORPSE_STATE_REMOVEME then
+ Exit;
+ FDamage := FDamage + Value;
+
+{$IFDEF ENABLE_GIBS}
+ if FDamage > 150 then
+ begin
+ if FModel <> nil then
+ begin
+ FState := CORPSE_STATE_REMOVEME;
+ g_Gibs_Create(
+ 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
+{$ENDIF}
+ begin
+ FObj.Vel.X := FObj.Vel.X + vx;
+ FObj.Vel.Y := FObj.Vel.Y + vy;
+ {$IFDEF ENABLE_GFX}
+ Blood := FModel.GetBlood();
+ 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);
+ {$ENDIF}
+ 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
+ FState := CORPSE_STATE_REMOVEME
+ else 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, 0, False);
+ // animation for mask (same as animation, compat with older saves)
+ anim := (FModel <> nil);
+ utils.writeBool(st, anim);
+ if anim then FModel.AnimState.SaveState(st, 0, False);
+ end;
+
+ procedure TCorpse.LoadState (st: TStream);
+ var anim, blending: Boolean; r, g, b, alpha: 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, alpha, blending);
+ 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, alpha, blending);
+ stub.Free;
+ 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_Corpses_Create (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.UID) then
+ gCorpses[i].FPlayerUID := 0;
+ end;
+
+ if Player.Obj.Y >= gMapInfo.Height+128 then
+ Exit;
+
+{$IFDEF ENABLE_GIBS}
+ if (Player.Health < -50) and (gGibsCount > 0) then
+ begin
+ g_Gibs_Create(Player.Obj.X + PLAYER_RECT_CX, Player.Obj.Y + PLAYER_RECT_CY, Player.Model.id, Player.Model.Color);
+ end
+ else
+{$ENDIF}
+ 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(Player.Obj.X, Player.Obj.Y, Player.Model.GetName(), Player.Health < -20);
+ gCorpses[find_id].FModel.Color := Player.Model.Color;
+ gCorpses[find_id].FObj.Vel := Player.Obj.Vel;
+ gCorpses[find_id].FObj.Accel := Player.Obj.Accel;
+ gCorpses[find_id].FPlayerUID := Player.UID;
+ Result := find_id;
+ end
+ end;
+
+ procedure g_Corpses_Update;
+ var i: Integer;
+ begin
+ if gCorpses <> nil then
+ begin
+ for i := 0 to High(gCorpses) do
+ begin
+ if gCorpses[i] <> nil then
+ begin
+ if gCorpses[i].State = CORPSE_STATE_REMOVEME then
+ begin
+ gCorpses[i].Free();
+ gCorpses[i] := nil;
+ end
+ else
+ gCorpses[i].Update();
+ end;
+ end;
+ end;
+ end;
+
+ procedure g_Corpses_RemoveAll;
+ var i: Integer;
+ begin
+ if gCorpses <> nil then
+ for i := 0 to High(gCorpses) do
+ gCorpses[i].Free();
+ gCorpses := nil;
+ SetLength(gCorpses, MaxCorpses);
+ end;
+
+{$IFNDEF HEADLESS}
+ function g_Corpses_GetCameraObj (Player: TPlayer): TObj;
+ begin
+ {$IFDEF ENABLE_CORPSES}
+ if (not Player.Alive) and (not Player.Spectator) and
+ (Player.Corpse >= 0) and (Player.Corpse < Length(gCorpses)) and
+ (gCorpses[Player.Corpse] <> nil) and (gCorpses[Player.Corpse].PlayerUID = Player.UID) then
+ begin
+ gCorpses[Player.Corpse].FObj.slopeUpLeft := Player.Obj.slopeUpLeft;
+ Result := gCorpses[Player.Corpse].Obj;
+ end
+ else
+ begin
+ Result := Player.Obj;
+ end;
+ {$ELSE}
+ Result := Player.Obj;
+ {$ENDIF}
+ end;
+{$ENDIF}
+
+end.
diff --git a/src/game/g_game.pas b/src/game/g_game.pas
index 8d47073d2a4eb41ae01a75517b34faf41d31ce59..6812d516e78746f006bdd531fa270a63995378e8 100644 (file)
--- a/src/game/g_game.pas
+++ b/src/game/g_game.pas
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
{$IFNDEF HEADLESS}
r_render, g_system,
{$ENDIF}
g_Map_Free(freeTextures);
g_Player_Free();
- g_Player_RemoveAllCorpses();
+
+ {$IFDEF ENABLE_GIBS}
+ g_Gibs_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENALBE_SHELLS}
+ g_Shells_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_RemoveAll;
+ {$ENDIF}
gGameSettings.GameType := GT_NONE;
if gGameSettings.GameMode = GM_SINGLE then
{$IFDEF ENABLE_GIBS}
g_Gibs_Update;
{$ENDIF}
- g_Player_UpdatePhysicalObjects();
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_Update;
+ {$ENDIF}
{$IFDEF ENABLE_SHELLS}
g_Shells_Update;
{$ENDIF}
nws: AnsiString;
begin
g_Map_Free((Map <> gCurrentMapFileName) and (oldMapPath <> gCurrentMapFileName));
- g_Player_RemoveAllCorpses();
+
+ {$IFDEF ENABLE_GIBS}
+ g_Gibs_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENALBE_SHELLS}
+ g_Shells_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_RemoveAll;
+ {$ENDIF}
if (not g_Game_IsClient) and
(gSwitchGameMode <> gGameSettings.GameMode) and
Exit;
end;
- g_Player_RemoveAllCorpses;
+ {$IFDEF ENABLE_GIBS}
+ g_Gibs_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENALBE_SHELLS}
+ g_Shells_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_RemoveAll;
+ {$ENDIF}
+
g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
if g_Game_IsNet then
MH_SEND_GameEvent(NET_EV_LMS_START);
begin
if Length(p) = 2 then
begin
- a := Max(0, StrToInt(p[1]));
- g_Corpses_SetMax(a)
+ {$IFDEF ENABLE_CORPSES}
+ a := Max(0, StrToInt(p[1]));
+ g_Corpses_SetMax(a)
+ {$ENDIF}
end
else if Length(p) = 1 then
begin
- e_LogWritefln('%s', [g_Corpses_GetMax()])
+ {$IFDEF ENABLE_CORPSES}
+ e_LogWritefln('%s', [g_Corpses_GetMax()])
+ {$ELSE}
+ e_LogWritefln('%s', [0])
+ {$ENDIF}
end
else
begin
diff --git a/src/game/g_gibs.pas b/src/game/g_gibs.pas
index 627764b6142c5de86389c69a42c482f2f7278fc3..804126414c3eb35090d7cda8ac5f2fdc19eac5f4 100644 (file)
--- a/src/game/g_gibs.pas
+++ b/src/game/g_gibs.pas
function g_Gibs_GetMax (): Word;
procedure g_Gibs_Create (fX, fY, mid: Integer; fColor: TRGB);
+ procedure g_Gibs_RemoveAll;
procedure g_Gibs_Update;
implementation
end;
end;
+ procedure g_Gibs_RemoveAll;
+ var i: Integer;
+ begin
+ i := g_Gibs_GetMax();
+ g_Gibs_SetMax(0);
+ g_Gibs_SetMax(i);
+ end;
+
procedure g_Gibs_Update;
var i: Integer; vel: TPoint2i; mr: Word;
begin
diff --git a/src/game/g_menu.pas b/src/game/g_menu.pas
index d88c79f45a04d95bc68515b1f47430661f7f9af0..33a2477065a524de5aa0754756445aeba646212e 100644 (file)
--- a/src/game/g_menu.pas
+++ b/src/game/g_menu.pas
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
g_gui, r_textures, r_graphics, g_game, g_map,
g_base, g_basic, g_console, g_sound, g_player, g_options, g_weapons,
e_log, SysUtils, CONFIG, g_playermodel, DateUtils,
{$IFDEF ENABLE_GIBS}
g_Gibs_SetMax(TGUIScroll(menu.GetControl('scGibsMax')).Value*25);
{$ENDIF}
- g_Corpses_SetMax(TGUIScroll(menu.GetControl('scCorpsesMax')).Value*5);
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_SetMax(TGUIScroll(menu.GetControl('scCorpsesMax')).Value*5);
+ {$ENDIF}
{$IFDEF ENABLE_GIBS}
case TGUISwitch(menu.GetControl('swGibsCount')).ItemIndex of
{$IFDEF ENABLE_GIBS}
TGUIScroll(menu.GetControl('scGibsMax')).Value := g_Gibs_GetMax() div 25;
{$ENDIF}
- TGUIScroll(menu.GetControl('scCorpsesMax')).Value := g_Corpses_GetMax() div 5;
+ {$IFDEF ENABLE_CORPSES}
+ TGUIScroll(menu.GetControl('scCorpsesMax')).Value := g_Corpses_GetMax() div 5;
+ {$ENDIF}
TGUISwitch(menu.GetControl('swBloodCount')).ItemIndex := gBloodCount;
with TGUISwitch(menu.GetControl('swScreenFlash')) do
index fbb75a56f1929a1b0b66cc734f6aa29f522287fb..9877ece2b6bb4a7ce11584deff04a3dd9f287204 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
e_log, g_sound, g_player, g_game,
g_weapons, g_triggers, g_items, g_options,
g_console, g_map, Math, wadreader,
end;
procedure TMonster.Update();
-var
- a, b, sx, sy, wx, wy, oldvelx: Integer;
- st: Word;
- o, co: TObj;
- fall: Boolean;
- mon: TMonster;
- mit: PMonster;
- it: TMonsterGrid.Iter;
+ {$IFDEF ENABLE_CORPSES}
+ var co: TObj;
+ {$ENDIF}
+ {$IF DEFINED(ENABLE_GIBS) OR DEFINED(ENABLE_CORPSES)}
+ var b: Integer;
+ {$ENDIF}
+ var
+ a, sx, sy, wx, wy, oldvelx: Integer;
+ st: Word;
+ o: TObj;
+ fall: Boolean;
+ mon: TMonster;
+ mit: PMonster;
+ it: TMonsterGrid.Iter;
label
_end;
begin
end;
end;
{$ENDIF}
- // Боссы могут пинать трупы:
- if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and
- (FObj.Vel.X <> 0) and (gCorpses <> nil) then
- begin
- b := Abs(FObj.Vel.X);
- if b > 1 then b := b * (Random(8 div b) + 1);
- for a := 0 to High(gCorpses) do
- if (gCorpses[a] <> nil) and (gCorpses[a].State > 0) then
- begin
- co := gCorpses[a].Obj;
- if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
- FObj.Rect.Width, 8, @co) and (Random(3) = 0) then
- // Пинаем трупы
- if FObj.Vel.X < 0 then
- gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево
- else
- gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо
- end;
- end;
+ {$IFDEF ENABLE_CORPSES}
+ // Боссы могут пинать трупы:
+ if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and
+ (FObj.Vel.X <> 0) and (gCorpses <> nil) then
+ begin
+ b := Abs(FObj.Vel.X);
+ if b > 1 then b := b * (Random(8 div b) + 1);
+ for a := 0 to High(gCorpses) do
+ if (gCorpses[a] <> nil) and (gCorpses[a].State > 0) then
+ begin
+ co := gCorpses[a].Obj;
+ if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
+ FObj.Rect.Width, 8, @co) and (Random(3) = 0) then
+ // Пинаем трупы
+ if FObj.Vel.X < 0 then
+ gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево
+ else
+ gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо
+ end;
+ end;
+ {$ENDIF}
// Если цель высоко, то, возможно, прыгаем:
if sy < -40 then
if g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj) then
end;
procedure TMonster.ClientUpdate();
-var
- a, b, sx, sy, oldvelx: Integer;
- st: Word;
- o, co: TObj;
- fall: Boolean;
+ {$IFDEF ENABLE_CORPSES}
+ var a, b: Integer; co: TObj;
+ {$ENDIF}
+ var
+ sx, sy, oldvelx: Integer;
+ st: Word;
+ o: TObj;
+ fall: Boolean;
label
_end;
begin
end;
end;
{$ENDIF}
- // Боссы могут пинать трупы:
- if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and
- (FObj.Vel.X <> 0) and (gCorpses <> nil) then
- begin
- b := Abs(FObj.Vel.X);
- if b > 1 then b := b * (Random(8 div b) + 1);
- for a := 0 to High(gCorpses) do
- if (gCorpses[a] <> nil) and (gCorpses[a].State > 0) then
- begin
- co := gCorpses[a].Obj;
- if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
- FObj.Rect.Width, 8, @co) and (Random(3) = 0) then
- // Пинаем трупы
- if FObj.Vel.X < 0 then
- gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево
- else
- gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо
- end;
- end;
+ {$IFDEF ENABLE_CORPSES}
+ // Боссы могут пинать трупы:
+ if (FMonsterType in [MONSTER_CYBER, MONSTER_SPIDER, MONSTER_ROBO]) and
+ (FObj.Vel.X <> 0) and (gCorpses <> nil) then
+ begin
+ b := Abs(FObj.Vel.X);
+ if b > 1 then b := b * (Random(8 div b) + 1);
+ for a := 0 to High(gCorpses) do
+ if (gCorpses[a] <> nil) and (gCorpses[a].State > 0) then
+ begin
+ co := gCorpses[a].Obj;
+ if g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y+FObj.Rect.Height-4,
+ FObj.Rect.Width, 8, @co) and (Random(3) = 0) then
+ // Пинаем трупы
+ if FObj.Vel.X < 0 then
+ gCorpses[a].Damage(b*2, FUID, -b, Random(7)) // налево
+ else
+ gCorpses[a].Damage(b*2, FUID, b, Random(7)); // направо
+ end;
+ end;
+ {$ENDIF}
end;
FSleep := FSleep + 1;
diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index 775a7ae0c06afeb392244540d9917605fb199097..b719a8f1575f00ef170ebb6c6410e46a8947c7df 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
{$IFDEF ENABLE_GFX}
g_gfx,
{$ENDIF}
+ {$IFDEF ENABLE_GIBS}
+ g_gibs,
+ {$ENDIF}
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
Math, ENet, e_input, e_log, g_base, g_basic,
g_textures, g_sound, g_console, g_options,
g_game, g_player, g_map, g_panel, g_items, g_weapons, g_phys,
NET_EV_LMS_START:
begin
- g_Player_RemoveAllCorpses;
+ {$IFDEF ENABLE_GIBS}
+ g_Gibs_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENALBE_SHELLS}
+ g_Shells_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_RemoveAll;
+ {$ENDIF}
gLMSRespawn := LMS_RESPAWN_NONE;
g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
end;
diff --git a/src/game/g_options.pas b/src/game/g_options.pas
index 83bae9679f92697cceb072d3ed4625f75bbd46a0..936f2b8cd8ad49444d168b110690315eb4a780d4 100644 (file)
--- a/src/game/g_options.pas
+++ b/src/game/g_options.pas
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
e_log, e_input, g_console, g_sound, g_player, Math,
g_map, g_net, g_netmaster, SysUtils, CONFIG, g_game,
g_items, wadreader, envvars;
{$IFDEF ENABLE_SHELLS}
g_Shells_SetMax(DefaultShellMax);
{$ENDIF}
- g_Corpses_SetMax(20);
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_SetMax(DefaultCorpsesMax);
+ {$ENDIF}
{$IFDEF ENABLE_GIBS}
g_Gibs_SetMax(DefaultGibsMax);
gGibsCount := DefaultGibsCount;
diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas
index f9b7371f213c2f8b4b380e02ec61bd7b03b6672f..61d341ebb2d82982f2c786ad463b2463a1ded98d 100644 (file)
--- a/src/game/g_panel.pas
+++ b/src/game/g_panel.pas
{$IFDEF ENABLE_GIBS}
g_gibs,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
g_basic, g_map, g_game, g_weapons, g_triggers,
g_console, g_language, g_monsters, g_player, g_grid, e_log, geom, utils, xstreams
;
{$IFDEF ENABLE_GIBS}
gib: PGib;
{$ENDIF}
- cor: TCorpse;
+ {$IFDEF ENABLE_CORPSES}
+ cor: TCorpse;
+ {$ENDIF}
+ {$IF DEFINED(ENABLE_GIBS) OR DEFINED(ENABLE_CORPSES)}
+ ontop: Boolean;
+ {$ENDIF}
mon: TMonster;
mpfrid: LongWord;
- ontop: Boolean;
actMoveTrig: Boolean;
actSizeTrig: Boolean;
begin
end;
{$ENDIF}
- // move and push corpses
- for f := 0 to High(gCorpses) do
- begin
- cor := gCorpses[f];
- if (cor = nil) then continue;
- cor.getMapBox(px, py, pw, ph);
- if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
- if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+ {$IFDEF ENABLE_CORPSES}
+ // move and push corpses
+ for f := 0 to High(gCorpses) do
begin
- // set new position
- cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+ cor := gCorpses[f];
+ if (cor = nil) then continue;
+ cor.getMapBox(px, py, pw, ph);
+ if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+ if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+ begin
+ // set new position
+ cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+ end;
end;
- end;
+ {$ENDIF}
// collect monsters
monCheckListUsed := 0;
diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index aab6b385b7658f3650a1880468bea002a799d92e..991b0d8799b91c6528ec9c49bbf63ab2b39f8e36 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
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;
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
// 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;
- 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
Goals: SmallInt;
var
gPlayers: Array of TPlayer;
- gCorpses: Array of TCorpse;
gTeamStat: TTeamStat;
gFly: Boolean = False;
gAimLine: Boolean = False;
function Lerp(X, Y, Factor: Integer): Integer;
-procedure g_Corpses_SetMax(Count: Word);
-function g_Corpses_GetMax(): Word;
-
procedure g_Player_Init();
procedure g_Player_Free();
function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boolean): Word;
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_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);
{$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,
BOTLIST_FILENAME = 'botlist.txt';
var
- MaxCorpses: Word = 20;
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_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;
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
-{$IFDEF ENABLE_GIBS}
- if (FHealth < -50) and (gGibsCount > 0) then
- begin
- g_Gibs_Create(FObj.X + PLAYER_RECT_CX, FObj.Y + PLAYER_RECT_CY, FModel.id, FModel.Color);
- end
- else
-{$ENDIF}
- 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
- end;
-end;
-
-procedure g_Player_UpdatePhysicalObjects();
- var i: Integer;
-begin
- 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();
-end;
-
-procedure g_Player_RemoveAllCorpses();
- var i: Integer;
-begin
- {$IFDEF ENABLE_GIBS}
- i := g_Gibs_GetMax();
- g_Gibs_SetMax(0);
- g_Gibs_SetMax(i);
- {$ENDIF}
- {$IFDEF ENABLE_SHELLS}
- i := g_Shells_GetMax();
- g_Shells_SetMax(0);
- g_Shells_SetMax(i);
- {$ENDIF}
-
- 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;
FFirePainTime := 0;
FFireAttacker := 0;
FHandicap := 100;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
FActualModelName := 'doomer';
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
FDeath := 0;
FSecrets := 0;
FSpawnInvul := 0;
- FCorpse := -1;
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
FReady := False;
if FNoRespawn then
begin
FPain := 0;
FLastHit := 0;
FSpawnInvul := 0;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
if not g_Game_IsServer then
Exit;
FPhysics := False;
FWantsInGame := False;
FSpawned := False;
- FCorpse := -1;
+
+ {$IFDEF ENABLE_CORPSES}
+ FCorpse := -1;
+ {$ENDIF}
if FNoRespawn then
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;
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);
- {$IFDEF ENABLE_GFX}
- var Blood: TModelBlood;
- {$ENDIF}
-begin
- if FState = CORPSE_STATE_REMOVEME then
- Exit;
-
- FDamage := FDamage + Value;
-
-{$IFDEF ENABLE_GIBS}
- if FDamage > 150 then
- begin
- if FModel <> nil then
- begin
- FState := CORPSE_STATE_REMOVEME;
-
- g_Gibs_Create(
- 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
-{$ENDIF}
- begin
- FObj.Vel.X := FObj.Vel.X + vx;
- FObj.Vel.Y := FObj.Vel.Y + vy;
- {$IFDEF ENABLE_GFX}
- Blood := FModel.GetBlood();
- 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);
- {$ENDIF}
- 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, 0, False);
- // animation for mask (same as animation, compat with older saves)
- anim := (FModel <> nil);
- utils.writeBool(st, anim);
- if anim then FModel.AnimState.SaveState(st, 0, False);
-end;
-
-
-procedure TCorpse.LoadState (st: TStream);
- var anim, blending: Boolean; r, g, b, alpha: 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, alpha, blending);
- 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, alpha, blending);
- stub.Free;
-end;
-
{ T B o t : }
constructor TBot.Create();
index d603440d839241a9c3513f59140ae34d0ca755ba..14539ddd88f6ef4ba2dedcb505d08a6a39f0fc5c 100644 (file)
--- a/src/game/g_saveload.pas
+++ b/src/game/g_saveload.pas
implementation
uses
+ {$IFDEF ENABLE_GIBS}
+ g_gibs,
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
MAPDEF, utils, xstreams,
g_game, g_items, g_map, g_monsters, g_triggers,
g_basic, Math, wadreader,
end;
end;
+procedure g_Player_Corpses_SaveState (st: TStream);
+ {$IFDEF ENABLE_CORPSES}
+ var i: Integer;
+ {$ENDIF}
+ var count: Integer;
+begin
+ count := 0;
+ {$IFDEF ENABLE_CORPSES}
+ for i := 0 to High(gCorpses) do
+ if (gCorpses[i] <> nil) then
+ Inc(count);
+ {$ENDIF}
+ utils.writeInt(st, LongInt(count));
+ {$IFDEF ENABLE_CORPSES}
+ if count > 0 then
+ begin
+ for i := 0 to High(gCorpses) do
+ begin
+ if gCorpses[i] <> nil then
+ begin
+ utils.writeStr(st, gCorpses[i].Model.GetName());
+ utils.writeBool(st, gCorpses[i].Mess);
+ gCorpses[i].SaveState(st);
+ end;
+ end;
+ end;
+ {$ENDIF}
+end;
+
+procedure g_Player_Corpses_LoadState (st: TStream);
+ {$IFDEF ENABLE_CORPSES}
+ var str: String; b: Boolean; i: Integer;
+ {$ENDIF}
+ var count: Integer;
+begin
+ assert(st <> nil);
+
+ {$IFDEF ENABLE_GIBS}
+ g_Gibs_RemoveAll;
+ {$ENDIF}
+ {$IFDEF ENALBE_SHELLS}
+ g_Shells_RemoveAll; // ???
+ {$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_Corpses_RemoveAll;
+ {$ENDIF}
+
+ count := utils.readLongInt(st);
+
+ {$IFDEF ENABLE_CORPSES}
+ if (count < 0) or (count > Length(gCorpses)) then
+ raise XStreamError.Create('invalid number of corpses');
+ 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;
+ {$ELSE}
+ if count <> 0 then
+ raise XStreamError.Create('corpses not supported in this version');
+ {$ENDIF}
+end;
function g_SaveGameTo (const filename: AnsiString; const aname: AnsiString; deleteOnError: Boolean=true): Boolean;
var
diff --git a/src/game/g_shells.pas b/src/game/g_shells.pas
index de0fc86c06380e51c2092bb0449ae670515b5025..1ba5fdb9d0d53130d8fad8475a1c574588d5c261 100644 (file)
--- a/src/game/g_shells.pas
+++ b/src/game/g_shells.pas
function g_Shells_GetMax (): Word;
procedure g_Shells_Create (fX, fY, dX, dY: Integer; T: Byte);
+ procedure g_Shells_RemoveAll;
procedure g_Shells_Update;
implementation
end;
end;
+ procedure g_Shells_RemoveAll;
+ var i: Integer;
+ begin
+ i := g_Shells_GetMax();
+ g_Shells_SetMax(0);
+ g_Shells_SetMax(i);
+ end;
+
procedure g_Shells_SoundBounce(X, Y: Integer; T: Byte);
var k: Integer;
begin
diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas
index 0353a85a5809c7a9496770d8651ed676655f6326..beabbcfe8490cb53041553547c54150939f22944 100644 (file)
--- a/src/game/g_weapons.pas
+++ b/src/game/g_weapons.pas
{$IFDEF ENABLE_GIBS}
g_gibs,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
Math, g_map, g_player, g_sound, g_panel,
g_console, g_options, g_game,
g_triggers, MAPDEF, e_log, g_monsters, g_saveload,
begin
//g_Sound_PlayEx('SOUND_WEAPON_EXPLODEBFG', 255);
- h := High(gCorpses);
-
- if gAdvCorpses and (h <> -1) then
- for i := 0 to h do
- if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
- with gCorpses[i] do
- if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
- Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
- g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
- Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
+ {$IFDEF ENABLE_CORPSES}
+ h := High(gCorpses);
+ if gAdvCorpses and (h <> -1) then
+ begin
+ for i := 0 to h do
+ begin
+ if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
+ begin
+ with gCorpses[i] do
begin
- Damage(50, SpawnerUID, 0, 0);
- g_Weapon_BFGHit(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
- Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2));
+ if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
+ Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
+ g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
+ Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
+ begin
+ Damage(50, SpawnerUID, 0, 0);
+ g_Weapon_BFGHit(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2), Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2));
+ end;
end;
+ end;
+ end;
+ end;
+ {$ENDIF}
st := TEAM_NONE;
pl := g_Player_Get(SpawnerUID);
end;
function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorpses: Boolean = True): Byte;
-var
- i, h: Integer;
+ {$IFDEF ENABLE_CORPSES}
+ var i: Integer;
+ {$ENDIF}
+ var h: Integer;
function PlayerHit(Team: Byte = 0): Boolean;
var
begin
Result := 0;
- if HitCorpses then
- begin
- h := High(gCorpses);
-
- if gAdvCorpses and (h <> -1) then
- for i := 0 to h do
- if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) and
- g_Obj_Collide(obj, @gCorpses[i].Obj) then
+ {$IFDEF ENABLE_CORPSES}
+ if HitCorpses then
+ begin
+ h := High(gCorpses);
+ if gAdvCorpses and (h <> -1) then
+ begin
+ for i := 0 to h do
begin
- // Ðàñïèëèâàåì òðóï:
- gCorpses[i].Damage(d, SpawnerUID, (obj^.Vel.X+obj^.Accel.X) div 4,
- (obj^.Vel.Y+obj^.Accel.Y) div 4);
- Result := 1;
+ if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) and
+ g_Obj_Collide(obj, @gCorpses[i].Obj) then
+ begin
+ // Ðàñïèëèâàåì òðóï:
+ gCorpses[i].Damage(d, SpawnerUID, (obj^.Vel.X+obj^.Accel.X) div 4,
+ (obj^.Vel.Y+obj^.Accel.Y) div 4);
+ Result := 1;
+ end;
end;
- end;
+ end;
+ end;
+ {$ENDIF}
case gGameSettings.GameMode of
// Êàìïàíèÿ:
end;
end;
- var i, h, dx, dy, m, mm: Integer;
+ var i, h, dx, dy, mm: Integer;
{$IFDEF ENABLE_GIBS}
var _angle: SmallInt;
{$ENDIF}
+ {$IF DEFINED(ENABLE_GIBS) OR DEFINED(ENABLE_CORPSES)}
+ var m: Integer;
+ {$ENDIF}
begin
result := false;
//g_Mons_ForEach(monsExCheck);
g_Mons_ForEachAt(X-(rad+32), Y-(rad+32), (rad+32)*2, (rad+32)*2, monsExCheck);
- h := High(gCorpses);
-
- if gAdvCorpses and (h <> -1) then
- for i := 0 to h do
- if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
- with gCorpses[i] do
+ {$IFDEF ENABLE_CORPSES}
+ h := High(gCorpses);
+ if gAdvCorpses and (h <> -1) then
+ begin
+ for i := 0 to h do
+ begin
+ if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
begin
- dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
- dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
-
- if dx > 1000 then dx := 1000;
- if dy > 1000 then dy := 1000;
-
- if dx*dx+dy*dy < r then
+ with gCorpses[i] do
begin
- m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
- Obj.Rect.Width, Obj.Rect.Height);
-
- mm := Max(abs(dx), abs(dy));
- if mm = 0 then mm := 1;
-
- Damage(Round(100*(rad-m)/rad), SpawnerUID, (dx*10) div mm, (dy*10) div mm);
+ dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
+ dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
+ if dx > 1000 then dx := 1000;
+ if dy > 1000 then dy := 1000;
+ if dx*dx+dy*dy < r then
+ begin
+ m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, Obj.Rect.Width, Obj.Rect.Height);
+ mm := Max(abs(dx), abs(dy));
+ if mm = 0 then
+ mm := 1;
+ Damage(Round(100*(rad-m)/rad), SpawnerUID, (dx*10) div mm, (dy*10) div mm);
+ end;
end;
end;
+ end;
+ end;
+ {$ENDIF}
{$IFDEF ENABLE_GIBS}
h := High(gGibs);
index 58bbd6305edcc9739acee071f1779a0f347aa2ad..286ce250b12e292e780e7e85a2b62872f07c1411 100644 (file)
{$IFDEF ENABLE_GFX}
g_gfx, r_gfx,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
SysUtils, Classes, Math,
g_base, g_basic, r_graphics,
g_system,
{$IFDEF ENABLE_GIBS}
drawOther('gibs', @r_PlayerModel_DrawGibs);
{$ENDIF}
- drawOther('corpses', @r_Player_DrawCorpses);
+ {$IFDEF ENABLE_CORPSES}
+ drawOther('corpses', @r_Player_DrawCorpses);
+ {$ENDIF}
drawPanelType('*wall', PANEL_WALL, g_rlayer_wall);
drawOther('monsters', @r_Monsters_Draw);
drawOther('itemdrop', @r_Items_DrawDrop);
glPushMatrix();
- camObj := p.getCameraObj();
+ {$IFDEF ENABLE_CORPSES}
+ camObj := g_Corpses_GetCameraObj(p);
+ {$ELSE}
+ camObj := p.Obj;
+ {$ENDIF}
+
camObj.lerp(gLerpFactor, fX, fY);
px := fX + PLAYER_RECT_CX;
py := fY + PLAYER_RECT_CY+nlerp(p.SlopeOld, camObj.slopeUpLeft, gLerpFactor);
index c803b4c9e582de6c48867123a557f63a43951f28..49d2c0c78c3cc7f382e3450c148d60acbc989f2f 100644 (file)
procedure r_Player_DrawDebug (p: TPlayer);
procedure r_Player_DrawHealth;
- procedure r_Player_DrawCorpses;
-
procedure r_Player_Draw (p: TPlayer);
procedure r_Player_DrawIndicator (p: TPlayer; Color: TRGB);
procedure r_Player_DrawBubble (p: TPlayer);
procedure r_Player_DrawShells;
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ procedure r_Player_DrawCorpses;
+ {$ENDIF}
+
implementation
uses
{$IFDEF ENABLE_SHELLS}
g_shells,
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ g_corpses,
+ {$ENDIF}
SysUtils, Classes, Math,
MAPDEF, utils,
g_basic, g_game, g_phys, g_map, g_language, g_weapons, g_items, g_net, g_options,
end;
end;
+{$IFDEF ENABLE_CORPSES}
procedure r_Player_DrawCorpse (p: TCorpse);
var fX, fY: Integer;
begin
if gCorpses[i] <> nil then
r_Player_DrawCorpse(gCorpses[i])
end;
+{$ENDIF}
{$IFDEF ENABLE_SHELLS}
procedure r_Player_DrawShells;
Dot: Byte;
CObj: TObj;
begin
- CObj := p.getCameraObj();
+ {$IFDEF ENABLE_CORPSES}
+ CObj := g_Corpses_GetCameraObj(p);
+ {$ELSE}
+ CObj := p.Obj;
+ {$ENDIF}
CObj.lerp(gLerpFactor, fX, fY);
// NB: _F_Obj.Rect is used to keep the bubble higher; this is not a mistake
bubX := fX + p.Obj.Rect.X + IfThen(p.Direction = TDirection.D_LEFT, -4, 18);
diff --git a/src/shared/a_modes.inc b/src/shared/a_modes.inc
index 1ba73469a5954abfbbf82d24cf504c9edde6ec3f..6789e6ee7ac17a5d783d10518add164132f5a4b3 100644 (file)
--- a/src/shared/a_modes.inc
+++ b/src/shared/a_modes.inc
{$UNDEF ENABLE_SHELLS}
{$DEFINE DISABLE_SHELLS}
{$ENDIF}
+ {$IFDEF ENABLE_CORPSES}
+ {$WARNING Corpses in headless mode has no sense. Disabled.}
+ {$UNDEF ENABLE_CORPSES}
+ {$DEFINE DISABLE_CORPSES}
+ {$ENDIF}
{$ENDIF}
{$IF DEFINED(ENABLE_MENU) AND DEFINED(DISABLE_MENU)}
{$ENDIF}
{$ENDIF}
+{$IF DEFINED(ENABLE_CORPSES) AND DEFINED(DISABLE_CORPSES)}
+ {$ERROR Select ENABLE_CORPSES or DISABLE_CORPSES}
+{$ELSEIF NOT DEFINED(ENABLE_CORPSES) AND NOT DEFINED(DISABLE_CORPSES)}
+ // default ENABLE/DISABLE corpses
+ {$IFDEF HEADLESS}
+ {$DEFINE DISABLE_CORPSES}
+ {$ELSE}
+ {$DEFINE ENABLE_CORPSES}
+ {$ENDIF}
+{$ENDIF}
+
{$IF DEFINED(USE_SYSSTUB)}
{$IF DEFINED(USE_SDL) OR DEFINED(USE_SDL2)}
{$ERROR Only one system driver must be selected!}