X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=9c20c904f520d41a9855248c2a9822ee95e46138;hb=2e74c901511298e44d168948d85e9cff009fcb7e;hp=f4e3b0fff39acd98b14a65fa9bc9bcfe82bdb5d6;hpb=0fdf4d69047801a6a8d789df6def4a47015e9ae4;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index f4e3b0f..9c20c90 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -14,13 +14,14 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} +{$M+} unit g_player; interface uses e_graphics, g_playermodel, g_basic, g_textures, - g_weapons, g_phys, g_sound, g_saveload, MAPSTRUCT, + g_weapons, g_phys, g_sound, g_saveload, MAPDEF, BinEditor, g_panel; const @@ -138,7 +139,7 @@ type FUID: Word; FName: String; FTeam: Byte; - FLive: Boolean; + FAlive: Boolean; FSpawned: Boolean; FDirection: TDirection; FHealth: Integer; @@ -194,34 +195,38 @@ type FNoReload: Boolean; FJustTeleported: Boolean; FNetTime: LongWord; - - function CollideLevel(XInc, YInc: Integer): Boolean; - function StayOnStep(XInc, YInc: Integer): Boolean; - function HeadInLiquid(XInc, YInc: Integer): Boolean; - function BodyInLiquid(XInc, YInc: Integer): Boolean; - function BodyInAcid(XInc, YInc: Integer): Boolean; - function FullInLift(XInc, YInc: Integer): Integer; - {procedure CollideItem();} - procedure FlySmoke(Times: DWORD = 1); - procedure OnFireFlame(Times: DWORD = 1); - function GetAmmoByWeapon(Weapon: Byte): Word; - procedure SetAction(Action: Byte; Force: Boolean = False); - procedure OnDamage(Angle: SmallInt); virtual; - function firediry(): Integer; - - procedure Run(Direction: TDirection); - procedure NextWeapon(); - procedure PrevWeapon(); - procedure SeeUp(); - procedure SeeDown(); - procedure Fire(); - procedure Jump(); - procedure Use(); + mEDamageType: Integer; + + + function CollideLevel(XInc, YInc: Integer): Boolean; + function StayOnStep(XInc, YInc: Integer): Boolean; + function HeadInLiquid(XInc, YInc: Integer): Boolean; + function BodyInLiquid(XInc, YInc: Integer): Boolean; + function BodyInAcid(XInc, YInc: Integer): Boolean; + function FullInLift(XInc, YInc: Integer): Integer; + {procedure CollideItem();} + procedure FlySmoke(Times: DWORD = 1); + procedure OnFireFlame(Times: DWORD = 1); + function GetAmmoByWeapon(Weapon: Byte): Word; + procedure SetAction(Action: Byte; Force: Boolean = False); + procedure OnDamage(Angle: SmallInt); virtual; + function firediry(): Integer; + + procedure Run(Direction: TDirection); + procedure NextWeapon(); + procedure PrevWeapon(); + procedure SeeUp(); + procedure SeeDown(); + procedure Fire(); + procedure Jump(); + procedure Use(); function getNextWeaponIndex (): Byte; // return 255 for "no switch" procedure resetWeaponQueue (); function hasAmmoForWeapon (weapon: Byte): Boolean; + procedure doDamage (v: Integer); + public FDamageBuffer: Integer; @@ -249,6 +254,11 @@ type FDummy: Boolean; FFireTime: Integer; + // debug: viewport offset + viewPortX, viewPortY, viewPortW, viewPortH: Integer; + + function isValidViewPort (): Boolean; inline; + constructor Create(); virtual; destructor Destroy(); override; procedure Respawn(Silent: Boolean; Force: Boolean = False); virtual; @@ -312,7 +322,14 @@ type procedure CatchFire(Attacker: Word); //WARNING! this does nothing for now, but still call it! - procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! + procedure positionChanged (); //WARNING! call this after entity position was changed, or coldet will not work right! + + procedure getMapBox (out x, y, w, h: Integer); inline; + procedure moveBy (dx, dy: Integer); inline; + + public + property Vel: TPoint2i read FObj.Vel; + property Obj: TObj read FObj; property Name: String read FName write FName; property Model: TPlayerModel read FModel; @@ -330,7 +347,7 @@ type property GodMode: Boolean read FGodMode write FGodMode; property NoTarget: Boolean read FNoTarget write FNoTarget; property NoReload: Boolean read FNoReload write FNoReload; - property Live: Boolean read FLive write FLive; + property alive: Boolean read FAlive write FAlive; property Flag: Byte read FFlag; property Team: Byte read FTeam write FTeam; property Direction: TDirection read FDirection; @@ -340,12 +357,45 @@ type property GameVelY: Integer read FObj.Vel.Y write FObj.Vel.Y; property GameAccelX: Integer read FObj.Accel.X write FObj.Accel.X; property GameAccelY: Integer read FObj.Accel.Y write FObj.Accel.Y; - property Vel: TPoint2i read FObj.Vel; - property Obj: TObj read FObj; property IncCam: Integer read FIncCam write FIncCam; property UID: Word read FUID write FUID; property JustTeleported: Boolean read FJustTeleported write FJustTeleported; property NetTime: LongWord read FNetTime write FNetTime; + + published + property eName: String read FName write FName; + property eHealth: Integer read FHealth write FHealth; + property eLives: Byte read FLives write FLives; + property eArmor: Integer read FArmor write FArmor; + property eAir: Integer read FAir write FAir; + property eJetFuel: Integer read FJetFuel write FJetFuel; + property eFrags: Integer read FFrags write FFrags; + property eDeath: Integer read FDeath write FDeath; + property eKills: Integer read FKills write FKills; + property eCurrWeap: Byte read FCurrWeap write FCurrWeap; + property eMonsterKills: Integer read FMonsterKills write FMonsterKills; + property eSecrets: Integer read FSecrets write FSecrets; + property eGodMode: Boolean read FGodMode write FGodMode; + property eNoTarget: Boolean read FNoTarget write FNoTarget; + property eNoReload: Boolean read FNoReload write FNoReload; + property eAlive: Boolean read FAlive write FAlive; + property eFlag: Byte read FFlag; + property eTeam: Byte read FTeam write FTeam; + property eDirection: TDirection read FDirection; + property eGameX: Integer read FObj.X write FObj.X; + property eGameY: Integer read FObj.Y write FObj.Y; + property eGameVelX: Integer read FObj.Vel.X write FObj.Vel.X; + property eGameVelY: Integer read FObj.Vel.Y write FObj.Vel.Y; + property eGameAccelX: Integer read FObj.Accel.X write FObj.Accel.X; + property eGameAccelY: Integer read FObj.Accel.Y write FObj.Accel.Y; + property eIncCam: Integer read FIncCam write FIncCam; + property eUID: Word read FUID; + property eJustTeleported: Boolean read FJustTeleported; + property eNetTime: LongWord read FNetTime; + + // set this before assigning something to `eDamage` + property eDamageType: Integer read mEDamageType write mEDamageType; + property eDamage: Integer write doDamage; end; TDifficult = record @@ -402,28 +452,36 @@ type procedure LoadState(var Mem: TBinMemoryReader); override; end; + PGib = ^TGib; TGib = record - Live: Boolean; + alive: Boolean; ID: DWORD; MaskID: DWORD; RAngle: Integer; Color: TRGB; Obj: TObj; - procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! + 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; - Live: Boolean; + alive: Boolean; SType: Byte; RAngle: Integer; Timeout: Cardinal; CX, CY: Integer; Obj: TObj; - procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! + 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 (TObject) @@ -446,9 +504,14 @@ type procedure SaveState(var Mem: TBinMemoryWriter); procedure LoadState(var Mem: TBinMemoryReader); - procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! + procedure getMapBox (out x, y, w, h: Integer); inline; + procedure moveBy (dx, dy: Integer); inline; - property Obj: TObj read FObj; + 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; end; @@ -517,8 +580,9 @@ implementation uses e_log, g_map, g_items, g_console, SysUtils, g_gfx, Math, - g_options, g_triggers, g_menu, MAPDEF, g_game, - wadreader, g_main, g_monsters, CONFIG, g_language, g_net, g_netmsg; + g_options, g_triggers, g_menu, g_game, g_grid, + wadreader, g_main, g_monsters, CONFIG, g_language, + g_net, g_netmsg, g_window, GL, g_holmes; type TBotProfile = record @@ -555,7 +619,7 @@ const ANGLE_LEFTUP = 125; ANGLE_LEFTDOWN = -145; PLAYER_HEADRECT: TRectWH = (X:24; Y:12; Width:20; Height:12); - WEAPONPOINT: Array [TDirection] of TPoint = ((X:16; Y:32), (X:47; Y:32)); + WEAPONPOINT: Array [TDirection] of TDFPoint = ((X:16; Y:32), (X:47; Y:32)); BOT_MAXJUMP = 84; BOT_LONGDIST = 300; BOT_UNSAFEDIST = 128; @@ -604,10 +668,6 @@ var BotList: Array of TBotProfile; -procedure TGib.positionChanged (); begin end; -procedure TShell.positionChanged (); begin end; - - function Lerp(X, Y, Factor: Integer): Integer; begin Result := X + ((Y - X) div Factor); @@ -736,7 +796,7 @@ begin gPlayers[a].FModel.Color := Color; gPlayers[a].FUID := g_CreateUID(UID_PLAYER); - gPlayers[a].FLive := False; + gPlayers[a].FAlive := False; Result := gPlayers[a].FUID; end; @@ -797,7 +857,7 @@ begin Mem.ReadByte(gPlayers[a].FTeam); gPlayers[a].FPreferredTeam := gPlayers[a].FTeam; // Æèâ ëè: - Mem.ReadBoolean(gPlayers[a].FLive); + Mem.ReadBoolean(gPlayers[a].FAlive); // Èçðàñõîäîâàë ëè âñå æèçíè: Mem.ReadBoolean(gPlayers[a].FNoRespawn); // Íàïðàâëåíèå: @@ -1431,7 +1491,7 @@ var i: Integer; begin for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live then + if (gPlayers[i] <> nil) and gPlayers[i].alive then gPlayers[i].RememberState; end; @@ -1465,7 +1525,7 @@ var find_id: DWORD; ok: Boolean; begin - if Player.Live then + if Player.alive then Exit; if Player.FObj.Y >= gMapInfo.Height+128 then Exit; @@ -1532,7 +1592,7 @@ begin Obj.Rect.Height := 3; end; SType := T; - Live := True; + alive := True; Obj.X := fX; Obj.Y := fY; g_Obj_Push(@Obj, dX + Random(4)-Random(4), dY-Random(4)); @@ -1563,7 +1623,7 @@ begin Color := fColor; ID := GibsArray[a].ID; MaskID := GibsArray[a].MaskID; - Live := True; + alive := True; g_Obj_Init(@Obj); Obj.Rect := GibsArray[a].Rect; Obj.X := fX-GibsArray[a].Rect.X-(GibsArray[a].Rect.Width div 2); @@ -1604,7 +1664,7 @@ begin // Êóñêè ìÿñà: if gGibs <> nil then for i := 0 to High(gGibs) do - if gGibs[i].Live then + if gGibs[i].alive then with gGibs[i] do begin vel := Obj.Vel; @@ -1613,7 +1673,7 @@ begin if WordBool(mr and MOVE_FALLOUT) then begin - Live := False; + alive := False; Continue; end; @@ -1654,7 +1714,7 @@ begin // Ãèëüçû: if gShells <> nil then for i := 0 to High(gShells) do - if gShells[i].Live then + if gShells[i].alive then with gShells[i] do begin vel := Obj.Vel; @@ -1663,7 +1723,7 @@ begin if WordBool(mr and MOVE_FALLOUT) or (gShells[i].Timeout < gTime) then begin - Live := False; + alive := False; Continue; end; @@ -1700,14 +1760,57 @@ begin 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_DrawCorpses(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gGibs <> nil then for i := 0 to High(gGibs) do - if gGibs[i].Live then + if gGibs[i].alive then with gGibs[i] do begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then @@ -1734,11 +1837,11 @@ end; procedure g_Player_DrawShells(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gShells <> nil then for i := 0 to High(gShells) do - if gShells[i].Live then + if gShells[i].alive then with gShells[i] do begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then @@ -1842,6 +1945,8 @@ end; { T P l a y e r : } +function TPlayer.isValidViewPort (): Boolean; inline; begin result := (viewPortW > 0) and (viewPortH > 0); end; + procedure TPlayer.BFGHit(); begin g_Weapon_BFGHit(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), @@ -1906,7 +2011,7 @@ begin Exit; if not (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then Exit; - if gGameOn and FLive then + if gGameOn and FAlive then Kill(K_SIMPLEKILL, FUID, HIT_SELF); if FTeam = TEAM_RED then @@ -1949,12 +2054,12 @@ var r: Boolean; begin if gItems = nil then Exit; - if not FLive then Exit; + if not FAlive then Exit; for i := 0 to High(gItems) do with gItems[i] do begin - if (ItemType <> ITEM_NONE) and Live then + if (ItemType <> ITEM_NONE) and alive then if g_Obj_Collide(FObj.X+PLAYER_RECT.X, FObj.Y+PLAYER_RECT.Y, PLAYER_RECT.Width, PLAYER_RECT.Height, @Obj) then begin @@ -1985,6 +2090,12 @@ end; constructor TPlayer.Create(); begin + viewPortX := 0; + viewPortY := 0; + viewPortW := 0; + viewPortH := 0; + mEDamageType := HIT_SOME; + FIamBot := False; FDummy := False; FSpawned := False; @@ -2027,15 +2138,22 @@ begin resetWeaponQueue(); end; -procedure TPlayer.positionChanged (); +procedure TPlayer.positionChanged (); inline; begin end; +procedure TPlayer.doDamage (v: Integer); +begin + if (v <= 0) then exit; + if (v > 32767) then v := 32767; + Damage(v, 0, 0, 0, mEDamageType); +end; + procedure TPlayer.Damage(value: Word; SpawnerUID: Word; vx, vy: Integer; t: Byte); var c: Word; begin - if (not g_Game_IsClient) and (not FLive) then + if (not g_Game_IsClient) and (not FAlive) then Exit; FLastHit := t; @@ -2104,7 +2222,7 @@ begin end; // Áóôåð óðîíà: - if FLive then + if FAlive then Inc(FDamageBuffer, value); // Âñïûøêà áîëè: @@ -2125,7 +2243,7 @@ begin Result := False; if g_Game_IsClient then Exit; - if not FLive then + if not FAlive then Exit; if Soft and (FHealth < PLAYER_HP_SOFT) then @@ -2248,7 +2366,7 @@ var w, h: Word; dr: Boolean; begin - if FLive then + if FAlive then begin if (FMegaRulez[MR_INVUL] > gTime) and (gPlayerDrawn <> Self) then if g_Texture_Get('TEXTURE_PLAYER_INVULPENTA', ID) then @@ -2256,10 +2374,10 @@ begin e_GetTextureSize(ID, @w, @h); if FDirection = D_LEFT then e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)+4, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7, 0, True, False) + FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False) else e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)-2, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7, 0, True, False); + FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False); end; if FMegaRulez[MR_INVIS] > gTime then @@ -2272,15 +2390,15 @@ begin else dr := True; if dr then - FModel.Draw(FObj.X, FObj.Y, 200) + FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 200) else - FModel.Draw(FObj.X, FObj.Y); + FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); end else - FModel.Draw(FObj.X, FObj.Y, 254); + FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 254); end else - FModel.Draw(FObj.X, FObj.Y); + FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); end; if g_debug_Frames then @@ -2295,12 +2413,33 @@ begin if (gChatBubble > 0) and (FKeys[KEY_CHAT].Pressed) and not FGhost then DrawBubble(); // e_DrawPoint(5, 335, 288, 255, 0, 0); // DL, UR, DL, UR - if gAimLine and Live and + if gAimLine and alive and ((Self = gPlayer1) or (Self = gPlayer2)) then DrawAim(); end; + procedure TPlayer.DrawAim(); + procedure drawCast (sz: Integer; ax0, ay0, ax1, ay1: Integer); + var + ex, ey: Integer; + begin + if isValidViewPort and (self = gPlayer1) then + begin + g_Holmes_plrLaser(ax0, ay0, ax1, ay1); + end; + + e_DrawLine(sz, ax0, ay0, ax1, ay1, 255, 0, 0, 96); + if (g_Map_traceToNearestWall(ax0, ay0, ax1, ay1, @ex, @ey) <> nil) then + begin + e_DrawLine(sz, ax0, ay0, ex, ey, 0, 255, 0, 96); + end + else + begin + e_DrawLine(sz, ax0, ay0, ex, ey, 0, 0, 255, 96); + end; + end; + var wx, wy, xx, yy: Integer; angle: SmallInt; @@ -2387,7 +2526,11 @@ begin end; xx := Trunc(Cos(-DegToRad(angle)) * len) + wx; yy := Trunc(Sin(-DegToRad(angle)) * len) + wy; + {$IF DEFINED(D2F_DEBUG)} + drawCast(sz, wx, wy, xx, yy); + {$ELSE} e_DrawLine(sz, wx, wy, xx, yy, 255, 0, 0, 96); + {$ENDIF} end; procedure TPlayer.DrawGUI(); @@ -2973,31 +3116,33 @@ var DoFrags: Boolean; OldLR: Byte; KP: TPlayer; + it: PItem; procedure PushItem(t: Byte); var id: DWORD; begin id := g_Items_Create(FObj.X, FObj.Y, t, True, False); + it := g_Items_ByIdx(id); if KillType = K_EXTRAHARDKILL then // -7..+7; -8..0 begin - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-7+Random(15), - (FObj.Vel.Y div 2)-Random(9)); - gItems[id].positionChanged(); // this updates spatial accelerators + g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-7+Random(15), + (FObj.Vel.Y div 2)-Random(9)); + it.positionChanged(); // this updates spatial accelerators end else begin if KillType = K_HARDKILL then // -5..+5; -5..0 begin - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-5+Random(11), - (FObj.Vel.Y div 2)-Random(6)); + g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-5+Random(11), + (FObj.Vel.Y div 2)-Random(6)); end else // -3..+3; -3..0 begin - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-3+Random(7), - (FObj.Vel.Y div 2)-Random(4)); + g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-3+Random(7), + (FObj.Vel.Y div 2)-Random(4)); end; - gItems[id].positionChanged(); // this updates spatial accelerators + it.positionChanged(); // this updates spatial accelerators end; if g_Game_IsNet and g_Game_IsServer then @@ -3009,13 +3154,13 @@ begin Srv := g_Game_IsServer; Netsrv := g_Game_IsServer and g_Game_IsNet; if Srv then FDeath := FDeath + 1; - if FLive then + if FAlive then begin if FGhost then FGhost := False; if not FPhysics then FPhysics := True; - FLive := False; + FAlive := False; end; FShellTimer := -1; @@ -3119,11 +3264,11 @@ begin end else if g_GetUIDType(SpawnerUID) = UID_MONSTER then begin // Óáèò ìîíñòðîì - mon := g_Monsters_Get(SpawnerUID); + mon := g_Monsters_ByUID(SpawnerUID); if mon = nil then s := '?' else - s := g_Monsters_GetKilledBy(mon.MonsterType); + s := g_Mons_GetKilledByTypeId(mon.MonsterType); case KillType of K_HARDKILL: @@ -3539,6 +3684,16 @@ begin end; function TPlayer.PickItem(ItemType: Byte; arespawn: Boolean; var remove: Boolean): Boolean; + + function allowBerserkSwitching (): Boolean; + begin + if (FBFGFireCounter <> -1) then begin result := false; exit; end; + result := true; + if gBerserkAutoswitch then exit; + if not (gDebugMode or gCheats) then exit; + result := false; + end; + var a: Boolean; begin @@ -3881,15 +4036,17 @@ begin if not (R_BERSERK in FRulez) then begin Include(FRulez, R_BERSERK); - if FBFGFireCounter = -1 then + if allowBerserkSwitching then begin FCurrWeap := WEAPON_KASTET; resetWeaponQueue(); FModel.SetWeapon(WEAPON_KASTET); end; if gFlash <> 0 then + begin Inc(FPain, 100); if gFlash = 2 then Inc(FPickup, 5); + end; FBerserk := gTime+30000; Result := True; remove := True; @@ -3955,7 +4112,7 @@ end; procedure TPlayer.Touch(); begin - if not FLive then + if not FAlive then Exit; //FModel.PlaySound(MODELSOUND_PAIN, 1, FObj.X, FObj.Y); if FIamBot then @@ -3979,7 +4136,7 @@ end; procedure TPlayer.Reset(Force: Boolean); begin if Force then - FLive := False; + FAlive := False; FSpawned := False; FTime[T_RESPAWN] := 0; @@ -4189,7 +4346,7 @@ begin if Force then begin FTime[T_RESPAWN] := 0; - FLive := False; + FAlive := False; end; FNetTime := 0; // if server changes MaxLives we gotta be ready @@ -4225,11 +4382,11 @@ begin SetFlag(FLAG_NONE); // Âîñêðåøåíèå áåç îðóæèÿ: - if not FLive then + if not FAlive then begin FHealth := PLAYER_HP_SOFT; FArmor := 0; - FLive := True; + FAlive := True; FAir := AIR_DEF; FJetFuel := 0; @@ -4335,7 +4492,7 @@ end; procedure TPlayer.Spectate(NoMove: Boolean = False); begin - if FLive then + if FAlive then Kill(K_EXTRAHARDKILL, FUID, HIT_SOME) else if (not NoMove) then begin @@ -4345,7 +4502,7 @@ begin FXTo := GameX; FYTo := GameY; - FLive := False; + FAlive := False; FSpectator := True; FGhost := True; FPhysics := False; @@ -4372,7 +4529,7 @@ end; procedure TPlayer.SwitchNoClip; begin - if not FLive then + if not FAlive then Exit; FGhost := not FGhost; FPhysics := not FGhost; @@ -4411,7 +4568,7 @@ begin if b > 1 then b := b * (Random(8 div b) + 1); for a := 0 to High(gGibs) do begin - if gGibs[a].Live and + 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 @@ -4523,7 +4680,7 @@ begin FObj.X := X-PLAYER_RECT.X; FObj.Y := Y-PLAYER_RECT.Y; - if FLive and FGhost then + if FAlive and FGhost then begin FXTo := FObj.X; FYTo := FObj.Y; @@ -4613,7 +4770,7 @@ begin FLoss := 0; end; - if FLive and (gFly or FJetpack) then + if FAlive and (gFly or FJetpack) then FlySmoke(); if FDirection = D_LEFT then @@ -4621,7 +4778,7 @@ begin else FAngle := 0; - if FLive and (not FGhost) then + if FAlive and (not FGhost) then begin if FKeys[KEY_UP].Pressed then SeeUp(); @@ -4639,12 +4796,12 @@ begin end; // no need to do that each second frame, weapon queue will take care of it - if FLive and FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon(); - if FLive and FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon(); + if FAlive and FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon(); + if FAlive and FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon(); if gTime mod (GAME_TICK*2) <> 0 then begin - if (FObj.Vel.X = 0) and FLive then + if (FObj.Vel.X = 0) and FAlive then begin if FKeys[KEY_LEFT].Pressed then Run(D_LEFT); @@ -4663,7 +4820,7 @@ begin FActionChanged := False; - if FLive then + if FAlive then begin // Let alive player do some actions if FKeys[KEY_LEFT].Pressed then Run(D_LEFT); @@ -4702,7 +4859,7 @@ begin Respawn(False) else // Single if (FTime[T_RESPAWN] <= gTime) and - gGameOn and (not FLive) then + gGameOn and (not FAlive) then begin if (g_Player_GetCount() > 1) then Respawn(False) @@ -4728,7 +4885,7 @@ begin SetSpect := False; for I := FSpectatePlayer + 1 to High(gPlayers) do if gPlayers[I] <> nil then - if gPlayers[I].Live then + if gPlayers[I].alive then if gPlayers[I].UID <> FUID then begin FSpectatePlayer := I; @@ -4790,7 +4947,7 @@ begin if FSpectator then if (FSpectatePlayer <= High(gPlayers)) and (FSpectatePlayer >= 0) then if gPlayers[FSpectatePlayer] <> nil then - if gPlayers[FSpectatePlayer].Live then + if gPlayers[FSpectatePlayer].alive then begin FXTo := gPlayers[FSpectatePlayer].GameX; FYTo := gPlayers[FSpectatePlayer].GameY; @@ -4803,7 +4960,7 @@ begin headwater := HeadInLiquid(0, 0); // Ñîïðîòèâëåíèå âîçäóõà: - if (not FLive) or not (FKeys[KEY_LEFT].Pressed or FKeys[KEY_RIGHT].Pressed) then + if (not FAlive) or not (FKeys[KEY_LEFT].Pressed or FKeys[KEY_RIGHT].Pressed) then if FObj.Vel.X <> 0 then FObj.Vel.X := z_dec(FObj.Vel.X, 1); @@ -4811,7 +4968,7 @@ begin DecMin(FPain, 5, 0); DecMin(FPickup, 1, 0); - if FLive and (FObj.Y > gMapInfo.Height+128) and AnyServer then + if FAlive and (FObj.Y > Integer(gMapInfo.Height)+128) and AnyServer then begin // Îáíóëèòü äåéñòâèÿ ïðèìî÷åê, ÷òîáû ôîí ïðîïàë FMegaRulez[MR_SUIT] := 0; @@ -4822,7 +4979,7 @@ begin i := 9; - if FLive then + if FAlive then begin if FCurrWeap = WEAPON_SAW then if not (FSawSound.IsPlaying() or FSawSoundHit.IsPlaying() or @@ -4966,7 +5123,7 @@ begin else if FHealth > -50 then Kill(K_HARDKILL, FLastSpawnerUID, FLastHit) else Kill(K_EXTRAHARDKILL, FLastSpawnerUID, FLastHit); - if FLive then + if FAlive then begin if FDamageBuffer <= 20 then FModel.PlaySound(MODELSOUND_PAIN, 1, FObj.X, FObj.Y) else if FDamageBuffer <= 55 then FModel.PlaySound(MODELSOUND_PAIN, 2, FObj.X, FObj.Y) @@ -4978,7 +5135,7 @@ begin end; {CollideItem();} - end; // if FLive then ... + end; // if FAlive then ... if (FActionAnim = A_PAIN) and (FModel.Animation <> A_PAIN) then begin @@ -4996,6 +5153,27 @@ begin if FKeys[b].Time = 0 then FKeys[b].Pressed := False else Dec(FKeys[b].Time); end; + +procedure TPlayer.getMapBox (out x, y, w, h: Integer); inline; +begin + x := FObj.X+PLAYER_RECT.X; + y := FObj.Y+PLAYER_RECT.Y; + w := PLAYER_RECT.Width; + h := PLAYER_RECT.Height; +end; + + +procedure TPlayer.moveBy (dx, dy: Integer); inline; +begin + if (dx <> 0) or (dy <> 0) then + begin + FObj.X += dx; + FObj.Y += dy; + positionChanged(); + end; +end; + + function TPlayer.Collide(X, Y: Integer; Width, Height: Word): Boolean; begin Result := g_Collide(FObj.X+PLAYER_RECT.X, @@ -5076,7 +5254,7 @@ begin for a := 0 to High(gPlayers) do if (gPlayers[a] <> nil) and (gPlayers[a] <> Self) and - gPlayers[a].Live and SameTeam(FUID, gPlayers[a].FUID) and + gPlayers[a].alive and SameTeam(FUID, gPlayers[a].FUID) and g_Obj_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height, @gPlayers[a].FObj) then begin @@ -5520,7 +5698,7 @@ begin // Êîìàíäà: Mem.WriteByte(FTeam); // Æèâ ëè: - Mem.WriteBoolean(FLive); + Mem.WriteBoolean(FAlive); // Èçðàñõîäîâàë ëè âñå æèçíè: Mem.WriteBoolean(FNoRespawn); // Íàïðàâëåíèå: @@ -5660,7 +5838,7 @@ begin // Êîìàíäà: Mem.ReadByte(FTeam); // Æèâ ëè: - Mem.ReadBoolean(FLive); + Mem.ReadBoolean(FAlive); // Èçðàñõîäîâàë ëè âñå æèçíè: Mem.ReadBoolean(FNoRespawn); // Íàïðàâëåíèå: @@ -6041,7 +6219,29 @@ begin inherited; end; -procedure TCorpse.positionChanged (); begin 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; vx, vy: Integer); var @@ -6300,6 +6500,41 @@ var mon: TMonster; pla, tpla: TPlayer; vsPlayer, vsMonster, ok: Boolean; + + + function monsUpdate (mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.alive and (mon.MonsterType <> MONSTER_BARREL) then + begin + if not TargetOnScreen(mon.Obj.X+mon.Obj.Rect.X, mon.Obj.Y+mon.Obj.Rect.Y) then exit; + + x2 := mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2); + y2 := mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2); + + // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé + if g_TraceVector(x1, y1, x2, y2) then + begin + // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé + SetLength(targets, Length(targets)+1); + with targets[High(targets)] do + begin + UID := mon.UID; + X := mon.Obj.X; + Y := mon.Obj.Y; + cX := x2; + cY := y2; + Rect := mon.Obj.Rect; + Dist := g_PatchLength(x1, y1, x2, y2); + Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and + (y1-4 > Target.Y + mon.Obj.Rect.Y); + Visible := True; + IsPlayer := False; + end; + end; + end; + end; + begin vsPlayer := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSPLAYER); vsMonster := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSMONSTER); @@ -6356,7 +6591,7 @@ begin if (g_GetUIDType(Target.UID) = UID_MONSTER) and vsMonster then begin // Ìîíñòð - mon := g_Monsters_Get(Target.UID); + mon := g_Monsters_ByUID(Target.UID); if mon <> nil then begin Target.X := mon.Obj.X; @@ -6393,7 +6628,7 @@ begin // Èãðîêè: if vsPlayer then for a := 0 to High(gPlayers) do - if (gPlayers[a] <> nil) and (gPlayers[a].Live) and + if (gPlayers[a] <> nil) and (gPlayers[a].alive) and (gPlayers[a].FUID <> FUID) and (not SameTeam(FUID, gPlayers[a].FUID)) and (not gPlayers[a].NoTarget) and @@ -6429,41 +6664,7 @@ begin end; // Ìîíñòðû: - if vsMonster and (gMonsters <> nil) then - for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and (gMonsters[a].Live) and - (gMonsters[a].MonsterType <> MONSTER_BARREL) then - begin - mon := gMonsters[a]; - - if not TargetOnScreen(mon.Obj.X + mon.Obj.Rect.X, - mon.Obj.Y + mon.Obj.Rect.Y) then - Continue; - - x2 := mon.Obj.X + mon.Obj.Rect.X + (mon.Obj.Rect.Width div 2); - y2 := mon.Obj.Y + mon.Obj.Rect.Y + (mon.Obj.Rect.Height div 2); - - // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé: - if g_TraceVector(x1, y1, x2, y2) then - begin - // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé: - SetLength(targets, Length(targets)+1); - with targets[High(targets)] do - begin - UID := mon.UID; - X := mon.Obj.X; - Y := mon.Obj.Y; - cX := x2; - cY := y2; - Rect := mon.Obj.Rect; - Dist := g_PatchLength(x1, y1, x2, y2); - Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and - (y1-4 > Target.Y + mon.Obj.Rect.Y); - Visible := True; - IsPlayer := False; - end; - end; - end; + if vsMonster then g_Mons_ForEach(monsUpdate); end; // Åñëè åñòü âîçìîæíûå öåëè: @@ -6617,14 +6818,14 @@ begin if Target.IsPlayer then begin // Öåëü - èãðîê pla := g_Player_Get(Target.UID); - if (pla = nil) or (not pla.Live) or pla.NoTarget or + if (pla = nil) or (not pla.alive) or pla.NoTarget or (pla.FMegaRulez[MR_INVIS] >= gTime) then Target.UID := 0; // òî çàáûòü öåëü end else begin // Öåëü - ìîíñòð - mon := g_Monsters_Get(Target.UID); - if (mon = nil) or (not mon.Live) then + mon := g_Monsters_ByUID(Target.UID); + if (mon = nil) or (not mon.alive) then Target.UID := 0; // òî çàáûòü öåëü end; end; @@ -6766,7 +6967,7 @@ procedure TBot.Update(); var EnableAI: Boolean; begin - if not FLive then + if not FAlive then begin // Respawn ReleaseKeys(); PressKey(KEY_UP); @@ -7375,7 +7576,7 @@ begin if (g_GetUIDType(FLastSpawnerUID) = UID_MONSTER) and LongBool(gGameSettings.Options and GAME_OPTION_BOTVSMONSTER) then begin // Ìîíñòð - mon := g_Monsters_Get(FLastSpawnerUID); + mon := g_Monsters_ByUID(FLastSpawnerUID); ok := not TargetOnScreen(mon.Obj.X + mon.Obj.Rect.X, mon.Obj.Y + mon.Obj.Rect.Y); end; @@ -7469,4 +7670,7 @@ begin FDifficult := TDifficult(p^); end; + +begin + conRegVar('cheat_berserk_autoswitch', @gBerserkAutoswitch, 'autoswitch to fist when berserk pack taken', '', true, true); end.