DEADSOFTWARE

Revert "Revert "no more delay between weapon switching: now player should release...
[d2df-sdl.git] / src / game / g_game.pas
index b2c3dc06b4533c45e59df0fb5262c79780f75ae2..de729fae42e2b139d809d3e451dccd8c7afee1b2 100644 (file)
@@ -124,6 +124,7 @@ function  g_Game_GetMegaWADInfo(WAD: String): TMegaWADInfo;
 procedure g_Game_ChatSound(Text: String; Taunt: Boolean = True);
 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
 procedure g_Game_Announce_KillCombo(Param: Integer);
+procedure g_Game_Announce_BodyKill(SpawnerUID: Word);
 procedure g_Game_StartVote(Command, Initiator: string);
 procedure g_Game_CheckVote;
 procedure g_TakeScreenShot();
@@ -201,6 +202,7 @@ const
   DE_GLOBEVENT = 0;
   DE_BFGHIT    = 1;
   DE_KILLCOMBO = 2;
+  DE_BODYKILL  = 3;
 
   ANNOUNCE_NONE   = 0;
   ANNOUNCE_ME     = 1;
@@ -234,6 +236,8 @@ var
   gAnnouncer: Byte = ANNOUNCE_NONE;
   goodsnd: array[0..3] of TPlayableSound;
   killsnd: array[0..3] of TPlayableSound;
+  hahasnd: array[0..2] of TPlayableSound;
+  gBodyKillEvent: Integer = -1;
   gDefInterTime: ShortInt = -1;
   gInterEndTime: LongWord = 0;
   gInterTime: LongWord = 0;
@@ -263,6 +267,10 @@ var
   gSpectViewTwo: Boolean = False;
   gSpectPID1: Integer = -1;
   gSpectPID2: Integer = -1;
+  gSpectAuto: Boolean = False;
+  gSpectAutoNext: LongWord;
+  gSpectAutoStepX: Integer;
+  gSpectAutoStepY: Integer;
   gMusic: TMusic = nil;
   gLoadGameMode: Boolean;
   gCheats: Boolean = False;
@@ -354,10 +362,9 @@ function gPause (): Boolean; inline;
 implementation
 
 uses
-{$IFDEF USE_NANOGL}
-  nanoGL,
-{$ELSE}
-  GL, GLExt,
+{$INCLUDE ../nogl/noGLuses.inc}
+{$IFDEF ENABLE_HOLMES}
+  g_holmes,
 {$ENDIF}
   e_texture, g_textures, g_main, g_window, g_menu,
   e_input, e_log, g_console, g_items, g_map, g_panel,
@@ -365,7 +372,7 @@ uses
   g_triggers, g_monsters, e_sound, CONFIG,
   g_language, g_net,
   ENet, e_msg, g_netmsg, g_netmaster,
-  sfs, wadreader, g_holmes;
+  sfs, wadreader;
 
 
 var
@@ -932,6 +939,7 @@ begin
               end
               else
                 slWaitStr := _lc[I_NET_SLIST_ERROR];
+              g_Serverlist_GenerateTable(slCurrent, slTable);
             end;
 
             g_Game_ExecuteEvent('ongameend');
@@ -1015,6 +1023,7 @@ begin
             gMusic.SetByName('MUSIC_INTERMUS');
             gMusic.Play();
             gState := STATE_INTERSINGLE;
+            e_UnpressAllKeys();
 
             g_Game_ExecuteEvent('oninter');
           end
@@ -1435,6 +1444,59 @@ begin
     Result := ids[(Length(ids) - 1 + idx) mod Length(ids)];
 end;
 
