DEADSOFTWARE

game: set randomized rulez respawn to false
[d2df-sdl.git] / src / game / g_game.pas
index 0231bc8c5858249a2d24586d2772aacd879cb359..7c499d4958f690958daecda3d5fd070d97fd67c3 100644 (file)
@@ -29,10 +29,11 @@ type
     GameType: Byte;
     GameMode: Byte;
     TimeLimit: Word;
-    GoalLimit: Word;
+    ScoreLimit: Word;
     WarmupTime: Word;
     SpawnInvul: Word;
     ItemRespawnTime: Word;
+    RulezTimeMultiplier: Word;
     MaxLives: Byte;
     Options: LongWord;
     WAD: String;
@@ -62,6 +63,11 @@ type
     Model: String;
     Color: TRGB;
     Team: Byte;
+    // ones below are sent only to the server
+    WeaponSwitch: Byte;
+    WeaponPreferences: Array[WP_FIRST..WP_LAST+1] of Byte;
+    SwitchToEmpty: Byte;
+    SkipFist: Byte;
   end;
 
   TMegaWADInfo = record
@@ -84,6 +90,7 @@ procedure g_Game_Free (freeTextures: Boolean=true);
 procedure g_Game_LoadData();
 procedure g_Game_FreeData();
 procedure g_Game_Update();
+procedure g_Game_PreUpdate();
 procedure g_Game_Draw();
 procedure g_Game_Quit();
 procedure g_Game_SetupScreenSize();
@@ -97,8 +104,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, GoalLimit: Word; MaxLives: Byte; Options: LongWord; nPlayers: Byte);
-procedure g_Game_StartServer(Map: String; GameMode: Byte; TimeLimit, GoalLimit: 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: 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_StartClient(Addr: String; Port: Word; PW: String);
 procedure g_Game_Restart();
 procedure g_Game_RestartLevel();
@@ -125,6 +132,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 = '');
@@ -175,14 +183,20 @@ 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_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;
+  GAME_OPTION_RULEZRANDOM       = 8192;
 
   STATE_NONE        = 0;
   STATE_MENU        = 1;
@@ -264,8 +278,9 @@ var
   gPauseHolmes: Boolean = false;
   gShowTime: Boolean = False;
   gShowFPS: Boolean = False;
-  gShowGoals: Boolean = True;
+  gShowScore: Boolean = True;
   gShowStat: Boolean = True;
+  gShowPIDs: Boolean = False;
   gShowKillMsg: Boolean = True;
   gShowLives: Boolean = True;
   gShowPing: Boolean = False;
@@ -335,8 +350,10 @@ var
   gDelayedEvents: Array of TDelayedEvent;
   gUseChatSounds: Boolean = True;
   gChatSounds: Array of TChatSound;
+  gWeaponAction: Array [0..1, WP_FACT..WP_LACT] of Boolean; // [player, weapon_action]
   gSelectWeapon: Array [0..1, WP_FIRST..WP_LAST] of Boolean; // [player, weapon]
   gInterReadyCount: Integer = 0;
+  gMaxBots: Integer = 127;
 
   g_dbg_ignore_bounds: Boolean = false;
   r_smallmap_h: Integer = 0; // 0: left; 1: center; 2: right
@@ -386,7 +403,7 @@ uses
   e_input, e_log, g_console, g_items, g_map, g_panel,
   g_playermodel, g_gfx, g_options, Math,
   g_triggers, g_monsters, e_sound, CONFIG,
-  g_language, g_net, g_main,
+  g_language, g_net, g_main, g_phys,
   ENet, e_msg, g_netmsg, g_netmaster,
   sfs, wadreader, g_system;
 
@@ -653,7 +670,7 @@ 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;
   I: Integer;
@@ -666,6 +683,7 @@ begin
     fname := e_CatPath(fname, StatFilename + '.csv');
     AssignFile(s, fname);
     try
+      SetTextCodePage(s, CP_UTF8);
       Rewrite(s);
       // line 1: stats ver, datetime, server name, map name, game mode, time limit, score limit, dmflags, game time, num players
       if g_Game_IsNet then fname := NetServerName else fname := '';
@@ -684,7 +702,7 @@ begin
         dquoteStr(map),
         mode,
         gGameSettings.TimeLimit,
-        gGameSettings.GoalLimit,
+        gGameSettings.ScoreLimit,
         gGameSettings.Options,
         etime,
         Length(Stat.PlayerStat)
@@ -694,8 +712,8 @@ 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, 
-          Format('red_score,blue_score' + LineEnding + '%d,%d', [Stat.TeamStat[TEAM_RED].Goals, Stat.TeamStat[TEAM_BLUE].Goals]))
+        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,
           Format('mon_killed,mon_total,secrets_found,secrets_total' + LineEnding + '%d,%d,%d,%d',[gCoopMonstersKilled, gTotalMonsters, gCoopSecretsFound, gSecretsCount]));
@@ -713,6 +731,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 := '';
@@ -1161,6 +1190,7 @@ var
   stat: TPlayerStatArray;
   wad, map: string;
   mapstr: string;
+  namestr: string;
 begin
   s1 := '';
   s2 := '';
@@ -1192,7 +1222,7 @@ begin
         s1 := _lc[I_GAME_DM]
       else
         s1 := _lc[I_GAME_LMS];
-      s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
+      s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.ScoreLimit]);
       s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
     end;
 
@@ -1202,14 +1232,14 @@ begin
         s1 := _lc[I_GAME_TDM]
       else
         s1 := _lc[I_GAME_TLMS];
-      s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
+      s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.ScoreLimit]);
       s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
     end;
 
     GM_CTF:
     begin
       s1 := _lc[I_GAME_CTF];
-      s2 := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.GoalLimit]);
+      s2 := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.ScoreLimit]);
       s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
     end;
 
@@ -1279,7 +1309,7 @@ begin
       end;
 
       e_TextureFontPrintEx(x+16, _y, s1, gStdFont, r, g, b, 1);
-      e_TextureFontPrintEx(x+w1+16, _y, IntToStr(gTeamStat[a].Goals),
+      e_TextureFontPrintEx(x+w1+16, _y, IntToStr(gTeamStat[a].Score),
                            gStdFont, r, g, b, 1);
 
       _y := _y+ch+(ch div 4);
@@ -1302,8 +1332,12 @@ begin
               gg := g;
               bb := b;
             end;
+            if gShowPIDs then
+              namestr := Format('[%5d] %s', [UID, Name])
+            else
+              namestr := Name;
             // Èìÿ
-            e_TextureFontPrintEx(x+16, _y, Name, gStdFont, rr, gg, bb, 1);
+            e_TextureFontPrintEx(x+16, _y, namestr, gStdFont, rr, gg, bb, 1);
             // Ïèíã/ïîòåðè
             e_TextureFontPrintEx(x+w1+16, _y, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, rr, gg, bb, 1);
             // Ôðàãè
@@ -1338,11 +1372,15 @@ begin
           r := 255;
           g := 127;
         end;
+        if gShowPIDs then
+          namestr := Format('[%5d] %s', [UID, Name])
+        else
+          namestr := Name;
         // Öâåò èãðîêà
         e_DrawFillQuad(x+16, _y+4, x+32-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
         e_DrawQuad(x+16, _y+4, x+32-1, _y+16+4-1, 192, 192, 192);
         // Èìÿ
-        e_TextureFontPrintEx(x+16+16+8, _y+4, Name, gStdFont, r, g, 0, 1);
+        e_TextureFontPrintEx(x+16+16+8, _y+4, namestr, gStdFont, r, g, 0, 1);
         // Ïèíã/ïîòåðè
         e_TextureFontPrintEx(x+w1+16, _y+4, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, r, g, 0, 1);
         // Ôðàãè
@@ -1676,12 +1714,16 @@ begin
   if gPlayerAction[p, ACTION_LOOKUP] then plr.PressKey(KEY_UP, time);
   if gPlayerAction[p, ACTION_LOOKDOWN] then plr.PressKey(KEY_DOWN, time);
   if gPlayerAction[p, ACTION_ATTACK] then plr.PressKey(KEY_FIRE);
-  if gPlayerAction[p, ACTION_WEAPNEXT] then plr.PressKey(KEY_NEXTWEAPON);
-  if gPlayerAction[p, ACTION_WEAPPREV] then plr.PressKey(KEY_PREVWEAPON);
   if gPlayerAction[p, ACTION_ACTIVATE] then plr.PressKey(KEY_OPEN);
 
-  gPlayerAction[p, ACTION_WEAPNEXT] := False; // HACK, remove after readyweaon&pendinweapon implementation
-  gPlayerAction[p, ACTION_WEAPPREV] := False; // HACK, remove after readyweaon&pendinweapon implementation
+  for i := WP_FACT to WP_LACT do
+  begin
+    if gWeaponAction[p, i] then
+    begin
+      plr.ProcessWeaponAction(i);
+      gWeaponAction[p, i] := False
+    end
+  end;
 
   for i := WP_FIRST to WP_LAST do
   begin
@@ -1716,6 +1758,17 @@ begin
   MC_SEND_CheatRequest(NET_CHEAT_READY);
 end;
 
+procedure g_Game_PreUpdate();
+begin
+  // these are in separate PreUpdate functions because they can interact during Update()
+  // and are synced over the net
+  // we don't care that much about corpses and gibs
+  g_Player_PreUpdate();
+  g_Monsters_PreUpdate();
+  g_Items_PreUpdate();
+  g_Weapon_PreUpdate();
+end;
+
 procedure g_Game_Update();
 var
   Msg: g_gui.TMessage;
@@ -1749,6 +1802,16 @@ var
     if mon.gncNeedSend then MH_SEND_MonsterPos(mon.UID);
   end;
 
+  function sendItemPos (it: PItem): Boolean;
+  begin
+    result := false; // don't stop
+    if it.needSend then
+    begin
+      MH_SEND_ItemPos(it.myId);
+      it.needSend := False;
+    end;
+  end;
+
 var
   reliableUpdate: Boolean;
 begin
@@ -1876,6 +1939,7 @@ begin
           // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå:
             if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
               begin
+                gState := STATE_INTERCUSTOM;
                 InterReadyTime := -1;
                 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
                 begin
@@ -1885,9 +1949,7 @@ begin
                 end
                 else
                   gMusic.SetByName('MUSIC_ROUNDMUS');
-
                 gMusic.Play();
-                gState := STATE_INTERCUSTOM;
                 e_UnpressAllKeys();
               end
             else // Çàêîí÷èëàñü ïîñëåäíÿÿ êàðòà â Îäèíî÷íîé èãðå
@@ -1963,7 +2025,7 @@ begin
         gFlags[FLAG_BLUE].CaptureTime := gFlags[FLAG_BLUE].CaptureTime + GAME_TICK;
 
     // Áûë çàäàí ëèìèò ïîáåä:
-      if (gGameSettings.GoalLimit > 0) then
+      if (gGameSettings.ScoreLimit > 0) then
       begin
         b := 0;
 
@@ -1977,11 +2039,11 @@ begin
         else
           if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
           begin // Â CTF/TDM âûáèðàåì êîìàíäó ñ íàèáîëüøèì ñ÷åòîì
-            b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
+            b := Max(gTeamStat[TEAM_RED].Score, gTeamStat[TEAM_BLUE].Score);
           end;
 
       // Ëèìèò ïîáåä íàáðàí => êîíåö óðîâíÿ:
-        if b >= gGameSettings.GoalLimit then
+        if b >= gGameSettings.ScoreLimit then
         begin
           g_Game_NextLevel();
           Exit;
@@ -2031,17 +2093,17 @@ begin
             gSpectY := Max(gSpectY - gSpectStep, 0);
           if gPlayerAction[0, ACTION_LOOKDOWN] then
             gSpectY := Min(gSpectY + gSpectStep, gMapInfo.Height - gScreenHeight);
-          if gPlayerAction[0, ACTION_WEAPPREV] then
+          if gWeaponAction[0, WP_PREV] then
           begin
             // decrease step
             if gSpectStep > 4 then gSpectStep := gSpectStep shr 1;
-            gSpectKeyPress := True;
+            gWeaponAction[0, WP_PREV] := False;
           end;
-          if gPlayerAction[0, ACTION_WEAPNEXT] then
+          if gWeaponAction[0, WP_NEXT] then
           begin
             // increase step
             if gSpectStep < 64 then gSpectStep := gSpectStep shl 1;
-            gSpectKeyPress := True;
+            gWeaponAction[0, WP_NEXT] := False;
           end;
         end;
         if (gSpectMode = SPECT_PLAYERS)
@@ -2071,17 +2133,17 @@ begin
             gSpectPID1 := GetActivePlayerID_Next(gSpectPID1);
             gSpectKeyPress := True;
           end;
-          if gPlayerAction[0, ACTION_WEAPPREV] then
+          if gWeaponAction[0, WP_PREV] then
           begin
             // prev player (view 2)
             gSpectPID2 := GetActivePlayerID_Prev(gSpectPID2);
-            gSpectKeyPress := True;
+            gWeaponAction[0, WP_PREV] := False;
           end;
-          if gPlayerAction[0, ACTION_WEAPNEXT] then
+          if gWeaponAction[0, WP_NEXT] then
           begin
             // next player (view 2)
             gSpectPID2 := GetActivePlayerID_Next(gSpectPID2);
-            gSpectKeyPress := True;
+            gWeaponAction[0, WP_NEXT] := False;
           end;
         end;
         if gPlayerAction[0, ACTION_ATTACK] then
@@ -2108,9 +2170,7 @@ begin
            (not gPlayerAction[0, ACTION_MOVELEFT]) and
            (not gPlayerAction[0, ACTION_MOVERIGHT]) and
            (not gPlayerAction[0, ACTION_LOOKUP]) and
-           (not gPlayerAction[0, ACTION_LOOKDOWN]) and
-           (not gPlayerAction[0, ACTION_WEAPPREV]) and
-           (not gPlayerAction[0, ACTION_WEAPNEXT]) then
+           (not gPlayerAction[0, ACTION_LOOKDOWN]) then
           gSpectKeyPress := False;
 
       if gSpectAuto then
@@ -2162,13 +2222,6 @@ begin
       end;
     end;
 
-  // these are in separate PreUpdate functions because they can interact during Update()
-  // we don't care that much about corpses and gibs
-    g_Player_PreUpdate();
-    g_Monsters_PreUpdate();
-    g_Items_PreUpdate();
-    g_Weapon_PreUpdate();
-
   // Îáíîâëÿåì âñå îñòàëüíîå:
     g_Map_Update();
     g_Items_Update();
@@ -2217,6 +2270,18 @@ begin
 
         g_Mons_ForEach(sendMonsPos);
 
+        // update flags that aren't stationary
+        if gGameSettings.GameMode = GM_CTF then
+          for I := FLAG_RED to FLAG_BLUE do
+            if gFlags[I].NeedSend then
+            begin
+              gFlags[I].NeedSend := False;
+              MH_SEND_FlagPos(I);
+            end;
+
+        // update items that aren't stationary
+        g_Items_ForEachAlive(sendItemPos);
+
         if reliableUpdate then
         begin
           NetTimeToReliable := 0;
@@ -2797,8 +2862,8 @@ begin
     _y := _y+16+16;
 
     with CustomStat do
-      if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED]
-        else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE]
+      if TeamStat[TEAM_RED].Score > TeamStat[TEAM_BLUE].Score then s1 := _lc[I_GAME_WIN_RED]
+        else if TeamStat[TEAM_BLUE].Score > TeamStat[TEAM_RED].Score then s1 := _lc[I_GAME_WIN_BLUE]
           else s1 := _lc[I_GAME_WIN_DRAW];
 
     e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
@@ -2810,7 +2875,7 @@ begin
       begin
         e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED],
                              gStdFont, 255, 0, 0, 1);
-        e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals),
+        e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Score),
                              gStdFont, 255, 0, 0, 1);
         r := 255;
         g := 0;
@@ -2820,7 +2885,7 @@ begin
       begin
         e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE],
                              gStdFont, 0, 0, 255, 1);
-        e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals),
+        e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Score),
                              gStdFont, 0, 0, 255, 1);
         r := 0;
         g := 0;
@@ -3630,6 +3695,7 @@ end;
 procedure DrawPlayer(p: TPlayer);
 var
   px, py, a, b, c, d, i, fX, fY: Integer;
+  camObj: TObj;
   //R: TRect;
 begin
   if (p = nil) or (p.FDummy) then
@@ -3647,9 +3713,10 @@ begin
 
   glPushMatrix();
 
-  p.Obj.lerp(gLerpFactor, fX, fY);
+  camObj := p.getCameraObj();
+  camObj.lerp(gLerpFactor, fX, fY);
   px := fX + PLAYER_RECT_CX;
-  py := fY + PLAYER_RECT_CY+nlerp(p.SlopeOld, p.Obj.slopeUpLeft, gLerpFactor);
+  py := fY + PLAYER_RECT_CY+nlerp(p.SlopeOld, camObj.slopeUpLeft, gLerpFactor);
 
   if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then
   begin
@@ -3838,6 +3905,9 @@ begin
     FPSTime := Time;
   end;
 
+  e_SetRendertarget(True);
+  e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
+
   if gGameOn or (gState = STATE_FOLD) then
   begin
     if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
@@ -3978,7 +4048,8 @@ begin
                   Round(gScreenHeight / 2.75)-(h div 2), MessageText);
     end;
 
-    if IsDrawStat or (gSpectMode = 1) then DrawStat();
+    if IsDrawStat or (gSpectMode = SPECT_STATS) then
+      DrawStat();
 
     if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) and (not gSpectAuto) then
     begin
@@ -4168,10 +4239,20 @@ begin
 
   if gGameOn then drawProfilers();
 
+  // TODO: draw this after the FBO and remap mouse click coordinates
+
 {$IFDEF ENABLE_HOLMES}
   g_Holmes_DrawUI();
 {$ENDIF}
 
+  // blit framebuffer to screen
+
+  e_SetRendertarget(False);
+  e_SetViewPort(0, 0, gWinSizeX, gWinSizeY);
+  e_BlitFramebuffer(gWinSizeX, gWinSizeY);
+
+  // draw the overlay stuff on top of it
+
   g_Touch_Draw;
 end;
 
@@ -4203,6 +4284,7 @@ begin
   e_WriteLog(Format(_lc[I_FATAL_ERROR], [Text]), TMsgType.Warning);
 
   gExit := EXIT_SIMPLE;
+  if gGameOn then EndGame;
 end;
 
 procedure g_SimpleError(Text: String);
@@ -4285,6 +4367,10 @@ begin
     else
     begin
       gPlayer1.Name := gPlayer1Settings.Name;
+      gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
+      gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
+      gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
+      gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
       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);
@@ -4315,6 +4401,10 @@ begin
     else
     begin
       gPlayer2.Name := gPlayer2Settings.Name;
+      gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
+      gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
+      gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
+      gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
       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);
@@ -4405,6 +4495,9 @@ begin
   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 := gGameSettings.Options + GAME_OPTION_RULEZRANDOM;
   gSwitchGameMode := GM_SINGLE;
 
   gLMSRespawn := LMS_RESPAWN_NONE;
@@ -4428,6 +4521,10 @@ begin
   end;
 
   gPlayer1.Name := gPlayer1Settings.Name;
+  gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
+  gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
+  gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
+  gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
   nPl := 1;
 
 // Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü:
@@ -4443,6 +4540,10 @@ begin
     end;
 
     gPlayer2.Name := gPlayer2Settings.Name;
+    gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
+    gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
+    gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
+    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
     Inc(nPl);
   end;
 
@@ -4463,7 +4564,7 @@ begin
 end;
 
 procedure g_Game_StartCustom(Map: String; GameMode: Byte;
-                             TimeLimit, GoalLimit: Word;
+                             TimeLimit, ScoreLimit: Word;
                              MaxLives: Byte;
                              Options: LongWord; nPlayers: Byte);
 var
@@ -4480,7 +4581,7 @@ begin
   gGameSettings.GameMode := GameMode;
   gSwitchGameMode := GameMode;
   gGameSettings.TimeLimit := TimeLimit;
-  gGameSettings.GoalLimit := GoalLimit;
+  gGameSettings.ScoreLimit := ScoreLimit;
   gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
   gGameSettings.Options := Options;
 
@@ -4522,6 +4623,10 @@ begin
     end;
 
     gPlayer1.Name := gPlayer1Settings.Name;
+    gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
+    gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
+    gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
+    gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
     Inc(nPl);
   end;
 
@@ -4538,6 +4643,10 @@ begin
     end;
 
     gPlayer2.Name := gPlayer2Settings.Name;
+    gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
+    gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
+    gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
+    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
     Inc(nPl);
   end;
 
@@ -4568,7 +4677,7 @@ begin
 end;
 
 procedure g_Game_StartServer(Map: String; GameMode: Byte;
-                             TimeLimit, GoalLimit: Word; MaxLives: Byte;
+                             TimeLimit, ScoreLimit: Word; MaxLives: Byte;
                              Options: LongWord; nPlayers: Byte;
                              IPAddr: LongWord; Port: Word);
 begin
@@ -4579,12 +4688,14 @@ begin
 
   g_Game_ClearLoading();
 
+  ClearDebugCvars();
+
 // Íàñòðîéêè èãðû:
   gGameSettings.GameType := GT_SERVER;
   gGameSettings.GameMode := GameMode;
   gSwitchGameMode := GameMode;
   gGameSettings.TimeLimit := TimeLimit;
-  gGameSettings.GoalLimit := GoalLimit;
+  gGameSettings.ScoreLimit := ScoreLimit;
   gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
   gGameSettings.Options := Options;
 
@@ -4625,6 +4736,10 @@ begin
     end;
 
     gPlayer1.Name := gPlayer1Settings.Name;
+    gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
+    gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
+    gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
+    gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
   end;
 
   if nPlayers >= 2 then
@@ -4640,6 +4755,10 @@ begin
     end;
 
     gPlayer2.Name := gPlayer2Settings.Name;
+    gPlayer2.WeapSwitchMode := gPlayer2Settings.WeaponSwitch;
+    gPlayer2.setWeaponPrefs(gPlayer2Settings.WeaponPreferences);
+    gPlayer2.SwitchToEmpty := gPlayer2Settings.SwitchToEmpty;
+    gPlayer2.SkipFist := gPlayer2Settings.SkipFist;
   end;
 
   g_Game_SetLoadingText(_lc[I_LOAD_HOST], 0, False);
@@ -4704,6 +4823,8 @@ begin
 
   g_Game_ClearLoading();
 
+  ClearDebugCvars();
+
 // Íàñòðîéêè èãðû:
   gGameSettings.GameType := GT_CLIENT;
 
@@ -4753,12 +4874,6 @@ begin
     begin
       if (NetEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
       begin
-        if (NetEvent.channelID = NET_CHAN_DOWNLOAD_EX) then
-        begin
-          // ignore all download packets, they're processed by separate code
-          enet_packet_destroy(NetEvent.packet);
-          continue;
-        end;
         Ptr := NetEvent.packet^.data;
         if not InMsg.Init(Ptr, NetEvent.packet^.dataLength, True) then
         begin
@@ -4781,7 +4896,7 @@ begin
 
           gGameSettings.GameMode := InMsg.ReadByte();
           gSwitchGameMode := gGameSettings.GameMode;
-          gGameSettings.GoalLimit := InMsg.ReadWord();
+          gGameSettings.ScoreLimit := InMsg.ReadWord();
           gGameSettings.TimeLimit := InMsg.ReadWord();
           gGameSettings.MaxLives := InMsg.ReadByte();
           gGameSettings.Options := InMsg.ReadLongWord();
@@ -4818,6 +4933,10 @@ begin
           end;
 
           gPlayer1.Name := gPlayer1Settings.Name;
+          gPlayer1.WeapSwitchMode := gPlayer1Settings.WeaponSwitch;
+          gPlayer1.setWeaponPrefs(gPlayer1Settings.WeaponPreferences);
+          gPlayer1.SwitchToEmpty := gPlayer1Settings.SwitchToEmpty;
+          gPlayer1.SkipFist := gPlayer1Settings.SkipFist;
           gPlayer1.UID := NetPlrUID1;
           gPlayer1.Reset(True);
 
@@ -4854,8 +4973,7 @@ begin
       end;
     end;
 
-    ProcessLoading(true);
-
+    ProcessLoading(True);
     if g_Net_UserRequestExit() then
     begin
       State := 0;
@@ -5058,6 +5176,11 @@ begin
 
   if NetMode = NET_SERVER then
   begin
+  // reset full state flags
+    if NetClients <> nil then
+      for I := 0 to High(NetClients) do
+        NetClients[I].FullUpdateSent := False;
+
     MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
 
   // Ìàñòåðñåðâåð
@@ -5075,7 +5198,7 @@ begin
           end;
         end;
 
-    g_Net_UnbanNonPermHosts();
+    g_Net_UnbanNonPerm();
   end;
 
   if gLastMap then
@@ -5411,6 +5534,7 @@ var
   a, b: Integer;
   stat: TPlayerStatArray;
   cmd: string;
+  it: PItem;
 
   procedure ParseGameFlag(Flag: LongWord; OffMsg, OnMsg: TStrings_Locale; OnMapChange: Boolean = False);
   var
@@ -5478,6 +5602,22 @@ begin
   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_powerup_randomize_respawn' then
+  begin
+    ParseGameFlag(GAME_OPTION_RULEZRANDOM, I_MSG_RULEZ_RANDOM_OFF, I_MSG_RULEZ_RANDOM_ON, False);
+  end
   else if cmd = 'g_weaponstay' then
   begin
     ParseGameFlag(GAME_OPTION_WEAPONSTAY, I_MSG_WEAPONSTAY_OFF, I_MSG_WEAPONSTAY_ON);
@@ -5490,6 +5630,14 @@ begin
   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);
@@ -5566,6 +5714,21 @@ begin
     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 = 'g_powerup_time_multiplier' then
+  begin
+    if Length(P) > 1 then
+    begin
+      gsRulezTimeMultiplier := nclamp(StrToIntDef(P[1], gsRulezTimeMultiplier), 0, $FFFF);
+      if g_Game_IsServer then
+      begin
+        gGameSettings.RulezTimeMultiplier := gsRulezTimeMultiplier;
+        if g_Game_IsNet then MH_SEND_GameSettings;
+      end;
+    end;
+
+    g_Console_Add(Format('%s %d', [cmd, Integer(gsRulezTimeMultiplier)]));
+    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
@@ -5577,7 +5740,7 @@ begin
   begin
     if Length(p) = 2 then
     begin
-      a := Max(0, StrToInt(p[1]));
+      a := Max(0, StrToIntDef(p[1], 0));
       g_GFX_SetMax(a)
     end
     else if Length(p) = 1 then
@@ -5593,7 +5756,7 @@ begin
   begin
     if Length(p) = 2 then
     begin
-      a := Max(0, StrToInt(p[1]));
+      a := Max(0, StrToIntDef(p[1], 0));
       g_Shells_SetMax(a)
     end
     else if Length(p) = 1 then
@@ -5609,7 +5772,7 @@ begin
   begin
     if Length(p) = 2 then
     begin
-      a := Max(0, StrToInt(p[1]));
+      a := Max(0, StrToIntDef(p[1], 0));
       g_Gibs_SetMax(a)
     end
     else if Length(p) = 1 then
@@ -5625,7 +5788,7 @@ begin
   begin
     if Length(p) = 2 then
     begin
-      a := Max(0, StrToInt(p[1]));
+      a := Max(0, StrToIntDef(p[1], 0));
       g_Corpses_SetMax(a)
     end
     else if Length(p) = 1 then
@@ -5637,11 +5800,69 @@ 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);
+      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 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
+  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 (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
+    end
+  end
   else if cmd = 'g_scorelimit' then
   begin
     if Length(P) > 1 then
     begin
-      gsGoalLimit := nclamp(StrToIntDef(P[1], gsGoalLimit), 0, $FFFF);
+      gsScoreLimit := nclamp(StrToIntDef(P[1], gsScoreLimit), 0, $FFFF);
 
       if g_Game_IsServer then
       begin
@@ -5655,17 +5876,17 @@ begin
                 b := stat[a].Frags;
         end
         else // TDM/CTF
-          b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
+          b := Max(gTeamStat[TEAM_RED].Score, gTeamStat[TEAM_BLUE].Score);
 
         // if someone has a higher score, set it to that instead
-        gsGoalLimit := max(gsGoalLimit, b);
-        gGameSettings.GoalLimit := gsGoalLimit;
+        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(gsGoalLimit)]));
+    g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [Integer(gsScoreLimit)]));
   end
   else if cmd = 'g_timelimit' then
   begin
@@ -5683,6 +5904,12 @@ begin
                          (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
@@ -5702,6 +5929,17 @@ end;
 procedure PlayerSettingsCVars(P: SSArray);
 var
   cmd: string;
+  team: Byte;
+
+  function ParseTeam(s: string): Byte;
+  begin
+    result := 0;
+    case s of
+      'red', '1':  result := TEAM_RED;
+      'blue', '2': result := TEAM_BLUE;
+      else         result := TEAM_NONE;
+    end;
+  end;
 begin
   cmd := LowerCase(P[0]);
   case cmd of
@@ -5795,6 +6033,184 @@ begin
           end;
         end;
       end;
+    'p1_team':
+      begin
+        // TODO: switch teams if in game or store this separately
+        if (Length(P) > 1) then
+        begin
+          team := ParseTeam(P[1]);
+          if team = TEAM_NONE then
+            g_Console_Add('expected ''red'', ''blue'', 1 or 2')
+          else if not gGameOn and not g_Game_IsNet then
+            gPlayer1Settings.Team := team
+          else
+            g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
+        end;
+      end;
+    'p2_team':
+      begin
+        // TODO: switch teams if in game or store this separately
+        if (Length(P) > 1) then
+        begin
+          team := ParseTeam(P[1]);
+          if team = TEAM_NONE then
+            g_Console_Add('expected ''red'', ''blue'', 1 or 2')
+          else if not gGameOn and not g_Game_IsNet then
+            gPlayer2Settings.Team := team
+          else
+            g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
+        end;
+      end;
+    'p1_autoswitch':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponSwitch := EnsureRange(StrTointDef(P[1], 0), 0, 2);
+        end;
+    'p2_autoswitch':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponSwitch := EnsureRange(StrTointDef(P[1], 0), 0, 2);
+        end;
+    'p1_switch_empty':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.SwitchToEmpty := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+        end;
+    'p2_switch_empty':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.SwitchToEmpty := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+        end;
+    'p1_skip_fist':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.SkipFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+        end;
+    'p2_skip_fist':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.SkipFist := EnsureRange(StrTointDef(P[1], 0), 0, 1);
+        end;
+    'p1_priority_kastet':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+        end;
+    'p2_priority_kastet':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_KASTET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_saw':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_SAW] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+        end;
+    'p2_priority_saw':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_SAW] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_pistol':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_KASTET] := 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;
+    'p1_priority_shotgun1':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_SHOTGUN1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_shotgun1':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_SHOTGUN1] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_shotgun2':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_SHOTGUN2] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_shotgun2':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_SHOTGUN2] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_chaingun':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_CHAINGUN] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_chaingun':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_CHAINGUN] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_rocketlauncher':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_ROCKETLAUNCHER] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_rocketlauncher':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_ROCKETLAUNCHER] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_plasma':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_PLASMA] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_plasma':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_PLASMA] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_bfg':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_BFG] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_bfg':
+      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':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_SUPERPULEMET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_super':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_SUPERPULEMET] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p1_priority_flamethrower':
+      begin
+        if (Length(P) = 2) then
+          gPlayer1Settings.WeaponPreferences[WEAPON_FLAMETHROWER] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      end;
+    'p2_priority_flamethrower':
+      begin
+        if (Length(P) = 2) then
+          gPlayer2Settings.WeaponPreferences[WEAPON_FLAMETHROWER] := EnsureRange(StrToIntDef(P[1], WP_FIRST), WP_FIRST, WP_LAST+1);
+      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);
+        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;
   end;
 end;
 
@@ -6167,6 +6583,7 @@ var
   nm: Boolean;
   listen: LongWord;
   found: Boolean;
+  t: Byte;
 begin
 // Îáùèå êîìàíäû:
   cmd := LowerCase(P[0]);
@@ -6211,7 +6628,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();
@@ -6255,7 +6672,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();
@@ -6264,6 +6681,34 @@ begin
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
+  else if cmd = 'kick_pid' then
+  begin
+    if g_Game_IsServer and g_Game_IsNet then
+    begin
+      if Length(P) < 2 then
+      begin
+        g_Console_Add('kick_pid <player ID>');
+        Exit;
+      end;
+      if P[1] = '' then
+      begin
+        g_Console_Add('kick_pid <player ID>');
+        Exit;
+      end;
+
+      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_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();
+      end;
+    end else
+      g_Console_Add(_lc[I_MSG_SERVERONLY]);
+  end
   else if cmd = 'ban' then
   begin
     if g_Game_IsServer and g_Game_IsNet then
@@ -6281,14 +6726,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]);
@@ -6311,14 +6750,29 @@ 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
+  else if cmd = 'ban_pid' then
+  begin
+    if g_Game_IsServer and g_Game_IsNet then
+    begin
+      if Length(P) < 2 then
+      begin
+        g_Console_Add('ban_pid <player ID>');
+        Exit;
+      end;
+      if P[1] = '' then
+      begin
+        g_Console_Add('ban_pid <player ID>');
+        Exit;
+      end;
+
+      a := StrToIntDef(P[1], 0);
+      pl := g_Net_Client_ByPlayer(a);
+      if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then
+        g_Net_Host_Ban(pl, False);
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6339,15 +6793,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]);
@@ -6370,15 +6817,50 @@ 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
+  else if cmd = 'permban_pid' then
+  begin
+    if g_Game_IsServer and g_Game_IsNet then
+    begin
+      if Length(P) < 2 then
+      begin
+        g_Console_Add('permban_pid <player ID>');
+        Exit;
+      end;
+      if P[1] = '' then
+      begin
+        g_Console_Add('permban_pid <player ID>');
+        Exit;
+      end;
+
+      a := StrToIntDef(P[1], 0);
+      pl := g_Net_Client_ByPlayer(a);
+      if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then
+        g_Net_Host_Ban(pl, True);
+    end else
+      g_Console_Add(_lc[I_MSG_SERVERONLY]);
+  end
+  else if cmd = 'permban_ip' then
+  begin
+    if g_Game_IsServer and g_Game_IsNet then
+    begin
+      if Length(P) < 2 then
+      begin
+        g_Console_Add('permban_ip <IP address>');
+        Exit;
+      end;
+      if P[1] = '' then
+      begin
+        g_Console_Add('permban_ip <IP address>');
+        Exit;
+      end;
+
+      g_Net_BanAddress(P[1]);
+      g_Net_SaveBanList();
+      g_Console_Add(Format(_lc[I_PLAYER_BAN], [P[1]]));
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
   end
@@ -6397,7 +6879,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();
@@ -6477,23 +6959,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
@@ -6555,6 +7043,34 @@ begin
     end else
       g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
   end
+  else if (cmd = 'an') or (cmd = 'announce') then
+  begin
+    if g_Game_IsNet then
+    begin
+      if Length(P) > 1 then
+      begin
+        for a := 1 to High(P) do
+          chstr := chstr + P[a] + ' ';
+
+        if Length(chstr) > 200 then SetLength(chstr, 200);
+
+        if Length(chstr) < 1 then
+        begin
+          g_Console_Add('announce <text>');
+          Exit;
+        end;
+
+        chstr := 'centerprint 100 ' + b_Text_Format(chstr);
+        if g_Game_IsClient then
+          MC_SEND_RCONCommand(chstr)
+        else
+          g_Console_Process(chstr, True);
+      end
+      else
+        g_Console_Add('announce <text>');
+    end else
+      g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
+  end
   else if cmd = 'game' then
   begin
     if gGameSettings.GameType <> GT_NONE then
@@ -6590,6 +7106,7 @@ begin
         g_Game_Free();
         with gGameSettings do
         begin
+          Options := gsGameFlags;
           GameMode := g_Game_TextToMode(gsGameMode);
           if gSwitchGameMode <> GM_NONE then
             GameMode := gSwitchGameMode;
@@ -6599,7 +7116,7 @@ begin
           if Length(P) >= 4 then
             b := StrToIntDef(P[3], 1);
           g_Game_StartCustom(s, GameMode, TimeLimit,
-                             GoalLimit, MaxLives, Options, b);
+                             ScoreLimit, MaxLives, Options, b);
         end;
       end
       else
@@ -6644,6 +7161,7 @@ begin
         g_Game_Free();
         with gGameSettings do
         begin
+          Options := gsGameFlags;
           GameMode := g_Game_TextToMode(gsGameMode);
           if gSwitchGameMode <> GM_NONE then GameMode := gSwitchGameMode;
           if GameMode = GM_NONE then GameMode := GM_DM;
@@ -6651,7 +7169,7 @@ begin
           b := 0;
           if Length(P) >= 6 then
             b := StrToIntDef(P[5], 0);
-          g_Game_StartServer(s, GameMode, TimeLimit, GoalLimit, MaxLives, Options, b, listen, prt)
+          g_Game_StartServer(s, GameMode, TimeLimit, ScoreLimit, MaxLives, Options, b, listen, prt)
         end
       end
       else
@@ -6681,6 +7199,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
@@ -6808,6 +7330,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;
@@ -6997,25 +7523,72 @@ begin
   begin
     g_TakeScreenShot()
   end
+  else if (cmd = 'weapnext') or (cmd = 'weapprev') then
+  begin
+    a := 1 - (ord(cmd[5]) - ord('n'));
+    if a = -1 then
+      gWeaponAction[0, WP_PREV] := True;
+    if a = 1 then
+      gWeaponAction[0, WP_NEXT] := True;
+  end
   else if cmd = 'weapon' then
   begin
     if Length(p) = 2 then
     begin
-      a := WP_FIRST + StrToInt(p[1]) - 1;
+      a := WP_FIRST + StrToIntDef(p[1], 0) - 1;
       if (a >= WP_FIRST) and (a <= WP_LAST) then
         gSelectWeapon[0, a] := True
     end
   end
+  else if (cmd = 'p1_weapnext') or (cmd = 'p1_weapprev')
+       or (cmd = 'p2_weapnext') or (cmd = 'p2_weapprev') then
+  begin
+    a := 1 - (ord(cmd[8]) - ord('n'));
+    b := ord(cmd[2]) - ord('1');
+    if a = -1 then
+      gWeaponAction[b, WP_PREV] := True;
+    if a = 1 then
+      gWeaponAction[b, WP_NEXT] := True;
+  end
   else if (cmd = 'p1_weapon') or (cmd = 'p2_weapon') then
   begin
     if Length(p) = 2 then
     begin
