DEADSOFTWARE

panels: handle panel animation in render (bump protocol)
[d2df-sdl.git] / src / game / g_netmsg.pas
index 3590bd43add3c68343b3c1535fe6d9b37cc5dee6..4ada39477e8bf9ee37c7a738029786fce98211a4 100644 (file)
@@ -181,7 +181,7 @@ procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYON
 procedure MH_SEND_ItemDestroy(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
 procedure MH_SEND_ItemPos(IID: Word; ID: Integer = NET_EVERYONE);
 // PANEL
-procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; ID: Integer = NET_EVERYONE);
 procedure MH_SEND_PanelState(PGUID: Integer; ID: Integer = NET_EVERYONE);
 // MONSTER
 procedure MH_SEND_MonsterSpawn(UID: Word; ID: Integer = NET_EVERYONE);
@@ -283,11 +283,27 @@ function IsValidFilePath(const S: String): Boolean;
 
 implementation
 
-uses
-  Math, ENet, e_input, e_graphics, e_log,
-  g_textures, g_gfx, g_sound, g_console, g_basic, g_options, g_main,
-  g_game, g_player, g_map, g_panel, g_items, g_weapons, g_phys, g_gui,
-  g_language, g_monsters, g_netmaster, utils, wadreader, MAPDEF;
+  uses
+    {$IFDEF ENABLE_MENU}
+      g_gui,
+    {$ENDIF}
+    {$IFDEF ENABLE_GFX}
+      g_gfx,
+    {$ENDIF}
+    {$IFDEF ENABLE_GIBS}
+      g_gibs,
+    {$ENDIF}
+    {$IFDEF ENABLE_SHELLS}
+      g_shells,
+    {$ENDIF}
+    {$IFDEF ENABLE_CORPSES}
+      g_corpses,
+    {$ENDIF}
+    Math, ENet, e_input, e_log, g_base, g_basic,
+    g_sound, g_console, g_options,
+    g_game, g_player, g_map, g_panel, g_items, g_weapons, g_phys,
+    g_language, g_monsters, g_netmaster, utils, wadreader, MAPDEF
+  ;
 
 const
   NET_KEY_LEFT     = 1 shl 0;
@@ -341,7 +357,7 @@ procedure MH_MalformedPacket(C: pTNetClient);
 begin
   g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_HOST_REJECT] +
     _lc[I_NET_DISC_PROTOCOL]);
-  enet_peer_disconnect(C^.Peer, NET_DISC_PROTOCOL);
+  g_Net_Host_Kick(C^.ID, NET_DISC_PROTOCOL);
 end;
 
 procedure MH_RECV_Chat(C: pTNetClient; var M: TMsg);
@@ -380,6 +396,10 @@ procedure MH_RECV_Info(C: pTNetClient; var M: TMsg);
 var
   Ver, PName, Model, Pw: string;
   R, G, B, T: Byte;
+  WeapSwitch: Byte;
+  TmpPrefArray: Array [WP_FIRST .. WP_LAST + 1] of Byte;
+  SwitchEmpty: Byte;
+  SkipF: Byte;
   PID: Word;
   Color: TRGB;
   I: Integer;
@@ -395,6 +415,11 @@ begin
     G := M.ReadByte();
     B := M.ReadByte();
     T := M.ReadByte();
+    WeapSwitch := M.ReadByte();
+    for I := WP_FIRST to WP_LAST + 1 do
+      TmpPrefArray[I] := M.ReadByte();
+    SwitchEmpty := M.ReadByte();
+    SkipF := M.ReadByte();
   except
     Err := True;
   end;
@@ -405,7 +430,7 @@ begin
   begin
     g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_HOST_REJECT] +
       _lc[I_NET_DISC_VERSION]);
-    enet_peer_disconnect(C^.Peer, NET_DISC_VERSION);
+    g_Net_Host_Kick(C^.ID, NET_DISC_VERSION);
     Exit;
   end;
 
