DEADSOFTWARE

nail the sky on scaled small levels (actually, better sky moving in non-standard...
[d2df-sdl.git] / src / game / g_game.pas
index 7e20f0962af8e18c463e556ec3a9443ba9d9a668..fcb43f319d324f9cf568c3d6abd04837aabd3ebe 100644 (file)
@@ -22,7 +22,7 @@ uses
   SysUtils, Classes,
   MAPDEF,
   g_basic, g_player, e_graphics, g_res_downloader,
-  g_sound, g_gui, utils, md5, xprofiler;
+  g_sound, g_gui, utils, md5, mempool, xprofiler;
 
 type
   TGameSettings = record
@@ -49,6 +49,12 @@ type
     DEStr: String;
   end;
 
+  TChatSound = record
+    Sound: TPlayableSound;
+    Tags: Array of String;
+    FullWord: Boolean;
+  end;
+
   TPlayerSettings = record
     Name: String;
     Model: String;
@@ -114,6 +120,7 @@ procedure g_Game_PauseAllSounds(Enable: Boolean);
 procedure g_Game_StopAllSounds(all: Boolean);
 procedure g_Game_UpdateTriggerSounds();
 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_StartVote(Command, Initiator: string);
@@ -303,6 +310,10 @@ var
   gVotesEnabled: Boolean = True;
   gEvents: Array of TGameEvent;
   gDelayedEvents: Array of TDelayedEvent;
+  gUseChatSounds: Boolean = True;
+  gChatSounds: Array of TChatSound;
+
+  g_dbg_ignore_bounds: Boolean = false;
 
   // move button values:
   // bits 0-1: l/r state:
@@ -344,7 +355,7 @@ uses
   e_input, e_log, g_console, g_items, g_map, g_panel,
   g_playermodel, g_gfx, g_options, g_weapons, Math,
   g_triggers, g_monsters, e_sound, CONFIG,
-  g_language, g_net, SDL,
+  g_language, g_net,
   ENet, e_msg, g_netmsg, g_netmaster, GL, GLExt,
   sfs, wadreader, g_holmes;
 
@@ -1532,6 +1543,8 @@ var
   reliableUpdate: Boolean;
 begin
   g_ResetDynlights();
+  framePool.reset();
+
 // Ïîðà âûêëþ÷àòü èãðó:
   if gExit = EXIT_QUIT then
     Exit;
@@ -2047,6 +2060,63 @@ begin
   end;
 end;
 
+procedure g_Game_LoadChatSounds(Resource: string);
+var
+  WAD: TWADFile;
+  FileName, Snd: string;
+  p: Pointer;
+  len, cnt, tags, i, j: Integer;
+  cfg: TConfig;
+begin
+  FileName := g_ExtractWadName(Resource);
+
+  WAD := TWADFile.Create();
+  WAD.ReadFile(FileName);
+
+  if not WAD.GetResource(g_ExtractFilePathName(Resource), p, len) then
+  begin
+    gChatSounds := nil;
+    WAD.Free();
+    Exit;
+  end;
+
+  cfg := TConfig.CreateMem(p, len);
+  cnt := cfg.ReadInt('ChatSounds', 'Count', 0);
+
+  SetLength(gChatSounds, cnt);
+  for i := 0 to Length(gChatSounds) - 1 do
+  begin
+    gChatSounds[i].Sound := nil;
+    Snd := Trim(cfg.ReadStr(IntToStr(i), 'Sound', ''));
+    tags := cfg.ReadInt(IntToStr(i), 'Tags', 0);
+    if (Snd = '') or (Tags <= 0) then
+      continue;
+    g_Sound_CreateWADEx('SOUND_CHAT_MACRO' + IntToStr(i), GameWAD+':'+Snd);
+    gChatSounds[i].Sound := TPlayableSound.Create();
+    gChatSounds[i].Sound.SetByName('SOUND_CHAT_MACRO' + IntToStr(i));
+    SetLength(gChatSounds[i].Tags, tags);
+    for j := 0 to tags - 1 do
+      gChatSounds[i].Tags[j] := toLowerCase1251(cfg.ReadStr(IntToStr(i), 'Tag' + IntToStr(j), ''));
+    gChatSounds[i].FullWord := cfg.ReadBool(IntToStr(i), 'FullWord', False);
+  end;
+
+  cfg.Free();
+  WAD.Free();
+end;
+
+procedure g_Game_FreeChatSounds();
+var
+  i: Integer;
+begin
+  for i := 0 to Length(gChatSounds) - 1 do
+  begin
+    gChatSounds[i].Sound.Free();
+    g_Sound_Delete('SOUND_CHAT_MACRO' + IntToStr(i));
+  end;
+  SetLength(gChatSounds, 0);
+  gChatSounds := nil;
+end;
+
 procedure g_Game_LoadData();
 var
   wl, hl: Integer;
@@ -2096,6 +2166,7 @@ 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_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');
@@ -2136,6 +2207,8 @@ begin
   killsnd[2].SetByName('SOUND_ANNOUNCER_KILL4X');
   killsnd[3].SetByName('SOUND_ANNOUNCER_KILLMX');
 
+  g_Game_LoadChatSounds(GameWAD+':CHATSND\SNDCFG');
+
   g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
   g_Items_LoadData();
 
@@ -2170,6 +2243,7 @@ begin
   g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
   g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
   g_Frames_DeleteByName('FRAMES_TELEPORT');
+  g_Frames_DeleteByName('FRAMES_PUNCH');
   g_Sound_Delete('SOUND_GAME_TELEPORT');
   g_Sound_Delete('SOUND_GAME_NOTELEPORT');
   g_Sound_Delete('SOUND_GAME_DOOROPEN');
@@ -2201,6 +2275,8 @@ begin
   g_Sound_Delete('SOUND_ANNOUNCER_KILL4X');
   g_Sound_Delete('SOUND_ANNOUNCER_KILLMX');
 
+  g_Game_FreeChatSounds();
+
   DataLoaded := False;
 end;
 
@@ -2579,7 +2655,8 @@ procedure DrawLoadingStat();
       g_Texture_Get('UI_GFX_PBAR_MARKER', idm);
       g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm, hm);
 
