DEADSOFTWARE

Game: Use proper syntax of sets for game options instead of raw bitwise operations
[d2df-sdl.git] / src / game / g_game.pas
index 7b4ae2ee0fa1958759e5166850cc184cbdb7c344..824595b850be4297c8199295f4f1d7b8c9f73cc0 100644 (file)
@@ -25,6 +25,28 @@ uses
   g_touch, g_weapons;
 
 type
+  TGameOption = (
+    //RESERVED = 0,  // FIXME: reuse for something
+    TEAM_DAMAGE = 1,
+    ALLOW_EXIT,
+    WEAPONS_STAY,
+    MONSTERS,
+    BOTS_VS_PLAYERS,
+    BOTS_VS_MONSTERS,
+    DM_KEYS,
+    TEAM_HIT_TRACE,
+    TEAM_HIT_PROJECTILE,
+    TEAM_ABSORB_DAMAGE,
+    ALLOW_DROP_FLAG,
+    THROW_FLAG,
+    POWERUP_RANDOM,
+    ITEM_ALL_RANDOM,
+    ITEM_LIFE_RANDOM,
+    ITEM_AMMO_RANDOM,
+    ITEM_WEAPON_RANDOM
+  );
+  TGameOptions = set of TGameOption;
+
   TGameSettings = record
     GameType: Byte;
     GameMode: Byte;
@@ -33,8 +55,11 @@ type
     WarmupTime: Word;
     SpawnInvul: Word;
     ItemRespawnTime: Word;
+    ItemRespawnRandom: Word;
+    PowerupRespawnTime: Word;
+    PowerupRespawnRandom: Word;
     MaxLives: Byte;
-    Options: LongWord;
+    Options: TGameOptions;
     WAD: String;
   end;
 
@@ -66,7 +91,7 @@ type
     WeaponSwitch: Byte;
     WeaponPreferences: Array[WP_FIRST..WP_LAST+1] of Byte;
     SwitchToEmpty: Byte;
-    SkipFist: Byte;
+    SkipIronFist: Byte;
   end;
 
   TMegaWADInfo = record
@@ -103,8 +128,8 @@ procedure g_Game_RemovePlayer();
 procedure g_Game_Spectate();
 procedure g_Game_SpectateCenterView();
 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
-procedure g_Game_StartCustom(Map: String; GameMode: Byte; TimeLimit, ScoreLimit: Word; MaxLives: Byte; Options: LongWord; nPlayers: Byte);
-procedure g_Game_StartServer(Map: String; GameMode: Byte; TimeLimit, ScoreLimit: Word; MaxLives: Byte; Options: LongWord; nPlayers: Byte; IPAddr: LongWord; Port: Word);
+procedure g_Game_StartCustom(Map: String; GameMode: Byte; TimeLimit, ScoreLimit: Word; MaxLives: Byte; Options: TGameOptions; nPlayers: Byte);
+procedure g_Game_StartServer(Map: String; GameMode: Byte; TimeLimit, ScoreLimit: Word; MaxLives: Byte; Options: TGameOptions; nPlayers: Byte; IPAddr: LongWord; Port: Word);
 procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
 procedure g_Game_Restart();
 procedure g_Game_RestartLevel();
@@ -131,6 +156,7 @@ 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_Effect_Bubbles(fX, fY: Integer; count: Word; devX, devY: Byte; Silent: Boolean = False);
 procedure g_Game_StartVote(Command, Initiator: string);
 procedure g_Game_CheckVote;
 procedure g_TakeScreenShot(Filename: string = '');
@@ -181,20 +207,6 @@ const
   EXIT_ENDLEVELSINGLE  = 4;
   EXIT_ENDLEVELCUSTOM  = 5;
 
-  GAME_OPTION_RESERVED          = 1;
-  GAME_OPTION_TEAMDAMAGE        = 2;
-  GAME_OPTION_ALLOWEXIT         = 4;
-  GAME_OPTION_WEAPONSTAY        = 8;
-  GAME_OPTION_MONSTERS          = 16;
-  GAME_OPTION_BOTVSPLAYER       = 32;
-  GAME_OPTION_BOTVSMONSTER      = 64;
-  GAME_OPTION_DMKEYS            = 128;
-  GAME_OPTION_TEAMHITTRACE      = 256;
-  GAME_OPTION_TEAMHITPROJECTILE = 512;
-  GAME_OPTION_TEAMABSORBDAMAGE  = 1024;
-  GAME_OPTION_ALLOWDROPFLAG     = 2048;
-  GAME_OPTION_THROWFLAG         = 4096;
-
   STATE_NONE        = 0;
   STATE_MENU        = 1;
   STATE_FOLD        = 2;
@@ -667,9 +679,10 @@ end;
 
 // saves a shitty CSV containing the game stats passed to it
 procedure SaveGameStat(Stat: TEndCustomGameStat; Path: string);
-var 
+var
   s: TextFile;
-  dir, fname, map, mode, etime: String;
+  dir, fname, map, mode, etime, flags, strf: String;
+  flag: TGameOption;
   I: Integer;
 begin
   try
@@ -691,8 +704,17 @@ begin
         (Stat.GameTime div 1000 div 60) mod 60,
         Stat.GameTime div 1000 mod 60
       ]);
+      flags := '';
+      strf := '';
+      for flag in gGameSettings.Options do
+      begin
+        flags += strf;
+        System.WriteStr(strf, flag);  // FIXME: rename our utils.WriteStr()
+        flags += strf;
+        strf := ', ';
+      end;
       WriteLn(s, 'stats_ver,datetime,server,map,mode,timelimit,scorelimit,dmflags,time,num_players');