+function GetActivePlayerID_Random(Skip: Integer = -1): Integer;
+var
+  a, idx: Integer;
+  ids: Array of Word;
+begin
+  Result := -1;
+  if gPlayers = nil then
+    Exit;
+  SetLength(ids, 0);
+  idx := -1;
+  for a := Low(gPlayers) to High(gPlayers) do
+    if IsActivePlayer(gPlayers[a]) then
+    begin
+      SetLength(ids, Length(ids) + 1);
+      ids[High(ids)] := gPlayers[a].UID;
+      if gPlayers[a].UID = Skip then
+        idx := High(ids);
+    end;
+  if Length(ids) = 0 then
+    Exit;
+  if Length(ids) = 1 then
+  begin
+    Result := ids[0];
+    Exit;
+  end;
+  Result := ids[Random(Length(ids))];
+  a := 10;
+  while (idx <> -1) and (Result = Skip) and (a > 0) do
+  begin
+    Result := ids[Random(Length(ids))];
+    Dec(a);
+  end;
+end;
+
+function GetRandomSpectMode(Current: Byte): Byte;
+label
+  retry;
+begin
+  Result := Current;
+retry:
+  case Random(7) of
+    0: Result := SPECT_STATS;
+    1: Result := SPECT_MAPVIEW;
+    2: Result := SPECT_MAPVIEW;
+    3: Result := SPECT_PLAYERS;
+    4: Result := SPECT_PLAYERS;
+    5: Result := SPECT_PLAYERS;
+    6: Result := SPECT_PLAYERS;
+  end;
+  if (Current in [SPECT_STATS, SPECT_MAPVIEW]) and (Current = Result) then
+    goto retry;
+end;
+
 function isKeyPressed (key1: Word; key2: Word): Boolean;
 begin
   if (key1 <> 0) and e_KeyPressed(key1) then begin result := true; exit; end;
@@ -1442,11 +1504,18 @@ begin
   result := false;
 end;
 
+function isOneKeyPressed (key1: Word): Boolean;
+begin
+  if (key1 <> 0) and e_KeyPressed(key1) then begin result := true; exit; end;
+  result := false;
+end;
+
 procedure processPlayerControls (plr: TPlayer; var ctrl: TPlayerControl; var MoveButton: Byte; p2hack: Boolean=false);
 var
   time: Word;
   strafeDir: Byte;
   i: Integer;
+  rwk: Boolean;
 begin
   if (plr = nil) then exit;
   if (p2hack) then time := 1000 else time := 1;
@@ -1490,13 +1559,42 @@ begin
     if isKeyPressed(KeyUp, KeyUp2) then plr.PressKey(KEY_UP, time);
     if isKeyPressed(KeyDown, KeyDown2) then plr.PressKey(KEY_DOWN, time);
     if isKeyPressed(KeyFire, KeyFire2) then plr.PressKey(KEY_FIRE);
-    if isKeyPressed(KeyNextWeapon, KeyNextWeapon2) then plr.PressKey(KEY_NEXTWEAPON);
-    if isKeyPressed(KeyPrevWeapon, KeyPrevWeapon2) then plr.PressKey(KEY_PREVWEAPON);
+    if isKeyPressed(KeyNextWeapon, KeyNextWeapon2) then
+    begin
+      rwk := plr.isWeaponSwitchKeyReleased(-1);
+      if rwk then plr.PressKey(KEY_NEXTWEAPON);
+      plr.weaponSwitchKeysStateChange(-1, true);
+    end
+    else
+    begin
+      plr.weaponSwitchKeysStateChange(-1, false);
+    end;
+    if isKeyPressed(KeyPrevWeapon, KeyPrevWeapon2) then
+    begin
+      rwk := plr.isWeaponSwitchKeyReleased(-2);
+      if rwk then plr.PressKey(KEY_PREVWEAPON);
+      plr.weaponSwitchKeysStateChange(-2, true);
+    end
+    else
+    begin
+      plr.weaponSwitchKeysStateChange(-2, false);
+    end;
     if isKeyPressed(KeyOpen, KeyOpen2) then plr.PressKey(KEY_OPEN);
 
     for i := 0 to High(KeyWeapon) do
+    begin
       if isKeyPressed(KeyWeapon[i], KeyWeapon2[i]) then
-        plr.QueueWeaponSwitch(i); // all choices are passed there, and god will take the best
+      begin
+        rwk := plr.isWeaponSwitchKeyReleased(i);
+        //writeln('rwk:', rwk);
+        plr.weaponSwitchKeysStateChange(i, true);
+        if rwk then plr.QueueWeaponSwitch(i); // all choices are passed there, and god will take the best
+      end
+      else
+      begin
+        plr.weaponSwitchKeysStateChange(i, false);
+      end;
+    end;
   end;
 
   // HACK: add dynlight here
@@ -1665,12 +1763,14 @@ begin
 
                 gMusic.Play();
                 gState := STATE_INTERCUSTOM;
+                e_UnpressAllKeys();
               end
             else // Çàêîí÷èëàñü ïîñëåäíÿÿ êàðòà â Îäèíî÷íîé èãðå
               begin
                 gMusic.SetByName('MUSIC_INTERMUS');
                 gMusic.Play();
                 gState := STATE_INTERSINGLE;
+                e_UnpressAllKeys();
               end;
             g_Game_ExecuteEvent('oninter');
           end
@@ -1688,7 +1788,7 @@ begin
       end;
 
     STATE_SLIST:
-        g_Serverlist_Control(slCurrent);
+        g_Serverlist_Control(slCurrent, slTable);
   end;
 
   if g_Game_IsNet then
@@ -1806,7 +1906,8 @@ begin
     begin
       if not gSpectKeyPress then
       begin
-        if isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2) then
+        if isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2)
+           and (not gSpectAuto) then
         begin
           // switch spect mode
           case gSpectMode of
@@ -1817,7 +1918,8 @@ begin
           end;
           gSpectKeyPress := True;
         end;
-        if gSpectMode = SPECT_MAPVIEW then
+        if (gSpectMode = SPECT_MAPVIEW)
+           and (not gSpectAuto) then
         begin
           if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
             gSpectX := Max(gSpectX - gSpectStep, 0);
@@ -1840,7 +1942,8 @@ begin
             gSpectKeyPress := True;
           end;
         end;
-        if gSpectMode = SPECT_PLAYERS then
+        if (gSpectMode = SPECT_PLAYERS)
+           and (not gSpectAuto) then
         begin
           if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
           begin
@@ -1879,9 +1982,27 @@ begin
             gSpectKeyPress := True;
           end;
         end;
+        if isKeyPressed(gGameControls.P1Control.KeyFire, gGameControls.P1Control.KeyFire2) then
+        begin
+          if (gSpectMode = SPECT_STATS) and (not gSpectAuto) then
+          begin
+            gSpectAuto := True;
+            gSpectAutoNext := 0;
+            gSpectViewTwo := False;
+            gSpectKeyPress := True;
+          end
+          else
+            if gSpectAuto then
+            begin
+              gSpectMode := SPECT_STATS;
+              gSpectAuto := False;
+              gSpectKeyPress := True;
+            end;
+        end;
       end
       else
         if (not isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2)) and
+           (not isKeyPressed(gGameControls.P1Control.KeyFire, gGameControls.P1Control.KeyFire2)) and
            (not isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2)) and
            (not isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2)) and
            (not isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2)) and
@@ -1889,6 +2010,54 @@ begin
            (not isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2)) and
            (not isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2)) then
           gSpectKeyPress := False;
+
+      if gSpectAuto then
+      begin
+        if gSpectMode = SPECT_MAPVIEW then
+        begin
+          i := Min(Max(gSpectX + gSpectAutoStepX, 0), gMapInfo.Width - gScreenWidth);
+          if i = gSpectX then
+            gSpectAutoNext := gTime
+          else
+            gSpectX := i;
+          i := Min(Max(gSpectY + gSpectAutoStepY, 0), gMapInfo.Height - gScreenHeight);
+          if i = gSpectY then
+            gSpectAutoNext := gTime
+          else
+            gSpectY := i;
+        end;
+        if gSpectAutoNext <= gTime then
+        begin
+          if gSpectAutoNext > 0 then
+          begin
+            gSpectMode := GetRandomSpectMode(gSpectMode);
+            case gSpectMode of
+              SPECT_MAPVIEW:
+              begin
+                gSpectX := Random(gMapInfo.Width - gScreenWidth);
+                gSpectY := Random(gMapInfo.Height - gScreenHeight);
+                gSpectAutoStepX := Random(9) - 4;
+                gSpectAutoStepY := Random(9) - 4;
+                if ((gSpectX < 800) and (gSpectAutoStepX < 0)) or
+                   ((gSpectX > gMapInfo.Width - gScreenWidth - 800) and (gSpectAutoStepX > 0)) then
+                  gSpectAutoStepX := gSpectAutoStepX * -1;
+                if ((gSpectY < 800) and (gSpectAutoStepY < 0)) or
+                   ((gSpectY > gMapInfo.Height - gScreenHeight - 800) and (gSpectAutoStepY > 0)) then
+                  gSpectAutoStepY := gSpectAutoStepY * -1;
+              end;
+              SPECT_PLAYERS:
+              begin
+                gSpectPID1 := GetActivePlayerID_Random(gSpectPID1);
+              end;
+            end;
+          end;
+          case gSpectMode of
+            SPECT_STATS:   gSpectAutoNext := gTime + (Random(3) + 5) * 1000;
+            SPECT_MAPVIEW: gSpectAutoNext := gTime + (Random(4) + 7) * 1000;
+            SPECT_PLAYERS: gSpectAutoNext := gTime + (Random(7) + 8) * 1000;
+          end;
+        end;
+      end;
     end;
 
   // Îáíîâëÿåì âñå îñòàëüíîå:
