DEADSOFTWARE

game: disable shells for server
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Sat, 29 Jan 2022 12:43:09 +0000 (15:43 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Fri, 9 Jun 2023 08:05:31 +0000 (11:05 +0300)
13 files changed:
src/game/Doom2DF.lpr
src/game/g_console.pas
src/game/g_game.pas
src/game/g_menu.pas
src/game/g_monsters.pas
src/game/g_netmsg.pas
src/game/g_options.pas
src/game/g_player.pas
src/game/g_shells.pas [new file with mode: 0644]
src/game/g_triggers.pas
src/game/opengl/r_game.pas
src/game/opengl/r_player.pas
src/shared/a_modes.inc

index 32bff3807a4516af3e4489f1b3aee23109c2e42b..f368d971c40a394694145a7ded6140fe75c57a0a 100644 (file)
@@ -129,6 +129,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs in 'g_gibs.pas',
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells in 'g_shells.pas',
+  {$ENDIF}
   g_items in 'g_items.pas',
   g_map in 'g_map.pas',
   g_monsters in 'g_monsters.pas',
index c726ac2481f298e387ba850c72415e58554f5b7f..5bb4c178565164c40faf1cf9186c623fd570f939 100644 (file)
@@ -114,6 +114,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   g_textures, e_input, g_game, g_player, g_items,
   SysUtils, g_basic, g_options, Math, e_res,
   g_language, g_net, g_netmsg, e_log, conbuf, g_weapons,
@@ -2093,7 +2096,9 @@ begin
   {$IFDEF ENABLE_GFX}
     WriteLn(f, 'g_max_particles ', g_GFX_GetMax());
   {$ENDIF}
-  WriteLn(f, 'g_max_shells ', g_Shells_GetMax());
+  {$IFDEF ENABLE_SHELLS}
+    WriteLn(f, 'g_max_shells ', g_Shells_GetMax());
+  {$ENDIF}
   {$IFDEF ENABLE_GIBS}
     WriteLn(f, 'g_max_gibs ', g_Gibs_GetMax());
   {$ENDIF}
index ad1c9afb36bb8468c93369e414779da2de3e034b..bb914b69a94f862ae651197d616bdd88733fbebd 100644 (file)
@@ -463,6 +463,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   {$IFNDEF HEADLESS}
     r_render, g_system,
   {$ENDIF}
@@ -2217,6 +2220,9 @@ begin
       g_Gibs_Update;
     {$ENDIF}
     g_Player_UpdatePhysicalObjects();
+    {$IFDEF ENABLE_SHELLS}
+      g_Shells_Update;
+    {$ENDIF}
 
     // server: send newly spawned monsters unconditionally
     if (gGameSettings.GameType = GT_SERVER) then
@@ -4066,12 +4072,18 @@ begin
   begin
     if Length(p) = 2 then
     begin
-      a := Max(0, StrToIntDef(p[1], 0));
-      g_Shells_SetMax(a)
+      {$IFDEF ENABLE_SHELLS}
+        a := Max(0, StrToIntDef(p[1], 0));
+        g_Shells_SetMax(a)
+      {$ENDIF}
     end
     else if Length(p) = 1 then
     begin
-      e_LogWritefln('%s', [g_Shells_GetMax()])
+      {$IFDEF ENABLE_SHELLS}
+        e_LogWritefln('%s', [g_Shells_GetMax()])
+      {$ELSE}
+        e_LogWritefln('%s', [0])
+      {$ENDIF}
     end
     else
     begin
index 5c4f23285f7741d9bd374f675c5bbee486d805ae..11d42616ea07bcf86b7a6258a2fa505d10e47e71 100644 (file)
@@ -45,6 +45,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   g_gui, r_textures, r_graphics, g_game, g_map,
   g_base, g_basic, g_console, g_sound, g_player, g_options, g_weapons,
   e_log, SysUtils, CONFIG, g_playermodel, DateUtils,
@@ -141,7 +144,9 @@ begin
   {$IFDEF ENABLE_GFX}
     g_GFX_SetMax(TGUIScroll(menu.GetControl('scParticlesCount')).Value*1000);
   {$ENDIF}
-  g_Shells_SetMax(TGUIScroll(menu.GetControl('scShellsMax')).Value*30);
+  {$IFDEF ENABLE_SHELLS}
+    g_Shells_SetMax(TGUIScroll(menu.GetControl('scShellsMax')).Value*30);
+  {$ENDIF}
   {$IFDEF ENABLE_GIBS}
     g_Gibs_SetMax(TGUIScroll(menu.GetControl('scGibsMax')).Value*25);
   {$ENDIF}
@@ -589,7 +594,9 @@ begin
   {$IFDEF ENABLE_GFX}
     TGUIScroll(menu.GetControl('scParticlesCount')).Value := g_GFX_GetMax() div 1000;
   {$ENDIF}
-  TGUIScroll(menu.GetControl('scShellsMax')).Value := g_Shells_GetMax() div 30;
+  {$IFDEF ENABLE_SHELLS}
+    TGUIScroll(menu.GetControl('scShellsMax')).Value := g_Shells_GetMax() div 30;
+  {$ENDIF}
   {$IFDEF ENABLE_GIBS}
     TGUIScroll(menu.GetControl('scGibsMax')).Value := g_Gibs_GetMax() div 25;
   {$ENDIF}
index 5369b9c9c6d4cbbc887539714cbc067c0c9553fa..cd660a29d5a32b034fa0188b869720ce1a34d724 100644 (file)
@@ -87,8 +87,10 @@ type
       FBloodBlue: Byte;
       FBloodKind: Byte;
     {$ENDIF}
-    FShellTimer: Integer;
-    FShellType: Byte;
+    {$IFDEF ENABLE_SHELLS}
+      FShellTimer: Integer;
+      FShellType: Byte;
+    {$ENDIF}
     FFirePainTime: Integer;
     FFireAttacker: Word;
     vilefire: TAnimationState;
@@ -532,6 +534,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   e_log, g_sound, g_player, g_game,
   g_weapons, g_triggers, g_items, g_options,
   g_console, g_map, Math, wadreader,
@@ -1591,7 +1596,9 @@ begin
   FDieTriggers := nil;
   FWaitAttackAnim := False;
   FChainFire := False;
-  FShellTimer := -1;
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
 
   FState := MONSTATE_SLEEP;
   FCurAnim := ANIM_SLEEP;
@@ -1628,7 +1635,9 @@ begin
   FChainFire := False;
   FStartID := aID;
   FNoRespawn := False;
-  FShellTimer := -1;
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
   FBehaviour := BH_NORMAL;
   FFireTime := 0;
   FFirePainTime := 0;
@@ -2218,25 +2227,35 @@ begin
 // Таймер - ждем после потери цели:
   FTargetTime := FTargetTime + 1;
 
-// Гильзы
+{$IFDEF ENABLE_SHELLS}
+  // Гильзы
   if FShellTimer > -1 then
+  begin
     if FShellTimer = 0 then
     begin
       if FShellType = SHELL_SHELL then
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+      begin
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX, GameVelY-2, SHELL_SHELL)
+      end
       else if FShellType = SHELL_DBLSHELL then
       begin
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX-1, GameVelY-2, SHELL_SHELL);
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX+1, GameVelY-2, SHELL_SHELL);
       end;
       FShellTimer := -1;