-      WriteLn(s, Format('%d,%s,%s,%s,%s,%u,%u,%u,%s,%d', [
+      WriteLn(s, Format('%d,%s,%s,%s,%s,%u,%u,"%s",%s,%d', [
         STATFILE_VERSION,
         StatDate,
         dquoteStr(fname),
@@ -700,7 +722,7 @@ begin
         mode,
         gGameSettings.TimeLimit,
         gGameSettings.ScoreLimit,
-        gGameSettings.Options,
+        flags,
         etime,
         Length(Stat.PlayerStat)
       ]));
@@ -709,7 +731,7 @@ begin
       //   if it's a coop game: monsters killed, monsters total, secrets found, secrets total
       //   otherwise nothing
       if Stat.GameMode in [GM_TDM, GM_CTF] then
-        WriteLn(s, 
+        WriteLn(s,
           Format('red_score,blue_score' + LineEnding + '%d,%d', [Stat.TeamStat[TEAM_RED].Score, Stat.TeamStat[TEAM_BLUE].Score]))
       else if Stat.GameMode in [GM_COOP, GM_SINGLE] then
         WriteLn(s,
@@ -728,6 +750,17 @@ begin
   CloseFile(s);
 end;
 
+procedure ClearDebugCvars();
+begin
+  g_debug_Sounds := False;
+  g_debug_Frames := False;
+  g_debug_WinMsgs := False;
+  g_debug_MonsterOff := False;
+  g_debug_BotAIOff := 0;
+  g_debug_HealthBar := False;
+  g_Debug_Player := False;
+end;
+
 function g_Game_ModeToText(Mode: Byte): string;
 begin
   Result := '';
@@ -3853,7 +3886,7 @@ begin
 
   p.DrawPain();
   p.DrawPickup();
-  p.DrawRulez();
+  p.DrawOverlay();
   if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128));
   if g_Debug_Player then
     g_Player_DrawDebug(p);
@@ -3865,9 +3898,20 @@ var
   px: Integer = -1;
   py: Integer = -1;
 begin
-  if g_profile_frame_draw and (profileFrameDraw <> nil) then px := px-drawProfiles(px, py, profileFrameDraw);
-  if g_profile_collision and (profMapCollision <> nil) then begin px := px-drawProfiles(px, py, profMapCollision); py -= calcProfilesHeight(profMonsLOS); end;
-  if g_profile_los and (profMonsLOS <> nil) then begin px := px-drawProfiles(px, py, profMonsLOS); py -= calcProfilesHeight(profMonsLOS); end;
+  if g_profile_frame_draw and (profileFrameDraw <> nil) then
+    px -= drawProfiles(px, py, profileFrameDraw);
+
+  if g_profile_collision and (profMapCollision <> nil) then
+  begin
+    px -= drawProfiles(px, py, profMapCollision);
+    py -= calcProfilesHeight(profMonsLOS);
+  end;
+
+  if g_profile_los and (profMonsLOS <> nil) then
+  begin
+    px -= drawProfiles(px, py, profMonsLOS);
+    py -= calcProfilesHeight(profMonsLOS);
+  end;
 end;
 
 procedure g_Game_Draw();
@@ -4356,7 +4400,7 @@ begin
       gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
       gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
       gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
-      gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
+      gPlayer1.SkipIronFist := gPlayer1Settings.SkipIronFist;
       g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer1.Name]), True);
       if g_Game_IsServer and g_Game_IsNet then
         MH_SEND_PlayerCreate(gPlayer1.UID);
@@ -4390,7 +4434,7 @@ begin
       gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
       gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
       gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
-      gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
+      gPlayer2.SkipIronFist := gPlayer2Settings.SkipIronFist;
       g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer2.Name]), True);
       if g_Game_IsServer and g_Game_IsNet then
         MH_SEND_PlayerCreate(gPlayer2.UID);
@@ -4473,16 +4517,15 @@ begin
   g_Game_ClearLoading();
 
 // Íàñòðîéêè èãðû:
-  FillByte(gGameSettings, SizeOf(TGameSettings), 0);
+  gGameSettings := Default(TGameSettings);
   gAimLine := False;
   gShowMap := False;
   gGameSettings.GameType := GT_SINGLE;
   gGameSettings.MaxLives := 0;
-  gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT;
-  gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS;
-  gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER;
-  gGameSettings.Options := gGameSettings.Options + GAME_OPTION_TEAMHITPROJECTILE;
-  gGameSettings.Options := gGameSettings.Options + GAME_OPTION_TEAMHITTRACE;
+  gGameSettings.Options := [TGameOption.ALLOW_EXIT, TGameOption.MONSTERS,
+    TGameOption.BOTS_VS_MONSTERS, TGameOption.TEAM_HIT_PROJECTILE, TGameOption.TEAM_HIT_TRACE,
+    TGameOption.POWERUP_RANDOM, TGameOption.ITEM_ALL_RANDOM, TGameOption.ITEM_LIFE_RANDOM,
+    TGameOption.ITEM_AMMO_RANDOM, TGameOption.ITEM_WEAPON_RANDOM];
   gSwitchGameMode := GM_SINGLE;
 
   gLMSRespawn := LMS_RESPAWN_NONE;
@@ -4509,7 +4552,7 @@ begin
   gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
   gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
   gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
-  gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
+  gPlayer1.SkipIronFist := gPlayer1Settings.SkipIronFist;
   nPl := 1;
 
 // Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü:
@@ -4528,7 +4571,7 @@ begin
     gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
     gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
     gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
-    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
+    gPlayer2.SkipIronFist := gPlayer2Settings.SkipIronFist;
     Inc(nPl);
   end;
 
@@ -4551,7 +4594,7 @@ end;
 procedure g_Game_StartCustom(Map: String; GameMode: Byte;
                              TimeLimit, ScoreLimit: Word;
                              MaxLives: Byte;
-                             Options: LongWord; nPlayers: Byte);
+                             Options: TGameOptions; nPlayers: Byte);
 var
   i, nPl: Integer;
 begin
@@ -4611,7 +4654,7 @@ begin
     gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
     gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
     gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
-    gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
+    gPlayer1.SkipIronFist := gPlayer1Settings.SkipIronFist;
     Inc(nPl);
   end;
 
@@ -4631,7 +4674,7 @@ begin
     gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
     gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
     gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
-    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
+    gPlayer2.SkipIronFist := gPlayer2Settings.SkipIronFist;
     Inc(nPl);
   end;
 
@@ -4663,7 +4706,7 @@ end;
 
 procedure g_Game_StartServer(Map: String; GameMode: Byte;
                              TimeLimit, ScoreLimit: Word; MaxLives: Byte;
-                             Options: LongWord; nPlayers: Byte;
+                             Options: TGameOptions; nPlayers: Byte;
                              IPAddr: LongWord; Port: Word);
 begin
   g_Game_Free();
@@ -4673,6 +4716,8 @@ begin
 
   g_Game_ClearLoading();
 
+  ClearDebugCvars();
+
 // Íàñòðîéêè èãðû:
   gGameSettings.GameType := GT_SERVER;
   gGameSettings.GameMode := GameMode;
@@ -4722,7 +4767,7 @@ begin
     gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
     gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
     gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
-    gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
+    gPlayer1.SkipIronFist := gPlayer1Settings.SkipIronFist;
   end;
 
   if nPlayers >= 2 then
@@ -4741,7 +4786,7 @@ begin
     gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
     gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
     gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
-    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
+    gPlayer2.SkipIronFist := gPlayer2Settings.SkipIronFist;
   end;
 
   g_Game_SetLoadingText(_lc[I_LOAD_HOST], 0, False);
@@ -4806,6 +4851,8 @@ begin
 
   g_Game_ClearLoading();
 
+  ClearDebugCvars();
+
 // Íàñòðîéêè èãðû:
   gGameSettings.GameType := GT_CLIENT;
 
@@ -4880,7 +4927,7 @@ begin
           gGameSettings.ScoreLimit := InMsg.ReadWord();
           gGameSettings.TimeLimit := InMsg.ReadWord();
           gGameSettings.MaxLives := InMsg.ReadByte();
-          gGameSettings.Options := InMsg.ReadLongWord();
+          gGameSettings.Options := TGameOptions(InMsg.ReadLongWord());
           T := InMsg.ReadLongWord();
 
           //newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
@@ -4917,7 +4964,7 @@ begin
           gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
           gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
           gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
-          gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
+          gPlayer1.SkipIronFist := gPlayer1Settings.SkipIronFist;
           gPlayer1.UID := NetPlrUID1;
           gPlayer1.Reset(True);
 
@@ -5179,7 +5226,7 @@ begin
           end;
         end;
 
-    g_Net_UnbanNonPermHosts();
+    g_Net_UnbanNonPerm();
   end;
 
   if gLastMap then
@@ -5366,7 +5413,7 @@ begin
     if gGameSettings.GameMode = GM_COOP then
     begin
       gPlayers[i].Frags := 0;
