DEADSOFTWARE

Revert "fixed weapon switching over the network; bumped protocol version"
[d2df-sdl.git] / src / game / g_netmsg.pas
index bc54015ae519443c100ec950b635f3b7412bb7b3..a7ff31a9639fe68fdf2efdae7e308b54a1683a5d 100644 (file)
@@ -1,4 +1,4 @@
-(* Copyright (C)  DooM 2D:Forever Developers
+(* Copyright (C)  Doom 2D: Forever Developers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *)
-{$MODE DELPHI}
+{$INCLUDE ../shared/a_modes.inc}
 unit g_netmsg;
 
 interface
 
-uses g_net, g_triggers, Classes, SysUtils, md5;
+uses e_msg, g_net, g_triggers, Classes, SysUtils, md5;
 
 const
   NET_MSG_INFO   = 100;
@@ -52,8 +52,8 @@ const
   NET_MSG_MSHOT  = 134;
   NET_MSG_MDEL   = 135;
 
-  NET_MSG_PSTATE = 141;
-  NET_MSG_PTEX   = 142;
+  NET_MSG_PSTATE   = 141;
+  NET_MSG_PTEX     = 142;
 
   NET_MSG_TSOUND = 151;
   NET_MSG_TMUSIC = 152;
@@ -129,17 +129,17 @@ const
 
 // HOST MESSAGES
 
-procedure MH_RECV_Info(C: pTNetClient; P: Pointer);
-procedure MH_RECV_Chat(C: pTNetClient; P: Pointer);
-procedure MH_RECV_FullStateRequest(C: pTNetClient; P: Pointer);
-function  MH_RECV_PlayerPos(C: pTNetClient; P: Pointer): Word;
-procedure MH_RECV_PlayerSettings(C: pTNetClient; P: Pointer);
-procedure MH_RECV_CheatRequest(C: pTNetClient; P: Pointer);
-procedure MH_RECV_RCONPassword(C: pTNetClient; P: Pointer);
-procedure MH_RECV_RCONCommand(C: pTNetClient; P: Pointer);
-procedure MH_RECV_MapRequest(C: pTNetClient; P: Pointer);
-procedure MH_RECV_ResRequest(C: pTNetClient; P: Pointer);
-procedure MH_RECV_Vote(C: pTNetClient; P: Pointer);
+procedure MH_RECV_Info(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_Chat(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_FullStateRequest(C: pTNetClient; var M: TMsg);
+function  MH_RECV_PlayerPos(C: pTNetClient; var M: TMsg): Word;
+procedure MH_RECV_PlayerSettings(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_CheatRequest(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_RCONPassword(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_RCONCommand(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_MapRequest(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_ResRequest(C: pTNetClient; var M: TMsg);
+procedure MH_RECV_Vote(C: pTNetClient; var M: TMsg);
 
 // GAME
 procedure MH_SEND_Everything(CreatePlayers: Boolean = False; ID: Integer = NET_EVERYONE);
@@ -168,8 +168,8 @@ procedure MH_SEND_PlayerSettings(PID: Word; Mdl: string = ''; ID: Integer = NET_
 procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
 procedure MH_SEND_ItemDestroy(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
 // PANEL
-procedure MH_SEND_PanelTexture(PType: Word; PID: LongWord; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
-procedure MH_SEND_PanelState(PType: Word; PID: LongWord; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; 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);
 procedure MH_SEND_MonsterPos(UID: Word; ID: Integer = NET_EVERYONE);
@@ -189,45 +189,45 @@ procedure MH_SEND_VoteEvent(EvType: Byte;
 // CLIENT MESSAGES //
 
 // GAME
-procedure MC_RECV_Chat(P: Pointer);
-procedure MC_RECV_Effect(P: Pointer);
-procedure MC_RECV_Sound(P: Pointer);
-procedure MC_RECV_GameStats(P: Pointer);
-procedure MC_RECV_CoopStats(P: Pointer);
-procedure MC_RECV_GameEvent(P: Pointer);
-procedure MC_RECV_FlagEvent(P: Pointer);
-procedure MC_RECV_GameSettings(P: Pointer);
+procedure MC_RECV_Chat(var M: TMsg);
+procedure MC_RECV_Effect(var M: TMsg);
+procedure MC_RECV_Sound(var M: TMsg);
+procedure MC_RECV_GameStats(var M: TMsg);
+procedure MC_RECV_CoopStats(var M: TMsg);
+procedure MC_RECV_GameEvent(var M: TMsg);
+procedure MC_RECV_FlagEvent(var M: TMsg);
+procedure MC_RECV_GameSettings(var M: TMsg);
 // PLAYER
-function  MC_RECV_PlayerCreate(P: Pointer): Word;
-function  MC_RECV_PlayerPos(P: Pointer): Word;
-function  MC_RECV_PlayerStats(P: Pointer): Word;
-function  MC_RECV_PlayerDelete(P: Pointer): Word;
-function  MC_RECV_PlayerDamage(P: Pointer): Word;
-function  MC_RECV_PlayerDeath(P: Pointer): Word;
-function  MC_RECV_PlayerFire(P: Pointer): Word;
-procedure MC_RECV_PlayerSettings(P: Pointer);
+function  MC_RECV_PlayerCreate(var M: TMsg): Word;
+function  MC_RECV_PlayerPos(var M: TMsg): Word;
+function  MC_RECV_PlayerStats(var M: TMsg): Word;
+function  MC_RECV_PlayerDelete(var M: TMsg): Word;
+function  MC_RECV_PlayerDamage(var M: TMsg): Word;
+function  MC_RECV_PlayerDeath(var M: TMsg): Word;
+function  MC_RECV_PlayerFire(var M: TMsg): Word;
+procedure MC_RECV_PlayerSettings(var M: TMsg);
 // ITEM
-procedure MC_RECV_ItemSpawn(P: Pointer);
-procedure MC_RECV_ItemDestroy(P: Pointer);
+procedure MC_RECV_ItemSpawn(var M: TMsg);
+procedure MC_RECV_ItemDestroy(var M: TMsg);
 // PANEL
-procedure MC_RECV_PanelTexture(P: Pointer);
-procedure MC_RECV_PanelState(P: Pointer);
+procedure MC_RECV_PanelTexture(var M: TMsg);
+procedure MC_RECV_PanelState(var M: TMsg);
 // MONSTER
-procedure MC_RECV_MonsterSpawn(P: Pointer);
-procedure MC_RECV_MonsterPos(P: Pointer);
-procedure MC_RECV_MonsterState(P: Pointer);
-procedure MC_RECV_MonsterShot(P: Pointer);
-procedure MC_RECV_MonsterDelete(P: Pointer);
+procedure MC_RECV_MonsterSpawn(var M: TMsg);
+procedure MC_RECV_MonsterPos(var M: TMsg);
+procedure MC_RECV_MonsterState(var M: TMsg);
+procedure MC_RECV_MonsterShot(var M: TMsg);
+procedure MC_RECV_MonsterDelete(var M: TMsg);
 // SHOT
-procedure MC_RECV_CreateShot(P: Pointer);
-procedure MC_RECV_UpdateShot(P: Pointer);
-procedure MC_RECV_DeleteShot(P: Pointer);
+procedure MC_RECV_CreateShot(var M: TMsg);
+procedure MC_RECV_UpdateShot(var M: TMsg);
+procedure MC_RECV_DeleteShot(var M: TMsg);
 // TRIGGER
-procedure MC_RECV_TriggerSound(P: Pointer);
-procedure MC_RECV_TriggerMusic(P: Pointer);
+procedure MC_RECV_TriggerSound(var M: TMsg);
+procedure MC_RECV_TriggerMusic(var M: TMsg);
 // MISC
-procedure MC_RECV_TimeSync(P: Pointer);
-procedure MC_RECV_VoteEvent(P: Pointer);
+procedure MC_RECV_TimeSync(var M: TMsg);
+procedure MC_RECV_VoteEvent(var M: TMsg);
 // SERVICE
 procedure MC_SEND_Info(Password: string);
 procedure MC_SEND_Chat(Txt: string; Mode: Byte);
@@ -267,7 +267,7 @@ function ResDataFromMsgStream(msgStream: TMemoryStream):TResDataMsg;
 implementation
 
 uses
-  Math, ENet, e_input, e_fixedbuffer, e_graphics, e_log,
+  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;
@@ -295,7 +295,7 @@ const
 
 // GAME
 
-procedure MH_RECV_Chat(C: pTNetClient; P: Pointer);
+procedure MH_RECV_Chat(C: pTNetClient; var M: TMsg);
 var
   Txt: string;
   Mode: Byte;
@@ -305,8 +305,8 @@ begin
   PID := C^.Player;
   Pl := g_Player_Get(PID);
 
-  Txt := e_Raw_Read_String(P);
-  Mode := e_Raw_Read_Byte(P);
+  Txt := M.ReadString();
+  Mode := M.ReadByte();
   if (Mode = NET_CHAT_SYSTEM) then
     Mode := NET_CHAT_PLAYER; // prevent sending system messages from clients
   if (Mode = NET_CHAT_TEAM) and (not gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
@@ -318,7 +318,7 @@ begin
     MH_SEND_Chat(Pl.Name + ': ' + Txt, Mode, IfThen(Mode = NET_CHAT_TEAM, Pl.Team, NET_EVERYONE));
 end;
 
-procedure MH_RECV_Info(C: pTNetClient; P: Pointer);
+procedure MH_RECV_Info(C: pTNetClient; var M: TMsg);
 var
   Ver, PName, Model, Pw: string;
   R, G, B, T: Byte;
@@ -326,14 +326,14 @@ var
   Color: TRGB;
   I: Integer;
 begin
-  Ver := e_Raw_Read_String(P);
-  Pw := e_Raw_Read_String(P);
-  PName := e_Raw_Read_String(P);
-  Model := e_Raw_Read_String(P);
-  R := e_Raw_Read_Byte(P);
-  G := e_Raw_Read_Byte(P);
-  B := e_Raw_Read_Byte(P);
-  T := e_Raw_Read_Byte(P);
+  Ver := M.ReadString();
+  Pw := M.ReadString();
+  PName := M.ReadString();
+  Model := M.ReadString();
+  R := M.ReadByte();
+  G := M.ReadByte();
+  B := M.ReadByte();
+  T := M.ReadByte();
 
   if Ver <> GAME_VERSION then
   begin
@@ -384,7 +384,7 @@ begin
 
   g_Console_Add(Format(_lc[I_PLAYER_JOIN], [PName]), True);
   e_WriteLog('NET: Client ' + PName + ' [' + IntToStr(C^.ID) +
-             '] connected. Assigned player #' + IntToStr(PID) + '.', MSG_NOTIFY);
+             '] connected. Assigned player #' + IntToStr(PID) + '.', TMsgType.Notify);
 
   MH_SEND_Info(C^.ID);
 
@@ -418,7 +418,7 @@ begin
   if NetUseMaster then g_Net_Slist_Update;
 end;
 
-procedure MH_RECV_FullStateRequest(C: pTNetClient; P: Pointer);
+procedure MH_RECV_FullStateRequest(C: pTNetClient; var M: TMsg);
 begin
   if gGameOn then
     MH_SEND_Everything((C^.State = NET_STATE_AUTH), C^.ID)
@@ -428,7 +428,7 @@ end;
 
 // PLAYER
 
-function  MH_RECV_PlayerPos(C: pTNetClient; P: Pointer): Word;
+function  MH_RECV_PlayerPos(C: pTNetClient; var M: TMsg): Word;
 var
   Dir, i: Byte;
   WeaponSelect: Word;
@@ -440,7 +440,7 @@ begin
   Result := 0;
   if not gGameOn then Exit;
 
-  GT := e_Raw_Read_LongWord(P);
+  GT := M.ReadLongWord();
   PID := C^.Player;
   Pl := g_Player_Get(PID);
   if Pl = nil then
@@ -451,9 +451,9 @@ begin
   with Pl do
   begin
     NetTime := GT;
-    kByte := e_Raw_Read_Word(P);
-    Dir := e_Raw_Read_Byte(P);
-    WeaponSelect := e_Raw_Read_Word(P);
+    kByte := M.ReadWord();
+    Dir := M.ReadByte();
+    WeaponSelect := M.ReadWord();
     //e_WriteLog(Format('R:ws=%d', [WeaponSelect]), MSG_WARNING);
     if Direction <> TDirection(Dir) then
       JustTeleported := False;
@@ -490,7 +490,7 @@ begin
   // MH_SEND_PlayerPos(False, PID, C^.ID);
 end;
 
-procedure MH_RECV_CheatRequest(C: pTNetClient; P: Pointer);
+procedure MH_RECV_CheatRequest(C: pTNetClient; var M: TMsg);
 var
   CheatKind: Byte;
   Pl: TPlayer;
@@ -498,7 +498,7 @@ begin
   Pl := g_Player_Get(C^.Player);
   if Pl = nil then Exit;
 
-  CheatKind := e_Raw_Read_Byte(P);
+  CheatKind := M.ReadByte();
 
   case CheatKind of
     NET_CHEAT_SUICIDE:
@@ -513,7 +513,7 @@ begin
   end;
 end;
 
-procedure MH_RECV_PlayerSettings(C: pTNetClient; P: Pointer);
+procedure MH_RECV_PlayerSettings(C: pTNetClient; var M: TMsg);
 var
   TmpName: string;
   TmpModel: string;
@@ -521,12 +521,12 @@ var
   TmpTeam: Byte;
   Pl: TPlayer;
 begin
-  TmpName := e_Raw_Read_String(P);
-  TmpModel := e_Raw_Read_String(P);
-  TmpColor.R := e_Raw_Read_Byte(P);
-  TmpColor.G := e_Raw_Read_Byte(P);
-  TmpColor.B := e_Raw_Read_Byte(P);
-  TmpTeam := e_Raw_Read_Byte(P);
+  TmpName := M.ReadString();
+  TmpModel := M.ReadString();
+  TmpColor.R := M.ReadByte();
+  TmpColor.G := M.ReadByte();
+  TmpColor.B := M.ReadByte();
+  TmpTeam := M.ReadByte();
 
   Pl := g_Player_Get(C^.Player);
   if Pl = nil then Exit;
@@ -550,11 +550,11 @@ end;
 
 // RCON
 
-procedure MH_RECV_RCONPassword(C: pTNetClient; P: Pointer);
+procedure MH_RECV_RCONPassword(C: pTNetClient; var M: TMsg);
 var
   Pwd: string;
 begin
-  Pwd := e_Raw_Read_String(P);
+  Pwd := M.ReadString();
   if not NetAllowRCON then Exit;
   if Pwd = NetRCONPassword then
   begin
@@ -565,11 +565,11 @@ begin
     MH_SEND_GameEvent(NET_EV_RCON, NET_RCON_PWBAD, 'N', C^.ID);
 end;
 
-procedure MH_RECV_RCONCommand(C: pTNetClient; P: Pointer);
+procedure MH_RECV_RCONCommand(C: pTNetClient; var M: TMsg);
 var
   Cmd: string;
 begin
-  Cmd := e_Raw_Read_String(P);
+  Cmd := M.ReadString();
   if not NetAllowRCON then Exit;
   if not C^.RCONAuth then
   begin
@@ -581,15 +581,15 @@ end;
 
 // MISC
 
-procedure MH_RECV_Vote(C: pTNetClient; P: Pointer);
+procedure MH_RECV_Vote(C: pTNetClient; var M: TMsg);
 var
   Start: Boolean;
   Name, Command: string;
   Need: Integer;
   Pl: TPlayer;
 begin
-  Start := e_Raw_Read_Byte(P) <> 0;
-  Command := e_Raw_Read_String(P);
+  Start := M.ReadByte() <> 0;
+  Command := M.ReadString();
 
   Pl := g_Player_Get(C^.Player);
   if Pl = nil then Exit;
@@ -627,11 +627,33 @@ end;
 // GAME (SEND)
 
 procedure MH_SEND_Everything(CreatePlayers: Boolean = False; ID: Integer = NET_EVERYONE);
+
+  function sendItemRespawn (it: PItem): Boolean;
+  begin
+    result := false; // don't stop
+    MH_SEND_ItemSpawn(True, it.myid, ID);
+  end;
+
+  function sendMonSpawn (mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    MH_SEND_MonsterSpawn(mon.UID, ID);
+  end;
+
+  function sendPanelState (pan: TPanel): Boolean;
+  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);
+  end;
+
 var
   I: Integer;
 begin
   if gPlayers <> nil then
+  begin
     for I := Low(gPlayers) to High(gPlayers) do
+    begin
       if gPlayers[I] <> nil then
       begin
         if CreatePlayers then MH_SEND_PlayerCreate(gPlayers[I].UID, ID);
@@ -639,93 +661,38 @@ begin
         MH_SEND_PlayerStats(gPlayers[I].UID, ID);
 
         if (gPlayers[I].Flag <> FLAG_NONE) and (gGameSettings.GameMode = GM_CTF) then
+        begin
           MH_SEND_FlagEvent(FLAG_STATE_CAPTURED, gPlayers[I].Flag, gPlayers[I].UID, True, ID);
+        end;
       end;
-
-  if gItems <> nil then
-  begin
-    for I := High(gItems) downto Low(gItems) do
-      if gItems[I].Live then
-        MH_SEND_ItemSpawn(True, I, ID);
+    end;
   end;
 
-  if gMonsters <> nil then
-    for I := 0 to High(gMonsters) do
-      if gMonsters[I] <> nil then
-        MH_SEND_MonsterSpawn(gMonsters[I].UID, ID);
-
-  if gWalls <> nil then
-    for I := Low(gWalls) to High(gWalls) do
-      if gWalls[I] <> nil then
-        with gWalls[I] do
-        begin
-          if Door then
-            MH_SEND_PanelState(PanelType, I, ID);
-
-          if GetTextureCount > 1 then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-        end;
-
-  if gLifts <> nil then
-    for I := Low(gLifts) to High(gLifts) do
-      if gLifts[I] <> nil then
-        with gLifts[I] do
-          MH_SEND_PanelState(PanelType, I, ID);
-
-  if gRenderForegrounds <> nil then
-    for I := Low(gRenderForegrounds) to High(gRenderForegrounds) do
-      if gRenderForegrounds[I] <> nil then
-        with gRenderForegrounds[I] do
-        begin
-          if (GetTextureCount > 1) then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-          if Moved then
-            MH_SEND_PanelState(PanelType, I, ID);
-        end;
-  if gRenderBackgrounds <> nil then
-    for I := Low(gRenderBackgrounds) to High(gRenderBackgrounds) do
-      if gRenderBackgrounds[I] <> nil then
-        with gRenderBackgrounds[I] do
-        begin
-          if (GetTextureCount > 1) then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-          if Moved then
-            MH_SEND_PanelState(PanelType, I, ID);
-        end;
-  if gWater <> nil then
-    for I := Low(gWater) to High(gWater) do
-      if gWater[I] <> nil then
-        with gWater[I] do
-          if GetTextureCount > 1 then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-  if gAcid1 <> nil then
-    for I := Low(gAcid1) to High(gAcid1) do
-      if gAcid1[I] <> nil then
-        with gAcid1[I] do
-          if GetTextureCount > 1 then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-  if gAcid2 <> nil then
-    for I := Low(gAcid2) to High(gAcid2) do
-      if gAcid2[I] <> nil then
-        with gAcid2[I] do
-          if GetTextureCount > 1 then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
-  if gSteps <> nil then
-    for I := Low(gSteps) to High(gSteps) do
-      if gSteps[I] <> nil then
-        with gSteps[I] do
-          if GetTextureCount > 1 then
-            MH_SEND_PanelTexture(PanelType, I, LastAnimLoop, ID);
+  g_Items_ForEachAlive(sendItemRespawn, true); // backwards
+  g_Mons_ForEach(sendMonSpawn);
+  g_Map_ForEachPanel(sendPanelState);
 
   if gTriggers <> nil then
+  begin
     for I := Low(gTriggers) to High(gTriggers) do
+    begin
       if gTriggers[I].TriggerType = TRIGGER_SOUND then
+      begin
         MH_SEND_TriggerSound(gTriggers[I], ID);
+      end;
+    end;
+  end;
 
   if Shots <> nil then
+  begin
     for I := Low(Shots) to High(Shots) do
+    begin
       if Shots[i].ShotType in [6, 7, 8] then
+      begin
         MH_SEND_CreateShot(i, ID);
+      end;
+    end;
+  end;
 
   MH_SEND_TriggerMusic(ID);
 
@@ -734,16 +701,16 @@ begin
 
   if gGameSettings.GameMode = GM_CTF then
   begin
-    if gFlags[FLAG_RED].State <> FLAG_STATE_CAPTURED then
-      MH_SEND_FlagEvent(gFlags[FLAG_RED].State, FLAG_RED, 0, True, ID);
-    if gFlags[FLAG_BLUE].State <> FLAG_STATE_CAPTURED then
-      MH_SEND_FlagEvent(gFlags[FLAG_BLUE].State, FLAG_BLUE, 0, True, ID);
+    if gFlags[FLAG_RED].State <> FLAG_STATE_CAPTURED then MH_SEND_FlagEvent(gFlags[FLAG_RED].State, FLAG_RED, 0, True, ID);
+    if gFlags[FLAG_BLUE].State <> FLAG_STATE_CAPTURED then MH_SEND_FlagEvent(gFlags[FLAG_BLUE].State, FLAG_BLUE, 0, True, ID);
   end;
 
   if CreatePlayers and (ID >= 0) then NetClients[ID].State := NET_STATE_GAME;
 
   if gLMSRespawn > LMS_RESPAWN_NONE then
+  begin
     MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000, 'N', ID);
+  end;
 end;
 
 procedure MH_SEND_Info(ID: Byte);
@@ -752,20 +719,20 @@ var
 begin
   Map := g_ExtractFileName(gMapInfo.Map);
 
-  e_Buffer_Clear(@NetOut);
-
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_INFO));
-  e_Buffer_Write(@NetOut, ID);
-  e_Buffer_Write(@NetOut, NetClients[ID].Player);
-  e_Buffer_Write(@NetOut, gGameSettings.WAD);
-  e_Buffer_Write(@NetOut, Map);
-  e_Buffer_Write(@NetOut, gWADHash);
-  e_Buffer_Write(@NetOut, gGameSettings.GameMode);
-  e_Buffer_Write(@NetOut, gGameSettings.GoalLimit);
-  e_Buffer_Write(@NetOut, gGameSettings.TimeLimit);
-  e_Buffer_Write(@NetOut, gGameSettings.MaxLives);
-  e_Buffer_Write(@NetOut, gGameSettings.Options);
-  e_Buffer_Write(@NetOut, gTime);
+  NetOut.Clear();
+
+  NetOut.Write(Byte(NET_MSG_INFO));
+  NetOut.Write(ID);
+  NetOut.Write(NetClients[ID].Player);
+  NetOut.Write(gGameSettings.WAD);
+  NetOut.Write(Map);
+  NetOut.Write(gWADHash);
+  NetOut.Write(gGameSettings.GameMode);
+  NetOut.Write(gGameSettings.GoalLimit);
+  NetOut.Write(gGameSettings.TimeLimit);
+  NetOut.Write(gGameSettings.MaxLives);
+  NetOut.Write(gGameSettings.Options);
+  NetOut.Write(gTime);
 
   g_Net_Host_Send(ID, True, NET_CHAN_SERVICE);
 end;
@@ -786,9 +753,9 @@ begin
       if (gPlayers[i] <> nil) and (gPlayers[i].FClientID >= 0) and
          (gPlayers[i].Team = ID) then
       begin
-        e_Buffer_Write(@NetOut, Byte(NET_MSG_CHAT));
-        e_Buffer_Write(@NetOut, Txt);
-        e_Buffer_Write(@NetOut, Mode);
+        NetOut.Write(Byte(NET_MSG_CHAT));
+        NetOut.Write(Txt);
+        NetOut.Write(Mode);
         g_Net_Host_Send(gPlayers[i].FClientID, True, NET_CHAN_CHAT);
       end;
     Team := ID;
@@ -796,9 +763,9 @@ begin
   end
   else
   begin
-    e_Buffer_Write(@NetOut, Byte(NET_MSG_CHAT));
-    e_Buffer_Write(@NetOut, Txt);
-    e_Buffer_Write(@NetOut, Mode);
+    NetOut.Write(Byte(NET_MSG_CHAT));
+    NetOut.Write(Txt);
+    NetOut.Write(Mode);
     g_Net_Host_Send(ID, True, NET_CHAN_CHAT);
   end;
 
@@ -810,8 +777,8 @@ begin
     if Mode = NET_CHAT_PLAYER then
     begin
       g_Console_Add(Txt, True);
-      e_WriteLog('[Chat] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-      g_Sound_PlayEx('SOUND_GAME_RADIO');
+      e_WriteLog('[Chat] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+      g_Game_ChatSound(b_Text_Unformat(Txt));
     end
     else
     if Mode = NET_CHAT_TEAM then
@@ -820,14 +787,14 @@ begin
         if (gPlayer1.Team = TEAM_RED) and (Team = TEAM_RED) then
         begin
           g_Console_Add(#18'[Team] '#2 + Txt, True);
-          e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-          g_Sound_PlayEx('SOUND_GAME_RADIO');
+          e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+          g_Game_ChatSound(b_Text_Unformat(Txt));
         end
         else if (gPlayer1.Team = TEAM_BLUE) and (Team = TEAM_BLUE) then
         begin
           g_Console_Add(#20'[Team] '#2 + Txt, True);
-          e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-          g_Sound_PlayEx('SOUND_GAME_RADIO');
+          e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+          g_Game_ChatSound(b_Text_Unformat(Txt));
         end;
       end;
   end
@@ -835,34 +802,34 @@ begin
   begin
     Name := g_Net_ClientName_ByID(ID);
     g_Console_Add('-> ' + Name + ': ' + Txt, True);
-    e_WriteLog('[Tell ' + Name + '] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-    g_Sound_PlayEx('SOUND_GAME_RADIO');
+    e_WriteLog('[Tell ' + Name + '] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+    g_Game_ChatSound(b_Text_Unformat(Txt), False);
   end;
 end;
 
 procedure MH_SEND_Effect(X, Y: Integer; Ang: SmallInt; Kind: Byte; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_GFX));
-  e_Buffer_Write(@NetOut, Kind);
-  e_Buffer_Write(@NetOut, X);
-  e_Buffer_Write(@NetOut, Y);
-  e_Buffer_Write(@NetOut, Ang);
+  NetOut.Write(Byte(NET_MSG_GFX));
+  NetOut.Write(Kind);
+  NetOut.Write(X);
+  NetOut.Write(Y);
+  NetOut.Write(Ang);
 
   g_Net_Host_Send(ID, False, NET_CHAN_GAME);
 end;
 
 procedure MH_SEND_Sound(X, Y: Integer; Name: string; Pos: Boolean = True; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_SND));
-  e_Buffer_Write(@NetOut, Name);
+  NetOut.Write(Byte(NET_MSG_SND));
+  NetOut.Write(Name);
   if Pos then
   begin
-    e_Buffer_Write(@NetOut, Byte(1));
-    e_Buffer_Write(@NetOut, X);
-    e_Buffer_Write(@NetOut, Y);
+    NetOut.Write(Byte(1));
+    NetOut.Write(X);
+    NetOut.Write(Y);
   end
   else
-    e_Buffer_Write(@NetOut, Byte(0));
+    NetOut.Write(Byte(0));
 
   g_Net_Host_Send(ID, False, NET_CHAN_GAME);
 end;
@@ -871,16 +838,16 @@ procedure MH_SEND_CreateShot(Proj: LongInt; ID: Integer = NET_EVERYONE);
 begin
   if (Shots = nil) or (Proj < 0) or (Proj > High(Shots)) then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_SHADD));
-  e_Buffer_Write(@NetOut, Proj);
-  e_Buffer_Write(@NetOut, Shots[Proj].ShotType);
-  e_Buffer_Write(@NetOut, Shots[Proj].Target);
-  e_Buffer_Write(@NetOut, Shots[Proj].SpawnerUID);
-  e_Buffer_Write(@NetOut, Shots[Proj].Timeout);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.X);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Y);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Vel.X);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Vel.Y);
+  NetOut.Write(Byte(NET_MSG_SHADD));
+  NetOut.Write(Proj);
+  NetOut.Write(Shots[Proj].ShotType);
+  NetOut.Write(Shots[Proj].Target);
+  NetOut.Write(Shots[Proj].SpawnerUID);
+  NetOut.Write(Shots[Proj].Timeout);
+  NetOut.Write(Shots[Proj].Obj.X);
+  NetOut.Write(Shots[Proj].Obj.Y);
+  NetOut.Write(Shots[Proj].Obj.Vel.X);
+  NetOut.Write(Shots[Proj].Obj.Vel.Y);
 
   g_Net_Host_Send(ID, True, NET_CHAN_SHOTS);
 end;
@@ -889,40 +856,40 @@ procedure MH_SEND_UpdateShot(Proj: LongInt; ID: Integer = NET_EVERYONE);
 begin
   if (Shots = nil) or (Proj < 0) or (Proj > High(Shots)) then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_SHPOS));
-  e_Buffer_Write(@NetOut, Proj);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.X);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Y);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Vel.X);
-  e_Buffer_Write(@NetOut, Shots[Proj].Obj.Vel.Y);
+  NetOut.Write(Byte(NET_MSG_SHPOS));
+  NetOut.Write(Proj);
+  NetOut.Write(Shots[Proj].Obj.X);
+  NetOut.Write(Shots[Proj].Obj.Y);
+  NetOut.Write(Shots[Proj].Obj.Vel.X);
+  NetOut.Write(Shots[Proj].Obj.Vel.Y);
 
   g_Net_Host_Send(ID, False, NET_CHAN_SHOTS);
 end;
 
 procedure MH_Send_DeleteShot(Proj: LongInt; X, Y: LongInt; Loud: Boolean = True; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_SHDEL));
-  e_Buffer_Write(@NetOut, Proj);
-  e_Buffer_Write(@NetOut, Byte(Loud));
-  e_Buffer_Write(@NetOut, X);
-  e_Buffer_Write(@NetOut, Y);
+  NetOut.Write(Byte(NET_MSG_SHDEL));
+  NetOut.Write(Proj);
+  NetOut.Write(Byte(Loud));
+  NetOut.Write(X);
+  NetOut.Write(Y);
 
   g_Net_Host_Send(ID, True, NET_CHAN_SHOTS);
 end;
 
 procedure MH_SEND_GameStats(ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_SCORE));