-    end else Dec(FShellTimer);
+    end
+    else
+    begin
+      Dec(FShellTimer);
+    end;
+  end;
+{$ENDIF}
 
 // Пробуем увернуться от летящей пули:
   if fall then
@@ -2917,20 +2936,26 @@ _end:
                   begin
                     g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', wx, wy);
                     g_Weapon_gun(wx, wy, tx, ty, 1, 3, FUID, True);
-                    g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+                    {$IFDEF ENABLE_SHELLS}
+                      g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+                    {$ENDIF}
                   end;
                 MONSTER_SERG:
                   begin
                     g_Weapon_shotgun(wx, wy, tx, ty, FUID);
                     if not gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', wx, wy);
-                    FShellTimer := 10;
-                    FShellType := SHELL_SHELL;
+                    {$IFDEF ENABLE_SHELLS}
+                      FShellTimer := 10;
+                      FShellType := SHELL_SHELL;
+                    {$ENDIF}
                   end;
                 MONSTER_MAN:
                   begin
                     g_Weapon_dshotgun(wx, wy, tx, ty, FUID);
-                    FShellTimer := 13;
-                    FShellType := SHELL_DBLSHELL;
+                    {$IFDEF ENABLE_SHELLS}
+                      FShellTimer := 13;
+                      FShellType := SHELL_DBLSHELL;
+                    {$ENDIF}
                     FAmmo := -36;
                   end;
                 MONSTER_CYBER:
@@ -2944,13 +2969,17 @@ _end:
                   begin
                     g_Weapon_mgun(wx, wy, tx, ty, FUID);
                     if not gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', wx, wy);
-                    g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+                    {$IFDEF ENABLE_SHELLS}
+                      g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+                    {$ENDIF}
                   end;
                 MONSTER_SPIDER:
                   begin
                     g_Weapon_mgun(wx, wy, tx, ty, FUID);
                     if not gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', wx, wy);
-                    g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
+                    {$IFDEF ENABLE_SHELLS}
+                      g_Shells_Create(wx, wy, 0, -2, SHELL_SHELL);
+                    {$ENDIF}
                   end;
                 MONSTER_BSP:
                   g_Weapon_aplasma(wx, wy, tx, ty, FUID);
@@ -3184,24 +3213,34 @@ begin
 // Таймер - ждем после потери цели:
   FTargetTime := FTargetTime + 1;
 
+{$IFDEF ENABLE_SHELLS}
   if FShellTimer > -1 then
+  begin
     if FShellTimer = 0 then
     begin
       if FShellType = SHELL_SHELL then
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+      begin
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX, GameVelY-2, SHELL_SHELL)
+      end
       else if FShellType = SHELL_DBLSHELL then
       begin
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX-1, GameVelY-2, SHELL_SHELL);
-        g_Player_CreateShell(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
+        g_Shells_Create(FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2),
                              FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2),
                              GameVelX+1, GameVelY-2, SHELL_SHELL);
       end;
       FShellTimer := -1;
-    end else Dec(FShellTimer);
+    end
+    else
+    begin
+      Dec(FShellTimer);
+    end;
+  end;
+{$ENDIF}
 
 // Пробуем увернуться от летящей пули:
   if fall then
@@ -3743,24 +3782,32 @@ begin
     MONSTER_ZOMBY:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', wx, wy);
-      g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+      {$ENDIF}
     end;
     MONSTER_SERG:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', wx, wy);
-      FShellTimer := 10;
-      FShellType := SHELL_SHELL;
+      {$IFDEF ENABLE_SHELLS}
+        FShellTimer := 10;
+        FShellType := SHELL_SHELL;
+      {$ENDIF}
     end;
     MONSTER_MAN:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', wx, wy);
-      FShellTimer := 13;
-      FShellType := SHELL_DBLSHELL;
+      {$IFDEF ENABLE_SHELLS}
+        FShellTimer := 13;
+        FShellType := SHELL_DBLSHELL;
+      {$ENDIF}
     end;
     MONSTER_CGUN, MONSTER_SPIDER:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', wx, wy);
-      g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+      {$ENDIF}
     end;
     MONSTER_IMP:
       g_Weapon_ball1(wx, wy, atx, aty, FUID);
index 02b6286b21cf406dab858542c3d73a6e13d0d3f3..39a4023d68a194a0eb30cc458f9572466a3383ed 100644 (file)
@@ -290,6 +290,9 @@ implementation
     {$IFDEF ENABLE_GFX}
       g_gfx,
     {$ENDIF}
+    {$IFDEF ENABLE_SHELLS}
+      g_shells,
+    {$ENDIF}
     Math, ENet, e_input, e_log, g_base, g_basic,
     g_textures, g_sound, g_console, g_options,
     g_game, g_player, g_map, g_panel, g_items, g_weapons, g_phys,
@@ -1792,16 +1795,22 @@ begin
     end;
     NET_GFX_SHELL1:
     begin
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_BULLET);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_BULLET);
+      {$ENDIF}
     end;
     NET_GFX_SHELL2:
     begin
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+      {$ENDIF}
     end;
     NET_GFX_SHELL3:
     begin
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+      {$ENDIF}
     end;
   end;
 end;
index 0358e4632ca2f4ce9915b4fa8fea12be7cc0da33..845d312917cb5a4f5b5977a11d09b12184dfe203 100644 (file)
@@ -130,6 +130,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   e_log, e_input, g_console, g_sound, g_player, Math,
   g_map, g_net, g_netmaster, SysUtils, CONFIG, g_game,
   g_items, wadreader, envvars;
@@ -285,7 +288,9 @@ begin
   {$IFDEF ENABLE_GFX}
     g_GFX_SetMax(2000);
   {$ENDIF}
-  g_Shells_SetMax(300);
+  {$IFDEF ENABLE_SHELLS}
+    g_Shells_SetMax(DefaultShellMax);
+  {$ENDIF}
   g_Corpses_SetMax(20);
   {$IFDEF ENABLE_GIBS}
     g_Gibs_SetMax(DefaultGibsMax);
index 11e20ede01852cf6982344fa0a2aa42cc1b092fa..55b8bfd0d1d8d7dcb8e88910dc9b519b5fb68d75 100644 (file)
@@ -77,10 +77,6 @@ const
   TEAM_BLUE         = 2;
   TEAM_COOP         = 3;
 
-  SHELL_BULLET      = 0;
-  SHELL_SHELL       = 1;
-  SHELL_DBLSHELL    = 2;
-
   ANGLE_NONE        = Low(SmallInt);
 
   CORPSE_STATE_REMOVEME = 0;
@@ -204,8 +200,10 @@ type
     FIncCamOld:      Integer;
     FIncCam:         Integer;
     FSlopeOld:       Integer;
-    FShellTimer:     Integer;
-    FShellType:      Byte;
+    {$IFDEF ENABLE_SHELLS}
+      FShellTimer:     Integer;
+      FShellType:      Byte;
+    {$ENDIF}
     FSawSound:       TPlayableSound;
     FSawSoundIdle:   TPlayableSound;
     FSawSoundHit:    TPlayableSound;
@@ -520,20 +518,6 @@ type
     procedure   LoadState (st: TStream); override;
   end;
 
-  PShell = ^TShell;
-  TShell = record
-    alive:    Boolean;
-    SType:    Byte;
-    RAngle:   Integer;
-    Timeout:  Cardinal;
-    Obj:      TObj;
-
-    procedure getMapBox (out x, y, w, h: Integer); inline;
-    procedure moveBy (dx, dy: Integer); inline;
-
-    procedure positionChanged ();  inline; //WARNING! call this after entity position was changed, or coldet will not work right!
-  end;
-
   TCorpse = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
   private
     FMess:          Boolean;
@@ -572,7 +556,6 @@ type
 var
   gPlayers: Array of TPlayer;
   gCorpses: Array of TCorpse;
-  gShells: Array of TShell;
   gTeamStat: TTeamStat;
   gFly: Boolean = False;
   gAimLine: Boolean = False;
@@ -584,7 +567,6 @@ var
   gSpectLatchPID2: Word = 0;
   MAX_RUNVEL: Integer = 8;
   VEL_JUMP: Integer = 10;
-  SHELL_TIMEOUT: Cardinal = 60000;
 
 function  Lerp(X, Y, Factor: Integer): Integer;
 
@@ -594,8 +576,6 @@ procedure g_Force_Model_Set(Mode: Word);
 function g_Force_Model_Get(): Word;
 procedure g_Forced_Model_SetName(Model: String);
 function  g_Forced_Model_GetName(): String;
-procedure g_Shells_SetMax(Count: Word);
-function  g_Shells_GetMax(): Word;
 
 procedure g_Player_Init();
 procedure g_Player_Free();
@@ -612,7 +592,6 @@ function  g_Player_GetCount(): Byte;
 function  g_Player_GetStats(): TPlayerStatArray;
 function  g_Player_ValidName(Name: String): Boolean;
 function  g_Player_CreateCorpse(Player: TPlayer): Integer;
-procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte);
 procedure g_Player_UpdatePhysicalObjects();
 procedure g_Player_RemoveAllCorpses();
 procedure g_Player_Corpses_SaveState (st: TStream);
@@ -642,6 +621,9 @@ uses
   {$IFDEF ENABLE_GIBS}
     g_gibs,
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    g_shells,
+  {$ENDIF}
   e_log, g_map, g_items, g_console, Math,
   g_options, g_triggers, g_game, g_grid, e_res,
   wadreader, g_monsters, CONFIG, g_language,
@@ -716,10 +698,8 @@ const
 
 var
   MaxCorpses: Word = 20;
-  MaxShells: Word = 300;
   ForceModel: Word = 0;
   ForcedModelName: String = STD_PLAYER_MODEL;
-  CurrentShell: Integer = 0;
   BotNames: Array of String;
   BotList: Array of TBotProfile;
   SavedStates: Array of TPlayerSavedState;
@@ -745,21 +725,6 @@ begin
   Result := g_Player_Get(UID1).FTeam = g_Player_Get(UID2).FTeam;
 end;
 
-procedure g_Shells_SetMax(Count: Word);
-begin
-  MaxShells := Count;
-  SetLength(gShells, Count);
-
-  if CurrentShell >= Count then
-    CurrentShell := 0;
-end;
-
-function g_Shells_GetMax(): Word;
-begin
-  Result := MaxShells;
-end;
-
-
 procedure g_Corpses_SetMax(Count: Word);
 begin
   MaxCorpses := Count;
@@ -1514,61 +1479,9 @@ begin
   end;
 end;
 
-procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte);
-begin
-  if (gShells = nil) or (Length(gShells) = 0) then
-    Exit;
-
-  with gShells[CurrentShell] do
-  begin
-    g_Obj_Init(@Obj);
-    Obj.Rect.X := 0;
-    Obj.Rect.Y := 0;
-    if T = SHELL_BULLET then
-    begin
-      Obj.Rect.Width := 4;
-      Obj.Rect.Height := 2;
-    end
-    else
-    begin
-      Obj.Rect.Width := 7;
-      Obj.Rect.Height := 3;
-    end;
-    SType := T;
-    alive := True;
-    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;
-
-    if CurrentShell >= High(gShells) then
-      CurrentShell := 0
-    else
-      Inc(CurrentShell);
-  end;
-end;
-
 procedure g_Player_UpdatePhysicalObjects();
-var
-  i: Integer;
-  vel: TPoint2i;
-  mr: Word;
-
-  procedure ShellSound_Bounce(X, Y: Integer; T: Byte);
-  var
-    k: Integer;
-  begin
-    k := 1 + Random(2);
-    if T = SHELL_BULLET then
-      g_Sound_PlayExAt('SOUND_PLAYER_CASING' + IntToStr(k), X, Y)
-    else
-      g_Sound_PlayExAt('SOUND_PLAYER_SHELL' + IntToStr(k), X, Y);
-  end;
-
+  var i: Integer;
 begin
-// Трупы:
   if gCorpses <> nil then
     for i := 0 to High(gCorpses) do
       if gCorpses[i] <> nil then
@@ -1579,94 +1492,21 @@ begin
           end
         else
           gCorpses[i].Update();
-
-// Гильзы:
-  if gShells <> nil then
-    for i := 0 to High(gShells) do
-      if gShells[i].alive then
-        with gShells[i] do
-        begin
-          Obj.oldX := Obj.X;
-          Obj.oldY := Obj.Y;
-
-          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
-            alive := False;
-            Continue;
-          end;
-
-        // Отлетает от удара о стену/потолок/пол:
-          if WordBool(mr and MOVE_HITWALL) then
-          begin
-            Obj.Vel.X := -(vel.X div 2);
-            if not WordBool(mr and MOVE_INWATER) then
-              ShellSound_Bounce(Obj.X, Obj.Y, SType);
-          end;
-          if WordBool(mr and (MOVE_HITCEIL or MOVE_HITLAND)) then
-          begin
-            Obj.Vel.Y := -(vel.Y div 2);
-            if Obj.Vel.X <> 0 then Obj.Vel.X := Obj.Vel.X div 2;
-            if (Obj.Vel.X = 0) and (Obj.Vel.Y = 0) then
-            begin
-              if RAngle mod 90 <> 0 then
-                RAngle := (RAngle div 90) * 90;
-            end
-            else if not WordBool(mr and MOVE_INWATER) then
-              ShellSound_Bounce(Obj.X, Obj.Y, SType);
-          end;
-
-          if (Obj.Vel.X >= 0) then
-          begin // Clockwise
-            RAngle := RAngle + Abs(Obj.Vel.X)*8 + Abs(Obj.Vel.Y);
-            if RAngle >= 360 then
-              RAngle := RAngle mod 360;
-          end else begin // Counter-clockwise
-            RAngle := RAngle - Abs(Obj.Vel.X)*8 - Abs(Obj.Vel.Y);
-            if RAngle < 0 then
-              RAngle := (360 - (Abs(RAngle) mod 360)) mod 360;
-          end;
-        end;
-end;
-
-procedure TShell.getMapBox (out x, y, w, h: Integer); inline;
-begin
-  x := Obj.X;
-  y := Obj.Y;
-  w := Obj.Rect.Width;
-  h := Obj.Rect.Height;
 end;
 
-procedure TShell.moveBy (dx, dy: Integer); inline;
-begin
-  if (dx <> 0) or (dy <> 0) then
-  begin
-    Obj.X += dx;
-    Obj.Y += dy;
-    positionChanged();
-  end;
-end;
-
-procedure TShell.positionChanged (); inline; begin end;
-
-
 procedure g_Player_RemoveAllCorpses();
   var i: Integer;
-  {$IFDEF ENABLE_GIBS}
-    var maxgibs: Integer;
-  {$ENDIF}
 begin
   {$IFDEF ENABLE_GIBS}
-    maxgibs := g_Gibs_GetMax();
+    i := g_Gibs_GetMax();
     g_Gibs_SetMax(0);
-    g_Gibs_SetMax(maxgibs);
+    g_Gibs_SetMax(i);
+  {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    i := g_Shells_GetMax();
+    g_Shells_SetMax(0);
+    g_Shells_SetMax(i);
   {$ENDIF}
-  gShells := nil;
-  SetLength(gShells, MaxShells);
-  CurrentShell := 0;
 
   if gCorpses <> nil then
     for i := 0 to High(gCorpses) do
@@ -1985,7 +1825,9 @@ begin
   FPing := 0;
   FLoss := 0;
   FSavedStateNum := -1;
-  FShellTimer := -1;
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
   FFireTime := 0;
   FFirePainTime := 0;
   FFireAttacker := 0;
@@ -2257,8 +2099,9 @@ begin
         FFireAngle := FAngle;
         f := True;
         DidFire := True;
-        g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_BULLET);
+        {$IFDEF ENABLE_SHELLS}
+          g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+        {$ENDIF}
       end;
 
     WEAPON_SHOTGUN1:
@@ -2271,8 +2114,10 @@ begin
         FFireAngle := FAngle;
         f := True;
         DidFire := True;
-        FShellTimer := 10;
-        FShellType := SHELL_SHELL;
+        {$IFDEF ENABLE_SHELLS}
+          FShellTimer := 10;
+          FShellType := SHELL_SHELL;
+        {$ENDIF}
       end;
 
     WEAPON_SHOTGUN2:
@@ -2284,8 +2129,10 @@ begin
         FFireAngle := FAngle;
         f := True;
         DidFire := True;
-        FShellTimer := 13;
-        FShellType := SHELL_DBLSHELL;
+        {$IFDEF ENABLE_SHELLS}
+          FShellTimer := 13;
+          FShellType := SHELL_DBLSHELL;
+        {$ENDIF}
       end;
 
     WEAPON_CHAINGUN:
@@ -2298,8 +2145,9 @@ begin
         FFireAngle := FAngle;
         f := True;
         DidFire := True;
-        g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_BULLET);
+        {$IFDEF ENABLE_SHELLS}
+          g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+        {$ENDIF}
       end;
 
     WEAPON_ROCKETLAUNCHER:
@@ -2344,8 +2192,9 @@ begin
         FFireAngle := FAngle;
         f := True;
         DidFire := True;
-        g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_SHELL);
+        {$IFDEF ENABLE_SHELLS}
+          g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_SHELL);
+        {$ENDIF}
       end;
 
     WEAPON_FLAMETHROWER:
@@ -2574,7 +2423,10 @@ begin
       FPhysics := True;
     FAlive := False;
   end;
-  FShellTimer := -1;
+
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
 
   if (gGameSettings.MaxLives > 0) and Srv and (gLMSRespawn = LMS_RESPAWN_NONE) then
   begin
@@ -3656,7 +3508,9 @@ begin
   FIncCamOld := 0;
   FIncCam := 0;
   FBFGFireCounter := -1;
-  FShellTimer := -1;
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
   FPain := 0;
   FLastHit := 0;
   FLastFrag := 0;
@@ -3739,7 +3593,9 @@ begin
   FIncCamOld := 0;
   FIncCam := 0;
   FBFGFireCounter := -1;
-  FShellTimer := -1;
+  {$IFDEF ENABLE_SHELLS}
+    FShellTimer := -1;
+  {$ENDIF}
   FPain := 0;
   FLastHit := 0;
   FSpawnInvul := 0;
@@ -4476,21 +4332,23 @@ begin
         else
           Dec(FReloading[b]);
 
+{$IFDEF ENABLE_SHELLS}
     if FShellTimer > -1 then
       if FShellTimer = 0 then
       begin
         if FShellType = SHELL_SHELL then
-          g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+          g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
                                GameVelX, GameVelY-2, SHELL_SHELL)
         else if FShellType = SHELL_DBLSHELL then
         begin
-          g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+          g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
                                GameVelX+1, GameVelY-2, SHELL_SHELL);
-          g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
+          g_Shells_Create(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
                                GameVelX-1, GameVelY-2, SHELL_SHELL);
         end;
         FShellTimer := -1;
       end else Dec(FShellTimer);
+{$ENDIF}
 
     if (FBFGFireCounter > -1) then
       if FBFGFireCounter = 0 then
@@ -4805,32 +4663,38 @@ begin
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', GameX, Gamey);
       FFireAngle := FAngle;
-      g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_BULLET);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+      {$ENDIF}
     end;
 
     WEAPON_SHOTGUN1:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey);
       FFireAngle := FAngle;
-      FShellTimer := 10;
-      FShellType := SHELL_SHELL;
+      {$IFDEF ENABLE_SHELLS}
+        FShellTimer := 10;
+        FShellType := SHELL_SHELL;
+      {$ENDIF}
     end;
 
     WEAPON_SHOTGUN2:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', Gamex, Gamey);
       FFireAngle := FAngle;
-      FShellTimer := 13;
-      FShellType := SHELL_DBLSHELL;
+      {$IFDEF ENABLE_SHELLS}
+        FShellTimer := 13;
+        FShellType := SHELL_DBLSHELL;
+      {$ENDIF}
     end;
 
     WEAPON_CHAINGUN:
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', Gamex, Gamey);
       FFireAngle := FAngle;
-      g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_BULLET);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_BULLET);
+      {$ENDIF}
     end;
 
     WEAPON_ROCKETLAUNCHER:
@@ -4855,8 +4719,9 @@ begin
     begin
       g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', Gamex, Gamey);
       FFireAngle := FAngle;
-      g_Player_CreateShell(GameX+PLAYER_RECT_CX, GameY+PLAYER_RECT_CX,
-                             GameVelX, GameVelY-2, SHELL_SHELL);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(GameX + PLAYER_RECT_CX, GameY + PLAYER_RECT_CX, GameVelX, GameVelY - 2, SHELL_SHELL);
+      {$ENDIF}
     end;
 
     WEAPON_FLAMETHROWER:
diff --git a/src/game/g_shells.pas b/src/game/g_shells.pas
new file mode 100644 (file)
index 0000000..de0fc86
--- /dev/null
@@ -0,0 +1,203 @@
+(* 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, version 3 of the License ONLY.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
+unit g_shells;
+
+interface
+
+  uses g_phys;
+
+  const
+    SHELL_BULLET   = 0;
+    SHELL_SHELL    = 1;
+    SHELL_DBLSHELL = 2;
+
+    DefaultShellTimeout = 60000;
+    DefaultShellMax = 300;
+
+  type
+    PShell = ^TShell;
+    TShell = record
+      alive:    Boolean;
+      SType:    Byte;
+      RAngle:   Integer;
+      Timeout:  Cardinal;
+      Obj:      TObj;
+
+      procedure getMapBox (out x, y, w, h: Integer); inline;
+      procedure moveBy (dx, dy: Integer); inline;
+
+      procedure positionChanged ();  inline; //WARNING! call this after entity position was changed, or coldet will not >
+    end;
+
+  var
+    gShells: Array of TShell;
+
+  procedure g_Shells_SetMax (Count: Word);
+  function g_Shells_GetMax (): Word;
+
+  procedure g_Shells_Create (fX, fY, dX, dY: Integer; T: Byte);
+  procedure g_Shells_Update;
+
+implementation
+
+  uses SysUtils, g_base, g_game, g_sound;
+
+  var
+    SHELL_TIMEOUT: Cardinal = DefaultShellTimeout;
+    MaxShells: Word = DefaultShellMax;
+    CurrentShell: Integer = 0;
+
+  procedure TShell.getMapBox (out x, y, w, h: Integer); inline;
+  begin
+    x := Obj.X;
+    y := Obj.Y;
+    w := Obj.Rect.Width;
+    h := Obj.Rect.Height;
+  end;
+
+  procedure TShell.moveBy (dx, dy: Integer); inline;
+  begin
+    if (dx <> 0) or (dy <> 0) then
+    begin
+      Obj.X += dx;
+      Obj.Y += dy;
+      positionChanged;
+    end;
+  end;
+
+  procedure TShell.positionChanged (); inline;
+  begin
+  end;
+
+  procedure g_Shells_SetMax (Count: Word);
+  begin
+    MaxShells := Count;
+    SetLength(gShells, Count);
+    if CurrentShell >= Count then
+      CurrentShell := 0;
+  end;
+
+  function g_Shells_GetMax (): Word;
+  begin
+    Result := MaxShells;
+  end;
+
+  procedure g_Shells_Create (fX, fY, dX, dY: Integer; T: Byte);
+  begin
+    if (gShells = nil) or (Length(gShells) = 0) then
+      Exit;
+
+    with gShells[CurrentShell] do
+    begin
+      g_Obj_Init(@Obj);
+      Obj.Rect.X := 0;
+      Obj.Rect.Y := 0;
+      if T = SHELL_BULLET then
+      begin
+        Obj.Rect.Width := 4;
+        Obj.Rect.Height := 2;
+      end
+      else
+      begin
+        Obj.Rect.Width := 7;
+        Obj.Rect.Height := 3;
+      end;
+      SType := T;
+      alive := True;
+      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;
+      if CurrentShell >= High(gShells) then
+        CurrentShell := 0
+      else
+        Inc(CurrentShell);
+    end;
+  end;
+
+  procedure g_Shells_SoundBounce(X, Y: Integer; T: Byte);
+    var k: Integer;
+  begin
+    k := 1 + Random(2);
+    if T = SHELL_BULLET then
+      g_Sound_PlayExAt('SOUND_PLAYER_CASING' + IntToStr(k), X, Y)
+    else
+      g_Sound_PlayExAt('SOUND_PLAYER_SHELL' + IntToStr(k), X, Y);
+  end;
+
+  procedure g_Shells_Update;
+    var i: Integer; vel: TPoint2i; mr: Word;
+  begin
+    if gShells = nil then
+      Exit;
+
+    for i := 0 to High(gShells) do
+    begin
+      if gShells[i].alive then
+      begin
+        with gShells[i] do
+        begin
+          Obj.oldX := Obj.X;
+          Obj.oldY := Obj.Y;
+
+          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
+            alive := False;
+            Continue;
+          end;
+
+        // Отлетает от удара о стену/потолок/пол:
+          if WordBool(mr and MOVE_HITWALL) then
+          begin
+            Obj.Vel.X := -(vel.X div 2);
+            if not WordBool(mr and MOVE_INWATER) then
+              g_Shells_SoundBounce(Obj.X, Obj.Y, SType);
+          end;
+          if WordBool(mr and (MOVE_HITCEIL or MOVE_HITLAND)) then
+          begin
+            Obj.Vel.Y := -(vel.Y div 2);
+            if Obj.Vel.X <> 0 then Obj.Vel.X := Obj.Vel.X div 2;
+            if (Obj.Vel.X = 0) and (Obj.Vel.Y = 0) then
+            begin
+              if RAngle mod 90 <> 0 then
+                RAngle := (RAngle div 90) * 90;
+            end
+            else if not WordBool(mr and MOVE_INWATER) then
+              g_Shells_SoundBounce(Obj.X, Obj.Y, SType);
+          end;
+
+          if (Obj.Vel.X >= 0) then
+          begin // Clockwise
+            RAngle := RAngle + Abs(Obj.Vel.X)*8 + Abs(Obj.Vel.Y);
+            if RAngle >= 360 then
+              RAngle := RAngle mod 360;
+          end else begin // Counter-clockwise
+            RAngle := RAngle - Abs(Obj.Vel.X)*8 - Abs(Obj.Vel.Y);
+            if RAngle < 0 then
+              RAngle := (360 - (Abs(RAngle) mod 360)) mod 360;
+          end;
+        end;
+      end;
+    end;
+  end;
+
+end.
index afbfc431e6a003680098ab0b511fde6edd295d35..1f4f86f73e577f5295d6c2aba8f94ea4614f2551 100644 (file)
@@ -105,6 +105,9 @@ implementation
     {$IFDEF ENABLE_GFX}
       g_gfx,
     {$ENDIF}
+    {$IFDEF ENABLE_SHELLS}
+      g_shells,
+    {$ENDIF}
     Math,
     g_player, g_map, g_panel, g_game,
     g_console, g_monsters, g_items, g_phys, g_weapons,
@@ -681,7 +684,9 @@ begin
         Projectile := False;
         if ShotSound then
         begin
-          g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+          {$IFDEF ENABLE_SHELLS}
+            g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+          {$ENDIF}
           if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
         end;
       end;
@@ -694,7 +699,9 @@ begin
         Projectile := False;
         if ShotSound then
         begin
-          g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
+          {$IFDEF ENABLE_SHELLS}
+            g_Shells_Create(wx, wy, 0, -2, SHELL_BULLET);
+          {$ENDIF}
           if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
         end;
       end;
@@ -706,7 +713,9 @@ begin
         Projectile := False;
         if ShotSound then
         begin
-          g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
+          {$IFDEF ENABLE_SHELLS}
+            g_Shells_Create(wx, wy, 0, -2, SHELL_SHELL);
+          {$ENDIF}
           if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2);
         end;
       end;
@@ -718,8 +727,10 @@ begin
         Projectile := False;
         if ShotSound then
         begin
-          g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
-          g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
+          {$IFDEF ENABLE_SHELLS}
+            g_Shells_Create(wx, wy, 0, -2, SHELL_SHELL);
+            g_Shells_Create(wx, wy, 0, -2, SHELL_SHELL);
+          {$ENDIF}
           if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3);
         end;
       end;
index fad2a697ad70ddf2df21060d7e26589e622f7b0b..692092e24f8a32d43413d697bb709c158df29b40 100644 (file)
@@ -1547,7 +1547,9 @@ begin
   drawPanelType('*step', PANEL_STEP, g_rlayer_step);
   drawOther('items', @r_Items_Draw);
   drawOther('weapons', @r_Weapon_Draw);
-  drawOther('shells', @r_Player_DrawShells);
+  {$IFDEF ENABLE_SHELLS}
+    drawOther('shells', @r_Player_DrawShells);
+  {$ENDIF}
   drawOther('drawall', @r_Player_DrawAll);
   {$IFDEF ENABLE_GIBS}
     drawOther('gibs', @r_PlayerModel_DrawGibs);
index 62f81929bb612497f77a7f3795afa4e794abc927..638674f32418583a32ee1e4c383391f79215818a 100644 (file)
@@ -27,7 +27,6 @@ interface
   procedure r_Player_DrawHealth;
 
   procedure r_Player_DrawCorpses;
-  procedure r_Player_DrawShells;
 
   procedure r_Player_Draw (p: TPlayer);
   procedure r_Player_DrawIndicator (p: TPlayer; Color: TRGB);
@@ -38,6 +37,10 @@ interface
   procedure r_Player_DrawPain (p: TPlayer);
   procedure r_Player_DrawPickup (p: TPlayer);
 
+  {$IFDEF ENABLE_SHELLS}
+    procedure r_Player_DrawShells;
+  {$ENDIF}
+
 implementation
 
   uses
@@ -47,6 +50,9 @@ implementation
     {$IFDEF ENABLE_MENU}
       g_menu,
     {$ENDIF}
+    {$IFDEF ENABLE_SHELLS}
+      g_shells,
+    {$ENDIF}
     SysUtils, Classes, Math,
     MAPDEF, utils,
     g_basic, g_game, g_phys, g_map, g_language, g_weapons, g_items, g_net, g_options,
@@ -149,6 +155,7 @@ end;
           r_Player_DrawCorpse(gCorpses[i])
   end;
 
+{$IFDEF ENABLE_SHELLS}
   procedure r_Player_DrawShells;
     var i, fX, fY: Integer; a: TDFPoint; TextureID: DWORD = DWORD(-1);
   begin
@@ -180,6 +187,7 @@ end;
       end
     end
   end;
+{$ENDIF}
 
 procedure r_Player_DrawIndicator (p: TPlayer; Color: TRGB);
 var
index 03de73281ab91ff675adc24ad920af04cd587356..91cd362a34605059014cddca02a203d096e2c8f6 100644 (file)
     {$UNDEF ENABLE_GIBS}
     {$DEFINE DISABLE_GIBS}
   {$ENDIF}
+  {$IFDEF ENABLE_SHELLS}
+    {$WARNING Shells in headless mode has no sense. Disabled.}
+    {$UNDEF ENABLE_SHELLS}
+    {$DEFINE DISABLE_SHELLS}
+  {$ENDIF}
 {$ENDIF}
 
 {$IF DEFINED(ENABLE_MENU) AND DEFINED(DISABLE_MENU)}
   {$ENDIF}
 {$ENDIF}
 
+{$IF DEFINED(ENABLE_SHELLS) AND DEFINED(DISABLE_SHELLS)}
+  {$ERROR Select ENABLE_SHELLS or DISABLE_SHELLS}
+{$ELSEIF NOT DEFINED(ENABLE_SHELLS) AND NOT DEFINED(DISABLE_SHELLS)}
+  // default ENABLE/DISABLE gibs
+  {$IFDEF HEADLESS}
+    {$DEFINE DISABLE_SHELLS}
+  {$ELSE}
+    {$DEFINE ENABLE_SHELLS}
+  {$ENDIF}
+{$ENDIF}
+
 {$IF DEFINED(USE_SYSSTUB)}
   {$IF DEFINED(USE_SDL) OR DEFINED(USE_SDL2)}
     {$ERROR Only one system driver must be selected!}