-      gPlayers[i].RecallState;
+      gPlayers[i].RestoreState;
     end;
     if (gPlayer1 = nil) and (gSpectLatchPID1 > 0) then
       gPlayer1 := g_Player_Get(gSpectLatchPID1);
@@ -5515,34 +5562,34 @@ var
   a, b: Integer;
   stat: TPlayerStatArray;
   cmd: string;
+  it: PItem;
 
-  procedure ParseGameFlag(Flag: LongWord; OffMsg, OnMsg: TStrings_Locale; OnMapChange: Boolean = False);
+  procedure ParseGameFlag(Flag: TGameOption; OffMsg, OnMsg: TStrings_Locale; OnMapChange: Boolean = False);
   var
     x: Boolean;
   begin
-    if Length(P) > 1 then
+    if Length(P) <= 1 then
+      x := Flag in gsGameFlags
+    else
     begin
       x := P[1] = '1';
 
-      if x then
-        gsGameFlags := gsGameFlags or Flag
-      else
-        gsGameFlags := gsGameFlags and (not Flag);
+      if x
+        then gsGameFlags += [Flag]
+        else gsGameFlags -= [Flag];
 
       if g_Game_IsServer then
       begin
-        if x then
-          gGameSettings.Options := gGameSettings.Options or Flag
-        else
-          gGameSettings.Options := gGameSettings.Options and (not Flag);
+        if x
+          then gGameSettings.Options += [Flag]
+          else gGameSettings.Options -= [Flag];
         if g_Game_IsNet then MH_SEND_GameSettings;
       end;
     end;
 
-    if LongBool(gsGameFlags and Flag) then
-      g_Console_Add(_lc[OnMsg])
-    else
-      g_Console_Add(_lc[OffMsg]);
+    if x
+      then g_Console_Add(_lc[OnMsg])
+      else g_Console_Add(_lc[OffMsg]);
 
     if OnMapChange and g_Game_IsServer then
       g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
@@ -5552,310 +5599,371 @@ begin
   stat := nil;
   cmd := LowerCase(P[0]);
 
-  if cmd = 'g_gamemode' then
-  begin
-    if (Length(P) > 1) then
-    begin
-      a := g_Game_TextToMode(P[1]);
-      if a = GM_SINGLE then a := GM_COOP;
-      gsGameMode := g_Game_ModeToText(a);
-      if g_Game_IsServer then
+  case cmd of
+    'g_gamemode': begin
+      if (Length(P) > 1) then
       begin
-        gSwitchGameMode := a;
-        if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
-           (gState = STATE_INTERSINGLE) then
-          gSwitchGameMode := GM_SINGLE;
-        if not gGameOn then
-          gGameSettings.GameMode := gSwitchGameMode;
+        a := g_Game_TextToMode(P[1]);
+        if a = GM_SINGLE then a := GM_COOP;
+        gsGameMode := g_Game_ModeToText(a);
+        if g_Game_IsServer then
+        begin
+          gSwitchGameMode := a;
+          if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
+             (gState = STATE_INTERSINGLE) then
+            gSwitchGameMode := GM_SINGLE;
+          if not gGameOn then
+            gGameSettings.GameMode := gSwitchGameMode;
+        end;
       end;
+
+      if gSwitchGameMode = gGameSettings.GameMode then
+        g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
+                            [g_Game_ModeToText(gGameSettings.GameMode)]))
+      else
+        g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
+                            [g_Game_ModeToText(gGameSettings.GameMode),
+                             g_Game_ModeToText(gSwitchGameMode)]));
     end;
 