@@ -415,13 +440,13 @@ begin
     begin
       g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_HOST_REJECT] +
         _lc[I_NET_DISC_BAN]);
-      enet_peer_disconnect(C^.Peer, NET_DISC_BAN);
+      g_Net_Host_Kick(C^.ID, NET_DISC_BAN);
     end
     else
     begin
       g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_HOST_REJECT] +
         _lc[I_NET_DISC_BAN]);
-      enet_peer_disconnect(C^.Peer, NET_DISC_TEMPBAN);
+      g_Net_Host_Kick(C^.ID, NET_DISC_TEMPBAN);
     end;
     Exit;
   end;
@@ -431,7 +456,7 @@ begin
     begin
       g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_HOST_REJECT] +
         _lc[I_NET_DISC_PASSWORD]);
-      enet_peer_disconnect(C^.Peer, NET_DISC_PASSWORD);
+      g_Net_Host_Kick(C^.ID, NET_DISC_PASSWORD);
       Exit;
     end;
 
@@ -450,11 +475,18 @@ begin
   with g_Player_Get(PID) do
   begin
     Name := PName;
+    WeapSwitchMode := WeapSwitch;
+    SetWeaponPrefs(TmpPrefArray);
+    SwitchToEmpty := SwitchEmpty;
+    SkipFist := SkipF;
+    if (g_Force_Model_Get() <> 0) then
+      SetModel(g_Forced_Model_GetName());
     Reset(True);
   end;
 
   C^.Player := PID;
   C^.WaitForFirstSpawn := false;