+  NetOut.Write(Byte(NET_MSG_SCORE));
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
-    e_Buffer_Write(@NetOut, gTeamStat[TEAM_RED].Goals);
-    e_Buffer_Write(@NetOut, gTeamStat[TEAM_BLUE].Goals);
+    NetOut.Write(gTeamStat[TEAM_RED].Goals);
+    NetOut.Write(gTeamStat[TEAM_BLUE].Goals);
   end
   else
     if gGameSettings.GameMode = GM_COOP then
     begin
-      e_Buffer_Write(@NetOut, gCoopMonstersKilled);
-      e_Buffer_Write(@NetOut, gCoopSecretsFound);
+      NetOut.Write(gCoopMonstersKilled);
+      NetOut.Write(gCoopSecretsFound);
     end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
@@ -930,58 +897,58 @@ end;
 
 procedure MH_SEND_CoopStats(ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_COOP));
-  e_Buffer_Write(@NetOut, gTotalMonsters);
-  e_Buffer_Write(@NetOut, gSecretsCount);
-  e_Buffer_Write(@NetOut, gCoopTotalMonstersKilled);
-  e_Buffer_Write(@NetOut, gCoopTotalSecretsFound);
-  e_Buffer_Write(@NetOut, gCoopTotalMonsters);
-  e_Buffer_Write(@NetOut, gCoopTotalSecrets);
+  NetOut.Write(Byte(NET_MSG_COOP));
+  NetOut.Write(gTotalMonsters);
+  NetOut.Write(gSecretsCount);
+  NetOut.Write(gCoopTotalMonstersKilled);
+  NetOut.Write(gCoopTotalSecretsFound);
+  NetOut.Write(gCoopTotalMonsters);
+  NetOut.Write(gCoopTotalSecrets);
 end;
 
 procedure MH_SEND_GameEvent(EvType: Byte; EvNum: Integer = 0; EvStr: string = 'N'; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_GEVENT));