-    if gSwitchGameMode = gGameSettings.GameMode then
-      g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
-                          [g_Game_ModeToText(gGameSettings.GameMode)]))
-    else
-      g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
-                          [g_Game_ModeToText(gGameSettings.GameMode),
-                           g_Game_ModeToText(gSwitchGameMode)]));
-  end
-  else if cmd = 'g_friendlyfire' then
-  begin
-    ParseGameFlag(GAME_OPTION_TEAMDAMAGE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON);
-  end
-  else if cmd = 'g_friendly_absorb_damage' then
-  begin
-    ParseGameFlag(GAME_OPTION_TEAMABSORBDAMAGE, I_MSG_FRIENDLY_ABSORB_DAMAGE_OFF, I_MSG_FRIENDLY_ABSORB_DAMAGE_ON);
-  end
-  else if cmd = 'g_friendly_hit_trace' then
-  begin
-    ParseGameFlag(GAME_OPTION_TEAMHITTRACE, I_MSG_FRIENDLY_HIT_TRACE_OFF, I_MSG_FRIENDLY_HIT_TRACE_ON);
-  end
-  else if cmd = 'g_friendly_hit_projectile' then
-  begin
-    ParseGameFlag(GAME_OPTION_TEAMHITPROJECTILE, I_MSG_FRIENDLY_PROJECT_TRACE_OFF, I_MSG_FRIENDLY_PROJECT_TRACE_ON);
-  end
-  else if cmd = 'g_weaponstay' then
-  begin
-    ParseGameFlag(GAME_OPTION_WEAPONSTAY, I_MSG_WEAPONSTAY_OFF, I_MSG_WEAPONSTAY_ON);
-  end
-  else if cmd = 'g_allow_exit' then
-  begin
-    ParseGameFlag(GAME_OPTION_ALLOWEXIT, I_MSG_ALLOWEXIT_OFF, I_MSG_ALLOWEXIT_ON, True);
-  end
-  else if cmd = 'g_allow_monsters' then
-  begin
-    ParseGameFlag(GAME_OPTION_MONSTERS, I_MSG_ALLOWMON_OFF, I_MSG_ALLOWMON_ON, True);
-  end
-  else if cmd = 'g_allow_dropflag' then
-  begin
-    ParseGameFlag(GAME_OPTION_ALLOWDROPFLAG, I_MSG_ALLOWDROPFLAG_OFF, I_MSG_ALLOWDROPFLAG_ON);
-  end
-  else if cmd = 'g_throw_flag' then
-  begin
-    ParseGameFlag(GAME_OPTION_THROWFLAG, I_MSG_THROWFLAG_OFF, I_MSG_THROWFLAG_ON);
-  end
-  else if cmd = 'g_bot_vsplayers' then
-  begin
-    ParseGameFlag(GAME_OPTION_BOTVSPLAYER, I_MSG_BOTSVSPLAYERS_OFF, I_MSG_BOTSVSPLAYERS_ON);
-  end
-  else if cmd = 'g_bot_vsmonsters' then
-  begin
-    ParseGameFlag(GAME_OPTION_BOTVSMONSTER, I_MSG_BOTSVSMONSTERS_OFF, I_MSG_BOTSVSMONSTERS_ON);
-  end
-  else if cmd = 'g_dm_keys' then
-  begin
-    ParseGameFlag(GAME_OPTION_DMKEYS, I_MSG_DMKEYS_OFF, I_MSG_DMKEYS_ON, True);
-  end
-  else if cmd = 'g_gameflags' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsGameFlags := StrToDWordDef(P[1], gsGameFlags);
-      if g_Game_IsServer then
+    'g_friendlyfire':
+      ParseGameFlag(TGameOption.TEAM_DAMAGE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON);
+    'g_friendly_absorb_damage':
+      ParseGameFlag(TGameOption.TEAM_ABSORB_DAMAGE, I_MSG_FRIENDLY_ABSORB_DAMAGE_OFF, I_MSG_FRIENDLY_ABSORB_DAMAGE_ON);
+    'g_friendly_hit_trace':
+      ParseGameFlag(TGameOption.TEAM_HIT_TRACE, I_MSG_FRIENDLY_HIT_TRACE_OFF, I_MSG_FRIENDLY_HIT_TRACE_ON);
+    'g_friendly_hit_projectile':
+      ParseGameFlag(TGameOption.TEAM_HIT_PROJECTILE, I_MSG_FRIENDLY_PROJECT_TRACE_OFF, I_MSG_FRIENDLY_PROJECT_TRACE_ON);
+    'g_items_all_respawn_random':
+      ParseGameFlag(TGameOption.ITEM_ALL_RANDOM, I_MSG_ITEM_ALL_RANDOM_OFF, I_MSG_ITEM_ALL_RANDOM_ON, False);
+    'g_items_help_respawn_random':
+      ParseGameFlag(TGameOption.ITEM_LIFE_RANDOM, I_MSG_ITEM_LIFE_RANDOM_OFF, I_MSG_ITEM_LIFE_RANDOM_ON, False);
+    'g_items_ammo_respawn_random':
+      ParseGameFlag(TGameOption.ITEM_AMMO_RANDOM, I_MSG_ITEM_AMMO_RANDOM_OFF, I_MSG_ITEM_AMMO_RANDOM_ON, False);
+    'g_items_weapon_respawn_random':
+      ParseGameFlag(TGameOption.ITEM_WEAPON_RANDOM, I_MSG_ITEM_WEAPON_RANDOM_OFF, I_MSG_ITEM_WEAPON_RANDOM_ON);
+    'g_powerup_randomize_respawn':
+      ParseGameFlag(TGameOption.POWERUP_RANDOM, I_MSG_POWERUP_RANDOM_OFF, I_MSG_POWERUP_RANDOM_ON, False);
+    'g_weaponstay':
+      ParseGameFlag(TGameOption.WEAPONS_STAY, I_MSG_WEAPONSTAY_OFF, I_MSG_WEAPONSTAY_ON);
+    'g_allow_exit':
+      ParseGameFlag(TGameOption.ALLOW_EXIT, I_MSG_ALLOWEXIT_OFF, I_MSG_ALLOWEXIT_ON, True);
+    'g_allow_monsters':
+      ParseGameFlag(TGameOption.MONSTERS, I_MSG_ALLOWMON_OFF, I_MSG_ALLOWMON_ON, True);
+    'g_allow_dropflag':
+      ParseGameFlag(TGameOption.ALLOW_DROP_FLAG, I_MSG_ALLOWDROPFLAG_OFF, I_MSG_ALLOWDROPFLAG_ON);
+    'g_throw_flag':
+      ParseGameFlag(TGameOption.THROW_FLAG, I_MSG_THROWFLAG_OFF, I_MSG_THROWFLAG_ON);
+    'g_bot_vsplayers':
+      ParseGameFlag(TGameOption.BOTS_VS_PLAYERS, I_MSG_BOTSVSPLAYERS_OFF, I_MSG_BOTSVSPLAYERS_ON);
+    'g_bot_vsmonsters':
+      ParseGameFlag(TGameOption.BOTS_VS_MONSTERS, I_MSG_BOTSVSMONSTERS_OFF, I_MSG_BOTSVSMONSTERS_ON);
+    'g_dm_keys':
+      ParseGameFlag(TGameOption.DM_KEYS, I_MSG_DMKEYS_OFF, I_MSG_DMKEYS_ON, True);
+
+    'g_gameflags': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.Options := gsGameFlags;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+        gsGameFlags := TGameOptions(StrToDWordDef(P[1], LongWord(gsGameFlags)));
+        if g_Game_IsServer then
+        begin
+          gGameSettings.Options := gsGameFlags;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
+
+      g_Console_Add(Format('%s %u', [cmd, LongWord(gsGameFlags)]));
     end;
 
-    g_Console_Add(Format('%s %u', [cmd, gsGameFlags]));
-  end
-  else if cmd = 'g_warmup_time' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsWarmupTime := nclamp(StrToIntDef(P[1], gsWarmupTime), 0, $FFFF);
-      if g_Game_IsServer then
+    'g_warmup_time': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.WarmupTime := gsWarmupTime;
-        // extend warmup if it's already going
-        if gLMSRespawn = LMS_RESPAWN_WARMUP then
+        gsWarmupTime := nclamp(StrToIntDef(P[1], gsWarmupTime), 0, $FFFF);
+        if g_Game_IsServer then
         begin
-          gLMSRespawnTime := gTime + gsWarmupTime * 1000;
-          if g_Game_IsNet then MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime);
+          gGameSettings.WarmupTime := gsWarmupTime;
+          // extend warmup if it's already going
+          if gLMSRespawn = LMS_RESPAWN_WARMUP then
+          begin
+            gLMSRespawnTime := gTime + gsWarmupTime * 1000;
+            if g_Game_IsNet then MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime);
+          end;
+          if g_Game_IsNet then MH_SEND_GameSettings;
         end;
-        if g_Game_IsNet then MH_SEND_GameSettings;
       end;
+
+      g_Console_Add(Format(_lc[I_MSG_WARMUP], [Integer(gsWarmupTime)]));
+      if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
     end;
 