-      a := WP_FIRST + StrToInt(p[1]) - 1;
+      a := WP_FIRST + StrToIntDef(p[1], 0) - 1;
       b := ord(cmd[2]) - ord('1');
       if (a >= WP_FIRST) and (a <= WP_LAST) then
         gSelectWeapon[b, a] := True
     end
   end
+  else if (cmd = 'p1_weapbest') or (cmd = 'p2_weapbest') then
+  begin
+    b := ord(cmd[2]) - ord('1');
+    if b = 0 then
+      gSelectWeapon[b, gPlayer1.GetMorePrefered()] := True
+    else
+      gSelectWeapon[b, gPlayer2.GetMorePrefered()] := True;
+  end
+  else if (cmd = 'dropflag') then
+  begin
+    if g_Game_IsServer then
+    begin
+      if gPlayer2 <> nil then gPlayer2.TryDropFlag();
+      if gPlayer1 <> nil then gPlayer1.TryDropFlag();
+    end
+    else
+      MC_SEND_CheatRequest(NET_CHEAT_DROPFLAG);
+  end
+  else if (cmd = 'p1_dropflag') or (cmd = 'p2_dropflag') then
+  begin
+    b := ord(cmd[2]) - ord('1');
+    if g_Game_IsServer then
+    begin
+      if (b = 1) and (gPlayer2 <> nil) then gPlayer2.TryDropFlag()
+      else if (b = 0) and (gPlayer1 <> nil) then gPlayer1.TryDropFlag();
+    end
+    else
+      MC_SEND_CheatRequest(NET_CHEAT_DROPFLAG);
+  end
 // Êîìàíäû Ñâîåé èãðû:
   else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
   begin
@@ -7224,7 +7797,6 @@ end;
 procedure SystemCommands(P: SSArray);
 var
   cmd: string;
-  a: Integer;
 begin
   cmd := LowerCase(P[0]);
   case cmd of
@@ -7302,11 +7874,11 @@ begin
       DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t);
       Filename := 'screenshot-' + date;
     end;
-    
+
     name := e_CatPath(dir, Filename + '.png');
     s := createDiskFile(name);
     try
-      e_MakeScreenshot(s, gScreenWidth, gScreenHeight);
+      e_MakeScreenshot(s, gWinSizeX, gWinSizeY);
       s.Free;
       g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [name]))
     except
@@ -7643,8 +8215,7 @@ begin
   case gAnnouncer of
     ANNOUNCE_NONE:
       Exit;
-    ANNOUNCE_ME,
-    ANNOUNCE_MEPLUS:
+    ANNOUNCE_ME:
       if not g_Game_IsWatchedPlayer(SpawnerUID) then
         Exit;
   end;
@@ -7655,6 +8226,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;
@@ -7800,8 +8379,7 @@ begin
   end;
 
   g_ActiveWindow := nil;
-
-  ProcessLoading(true);
+  ProcessLoading(True);
 end;
 
 procedure g_Game_StepLoading(Value: Integer = -1);
@@ -7815,10 +8393,11 @@ begin
     end
     else
       CurValue := Value;
+
     if (ShowCount > LOADING_SHOW_STEP) or (Value > -1) then
     begin
       ShowCount := 0;
-      ProcessLoading();
+      ProcessLoading(False);
     end;
   end;
 end;
@@ -7852,9 +8431,9 @@ begin
   while i <= ParamCount do
   begin
     s := ParamStr(i);
-    if (s[1] = '-') and (Length(s) > 1) then
+    if (Length(s) > 1) and (s[1] = '-') then
     begin
-      if (s[2] = '-') and (Length(s) > 2) then
+      if (Length(s) > 2) and (s[2] = '-') then
         begin // Îäèíî÷íûé ïàðàìåòð
           SetLength(pars, Length(pars) + 1);
           with pars[High(pars)] do
@@ -7962,7 +8541,7 @@ begin
     if LimT < 0 then
       LimT := 0;
 
-  // Goal limit:
+  // Score limit:
     s := Find_Param_Value(pars, '-lims');
     if (s = '') or (not TryStrToInt(s, LimS)) then
       LimS := 0;
@@ -7979,8 +8558,7 @@ begin
   // Options:
     s := Find_Param_Value(pars, '-opt');
     if (s = '') then
-      Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or
-        GAME_OPTION_BOTVSMONSTER or GAME_OPTION_DMKEYS
+      Opt := gsGameFlags
     else
       Opt := StrToIntDef(s, 0);
 
@@ -8106,9 +8684,10 @@ begin
   conRegVar('r_showfps', @gShowFPS, 'draw fps counter', 'draw fps counter');
   conRegVar('r_showtime', @gShowTime, 'show game time', 'show game time');
   conRegVar('r_showping', @gShowPing, 'show ping', 'show ping');
-  conRegVar('r_showscore', @gShowGoals, 'show score', 'show score');
+  conRegVar('r_showscore', @gShowScore, 'show score', 'show score');
   conRegVar('r_showkillmsg', @gShowKillMsg, 'show kill log', 'show kill log');
   conRegVar('r_showlives', @gShowLives, 'show lives', 'show lives');
   conRegVar('r_showspect', @gSpectHUD, 'show spectator hud', 'show spectator hud');
   conRegVar('r_showstat', @gShowStat, 'show stats', 'show stats');
+  conRegVar('r_showpids', @gShowPIDs, 'show PIDs', 'show PIDs');
 end.