-  e_Buffer_Write(@NetOut, EvType);
-  e_Buffer_Write(@NetOut, EvNum);
-  e_Buffer_Write(@NetOut, EvStr);
-  e_Buffer_Write(@NetOut, Byte(gLastMap));
-  e_Buffer_Write(@NetOut, gTime);
-  if (EvType = NET_EV_MAPSTART) and (Pos(':\', EvStr) > 0) then
+  NetOut.Write(Byte(NET_MSG_GEVENT));
+  NetOut.Write(EvType);
+  NetOut.Write(EvNum);
+  NetOut.Write(EvStr);
+  NetOut.Write(Byte(gLastMap));
+  NetOut.Write(gTime);
+  if (EvType = NET_EV_MAPSTART) and isWadPath(EvStr) then
   begin
-    e_Buffer_Write(@NetOut, Byte(1));
-    e_Buffer_Write(@NetOut, gWADHash);
+    NetOut.Write(Byte(1));
+    NetOut.Write(gWADHash);
   end else
-    e_Buffer_Write(@NetOut, Byte(0));
+    NetOut.Write(Byte(0));
 
   g_Net_Host_Send(ID, True, NET_CHAN_SERVICE);
 end;
 
 procedure MH_SEND_FlagEvent(EvType: Byte; Flag: Byte; PID: Word; Quiet: Boolean = False; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_FLAG));
-  e_Buffer_Write(@NetOut, EvType);
-  e_Buffer_Write(@NetOut, Flag);
-  e_Buffer_Write(@NetOut, Byte(Quiet));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, gFlags[Flag].State);
-  e_Buffer_Write(@NetOut, gFlags[Flag].CaptureTime);
-  e_Buffer_Write(@NetOut, gFlags[Flag].Obj.X);
-  e_Buffer_Write(@NetOut, gFlags[Flag].Obj.Y);
-  e_Buffer_Write(@NetOut, gFlags[Flag].Obj.Vel.X);
-  e_Buffer_Write(@NetOut, gFlags[Flag].Obj.Vel.Y);
+  NetOut.Write(Byte(NET_MSG_FLAG));
+  NetOut.Write(EvType);
+  NetOut.Write(Flag);
+  NetOut.Write(Byte(Quiet));
+  NetOut.Write(PID);
+  NetOut.Write(gFlags[Flag].State);
+  NetOut.Write(gFlags[Flag].CaptureTime);
+  NetOut.Write(gFlags[Flag].Obj.X);
+  NetOut.Write(gFlags[Flag].Obj.Y);
+  NetOut.Write(gFlags[Flag].Obj.Vel.X);
+  NetOut.Write(gFlags[Flag].Obj.Vel.Y);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
 end;
 
 procedure MH_SEND_GameSettings(ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_GSET));
-  e_Buffer_Write(@NetOut, gGameSettings.GameMode);
-  e_Buffer_Write(@NetOut, gGameSettings.GoalLimit);
-  e_Buffer_Write(@NetOut, gGameSettings.TimeLimit);
-  e_Buffer_Write(@NetOut, gGameSettings.MaxLives);
-  e_Buffer_Write(@NetOut, gGameSettings.Options);
+  NetOut.Write(Byte(NET_MSG_GSET));
+  NetOut.Write(gGameSettings.GameMode);
+  NetOut.Write(gGameSettings.GoalLimit);
+  NetOut.Write(gGameSettings.TimeLimit);
+  NetOut.Write(gGameSettings.MaxLives);
+  NetOut.Write(gGameSettings.Options);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
 end;
@@ -995,15 +962,15 @@ begin
   P := g_Player_Get(PID);
   if P = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLR));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, P.Name);
+  NetOut.Write(Byte(NET_MSG_PLR));
+  NetOut.Write(PID);
+  NetOut.Write(P.Name);
 
-  e_Buffer_Write(@NetOut, P.FActualModelName);
-  e_Buffer_Write(@NetOut, P.FColor.R);
-  e_Buffer_Write(@NetOut, P.FColor.G);
-  e_Buffer_Write(@NetOut, P.FColor.B);
-  e_Buffer_Write(@NetOut, P.Team);
+  NetOut.Write(P.FActualModelName);
+  NetOut.Write(P.FColor.R);
+  NetOut.Write(P.FColor.G);
+  NetOut.Write(P.FColor.B);
+  NetOut.Write(P.Team);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT)
 end;
@@ -1017,16 +984,16 @@ begin
   if Pl = nil then Exit;
   if Pl.FDummy then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRPOS));
-  e_Buffer_Write(@NetOut, gTime);
-  e_Buffer_Write(@NetOut, PID);
+  NetOut.Write(Byte(NET_MSG_PLRPOS));
+  NetOut.Write(gTime);
+  NetOut.Write(PID);
 
   kByte := 0;
 
   with Pl do
   begin
-    e_Buffer_Write(@NetOut, FPing);
-    e_Buffer_Write(@NetOut, FLoss);
+    NetOut.Write(FPing);
+    NetOut.Write(FLoss);
     if IsKeyPressed(KEY_CHAT) then
       kByte := NET_KEY_CHAT
     else
@@ -1039,14 +1006,14 @@ begin
       if JustTeleported then kByte := kByte or NET_KEY_FORCEDIR;
     end;
 
-    e_Buffer_Write(@NetOut, kByte);
-    if Direction = D_LEFT then e_Buffer_Write(@NetOut, Byte(0)) else e_Buffer_Write(@NetOut, Byte(1));
-    e_Buffer_Write(@NetOut, GameX);
-    e_Buffer_Write(@NetOut, GameY);
-    e_Buffer_Write(@NetOut, GameVelX);
-    e_Buffer_Write(@NetOut, GameVelY);
-    e_Buffer_Write(@NetOut, GameAccelX);
-    e_Buffer_Write(@NetOut, GameAccelY);
+    NetOut.Write(kByte);
+    if Direction = TDirection.D_LEFT then NetOut.Write(Byte(0)) else NetOut.Write(Byte(1));
+    NetOut.Write(GameX);
+    NetOut.Write(GameY);
+    NetOut.Write(GameVelX);
+    NetOut.Write(GameVelY);
+    NetOut.Write(GameAccelX);
+    NetOut.Write(GameAccelY);
   end;
 
   g_Net_Host_Send(ID, Reliable, NET_CHAN_PLAYERPOS);
@@ -1060,48 +1027,49 @@ begin
   P := g_Player_Get(PID);
   if P = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRSTA));
-  e_Buffer_Write(@NetOut, PID);
+  NetOut.Write(Byte(NET_MSG_PLRSTA));
+  NetOut.Write(PID);
 
   with P do
   begin
-    e_Buffer_Write(@NetOut, Byte(Live));
-    e_Buffer_Write(@NetOut, Byte(GodMode));
-    e_Buffer_Write(@NetOut, Health);
-    e_Buffer_Write(@NetOut, Armor);
-    e_Buffer_Write(@NetOut, Air);
-    e_Buffer_Write(@NetOut, JetFuel);
-    e_Buffer_Write(@NetOut, Lives);
-    e_Buffer_Write(@NetOut, Team);
+    NetOut.Write(Byte(alive));
+    NetOut.Write(Byte(GodMode));
+    NetOut.Write(Health);
+    NetOut.Write(Armor);
+    NetOut.Write(Air);
+    NetOut.Write(JetFuel);
+    NetOut.Write(Lives);
+    NetOut.Write(Team);
 
-    for I := WEAPON_KASTET to WEAPON_SUPERPULEMET do
-      e_Buffer_Write(@NetOut, Byte(FWeapon[I]));
+    for I := WP_FIRST to WP_LAST do
+      NetOut.Write(Byte(FWeapon[I]));
 
-    for I := A_BULLETS to A_CELLS do
-      e_Buffer_Write(@NetOut, FAmmo[I]);
+    for I := A_BULLETS to A_HIGH do
+      NetOut.Write(FAmmo[I]);
 
-    for I := A_BULLETS to A_CELLS do
-      e_Buffer_Write(@NetOut, FMaxAmmo[I]);
+    for I := A_BULLETS to A_HIGH do
+      NetOut.Write(FMaxAmmo[I]);
 
     for I := MR_SUIT to MR_MAX do
-      e_Buffer_Write(@NetOut, LongWord(FMegaRulez[I]));
+      NetOut.Write(LongWord(FMegaRulez[I]));
 
-    e_Buffer_Write(@NetOut, Byte(R_ITEM_BACKPACK in FRulez));
-    e_Buffer_Write(@NetOut, Byte(R_KEY_RED in FRulez));
-    e_Buffer_Write(@NetOut, Byte(R_KEY_GREEN in FRulez));
-    e_Buffer_Write(@NetOut, Byte(R_KEY_BLUE in FRulez));
-    e_Buffer_Write(@NetOut, Byte(R_BERSERK in FRulez));
+    NetOut.Write(Byte(R_ITEM_BACKPACK in FRulez));
+    NetOut.Write(Byte(R_KEY_RED in FRulez));
+    NetOut.Write(Byte(R_KEY_GREEN in FRulez));
+    NetOut.Write(Byte(R_KEY_BLUE in FRulez));
+    NetOut.Write(Byte(R_BERSERK in FRulez));
 
-    e_Buffer_Write(@NetOut, Frags);
-    e_Buffer_Write(@NetOut, Death);
+    NetOut.Write(Frags);
+    NetOut.Write(Death);
 
-    e_Buffer_Write(@NetOut, CurrWeap);
+    NetOut.Write(CurrWeap);
 
-    e_Buffer_Write(@NetOut, Byte(FSpectator));
-    e_Buffer_Write(@NetOut, Byte(FGhost));
-    e_Buffer_Write(@NetOut, Byte(FPhysics));
-    e_Buffer_Write(@NetOut, Byte(FNoRespawn));
-    e_Buffer_Write(@NetOut, Byte(FJetpack));
+    NetOut.Write(Byte(FSpectator));
+    NetOut.Write(Byte(FGhost));
+    NetOut.Write(Byte(FPhysics));
+    NetOut.Write(Byte(FNoRespawn));
+    NetOut.Write(Byte(FJetpack));
+    NetOut.Write(FFireTime);
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_PLAYER);
@@ -1109,46 +1077,46 @@ end;
 
 procedure MH_SEND_PlayerDamage(PID: Word; Kind: Byte; Attacker, Value: Word; VX, VY: Integer; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRDMG));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, Kind);
-  e_Buffer_Write(@NetOut, Attacker);
-  e_Buffer_Write(@NetOut, Value);
-  e_Buffer_Write(@NetOut, VX);
-  e_Buffer_Write(@NetOut, VY);
+  NetOut.Write(Byte(NET_MSG_PLRDMG));
+  NetOut.Write(PID);
+  NetOut.Write(Kind);
+  NetOut.Write(Attacker);
+  NetOut.Write(Value);
+  NetOut.Write(VX);
+  NetOut.Write(VY);
 
   g_Net_Host_Send(ID, False, NET_CHAN_PLAYER);
 end;
 
 procedure MH_SEND_PlayerDeath(PID: Word; KillType, DeathType: Byte; Attacker: Word; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRDIE));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, KillType);
-  e_Buffer_Write(@NetOut, DeathType);
-  e_Buffer_Write(@NetOut, Attacker);
+  NetOut.Write(Byte(NET_MSG_PLRDIE));
+  NetOut.Write(PID);
+  NetOut.Write(KillType);
+  NetOut.Write(DeathType);
+  NetOut.Write(Attacker);
 
   g_Net_Host_Send(ID, True, NET_CHAN_PLAYER);
 end;
 
 procedure MH_SEND_PlayerFire(PID: Word; Weapon: Byte; X, Y, AX, AY: Integer; ShotID: Integer = -1; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRFIRE));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, Weapon);
-  e_Buffer_Write(@NetOut, X);
-  e_Buffer_Write(@NetOut, Y);
-  e_Buffer_Write(@NetOut, AX);
-  e_Buffer_Write(@NetOut, AY);
-  e_Buffer_Write(@NetOut, ShotID);
+  NetOut.Write(Byte(NET_MSG_PLRFIRE));
+  NetOut.Write(PID);
+  NetOut.Write(Weapon);
+  NetOut.Write(X);
+  NetOut.Write(Y);
+  NetOut.Write(AX);
+  NetOut.Write(AY);
+  NetOut.Write(ShotID);
 
   g_Net_Host_Send(ID, True, NET_CHAN_SHOTS);
 end;
 
 procedure MH_SEND_PlayerDelete(PID: Word; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRDEL));
-  e_Buffer_Write(@NetOut, PID);
+  NetOut.Write(Byte(NET_MSG_PLRDEL));
+  NetOut.Write(PID);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
 end;
@@ -1160,17 +1128,17 @@ begin
   Pl := g_Player_Get(PID);
   if Pl = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRSET));
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, Pl.Name);
+  NetOut.Write(Byte(NET_MSG_PLRSET));
+  NetOut.Write(PID);
+  NetOut.Write(Pl.Name);
   if Mdl = '' then
-    e_Buffer_Write(@NetOut, Pl.Model.Name)
+    NetOut.Write(Pl.Model.Name)
   else
-    e_Buffer_Write(@NetOut, Mdl);
-  e_Buffer_Write(@NetOut, Pl.FColor.R);
-  e_Buffer_Write(@NetOut, Pl.FColor.G);
-  e_Buffer_Write(@NetOut, Pl.FColor.B);
-  e_Buffer_Write(@NetOut, Pl.Team);
+    NetOut.Write(Mdl);
+  NetOut.Write(Pl.FColor.R);
+  NetOut.Write(Pl.FColor.G);
+  NetOut.Write(Pl.FColor.B);
+  NetOut.Write(Pl.Team);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
 end;
@@ -1178,99 +1146,89 @@ end;
 // ITEM (SEND)
 
 procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
-begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_ISPAWN));
-  e_Buffer_Write(@NetOut, IID);
-  e_Buffer_Write(@NetOut, Byte(Quiet));
-  e_Buffer_Write(@NetOut, gItems[IID].ItemType);
-  e_Buffer_Write(@NetOut, Byte(gItems[IID].Fall));
-  e_Buffer_Write(@NetOut, Byte(gItems[IID].Respawnable));
-  e_Buffer_Write(@NetOut, gItems[IID].Obj.X);
-  e_Buffer_Write(@NetOut, gItems[IID].Obj.Y);
-  e_Buffer_Write(@NetOut, gItems[IID].Obj.Vel.X);
-  e_Buffer_Write(@NetOut, gItems[IID].Obj.Vel.Y);
+var
+  it: PItem;
+  tt: Byte;
+begin
+  it := g_Items_ByIdx(IID);
+
+  NetOut.Write(Byte(NET_MSG_ISPAWN));
+  NetOut.Write(IID);
+  NetOut.Write(Byte(Quiet));
+  tt := it.ItemType;
+  if it.dropped then tt := tt or $80;
+  NetOut.Write(tt);
+  NetOut.Write(Byte(it.Fall));
+  NetOut.Write(Byte(it.Respawnable));
+  NetOut.Write(it.Obj.X);
+  NetOut.Write(it.Obj.Y);
+  NetOut.Write(it.Obj.Vel.X);
+  NetOut.Write(it.Obj.Vel.Y);
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
 
 procedure MH_SEND_ItemDestroy(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_IDEL));
-  e_Buffer_Write(@NetOut, IID);
-  e_Buffer_Write(@NetOut, Byte(Quiet));
+  NetOut.Write(Byte(NET_MSG_IDEL));
+  NetOut.Write(IID);
+  NetOut.Write(Byte(Quiet));
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
 
 // PANEL
 
-procedure MH_SEND_PanelTexture(PType: Word; PID: LongWord; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
 var
   TP: TPanel;
 begin
-  case PType of
-    PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
-      TP := gWalls[PID];
-    PANEL_FORE:
-      TP := gRenderForegrounds[PID];
-    PANEL_BACK:
-      TP := gRenderBackgrounds[PID];
-    PANEL_WATER:
-      TP := gWater[PID];
-    PANEL_ACID1:
-      TP := gAcid1[PID];
-    PANEL_ACID2:
-      TP := gAcid2[PID];
-    PANEL_STEP:
-      TP := gSteps[PID];
-    else
-      Exit;
-  end;
+  TP := g_Map_PanelByGUID(PGUID);
+  if (TP = nil) then exit;
 
   with TP do
   begin
-    e_Buffer_Write(@NetOut, Byte(NET_MSG_PTEX));
-    e_Buffer_Write(@NetOut, PType);
-    e_Buffer_Write(@NetOut, PID);
-    e_Buffer_Write(@NetOut, FCurTexture);
-    e_Buffer_Write(@NetOut, FCurFrame);
-    e_Buffer_Write(@NetOut, FCurFrameCount);
-    e_Buffer_Write(@NetOut, AnimLoop);
+    NetOut.Write(Byte(NET_MSG_PTEX));
+    NetOut.Write(LongWord(PGUID));
+    NetOut.Write(FCurTexture);
+    NetOut.Write(FCurFrame);
+    NetOut.Write(FCurFrameCount);
+    NetOut.Write(AnimLoop);
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
 
-procedure MH_SEND_PanelState(PType: Word; PID: LongWord; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelState(PGUID: Integer; ID: Integer = NET_EVERYONE);
 var
   TP: TPanel;
-begin
-  case PType of
-    PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
-      TP := gWalls[PID];
-    PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
-      TP := gLifts[PID];
-    PANEL_BACK:
-    begin
-      TP := gRenderBackgrounds[PID];
-      TP.Moved := True;
-    end;
-    PANEL_FORE:
-    begin
-      TP := gRenderForegrounds[PID];
-      TP.Moved := True;
-    end;
-    else
-      Exit;
-  end;
-
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PSTATE));
-  e_Buffer_Write(@NetOut, PType);
-  e_Buffer_Write(@NetOut, PID);
-  e_Buffer_Write(@NetOut, Byte(TP.Enabled));
-  e_Buffer_Write(@NetOut, TP.LiftType);
-  e_Buffer_Write(@NetOut, TP.X);
-  e_Buffer_Write(@NetOut, TP.Y);
+  mpflags: Byte = 0;
+begin
+  TP := g_Map_PanelByGUID(PGUID);
+  if (TP = nil) then exit;
+
+  NetOut.Write(Byte(NET_MSG_PSTATE));
+  NetOut.Write(LongWord(PGUID));
+  NetOut.Write(Byte(TP.Enabled));
+  NetOut.Write(TP.LiftType);
+  NetOut.Write(TP.X);
+  NetOut.Write(TP.Y);
+  NetOut.Write(Word(TP.Width));
+  NetOut.Write(Word(TP.Height));
+  // mplats
+  NetOut.Write(LongInt(TP.movingSpeedX));
+  NetOut.Write(LongInt(TP.movingSpeedY));
+  NetOut.Write(LongInt(TP.movingStartX));
+  NetOut.Write(LongInt(TP.movingStartY));
+  NetOut.Write(LongInt(TP.movingEndX));
+  NetOut.Write(LongInt(TP.movingEndY));
+  NetOut.Write(LongInt(TP.sizeSpeedX));
+  NetOut.Write(LongInt(TP.sizeSpeedY));
+  NetOut.Write(LongInt(TP.sizeEndX));
+  NetOut.Write(LongInt(TP.sizeEndY));
+  if TP.movingActive then mpflags := mpflags or 1;
+  if TP.moveOnce then mpflags := mpflags or 2;
+  NetOut.Write(Byte(mpflags));
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
@@ -1282,22 +1240,22 @@ begin
   if gTriggers = nil then Exit;
   if T.Sound = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_TSOUND));
-  e_Buffer_Write(@NetOut, T.ClientID);
-  e_Buffer_Write(@NetOut, Byte(T.Sound.IsPlaying));
-  e_Buffer_Write(@NetOut, LongWord(T.Sound.GetPosition));
-  e_Buffer_Write(@NetOut, T.SoundPlayCount);
+  NetOut.Write(Byte(NET_MSG_TSOUND));
+  NetOut.Write(T.ClientID);
+  NetOut.Write(Byte(T.Sound.IsPlaying));
+  NetOut.Write(LongWord(T.Sound.GetPosition));
+  NetOut.Write(T.SoundPlayCount);
 
   g_Net_Host_Send(ID, True);
 end;
 
 procedure MH_SEND_TriggerMusic(ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_TMUSIC));
-  e_Buffer_Write(@NetOut, gMusic.Name);
-  e_Buffer_Write(@NetOut, Byte(gMusic.IsPlaying));
-  e_Buffer_Write(@NetOut, LongWord(gMusic.GetPosition));
-  e_Buffer_Write(@NetOut, Byte(gMusic.SpecPause or gMusic.IsPaused));
+  NetOut.Write(Byte(NET_MSG_TMUSIC));
+  NetOut.Write(gMusic.Name);
+  NetOut.Write(Byte(gMusic.IsPlaying));
+  NetOut.Write(LongWord(gMusic.GetPosition));
+  NetOut.Write(Byte(gMusic.SpecPause or gMusic.IsPaused));
 
   g_Net_Host_Send(ID, True);
 end;
@@ -1308,28 +1266,28 @@ procedure MH_SEND_MonsterSpawn(UID: Word; ID: Integer = NET_EVERYONE);
 var
   M: TMonster;
 begin
-  M := g_Monsters_Get(UID);
+  M := g_Monsters_ByUID(UID);
   if M = nil then
     Exit;
 
   with M do
   begin
-    e_Buffer_Write(@NetOut, Byte(NET_MSG_MSPAWN));
-    e_Buffer_Write(@NetOut, UID);
-    e_Buffer_Write(@NetOut, MonsterType);
-    e_Buffer_Write(@NetOut, MonsterState);
-    e_Buffer_Write(@NetOut, MonsterAnim);
-    e_Buffer_Write(@NetOut, MonsterTargetUID);
-    e_Buffer_Write(@NetOut, MonsterTargetTime);
-    e_Buffer_Write(@NetOut, MonsterBehaviour);
-    e_Buffer_Write(@NetOut, MonsterSleep);
-    e_Buffer_Write(@NetOut, MonsterHealth);
-    e_Buffer_Write(@NetOut, MonsterAmmo);
-    e_Buffer_Write(@NetOut, GameX);
-    e_Buffer_Write(@NetOut, GameY);
-    e_Buffer_Write(@NetOut, GameVelX);
-    e_Buffer_Write(@NetOut, GameVelY);
-    e_Buffer_Write(@NetOut, Byte(GameDirection));
+    NetOut.Write(Byte(NET_MSG_MSPAWN));
+    NetOut.Write(UID);
+    NetOut.Write(MonsterType);
+    NetOut.Write(MonsterState);
+    NetOut.Write(MonsterAnim);
+    NetOut.Write(MonsterTargetUID);
+    NetOut.Write(MonsterTargetTime);
+    NetOut.Write(MonsterBehaviour);
+    NetOut.Write(MonsterSleep);
+    NetOut.Write(MonsterHealth);
+    NetOut.Write(MonsterAmmo);
+    NetOut.Write(GameX);
+    NetOut.Write(GameY);
+    NetOut.Write(GameVelX);
+    NetOut.Write(GameVelY);
+    NetOut.Write(Byte(GameDirection));
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
@@ -1339,19 +1297,19 @@ procedure MH_SEND_MonsterPos(UID: Word; ID: Integer = NET_EVERYONE);
 var
   M: TMonster;
 begin
-  M := g_Monsters_Get(UID);
+  M := g_Monsters_ByUID(UID);
   if M = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_MPOS));
-  e_Buffer_Write(@NetOut, UID);
+  NetOut.Write(Byte(NET_MSG_MPOS));
+  NetOut.Write(UID);
 
   with M do
   begin
-    e_Buffer_Write(@NetOut, GameX);
-    e_Buffer_Write(@NetOut, GameY);
-    e_Buffer_Write(@NetOut, GameVelX);
-    e_Buffer_Write(@NetOut, GameVelY);
-    e_Buffer_Write(@NetOut, Byte(GameDirection));
+    NetOut.Write(GameX);
+    NetOut.Write(GameY);
+    NetOut.Write(GameVelX);
+    NetOut.Write(GameVelY);
+    NetOut.Write(Byte(GameDirection));
   end;
 
   g_Net_Host_Send(ID, False, NET_CHAN_MONSTERPOS);
@@ -1361,23 +1319,24 @@ procedure MH_SEND_MonsterState(UID: Word; ForcedAnim: Byte = 255; ID: Integer =
 var
   M: TMonster;
 begin
-  M := g_Monsters_Get(UID);
+  M := g_Monsters_ByUID(UID);
   if M = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_MSTATE));
-  e_Buffer_Write(@NetOut, UID);
+  NetOut.Write(Byte(NET_MSG_MSTATE));
+  NetOut.Write(UID);
 
   with M do
   begin
-    e_Buffer_Write(@NetOut, MonsterState);
-    e_Buffer_Write(@NetOut, ForcedAnim);
-    e_Buffer_Write(@NetOut, MonsterTargetUID);
-    e_Buffer_Write(@NetOut, MonsterTargetTime);
-    e_Buffer_Write(@NetOut, MonsterSleep);
-    e_Buffer_Write(@NetOut, MonsterHealth);
-    e_Buffer_Write(@NetOut, MonsterAmmo);
-    e_Buffer_Write(@NetOut, MonsterPain);
-    e_Buffer_Write(@NetOut, Byte(AnimIsReverse));
+    NetOut.Write(MonsterState);
+    NetOut.Write(ForcedAnim);
+    NetOut.Write(MonsterTargetUID);
+    NetOut.Write(MonsterTargetTime);
+    NetOut.Write(MonsterSleep);
+    NetOut.Write(MonsterHealth);
+    NetOut.Write(MonsterAmmo);
+    NetOut.Write(MonsterPain);
+    NetOut.Write(Byte(AnimIsReverse));
+    NetOut.Write(FFireTime);
   end;
 
   g_Net_Host_Send(ID, True, NET_CHAN_MONSTER);
@@ -1385,12 +1344,12 @@ end;
 
 procedure MH_SEND_MonsterShot(UID: Word; X, Y, VX, VY: Integer; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_MSHOT));
-  e_Buffer_Write(@NetOut, UID);
-  e_Buffer_Write(@NetOut, X);
-  e_Buffer_Write(@NetOut, Y);
-  e_Buffer_Write(@NetOut, VX);
-  e_Buffer_Write(@NetOut, VY);
+  NetOut.Write(Byte(NET_MSG_MSHOT));
+  NetOut.Write(UID);
+  NetOut.Write(X);
+  NetOut.Write(Y);
+  NetOut.Write(VX);
+  NetOut.Write(VY);
 
   g_Net_Host_Send(ID, True, NET_CHAN_MONSTER);
 end;
@@ -1399,11 +1358,11 @@ procedure MH_SEND_MonsterDelete(UID: Word; ID: Integer = NET_EVERYONE);
 var
   M: TMonster;
 begin
-  M := g_Monsters_Get(UID);
+  M := g_Monsters_ByUID(UID);
   if M = nil then Exit;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_MDEL));
-  e_Buffer_Write(@NetOut, UID);
+  NetOut.Write(Byte(NET_MSG_MDEL));
+  NetOut.Write(UID);
 
   g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
 end;
@@ -1412,8 +1371,8 @@ end;
 
 procedure MH_SEND_TimeSync(Time: LongWord; ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_TIME_SYNC));
-  e_Buffer_Write(@NetOut, Time);
+  NetOut.Write(Byte(NET_MSG_TIME_SYNC));
+  NetOut.Write(Time);
 
   g_Net_Host_Send(ID, False, NET_CHAN_SERVICE);
 end;
@@ -1423,12 +1382,12 @@ procedure MH_SEND_VoteEvent(EvType: Byte;
                             IntArg1: SmallInt = 0; IntArg2: SmallInt = 0;
                             ID: Integer = NET_EVERYONE);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_VOTE_EVENT));
-  e_Buffer_Write(@NetOut, EvType);
-  e_Buffer_Write(@NetOut, IntArg1);
-  e_Buffer_Write(@NetOut, IntArg2);
-  e_Buffer_Write(@NetOut, StrArg1);
-  e_Buffer_Write(@NetOut, StrArg2);
+  NetOut.Write(Byte(NET_MSG_VOTE_EVENT));
+  NetOut.Write(EvType);
+  NetOut.Write(IntArg1);
+  NetOut.Write(IntArg2);
+  NetOut.Write(StrArg1);
+  NetOut.Write(StrArg2);
 
   g_Net_Host_Send(ID, True, NET_CHAN_IMPORTANT);
 end;
@@ -1437,21 +1396,21 @@ end;
 
 // GAME
 
-procedure MC_RECV_Chat(P: Pointer);
+procedure MC_RECV_Chat(var M: TMsg);
 var
   Txt: string;
   Mode: Byte;
 begin
-  Txt := e_Raw_Read_String(P);
-  Mode := e_Raw_Read_Byte(P);
+  Txt := M.ReadString();
+  Mode := M.ReadByte();
 
   if Mode <> NET_CHAT_SYSTEM then
   begin
     if Mode = NET_CHAT_PLAYER then
     begin
       g_Console_Add(Txt, True);
-      e_WriteLog('[Chat] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-      g_Sound_PlayEx('SOUND_GAME_RADIO');
+      e_WriteLog('[Chat] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+      g_Game_ChatSound(b_Text_Unformat(Txt));
     end else
     if (Mode = NET_CHAT_TEAM) and (gPlayer1 <> nil) then
     begin
@@ -1459,14 +1418,14 @@ begin
         g_Console_Add(b_Text_Format('\r[Team] ') + Txt, True);
       if gPlayer1.Team = TEAM_BLUE then
         g_Console_Add(b_Text_Format('\b[Team] ') + Txt, True);
-      e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), MSG_NOTIFY);
-      g_Sound_PlayEx('SOUND_GAME_RADIO');
+      e_WriteLog('[Team Chat] ' + b_Text_Unformat(Txt), TMsgType.Notify);
+      g_Game_ChatSound(b_Text_Unformat(Txt));
     end;
   end else
     g_Console_Add(Txt, True);
 end;
 
-procedure MC_RECV_Effect(P: Pointer);
+procedure MC_RECV_Effect(var M: TMsg);
 var
   Kind: Byte;
   X, Y: Integer;
@@ -1475,10 +1434,10 @@ var
   ID: LongWord;
 begin
   if not gGameOn then Exit;
-  Kind := e_Raw_Read_Byte(P);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  Ang := e_Raw_Read_SmallInt(P);
+  Kind := M.ReadByte();
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  Ang := M.ReadSmallInt();
 
   case Kind of
     NET_GFX_SPARK:
@@ -1570,40 +1529,40 @@ begin
   end;
 end;
 
-procedure MC_RECV_Sound(P: Pointer);
+procedure MC_RECV_Sound(var M: TMsg);
 var
   Name: string;
   X, Y: Integer;
   Pos: Boolean;
 begin
-  Name := e_Raw_Read_String(P);
-  Pos := e_Raw_Read_Byte(P) <> 0;
+  Name := M.ReadString();
+  Pos := M.ReadByte() <> 0;
   if Pos then
   begin
-    X := e_Raw_Read_LongInt(P);
-    Y := e_Raw_Read_LongInt(P);
+    X := M.ReadLongInt();
+    Y := M.ReadLongInt();
     g_Sound_PlayExAt(Name, X, Y);
   end
   else
     g_Sound_PlayEx(Name);
 end;
 
-procedure MC_RECV_CreateShot(P: Pointer);
+procedure MC_RECV_CreateShot(var M: TMsg);
 var
   I, X, Y, XV, YV: Integer;
   Timeout: LongWord;
   Target, Spawner: Word;
   ShType: Byte;
 begin
-  I := e_Raw_Read_LongInt(P);
-  ShType := e_Raw_Read_Byte(P);
-  Target := e_Raw_Read_Word(P);
-  Spawner := e_Raw_Read_Word(P);
-  Timeout := e_Raw_Read_LongWord(P);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  XV := e_Raw_Read_LongInt(P);
-  YV := e_Raw_Read_LongInt(P);
+  I := M.ReadLongInt();
+  ShType := M.ReadByte();
+  Target := M.ReadWord();
+  Spawner := M.ReadWord();
+  Timeout := M.ReadLongWord();
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  XV := M.ReadLongInt();
+  YV := M.ReadLongInt();
 
   I := g_Weapon_CreateShot(I, ShType, Spawner, Target, X, Y, XV, YV);
   if (Shots <> nil) and (I <= High(Shots)) then
@@ -1613,15 +1572,15 @@ begin
   end;
 end;
 
-procedure MC_RECV_UpdateShot(P: Pointer);
+procedure MC_RECV_UpdateShot(var M: TMsg);
 var
   I, TX, TY, TXV, TYV: Integer;
 begin
-  I := e_Raw_Read_LongInt(P);
-  TX := e_Raw_Read_LongInt(P);
-  TY := e_Raw_Read_LongInt(P);
-  TXV := e_Raw_Read_LongInt(P);
-  TYV := e_Raw_Read_LongInt(P);
+  I := M.ReadLongInt();
+  TX := M.ReadLongInt();
+  TY := M.ReadLongInt();
+  TXV := M.ReadLongInt();
+  TYV := M.ReadLongInt();
 
   if (Shots <> nil) and (I <= High(Shots)) then
     with (Shots[i]) do
@@ -1633,46 +1592,46 @@ begin
     end;
 end;
 
-procedure MC_RECV_DeleteShot(P: Pointer);
+procedure MC_RECV_DeleteShot(var M: TMsg);
 var
   I, X, Y: Integer;
   L: Boolean;
 begin
   if not gGameOn then Exit;
-  I := e_Raw_Read_LongInt(P);
-  L := (e_Raw_Read_Byte(P) <> 0);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
+  I := M.ReadLongInt();
+  L := (M.ReadByte() <> 0);
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
 
   g_Weapon_DestroyShot(I, X, Y, L);
 end;
 
-procedure MC_RECV_GameStats(P: Pointer);
+procedure MC_RECV_GameStats(var M: TMsg);
 begin
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
-    gTeamStat[TEAM_RED].Goals := e_Raw_Read_SmallInt(P);
-    gTeamStat[TEAM_BLUE].Goals := e_Raw_Read_SmallInt(P);
+    gTeamStat[TEAM_RED].Goals := M.ReadSmallInt();
+    gTeamStat[TEAM_BLUE].Goals := M.ReadSmallInt();
   end
   else
     if gGameSettings.GameMode = GM_COOP then
     begin
-      gCoopMonstersKilled := e_Raw_Read_Word(P);
-      gCoopSecretsFound := e_Raw_Read_Word(P);
+      gCoopMonstersKilled := M.ReadWord();
+      gCoopSecretsFound := M.ReadWord();
     end;
 end;
 
-procedure MC_RECV_CoopStats(P: Pointer);
+procedure MC_RECV_CoopStats(var M: TMsg);
 begin
-  gTotalMonsters := e_Raw_Read_LongInt(P);
-  gSecretsCount := e_Raw_Read_LongInt(P);
-  gCoopTotalMonstersKilled := e_Raw_Read_Word(P);
-  gCoopTotalSecretsFound := e_Raw_Read_Word(P);
-  gCoopTotalMonsters := e_Raw_Read_Word(P);
-  gCoopTotalSecrets := e_Raw_Read_Word(P);
+  gTotalMonsters := M.ReadLongInt();
+  gSecretsCount := M.ReadLongInt();
+  gCoopTotalMonstersKilled := M.ReadWord();
+  gCoopTotalSecretsFound := M.ReadWord();
+  gCoopTotalMonsters := M.ReadWord();
+  gCoopTotalSecrets := M.ReadWord();
 end;
 
-procedure MC_RECV_GameEvent(P: Pointer);
+procedure MC_RECV_GameEvent(var M: TMsg);
 var
   EvType: Byte;
   EvNum: Integer;
@@ -1686,16 +1645,16 @@ var
   cnt: Byte;
 begin
   FillChar(EvHash, Sizeof(EvHash), 0);
-  EvType := e_Raw_Read_Byte(P);
-  EvNum := e_Raw_Read_LongInt(P);
-  EvStr := e_Raw_Read_String(P);
-  gLastMap := e_Raw_Read_Byte(P) <> 0;
+  EvType := M.ReadByte();
+  EvNum := M.ReadLongInt();
+  EvStr := M.ReadString();
+  gLastMap := M.ReadByte() <> 0;
   if gLastMap and (gGameSettings.GameMode = GM_COOP) then gStatsOff := True;
   gStatsPressed := True;
-  EvTime := e_Raw_Read_LongWord(P);
-  BHash := e_Raw_Read_Byte(P) <> 0;
+  EvTime := M.ReadLongWord();
+  BHash := M.ReadByte() <> 0;
   if BHash then
-    EvHash := e_Raw_Read_MD5(P);
+    EvHash := M.ReadMD5();
 
   gTime := EvTime;
 
@@ -1712,7 +1671,7 @@ begin
       gWADHash := EvHash;
       if not g_Game_StartMap(EvStr, True) then
       begin
-        if Pos(':\', EvStr) = 0 then
+        if not isWadPath(EvStr) then
           g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + EvStr]))
         else
           g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [EvStr]));
@@ -1874,7 +1833,7 @@ begin
   end;
 end;
 
-procedure MC_RECV_FlagEvent(P: Pointer);
+procedure MC_RECV_FlagEvent(var M: TMsg);
 var
   PID: Word;
   Pl: TPlayer;
@@ -1883,20 +1842,20 @@ var
   Quiet: Boolean;
   s, ts: string;
 begin
-  EvType := e_Raw_Read_Byte(P);
-  Fl := e_Raw_Read_Byte(P);
+  EvType := M.ReadByte();
+  Fl := M.ReadByte();
 
   if Fl = FLAG_NONE then Exit;
 
-  Quiet := (e_Raw_Read_Byte(P) <> 0);
-  PID := e_Raw_Read_Word(P);
+  Quiet := (M.ReadByte() <> 0);
+  PID := M.ReadWord();
 
-  gFlags[Fl].State := e_Raw_Read_Byte(P);
-  gFlags[Fl].CaptureTime := e_Raw_Read_LongWord(P);
-  gFlags[Fl].Obj.X := e_Raw_Read_LongInt(P);
-  gFlags[Fl].Obj.Y := e_Raw_Read_LongInt(P);
-  gFlags[Fl].Obj.Vel.X := e_Raw_Read_LongInt(P);
-  gFlags[Fl].Obj.Vel.Y := e_Raw_Read_LongInt(P);
+  gFlags[Fl].State := M.ReadByte();
+  gFlags[Fl].CaptureTime := M.ReadLongWord();
+  gFlags[Fl].Obj.X := M.ReadLongInt();
+  gFlags[Fl].Obj.Y := M.ReadLongInt();
+  gFlags[Fl].Obj.Vel.X := M.ReadLongInt();
+  gFlags[Fl].Obj.Vel.Y := M.ReadLongInt();
 
   Pl := g_Player_Get(PID);
   if (Pl = nil) and
@@ -1981,18 +1940,18 @@ begin
   end;
 end;
 
-procedure MC_RECV_GameSettings(P: Pointer);
+procedure MC_RECV_GameSettings(var M: TMsg);
 begin
-  gGameSettings.GameMode := e_Raw_Read_Byte(P);
-  gGameSettings.GoalLimit := e_Raw_Read_Word(P);
-  gGameSettings.TimeLimit := e_Raw_Read_Word(P);
-  gGameSettings.MaxLives := e_Raw_Read_Byte(P);
-  gGameSettings.Options := e_Raw_Read_LongWord(P);
+  gGameSettings.GameMode := M.ReadByte();
+  gGameSettings.GoalLimit := M.ReadWord();
+  gGameSettings.TimeLimit := M.ReadWord();
+  gGameSettings.MaxLives := M.ReadByte();
+  gGameSettings.Options := M.ReadLongWord();
 end;
 
 // PLAYER
 
-function MC_RECV_PlayerCreate(P: Pointer): Word;
+function MC_RECV_PlayerCreate(var M: TMsg): Word;
 var
   PID, DID: Word;
   PName, Model: string;
@@ -2000,15 +1959,15 @@ var
   T: Byte;
   Pl: TPlayer;
 begin
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
 
-  PName := e_Raw_Read_String(P);
-  Model := e_Raw_Read_String(P);
-  Color.R := e_Raw_Read_Byte(P);
-  Color.G := e_Raw_Read_Byte(P);
-  Color.B := e_Raw_Read_Byte(P);
-  T := e_Raw_Read_Byte(P);
+  PName := M.ReadString();
+  Model := M.ReadString();
+  Color.R := M.ReadByte();
+  Color.G := M.ReadByte();
+  Color.B := M.ReadByte();
+  T := M.ReadByte();
 
   Result := 0;
   if (PID <> NetPlrUID1) and (PID <> NetPlrUID2) then
@@ -2037,11 +1996,11 @@ begin
   end;
 
   g_Console_Add(Format(_lc[I_PLAYER_JOIN], [PName]), True);
-  e_WriteLog('NET: Player ' + PName + ' [' + IntToStr(PID) + '] added.', MSG_NOTIFY);
+  e_WriteLog('NET: Player ' + PName + ' [' + IntToStr(PID) + '] added.', TMsgType.Notify);
   Result := PID;
 end;
 
-function MC_RECV_PlayerPos(P: Pointer): Word;
+function MC_RECV_PlayerPos(var M: TMsg): Word;
 var
   GT: LongWord;
   PID: Word;
@@ -2052,7 +2011,7 @@ var
 begin
   Result := 0;
 
-  GT := e_Raw_Read_LongWord(P);
+  GT := M.ReadLongWord();
   if GT < gTime - NET_MAX_DIFFTIME then
   begin
     gTime := GT;
@@ -2060,7 +2019,7 @@ begin
   end;
   gTime := GT;
 
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
 
   if Pl = nil then Exit;
@@ -2069,13 +2028,13 @@ begin
 
   with Pl do
   begin
-    FPing := e_Raw_Read_Word(P);
-    FLoss := e_Raw_Read_Byte(P);
-    kByte := e_Raw_Read_Word(P);
-    Dir := e_Raw_Read_Byte(P);
+    FPing := M.ReadWord();
+    FLoss := M.ReadByte();
+    kByte := M.ReadWord();
+    Dir := M.ReadByte();
 
-    TmpX := e_Raw_Read_LongInt(P);
-    TmpY := e_Raw_Read_LongInt(P);
+    TmpX := M.ReadLongInt();
+    TmpY := M.ReadLongInt();
 
     ReleaseKeys;
 
@@ -2093,16 +2052,16 @@ begin
     if ((Pl <> gPlayer1) and (Pl <> gPlayer2)) or LongBool(kByte and NET_KEY_FORCEDIR) then
       SetDirection(TDirection(Dir));
 
-    GameVelX := e_Raw_Read_LongInt(P);
-    GameVelY := e_Raw_Read_LongInt(P);
-    GameAccelX := e_Raw_Read_LongInt(P);
-    GameAccelY := e_Raw_Read_LongInt(P);
+    GameVelX := M.ReadLongInt();
+    GameVelY := M.ReadLongInt();
+    GameAccelX := M.ReadLongInt();
+    GameAccelY := M.ReadLongInt();
     SetLerp(TmpX, TmpY);
     if NetForcePlayerUpdate then Update();
   end;
 end;
 
-function MC_RECV_PlayerStats(P: Pointer): Word;
+function MC_RECV_PlayerStats(var M: TMsg): Word;
 var
   PID: Word;
   Pl: TPlayer;
@@ -2110,7 +2069,7 @@ var
   OldJet: Boolean;
   NewTeam: Byte;
 begin
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   Result := 0;
   if Pl = nil then
@@ -2118,45 +2077,45 @@ begin
 
   with Pl do
   begin
-    Live := (e_Raw_Read_Byte(P) <> 0);
-    GodMode := (e_Raw_Read_Byte(P) <> 0);
-    Health := e_Raw_Read_LongInt(P);
-    Armor := e_Raw_Read_LongInt(P);
-    Air := e_Raw_Read_LongInt(P);
-    JetFuel := e_Raw_Read_LongInt(P);
-    Lives := e_Raw_Read_Byte(P);
-    NewTeam := e_Raw_Read_Byte(P);
+    alive := (M.ReadByte() <> 0);
+    GodMode := (M.ReadByte() <> 0);
+    Health := M.ReadLongInt();
+    Armor := M.ReadLongInt();
+    Air := M.ReadLongInt();
+    JetFuel := M.ReadLongInt();
+    Lives := M.ReadByte();
+    NewTeam := M.ReadByte();
 
-    for I := WEAPON_KASTET to WEAPON_SUPERPULEMET do
-      FWeapon[I] := (e_Raw_Read_Byte(P) <> 0);
+    for I := WP_FIRST to WP_LAST do
+      FWeapon[I] := (M.ReadByte() <> 0);
 
-    for I := A_BULLETS to A_CELLS do
-      FAmmo[I] := e_Raw_Read_Word(P);
+    for I := A_BULLETS to A_HIGH do
+      FAmmo[I] := M.ReadWord();
 
-    for I := A_BULLETS to A_CELLS do
-      FMaxAmmo[I] := e_Raw_Read_Word(P);
+    for I := A_BULLETS to A_HIGH do
+      FMaxAmmo[I] := M.ReadWord();
 
     for I := MR_SUIT to MR_MAX do
-      FMegaRulez[I] := e_Raw_Read_LongWord(P);
+      FMegaRulez[I] := M.ReadLongWord();
 
     FRulez := [];
-    if (e_Raw_Read_Byte(P) <> 0) then
+    if (M.ReadByte() <> 0) then
       FRulez := FRulez + [R_ITEM_BACKPACK];
-    if (e_Raw_Read_Byte(P) <> 0) then
+    if (M.ReadByte() <> 0) then
       FRulez := FRulez + [R_KEY_RED];
-    if (e_Raw_Read_Byte(P) <> 0) then
+    if (M.ReadByte() <> 0) then
       FRulez := FRulez + [R_KEY_GREEN];
-    if (e_Raw_Read_Byte(P) <> 0) then
+    if (M.ReadByte() <> 0) then
       FRulez := FRulez + [R_KEY_BLUE];
-    if (e_Raw_Read_Byte(P) <> 0) then
+    if (M.ReadByte() <> 0) then
       FRulez := FRulez + [R_BERSERK];
 
-    Frags := e_Raw_Read_LongInt(P);
-    Death := e_Raw_Read_LongInt(P);
+    Frags := M.ReadLongInt();
+    Death := M.ReadLongInt();
 
-    SetWeapon(e_Raw_Read_Byte(P));
+    SetWeapon(M.ReadByte());
 
-    FSpectator := e_Raw_Read_Byte(P) <> 0;
+    FSpectator := M.ReadByte() <> 0;
     if FSpectator then
     begin
       if Pl = gPlayer1 then
@@ -2177,11 +2136,12 @@ begin
       if (gPlayer2 = nil) and (gLMSPID2 > 0) then
         gPlayer2 := g_Player_Get(gLMSPID2);
     end;
-    FGhost := e_Raw_Read_Byte(P) <> 0;
-    FPhysics := e_Raw_Read_Byte(P) <> 0;
-    FNoRespawn := e_Raw_Read_Byte(P) <> 0;
+    FGhost := M.ReadByte() <> 0;
+    FPhysics := M.ReadByte() <> 0;
+    FNoRespawn := M.ReadByte() <> 0;
     OldJet := FJetpack;
-    FJetpack := e_Raw_Read_Byte(P) <> 0;
+    FJetpack := M.ReadByte() <> 0;
+    FFireTime := M.ReadLongInt();
     if OldJet and not FJetpack then
       JetpackOff
     else if not OldJet and FJetpack then
@@ -2193,7 +2153,7 @@ begin
   Result := PID;
 end;
 
-function MC_RECV_PlayerDamage(P: Pointer): Word;
+function MC_RECV_PlayerDamage(var M: TMsg): Word;
 var
   PID: Word;
   Pl: TPlayer;
@@ -2203,15 +2163,15 @@ var
 begin
   Result := 0;
   if not gGameOn then Exit;
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   if Pl = nil then Exit;
 
-  Kind := e_Raw_Read_Byte(P);
-  Attacker := e_Raw_Read_Word(P);
-  Value := e_Raw_Read_Word(P);
-  VX := e_Raw_Read_Word(P);
-  VY := e_Raw_Read_Word(P);
+  Kind := M.ReadByte();
+  Attacker := M.ReadWord();
+  Value := M.ReadWord();
+  VX := M.ReadWord();
+  VY := M.ReadWord();
 
   with Pl do
     Damage(Value, Attacker, VX, VY, Kind);
@@ -2219,7 +2179,7 @@ begin
   Result := PID;
 end;
 
-function MC_RECV_PlayerDeath(P: Pointer): Word;
+function MC_RECV_PlayerDeath(var M: TMsg): Word;
 var
   PID: Word;
   Pl: TPlayer;
@@ -2228,13 +2188,13 @@ var
 begin
   Result := 0;
   if not gGameOn then Exit;
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   if Pl = nil then Exit;
 
-  KillType := e_Raw_Read_Byte(P);
-  DeathType := e_Raw_Read_Byte(P);
-  Attacker := e_Raw_Read_Word(P);
+  KillType := M.ReadByte();
+  DeathType := M.ReadByte();
+  Attacker := M.ReadWord();
 
   with Pl do
   begin
@@ -2243,25 +2203,25 @@ begin
   end;
 end;
 
-function MC_RECV_PlayerDelete(P: Pointer): Word;
+function MC_RECV_PlayerDelete(var M: TMsg): Word;
 var
   PID: Word;
   Pl: TPlayer;
 begin
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   Result := 0;
   if Pl = nil then Exit;
 
   g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
-  e_WriteLog('NET: Player ' + Pl.Name + ' [' + IntToStr(PID) + '] removed.', MSG_NOTIFY);
+  e_WriteLog('NET: Player ' + Pl.Name + ' [' + IntToStr(PID) + '] removed.', TMsgType.Notify);
 
   g_Player_Remove(PID);
 
   Result := PID;
 end;
 
-function MC_RECV_PlayerFire(P: Pointer): Word;
+function MC_RECV_PlayerFire(var M: TMsg): Word;
 var
   PID: Word;
   Weap: Byte;
@@ -2271,22 +2231,22 @@ var
 begin
   Result := 0;
   if not gGameOn then Exit;
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   if Pl = nil then Exit;
 
-  Weap := e_Raw_Read_Byte(P);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  AX := e_Raw_Read_LongInt(P);
-  AY := e_Raw_Read_LongInt(P);
-  SHID := e_Raw_Read_LongInt(P);
+  Weap := M.ReadByte();
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  AX := M.ReadLongInt();
+  AY := M.ReadLongInt();
+  SHID := M.ReadLongInt();
 
   with Pl do
-    if Live then NetFire(Weap, X, Y, AX, AY, SHID);
+    if alive then NetFire(Weap, X, Y, AX, AY, SHID);
 end;
 
-procedure MC_RECV_PlayerSettings(P: Pointer);
+procedure MC_RECV_PlayerSettings(var M: TMsg);
 var
   TmpName: string;
   TmpModel: string;
@@ -2295,16 +2255,16 @@ var
   Pl: TPlayer;
   PID: Word;
 begin
-  PID := e_Raw_Read_Word(P);
+  PID := M.ReadWord();
   Pl := g_Player_Get(PID);
   if Pl = nil then Exit;
 
-  TmpName := e_Raw_Read_String(P);
-  TmpModel := e_Raw_Read_String(P);
-  TmpColor.R := e_Raw_Read_Byte(P);
-  TmpColor.G := e_Raw_Read_Byte(P);
-  TmpColor.B := e_Raw_Read_Byte(P);
-  TmpTeam := e_Raw_Read_Byte(P);
+  TmpName := M.ReadString();
+  TmpModel := M.ReadString();
+  TmpColor.R := M.ReadByte();
+  TmpColor.G := M.ReadByte();
+  TmpColor.B := M.ReadByte();
+  TmpTeam := M.ReadByte();
 
   if (gGameSettings.GameMode in [GM_TDM, GM_CTF]) and (Pl.Team <> TmpTeam) then
   begin
@@ -2328,7 +2288,7 @@ end;
 
 // ITEM
 
-procedure MC_RECV_ItemSpawn(P: Pointer);
+procedure MC_RECV_ItemSpawn(var M: TMsg);
 var
   ID: Word;
   AID: DWord;
@@ -2336,21 +2296,25 @@ var
   T: Byte;
   Quiet, Fall{, Resp}: Boolean;
   Anim: TAnimation;
+  it: PItem;
 begin
   if not gGameOn then Exit;
-  ID := e_Raw_Read_Word(P);
-  Quiet := e_Raw_Read_Byte(P) <> 0;
-  T := e_Raw_Read_Byte(P);
-  Fall := e_Raw_Read_Byte(P) <> 0;
-  {Resp :=} e_Raw_Read_Byte(P);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  VX := e_Raw_Read_LongInt(P);
-  VY := e_Raw_Read_LongInt(P);
-
-  g_Items_Create(X, Y, T, Fall, False, False, ID);
-  gItems[ID].Obj.Vel.X := VX;
-  gItems[ID].Obj.Vel.Y := VY;
+  ID := M.ReadWord();
+  Quiet := M.ReadByte() <> 0;
+  T := M.ReadByte();
+  Fall := M.ReadByte() <> 0;
+  {Resp :=} M.ReadByte();
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  VX := M.ReadLongInt();
+  VY := M.ReadLongInt();
+
+  g_Items_Create(X, Y, T and $7F, Fall, False, False, ID);
+  if ((T and $80) <> 0) then g_Items_SetDrop(ID);
+
+  it := g_Items_ByIdx(ID);
+  it.Obj.Vel.X := VX;
+  it.Obj.Vel.Y := VY;
 
   if not Quiet then
   begin
@@ -2358,158 +2322,121 @@ begin
     if g_Frames_Get(AID, 'FRAMES_ITEM_RESPAWN') then
     begin
       Anim := TAnimation.Create(AID, False, 4);
-      g_GFX_OnceAnim(X+(gItems[ID].Obj.Rect.Width div 2)-16, Y+(gItems[ID].Obj.Rect.Height div 2)-16, Anim);
+      g_GFX_OnceAnim(X+(it.Obj.Rect.Width div 2)-16, Y+(it.Obj.Rect.Height div 2)-16, Anim);
       Anim.Free();
     end;
   end;
 end;
 
-procedure MC_RECV_ItemDestroy(P: Pointer);
+procedure MC_RECV_ItemDestroy(var M: TMsg);
 var
   ID: Word;
   Quiet: Boolean;
 begin
   if not gGameOn then Exit;
-  ID := e_Raw_Read_Word(P);
-  Quiet := e_Raw_Read_Byte(P) <> 0;
-  if gItems = nil then Exit;
-  if (ID > High(gItems)) then Exit;
+  ID := M.ReadWord();
+  Quiet := M.ReadByte() <> 0;
 
-  if not Quiet then
-    if gSoundEffectsDF then
-    begin
-      if gItems[ID].ItemType in [ITEM_SPHERE_BLUE, ITEM_SPHERE_WHITE, ITEM_INVUL,
-                                 ITEM_INVIS, ITEM_MEDKIT_BLACK, ITEM_JETPACK] then
-        g_Sound_PlayExAt('SOUND_ITEM_GETRULEZ',
-          gItems[ID].Obj.X, gItems[ID].Obj.Y)
-        else
-          if gItems[ID].ItemType in [ITEM_WEAPON_SAW, ITEM_WEAPON_PISTOL, ITEM_WEAPON_SHOTGUN1, ITEM_WEAPON_SHOTGUN2,
-                                     ITEM_WEAPON_CHAINGUN, ITEM_WEAPON_ROCKETLAUNCHER, ITEM_WEAPON_PLASMA,
-                                     ITEM_WEAPON_BFG, ITEM_WEAPON_SUPERPULEMET, ITEM_AMMO_BACKPACK] then
-            g_Sound_PlayExAt('SOUND_ITEM_GETWEAPON',
-              gItems[ID].Obj.X, gItems[ID].Obj.Y)
-            else
-              g_Sound_PlayExAt('SOUND_ITEM_GETITEM',
-                gItems[ID].Obj.X, gItems[ID].Obj.Y);
-    end
-    else
-    begin
-      if gItems[ID].ItemType in [ITEM_SPHERE_BLUE, ITEM_SPHERE_WHITE, ITEM_SUIT,
-                                 ITEM_MEDKIT_BLACK, ITEM_INVUL, ITEM_INVIS, ITEM_JETPACK] then
-        g_Sound_PlayExAt('SOUND_ITEM_GETRULEZ',
-          gItems[ID].Obj.X, gItems[ID].Obj.Y)
-      else
-        if gItems[ID].ItemType in [ITEM_WEAPON_SAW, ITEM_WEAPON_PISTOL, ITEM_WEAPON_SHOTGUN1, ITEM_WEAPON_SHOTGUN2,
-                                   ITEM_WEAPON_CHAINGUN, ITEM_WEAPON_ROCKETLAUNCHER, ITEM_WEAPON_PLASMA,
-                                   ITEM_WEAPON_BFG, ITEM_WEAPON_SUPERPULEMET] then
-          g_Sound_PlayExAt('SOUND_ITEM_GETWEAPON',
-            gItems[ID].Obj.X, gItems[ID].Obj.Y)
-        else
-          g_Sound_PlayExAt('SOUND_ITEM_GETITEM',
-            gItems[ID].Obj.X, gItems[ID].Obj.Y);
-    end;
+  if not g_Items_ValidId(ID) then exit;
+
+  if not Quiet then g_Items_EmitPickupSound(ID);
 
   g_Items_Remove(ID);
 end;
 
 // PANEL
 
-procedure MC_RECV_PanelTexture(P: Pointer);
+procedure MC_RECV_PanelTexture(var M: TMsg);
 var
   TP: TPanel;
-  PType: Word;
-  ID: LongWord;
+  PGUID: Integer;
   Tex, Fr: Integer;
   Loop, Cnt: Byte;
 begin
   if not gGameOn then Exit;
-  PType := e_Raw_Read_Word(P);
-  ID := e_Raw_Read_LongWord(P);
-  Tex := e_Raw_Read_LongInt(P);
-  Fr := e_Raw_Read_LongInt(P);
-  Cnt := e_Raw_Read_Byte(P);
-  Loop := e_Raw_Read_Byte(P);
-
-  TP := nil;
-
-  case PType of
-    PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
-     if gWalls <> nil then
-      TP := gWalls[ID];
-    PANEL_FORE:
-     if gRenderForegrounds <> nil then
-      TP := gRenderForegrounds[ID];
-    PANEL_BACK:
-     if gRenderBackgrounds <> nil then
-      TP := gRenderBackgrounds[ID];
-    PANEL_WATER:
-     if gWater <> nil then
-      TP := gWater[ID];
-    PANEL_ACID1:
-     if gAcid1 <> nil then
-      TP := gAcid1[ID];
-    PANEL_ACID2:
-     if gAcid2 <> nil then
-      TP := gAcid2[ID];
-    PANEL_STEP:
-     if gSteps <> nil then
-      TP := gSteps[ID];
-    else
-      Exit;
-  end;
 
-  if TP <> nil then
-    if Loop = 0 then
-    begin    // switch texture
-      TP.SetTexture(Tex, Loop);
-      TP.SetFrame(Fr, Cnt);
-    end else // looped or non-looped animation
-      TP.NextTexture(Loop);
+  PGUID := Integer(M.ReadLongWord());
+  Tex := M.ReadLongInt();
+  Fr := M.ReadLongInt();
+  Cnt := M.ReadByte();
+  Loop := M.ReadByte();
+
+  TP := g_Map_PanelByGUID(PGUID);
+  if (TP <> nil) then
+  begin
+    // switch texture
+    TP.SetTexture(Tex, Loop);
+    TP.SetFrame(Fr, Cnt);
+  end;
 end;
 
-procedure MC_RECV_PanelState(P: Pointer);
+procedure MC_RECV_PanelState(var M: TMsg);
 var
-  ID: LongWord;
+  PGUID: Integer;
   E: Boolean;
   Lift: Byte;
-  PType: Word;
-  X, Y: Integer;
+  X, Y, W, H: Integer;
+  TP: TPanel;
+  speedX, speedY, startX, startY, endX, endY: Integer;
+  sizeSpX, sizeSpY, sizeEX, sizeEY: Integer;
+  mpflags: Byte;
 begin
   if not gGameOn then Exit;
-  PType := e_Raw_Read_Word(P);
-  ID := e_Raw_Read_LongWord(P);
-  E := (e_Raw_Read_Byte(P) <> 0);
-  Lift := e_Raw_Read_Byte(P);
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-
-  case PType of
-    PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
-      if E then
-        g_Map_EnableWall(ID)
-      else
-        g_Map_DisableWall(ID);
-
-    PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
-      g_Map_SetLift(ID, Lift);
-
-    PANEL_BACK:
-    begin
-      gRenderBackgrounds[ID].X := X;
-      gRenderBackgrounds[ID].Y := Y;
-    end;
 
-    PANEL_FORE:
-    begin
-      gRenderForegrounds[ID].X := X;
-      gRenderForegrounds[ID].Y := Y;
-    end;      
-  end;
+  PGUID := Integer(M.ReadLongWord());
+  E := (M.ReadByte() <> 0);
+  Lift := M.ReadByte();
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  W := M.ReadWord();
+  H := M.ReadWord();
+  // mplats
+  speedX := M.ReadLongInt();
+  speedY := M.ReadLongInt();
+  startX := M.ReadLongInt();
+  startY := M.ReadLongInt();
+  endX := M.ReadLongInt();
+  endY := M.ReadLongInt();
+  sizeSpX := M.ReadLongInt();
+  sizeSpY := M.ReadLongInt();
+  sizeEX := M.ReadLongInt();
+  sizeEY := M.ReadLongInt();
+  mpflags := M.ReadByte(); // bit0: TP.movingActive; bit1: TP.moveOnce
+
+  TP := g_Map_PanelByGUID(PGUID);
+  if (TP = nil) then exit;
+
+  // update lifts state
+  if TP.isGLift then g_Map_SetLiftGUID(PGUID, Lift);
+
+  // update enabled/disabled state for all panels
+  if E then g_Map_EnableWallGUID(PGUID) else g_Map_DisableWallGUID(PGUID);
+
+  // update panel position, as it can be moved (mplat)
+  TP.X := X;
+  TP.Y := Y;
+  TP.Width := W;
+  TP.Height := H;
+  // update mplat state
+  TP.movingSpeedX := speedX;
+  TP.movingSpeedY := speedY;
+  TP.movingStartX := startX;
+  TP.movingStartY := startY;
+  TP.movingEndX := endX;
+  TP.movingEndY := endY;
+  TP.sizeSpeedX := sizeSpX;
+  TP.sizeSpeedY := sizeSpY;
+  TP.sizeEndX := sizeEX;
+  TP.sizeEndY := sizeEY;
+  TP.movingActive := ((mpflags and 1) <> 0);
+  TP.moveOnce := ((mpflags and 2) <> 0);
+  // notify panel of it's position/size change, so it can fix other internal structures
+  TP.positionChanged();
 end;
 
 // TRIGGERS
 
-procedure MC_RECV_TriggerSound(P: Pointer);
+procedure MC_RECV_TriggerSound(var M: TMsg);
 var
   SPlaying: Boolean;
   SPos, SID: LongWord;
@@ -2519,32 +2446,35 @@ begin
   if not gGameOn then Exit;
   if gTriggers = nil then Exit;
 
-  SID := e_Raw_Read_LongWord(P);
-  SPlaying := e_Raw_Read_Byte(P) <> 0;
-  SPos := e_Raw_Read_LongWord(P);
-  SCount := e_Raw_Read_LongInt(P);
+  SID := M.ReadLongWord();
+  SPlaying := M.ReadByte() <> 0;
+  SPos := M.ReadLongWord();
+  SCount := M.ReadLongInt();
 
   for I := Low(gTriggers) to High(gTriggers) do
     if gTriggers[I].TriggerType = TRIGGER_SOUND then
       if gTriggers[I].ClientID = SID then
         with gTriggers[I] do
         begin
-          if SPlaying then
+          if Sound <> nil then
           begin
-            if Data.Local then
-              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0)
+            if SPlaying then
+            begin
+              if tgcLocal then
+                Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), tgcVolume/255.0)
+              else
+                Sound.PlayPanVolume((tgcPan-127.0)/128.0, tgcVolume/255.0);
+              Sound.SetPosition(SPos);
+            end
             else
-              Sound.PlayPanVolume((Data.Pan-127.0)/128.0, Data.Volume/255.0);
-            Sound.SetPosition(SPos);
-          end
-          else
-            if Sound.IsPlaying then Sound.Stop;
+              if Sound.IsPlaying then Sound.Stop;
+          end;
 
           SoundPlayCount := SCount;
         end;
 end;
 
-procedure MC_RECV_TriggerMusic(P: Pointer);
+procedure MC_RECV_TriggerMusic(var M: TMsg);
 var
   MName: string;
   MPlaying: Boolean;
@@ -2553,10 +2483,10 @@ var
 begin
   if not gGameOn then Exit;
 
-  MName := e_Raw_Read_String(P);
-  MPlaying := e_Raw_Read_Byte(P) <> 0;
-  MPos := e_Raw_Read_LongWord(P);
-  MPaused := e_Raw_Read_Byte(P) <> 0;
+  MName := M.ReadString();
+  MPlaying := M.ReadByte() <> 0;
+  MPos := M.ReadLongWord();
+  MPaused := M.ReadByte() <> 0;
 
   if MPlaying then
   begin
@@ -2571,46 +2501,42 @@ end;
 
 // MONSTERS
 
-procedure MC_RECV_MonsterSpawn(P: Pointer);
+procedure MC_RECV_MonsterSpawn(var M: TMsg);
 var
   ID: Word;
   MType, MState, MDir, MAnim, MBehav: Byte;
   X, Y, VX, VY, MTargTime, MHealth, MAmmo, MSleep: Integer;
   MTarg: Word;
-  M: TMonster;
+  Mon: TMonster;
 begin
-  ID := e_Raw_Read_Word(P);
-  M := g_Monsters_Get(ID);
-  if M <> nil then
+  ID := M.ReadWord();
+  Mon := g_Monsters_ByUID(ID);
+  if Mon <> nil then
     Exit;
 
-  MType := e_Raw_Read_Byte(P);
-  MState := e_Raw_Read_Byte(P);
-  MAnim := e_Raw_Read_Byte(P);
-  MTarg := e_Raw_Read_Word(P);
-  MTargTime := e_Raw_Read_LongInt(P);
-  MBehav := e_Raw_Read_Byte(P);
-  MSleep := e_Raw_Read_LongInt(P);
-  MHealth := e_Raw_Read_LongInt(P);
-  MAmmo := e_Raw_Read_LongInt(P);
-
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  VX := e_Raw_Read_LongInt(P);
-  VY := e_Raw_Read_LongInt(P);
-  MDir := e_Raw_Read_Byte(P);
+  MType := M.ReadByte();
+  MState := M.ReadByte();
+  MAnim := M.ReadByte();
+  MTarg := M.ReadWord();
+  MTargTime := M.ReadLongInt();
+  MBehav := M.ReadByte();
+  MSleep := M.ReadLongInt();
+  MHealth := M.ReadLongInt();
+  MAmmo := M.ReadLongInt();
+
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  VX := M.ReadLongInt();
+  VY := M.ReadLongInt();
+  MDir := M.ReadByte();
 
   g_Monsters_Create(MType, X, Y, TDirection(MDir), False, ID);
-  M := g_Monsters_Get(ID);
-  if M = nil then
+  Mon := g_Monsters_ByUID(ID);
+  if Mon = nil then
     Exit;
 
-  with M do
+  with Mon do
   begin
-    GameX := X;
-    GameY := Y;
-    GameVelX := VX;
-    GameVelY := VY;
 
     MonsterAnim := MAnim;
     MonsterTargetUID := MTarg;
@@ -2621,125 +2547,126 @@ begin
     SetHealth(MHealth);
 
     SetState(MState);
+
+    setPosition(X, Y); // this will call positionChanged();
+    GameVelX := VX;
+    GameVelY := VY;
   end;
 end;
 
-procedure MC_RECV_MonsterPos(P: Pointer);
+procedure MC_RECV_MonsterPos(var M: TMsg);
 var
-  M: TMonster;
+  Mon: TMonster;
   ID: Word;
+  X, Y: Integer;
 begin
-  ID := e_Raw_Read_Word(P);
-  M := g_Monsters_Get(ID);
-  if M = nil then
+  ID := M.ReadWord();
+  Mon := g_Monsters_ByUID(ID);
+  if Mon = nil then
     Exit;
 
-  with M do
+  with Mon do
   begin
-    GameX := e_Raw_Read_LongInt(P);
-    GameY := e_Raw_Read_LongInt(P);
-    GameVelX := e_Raw_Read_LongInt(P);
-    GameVelY := e_Raw_Read_LongInt(P);
-    GameDirection := TDirection(e_Raw_Read_Byte(P));
+    X := M.ReadLongInt();
+    Y := M.ReadLongInt();
+    Mon.setPosition(X, Y); // this will call `positionChanged()`
+    GameVelX := M.ReadLongInt();
+    GameVelY := M.ReadLongInt();
+    GameDirection := TDirection(M.ReadByte());
   end;
 end;
 
-procedure MC_RECV_MonsterState(P: Pointer);
+procedure MC_RECV_MonsterState(var M: TMsg);
 var
   ID: Integer;
   MState, MFAnm: Byte;
-  M: TMonster;
+  Mon: TMonster;
   AnimRevert: Boolean;
 begin
-  ID := e_Raw_Read_Word(P);
-  M := g_Monsters_Get(ID);
-  if M = nil then Exit;
+  ID := M.ReadWord();
+  Mon := g_Monsters_ByUID(ID);
+  if Mon = nil then Exit;
 
-  MState := e_Raw_Read_Byte(P);
-  MFAnm := e_Raw_Read_Byte(P);
+  MState := M.ReadByte();
+  MFAnm := M.ReadByte();
 
-  with M do
+  with Mon do
   begin
-    MonsterTargetUID := e_Raw_Read_Word(P);
-    MonsterTargetTime := e_Raw_Read_LongInt(P);
-    MonsterSleep := e_Raw_Read_LongInt(P);
-    MonsterHealth := e_Raw_Read_LongInt(P);
-    MonsterAmmo := e_Raw_Read_LongInt(P);
-    MonsterPain := e_Raw_Read_LongInt(P);
-    AnimRevert := e_Raw_Read_Byte(P) <> 0;
+    MonsterTargetUID := M.ReadWord();
+    MonsterTargetTime := M.ReadLongInt();
+    MonsterSleep := M.ReadLongInt();
+    MonsterHealth := M.ReadLongInt();
+    MonsterAmmo := M.ReadLongInt();
+    MonsterPain := M.ReadLongInt();
+    AnimRevert := M.ReadByte() <> 0;
+    FFireTime := M.ReadLongInt();
     RevertAnim(AnimRevert);
 
     if MonsterState <> MState then
     begin
-      if (MState = MONSTATE_GO) and (MonsterState = MONSTATE_SLEEP) then
-        WakeUpSound;
-      if (MState = MONSTATE_DIE) then
-        DieSound;
-      if (MState = MONSTATE_PAIN) then
-        MakeBloodSimple(Min(200, MonsterPain));
-      if (MState = MONSTATE_ATTACK) then
-        kick(nil);
-      if (MState = MONSTATE_DEAD) then
-        SetDeadAnim;
+      if (MState = MONSTATE_GO) and (MonsterState = MONSTATE_SLEEP) then WakeUpSound();
+      if (MState = MONSTATE_DIE) then DieSound();
+      if (MState = MONSTATE_PAIN) then MakeBloodSimple(Min(200, MonsterPain));
+      if (MState = MONSTATE_ATTACK) then kick(nil);
+      if (MState = MONSTATE_DEAD) then SetDeadAnim();
 
       SetState(MState, MFAnm);
     end;
   end;
 end;
 
-procedure MC_RECV_MonsterShot(P: Pointer);
+procedure MC_RECV_MonsterShot(var M: TMsg);
 var
   ID: Integer;
-  M: TMonster;
+  Mon: TMonster;
   X, Y, VX, VY: Integer;
 begin
-  ID := e_Raw_Read_Word(P);
+  ID := M.ReadWord();
 
-  M := g_Monsters_Get(ID);
-  if M = nil then Exit;
+  Mon := g_Monsters_ByUID(ID);
+  if Mon = nil then Exit;
 
-  X := e_Raw_Read_LongInt(P);
-  Y := e_Raw_Read_LongInt(P);
-  VX := e_Raw_Read_LongInt(P);
-  VY := e_Raw_Read_LongInt(P);
+  X := M.ReadLongInt();
+  Y := M.ReadLongInt();
+  VX := M.ReadLongInt();
+  VY := M.ReadLongInt();
 
-  M.ClientAttack(X, Y, VX, VY);
+  Mon.ClientAttack(X, Y, VX, VY);
 end;
 
-procedure MC_RECV_MonsterDelete(P: Pointer);
+procedure MC_RECV_MonsterDelete(var M: TMsg);
 var
   ID: Integer;
-  M: TMonster;
+  Mon: TMonster;
 begin
-  ID := e_Raw_Read_Word(P);
-  M := g_Monsters_Get(ID);
-  if M = nil then Exit;
-
-  gMonsters[ID].SetState(5);
-  gMonsters[ID].MonsterRemoved := True;
+  ID := M.ReadWord();
+  Mon := g_Monsters_ByUID(ID);
+  if Mon = nil then Exit;
+  Mon.SetState(5);
+  Mon.MonsterRemoved := True;
 end;
 
-procedure MC_RECV_TimeSync(P: Pointer);
+procedure MC_RECV_TimeSync(var M: TMsg);
 var
   Time: LongWord;
 begin
-  Time := e_Raw_Read_LongWord(P);
+  Time := M.ReadLongWord();
 
   if gState = STATE_INTERCUSTOM then
     gServInterTime := Min(Time, 255);
 end;
 
-procedure MC_RECV_VoteEvent(P: Pointer);
+procedure MC_RECV_VoteEvent(var M: TMsg);
 var
   EvID: Byte;
   Str1, Str2: string;
   Int1, Int2: SmallInt;
 begin
-  EvID := e_Raw_Read_Byte(P);
-  Int1 := e_Raw_Read_SmallInt(P);
-  Int2 := e_Raw_Read_SmallInt(P);
-  Str1 := e_Raw_Read_String(P);
-  Str2 := e_Raw_Read_String(P);
+  EvID := M.ReadByte();
+  Int1 := M.ReadSmallInt();
+  Int2 := M.ReadSmallInt();
+  Str1 := M.ReadString();
+  Str2 := M.ReadString();
 
   case EvID of
     NET_VE_STARTED:
@@ -2759,26 +2686,26 @@ end;
 
 procedure MC_SEND_Info(Password: string);
 begin
-  e_Buffer_Clear(@NetOut);
+  NetOut.Clear();
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_INFO));
-  e_Buffer_Write(@NetOut, GAME_VERSION);
-  e_Buffer_Write(@NetOut, Password);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Name);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Model);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.R);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.G);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.B);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Team);
+  NetOut.Write(Byte(NET_MSG_INFO));
+  NetOut.Write(GAME_VERSION);
+  NetOut.Write(Password);
+  NetOut.Write(gPlayer1Settings.Name);
+  NetOut.Write(gPlayer1Settings.Model);
+  NetOut.Write(gPlayer1Settings.Color.R);
+  NetOut.Write(gPlayer1Settings.Color.G);
+  NetOut.Write(gPlayer1Settings.Color.B);
+  NetOut.Write(gPlayer1Settings.Team);
 
   g_Net_Client_Send(True, NET_CHAN_SERVICE);
 end;
 
 procedure MC_SEND_Chat(Txt: string; Mode: Byte);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_CHAT));
-  e_Buffer_Write(@NetOut, Txt);
-  e_Buffer_Write(@NetOut, Mode);
+  NetOut.Write(Byte(NET_MSG_CHAT));
+  NetOut.Write(Txt);
+  NetOut.Write(Mode);
 
   g_Net_Client_Send(True, NET_CHAN_CHAT);
 end;
@@ -2821,13 +2748,13 @@ begin
         // new strafe mechanics
         if (strafeDir = 0) then strafeDir := P1MoveButton; // start strafing
         // now set direction according to strafe (reversed)
-             if (strafeDir = 2) then gPlayer1.SetDirection(D_LEFT)
-        else if (strafeDir = 1) then gPlayer1.SetDirection(D_RIGHT);
+             if (strafeDir = 2) then gPlayer1.SetDirection(TDirection.D_LEFT)
+        else if (strafeDir = 1) then gPlayer1.SetDirection(TDirection.D_RIGHT);
       end
       else
       begin
-             if (P1MoveButton = 2) and isKeyPressed(KeyLeft, KeyLeft2) then gPlayer1.SetDirection(D_LEFT)
-        else if (P1MoveButton = 1) and isKeyPressed(KeyRight, KeyRight2) then gPlayer1.SetDirection(D_RIGHT)
+             if (P1MoveButton = 2) and isKeyPressed(KeyLeft, KeyLeft2) then gPlayer1.SetDirection(TDirection.D_LEFT)
+        else if (P1MoveButton = 1) and isKeyPressed(KeyRight, KeyRight2) then gPlayer1.SetDirection(TDirection.D_RIGHT)
         else if P1MoveButton <> 0 then gPlayer1.SetDirection(TDirection(P1MoveButton-1));
       end;
 
@@ -2871,11 +2798,11 @@ begin
   else
     kByte := NET_KEY_CHAT;
 
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRPOS));
-  e_Buffer_Write(@NetOut, gTime);
-  e_Buffer_Write(@NetOut, kByte);
-  e_Buffer_Write(@NetOut, Byte(gPlayer1.Direction));
-  e_Buffer_Write(@NetOut, WeaponSelect);
+  NetOut.Write(Byte(NET_MSG_PLRPOS));
+  NetOut.Write(gTime);
+  NetOut.Write(kByte);
+  NetOut.Write(Byte(gPlayer1.Direction));
+  NetOut.Write(WeaponSelect);
   //e_WriteLog(Format('S:ws=%d', [WeaponSelect]), MSG_WARNING);
   g_Net_Client_Send(True, NET_CHAN_PLAYERPOS);
 
@@ -2885,50 +2812,50 @@ end;
 
 procedure MC_SEND_Vote(Start: Boolean = False; Command: string = 'a');
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_VOTE_EVENT));
-  e_Buffer_Write(@NetOut, Byte(Start));
-  e_Buffer_Write(@NetOut, Command);
+  NetOut.Write(Byte(NET_MSG_VOTE_EVENT));
+  NetOut.Write(Byte(Start));
+  NetOut.Write(Command);
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;
 
 procedure MC_SEND_PlayerSettings();
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_PLRSET));
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Name);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Model);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.R);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.G);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Color.B);
-  e_Buffer_Write(@NetOut, gPlayer1Settings.Team);
+  NetOut.Write(Byte(NET_MSG_PLRSET));
+  NetOut.Write(gPlayer1Settings.Name);
+  NetOut.Write(gPlayer1Settings.Model);
+  NetOut.Write(gPlayer1Settings.Color.R);
+  NetOut.Write(gPlayer1Settings.Color.G);
+  NetOut.Write(gPlayer1Settings.Color.B);
+  NetOut.Write(gPlayer1Settings.Team);
 
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;
 
 procedure MC_SEND_FullStateRequest();
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_REQFST));
+  NetOut.Write(Byte(NET_MSG_REQFST));
 
   g_Net_Client_Send(True, NET_CHAN_SERVICE);
 end;
 
 procedure MC_SEND_CheatRequest(Kind: Byte);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_CHEAT));
-  e_Buffer_Write(@NetOut, Kind);
+  NetOut.Write(Byte(NET_MSG_CHEAT));
+  NetOut.Write(Kind);
 
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;
 procedure MC_SEND_RCONPassword(Password: string);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_RCON_AUTH));
-  e_Buffer_Write(@NetOut, Password);
+  NetOut.Write(Byte(NET_MSG_RCON_AUTH));
+  NetOut.Write(Password);
 
   g_Net_Client_Send(True, NET_CHAN_SERVICE);
 end;
 procedure MC_SEND_RCONCommand(Cmd: string);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_RCON_CMD));
-  e_Buffer_Write(@NetOut, Cmd);
+  NetOut.Write(Byte(NET_MSG_RCON_CMD));
+  NetOut.Write(Cmd);
 
   g_Net_Client_Send(True, NET_CHAN_SERVICE);
 end;
@@ -2940,15 +2867,15 @@ var
   FileStream : TStream;
   fname: string;
 begin
-  e_WriteLog(Format('NETWORK: looking for file "%s"', [FileName]), MSG_NOTIFY);
+  e_WriteLog(Format('NETWORK: looking for file "%s"', [FileName]), TMsgType.Notify);
   fname := findDiskWad(FileName);
   if length(fname) = 0 then
   begin
-    e_WriteLog(Format('NETWORK: file "%s" not found!', [FileName]), MSG_FATALERROR);
+    e_WriteLog(Format('NETWORK: file "%s" not found!', [FileName]), TMsgType.Fatal);
     SetLength(Result, 0);
     exit;
   end;
-  e_WriteLog(Format('NETWORK: found file "%s"', [fname]), MSG_NOTIFY);
+  e_WriteLog(Format('NETWORK: found file "%s"', [fname]), TMsgType.Notify);
   Result := nil;
   FileStream := openDiskFileRO(fname);
   try
@@ -3069,28 +2996,28 @@ end;
 
 procedure MC_SEND_MapRequest();
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_MAP_REQUEST));
+  NetOut.Write(Byte(NET_MSG_MAP_REQUEST));
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;
 
 procedure MC_SEND_ResRequest(const resName: AnsiString);
 begin
-  e_Buffer_Write(@NetOut, Byte(NET_MSG_RES_REQUEST));
-  e_Buffer_Write(@NetOut, resName);
+  NetOut.Write(Byte(NET_MSG_RES_REQUEST));
+  NetOut.Write(resName);
   g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
 end;
 
-procedure MH_RECV_MapRequest(C: pTNetClient; P: Pointer);
+procedure MH_RECV_MapRequest(C: pTNetClient; var M: TMsg);
 var
   payload: AByte;
   peer: pENetPeer;
   mapDataMsg: TMapDataMsg;
 begin
   e_WriteLog('NET: Received map request from ' +
-             DecodeIPV4(C.Peer.address.host), MSG_NOTIFY);
+             DecodeIPV4(C^.Peer.address.host), TMsgType.Notify);
 
   mapDataMsg := CreateMapDataMsg(MapsDir + gGameSettings.WAD, gExternalResources);
-  peer := NetClients[C.ID].Peer;
+  peer := NetClients[C^.ID].Peer;
 
   MapDataMsgToBytes(payload, mapDataMsg);
   g_Net_SendData(payload, peer, True, NET_CHAN_DOWNLOAD);
@@ -3100,24 +3027,24 @@ begin
   mapDataMsg.ExternalResources := nil;
 end;
 
-procedure MH_RECV_ResRequest(C: pTNetClient; P: Pointer);
+procedure MH_RECV_ResRequest(C: pTNetClient; var M: TMsg);
 var
   payload: AByte;
   peer: pENetPeer;
   FileName: String;
   resDataMsg: TResDataMsg;
 begin
-  FileName := ExtractFileName(e_Raw_Read_String(P));
+  FileName := ExtractFileName(M.ReadString());
   e_WriteLog('NET: Received res request: ' + FileName +
-             ' from ' + DecodeIPV4(C.Peer.address.host), MSG_NOTIFY);
+             ' from ' + DecodeIPV4(C^.Peer.address.host), TMsgType.Notify);
 
   if not IsValidFilePath(FileName) then
   begin
-    e_WriteLog('Invalid filename: ' + FileName, MSG_WARNING);
+    e_WriteLog('Invalid filename: ' + FileName, TMsgType.Warning);
     exit;
   end;
 
-  peer := NetClients[C.ID].Peer;
+  peer := NetClients[C^.ID].Peer;
 
   if gExternalResources.IndexOf(FileName) > -1 then
   begin