X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=04719fccc88dca671b0e98a9838a388f55d7170f;hb=4aae1df7801692bcde3df413028c83edd5c3c655;hp=caddc0d9e7612dfa230b9676b010a95373bb6cbb;hpb=7cd1c130359bef86087eaefe317526775e8ad4f8;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index caddc0d..04719fc 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -13,14 +13,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$MODE DELPHI} +{$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 @@ -50,6 +51,12 @@ const A_SHELLS = 1; A_ROCKETS = 2; A_CELLS = 3; + A_FUEL = 4; + A_HIGH = 4; + + AmmoLimits: Array [0..1] of Array [A_BULLETS..A_HIGH] of Word = + ((200, 50, 50, 300, 100), + (400, 100, 100, 600, 200)); K_SIMPLEKILL = 0; K_HARDKILL = 1; @@ -112,9 +119,11 @@ type Air: Integer; JetFuel: Integer; CurrWeap: Byte; - Ammo: Array [A_BULLETS..A_CELLS] of Word; - MaxAmmo: Array [A_BULLETS..A_CELLS] of Word; - Weapon: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Boolean; + NextWeap: WORD; + NextWeapDelay: Byte; + Ammo: Array [A_BULLETS..A_HIGH] of Word; + MaxAmmo: Array [A_BULLETS..A_HIGH] of Word; + Weapon: Array [WP_FIRST..WP_LAST] of Boolean; Rulez: Set of R_ITEM_BACKPACK..R_BERSERK; WaitRecall: Boolean; end; @@ -151,12 +160,16 @@ type FFlag: Byte; FSecrets: Integer; FCurrWeap: Byte; + FNextWeap: WORD; + FNextWeapDelay: Byte; // frames FBFGFireCounter: SmallInt; FLastSpawnerUID: Word; FLastHit: Byte; FObj: TObj; FXTo, FYTo: Integer; FSpectatePlayer: Integer; + FFirePainTime: Integer; + FFireAttacker: Word; FSavedState: TPlayerSavedState; @@ -191,6 +204,7 @@ type 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; @@ -205,16 +219,20 @@ type procedure Jump(); procedure Use(); + function getNextWeaponIndex (): Byte; // return 255 for "no switch" + procedure resetWeaponQueue (); + function hasAmmoForWeapon (weapon: Byte): Boolean; + public FDamageBuffer: Integer; - FAmmo: Array [A_BULLETS..A_CELLS] of Word; - FMaxAmmo: Array [A_BULLETS..A_CELLS] of Word; - FWeapon: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Boolean; + FAmmo: Array [A_BULLETS..A_HIGH] of Word; + FMaxAmmo: Array [A_BULLETS..A_HIGH] of Word; + FWeapon: Array [WP_FIRST..WP_LAST] of Boolean; FRulez: Set of R_ITEM_BACKPACK..R_BERSERK; FBerserk: Integer; FMegaRulez: Array [MR_SUIT..MR_MAX] of DWORD; - FReloading: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Word; + FReloading: Array [WP_FIRST..WP_LAST] of Word; FTime: Array [T_RESPAWN..T_FLAGCAP] of DWORD; FKeys: Array [KEY_LEFT..KEY_CHAT] of TKeyState; FColor: TRGB; @@ -230,6 +248,12 @@ type FPing: Word; FLoss: Byte; FDummy: Boolean; + FFireTime: Integer; + + // debug: viewport offset + viewPortX, viewPortY, viewPortW, viewPortH: Integer; + + function isValidViewPort (): Boolean; inline; constructor Create(); virtual; destructor Destroy(); override; @@ -242,7 +266,7 @@ type procedure SetWeapon(W: Byte); function IsKeyPressed(K: Byte): Boolean; function GetKeys(): Byte; - function PickItem(ItemType: Byte; respawn: Boolean; var remove: Boolean): Boolean; virtual; + function PickItem(ItemType: Byte; arespawn: Boolean; var remove: Boolean): Boolean; virtual; function Collide(X, Y: Integer; Width, Height: Word): Boolean; overload; function Collide(Panel: TPanel): Boolean; overload; function Collide(X, Y: Integer): Boolean; overload; @@ -287,10 +311,22 @@ type procedure NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1); procedure DoLerp(Level: Integer = 2); procedure SetLerp(XTo, YTo: Integer); - procedure ForceWeapon(Weapon: Byte); + procedure QueueWeaponSwitch(Weapon: Byte); + procedure RealizeCurrentWeapon(); procedure JetpackOn; procedure JetpackOff; + 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 getMapBox (out x, y, w, h: Integer); inline; + + public + property Vel: TPoint2i read FObj.Vel; + property Obj: TObj read FObj; + + published property Name: String read FName write FName; property Model: TPlayerModel read FModel; property Health: Integer read FHealth write FHealth; @@ -317,8 +353,6 @@ 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; @@ -332,9 +366,9 @@ type FlyPrecision: Byte; Cover: Byte; CloseJump: Byte; - WeaponPrior: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; - CloseWeaponPrior: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; - //SafeWeaponPrior: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; + WeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; + CloseWeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; + //SafeWeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; end; TAIFlag = record @@ -356,9 +390,9 @@ type function FullInStep(XInc, YInc: Integer): Boolean; //function NeedItem(Item: Byte): Byte; procedure SelectWeapon(Dist: Integer); - procedure SetAIFlag(fName, fValue: String20); - function GetAIFlag(fName: String20): String20; - procedure RemoveAIFlag(fName: String20); + procedure SetAIFlag(aName, fValue: String20); + function GetAIFlag(aName: String20): String20; + procedure RemoveAIFlag(aName: String20); function Healthy(): Byte; procedure UpdateMove(); procedure UpdateCombat(); @@ -386,8 +420,11 @@ type RAngle: Integer; Color: TRGB; Obj: TObj; + + procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! end; + TShell = record SpriteID: DWORD; Live: Boolean; @@ -396,6 +433,8 @@ type Timeout: Cardinal; CX, CY: Integer; Obj: TObj; + + procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right! end; TCorpse = class (TObject) @@ -418,6 +457,8 @@ 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! + property Obj: TObj read FObj; property State: Byte read FState; property Mess: Boolean read FMess; @@ -487,8 +528,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 @@ -502,9 +544,9 @@ type fly_precision: Byte; cover: Byte; close_jump: Byte; - w_prior1: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; - w_prior2: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; - w_prior3: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte; + w_prior1: Array [WP_FIRST..WP_LAST] of Byte; + w_prior2: Array [WP_FIRST..WP_LAST] of Byte; + w_prior3: Array [WP_FIRST..WP_LAST] of Byte; end; const @@ -525,7 +567,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; @@ -533,27 +575,30 @@ const (R:0; G:0; B:255)); DIFFICULT_EASY: TDifficult = (DiagFire: 32; InvisFire: 32; DiagPrecision: 32; FlyPrecision: 32; Cover: 32; CloseJump: 32; - WeaponPrior:(0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0)); + WeaponPrior:(0,0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0,0)); DIFFICULT_MEDIUM: TDifficult = (DiagFire: 127; InvisFire: 127; DiagPrecision: 127; FlyPrecision: 127; Cover: 127; CloseJump: 127; - WeaponPrior:(0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0)); + WeaponPrior:(0,0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0,0)); DIFFICULT_HARD: TDifficult = (DiagFire: 255; InvisFire: 255; DiagPrecision: 255; FlyPrecision: 255; Cover: 255; CloseJump: 255; - WeaponPrior:(0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0)); - WEAPON_PRIOR1: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte = - (WEAPON_SUPERPULEMET, WEAPON_SHOTGUN2, WEAPON_SHOTGUN1, + WeaponPrior:(0,0,0,0,0,0,0,0,0,0,0); CloseWeaponPrior:(0,0,0,0,0,0,0,0,0,0,0)); + WEAPON_PRIOR1: Array [WP_FIRST..WP_LAST] of Byte = + (WEAPON_FLAMETHROWER, WEAPON_SUPERPULEMET, + WEAPON_SHOTGUN2, WEAPON_SHOTGUN1, WEAPON_CHAINGUN, WEAPON_PLASMA, WEAPON_ROCKETLAUNCHER, WEAPON_BFG, WEAPON_PISTOL, WEAPON_SAW, WEAPON_KASTET); - WEAPON_PRIOR2: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte = - (WEAPON_SUPERPULEMET, WEAPON_BFG, WEAPON_ROCKETLAUNCHER, + WEAPON_PRIOR2: Array [WP_FIRST..WP_LAST] of Byte = + (WEAPON_FLAMETHROWER, WEAPON_SUPERPULEMET, + WEAPON_BFG, WEAPON_ROCKETLAUNCHER, WEAPON_SHOTGUN2, WEAPON_PLASMA, WEAPON_SHOTGUN1, WEAPON_CHAINGUN, WEAPON_PISTOL, WEAPON_SAW, WEAPON_KASTET); - //WEAPON_PRIOR3: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte = - // (WEAPON_SUPERPULEMET, WEAPON_BFG, WEAPON_PLASMA, - // WEAPON_SHOTGUN2, WEAPON_CHAINGUN, WEAPON_SHOTGUN1, - // WEAPON_SAW, WEAPON_ROCKETLAUNCHER, WEAPON_PISTOL, WEAPON_KASTET); - WEAPON_RELOAD: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte = - (5, 2, 6, 18, 36, 2, 12, 2, 14, 2); + //WEAPON_PRIOR3: Array [WP_FIRST..WP_LAST] of Byte = + // (WEAPON_FLAMETHROWER, WEAPON_SUPERPULEMET, + // WEAPON_BFG, WEAPON_PLASMA, WEAPON_SHOTGUN2, + // WEAPON_CHAINGUN, WEAPON_SHOTGUN1, WEAPON_SAW, + // WEAPON_ROCKETLAUNCHER, WEAPON_PISTOL, WEAPON_KASTET); + WEAPON_RELOAD: Array [WP_FIRST..WP_LAST] of Byte = + (5, 2, 6, 18, 36, 2, 12, 2, 14, 2, 2); PLAYER_SIGNATURE = $52594C50; // 'PLYR' CORPSE_SIGNATURE = $50524F43; // 'CORP' @@ -570,6 +615,11 @@ var BotNames: Array of String; 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); @@ -798,6 +848,10 @@ begin Mem.ReadInt(gPlayers[a].FSecrets); // Òåêóùåå îðóæèå: Mem.ReadByte(gPlayers[a].FCurrWeap); +// Ñëåäóþùåå æåëàåìîå îðóæèå: + Mem.ReadWord(gPlayers[a].FNextWeap); +// ...è ïàóçà: + Mem.ReadByte(gPlayers[a].FNextWeapDelay); // Âðåìÿ çàðÿäêè BFG: Mem.ReadSmallInt(gPlayers[a].FBFGFireCounter); // Áóôåð óðîíà: @@ -809,16 +863,16 @@ begin // Îáúåêò èãðîêà: Obj_LoadState(@gPlayers[a].FObj, Mem); // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.ReadWord(gPlayers[a].FAmmo[i]); // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.ReadWord(gPlayers[a].FMaxAmmo[i]); // Íàëè÷èå îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.ReadBoolean(gPlayers[a].FWeapon[i]); // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.ReadWord(gPlayers[a].FReloading[i]); // Íàëè÷èå ðþêçàêà: Mem.ReadByte(b); @@ -984,7 +1038,7 @@ begin else FDifficult := DIFFICULT_HARD; end; - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for a := WP_FIRST to WP_LAST do begin FDifficult.WeaponPrior[a] := WEAPON_PRIOR1[a]; FDifficult.CloseWeaponPrior[a] := WEAPON_PRIOR2[a]; @@ -1062,7 +1116,7 @@ begin FDifficult.Cover := BotList[num].cover; FDifficult.CloseJump := BotList[num].close_jump; - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for a := WP_FIRST to WP_LAST do begin FDifficult.WeaponPrior[a] := BotList[num].w_prior1[a]; FDifficult.CloseWeaponPrior[a] := BotList[num].w_prior2[a]; @@ -1255,10 +1309,24 @@ var begin if gPlayers = nil then Exit; + //e_WriteLog('***g_Player_UpdateAll: ENTER', MSG_WARNING); for i := 0 to High(gPlayers) do + begin if gPlayers[i] <> nil then - if gPlayers[i] is TPlayer then gPlayers[i].Update() - else TBot(gPlayers[i]).Update(); + begin + if gPlayers[i] is TPlayer then + begin + gPlayers[i].Update(); + gPlayers[i].RealizeCurrentWeapon(); // WARNING! DO NOT MOVE THIS INTO `Update()`! + end + else + begin + // bot updates weapons in `UpdateCombat()` + TBot(gPlayers[i]).Update(); + end; + end; + end; + //e_WriteLog('***g_Player_UpdateAll: EXIT', MSG_WARNING); end; procedure g_Player_DrawAll(); @@ -1480,6 +1548,7 @@ begin 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; @@ -1512,6 +1581,7 @@ begin 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 @@ -1551,6 +1621,7 @@ begin begin vel := Obj.Vel; mr := g_Obj_Move(@Obj, True, False, True); + positionChanged(); // this updates spatial accelerators if WordBool(mr and MOVE_FALLOUT) then begin @@ -1600,6 +1671,7 @@ begin begin 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 @@ -1643,7 +1715,7 @@ end; procedure g_Player_DrawCorpses(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gGibs <> nil then for i := 0 to High(gGibs) do @@ -1674,7 +1746,7 @@ end; procedure g_Player_DrawShells(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gShells <> nil then for i := 0 to High(gShells) do @@ -1782,6 +1854,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), @@ -1794,13 +1868,13 @@ end; procedure TPlayer.ChangeModel(ModelName: string); var - Model: TPlayerModel; + locModel: TPlayerModel; begin - Model := g_PlayerModel_Get(ModelName); - if Model = nil then Exit; + locModel := g_PlayerModel_Get(ModelName); + if locModel = nil then Exit; FModel.Free(); - FModel := Model; + FModel := locModel; end; procedure TPlayer.SetModel(ModelName: string); @@ -1925,6 +1999,11 @@ end; constructor TPlayer.Create(); begin + viewPortX := 0; + viewPortY := 0; + viewPortW := 0; + viewPortH := 0; + FIamBot := False; FDummy := False; FSpawned := False; @@ -1951,6 +2030,9 @@ begin FLoss := 0; FSavedState.WaitRecall := False; FShellTimer := -1; + FFireTime := 0; + FFirePainTime := 0; + FFireAttacker := 0; FActualModelName := 'doomer'; @@ -1960,6 +2042,12 @@ begin FBFGFireCounter := -1; FJustTeleported := False; FNetTime := 0; + + resetWeaponQueue(); +end; + +procedure TPlayer.positionChanged (); +begin end; procedure TPlayer.Damage(value: Word; SpawnerUID: Word; vx, vy: Integer; t: Byte); @@ -2187,10 +2275,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 @@ -2203,15 +2291,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 @@ -2231,7 +2319,28 @@ begin 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; @@ -2318,7 +2427,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(); @@ -2458,6 +2571,7 @@ begin WEAPON_ROCKETLAUNCHER: ID := gItemsTexturesID[ITEM_WEAPON_ROCKETLAUNCHER]; WEAPON_PLASMA: ID := gItemsTexturesID[ITEM_WEAPON_PLASMA]; WEAPON_BFG: ID := gItemsTexturesID[ITEM_WEAPON_BFG]; + WEAPON_FLAMETHROWER: ID := gItemsTexturesID[ITEM_WEAPON_FLAMETHROWER]; end; e_CharFont_GetSize(gMenuFont, s, tw, th); @@ -2593,7 +2707,7 @@ procedure TPlayer.Fire(); var f, DidFire: Boolean; wx, wy, xd, yd: Integer; - obj: TObj; + locobj: TObj; begin if g_Game_IsClient then Exit; // FBFGFireCounter - âðåìÿ ïåðåä âûñòðåëîì (äëÿ BFG) @@ -2621,18 +2735,18 @@ begin if R_BERSERK in FRulez then begin //g_Weapon_punch(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, 75, FUID); - obj.X := FObj.X+FObj.Rect.X; - obj.Y := FObj.Y+FObj.Rect.Y; - obj.rect.X := 0; - obj.rect.Y := 0; - obj.rect.Width := 39; - obj.rect.Height := 52; - obj.Vel.X := (xd-wx) div 2; - obj.Vel.Y := (yd-wy) div 2; - obj.Accel.X := xd-wx; - obj.Accel.y := yd-wy; - - if g_Weapon_Hit(@obj, 50, FUID, HIT_SOME) <> 0 then + locobj.X := FObj.X+FObj.Rect.X; + locobj.Y := FObj.Y+FObj.Rect.Y; + locobj.rect.X := 0; + locobj.rect.Y := 0; + locobj.rect.Width := 39; + locobj.rect.Height := 52; + locobj.Vel.X := (xd-wx) div 2; + locobj.Vel.Y := (yd-wy) div 2; + locobj.Accel.X := xd-wx; + locobj.Accel.y := yd-wy; + + if g_Weapon_Hit(@locobj, 50, FUID, HIT_SOME) <> 0 then g_Sound_PlayExAt('SOUND_WEAPON_HITBERSERK', FObj.X, FObj.Y) else g_Sound_PlayExAt('SOUND_WEAPON_MISSBERSERK', FObj.X, FObj.Y); @@ -2765,6 +2879,17 @@ begin g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX, GameVelX, GameVelY-2, SHELL_SHELL); end; + + WEAPON_FLAMETHROWER: + if FAmmo[A_FUEL] > 0 then + begin + g_Weapon_flame(wx, wy, xd, yd, FUID); + FReloading[FCurrWeap] := WEAPON_RELOAD[FCurrWeap]; + Dec(FAmmo[A_FUEL]); + FFireAngle := FAngle; + f := True; + DidFire := True; + end; end; if g_Game_IsNet then @@ -2795,6 +2920,7 @@ begin WEAPON_SHOTGUN1, WEAPON_SHOTGUN2, WEAPON_SUPERPULEMET: Result := FAmmo[A_SHELLS]; WEAPON_ROCKETLAUNCHER: Result := FAmmo[A_ROCKETS]; WEAPON_PLASMA, WEAPON_BFG: Result := FAmmo[A_CELLS]; + WEAPON_FLAMETHROWER: Result := FAmmo[A_FUEL]; else Result := 0; end; end; @@ -2823,6 +2949,14 @@ begin FJetSoundOff.PlayAt(FObj.X, FObj.Y); end; +procedure TPlayer.CatchFire(Attacker: Word); +begin + FFireTime := 100; + FFireAttacker := Attacker; + if g_Game_IsNet and g_Game_IsServer then + MH_SEND_PlayerStats(FUID); +end; + procedure TPlayer.Jump(); begin if gFly or FJetpack then @@ -2883,22 +3017,34 @@ 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 - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-7+Random(15), - (FObj.Vel.Y div 2)-Random(9)) + begin + 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 - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-5+Random(11), - (FObj.Vel.Y div 2)-Random(6)) + begin + 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 - g_Obj_Push(@gItems[id].Obj, (FObj.Vel.X div 2)-3+Random(7), - (FObj.Vel.Y div 2)-Random(4)); + begin + g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-3+Random(7), + (FObj.Vel.Y div 2)-Random(4)); + end; + it.positionChanged(); // this updates spatial accelerators + end; if g_Game_IsNet and g_Game_IsServer then MH_SEND_ItemSpawn(True, id); @@ -3019,7 +3165,7 @@ 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 @@ -3054,7 +3200,7 @@ begin if Srv then begin // Âûáðîñ îðóæèÿ: - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for a := WP_FIRST to WP_LAST do if FWeapon[a] then begin case a of @@ -3066,6 +3212,7 @@ begin WEAPON_PLASMA: i := ITEM_WEAPON_PLASMA; WEAPON_BFG: i := ITEM_WEAPON_BFG; WEAPON_SUPERPULEMET: i := ITEM_WEAPON_SUPERPULEMET; + WEAPON_FLAMETHROWER: i := ITEM_WEAPON_FLAMETHROWER; else i := 0; end; @@ -3251,111 +3398,179 @@ begin 150, 0, 0); end; -procedure TPlayer.ForceWeapon(Weapon: Byte); -var - i: Byte; +procedure TPlayer.QueueWeaponSwitch(Weapon: Byte); begin if g_Game_IsClient then Exit; if Weapon > High(FWeapon) then Exit; - if FBFGFireCounter <> -1 then Exit; - - if FTime[T_SWITCH] > gTime then Exit; + FNextWeap := FNextWeap or (1 shl Weapon); +end; - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do - if FReloading[i] > 0 then Exit; +procedure TPlayer.resetWeaponQueue (); +begin + FNextWeap := 0; + FNextWeapDelay := 0; +end; - if FWeapon[Weapon] then - begin - FCurrWeap := Weapon; - FTime[T_SWITCH] := gTime+156; - if FCurrWeap = WEAPON_SAW then - FSawSoundSelect.PlayAt(FObj.X, FObj.Y); - FModel.SetWeapon(FCurrWeap); - if g_Game_IsNet then MH_SEND_PlayerStats(FUID); +function TPlayer.hasAmmoForWeapon (weapon: Byte): Boolean; +begin + result := false; + case weapon of + WEAPON_KASTET, WEAPON_SAW: result := true; + WEAPON_SHOTGUN1, WEAPON_SHOTGUN2: result := (FAmmo[A_SHELLS] > 0); + WEAPON_PISTOL, WEAPON_CHAINGUN, WEAPON_SUPERPULEMET: result := (FAmmo[A_BULLETS] > 0); + WEAPON_ROCKETLAUNCHER: result := (FAmmo[A_ROCKETS] > 0); + WEAPON_PLASMA, WEAPON_BFG: result := (FAmmo[A_CELLS] > 0); + WEAPON_FLAMETHROWER: result := (FAmmo[A_FUEL] > 0); + else result := (weapon < length(FWeapon)); end; end; -procedure TPlayer.NextWeapon(); +// return 255 for "no switch" +function TPlayer.getNextWeaponIndex (): Byte; var - i: Byte; - ok: Boolean; + i: Word; + wantThisWeapon: array[0..64] of Boolean; + wwc: Integer = 0; //HACK! + dir, cwi: Integer; begin - if g_Game_IsClient then Exit; - if FBFGFireCounter <> -1 then Exit; - - if FTime[T_SWITCH] > gTime then Exit; - - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do - if FReloading[i] > 0 then Exit; - - ok := False; - - for i := FCurrWeap+1 to WEAPON_SUPERPULEMET do - if FWeapon[i] then + result := 255; // default result: "no switch" + // had weapon cycling on previous frame? remove that flag + if (FNextWeap and $2000) <> 0 then + begin + FNextWeap := FNextWeap and $1FFF; + FNextWeapDelay := 0; + end; + // cycling has priority + if (FNextWeap and $C000) <> 0 then + begin + if (FNextWeap and $8000) <> 0 then + dir := 1 + else + dir := -1; + FNextWeap := FNextWeap or $2000; // we need this + if FNextWeapDelay > 0 then + exit; // cooldown time + cwi := FCurrWeap; + for i := 0 to High(FWeapon) do begin - FCurrWeap := i; - ok := True; - Break; - end; - - if not ok then - for i := WEAPON_KASTET to FCurrWeap-1 do - if FWeapon[i] then + cwi := (cwi+length(FWeapon)+dir) mod length(FWeapon); + if FWeapon[cwi] then begin - FCurrWeap := i; - Break; + //e_WriteLog(Format(' SWITCH: cur=%d; new=%d', [FCurrWeap, cwi]), MSG_WARNING); + result := Byte(cwi); + FNextWeapDelay := 10; + exit; end; - - FTime[T_SWITCH] := gTime+156; - - if FCurrWeap = WEAPON_SAW then - FSawSoundSelect.PlayAt(FObj.X, FObj.Y); - - FModel.SetWeapon(FCurrWeap); - - if g_Game_IsNet then MH_SEND_PlayerStats(FUID); + end; + resetWeaponQueue(); + exit; + end; + // no cycling + for i := 0 to High(wantThisWeapon) do + wantThisWeapon[i] := false; + for i := 0 to High(FWeapon) do + if (FNextWeap and (1 shl i)) <> 0 then + begin + wantThisWeapon[i] := true; + Inc(wwc); + end; + // exclude currently selected weapon from the set + wantThisWeapon[FCurrWeap] := false; + // slow down alterations a little + if wwc > 1 then + begin + //e_WriteLog(Format(' FNextWeap=%x; delay=%d', [FNextWeap, FNextWeapDelay]), MSG_WARNING); + // more than one weapon requested, assume "alteration" and check alteration delay + if FNextWeapDelay > 0 then + begin + FNextWeap := 0; + exit; + end; // yeah + end; + // do not reset weapon queue, it will be done in `RealizeCurrentWeapon()` + // but clear all counters if no weapon should be switched + if wwc < 1 then + begin + resetWeaponQueue(); + exit; + end; + //e_WriteLog(Format('wwc=%d', [wwc]), MSG_WARNING); + // try weapons in descending order + for i := High(FWeapon) downto 0 do + begin + if wantThisWeapon[i] and FWeapon[i] and ((wwc = 1) or hasAmmoForWeapon(i)) then + begin + // i found her! + result := Byte(i); + resetWeaponQueue(); + FNextWeapDelay := 10; // anyway, 'cause why not + exit; + end; + end; + // no suitable weapon found, so reset the queue, to avoid accidental "queuing" of weapon w/o ammo + resetWeaponQueue(); end; -procedure TPlayer.PrevWeapon(); +procedure TPlayer.RealizeCurrentWeapon(); + function switchAllowed (): Boolean; + var + i: Byte; + begin + result := false; + if FBFGFireCounter <> -1 then + exit; + if FTime[T_SWITCH] > gTime then + exit; + for i := WP_FIRST to WP_LAST do + if FReloading[i] > 0 then + exit; + result := true; + end; + var - i: Byte; - ok: Boolean; + nw: Byte; begin - if g_Game_IsClient then Exit; - if FBFGFireCounter <> -1 then Exit; + //e_WriteLog(Format('***RealizeCurrentWeapon: FNextWeap=%x; FNextWeapDelay=%d', [FNextWeap, FNextWeapDelay]), MSG_WARNING); + //FNextWeap := FNextWeap and $1FFF; + if FNextWeapDelay > 0 then Dec(FNextWeapDelay); // "alteration delay" - if FTime[T_SWITCH] > gTime then Exit; - - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do - if FReloading[i] > 0 then Exit; - - ok := False; - - if FCurrWeap > 0 then - for i := FCurrWeap-1 downto WEAPON_KASTET do - if FWeapon[i] then - begin - FCurrWeap := i; - ok := True; - Break; - end; - - if not ok then - for i := WEAPON_SUPERPULEMET downto FCurrWeap+1 do - if FWeapon[i] then - begin - FCurrWeap := i; - Break; - end; + if not switchAllowed then + begin + //HACK for weapon cycling + if (FNextWeap and $7000) <> 0 then FNextWeap := 0; + exit; + end; - FTime[T_SWITCH] := gTime+156; + nw := getNextWeaponIndex(); + if nw = 255 then exit; // don't reset anything here + if nw > High(FWeapon) then + begin + // don't forget to reset queue here! + //e_WriteLog(' RealizeCurrentWeapon: WUTAFUUUU', MSG_WARNING); + resetWeaponQueue(); + exit; + end; - if FCurrWeap = WEAPON_SAW then - FSawSoundSelect.PlayAt(FObj.X, FObj.Y); + if FWeapon[nw] then + begin + FCurrWeap := nw; + FTime[T_SWITCH] := gTime+156; + if FCurrWeap = WEAPON_SAW then FSawSoundSelect.PlayAt(FObj.X, FObj.Y); + FModel.SetWeapon(FCurrWeap); + if g_Game_IsNet then MH_SEND_PlayerStats(FUID); + end; +end; - FModel.SetWeapon(FCurrWeap); +procedure TPlayer.NextWeapon(); +begin + if g_Game_IsClient then Exit; + FNextWeap := $8000; +end; - if g_Game_IsNet then MH_SEND_PlayerStats(FUID); +procedure TPlayer.PrevWeapon(); +begin + if g_Game_IsClient then Exit; + FNextWeap := $4000; end; procedure TPlayer.SetWeapon(W: Byte); @@ -3366,9 +3581,10 @@ begin FCurrWeap := W; FModel.SetWeapon(CurrWeap); + resetWeaponQueue(); end; -function TPlayer.PickItem(ItemType: Byte; respawn: Boolean; var remove: Boolean): Boolean; +function TPlayer.PickItem(ItemType: Byte; arespawn: Boolean; var remove: Boolean): Boolean; var a: Boolean; begin @@ -3376,7 +3592,7 @@ begin if g_Game_IsClient then Exit; // a = true - ìåñòî ñïàâíà ïðåäìåòà: - a := LongBool(gGameSettings.Options and GAME_OPTION_WEAPONSTAY) and respawn; + a := LongBool(gGameSettings.Options and GAME_OPTION_WEAPONSTAY) and arespawn; remove := not a; case ItemType of @@ -3386,6 +3602,7 @@ begin IncMax(FHealth, 10, PLAYER_HP_SOFT); Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; @@ -3395,6 +3612,7 @@ begin IncMax(FHealth, 25, PLAYER_HP_SOFT); Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; @@ -3422,6 +3640,7 @@ begin IncMax(FHealth, 100, PLAYER_HP_LIMIT); Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; @@ -3434,11 +3653,12 @@ begin FArmor := PLAYER_AP_LIMIT; Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; ITEM_WEAPON_SAW: - if (not FWeapon[WEAPON_SAW]) or ((not respawn) and (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) then + if (not FWeapon[WEAPON_SAW]) or ((not arespawn) and (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) then begin FWeapon[WEAPON_SAW] := True; Result := True; @@ -3531,6 +3751,18 @@ begin if a and g_Game_IsNet then MH_SEND_Sound(GameX, GameY, 'SOUND_ITEM_GETWEAPON'); end; + ITEM_WEAPON_FLAMETHROWER: + if (FAmmo[A_FUEL] < FMaxAmmo[A_FUEL]) or not FWeapon[WEAPON_FLAMETHROWER] then + begin + if a and FWeapon[WEAPON_FLAMETHROWER] then Exit; + + IncMax(FAmmo[A_FUEL], 100, FMaxAmmo[A_FUEL]); + FWeapon[WEAPON_FLAMETHROWER] := True; + Result := True; + if gFlash = 2 then Inc(FPickup, 5); + if a and g_Game_IsNet then MH_SEND_Sound(GameX, GameY, 'SOUND_ITEM_GETWEAPON'); + end; + ITEM_AMMO_BULLETS: if FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS] then begin @@ -3603,17 +3835,28 @@ begin if gFlash = 2 then Inc(FPickup, 5); end; + ITEM_AMMO_FUELCAN: + if FAmmo[A_FUEL] < FMaxAmmo[A_FUEL] then + begin + IncMax(FAmmo[A_FUEL], 100, FMaxAmmo[A_FUEL]); + Result := True; + remove := True; + if gFlash = 2 then Inc(FPickup, 5); + end; + ITEM_AMMO_BACKPACK: if not(R_ITEM_BACKPACK in FRulez) or (FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS]) or (FAmmo[A_SHELLS] < FMaxAmmo[A_SHELLS]) or (FAmmo[A_ROCKETS] < FMaxAmmo[A_ROCKETS]) or - (FAmmo[A_CELLS] < FMaxAmmo[A_CELLS]) then + (FAmmo[A_CELLS] < FMaxAmmo[A_CELLS]) or + (FMaxAmmo[A_FUEL] < AmmoLimits[1, A_FUEL]) then begin - FMaxAmmo[A_BULLETS] := 400; - FMaxAmmo[A_SHELLS] := 100; - FMaxAmmo[A_ROCKETS] := 100; - FMaxAmmo[A_CELLS] := 600; + FMaxAmmo[A_BULLETS] := AmmoLimits[1, A_BULLETS]; + FMaxAmmo[A_SHELLS] := AmmoLimits[1, A_SHELLS]; + FMaxAmmo[A_ROCKETS] := AmmoLimits[1, A_ROCKETS]; + FMaxAmmo[A_CELLS] := AmmoLimits[1, A_CELLS]; + FMaxAmmo[A_FUEL] := AmmoLimits[1, A_FUEL]; if FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS] then IncMax(FAmmo[A_BULLETS], 10, FMaxAmmo[A_BULLETS]); @@ -3666,6 +3909,7 @@ begin FMegaRulez[MR_SUIT] := gTime+PLAYER_SUIT_TIME; Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; @@ -3686,6 +3930,7 @@ begin if FBFGFireCounter = -1 then begin FCurrWeap := WEAPON_KASTET; + resetWeaponQueue(); FModel.SetWeapon(WEAPON_KASTET); end; if gFlash <> 0 then @@ -3694,6 +3939,7 @@ begin FBerserk := gTime+30000; Result := True; remove := True; + FFireTime := 0; end; if FHealth < PLAYER_HP_SOFT then begin @@ -3701,6 +3947,7 @@ begin FBerserk := gTime+30000; Result := True; remove := True; + FFireTime := 0; end; end; @@ -3719,6 +3966,7 @@ begin IncMax(FHealth, 4, PLAYER_HP_LIMIT); Result := True; remove := True; + FFireTime := 0; if gFlash = 2 then Inc(FPickup, 5); end; @@ -4031,7 +4279,7 @@ begin FAir := AIR_DEF; FJetFuel := 0; - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for a := WP_FIRST to WP_LAST do begin FWeapon[a] := False; FReloading[a] := 0; @@ -4040,18 +4288,20 @@ begin FWeapon[WEAPON_PISTOL] := True; FWeapon[WEAPON_KASTET] := True; FCurrWeap := WEAPON_PISTOL; + resetWeaponQueue(); FModel.SetWeapon(FCurrWeap); - for b := A_BULLETS to A_CELLS do + for b := A_BULLETS to A_HIGH do FAmmo[b] := 0; FAmmo[A_BULLETS] := 50; - FMaxAmmo[A_BULLETS] := 200; - FMaxAmmo[A_SHELLS] := 50; - FMaxAmmo[A_ROCKETS] := 50; - FMaxAmmo[A_CELLS] := 300; + FMaxAmmo[A_BULLETS] := AmmoLimits[0, A_BULLETS]; + FMaxAmmo[A_SHELLS] := AmmoLimits[0, A_SHELLS]; + FMaxAmmo[A_ROCKETS] := AmmoLimits[0, A_SHELLS]; + FMaxAmmo[A_CELLS] := AmmoLimits[0, A_CELLS]; + FMaxAmmo[A_FUEL] := AmmoLimits[0, A_FUEL]; if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF] then FRulez := [R_KEY_RED, R_KEY_GREEN, R_KEY_BLUE] @@ -4098,6 +4348,9 @@ begin FDamageBuffer := 0; FJetpack := False; FCanJetpack := False; + FFireTime := 0; + FFirePainTime := 0; + FFireAttacker := 0; // Àíèìàöèÿ âîçðîæäåíèÿ: if (not gLoadGameMode) and (not Silent) then @@ -4203,14 +4456,23 @@ begin 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 gGibs[a].Live 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 // Ïèíàåì êóñêè 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; + end; end; SetAction(A_WALK); @@ -4422,6 +4684,10 @@ begin FIncCam := FIncCam*i; 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 gTime mod (GAME_TICK*2) <> 0 then begin if (FObj.Vel.X = 0) and FLive then @@ -4433,7 +4699,10 @@ begin end; if FPhysics then + begin g_Obj_Move(@FObj, True, True, True); + positionChanged(); // this updates spatial accelerators + end; Exit; end; @@ -4445,8 +4714,8 @@ begin // Let alive player do some actions if FKeys[KEY_LEFT].Pressed then Run(D_LEFT); if FKeys[KEY_RIGHT].Pressed then Run(D_RIGHT); - if FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon(); - if FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon(); + //if FKeys[KEY_NEXTWEAPON].Pressed and AnyServer then NextWeapon(); + //if FKeys[KEY_PREVWEAPON].Pressed and AnyServer then PrevWeapon(); if FKeys[KEY_FIRE].Pressed and AnyServer then Fire(); if FKeys[KEY_OPEN].Pressed and AnyServer then Use(); if FKeys[KEY_JUMP].Pressed then Jump() @@ -4556,7 +4825,10 @@ begin end; if FPhysics then - g_Obj_Move(@FObj, True, True, True) + begin + g_Obj_Move(@FObj, True, True, True); + positionChanged(); // this updates spatial accelerators + end else begin FObj.Vel.X := 0; @@ -4585,7 +4857,7 @@ begin DecMin(FPain, 5, 0); DecMin(FPickup, 1, 0); - if FLive and (FObj.Y > gMapInfo.Height+128) and AnyServer then + if FLive and (FObj.Y > Integer(gMapInfo.Height)+128) and AnyServer then begin // Îáíóëèòü äåéñòâèÿ ïðèìî÷åê, ÷òîáû ôîí ïðîïàë FMegaRulez[MR_SUIT] := 0; @@ -4611,7 +4883,7 @@ begin FJetSoundFly.PlayAt(FObj.X, FObj.Y); end; - for b := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for b := WP_FIRST to WP_LAST do if FReloading[b] > 0 then if FNoReload then FReloading[b] := 0 @@ -4685,6 +4957,35 @@ begin end else if FAir < AIR_DEF then FAir := AIR_DEF; + if FFireTime > 0 then + begin + if BodyInLiquid(0, 0) then + begin + FFireTime := 0; + FFirePainTime := 0; + end + else if FMegaRulez[MR_SUIT] >= gTime then + begin + if FMegaRulez[MR_SUIT] = gTime then + FFireTime := 1; + FFirePainTime := 0; + end + else + begin + OnFireFlame(1); + if FFirePainTime <= 0 then + begin + if g_Game_IsServer then + Damage(5, FFireAttacker, 0, 0, HIT_FLAME); + FFirePainTime := 18; + end; + FFirePainTime := FFirePainTime - 1; + FFireTime := FFireTime - 1; + if (FFireTime = 0) and g_Game_IsNet and g_Game_IsServer then + MH_SEND_PlayerStats(FUID); + end; + end; + if FDamageBuffer > 0 then begin if FDamageBuffer >= 9 then @@ -4741,6 +5042,14 @@ 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; + function TPlayer.Collide(X, Y: Integer; Width, Height: Word): Boolean; begin Result := g_Collide(FObj.X+PLAYER_RECT.X, @@ -4835,7 +5144,7 @@ end; procedure TPlayer.NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1); var - Obj: TObj; + locObj: TObj; F: Boolean; WX, WY, XD, YD: Integer; begin @@ -4851,18 +5160,18 @@ begin if R_BERSERK in FRulez then begin //g_Weapon_punch(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, 75, FUID); - obj.X := FObj.X+FObj.Rect.X; - obj.Y := FObj.Y+FObj.Rect.Y; - obj.rect.X := 0; - obj.rect.Y := 0; - obj.rect.Width := 39; - obj.rect.Height := 52; - obj.Vel.X := (xd-wx) div 2; - obj.Vel.Y := (yd-wy) div 2; - obj.Accel.X := xd-wx; - obj.Accel.y := yd-wy; - - if g_Weapon_Hit(@obj, 50, FUID, HIT_SOME) <> 0 then + locobj.X := FObj.X+FObj.Rect.X; + locobj.Y := FObj.Y+FObj.Rect.Y; + locobj.rect.X := 0; + locobj.rect.Y := 0; + locobj.rect.Width := 39; + locobj.rect.Height := 52; + locobj.Vel.X := (xd-wx) div 2; + locobj.Vel.Y := (yd-wy) div 2; + locobj.Accel.X := xd-wx; + locobj.Accel.y := yd-wy; + + if g_Weapon_Hit(@locobj, 50, FUID, HIT_SOME) <> 0 then g_Sound_PlayExAt('SOUND_WEAPON_HITBERSERK', FObj.X, FObj.Y) else g_Sound_PlayExAt('SOUND_WEAPON_MISSBERSERK', FObj.X, FObj.Y); @@ -4956,6 +5265,13 @@ begin g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX, GameVelX, GameVelY-2, SHELL_SHELL); end; + + WEAPON_FLAMETHROWER: + begin + g_Weapon_flame(wx, wy, xd, yd, FUID, WID); + FFireAngle := FAngle; + f := True; + end; end; if not f then Exit; @@ -5128,6 +5444,7 @@ begin Count := FLAG_TIME; g_Obj_Push(@Obj, (FObj.Vel.X div 2)-2+Random(5), (FObj.Vel.Y div 2)-2+Random(5)); + positionChanged(); // this updates spatial accelerators if FFlag = FLAG_RED then s := _lc[I_PLAYER_FLAG_RED] @@ -5193,6 +5510,8 @@ begin FSavedState.Air := FAir; FSavedState.JetFuel := FJetFuel; FSavedState.CurrWeap := FCurrWeap; + FSavedState.NextWeap := FNextWeap; + FSavedState.NextWeapDelay := FNextWeapDelay; for i := 0 to 3 do FSavedState.Ammo[i] := FAmmo[i]; @@ -5214,6 +5533,8 @@ begin FAir := FSavedState.Air; FJetFuel := FSavedState.JetFuel; FCurrWeap := FSavedState.CurrWeap; + FNextWeap := FSavedState.NextWeap; + FNextWeapDelay := FSavedState.NextWeapDelay; for i := 0 to 3 do FAmmo[i] := FSavedState.Ammo[i]; @@ -5292,6 +5613,10 @@ begin Mem.WriteInt(FSecrets); // Òåêóùåå îðóæèå: Mem.WriteByte(FCurrWeap); +// Æåëàåìîå îðóæèå: + Mem.WriteWord(FNextWeap); +// ...è ïàóçà + Mem.WriteByte(FNextWeapDelay); // Âðåìÿ çàðÿäêè BFG: Mem.WriteSmallInt(FBFGFireCounter); // Áóôåð óðîíà: @@ -5303,16 +5628,16 @@ begin // Îáúåêò èãðîêà: Obj_SaveState(@FObj, Mem); // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.WriteWord(FAmmo[i]); // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.WriteWord(FMaxAmmo[i]); // Íàëè÷èå îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.WriteBoolean(FWeapon[i]); // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.WriteWord(FReloading[i]); // Íàëè÷èå ðþêçàêà: if R_ITEM_BACKPACK in FRulez then @@ -5428,6 +5753,10 @@ begin Mem.ReadInt(FSecrets); // Òåêóùåå îðóæèå: Mem.ReadByte(FCurrWeap); +// Æåëàåìîå îðóæèå: + Mem.ReadWord(FNextWeap); +// ...è ïàóçà + Mem.ReadByte(FNextWeapDelay); // Âðåìÿ çàðÿäêè BFG: Mem.ReadSmallInt(FBFGFireCounter); // Áóôåð óðîíà: @@ -5439,16 +5768,16 @@ begin // Îáúåêò èãðîêà: Obj_LoadState(@FObj, Mem); // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.ReadWord(FAmmo[i]); // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_CELLS do + for i := A_BULLETS to A_HIGH do Mem.ReadWord(FMaxAmmo[i]); // Íàëè÷èå îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.ReadBoolean(FWeapon[i]); // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for i := WP_FIRST to WP_LAST do Mem.ReadWord(FReloading[i]); // Íàëè÷èå ðþêçàêà: Mem.ReadByte(b); @@ -5511,8 +5840,8 @@ begin Exit; end; - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do FWeapon[a] := True; - for a := A_BULLETS to A_CELLS do FAmmo[a] := 30000; + for a := WP_FIRST to WP_LAST do FWeapon[a] := True; + for a := A_BULLETS to A_HIGH do FAmmo[a] := 30000; FRulez := FRulez+[R_KEY_RED, R_KEY_GREEN, R_KEY_BLUE]; end; @@ -5574,6 +5903,7 @@ begin if FBFGFireCounter < 1 then begin FCurrWeap := WEAPON_KASTET; + resetWeaponQueue(); FModel.SetWeapon(WEAPON_KASTET); end; if gFlash <> 0 then @@ -5605,6 +5935,68 @@ begin FJetFuel := JET_MAX; end; + ITEM_MEDKIT_SMALL: if FHealth < PLAYER_HP_SOFT then IncMax(FHealth, 10, PLAYER_HP_SOFT); + ITEM_MEDKIT_LARGE: if FHealth < PLAYER_HP_SOFT then IncMax(FHealth, 25, PLAYER_HP_SOFT); + + ITEM_ARMOR_GREEN: if FArmor < PLAYER_AP_SOFT then FArmor := PLAYER_AP_SOFT; + ITEM_ARMOR_BLUE: if FArmor < PLAYER_AP_LIMIT then FArmor := PLAYER_AP_LIMIT; + + ITEM_SPHERE_BLUE: if FHealth < PLAYER_HP_LIMIT then IncMax(FHealth, 100, PLAYER_HP_LIMIT); + ITEM_SPHERE_WHITE: + if (FHealth < PLAYER_HP_LIMIT) or (FArmor < PLAYER_AP_LIMIT) then + begin + if FHealth < PLAYER_HP_LIMIT then FHealth := PLAYER_HP_LIMIT; + if FArmor < PLAYER_AP_LIMIT then FArmor := PLAYER_AP_LIMIT; + end; + + ITEM_WEAPON_SAW: FWeapon[WEAPON_SAW] := True; + ITEM_WEAPON_SHOTGUN1: FWeapon[WEAPON_SHOTGUN1] := True; + ITEM_WEAPON_SHOTGUN2: FWeapon[WEAPON_SHOTGUN2] := True; + ITEM_WEAPON_CHAINGUN: FWeapon[WEAPON_CHAINGUN] := True; + ITEM_WEAPON_ROCKETLAUNCHER: FWeapon[WEAPON_ROCKETLAUNCHER] := True; + ITEM_WEAPON_PLASMA: FWeapon[WEAPON_PLASMA] := True; + ITEM_WEAPON_BFG: FWeapon[WEAPON_BFG] := True; + ITEM_WEAPON_SUPERPULEMET: FWeapon[WEAPON_SUPERPULEMET] := True; + ITEM_WEAPON_FLAMETHROWER: FWeapon[WEAPON_FLAMETHROWER] := True; + + ITEM_AMMO_BULLETS: if FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS] then IncMax(FAmmo[A_BULLETS], 10, FMaxAmmo[A_BULLETS]); + ITEM_AMMO_BULLETS_BOX: if FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS] then IncMax(FAmmo[A_BULLETS], 50, FMaxAmmo[A_BULLETS]); + ITEM_AMMO_SHELLS: if FAmmo[A_SHELLS] < FMaxAmmo[A_SHELLS] then IncMax(FAmmo[A_SHELLS], 4, FMaxAmmo[A_SHELLS]); + ITEM_AMMO_SHELLS_BOX: if FAmmo[A_SHELLS] < FMaxAmmo[A_SHELLS] then IncMax(FAmmo[A_SHELLS], 25, FMaxAmmo[A_SHELLS]); + ITEM_AMMO_ROCKET: if FAmmo[A_ROCKETS] < FMaxAmmo[A_ROCKETS] then IncMax(FAmmo[A_ROCKETS], 1, FMaxAmmo[A_ROCKETS]); + ITEM_AMMO_ROCKET_BOX: if FAmmo[A_ROCKETS] < FMaxAmmo[A_ROCKETS] then IncMax(FAmmo[A_ROCKETS], 5, FMaxAmmo[A_ROCKETS]); + ITEM_AMMO_CELL: if FAmmo[A_CELLS] < FMaxAmmo[A_CELLS] then IncMax(FAmmo[A_CELLS], 40, FMaxAmmo[A_CELLS]); + ITEM_AMMO_CELL_BIG: if FAmmo[A_CELLS] < FMaxAmmo[A_CELLS] then IncMax(FAmmo[A_CELLS], 100, FMaxAmmo[A_CELLS]); + ITEM_AMMO_FUELCAN: if FAmmo[A_FUEL] < FMaxAmmo[A_FUEL] then IncMax(FAmmo[A_FUEL], 100, FMaxAmmo[A_FUEL]); + + ITEM_AMMO_BACKPACK: + if (FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS]) or + (FAmmo[A_SHELLS] < FMaxAmmo[A_SHELLS]) or + (FAmmo[A_ROCKETS] < FMaxAmmo[A_ROCKETS]) or + (FAmmo[A_CELLS] < FMaxAmmo[A_CELLS]) or + (FMaxAmmo[A_FUEL] < AmmoLimits[1, A_FUEL]) then + begin + FMaxAmmo[A_BULLETS] := AmmoLimits[1, A_BULLETS]; + FMaxAmmo[A_SHELLS] := AmmoLimits[1, A_SHELLS]; + FMaxAmmo[A_ROCKETS] := AmmoLimits[1, A_ROCKETS]; + FMaxAmmo[A_CELLS] := AmmoLimits[1, A_CELLS]; + FMaxAmmo[A_FUEL] := AmmoLimits[1, A_FUEL]; + + if FAmmo[A_BULLETS] < FMaxAmmo[A_BULLETS] then IncMax(FAmmo[A_BULLETS], 10, FMaxAmmo[A_BULLETS]); + if FAmmo[A_SHELLS] < FMaxAmmo[A_SHELLS] then IncMax(FAmmo[A_SHELLS], 4, FMaxAmmo[A_SHELLS]); + if FAmmo[A_ROCKETS] < FMaxAmmo[A_ROCKETS] then IncMax(FAmmo[A_ROCKETS], 1, FMaxAmmo[A_ROCKETS]); + if FAmmo[A_CELLS] < FMaxAmmo[A_CELLS] then IncMax(FAmmo[A_CELLS], 40, FMaxAmmo[A_CELLS]); + + FRulez := FRulez + [R_ITEM_BACKPACK]; + end; + + ITEM_KEY_RED: if not (R_KEY_RED in FRulez) then Include(FRulez, R_KEY_RED); + ITEM_KEY_GREEN: if not (R_KEY_GREEN in FRulez) then Include(FRulez, R_KEY_GREEN); + ITEM_KEY_BLUE: if not (R_KEY_BLUE in FRulez) then Include(FRulez, R_KEY_BLUE); + + ITEM_BOTTLE: if FHealth < PLAYER_HP_LIMIT then IncMax(FHealth, 4, PLAYER_HP_LIMIT); + ITEM_HELMET: if FArmor < PLAYER_AP_LIMIT then IncMax(FArmor, 5, PLAYER_AP_LIMIT); + else Exit; end; @@ -5644,6 +6036,27 @@ begin end; end; +procedure TPlayer.OnFireFlame(Times: DWORD = 1); +var + id, i: DWORD; + Anim: TAnimation; +begin + if (Random(10) = 1) and (Times = 1) then + Exit; + + if g_Frames_Get(id, 'FRAMES_FLAME') then + 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; + end; +end; + procedure TPlayer.PauseSounds(Enable: Boolean); begin FSawSound.Pause(Enable); @@ -5682,6 +6095,8 @@ begin inherited; end; +procedure TCorpse.positionChanged (); begin end; + procedure TCorpse.Damage(Value: Word; vx, vy: Integer); var pm: TPlayerModel; @@ -5748,7 +6163,7 @@ begin if gTime mod (GAME_TICK*2) <> 0 then begin g_Obj_Move(@FObj, True, True, True); - + positionChanged(); // this updates spatial accelerators Exit; end; @@ -5756,6 +6171,7 @@ begin 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 @@ -5862,7 +6278,7 @@ begin Inc(gNumBots); - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do + for a := WP_FIRST to WP_LAST do begin FDifficult.WeaponPrior[a] := WEAPON_PRIOR1[a]; FDifficult.CloseWeaponPrior[a] := WEAPON_PRIOR2[a]; @@ -5890,6 +6306,7 @@ begin FAIFlags := nil; FSelectedWeapon := FCurrWeap; + resetWeaponQueue(); FTargetUID := 0; end; @@ -5935,8 +6352,43 @@ var firew, fireh: Integer; angle: SmallInt; mon: TMonster; - pla: TPlayer; + pla, tpla: TPlayer; vsPlayer, vsMonster, ok: Boolean; + + + function monsUpdate (mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.Live 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); @@ -5952,7 +6404,7 @@ begin case FCurrWeap of WEAPON_PLASMA, WEAPON_SUPERPULEMET, WEAPON_CHAINGUN: PressKey(KEY_FIRE, 20); - WEAPON_SAW, WEAPON_KASTET, WEAPON_MEGAKASTET: PressKey(KEY_FIRE, 40); + WEAPON_SAW, WEAPON_KASTET, WEAPON_FLAMETHROWER: PressKey(KEY_FIRE, 40); else PressKey(KEY_FIRE); end; end; @@ -5969,14 +6421,16 @@ begin if (g_GetUIDType(Target.UID) = UID_PLAYER) and vsPlayer then begin // Èãðîê - with g_Player_Get(Target.UID) do - begin - if (@FObj) <> nil then + tpla := g_Player_Get(Target.UID); + if tpla <> nil then + with tpla do begin - Target.X := FObj.X; - Target.Y := FObj.Y; + if (@FObj) <> nil then + begin + Target.X := FObj.X; + Target.Y := FObj.Y; + end; end; - end; Target.cX := Target.X + PLAYER_RECT_CX; Target.cY := Target.Y + PLAYER_RECT_CY; @@ -5991,7 +6445,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; @@ -6064,41 +6518,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; // Åñëè åñòü âîçìîæíûå öåëè: @@ -6258,7 +6678,7 @@ begin end else begin // Öåëü - ìîíñòð - mon := g_Monsters_Get(Target.UID); + mon := g_Monsters_ByUID(Target.UID); if (mon = nil) or (not mon.Live) then Target.UID := 0; // òî çàáûòü öåëü end; @@ -6316,6 +6736,9 @@ begin end; end; + //HACK! (does it belongs there?) + RealizeCurrentWeapon(); + // Åñëè åñòü âîçìîæíûå öåëè: // (Ñòðåëÿåì ïî íàïðàâëåíèþ ê öåëÿì) if (targets <> nil) and (GetAIFlag('NEEDFIRE') <> '') then @@ -6419,6 +6842,10 @@ begin begin UpdateMove(); UpdateCombat(); + end + else + begin + RealizeCurrentWeapon(); end; end; @@ -6439,33 +6866,33 @@ begin Result := FKeys[Key].Pressed; end; -function TBot.GetAIFlag(fName: String20): String20; +function TBot.GetAIFlag(aName: String20): String20; var a: Integer; begin Result := ''; - fName := LowerCase(fName); + aName := LowerCase(aName); if FAIFlags <> nil then for a := 0 to High(FAIFlags) do - if LowerCase(FAIFlags[a].Name) = fName then + if LowerCase(FAIFlags[a].Name) = aName then begin Result := FAIFlags[a].Value; Break; end; end; -procedure TBot.RemoveAIFlag(fName: String20); +procedure TBot.RemoveAIFlag(aName: String20); var a, b: Integer; begin if FAIFlags = nil then Exit; - fName := LowerCase(fName); + aName := LowerCase(aName); for a := 0 to High(FAIFlags) do - if LowerCase(FAIFlags[a].Name) = fName then + if LowerCase(FAIFlags[a].Name) = aName then begin if a <> High(FAIFlags) then for b := a to High(FAIFlags)-1 do @@ -6476,7 +6903,7 @@ begin end; end; -procedure TBot.SetAIFlag(fName, fValue: String20); +procedure TBot.SetAIFlag(aName, fValue: String20); var a: Integer; ok: Boolean; @@ -6484,11 +6911,11 @@ begin a := 0; ok := False; - fName := LowerCase(fName); + aName := LowerCase(aName); if FAIFlags <> nil then for a := 0 to High(FAIFlags) do - if LowerCase(FAIFlags[a].Name) = fName then + if LowerCase(FAIFlags[a].Name) = aName then begin ok := True; Break; @@ -6500,7 +6927,7 @@ begin SetLength(FAIFlags, Length(FAIFlags)+1); with FAIFlags[High(FAIFlags)] do begin - Name := fName; + Name := aName; Value := fValue; end; end; @@ -6917,6 +7344,7 @@ var WEAPON_PLASMA: Result := FAmmo[A_CELLS] >= 10; WEAPON_BFG: Result := FAmmo[A_CELLS] >= 40; WEAPON_SUPERPULEMET: Result := FAmmo[A_SHELLS] >= 1; + WEAPON_FLAMETHROWER: Result := FAmmo[A_FUEL] >= 1; else Result := True; end; end; @@ -7002,7 +7430,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;