-    g_Console_Add(Format(_lc[I_MSG_WARMUP], [Integer(gsWarmupTime)]));
-    if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
-  end
-  else if cmd = 'g_spawn_invul' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsSpawnInvul := nclamp(StrToIntDef(P[1], gsSpawnInvul), 0, $FFFF);
-      if g_Game_IsServer then
+    'g_spawn_invul': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.SpawnInvul := gsSpawnInvul;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+        gsSpawnInvul := nclamp(StrToIntDef(P[1], gsSpawnInvul), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.SpawnInvul := gsSpawnInvul;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
+
+      g_Console_Add(Format('%s %d', [cmd, Integer(gsSpawnInvul)]));
     end;
 
-    g_Console_Add(Format('%s %d', [cmd, Integer(gsSpawnInvul)]));
-  end
-  else if cmd = 'g_item_respawn_time' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsItemRespawnTime := nclamp(StrToIntDef(P[1], gsItemRespawnTime), 0, $FFFF);
-      if g_Game_IsServer then
+    'g_item_respawn_time': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.ItemRespawnTime := gsItemRespawnTime;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+        gsItemRespawnTime := nclamp(StrToIntDef(P[1], gsItemRespawnTime), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.ItemRespawnTime := gsItemRespawnTime;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
+
+      g_Console_Add(Format('%s %d', [cmd, Integer(gsItemRespawnTime)]));
+      if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
     end;
 
-    g_Console_Add(Format('%s %d', [cmd, Integer(gsItemRespawnTime)]));
-    if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
-  end
-  else if cmd = 'sv_intertime' then
-  begin
-    if (Length(P) > 1) then
-      gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
+    'g_item_time_random': begin
+      if Length(P) > 1 then
+      begin
+        gsItemRespawnRandom := nclamp(StrToIntDef(P[1], gsItemRespawnRandom), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.ItemRespawnRandom := gsItemRespawnRandom;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
+      end;
 
-    g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
-  end
-  else if cmd = 'g_max_particles' then
-  begin
-    if Length(p) = 2 then
-    begin
-      a := Max(0, StrToIntDef(p[1], 0));
-      g_GFX_SetMax(a)
-    end
-    else if Length(p) = 1 then
-    begin
-      e_LogWritefln('%s', [g_GFX_GetMax()])
-    end
-    else
-    begin
-      e_LogWritefln('usage: %s <n>', [cmd])
-    end
-  end
-  else if cmd = 'g_max_shells' then
-  begin
-    if Length(p) = 2 then
-    begin
-      a := Max(0, StrToIntDef(p[1], 0));
-      g_Shells_SetMax(a)
-    end
-    else if Length(p) = 1 then
-    begin
-      e_LogWritefln('%s', [g_Shells_GetMax()])
-    end
-    else
-    begin
-      e_LogWritefln('usage: %s <n>', [cmd])
-    end
-  end
-  else if cmd = 'g_max_gibs' then
-  begin
-    if Length(p) = 2 then
-    begin
-      a := Max(0, StrToIntDef(p[1], 0));
-      g_Gibs_SetMax(a)
-    end
-    else if Length(p) = 1 then
-    begin
-      e_LogWritefln('%s', [g_Gibs_GetMax()])
-    end
-    else
-    begin
-      e_LogWritefln('usage: %s <n>', [cmd])
-    end
-  end
-  else if cmd = 'g_max_corpses' then
-  begin
-    if Length(p) = 2 then
-    begin
-      a := Max(0, StrToIntDef(p[1], 0));
-      g_Corpses_SetMax(a)
-    end
-    else if Length(p) = 1 then
-    begin
-      e_LogWritefln('%s', [g_Corpses_GetMax()])
-    end
-    else
-    begin
-      e_LogWritefln('usage: %s <n>', [cmd])
-    end
-  end
-  else if cmd = 'g_force_model' then
-  begin
-    if Length(p) = 2 then
-    begin
-      a := StrToIntDef(p[1], 0);
-      g_Force_Model_Set(a);
-    end
-  end
-  else if cmd = 'g_force_model_name' then
-  begin
-    if (Length(P) > 1) then
-    begin
-      cmd := b_Text_Unformat(P[1]);
-      g_Forced_Model_SetName(cmd);
-      if (gGameSettings.GameType <> GT_SINGLE) and (g_Force_Model_Get() <> 0) and (gPlayers <> nil) then
+      g_Console_Add(Format('%s %d', [cmd, Integer(gsItemRespawnRandom)]));
+      if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
+    end;
+
+    'g_powerup_respawn_time': begin
+      if Length(P) > 1 then
       begin
-        for a := Low(gPlayers) to High(gPlayers) do
+        gsPowerupRespawnTime := nclamp(StrToIntDef(P[1], gsPowerupRespawnTime), 0, $FFFF);
+        if g_Game_IsServer then
         begin
-          if (gPlayers[a] <> nil) then
+          gGameSettings.PowerupRespawnTime := gsPowerupRespawnTime;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
+      end;
+
+      g_Console_Add(Format('%s %d', [cmd, Integer(gsPowerupRespawnTime)]));
+      if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
+    end;
+
+    'g_powerup_time_random': begin
+      if Length(P) > 1 then
+      begin
+        gsPowerupRespawnRandom := nclamp(StrToIntDef(P[1], gsPowerupRespawnRandom), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.PowerupRespawnRandom := gsPowerupRespawnRandom;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
+      end;
+
+      g_Console_Add(Format('%s %d', [cmd, Integer(gsPowerupRespawnRandom)]));
+      if g_Game_IsServer then g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
+    end;
+
+    'sv_intertime': begin
+      if (Length(P) > 1) then
+        gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
+
+      g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
+    end;
+
+    'g_max_particles': begin
+      if Length(p) = 2 then
+      begin
+        a := Max(0, StrToIntDef(p[1], 0));
+        g_GFX_SetMax(a)
+      end
+      else if Length(p) = 1 then
+      begin
+        e_LogWritefln('%s', [g_GFX_GetMax()])
+      end
+      else
+      begin
+        e_LogWritefln('usage: %s <n>', [cmd])
+      end
+    end;
+
+    'g_max_shells': begin
+      if Length(p) = 2 then
+      begin
+        a := Max(0, StrToIntDef(p[1], 0));
+        g_Shells_SetMax(a)
+      end
+      else if Length(p) = 1 then
+      begin
+        e_LogWritefln('%s', [g_Shells_GetMax()])
+      end
+      else
+      begin
+        e_LogWritefln('usage: %s <n>', [cmd])
+      end
+    end;
+
+    'g_max_gibs': begin
+      if Length(p) = 2 then
+      begin
+        a := Max(0, StrToIntDef(p[1], 0));
+        g_Gibs_SetMax(a)
+      end
+      else if Length(p) = 1 then
+      begin
+        e_LogWritefln('%s', [g_Gibs_GetMax()])
+      end
+      else
+      begin
+        e_LogWritefln('usage: %s <n>', [cmd])
+      end
+    end;
+
+    'g_max_corpses': begin
+      if Length(p) = 2 then
+      begin
+        a := Max(0, StrToIntDef(p[1], 0));
+        g_Corpses_SetMax(a)
+      end
+      else if Length(p) = 1 then
+      begin
+        e_LogWritefln('%s', [g_Corpses_GetMax()])
+      end
+      else
+      begin
+        e_LogWritefln('usage: %s <n>', [cmd])
+      end
+    end;
+
+    'g_force_model': begin
+      if Length(p) = 2 then
+      begin
+        a := StrToIntDef(p[1], 0);
+        g_Force_Model_Set(a);
+        if (g_Force_Model_Get() <> 0) and (gPlayers <> nil) then
+        begin
+          for a := Low(gPlayers) to High(gPlayers) do
           begin
-            if (gPlayers[a].UID = gPlayer1.UID) then
-              continue
-            else if (gPlayer2 <> nil) and (gPlayers[a].UID = gPlayer2.UID) then
-              continue;
-            gPlayers[a].setModel(g_Forced_Model_GetName());
-          end;
+            if (gPlayers[a] <> nil) then
+            begin
+              if (gPlayers[a].UID = gPlayer1.UID) then
+                continue
+              else if (gPlayer2 <> nil) and (gPlayers[a].UID = gPlayer2.UID) then
+                continue;
+              gPlayers[a].setModel(g_Forced_Model_GetName());
+            end;
+          end
+        end
+        else if (g_Force_Model_Get() = 0) and (gPlayers <> nil) then
+        begin
+          for a := Low(gPlayers) to High(gPlayers) do
+          begin
+            if (gPlayers[a] <> nil) then
+            begin
+              if (gPlayers[a].UID = gPlayer1.UID) then
+                continue
+              else if (gPlayer2 <> nil) and (gPlayers[a].UID = gPlayer2.UID) then
+                continue;
+              gPlayers[a].setModel(gPlayers[a].FActualModelName);
+            end;
+          end
         end
       end
-    end
-  end
-  else if cmd = 'g_scorelimit' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsScoreLimit := nclamp(StrToIntDef(P[1], gsScoreLimit), 0, $FFFF);
+    end;
 
-      if g_Game_IsServer then
+    'g_force_model_name': begin
+      if (Length(P) > 1) then
       begin
-        b := 0;
-        if gGameSettings.GameMode = GM_DM then
-        begin // DM
-          stat := g_Player_GetStats();
-          if stat <> nil then
-            for a := 0 to High(stat) do
-              if stat[a].Frags > b then
-                b := stat[a].Frags;
+        cmd := b_Text_Unformat(P[1]);
+        g_Forced_Model_SetName(cmd);
+        if (g_Force_Model_Get() <> 0) and (gPlayers <> nil) then
+        begin
+          for a := Low(gPlayers) to High(gPlayers) do
+          begin
+            if (gPlayers[a] <> nil) then
+            begin
+              if (gPlayers[a].UID = gPlayer1.UID) then
+                continue
+              else if (gPlayer2 <> nil) and (gPlayers[a].UID = gPlayer2.UID) then
+                continue;
+              gPlayers[a].setModel(g_Forced_Model_GetName());
+            end;
+          end
         end
-        else // TDM/CTF
-          b := Max(gTeamStat[TEAM_RED].Score, gTeamStat[TEAM_BLUE].Score);
+      end
+    end;
 
-        // if someone has a higher score, set it to that instead
-        gsScoreLimit := max(gsScoreLimit, b);
-        gGameSettings.ScoreLimit := gsScoreLimit;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+    'g_scorelimit': begin
+      if Length(P) > 1 then
+      begin
+        gsScoreLimit := nclamp(StrToIntDef(P[1], gsScoreLimit), 0, $FFFF);
+
+        if g_Game_IsServer then
+        begin
+          b := 0;
+          if gGameSettings.GameMode = GM_DM then
+          begin // DM
+            stat := g_Player_GetStats();
+            if stat <> nil then
+              for a := 0 to High(stat) do
+                if stat[a].Frags > b then
+                  b := stat[a].Frags;
+          end
+          else // TDM/CTF
+            b := Max(gTeamStat[TEAM_RED].Score, gTeamStat[TEAM_BLUE].Score);
+
+          // if someone has a higher score, set it to that instead
+          gsScoreLimit := max(gsScoreLimit, b);
+          gGameSettings.ScoreLimit := gsScoreLimit;
+
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
+
+      g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [Integer(gsScoreLimit)]));
     end;
 
-    g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [Integer(gsScoreLimit)]));
-  end
-  else if cmd = 'g_timelimit' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsTimeLimit := nclamp(StrToIntDef(P[1], gsTimeLimit), 0, $FFFF);
-      if g_Game_IsServer then
+    'g_timelimit': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.TimeLimit := gsTimeLimit;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+        gsTimeLimit := nclamp(StrToIntDef(P[1], gsTimeLimit), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.TimeLimit := gsTimeLimit;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
+      g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
+                           [gsTimeLimit div 3600,
+                           (gsTimeLimit div 60) mod 60,
+                            gsTimeLimit mod 60]));
     end;