-      rectW := gScreenWidth-64;
+      //rectW := gScreenWidth-360;
+      rectW := trunc(624.0*gScreenWidth/1024.0);
       rectH := hl;
 
       x0 := (gScreenWidth-rectW) div 2;
@@ -2607,7 +2684,7 @@ procedure DrawLoadingStat();
       if (wdt > rectW-wl-wr) then wdt := rectW-wr-wr;
       if (wdt > 0) then
       begin
-        my := y0+(rectH-wm) div 2;
+        my := y0; // don't be so smart, ketmar: +(rectH-wm) div 2;
         glScissor(x0+wl, gScreenHeight-my-rectH, wdt, hm);
         f := x0+wl;
         while (wdt > 0) do
@@ -2619,13 +2696,6 @@ procedure DrawLoadingStat();
       end;
 
       glScissor(0, 0, gScreenWidth, gScreenHeight);
-
-{
-procedure e_DrawSize(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
-                     Blending: Boolean; Width, Height: Word; Mirror: TMirrorType = TMirrorType.None);
-        if g_Texture_Get('MENU_BACKGROUND', ID) then e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
-        else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
-}
     end
     else
     begin
@@ -3182,7 +3252,7 @@ begin
   px := p.GameX + PLAYER_RECT_CX;
   py := p.GameY + PLAYER_RECT_CY+p.Obj.slopeUpLeft;
 
-  if (g_dbg_scale = 1.0) then
+  if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then
   begin
     if (px > (gPlayerScreenSize.X div 2)) then a := -px+(gPlayerScreenSize.X div 2) else a := 0;
     if (py > (gPlayerScreenSize.Y div 2)) then b := -py+(gPlayerScreenSize.Y div 2) else b := 0;
@@ -3260,6 +3330,16 @@ begin
   //conwritefln('OLD: (%s,%s)-(%s,%s)', [sX, sY, sWidth, sHeight]);
   fixViewportForScale();
   //conwritefln('     (%s,%s)-(%s,%s)', [sX, sY, sWidth, sHeight]);
+  if (g_dbg_scale <> 1.0) and (not g_dbg_ignore_bounds) then
+  begin
+    if (sX+sWidth > gMapInfo.Width) then sX := gMapInfo.Width-sWidth;
+    if (sY+sHeight > gMapInfo.Height) then sY := gMapInfo.Height-sHeight;
+    if (sX < 0) then sX := 0;
+    if (sY < 0) then sY := 0;
+
+    if (gBackSize.X <= gPlayerScreenSize.X) or (gMapInfo.Width <= sWidth) then c := 0 else c := trunc((gBackSize.X-gPlayerScreenSize.X)*sX/(gMapInfo.Width-sWidth));
+    if (gBackSize.Y <= gPlayerScreenSize.Y) or (gMapInfo.Height <= sHeight) then d := 0 else d := trunc((gBackSize.Y-gPlayerScreenSize.Y)*sY/(gMapInfo.Height-sHeight));
+  end;
   p.viewPortX := sX;
   p.viewPortY := sY;
   p.viewPortW := sWidth;
@@ -6894,6 +6974,71 @@ begin
   MessageTime := Time;
 end;
 
+procedure g_Game_ChatSound(Text: String; Taunt: Boolean = True);
+const
+  punct: Array[0..13] of String =
+  ('.', ',', ':', ';', '!', '?', '(', ')', '''', '"', '/', '\', '*', '^');
+var
+  i, j: Integer;
+  ok: Boolean;
+  fpText: String;
+
+  function IsPunctuation(S: String): Boolean;
+  var
+    i: Integer;
+  begin
+    Result := False;
+    if Length(S) <> 1 then
+      Exit;
+    for i := Low(punct) to High(punct) do
+      if S = punct[i] then
+      begin
+        Result := True;
+        break;
+      end;
+  end;
+  function FilterPunctuation(S: String): String;
+  var
+    i: Integer;
+  begin
+    for i := Low(punct) to High(punct) do
+      S := StringReplace(S, punct[i], ' ', [rfReplaceAll]);
+    Result := S;
+  end;
+begin
+  ok := False;
+
+  if gUseChatSounds and Taunt and (gChatSounds <> nil) and (Pos(': ', Text) > 0) then
+  begin
+    // remove player name
+    Delete(Text, 1, Pos(': ', Text) + 2 - 1);
+    // for FullWord check
+    Text := toLowerCase1251(' ' + Text + ' ');
+    fpText := FilterPunctuation(Text);
+
+    for i := 0 to Length(gChatSounds) - 1 do
+    begin
+      ok := True;
+      for j := 0 to Length(gChatSounds[i].Tags) - 1 do
+      begin
+        if gChatSounds[i].FullWord and (not IsPunctuation(gChatSounds[i].Tags[j])) then
+          ok := Pos(' ' + gChatSounds[i].Tags[j] + ' ', fpText) > 0
+        else
+          ok := Pos(gChatSounds[i].Tags[j], Text) > 0;
+        if not ok then
+          break;
+      end;
+      if ok then
+      begin
+        gChatSounds[i].Sound.Play();
+        break;
+      end;
+    end;
+  end;
+  if not ok then
+    g_Sound_PlayEx('SOUND_GAME_RADIO');
+end;
+
 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
 var
   a: Integer;
@@ -7393,7 +7538,9 @@ begin
 
   conRegVar('dbg_holmes', @g_holmes_enabled, 'enable/disable Holmes', 'Holmes', true);
 
-  conRegVar('dbg_scale', @g_dbg_scale, 0.01, 100.0, 'experimental deBUG scale mode', '',  false);
+  conRegVar('dbg_ignore_level_bounds', @g_dbg_ignore_bounds, 'ignore level bounds', '',  false);
+
+  conRegVar('r_scale', @g_dbg_scale, 0.01, 100.0, 'render scale', '',  false);
 
   conRegVar('light_enabled', @gwin_k8_enable_light_experiments, 'enable/disable dynamic lighting', 'lighting');
   conRegVar('light_player_halo', @g_playerLight, 'enable/disable player halo', 'player light halo');