+  C^.AuthTime := 0;
 
   g_Console_Add(Format(_lc[I_PLAYER_JOIN], [PName]), True);
   e_WriteLog('NET: Client ' + PName + ' [' + IntToStr(C^.ID) +
@@ -541,6 +573,14 @@ end;
 procedure MH_RECV_FullStateRequest(C: pTNetClient; var M: TMsg);
 begin
   //e_LogWritefln('*** client #%u (cid #%u) full state request', [C.ID, C.Player]);
+
+  if C^.FullUpdateSent then
+  begin
+    // FullStateRequest spam?
+    g_Net_Penalize(C, 'duplicate full state request');
+    exit;
+  end;
+
   if gGameOn then
   begin
     MH_SEND_Everything((C^.State = NET_STATE_AUTH), C^.ID)
@@ -699,6 +739,11 @@ var
   TmpModel: string;
   TmpColor: TRGB;
   TmpTeam: Byte;
+  TmpWeapSwitch: Byte;
+  TmpPrefArray: Array [WP_FIRST .. WP_LAST + 1] of Byte;
+  TmpSwEmpty: Byte;
+  TmpSkipF: Byte;
+  I: Integer;
   Pl: TPlayer;
   Err: Boolean;
 begin
@@ -710,6 +755,11 @@ begin
     TmpColor.G := M.ReadByte();
     TmpColor.B := M.ReadByte();
     TmpTeam := M.ReadByte();
+    TmpWeapSwitch := M.ReadByte();
+    for I := WP_FIRST to WP_LAST + 1 do
+      TmpPrefArray[I] := M.ReadByte();
+    TmpSwEmpty := M.ReadByte();
+    TmpSkipF := M.ReadByte();
   except
     Err := True;
   end;
@@ -730,9 +780,21 @@ begin
     Pl.Name := TmpName;
   end;
 
-  if TmpModel <> Pl.Model.Name then
+  if (g_Force_Model_Get() <> 0) then
+    TmpModel := g_Forced_Model_GetName();
+  if TmpModel <> Pl.Model.GetName() then
     Pl.SetModel(TmpModel);
 
+  if (TmpWeapSwitch <> Pl.WeapSwitchMode) then
+    Pl.WeapSwitchMode := TmpWeapSwitch;
+
+  Pl.SetWeaponPrefs(TmpPrefArray);
+  if (TmpSwEmpty <> Pl.SwitchToEmpty) then
+    Pl.SwitchToEmpty := TmpSwEmpty;
+
+  if (TmpSkipF <> Pl.SkipFist) then
+    Pl.SkipFist := TmpSkipF;
+
   MH_SEND_PlayerSettings(Pl.UID, TmpModel);
 end;
 
@@ -854,17 +916,20 @@ procedure MH_SEND_Everything(CreatePlayers: Boolean {= False}; ID: Integer {= NE
   begin
     result := false; // don't stop
     MH_SEND_PanelState(pan.guid, ID); // anyway, to sync mplats
-    if (pan.CanChangeTexture) then MH_SEND_PanelTexture(pan.guid, pan.LastAnimLoop, ID);
+    if (pan.CanChangeTexture) then MH_SEND_PanelTexture(pan.guid, ID);
   end;
 
 var
   I: Integer;
 begin
-  if (ID >= 0) and (ID < length(NetClients)) then
-  begin
-    e_LogWritefln('*** client #%u (cid #%u) will get everything', [ID, NetClients[ID].Player]);
-    MH_ProcessFirstSpawn(@NetClients[ID]);
-  end;
+  if (ID < 0) or (ID >= Length(NetClients)) then
+    exit; // bogus client, this shouldn't happen
+
+  NetClients[ID].FullUpdateSent := True;
+
+  e_LogWritefln('*** client #%u (cid #%u) will get everything', [ID, NetClients[ID].Player]);
+
+  MH_ProcessFirstSpawn(@NetClients[ID]);
 
   if gPlayers <> nil then
   begin
@@ -937,7 +1002,7 @@ begin
   NetOut.Write(g_ExtractFileName(gMapInfo.Map));
   NetOut.Write(gWADHash);
   NetOut.Write(gGameSettings.GameMode);
-  NetOut.Write(gGameSettings.GoalLimit);
+  NetOut.Write(gGameSettings.ScoreLimit);
   NetOut.Write(gGameSettings.TimeLimit);
   NetOut.Write(gGameSettings.MaxLives);
   NetOut.Write(gGameSettings.Options);
@@ -1091,8 +1156,8 @@ begin
   NetOut.Write(Byte(NET_MSG_SCORE));
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
-    NetOut.Write(gTeamStat[TEAM_RED].Goals);
-    NetOut.Write(gTeamStat[TEAM_BLUE].Goals);
+    NetOut.Write(gTeamStat[TEAM_RED].Score);
+    NetOut.Write(gTeamStat[TEAM_BLUE].Score);
   end
   else
     if gGameSettings.GameMode = GM_COOP then
@@ -1167,7 +1232,7 @@ procedure MH_SEND_GameSettings(ID: Integer = NET_EVERYONE);
 begin
   NetOut.Write(Byte(NET_MSG_GSET));
   NetOut.Write(gGameSettings.GameMode);
-  NetOut.Write(gGameSettings.GoalLimit);
+  NetOut.Write(gGameSettings.ScoreLimit);
   NetOut.Write(gGameSettings.TimeLimit);
   NetOut.Write(gGameSettings.MaxLives);
   NetOut.Write(gGameSettings.Options);
@@ -1357,7 +1422,7 @@ begin
   NetOut.Write(PID);
   NetOut.Write(Pl.Name);
   if Mdl = '' then
-    NetOut.Write(Pl.Model.Name)
+    NetOut.Write(Pl.Model.GetName())
   else
     NetOut.Write(Mdl);
   NetOut.Write(Pl.FColor.R);
@@ -1420,22 +1485,18 @@ end;
 
 // PANEL
 
-procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; ID: Integer = NET_EVERYONE);
 var
   TP: TPanel;
 begin
   TP := g_Map_PanelByGUID(PGUID);
   if (TP = nil) then exit;
 
-  with TP do
-  begin
-    NetOut.Write(Byte(NET_MSG_PTEX));
-    NetOut.Write(LongWord(PGUID));
-    NetOut.Write(FCurTexture);
-    NetOut.Write(FCurFrame);
-    NetOut.Write(FCurFrameCount);
-    NetOut.Write(AnimLoop);
-  end;
+  NetOut.Write(Byte(NET_MSG_PTEX));
+  NetOut.Write(LongWord(PGUID));
+  NetOut.Write(TP.FCurTexture);
+  NetOut.Write(TP.AnimTime);
+  NetOut.Write(TP.LastAnimLoop);
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
@@ -1674,8 +1735,6 @@ var
   Kind: Byte;
   X, Y: Integer;
   Ang: SmallInt;
-  Anim: TAnimation;
-  ID: LongWord;
 begin
   if not gGameOn then Exit;
   Kind := M.ReadByte();
@@ -1685,90 +1744,75 @@ begin
 
   case Kind of
     NET_GFX_SPARK:
-      g_GFX_Spark(X, Y, 2 + Random(2), Ang, 0, 0);
-
+    begin
+      {$IFDEF ENABLE_GFX}
+        g_GFX_Spark(X, Y, 2 + Random(2), Ang, 0, 0);
+      {$ENDIF}
+    end;
     NET_GFX_TELE:
     begin
-      if g_Frames_Get(ID, 'FRAMES_TELEPORT') then
-      begin
-        Anim := TAnimation.Create(ID, False, 3);
-        g_GFX_OnceAnim(X, Y, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_TELEPORT_FAST, X, Y);
+      {$ENDIF}
       if Ang = 1 then
         g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y);
     end;
-
     NET_GFX_EXPLODE:
     begin
-      if g_Frames_Get(ID, 'FRAMES_EXPLODE_ROCKET') then
-      begin
-        Anim := TAnimation.Create(ID, False, 6);
-        Anim.Blending := False;
-        g_GFX_OnceAnim(X-64, Y-64, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_EXPLODE_ROCKET, X - 64, Y - 64);
+      {$ENDIF}
       if Ang = 1 then
         g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEROCKET', X, Y);
     end;
-
     NET_GFX_BFGEXPL:
     begin
-      if g_Frames_Get(ID, 'FRAMES_EXPLODE_BFG') then
-      begin
-        Anim := TAnimation.Create(ID, False, 6);
-        Anim.Blending := False;
-        g_GFX_OnceAnim(X-64, Y-64, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_EXPLODE_BFG, X - 64, Y - 64);
+      {$ENDIF}
       if Ang = 1 then
         g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', X, Y);
     end;
-
     NET_GFX_BFGHIT:
     begin
-      if g_Frames_Get(ID, 'FRAMES_BFGHIT') then
-      begin
-        Anim := TAnimation.Create(ID, False, 4);
-        g_GFX_OnceAnim(X-32, Y-32, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_BFG_HIT, X - 32, Y - 32);
+      {$ENDIF}
     end;
-
     NET_GFX_FIRE:
     begin
-      if g_Frames_Get(ID, 'FRAMES_FIRE') then
-      begin
-        Anim := TAnimation.Create(ID, False, 4);
-        g_GFX_OnceAnim(X, Y, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_FIRE, X, Y);
+      {$ENDIF}
       if Ang = 1 then
         g_Sound_PlayExAt('SOUND_FIRE', X, Y);
     end;
-
     NET_GFX_RESPAWN:
     begin
-      if g_Frames_Get(ID, 'FRAMES_ITEM_RESPAWN') then
-      begin
-        Anim := TAnimation.Create(ID, False, 4);
-        g_GFX_OnceAnim(X, Y, Anim);
-        Anim.Free();
-      end;
+      {$IFDEF ENABLE_GFX}
+        g_GFX_QueueEffect(R_GFX_ITEM_RESPAWN, X, Y);
+      {$ENDIF}
       if Ang = 1 then
         g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
     end;
-
     NET_GFX_SHELL1:
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_BULLET);
-
+    begin
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_BULLET);
+      {$ENDIF}
+    end;
     NET_GFX_SHELL2:
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
-
+    begin
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+      {$ENDIF}
+    end;
     NET_GFX_SHELL3:
     begin
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
-      g_Player_CreateShell(X, Y, 0, -2, SHELL_SHELL);
+      {$IFDEF ENABLE_SHELLS}
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+        g_Shells_Create(X, Y, 0, -2, SHELL_SHELL);
+      {$ENDIF}
     end;
   end;
 end;
@@ -1854,8 +1898,8 @@ procedure MC_RECV_GameStats(var M: TMsg);
 begin
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
-    gTeamStat[TEAM_RED].Goals := M.ReadSmallInt();
-    gTeamStat[TEAM_BLUE].Goals := M.ReadSmallInt();
+    gTeamStat[TEAM_RED].Score := M.ReadSmallInt();
+    gTeamStat[TEAM_BLUE].Score := M.ReadSmallInt();
   end
   else
     if gGameSettings.GameMode = GM_COOP then
@@ -2094,7 +2138,15 @@ begin
 
     NET_EV_LMS_START:
     begin
-      g_Player_RemoveAllCorpses;
+      {$IFDEF ENABLE_GIBS}
+        g_Gibs_RemoveAll;
+      {$ENDIF}
+      {$IFDEF ENALBE_SHELLS}
+        g_Shells_RemoveAll;
+      {$ENDIF}
+      {$IFDEF ENABLE_CORPSES}
+        g_Corpses_RemoveAll;
+      {$ENDIF}
       gLMSRespawn := LMS_RESPAWN_NONE;
       g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
     end;
@@ -2320,7 +2372,7 @@ end;
 procedure MC_RECV_GameSettings(var M: TMsg);
 begin
   gGameSettings.GameMode := M.ReadByte();
-  gGameSettings.GoalLimit := M.ReadWord();
+  gGameSettings.ScoreLimit := M.ReadWord();
   gGameSettings.TimeLimit := M.ReadWord();
   gGameSettings.MaxLives := M.ReadByte();
   gGameSettings.Options := M.ReadLongWord();
@@ -2350,6 +2402,8 @@ begin
   if (PID <> NetPlrUID1) and (PID <> NetPlrUID2) then
   begin
     if (Pl <> nil) then Exit;
+    if (g_Force_Model_Get() <> 0) then
+      Model := g_Forced_Model_GetName();
     DID := g_Player_Create(Model, Color, T, False);
     with g_Player_Get(DID) do
     begin
@@ -2644,6 +2698,7 @@ procedure MC_RECV_PlayerSettings(var M: TMsg);
 var
   TmpName: string;
   TmpModel: string;
+  CheckModel: string;
   TmpColor: TRGB;
   TmpTeam: Byte;
   Pl: TPlayer;
@@ -2677,7 +2732,9 @@ begin
     Pl.Name := TmpName;
   end;
 
-  if TmpModel <> Pl.Model.Name then
+  if (g_Force_Model_Get() <> 0) then
+    TmpModel := g_Forced_Model_GetName();
+  if TmpModel <> Pl.Model.GetName() then
     Pl.SetModel(TmpModel);
 end;
 
@@ -2686,11 +2743,9 @@ end;
 procedure MC_RECV_ItemSpawn(var M: TMsg);
 var
   ID: Word;
-  AID: DWord;
   X, Y, VX, VY: Integer;
   T: Byte;
   Quiet, Fall{, Resp}: Boolean;
-  Anim: TAnimation;
   it: PItem;
 begin
   if not gGameOn then Exit;
@@ -2714,12 +2769,9 @@ begin
   if not Quiet then
   begin
     g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
-    if g_Frames_Get(AID, 'FRAMES_ITEM_RESPAWN') then
-    begin
-      Anim := TAnimation.Create(AID, False, 4);
-      g_GFX_OnceAnim(X+(it.Obj.Rect.Width div 2)-16, Y+(it.Obj.Rect.Height div 2)-16, Anim);
-      Anim.Free();
-    end;
+    {$IFDEF ENABLE_GFX}
+      g_GFX_QueueEffect(R_GFX_ITEM_RESPAWN, X+(it.Obj.Rect.Width div 2)-16, Y+(it.Obj.Rect.Height div 2)-16);
+    {$ENDIF}
   end;
 end;
 
@@ -2767,18 +2819,13 @@ end;
 // PANEL
 
 procedure MC_RECV_PanelTexture(var M: TMsg);
-var
-  TP: TPanel;
-  PGUID: Integer;
-  Tex, Fr: Integer;
-  Loop, Cnt: Byte;
+  var TP: TPanel; PGUID, Tex: Integer; AnimTime: LongWord; Loop: Byte;
 begin
   if not gGameOn then Exit;
 
   PGUID := Integer(M.ReadLongWord());
   Tex := M.ReadLongInt();
-  Fr := M.ReadLongInt();
-  Cnt := M.ReadByte();
+  AnimTime := M.ReadLongWord();
   Loop := M.ReadByte();
 
   TP := g_Map_PanelByGUID(PGUID);
@@ -2786,7 +2833,7 @@ begin
   begin
     // switch texture
     TP.SetTexture(Tex, Loop);
-    TP.SetFrame(Fr, Cnt);
+    TP.SetFrame(AnimTime);
   end;
 end;
 
@@ -3110,6 +3157,7 @@ end;
 // CLIENT SEND
 
 procedure MC_SEND_Info(Password: string);
+var i: Integer;
 begin
   NetOut.Clear();
 
@@ -3122,6 +3170,11 @@ begin
   NetOut.Write(gPlayer1Settings.Color.G);
   NetOut.Write(gPlayer1Settings.Color.B);
   NetOut.Write(gPlayer1Settings.Team);
+  NetOut.Write(gPlayer1Settings.WeaponSwitch);
+  for i := WP_FIRST to WP_LAST + 1 do
+    NetOut.Write(gPlayer1Settings.WeaponPreferences[i]);
+  NetOut.Write(gPlayer1Settings.SwitchToEmpty);
+  NetOut.Write(gPlayer1Settings.SkipFist);
 
   g_Net_Client_Send(True, NET_CHAN_SERVICE);
 end;
@@ -3151,7 +3204,11 @@ begin
   kByte := 0;
   Predict := NetPredictSelf; // and (not NetGotKeys);
 
+{$IFDEF DISABLE_MENU}
+  if (not gConsoleShow) and (not gChatShow) then
+{$ELSE}
   if (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
+{$ENDIF}
   begin
     strafeDir := P1MoveButton shr 4;
     P1MoveButton := P1MoveButton and $0F;
@@ -3261,6 +3318,7 @@ begin
 end;
 
 procedure MC_SEND_PlayerSettings();
+var i: Integer;
 begin
   NetOut.Write(Byte(NET_MSG_PLRSET));
   NetOut.Write(gPlayer1Settings.Name);
@@ -3269,6 +3327,11 @@ begin
   NetOut.Write(gPlayer1Settings.Color.G);
   NetOut.Write(gPlayer1Settings.Color.B);
   NetOut.Write(gPlayer1Settings.Team);
+  NetOut.Write(gPlayer1Settings.WeaponSwitch);
+  for i := WP_FIRST to WP_LAST + 1 do
+    NetOut.Write(gPlayer1Settings.WeaponPreferences[i]);
+  NetOut.Write(gPlayer1Settings.SwitchToEmpty);
+  NetOut.Write(gPlayer1Settings.SkipFist);
 
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;