-    g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
-                         [gsTimeLimit div 3600,
-                         (gsTimeLimit div 60) mod 60,
-                          gsTimeLimit mod 60]));
-  end
-  else if cmd = 'g_max_bots' then
-  begin
-    if Length(P) > 1 then
-      gMaxBots := nclamp(StrToIntDef(P[1], gMaxBots), 0, 127);
-    g_Console_Add('g_max_bots = ' + IntToStr(gMaxBots));
-  end
-  else if cmd = 'g_maxlives' then
-  begin
-    if Length(P) > 1 then
-    begin
-      gsMaxLives := nclamp(StrToIntDef(P[1], gsMaxLives), 0, $FFFF);
-      if g_Game_IsServer then
+
+    'g_max_bots': begin
+      if Length(P) > 1 then
+        gMaxBots := nclamp(StrToIntDef(P[1], gMaxBots), 0, 127);
+      g_Console_Add('g_max_bots = ' + IntToStr(gMaxBots));
+    end;
+
+    'g_maxlives': begin
+      if Length(P) > 1 then
       begin
-        gGameSettings.MaxLives := gsMaxLives;
-        if g_Game_IsNet then MH_SEND_GameSettings;
+        gsMaxLives := nclamp(StrToIntDef(P[1], gsMaxLives), 0, $FFFF);
+        if g_Game_IsServer then
+        begin
+          gGameSettings.MaxLives := gsMaxLives;
+          if g_Game_IsNet then MH_SEND_GameSettings;
+        end;
       end;
-    end;
 
-    g_Console_Add(Format(_lc[I_MSG_LIVES], [Integer(gsMaxLives)]));
+      g_Console_Add(Format(_lc[I_MSG_LIVES], [Integer(gsMaxLives)]));
+    end;
   end;
 end;
 
@@ -6014,26 +6122,26 @@ begin
         if (Length(P) = 2) then
           gPlayer2Settings.SwitchToEmpty := EnsureRange(StrTointDef(P[1], 0), 0, 1);
         end;
-    'p1_skip_fist':
+    'p1_skip_ironfist':
       begin
         if (Length(P) = 2) then
-          gPlayer1Settings.SkipFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+          gPlayer1Settings.SkipIronFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
         end;
-    'p2_skip_fist':
+    'p2_skip_ironfist':
       begin
         if (Length(P) = 2) then
-          gPlayer2Settings.SkipFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+          gPlayer2Settings.SkipIronFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
         end;
-    'p1_priority_kastet':
+    'p1_priority_ironfist':
       begin
         if (Length(P) = 2) then
-          gPlayer1Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
+          gPlayer1Settings.WeaponPreferences[WEAPON_IRONFIST] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
         end;
-    'p2_priority_kastet':
+    'p2_priority_ironfist':
       begin
         if (Length(P) = 2) then
-          gPlayer2Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
-      end;        
+          gPlayer2Settings.WeaponPreferences[WEAPON_IRONFIST] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
     'p1_priority_saw':
       begin
         if (Length(P) = 2) then
@@ -6047,13 +6155,13 @@ begin
     'p1_priority_pistol':
       begin
         if (Length(P) = 2) then
-          gPlayer1Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
+          gPlayer1Settings.WeaponPreferences[WEAPON_PISTOL] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
         end;
     'p2_priority_pistol':
       begin
         if (Length(P) = 2) then
-          gPlayer2Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
-      end;         
+          gPlayer2Settings.WeaponPreferences[WEAPON_PISTOL] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
     'p1_priority_shotgun1':
       begin
         if (Length(P) = 2) then
@@ -6114,15 +6222,15 @@ begin
         if (Length(P) = 2) then
           gPlayer2Settings.WeaponPreferences[WEAPON_BFG] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
       end;
-    'p1_priority_super':
+    'p1_priority_superchaingun':
       begin
         if (Length(P) = 2) then