@@ -2055,6 +2224,9 @@ begin
               if g_Game_IsNet and g_Game_IsServer then
                 MH_SEND_GameEvent(NET_EV_KILLCOMBO, gDelayedEvents[a].DENum);
             end;
+          DE_BODYKILL:
+            if gGameOn then
+              g_Game_Announce_BodyKill(gDelayedEvents[a].DENum);
         end;
         gDelayedEvents[a].Pending := False;
       end;
@@ -2181,7 +2353,12 @@ begin
   end;
 
   g_Frames_CreateWAD(nil, 'FRAMES_TELEPORT', GameWAD+':TEXTURES\TELEPORT', 64, 64, 10, False);
-  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH', GameWAD+':TEXTURES\PUNCH', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH', GameWAD+':WEAPONS\PUNCH', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_UP', GameWAD+':WEAPONS\PUNCH_UP', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_DN', GameWAD+':WEAPONS\PUNCH_DN', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK', GameWAD+':WEAPONS\PUNCHB', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK_UP', GameWAD+':WEAPONS\PUNCHB_UP', 64, 64, 4, False);
+  g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK_DN', GameWAD+':WEAPONS\PUNCHB_DN', 64, 64, 4, False);
   g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT');
   g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT');
   g_Sound_CreateWADEx('SOUND_GAME_DOOROPEN', GameWAD+':SOUNDS\DOOROPEN');
@@ -2201,6 +2378,9 @@ begin
   g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL3X', GameWAD+':SOUNDS\KILL3X');
   g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL4X', GameWAD+':SOUNDS\KILL4X');
   g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILLMX', GameWAD+':SOUNDS\KILLMX');
+  g_Sound_CreateWADEx('SOUND_ANNOUNCER_MUHAHA1', GameWAD+':SOUNDS\MUHAHA1');
+  g_Sound_CreateWADEx('SOUND_ANNOUNCER_MUHAHA2', GameWAD+':SOUNDS\MUHAHA2');
+  g_Sound_CreateWADEx('SOUND_ANNOUNCER_MUHAHA3', GameWAD+':SOUNDS\MUHAHA3');
 
   goodsnd[0] := TPlayableSound.Create();
   goodsnd[1] := TPlayableSound.Create();
@@ -2222,6 +2402,14 @@ begin
   killsnd[2].SetByName('SOUND_ANNOUNCER_KILL4X');
   killsnd[3].SetByName('SOUND_ANNOUNCER_KILLMX');
 
+  hahasnd[0] := TPlayableSound.Create();
+  hahasnd[1] := TPlayableSound.Create();
+  hahasnd[2] := TPlayableSound.Create();
+
+  hahasnd[0].SetByName('SOUND_ANNOUNCER_MUHAHA1');
+  hahasnd[1].SetByName('SOUND_ANNOUNCER_MUHAHA2');
+  hahasnd[2].SetByName('SOUND_ANNOUNCER_MUHAHA3');
+
   g_Game_LoadChatSounds(GameWAD+':CHATSND\SNDCFG');
 
   g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
@@ -2259,6 +2447,11 @@ begin
   g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
   g_Frames_DeleteByName('FRAMES_TELEPORT');
   g_Frames_DeleteByName('FRAMES_PUNCH');
