summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 50caedb)
raw | patch | inline | side by side (parent: 50caedb)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Sun, 6 Aug 2017 01:54:36 +0000 (04:54 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Sun, 6 Aug 2017 04:07:56 +0000 (07:07 +0300) |
it is now possible to assign one key to several weapons
it is now possible to switch between sg/ssg with one key
switching to a new weapon while current one is reloading
is correctly processed when reload complete
it is now possible to switch between sg/ssg with one key
switching to a new weapon while current one is reloading
is correctly processed when reload complete
src/game/g_game.pas | patch | blob | history | |
src/game/g_netmsg.pas | patch | blob | history | |
src/game/g_player.pas | patch | blob | history |
diff --git a/src/game/g_game.pas b/src/game/g_game.pas
index c3f4b589684658007dcc4e7d63a9b96a33e20c18..91e0a9d7be9f2bee353d4112a415a01add2e5611 100644 (file)
--- a/src/game/g_game.pas
+++ b/src/game/g_game.pas
for i := 0 to High(KeyWeapon) do
if isKeyPressed(KeyWeapon[i], KeyWeapon2[i]) then
- begin
- plr.ForceWeapon(i);
- Break;
- end;
+ plr.QueueWeaponSwitch(i); // all choices are passed there, and god will take the best
end;
end;
begin
if g_Game_IsNet and (gPlayer1 <> nil) then gPlayer1.PressKey(KEY_CHAT, 10000);
end;
+ // process weapon switch queue
+ if gPlayer1 <> nil then gPlayer1.RealizeCurrentWeapon();
+ if gPlayer2 <> nil then gPlayer2.RealizeCurrentWeapon();
end; // if server
// Íàáëþäàòåëü
if cmd = 'jetpack' then begin plr.GiveItem(ITEM_JETPACK); g_Console_Add('player got jetpack'); continue; end;
if cmd = 'suit' then begin plr.GiveItem(ITEM_SUIT); g_Console_Add('player got envirosuit'); continue; end;
if cmd = 'berserk' then begin plr.GiveItem(ITEM_MEDKIT_BLACK); g_Console_Add('player got berserk pack'); continue; end;
+ if (cmd = 'shotgun') or (cmd = 'sg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN1); plr.GiveItem(ITEM_AMMO_SHELLS_BOX); g_Console_Add('player got a shotgun'); continue; end;
+ if (cmd = 'supershotgun') or (cmd = 'ssg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN2); plr.GiveItem(ITEM_AMMO_SHELLS_BOX); g_Console_Add('player got a supershotgun'); continue; end;
+ if (cmd = 'chain') or (cmd = 'chaingun') then begin plr.GiveItem(ITEM_WEAPON_CHAINGUN); plr.GiveItem(ITEM_AMMO_BULLETS_BOX); g_Console_Add('player got a chaingun'); continue; end;
+ if (cmd = 'launcher') or (cmd = 'rocketlauncher') then begin plr.GiveItem(ITEM_WEAPON_ROCKETLAUNCHER); plr.GiveItem(ITEM_AMMO_ROCKET_BOX); g_Console_Add('player got a rocket launcher'); continue; end;
+ if cmd = 'plasmagun' then begin plr.GiveItem(ITEM_WEAPON_PLASMA); plr.GiveItem(ITEM_AMMO_CELL_BIG); g_Console_Add('player got a plasma gun'); continue; end;
+ if cmd = 'bfg' then begin plr.GiveItem(ITEM_WEAPON_BFG); plr.GiveItem(ITEM_AMMO_CELL_BIG); g_Console_Add('player got a BFG-9000'); continue; end;
g_Console_Add('i don''t know how to give '''+cmd+'''!');
end;
exit;
diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index abc65a04102c45ca288b87fd6a2caeeac914fa00..6e8106fc61701e20d9b29c2eede43ff50d6cec16 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
if LongBool(kByte and NET_KEY_PW) then PressKey(KEY_PREVWEAPON, 10000);
if WeaponSelect <> 255 then
- ForceWeapon(WeaponSelect);
+ QueueWeaponSwitch(WeaponSelect);
end;
// MH_SEND_PlayerPos(False, PID, C^.ID);
diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index caddc0d9e7612dfa230b9676b010a95373bb6cbb..989f11a095e2055a116a8a9316742798ac7ff684 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
Air: Integer;
JetFuel: Integer;
CurrWeap: Byte;
+ NextWeap: WORD;
Ammo: Array [A_BULLETS..A_CELLS] of Word;
MaxAmmo: Array [A_BULLETS..A_CELLS] of Word;
Weapon: Array [WEAPON_KASTET..WEAPON_SUPERPULEMET] of Boolean;
FFlag: Byte;
FSecrets: Integer;
FCurrWeap: Byte;
+ FNextWeap: WORD;
FBFGFireCounter: SmallInt;
FLastSpawnerUID: Word;
FLastHit: Byte;
procedure Jump();
procedure Use();
+ procedure cycleWeapon (dir: Integer);
+ function getNextWeaponIndex (): Byte; // return 255 for "no switch"
+ procedure resetWeaponQueue ();
+
public
FDamageBuffer: Integer;
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;
Mem.ReadInt(gPlayers[a].FSecrets);
// Òåêóùåå îðóæèå:
Mem.ReadByte(gPlayers[a].FCurrWeap);
+// Ñëåäóþùåå æåëàåìîå îðóæèå:
+ Mem.ReadWord(gPlayers[a].FNextWeap);
// Âðåìÿ çàðÿäêè BFG:
Mem.ReadSmallInt(gPlayers[a].FBFGFireCounter);
// Áóôåð óðîíà:
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;
+ FNextWeap := FNextWeap or (1 shl Weapon);
+end;
- if FTime[T_SWITCH] > gTime then Exit;
+procedure TPlayer.resetWeaponQueue ();
+begin
+ FNextWeap := 0;
+end;
- for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do
- if FReloading[i] > 0 then Exit;
+// return 255 for "no switch"; resets `FNextWeap`
+function TPlayer.getNextWeaponIndex (): Byte;
+var
+ i: Word;
+ wantThisWeapon: array[0..64] of Boolean;
+begin
+ result := 255; // default result: "no switch"
+ 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 wantThisWeapon[i] := true;
+ if wantThisWeapon[FCurrWeap] then
+ begin
+ // these hacks implements alternating between SG and SSG; sorry
+ if FCurrWeap = WEAPON_SHOTGUN1 then wantThisWeapon[WEAPON_SHOTGUN2] := true;
+ if FCurrWeap = WEAPON_SHOTGUN2 then wantThisWeapon[WEAPON_SHOTGUN1] := true;
+ // these hacks implements alternating between knuckles and chainsaw; sorry
+ if FCurrWeap = WEAPON_KASTET then wantThisWeapon[WEAPON_SAW] := true;
+ if FCurrWeap = WEAPON_SAW then wantThisWeapon[WEAPON_KASTET] := true;
+ end;
+ // now exclude currently selected weapon from the set
+ wantThisWeapon[FCurrWeap] := false;
+ // no more hacks (yet)
+ // do not reset weapon queue, it will be done in `RealizeCurrentWeapon()`
+ // now try weapons in descending order
+ for i := High(FWeapon) downto 0 do
+ begin
+ if wantThisWeapon[i] and FWeapon[i] then
+ begin
+ // i found her!
+ result := Byte(i);
+ exit;
+ end;
+ end;
+end;
+
+procedure TPlayer.RealizeCurrentWeapon();
+var
+ i, nw: Byte;
+begin
+ nw := getNextWeaponIndex();
+ if nw > High(FWeapon) then begin resetWeaponQueue(); exit; end; // don't forget to reset queue here!
+
+ if FBFGFireCounter <> -1 then exit;
+ if FTime[T_SWITCH] > gTime then exit;
- if FWeapon[Weapon] then
+ for i := WEAPON_KASTET to WEAPON_SUPERPULEMET do if FReloading[i] > 0 then exit;
+
+ if FWeapon[nw] then
begin
- FCurrWeap := Weapon;
+ FCurrWeap := nw;
FTime[T_SWITCH] := gTime+156;
- if FCurrWeap = WEAPON_SAW then
- FSawSoundSelect.PlayAt(FObj.X, FObj.Y);
+ if FCurrWeap = WEAPON_SAW then FSawSoundSelect.PlayAt(FObj.X, FObj.Y);
FModel.SetWeapon(FCurrWeap);
if g_Game_IsNet then MH_SEND_PlayerStats(FUID);
end;
+ // reset weapon queue; `getNextWeaponIndex()` guarantees to not select a weapon player don't have
+ resetWeaponQueue();
end;
-procedure TPlayer.NextWeapon();
+procedure TPlayer.cycleWeapon (dir: Integer);
var
- i: Byte;
- ok: Boolean;
+ i, 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
+ if dir < 0 then dir := 1 else if dir > 0 then dir := 1 else exit;
+ cwi := FCurrWeap;
+ for i := 0 to High(FWeapon) do
+ begin
+ cwi := cwi+dir;
+ if cwi < 0 then cwi += length(FWeapon)
+ else if cwi > High(FWeapon) then cwi := cwi-length(FWeapon);
+ if FWeapon[cwi] then
begin
- FCurrWeap := i;
- ok := True;
- Break;
+ QueueWeaponSwitch(Byte(cwi));
+ exit;
end;
+ end;
+end;
- if not ok then
- for i := WEAPON_KASTET to FCurrWeap-1 do
- if FWeapon[i] then
- begin
- FCurrWeap := i;
- Break;
- 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);
+procedure TPlayer.NextWeapon();
+begin
+ if g_Game_IsClient then Exit;
+ cycleWeapon(1);
end;
procedure TPlayer.PrevWeapon();
-var
- i: Byte;
- ok: Boolean;
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;
-
- 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;
-
- 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);
+ cycleWeapon(-1);
end;
procedure TPlayer.SetWeapon(W: Byte);
FCurrWeap := W;
FModel.SetWeapon(CurrWeap);
+ resetWeaponQueue();
end;
function TPlayer.PickItem(ItemType: Byte; respawn: Boolean; var remove: Boolean): Boolean;
if FBFGFireCounter = -1 then
begin
FCurrWeap := WEAPON_KASTET;
+ resetWeaponQueue();
FModel.SetWeapon(WEAPON_KASTET);
end;
if gFlash <> 0 then
FWeapon[WEAPON_PISTOL] := True;
FWeapon[WEAPON_KASTET] := True;
FCurrWeap := WEAPON_PISTOL;
+ resetWeaponQueue();
FModel.SetWeapon(FCurrWeap);
FSavedState.Air := FAir;
FSavedState.JetFuel := FJetFuel;
FSavedState.CurrWeap := FCurrWeap;
+ FSavedState.NextWeap := FNextWeap;
for i := 0 to 3 do
FSavedState.Ammo[i] := FAmmo[i];
FAir := FSavedState.Air;
FJetFuel := FSavedState.JetFuel;
FCurrWeap := FSavedState.CurrWeap;
+ FNextWeap := FSavedState.NextWeap;
for i := 0 to 3 do
FAmmo[i] := FSavedState.Ammo[i];
Mem.WriteInt(FSecrets);
// Òåêóùåå îðóæèå:
Mem.WriteByte(FCurrWeap);
+// Æåëàåìîå îðóæèå:
+ Mem.WriteWord(FNextWeap);
// Âðåìÿ çàðÿäêè BFG:
Mem.WriteSmallInt(FBFGFireCounter);
// Áóôåð óðîíà:
Mem.ReadInt(FSecrets);
// Òåêóùåå îðóæèå:
Mem.ReadByte(FCurrWeap);
+// Æåëàåìîå îðóæèå:
+ Mem.ReadWord(FNextWeap);
// Âðåìÿ çàðÿäêè BFG:
Mem.ReadSmallInt(FBFGFireCounter);
// Áóôåð óðîíà:
if FBFGFireCounter < 1 then
begin
FCurrWeap := WEAPON_KASTET;
+ resetWeaponQueue();
FModel.SetWeapon(WEAPON_KASTET);
end;
if gFlash <> 0 then
FJetFuel := JET_MAX;
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;
FAIFlags := nil;
FSelectedWeapon := FCurrWeap;
+ resetWeaponQueue();
FTargetUID := 0;
end;
end;
end;
+ //HACK! (does it belongs there?)
+ RealizeCurrentWeapon();
+
// Åñëè åñòü âîçìîæíûå öåëè:
// (Ñòðåëÿåì ïî íàïðàâëåíèþ ê öåëÿì)
if (targets <> nil) and (GetAIFlag('NEEDFIRE') <> '') then