-          gPlayer1Settings.WeaponPreferences[WEAPON_SUPERPULEMET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+          gPlayer1Settings.WeaponPreferences[WEAPON_SUPERCHAINGUN] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
       end;
-    'p2_priority_super':
+    'p2_priority_superchaingun':
       begin
         if (Length(P) = 2) then
-          gPlayer2Settings.WeaponPreferences[WEAPON_SUPERPULEMET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+          gPlayer2Settings.WeaponPreferences[WEAPON_SUPERCHAINGUN] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
       end;
     'p1_priority_flamethrower':
       begin
@@ -6133,17 +6241,17 @@ begin
       begin
         if (Length(P) = 2) then
           gPlayer2Settings.WeaponPreferences[WEAPON_FLAMETHROWER] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
-      end;      
+      end;
     'p1_priority_berserk':
       begin
         if (Length(P) = 2) then
-          gPlayer1Settings.WeaponPreferences[WP_LAST+1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
+          gPlayer1Settings.WeaponPreferences[WP_LAST+1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
         end;
     'p2_priority_berserk':
       begin
         if (Length(P) = 2) then
-          gPlayer2Settings.WeaponPreferences[WP_LAST+1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1); 
-      end;                                                                                  
+          gPlayer2Settings.WeaponPreferences[WP_LAST+1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
   end;
 end;
 
@@ -6175,7 +6283,7 @@ begin
     if cmd = 'd_window' then
     begin
       g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
-      g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
+      g_Console_Add(Format('gWinSizeX = %d, gWinSizeY = %d', [gWinSizeX, gWinSizeY]));
     end
     else if cmd = 'd_sounds' then
     begin
@@ -6322,7 +6430,7 @@ begin
     begin
       cmd := LowerCase(P[f]);
       if cmd = 'health' then begin plr.RestoreHealthArmor(); g_Console_Add('player feels himself better'); continue; end;
-      if (cmd = 'all') {or (cmd = 'weapons')} then begin plr.AllRulez(False); g_Console_Add('player got the gifts'); continue; end;
+      if (cmd = 'all') {or (cmd = 'weapons')} then begin plr.TankRamboCheats(False); g_Console_Add('player got the gifts'); continue; end;
       if cmd = 'exit' then
       begin
         if gTriggers <> nil then
@@ -6357,8 +6465,8 @@ begin
       if cmd = 'greenarmor' then begin plr.GiveItem(ITEM_ARMOR_GREEN); g_Console_Add('player got a security armor'); continue; end;
       if cmd = 'bluearmor' then begin plr.GiveItem(ITEM_ARMOR_BLUE); g_Console_Add('player got a combat armor'); continue; end;
 
-      if (cmd = 'megasphere') or (cmd = 'mega') then begin plr.GiveItem(ITEM_SPHERE_BLUE); g_Console_Add('player got a megasphere'); continue; end;
-      if (cmd = 'soulsphere') or (cmd = 'soul')then begin plr.GiveItem(ITEM_SPHERE_WHITE); g_Console_Add('player got a soul sphere'); continue; end;
+      if (cmd = 'soulsphere') or (cmd = 'soul') then begin plr.GiveItem(ITEM_SPHERE_BLUE); g_Console_Add('player got a soul sphere'); continue; end;
+      if (cmd = 'megasphere') or (cmd = 'mega') then begin plr.GiveItem(ITEM_SPHERE_WHITE); g_Console_Add('player got a megasphere'); continue; end;
 
       if (cmd = 'invul') or (cmd = 'invulnerability') then begin plr.GiveItem(ITEM_INVUL); g_Console_Add('player got invulnerability'); continue; end;
       if (cmd = 'invis') or (cmd = 'invisibility') then begin plr.GiveItem(ITEM_INVIS); g_Console_Add('player got invisibility'); continue; end;
@@ -6381,8 +6489,8 @@ begin
       if cmd = 'plasmagunzz' 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 = 'bfgzz' then begin plr.GiveItem(ITEM_WEAPON_BFG); plr.GiveItem(ITEM_AMMO_CELL_BIG); g_Console_Add('player got a BFG-9000'); continue; end;
 
-      if cmd = 'superchaingun' then begin plr.GiveItem(ITEM_WEAPON_SUPERPULEMET); g_Console_Add('player got a superchaingun'); continue; end;
-      if cmd = 'superchaingunzz' then begin plr.GiveItem(ITEM_WEAPON_SUPERPULEMET); plr.GiveItem(ITEM_AMMO_BULLETS_BOX); g_Console_Add('player got a superchaingun'); continue; end;
+      if cmd = 'superchaingun' then begin plr.GiveItem(ITEM_WEAPON_SUPERCHAINGUN); g_Console_Add('player got a superchaingun'); continue; end;
+      if cmd = 'superchaingunzz' then begin plr.GiveItem(ITEM_WEAPON_SUPERCHAINGUN); plr.GiveItem(ITEM_AMMO_BULLETS_BOX); g_Console_Add('player got a superchaingun'); continue; end;
 
       if (cmd = 'flamer') or (cmd = 'flamethrower') or (cmd = 'ft') then begin plr.GiveItem(ITEM_WEAPON_FLAMETHROWER); g_Console_Add('player got a flame thrower'); continue; end;
       if (cmd = 'flamerzz') or (cmd = 'flamethrowerzz') or (cmd = 'ftzz') then begin plr.GiveItem(ITEM_WEAPON_FLAMETHROWER); plr.GiveItem(ITEM_AMMO_FUELCAN); g_Console_Add('player got a flame thrower'); continue; end;
@@ -6516,6 +6624,7 @@ var
   nm: Boolean;
   listen: LongWord;
   found: Boolean;
+  t: Byte;
 begin
 // Îáùèå êîìàíäû:
   cmd := LowerCase(P[0]);
@@ -6560,7 +6669,7 @@ begin
       if (pl <> nil) then
       begin
         s := g_Net_ClientName_ByID(pl^.ID);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
+        g_Net_Host_Kick(pl^.ID, NET_DISC_KICK);
         g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
         MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
         g_Net_Slist_ServerPlayerLeaves();
@@ -6604,7 +6713,7 @@ begin
         if NetClients[a].Used and (NetClients[a].Peer <> nil) then
         begin
           s := g_Net_ClientName_ByID(NetClients[a].ID);
-          enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
+          g_Net_Host_Kick(NetClients[a].ID, NET_DISC_KICK);
           g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
           MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
           g_Net_Slist_ServerPlayerLeaves();
@@ -6633,7 +6742,7 @@ begin
       if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then
       begin
         s := g_Net_ClientName_ByID(pl^.ID);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
+        g_Net_Host_Kick(pl^.ID, NET_DISC_KICK);
         g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
         MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
         g_Net_Slist_ServerPlayerLeaves();
@@ -6658,14 +6767,8 @@ begin
 
       pl := g_Net_Client_ByName(P[1]);
       if (pl <> nil) then
-      begin
-        s := g_Net_ClientName_ByID(pl^.ID);
-        g_Net_BanHost(pl^.Peer^.address.host, False);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
-        g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-        MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        g_Net_Slist_ServerPlayerLeaves();
-      end else
+        g_Net_Host_Ban(pl, False)
+      else
         g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
@@ -6688,14 +6791,7 @@ begin
       a := StrToIntDef(P[1], 0);
       if (NetClients <> nil) and (a <= High(NetClients)) then
         if NetClients[a].Used and (NetClients[a].Peer <> nil) then
-        begin
-          s := g_Net_ClientName_ByID(NetClients[a].ID);
-          g_Net_BanHost(NetClients[a].Peer^.address.host, False);
-          enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
-          g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-          MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-          g_Net_Slist_ServerPlayerLeaves();
-        end;
+          g_Net_Host_Ban(pl, False);
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6717,14 +6813,7 @@ begin
       a := StrToIntDef(P[1], 0);
       pl := g_Net_Client_ByPlayer(a);
       if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then
-      begin
-        s := g_Net_ClientName_ByID(pl^.ID);
-        g_Net_BanHost(pl^.Peer^.address.host, False);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
-        g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-        MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        g_Net_Slist_ServerPlayerLeaves();
-      end;
+        g_Net_Host_Ban(pl, False);
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6745,15 +6834,8 @@ begin
 
       pl := g_Net_Client_ByName(P[1]);
       if (pl <> nil) then
-      begin
-        s := g_Net_ClientName_ByID(pl^.ID);
-        g_Net_BanHost(pl^.Peer^.address.host);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
-        g_Net_SaveBanList();
-        g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-        MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        g_Net_Slist_ServerPlayerLeaves();
-      end else
+        g_Net_Host_Ban(pl, True)
+      else
         g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
@@ -6776,15 +6858,7 @@ begin
       a := StrToIntDef(P[1], 0);
       if (NetClients <> nil) and (a <= High(NetClients)) then
         if NetClients[a].Used and (NetClients[a].Peer <> nil) then
-        begin
-          s := g_Net_ClientName_ByID(NetClients[a].ID);
-          g_Net_BanHost(NetClients[a].Peer^.address.host);
-          enet_peer_disconnect(NetClients[a].Peer, NET_DISC_BAN);
-          g_Net_SaveBanList();
-          g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-          MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-          g_Net_Slist_ServerPlayerLeaves();
-        end;
+          g_Net_Host_Ban(@NetClients[a], True);
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6806,15 +6880,7 @@ begin
       a := StrToIntDef(P[1], 0);
       pl := g_Net_Client_ByPlayer(a);
       if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then
-      begin
-        s := g_Net_ClientName_ByID(pl^.ID);
-        g_Net_BanHost(pl^.Peer^.address.host);
-        enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
-        g_Net_SaveBanList();
-        g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
-        MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        g_Net_Slist_ServerPlayerLeaves();
-      end;
+        g_Net_Host_Ban(pl, True);
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6833,7 +6899,7 @@ begin
         Exit;
       end;
 
-      g_Net_BanHost(P[1]);
+      g_Net_BanAddress(P[1]);
       g_Net_SaveBanList();
       g_Console_Add(Format(_lc[I_PLAYER_BAN], [P[1]]));
     end else
@@ -6854,7 +6920,7 @@ begin
         Exit;
       end;
 
-      if g_Net_UnbanHost(P[1]) then
+      if g_Net_UnbanAddress(P[1]) then
       begin
         g_Console_Add(Format(_lc[I_MSG_UNBAN_OK], [P[1]]));
         g_Net_SaveBanList();
@@ -6934,23 +7000,29 @@ begin
   else if (cmd = 'addbot') or
      (cmd = 'bot_add') then
   begin
-    if Length(P) > 2 then
-      g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2), StrToIntDef(P[2], 100))
-    else if Length(P) > 1 then
-      g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2))
+    case Length(P) of
+      1: g_Bot_Add(TEAM_NONE, 2);
+      2: g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2));
     else