+  g_Frames_DeleteByName('FRAMES_PUNCH_UP');
+  g_Frames_DeleteByName('FRAMES_PUNCH_DN');
+  g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK');
+  g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_UP');
+  g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_DN');
   g_Sound_Delete('SOUND_GAME_TELEPORT');
   g_Sound_Delete('SOUND_GAME_NOTELEPORT');
   g_Sound_Delete('SOUND_GAME_DOOROPEN');
@@ -2290,6 +2483,14 @@ begin
   g_Sound_Delete('SOUND_ANNOUNCER_KILL4X');
   g_Sound_Delete('SOUND_ANNOUNCER_KILLMX');
 
+  hahasnd[0].Free();
+  hahasnd[1].Free();
+  hahasnd[2].Free();
+
+  g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA1');
+  g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA2');
+  g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA3');
+
   g_Game_FreeChatSounds();
 
   DataLoaded := False;
@@ -3390,11 +3591,13 @@ begin
   p.viewPortW := sWidth;
   p.viewPortH := sHeight;
 
+{$IFDEF ENABLE_HOLMES}
   if (p = gPlayer1) then
   begin
     g_Holmes_plrViewPos(sX, sY);
     g_Holmes_plrViewSize(sWidth, sHeight);
   end;
+{$ENDIF}
 
   renderMapInternal(-c, -d, true);
 
@@ -3584,8 +3787,10 @@ begin
         e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
     end;
 
+{$IFDEF ENABLE_HOLMES}
     // draw inspector
     if (g_holmes_enabled) then g_Holmes_Draw();
+{$ENDIF}
 
     if MessageText <> '' then
     begin
@@ -3602,7 +3807,7 @@ begin
 
     if IsDrawStat or (gSpectMode = 1) then DrawStat();
 
-    if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) then
+    if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) and (not gSpectAuto) then
     begin
     // Draw spectator GUI
       ww := 0;
@@ -3617,6 +3822,11 @@ begin
           e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1);
       end;
       e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1);
+      if gSpectMode = SPECT_STATS then
+      begin
+        e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2)*2, 'Autoview', gStdFont, 255, 255, 255, 1);
+        e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2), '< fire >', gStdFont, 255, 255, 255, 1);
+      end;
       if gSpectMode = SPECT_MAPVIEW then
       begin
         e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1);
@@ -3763,7 +3973,7 @@ begin
         //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
         e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
       end;
-      g_Serverlist_Draw(slCurrent);
+      g_Serverlist_Draw(slCurrent, slTable);
     end;
   end;
 
@@ -3797,7 +4007,9 @@ begin
 
   if gGameOn then drawProfilers();
 
+{$IFDEF ENABLE_HOLMES}
   g_Holmes_DrawUI();
+{$ENDIF}
 
   g_Touch_Draw;
 end;
@@ -7163,6 +7375,25 @@ begin
   killsnd[n].Play();
 end;
 
+procedure g_Game_Announce_BodyKill(SpawnerUID: Word);
+var
+  a: Integer;
+begin
+  case gAnnouncer of
+    ANNOUNCE_NONE:
+      Exit;
+    ANNOUNCE_ME,
+    ANNOUNCE_MEPLUS:
+      if not g_Game_IsWatchedPlayer(SpawnerUID) then
+        Exit;
+  end;
+  for a := 0 to 2 do
+    if hahasnd[a].IsPlaying() then
+      Exit;
+
+  hahasnd[Random(3)].Play();
+end;
+
 procedure g_Game_StartVote(Command, Initiator: string);
 var
   Need: Integer;
@@ -7593,7 +7824,9 @@ begin
   conRegVar('los_enabled', @gmon_dbg_los_enabled, 'enable/disable monster LOS calculations', 'monster LOS', true);
   conRegVar('mon_think', @gmon_debug_think, 'enable/disable monster thinking', 'monster thinking', true);
 
+{$IFDEF ENABLE_HOLMES}
   conRegVar('dbg_holmes', @g_holmes_enabled, 'enable/disable Holmes', 'Holmes', true);
+{$ENDIF}
 
   conRegVar('dbg_ignore_level_bounds', @g_dbg_ignore_bounds, 'ignore level bounds', '',  false);