X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=7dd22f870f497aec99735edd27f4caa7887e7a60;hb=ba177dd9743397cb43dad787fbe7748c8ea51cba;hp=a8ddec74f3634655089671cf4a1ed81cbb018f4f;hpb=ff104a8cdc79693b7546d839605ec73ae135d904;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index a8ddec7..7dd22f8 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -1,3 +1,19 @@ +(* 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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 . + *) +{$MODE DELPHI} unit g_player; interface @@ -96,9 +112,11 @@ type Air: Integer; JetFuel: Integer; CurrWeap: Byte; + NextWeap: WORD; + NextWeapDelay: 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; + Weapon: Array [WP_FIRST..WP_LAST] of Boolean; Rulez: Set of R_ITEM_BACKPACK..R_BERSERK; WaitRecall: Boolean; end; @@ -135,6 +153,8 @@ type FFlag: Byte; FSecrets: Integer; FCurrWeap: Byte; + FNextWeap: WORD; + FNextWeapDelay: Byte; // frames FBFGFireCounter: SmallInt; FLastSpawnerUID: Word; FLastHit: Byte; @@ -189,16 +209,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; + 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; @@ -243,6 +267,7 @@ type procedure SetFlag(Flag: Byte); function DropFlag(): Boolean; procedure AllRulez(Health: Boolean); + procedure RestoreHealthArmor(); procedure FragCombo(); procedure GiveItem(ItemType: Byte); procedure Damage(value: Word; SpawnerUID: Word; vx, vy: Integer; t: Byte); virtual; @@ -270,6 +295,8 @@ type procedure NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1); procedure DoLerp(Level: Integer = 2); procedure SetLerp(XTo, YTo: Integer); + procedure QueueWeaponSwitch(Weapon: Byte); + procedure RealizeCurrentWeapon(); procedure JetpackOn; procedure JetpackOff; @@ -314,9 +341,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 @@ -470,7 +497,7 @@ implementation uses e_log, g_map, g_items, g_console, SysUtils, g_gfx, Math, g_options, g_triggers, g_menu, MAPDEF, g_game, - WADEDITOR, g_main, g_monsters, CONFIG, g_language, g_net, g_netmsg; + wadreader, g_main, g_monsters, CONFIG, g_language, g_net, g_netmsg; type TBotProfile = record @@ -484,9 +511,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 @@ -514,24 +541,27 @@ const TEAMCOLOR: Array [TEAM_RED..TEAM_BLUE] of TRGB = ((R:255; G:0; B:0), (R:0; G:0; B:255)); DIFFICULT_EASY: TDifficult = (DiagFire: 32; InvisFire: 32; DiagPrecision: 32; - FlyPrecision: 32; Cover: 32; CloseJump: 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)); DIFFICULT_MEDIUM: TDifficult = (DiagFire: 127; InvisFire: 127; DiagPrecision: 127; - FlyPrecision: 127; Cover: 127; CloseJump: 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)); DIFFICULT_HARD: TDifficult = (DiagFire: 255; InvisFire: 255; DiagPrecision: 255; - FlyPrecision: 255; Cover: 255; CloseJump: 255); - WEAPON_PRIOR1: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Byte = + 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 [WP_FIRST..WP_LAST] of Byte = (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_PRIOR2: Array [WP_FIRST..WP_LAST] of Byte = (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_PRIOR3: Array [WP_FIRST..WP_LAST] 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 = + WEAPON_RELOAD: Array [WP_FIRST..WP_LAST] of Byte = (5, 2, 6, 18, 36, 2, 12, 2, 14, 2); PLAYER_SIGNATURE = $52594C50; // 'PLYR' @@ -777,6 +807,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); // Áóôåð óðîíà: @@ -794,10 +828,10 @@ begin for i := A_BULLETS to A_CELLS 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); @@ -963,7 +997,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]; @@ -1041,7 +1075,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]; @@ -1234,10 +1268,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(); @@ -1939,6 +1987,8 @@ begin FBFGFireCounter := -1; FJustTeleported := False; FNetTime := 0; + + resetWeaponQueue(); end; procedure TPlayer.Damage(value: Word; SpawnerUID: Word; vx, vy: Integer; t: Byte); @@ -2156,6 +2206,7 @@ procedure TPlayer.Draw(); var ID: DWORD; w, h: Word; + dr: Boolean; begin if FLive then begin @@ -2175,7 +2226,16 @@ begin begin if (gPlayerDrawn <> nil) and ((Self = gPlayerDrawn) or ((FTeam = gPlayerDrawn.Team) and (gGameSettings.GameMode <> GM_DM))) then - FModel.Draw(FObj.X, FObj.Y, 200) + begin + if (FMegaRulez[MR_INVIS] - gTime) <= 2100 then + dr := not Odd((FMegaRulez[MR_INVIS] - gTime) div 300) + else + dr := True; + if dr then + FModel.Draw(FObj.X, FObj.Y, 200) + else + FModel.Draw(FObj.X, FObj.Y); + end else FModel.Draw(FObj.X, FObj.Y, 254); end @@ -3023,7 +3083,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 @@ -3220,87 +3280,156 @@ begin 150, 0, 0); end; -procedure TPlayer.NextWeapon(); -var - i: Byte; - ok: Boolean; +procedure TPlayer.QueueWeaponSwitch(Weapon: Byte); begin if g_Game_IsClient then Exit; - if FBFGFireCounter <> -1 then Exit; - - if FTime[T_SWITCH] > gTime then Exit; + if Weapon > High(FWeapon) 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; - ok := False; +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); + else result := (weapon < length(FWeapon)); + end; +end; - for i := FCurrWeap+1 to WEAPON_SUPERPULEMET do - if FWeapon[i] then +// return 255 for "no switch" +function TPlayer.getNextWeaponIndex (): Byte; +var + i: Word; + wantThisWeapon: array[0..64] of Boolean; + wwc: Integer = 0; //HACK! + dir, cwi: Integer; +begin + 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; - - if FTime[T_SWITCH] > gTime then Exit; - - for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do - if FReloading[i] > 0 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" - 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); @@ -3311,6 +3440,7 @@ begin FCurrWeap := W; FModel.SetWeapon(CurrWeap); + resetWeaponQueue(); end; function TPlayer.PickItem(ItemType: Byte; respawn: Boolean; var remove: Boolean): Boolean; @@ -3631,6 +3761,7 @@ begin if FBFGFireCounter = -1 then begin FCurrWeap := WEAPON_KASTET; + resetWeaponQueue(); FModel.SetWeapon(WEAPON_KASTET); end; if gFlash <> 0 then @@ -3976,7 +4107,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; @@ -3985,6 +4116,7 @@ begin FWeapon[WEAPON_PISTOL] := True; FWeapon[WEAPON_KASTET] := True; FCurrWeap := WEAPON_PISTOL; + resetWeaponQueue(); FModel.SetWeapon(FCurrWeap); @@ -4367,6 +4499,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 @@ -4390,8 +4526,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 +4692,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 @@ -5138,6 +5274,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]; @@ -5159,6 +5297,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]; @@ -5237,6 +5377,10 @@ begin Mem.WriteInt(FSecrets); // Òåêóùåå îðóæèå: Mem.WriteByte(FCurrWeap); +// Æåëàåìîå îðóæèå: + Mem.WriteWord(FNextWeap); +// ...è ïàóçà + Mem.WriteByte(FNextWeapDelay); // Âðåìÿ çàðÿäêè BFG: Mem.WriteSmallInt(FBFGFireCounter); // Áóôåð óðîíà: @@ -5254,10 +5398,10 @@ begin for i := A_BULLETS to A_CELLS 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 @@ -5373,6 +5517,10 @@ begin Mem.ReadInt(FSecrets); // Òåêóùåå îðóæèå: Mem.ReadByte(FCurrWeap); +// Æåëàåìîå îðóæèå: + Mem.ReadWord(FNextWeap); +// ...è ïàóçà + Mem.ReadByte(FNextWeapDelay); // Âðåìÿ çàðÿäêè BFG: Mem.ReadSmallInt(FBFGFireCounter); // Áóôåð óðîíà: @@ -5390,10 +5538,10 @@ begin for i := A_BULLETS to A_CELLS 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); @@ -5456,11 +5604,17 @@ begin Exit; end; - for a := WEAPON_KASTET to WEAPON_SUPERPULEMET do FWeapon[a] := True; + for a := WP_FIRST to WP_LAST do FWeapon[a] := True; for a := A_BULLETS to A_CELLS do FAmmo[a] := 30000; FRulez := FRulez+[R_KEY_RED, R_KEY_GREEN, R_KEY_BLUE]; end; +procedure TPlayer.RestoreHealthArmor(); +begin + FHealth := PLAYER_HP_LIMIT; + FArmor := PLAYER_AP_LIMIT; +end; + procedure TPlayer.FragCombo(); var Param: Integer; @@ -5513,6 +5667,7 @@ begin if FBFGFireCounter < 1 then begin FCurrWeap := WEAPON_KASTET; + resetWeaponQueue(); FModel.SetWeapon(WEAPON_KASTET); end; if gFlash <> 0 then @@ -5544,6 +5699,64 @@ 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_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_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]) then + begin + FMaxAmmo[A_BULLETS] := 400; + FMaxAmmo[A_SHELLS] := 100; + FMaxAmmo[A_ROCKETS] := 100; + FMaxAmmo[A_CELLS] := 600; + + 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; @@ -5642,8 +5855,9 @@ begin g_Player_CreateGibs(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2), FModelName, FColor); + // Çâóê ìÿñà îò òðóïà: pm := g_PlayerModel_Get(FModelName); - pm.PlaySound(MODELSOUND_DIE, 3, FObj.X, FObj.Y); + pm.PlaySound(MODELSOUND_DIE, 5, FObj.X, FObj.Y); pm.Free; end; end @@ -5800,7 +6014,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]; @@ -5828,6 +6042,7 @@ begin FAIFlags := nil; FSelectedWeapon := FCurrWeap; + resetWeaponQueue(); FTargetUID := 0; end; @@ -6254,6 +6469,9 @@ begin end; end; + //HACK! (does it belongs there?) + RealizeCurrentWeapon(); + // Åñëè åñòü âîçìîæíûå öåëè: // (Ñòðåëÿåì ïî íàïðàâëåíèþ ê öåëÿì) if (targets <> nil) and (GetAIFlag('NEEDFIRE') <> '') then @@ -6357,6 +6575,10 @@ begin begin UpdateMove(); UpdateCombat(); + end + else + begin + RealizeCurrentWeapon(); end; end;