-      g_Bot_Add(TEAM_NONE, 2);
+      g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2), StrToIntDef(P[2], 100));
+    end;
   end
   else if cmd = 'bot_addlist' then
   begin
-    if Length(P) > 1 then
-    begin
-      if Length(P) = 2 then
-        g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1))
-      else if Length(P) = 3 then
-        g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1), StrToIntDef(P[2], 100))
+    case Length(P) of
+      1: g_Bot_AddList(TEAM_NONE, '');
+      2: g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1));
+    else
+      if P[2] = 'red' then
+        t := TEAM_RED
+      else if P[2] = 'blue' then
+        t := TEAM_BLUE
       else
-        g_Bot_AddList(IfThen(P[2] = 'red', TEAM_RED, TEAM_BLUE), P[1], StrToIntDef(P[1], -1));
+        t := TEAM_NONE;
+
+      if Length(P) = 3
+        then g_Bot_AddList(t, P[1], StrToIntDef(P[1], -1))
+        else g_Bot_AddList(t, P[1], StrToIntDef(P[1], -1), StrToIntDef(P[3], 100));
     end;
   end
   else if cmd = 'bot_removeall' then
@@ -7052,7 +7124,7 @@ begin
       g_Console_Add(cmd + ' <WAD> [MAP] [# players]');
       Exit;
     end;
-    // game not started yet, load fist map from some wad
+    // game not started yet, load first map from some wad
     found := false;
     s := addWadExtension(P[1]);
     found := e_FindResource(AllMapDirs, s);
@@ -7168,6 +7240,10 @@ begin
         g_Console_Add(_lc[I_MSG_GM_UNAVAIL])
       end
     end
+    else if not e_IsValidResourceName(P[1]) then
+    begin
+      g_Console_Add('wad name must not be absolute or relative');
+    end
     else
     begin
       if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
@@ -7295,6 +7371,10 @@ begin
           g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
         end;
       end
+      else if not e_IsValidResourceName(P[1]) then
+      begin
+        g_Console_Add('wad name must not be absolute or relative');
+      end
       else
       begin
         nm := False;
@@ -7835,7 +7915,7 @@ begin
       DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t);
       Filename := 'screenshot-' + date;
     end;
-    
+
     name := e_CatPath(dir, Filename + '.png');
     s := createDiskFile(name);
     try
@@ -8187,6 +8267,14 @@ begin
   hahasnd[Random(3)].Play();
 end;
 
+procedure g_Game_Effect_Bubbles (fX, fY: Integer; count: Word; devX, devY: Byte; Silent: Boolean);
+begin
+  g_GFX_Bubbles(fX, fY, count, devX, devY);
+  if not Silent then if Random(2) = 0
+    then g_Sound_PlayExAt('SOUND_GAME_BUBBLE1', fX, fY)
+    else g_Sound_PlayExAt('SOUND_GAME_BUBBLE2', fX, fY);
+end;
+
 procedure g_Game_StartVote(Command, Initiator: string);
 var
   Need: Integer;
@@ -8431,7 +8519,7 @@ var
   map: String;
   GMode, n: Byte;
   LimT, LimS: Integer;
-  Opt: LongWord;
+  Opt: TGameOptions;
   Lives: Integer;
   s: String;
   Port: Integer;
@@ -8510,10 +8598,9 @@ begin
 
   // Options:
     s := Find_Param_Value(pars, '-opt');
-    if (s = '') then
-      Opt := gsGameFlags
-    else
-      Opt := StrToIntDef(s, 0);
+    if (s = '')
+      then Opt := gsGameFlags
+      else Opt := TGameOptions(StrToIntDef(s, 0));
 
   // Close after map:
     s := Find_Param_Value(pars, '--close');
@@ -8555,10 +8642,9 @@ begin
 
   // Start:
     s := Find_Param_Value(pars, '-port');
-    if (s = '') or not TryStrToInt(s, Port) then
-      g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
-    else
-      g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
+    if (s = '') or not TryStrToInt(s, Port)
+      then g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
+      else g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
   end;
 
 // Execute script when game loads: