diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index 53ab6a501b063c2cae51a19a9edcf326df2840a4..244b2ebd716ef55a21674fbd4b375f9c2324aad8 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
-(* 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
NET_MSG_TIME_SYNC = 194;
NET_MSG_VOTE_EVENT = 195;
+ {
NET_MSG_MAP_REQUEST = 201;
NET_MSG_MAP_RESPONSE = 202;
NET_MSG_RES_REQUEST = 203;
NET_MSG_RES_RESPONSE = 204;
+ }
NET_CHAT_SYSTEM = 0;
NET_CHAT_PLAYER = 1;
NET_EV_LMS_DRAW = 16;
NET_EV_KILLCOMBO = 17;
NET_EV_PLAYER_TOUCH = 18;
+ NET_EV_SECRET = 19;
+ NET_EV_INTER_READY = 20;
NET_VE_STARTED = 1;
NET_VE_PASSED = 2;
NET_CHEAT_SUICIDE = 1;
NET_CHEAT_SPECTATE = 2;
+ NET_CHEAT_READY = 3;
NET_MAX_DIFFTIME = 5000 div 36;
// HOST MESSAGES
+procedure MH_ProcessFirstSpawn (C: pTNetClient);
+
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);
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_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);
+procedure MH_SEND_Everything(CreatePlayers: Boolean {= False}; ID: Integer {= NET_EVERYONE});
procedure MH_SEND_Info(ID: Byte);
procedure MH_SEND_Chat(Txt: string; Mode: Byte; ID: Integer = NET_EVERYONE);
procedure MH_SEND_Effect(X, Y: Integer; Ang: SmallInt; Kind: Byte; ID: Integer = NET_EVERYONE);
@@ -168,8 +174,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; PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
-procedure MH_SEND_PanelState(PType: Word; PGUID: Integer; 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);
procedure MC_SEND_RCONCommand(Cmd: string);
procedure MC_SEND_Vote(Start: Boolean = False; Command: string = 'a');
// DOWNLOAD
-procedure MC_SEND_MapRequest();
-procedure MC_SEND_ResRequest(const resName: AnsiString);
+//procedure MC_SEND_MapRequest();
+//procedure MC_SEND_ResRequest(const resName: AnsiString);
+
type
TExternalResourceInfo = record
ExternalResources: array of TExternalResourceInfo;
end;
-function MapDataFromMsgStream(msgStream: TMemoryStream):TMapDataMsg;
-function ResDataFromMsgStream(msgStream: TMemoryStream):TResDataMsg;
+function IsValidFileName(const S: String): Boolean;
+function IsValidFilePath(const S: String): Boolean;
+
implementation
//kDirPrev: TDirection = D_LEFT;
//HostGameTime: Word = 0;
+
+function IsValidFileName(const S: String): Boolean;
+const
+ Forbidden: set of Char = ['<', '>', '|', '"', ':', '*', '?'];
+var
+ I: Integer;
+begin
+ Result := S <> '';
+ for I := 1 to Length(S) do
+ Result := Result and (not(S[I] in Forbidden));
+end;
+
+function IsValidFilePath(const S: String): Boolean;
+var
+ I: Integer;
+begin
+ Result := False;
+ if not IsValidFileName(S) then exit;
+ if FileExists(S) then exit;
+ I := LastDelimiter('\/', S);
+ if (I > 0) then
+ if (not DirectoryExists(Copy(S, 1, I-1))) then
+ exit;
+ Result := True;
+end;
+
+
// HOST MESSAGES //
end;
C^.Player := PID;
+ C^.WaitForFirstSpawn := false;
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);
FNoRespawn := True;
Spectate;
FWantsInGame := True; // TODO: look into this later
+ C^.WaitForFirstSpawn := true;
end
else
- Respawn(gGameSettings.GameType = GT_SINGLE);
+ begin
+ e_LogWritefln('*** client #%u (cid #%u) authenticated...', [C.ID, C.Player]);
+ //e_LogWritefln('spawning player with pid #%u...', [PID]);
+ //Respawn(gGameSettings.GameType = GT_SINGLE);
+ //k8: no, do not spawn a player yet, wait for a 'i am ready' packet
+ Lives := 0;
+ Spectate;
+ FNoRespawn := True;
+ FWantsInGame := false; // TODO: look into this later
+ C^.WaitForFirstSpawn := true;
+ end;
end;
- for I := Low(NetClients) to High(NetClients) do
+ //if not C^.WaitForFirstSpawn then
begin
- if NetClients[I].ID = C^.ID then Continue;
- MH_SEND_PlayerCreate(PID, NetClients[I].ID);
- MH_SEND_PlayerPos(True, PID, NetClients[I].ID);
- MH_SEND_PlayerStats(PID, NetClients[I].ID);
+ for I := Low(NetClients) to High(NetClients) do
+ begin
+ if NetClients[I].ID = C^.ID then Continue;
+ MH_SEND_PlayerCreate(PID, NetClients[I].ID);
+ MH_SEND_PlayerPos(True, PID, NetClients[I].ID);
+ MH_SEND_PlayerStats(PID, NetClients[I].ID);
+ end;
end;
if gState in [STATE_INTERCUSTOM, STATE_FOLD] then
if NetUseMaster then g_Net_Slist_Update;
end;
+
+procedure MH_ProcessFirstSpawn (C: pTNetClient);
+var
+ plr: TPlayer;
+begin
+ if not C.WaitForFirstSpawn then exit;
+ plr := g_Player_Get(C^.Player);
+ if not assigned(plr) then exit;
+ e_LogWritefln('*** client #%u (cid #%u) first spawn', [C.ID, C.Player]);
+ C.WaitForFirstSpawn := false;
+ plr.FNoRespawn := false;
+ plr.FWantsInGame := true; // TODO: look into this later
+ plr.Respawn(False);
+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 gGameOn then
+ begin
MH_SEND_Everything((C^.State = NET_STATE_AUTH), C^.ID)
+ end
else
+ begin
C^.RequestedFullUpdate := True;
+ end;
end;
// PLAYER
else
Pl.Spectate;
end;
+ NET_CHEAT_READY:
+ begin
+ if gState <> STATE_INTERCUSTOM then Exit;
+ Pl.FReady := not Pl.FReady;
+ if Pl.FReady then
+ begin
+ MH_SEND_GameEvent(NET_EV_INTER_READY, Pl.UID, 'Y');
+ Inc(gInterReadyCount);
+ end
+ else
+ begin
+ MH_SEND_GameEvent(NET_EV_INTER_READY, Pl.UID, 'N');
+ Dec(gInterReadyCount);
+ end;
+ end;
end;
end;
// GAME (SEND)
-procedure MH_SEND_Everything(CreatePlayers: Boolean = False; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_Everything(CreatePlayers: Boolean {= False}; ID: Integer {= NET_EVERYONE});
function sendItemRespawn (it: PItem): Boolean;
begin
@@ -640,9 +726,22 @@ procedure MH_SEND_Everything(CreatePlayers: Boolean = False; ID: Integer = NET_E
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 (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 gPlayers <> nil then
begin
for I := Low(gPlayers) to High(gPlayers) do
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;
end;
end;
g_Items_ForEachAlive(sendItemRespawn, true); // backwards
g_Mons_ForEach(sendMonSpawn);
-
- 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_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);
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
+ e_LogWritefln('*** client #%u (cid #%u) WARMUP', [ID, NetClients[ID].Player]);
MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000, 'N', ID);
+ end;
+
+ g_Net_Flush();
end;
procedure MH_SEND_Info(ID: Byte);
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
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
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;
NetOut.Write(EvStr);
NetOut.Write(Byte(gLastMap));
NetOut.Write(gTime);
- if (EvType = NET_EV_MAPSTART) and (Pos(':\', EvStr) > 0) then
+ if (EvType = NET_EV_MAPSTART) and isWadPath(EvStr) then
begin
NetOut.Write(Byte(1));
NetOut.Write(gWADHash);
end;
NetOut.Write(kByte);
- if Direction = D_LEFT then NetOut.Write(Byte(0)) else NetOut.Write(Byte(1));
+ if Direction = TDirection.D_LEFT then NetOut.Write(Byte(0)) else NetOut.Write(Byte(1));
NetOut.Write(GameX);
NetOut.Write(GameY);
NetOut.Write(GameVelX);
with P do
begin
- NetOut.Write(Byte(Live));
+ NetOut.Write(Byte(alive));
NetOut.Write(Byte(GodMode));
NetOut.Write(Health);
NetOut.Write(Armor);
NetOut.Write(Byte(FNoRespawn));
NetOut.Write(Byte(FJetpack));
NetOut.Write(FFireTime);
+ NetOut.Write(Byte(FFlaming));
end;
g_Net_Host_Send(ID, True, NET_CHAN_PLAYER);
procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYONE);
var
it: PItem;
+ tt: Byte;
begin
it := g_Items_ByIdx(IID);
NetOut.Write(Byte(NET_MSG_ISPAWN));
NetOut.Write(IID);
NetOut.Write(Byte(Quiet));
- NetOut.Write(it.ItemType);
+ 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);
// PANEL
-procedure MH_SEND_PanelTexture(PType: Word; PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelTexture(PGUID: Integer; AnimLoop: Byte; ID: Integer = NET_EVERYONE);
var
TP: TPanel;
begin
TP := g_Map_PanelByGUID(PGUID);
if (TP = nil) then exit;
- {
- 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;
- }
with TP do
begin
NetOut.Write(Byte(NET_MSG_PTEX));
- NetOut.Write(PType);
NetOut.Write(LongWord(PGUID));
NetOut.Write(FCurTexture);
NetOut.Write(FCurFrame);
g_Net_Host_Send(ID, True, NET_CHAN_LARGEDATA);
end;
-procedure MH_SEND_PanelState(PType: Word; PGUID: Integer; ID: Integer = NET_EVERYONE);
+procedure MH_SEND_PanelState(PGUID: Integer; ID: Integer = NET_EVERYONE);
var
TP: TPanel;
+ mpflags: Byte = 0;
begin
TP := g_Map_PanelByGUID(PGUID);
if (TP = nil) then exit;
- 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;
NetOut.Write(Byte(NET_MSG_PSTATE));
- NetOut.Write(PType);
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;
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
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);
i1, i2: TStrings_Locale;
pln: String;
cnt: Byte;
+ goodCmd: Boolean = true;
begin
FillChar(EvHash, Sizeof(EvHash), 0);
EvType := M.ReadByte();
gTime := EvTime;
+ if (g_Res_received_map_start <> 0) then
+ begin
+ if (g_Res_received_map_start < 0) then exit;
+ goodCmd := false;
+ case EvType of
+ NET_EV_MAPSTART: goodCmd := true;
+ NET_EV_MAPEND: goodCmd := true;
+ NET_EV_PLAYER_KICK: goodCmd := true;
+ NET_EV_PLAYER_BAN: goodCmd := true;
+ end;
+ if not goodCmd then exit;
+ end;
+
case EvType of
NET_EV_MAPSTART:
begin
- gGameOn := False;
- g_Game_ClearLoading();
- g_Game_StopAllSounds(True);
+ if (g_Res_received_map_start <> 0) then
+ begin
+ g_Res_received_map_start := -1;
+ end
+ else
+ begin
+ gGameOn := False;
+ g_Game_ClearLoading();
+ g_Game_StopAllSounds(True);
- gSwitchGameMode := Byte(EvNum);
- gGameSettings.GameMode := gSwitchGameMode;
+ gSwitchGameMode := Byte(EvNum);
+ gGameSettings.GameMode := gSwitchGameMode;
- gWADHash := EvHash;
- if not g_Game_StartMap(EvStr, True) then
- begin
- if Pos(':\', EvStr) = 0 then
- g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + EvStr]))
- else
- g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [EvStr]));
- Exit;
- end;
+ gWADHash := EvHash;
+ if not g_Game_StartMap(EvStr, True) then
+ begin
+ 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]));
+ Exit;
+ end;
- MC_SEND_FullStateRequest;
+ MC_SEND_FullStateRequest;
+ end;
end;
NET_EV_MAPEND:
begin
- gMissionFailed := EvNum <> 0;
- gExit := EXIT_ENDLEVELCUSTOM;
+ if (g_Res_received_map_start <> 0) then
+ begin
+ g_Res_received_map_start := -1;
+ end
+ else
+ begin
+ gMissionFailed := EvNum <> 0;
+ gExit := EXIT_ENDLEVELCUSTOM;
+ end;
end;
NET_EV_RCON:
end;
NET_EV_PLAYER_KICK:
- g_Console_Add(Format(_lc[I_PLAYER_KICK], [EvStr]), True);
+ begin
+ g_Console_Add(Format(_lc[I_PLAYER_KICK], [EvStr]), True);
+ if (g_Res_received_map_start <> 0) then g_Res_received_map_start := -1;
+ end;
NET_EV_PLAYER_BAN:
- g_Console_Add(Format(_lc[I_PLAYER_BAN], [EvStr]), True);
+ begin
+ g_Console_Add(Format(_lc[I_PLAYER_BAN], [EvStr]), True);
+ if (g_Res_received_map_start <> 0) then g_Res_received_map_start := -1;
+ end;
NET_EV_LMS_WARMUP:
g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [EvNum]), True);
pl.Touch();
end;
+ NET_EV_SECRET:
+ begin
+ pl := g_Player_Get(EvNum);
+ if pl <> nil then
+ begin
+ g_Console_Add(Format(_lc[I_PLAYER_SECRET], [pl.Name]), True);
+ g_Sound_PlayEx('SOUND_GAME_SECRET');
+ end;
+ end;
+
+ NET_EV_INTER_READY:
+ begin
+ pl := g_Player_Get(EvNum);
+ if pl <> nil then pl.FReady := (EvStr = 'Y');
+ end;
end;
end;
PID: Word;
Pl: TPlayer;
EvType: Byte;
- Fl: Byte;
+ Fl, a: Byte;
Quiet: Boolean;
s, ts: string;
begin
s := _lc[I_PLAYER_FLAG_BLUE];
g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
+
+ if ((Pl = gPlayer1) or (Pl = gPlayer2)
+ or ((gPlayer1 <> nil) and (gPlayer1.Team = Pl.Team))
+ or ((gPlayer2 <> nil) and (gPlayer2.Team = Pl.Team))) then
+ a := 0
+ else
+ a := 1;
+
+ if not sound_ret_flag[a].IsPlaying() then
+ sound_ret_flag[a].Play();
end;
FLAG_STATE_CAPTURED:
g_Console_Add(Format(_lc[I_PLAYER_FLAG_GET], [Pl.Name, s]), True);
g_Game_Message(Format(_lc[I_MESSAGE_FLAG_GET], [AnsiUpperCase(s)]), 144);
+
+ if ((Pl = gPlayer1) or (Pl = gPlayer2)
+ or ((gPlayer1 <> nil) and (gPlayer1.Team = Pl.Team))
+ or ((gPlayer2 <> nil) and (gPlayer2.Team = Pl.Team))) then
+ a := 0
+ else
+ a := 1;
+
+ if not sound_get_flag[a].IsPlaying() then
+ sound_get_flag[a].Play();
end;
FLAG_STATE_DROPPED:
g_Console_Add(Format(_lc[I_PLAYER_FLAG_DROP], [Pl.Name, s]), True);
g_Game_Message(Format(_lc[I_MESSAGE_FLAG_DROP], [AnsiUpperCase(s)]), 144);
+
+ if ((Pl = gPlayer1) or (Pl = gPlayer2)
+ or ((gPlayer1 <> nil) and (gPlayer1.Team = Pl.Team))
+ or ((gPlayer2 <> nil) and (gPlayer2.Team = Pl.Team))) then
+ a := 0
+ else
+ a := 1;
+
+ if not sound_lost_flag[a].IsPlaying() then
+ sound_lost_flag[a].Play();
end;
FLAG_STATE_SCORED:
Insert('.', ts, Length(ts) + 1 - 3);
g_Console_Add(Format(_lc[I_PLAYER_FLAG_CAPTURE], [Pl.Name, s, ts]), True);
g_Game_Message(Format(_lc[I_MESSAGE_FLAG_CAPTURE], [AnsiUpperCase(s)]), 144);
+
+ if ((Pl = gPlayer1) or (Pl = gPlayer2)
+ or ((gPlayer1 <> nil) and (gPlayer1.Team = Pl.Team))
+ or ((gPlayer2 <> nil) and (gPlayer2.Team = Pl.Team))) then
+ a := 0
+ else
+ a := 1;
+
+ if not sound_cap_flag[a].IsPlaying() then
+ sound_cap_flag[a].Play();
end;
FLAG_STATE_RETURNED:
s := _lc[I_PLAYER_FLAG_BLUE];
g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
+
+ if ((Pl = gPlayer1) or (Pl = gPlayer2)
+ or ((gPlayer1 <> nil) and (gPlayer1.Team = Pl.Team))
+ or ((gPlayer2 <> nil) and (gPlayer2.Team = Pl.Team))) then
+ a := 0
+ else
+ a := 1;
+
+ if not sound_ret_flag[a].IsPlaying() then
+ sound_ret_flag[a].Play();
end;
end;
end;
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;
var
PID: Word;
Pl: TPlayer;
- I: Integer;
- OldJet: Boolean;
+ I, OldFire: Integer;
+ OldJet, Flam: Boolean;
NewTeam: Byte;
begin
PID := M.ReadWord();
with Pl do
begin
- Live := (M.ReadByte() <> 0);
+ alive := (M.ReadByte() <> 0);
GodMode := (M.ReadByte() <> 0);
Health := M.ReadLongInt();
Armor := M.ReadLongInt();
FNoRespawn := M.ReadByte() <> 0;
OldJet := FJetpack;
FJetpack := M.ReadByte() <> 0;
+ OldFire := FFireTime;
FFireTime := M.ReadLongInt();
+ if (OldFire <= 0) and (FFireTime > 0) then
+ g_Sound_PlayExAt('SOUND_IGNITE', Obj.X, Obj.Y);
+ Flam := M.ReadByte() <> 0;
if OldJet and not FJetpack then
JetpackOff
else if not OldJet and FJetpack then
JetpackOn;
+ if FFlaming and not Flam then
+ FlamerOff;
if Team <> NewTeam then
Pl.ChangeTeam(NewTeam);
end;
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);
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(var M: TMsg);
VX := M.ReadLongInt();
VY := M.ReadLongInt();
- g_Items_Create(X, Y, T, Fall, False, False, ID);
+ 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;
procedure MC_RECV_PanelTexture(var M: TMsg);
var
TP: TPanel;
- //PType: Word;
PGUID: Integer;
Tex, Fr: Integer;
Loop, Cnt: Byte;
begin
if not gGameOn then Exit;
- {PType :=} M.ReadWord();
+
PGUID := Integer(M.ReadLongWord());
Tex := M.ReadLongInt();
Fr := M.ReadLongInt();
Loop := M.ReadByte();
TP := g_Map_PanelByGUID(PGUID);
-
- {
- 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 (TP <> nil) then
begin
- if Loop = 0 then
- begin
- // switch texture
- TP.SetTexture(Tex, Loop);
- TP.SetFrame(Fr, Cnt);
- end
- else
- begin
- // looped or non-looped animation
- TP.NextTexture(Loop);
- end;
+ // switch texture
+ TP.SetTexture(Tex, Loop);
+ TP.SetFrame(Fr, Cnt);
end;
end;
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 := M.ReadWord();
+
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
- case PType of
- PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
- if E then g_Map_EnableWallGUID(PGUID) else g_Map_DisableWallGUID(PGUID);
-
- PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
- g_Map_SetLiftGUID(PGUID, Lift);
-
- {PANEL_BACK,
- PANEL_FORE:}
- else
- begin
- TP := g_Map_PanelByGUID(PGUID);
- if (TP <> nil) then
- begin
- TP.X := X;
- TP.Y := Y;
- TP.positionChanged();
- end;
- //gRenderBackgrounds[ID].X := X;
- //gRenderBackgrounds[ID].Y := Y;
- end;
+ TP := g_Map_PanelByGUID(PGUID);
+ if (TP = nil) then exit;
- {
- PANEL_FORE:
- begin
- gRenderForegrounds[ID].X := X;
- gRenderForegrounds[ID].Y := Y;
- end;
- }
- end;
+ // 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
if gTriggers[I].ClientID = SID then
with gTriggers[I] do
begin
- if SPlaying then
+ if Sound <> nil then
begin
- if trigData.trigLocal then
- Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/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((trigData.trigPan-127.0)/128.0, trigData.trigVolume/255.0);
- Sound.SetPosition(SPos);
- end
- else
- if Sound.IsPlaying then Sound.Stop;
+ if Sound.IsPlaying then Sound.Stop;
+ end;
SoundPlayCount := SCount;
end;
MPlaying := M.ReadByte() <> 0;
MPos := M.ReadLongWord();
MPaused := M.ReadByte() <> 0;
+ MPos := MPos+1; //k8: stfu, fpc!
if MPlaying then
begin
gMusic.SetByName(MName);
gMusic.Play(True);
- gMusic.SetPosition(MPos);
+ // gMusic.SetPosition(MPos);
gMusic.SpecPause := MPaused;
end
else
with Mon do
begin
- GameX := X;
- GameY := Y;
- GameVelX := VX;
- GameVelY := VY;
MonsterAnim := MAnim;
MonsterTargetUID := MTarg;
SetState(MState);
- positionChanged(); // this updates spatial accelerators
+ setPosition(X, Y); // this will call positionChanged();
+ GameVelX := VX;
+ GameVelY := VY;
end;
end;
var
Mon: TMonster;
ID: Word;
+ X, Y: Integer;
begin
ID := M.ReadWord();
Mon := g_Monsters_ByUID(ID);
with Mon do
begin
- GameX := M.ReadLongInt();
- GameY := M.ReadLongInt();
+ X := M.ReadLongInt();
+ Y := M.ReadLongInt();
+ Mon.setPosition(X, Y); // this will call `positionChanged()`
GameVelX := M.ReadLongInt();
GameVelY := M.ReadLongInt();
GameDirection := TDirection(M.ReadByte());
- positionChanged(); // this updates spatial accelerators
end;
end;
procedure MC_RECV_MonsterState(var M: TMsg);
var
- ID: Integer;
+ ID, OldFire: Integer;
MState, MFAnm: Byte;
Mon: TMonster;
AnimRevert: Boolean;
MonsterAmmo := M.ReadLongInt();
MonsterPain := M.ReadLongInt();
AnimRevert := M.ReadByte() <> 0;
+ OldFire := FFireTime;
FFireTime := M.ReadLongInt();
+ if (OldFire <= 0) and (FFireTime > 0) then
+ g_Sound_PlayExAt('SOUND_IGNITE', Obj.X, Obj.Y);
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;
g_Net_Client_Send(True, NET_CHAN_CHAT);
end;
-function isKeyPressed (key1: Word; key2: Word): Boolean;
-begin
- if (key1 <> 0) and e_KeyPressed(key1) then begin result := true; exit; end;
- if (key2 <> 0) and e_KeyPressed(key2) then begin result := true; exit; end;
- result := false;
-end;
-
procedure MC_SEND_PlayerPos();
var
kByte: Word;
Predict: Boolean;
strafeDir: Byte;
WeaponSelect: Word = 0;
- I: Integer;
+ i: Integer;
begin
if not gGameOn then Exit;
if gPlayers = nil then Exit;
begin
strafeDir := P1MoveButton shr 4;
P1MoveButton := P1MoveButton and $0F;
- with gGameControls.P1Control do
+
+ if gPlayerAction[0, ACTION_MOVELEFT] and (not gPlayerAction[0, ACTION_MOVERIGHT]) then
+ P1MoveButton := 1
+ else if (not gPlayerAction[0, ACTION_MOVELEFT]) and gPlayerAction[0, ACTION_MOVERIGHT] then
+ P1MoveButton := 2
+ else if (not gPlayerAction[0, ACTION_MOVELEFT]) and (not gPlayerAction[0, ACTION_MOVERIGHT]) then
+ P1MoveButton := 0;
+
+ // strafing
+ if gPlayerAction[0, ACTION_STRAFE] then
+ 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(TDirection.D_LEFT)
+ else if (strafeDir = 1) then
+ gPlayer1.SetDirection(TDirection.D_RIGHT)
+ end
+ else
begin
- if isKeyPressed(KeyLeft, KeyLeft2) and (not isKeyPressed(KeyRight, KeyRight2)) then P1MoveButton := 1
- else if (not isKeyPressed(KeyLeft, KeyLeft2)) and isKeyPressed(KeyRight, KeyRight2) then P1MoveButton := 2
- else if (not isKeyPressed(KeyLeft, KeyLeft2)) and (not isKeyPressed(KeyRight, KeyRight2)) then P1MoveButton := 0;
+ strafeDir := 0; // not strafing anymore
+ if (P1MoveButton = 2) and gPlayerAction[0, ACTION_MOVELEFT] then
+ gPlayer1.SetDirection(TDirection.D_LEFT)
+ else if (P1MoveButton = 1) and gPlayerAction[0, ACTION_MOVERIGHT] then
+ gPlayer1.SetDirection(TDirection.D_RIGHT)
+ else if P1MoveButton <> 0 then
+ gPlayer1.SetDirection(TDirection(P1MoveButton-1));
+ end;
- // strafing
- if isKeyPressed(KeyStrafe, KeyStrafe2) then
- 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);
- 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)
- else if P1MoveButton <> 0 then gPlayer1.SetDirection(TDirection(P1MoveButton-1));
- end;
+ gPlayer1.ReleaseKeys;
+ if P1MoveButton = 1 then
+ begin
+ kByte := kByte or NET_KEY_LEFT;
+ if Predict then gPlayer1.PressKey(KEY_LEFT, 10000);
+ end;
+ if P1MoveButton = 2 then
+ begin
+ kByte := kByte or NET_KEY_RIGHT;
+ if Predict then gPlayer1.PressKey(KEY_RIGHT, 10000);
+ end;
+ if gPlayerAction[0, ACTION_LOOKUP] then
+ begin
+ kByte := kByte or NET_KEY_UP;
+ gPlayer1.PressKey(KEY_UP, 10000);
+ end;
+ if gPlayerAction[0, ACTION_LOOKDOWN] then
+ begin
+ kByte := kByte or NET_KEY_DOWN;
+ gPlayer1.PressKey(KEY_DOWN, 10000);
+ end;
+ if gPlayerAction[0, ACTION_JUMP] then
+ begin
+ kByte := kByte or NET_KEY_JUMP;
+ // gPlayer1.PressKey(KEY_JUMP, 10000); // TODO: Make a prediction option
+ end;
+ if gPlayerAction[0, ACTION_ATTACK] then kByte := kByte or NET_KEY_FIRE;
+ if gPlayerAction[0, ACTION_ACTIVATE] then kByte := kByte or NET_KEY_OPEN;
+ if gPlayerAction[0, ACTION_WEAPNEXT] then kByte := kByte or NET_KEY_NW;
+ if gPlayerAction[0, ACTION_WEAPPREV] then kByte := kByte or NET_KEY_PW;
- gPlayer1.ReleaseKeys;
- if P1MoveButton = 1 then
- begin
- kByte := kByte or NET_KEY_LEFT;
- if Predict then gPlayer1.PressKey(KEY_LEFT, 10000);
- end;
- if P1MoveButton = 2 then
- begin
- kByte := kByte or NET_KEY_RIGHT;
- if Predict then gPlayer1.PressKey(KEY_RIGHT, 10000);
- end;
- if isKeyPressed(KeyUp, KeyUp2) then
- begin
- kByte := kByte or NET_KEY_UP;
- gPlayer1.PressKey(KEY_UP, 10000);
- end;
- if isKeyPressed(KeyDown, KeyDown2) then
- begin
- kByte := kByte or NET_KEY_DOWN;
- gPlayer1.PressKey(KEY_DOWN, 10000);
- end;
- if isKeyPressed(KeyJump, KeyJump2) then
+ gPlayerAction[0, ACTION_WEAPNEXT] := False; // HACK, remove after readyweaon&pendinweapon implementation
+ gPlayerAction[0, ACTION_WEAPPREV] := False; // HACK, remove after readyweaon&pendinweapon implementation
+
+ for i := WP_FIRST to WP_LAST do
+ begin
+ if gSelectWeapon[0, i] then
begin
- kByte := kByte or NET_KEY_JUMP;
- // gPlayer1.PressKey(KEY_JUMP, 10000); // TODO: Make a prediction option
- end;
- if isKeyPressed(KeyFire, KeyFire2) then kByte := kByte or NET_KEY_FIRE;
- if isKeyPressed(KeyOpen, KeyOpen2) then kByte := kByte or NET_KEY_OPEN;
- if isKeyPressed(KeyNextWeapon, KeyNextWeapon2) then kByte := kByte or NET_KEY_NW;
- if isKeyPressed(KeyPrevWeapon, KeyPrevWeapon2) then kByte := kByte or NET_KEY_PW;
- for I := 0 to High(KeyWeapon) do
- if isKeyPressed(KeyWeapon[I], KeyWeapon2[I]) then
- WeaponSelect := WeaponSelect or Word(1 shl I);
+ WeaponSelect := WeaponSelect or Word(1 shl i);
+ gSelectWeapon[0, i] := False
+ end
end;
+
// fix movebutton state
P1MoveButton := P1MoveButton or (strafeDir shl 4);
end
g_Net_Client_Send(True, NET_CHAN_SERVICE);
end;
-// i have no idea why all this stuff is in here
-
-function ReadFile(const FileName: TFileName): AByte;
-var
- FileStream : TStream;
- fname: string;
-begin
- e_WriteLog(Format('NETWORK: looking for file "%s"', [FileName]), MSG_NOTIFY);
- fname := findDiskWad(FileName);
- if length(fname) = 0 then
- begin
- e_WriteLog(Format('NETWORK: file "%s" not found!', [FileName]), MSG_FATALERROR);
- SetLength(Result, 0);
- exit;
- end;
- e_WriteLog(Format('NETWORK: found file "%s"', [fname]), MSG_NOTIFY);
- Result := nil;
- FileStream := openDiskFileRO(fname);
- try
- if FileStream.Size > 0 then
- begin
- SetLength(Result, FileStream.Size);
- FileStream.Read(Result[0], FileStream.Size);
- end;
- finally
- FileStream.Free;
- end;
-end;
-
-function CreateMapDataMsg(const FileName: TFileName; ResList: TStringList): TMapDataMsg;
-var
- i: Integer;
-begin
- Result.MsgId := NET_MSG_MAP_RESPONSE;
- Result.FileData := ReadFile(FileName);
- Result.FileSize := Length(Result.FileData);
-
- SetLength(Result.ExternalResources, ResList.Count);
- for i:=0 to ResList.Count-1 do
- begin
- Result.ExternalResources[i].Name := ResList.Strings[i];
- Result.ExternalResources[i].md5 := MD5File(GameDir+'/wads/'+ResList.Strings[i]);
- end;
-end;
-
-procedure ResDataMsgToBytes(var bytes: AByte; const ResData: TResDataMsg);
-var
- ResultStream: TMemoryStream;
-begin
- ResultStream := TMemoryStream.Create;
-
- ResultStream.WriteBuffer(ResData.MsgId, SizeOf(ResData.MsgId)); //msgId
- ResultStream.WriteBuffer(ResData.FileSize, SizeOf(ResData.FileSize)); //file size
- ResultStream.WriteBuffer(ResData.FileData[0], ResData.FileSize); //file data
-
- SetLength(bytes, ResultStream.Size);
- ResultStream.Seek(0, soFromBeginning);
- ResultStream.ReadBuffer(bytes[0], ResultStream.Size);
-
- ResultStream.Free;
-end;
-
-function ResDataFromMsgStream(msgStream: TMemoryStream):TResDataMsg;
-begin
- msgStream.ReadBuffer(Result.MsgId, SizeOf(Result.MsgId));
- msgStream.ReadBuffer(Result.FileSize, SizeOf(Result.FileSize));
- SetLength(Result.FileData, Result.FileSize);
- msgStream.ReadBuffer(Result.FileData[0], Result.FileSize);
-end;
-
-procedure MapDataMsgToBytes(var bytes: AByte; const MapDataMsg: TMapDataMsg);
-var
- ResultStream: TMemoryStream;
- resCount: Integer;
-begin
- resCount := Length(MapDataMsg.ExternalResources);
-
- ResultStream := TMemoryStream.Create;
-
- ResultStream.WriteBuffer(MapDataMsg.MsgId, SizeOf(MapDataMsg.MsgId)); //msgId
- ResultStream.WriteBuffer(MapDataMsg.FileSize, SizeOf(MapDataMsg.FileSize)); //file size
- ResultStream.WriteBuffer(MapDataMsg.FileData[0], MapDataMsg.FileSize); //file data
-
- ResultStream.WriteBuffer(resCount, SizeOf(resCount)); //res count
- ResultStream.WriteBuffer(MapDataMsg.ExternalResources[0], resCount*SizeOf(TExternalResourceInfo)); //res data
-
- SetLength(bytes, ResultStream.Size);
- ResultStream.Seek(0, soFromBeginning);
- ResultStream.ReadBuffer(bytes[0], ResultStream.Size);
-
- ResultStream.Free;
-end;
-
-function MapDataFromMsgStream(msgStream: TMemoryStream):TMapDataMsg;
-var
- resCount: Integer;
-begin
- msgStream.ReadBuffer(Result.MsgId, SizeOf(Result.MsgId));
- msgStream.ReadBuffer(Result.FileSize, SizeOf(Result.FileSize)); //file size
-
- SetLength(Result.FileData, Result.FileSize);
- msgStream.ReadBuffer(Result.FileData[0], Result.FileSize); //file data
-
- msgStream.ReadBuffer(resCount, SizeOf(resCount)); //res count
- SetLength(Result.ExternalResources, resCount);
-
- msgStream.ReadBuffer(Result.ExternalResources[0], resCount * SizeOf(TExternalResourceInfo)); //res data
-end;
-
-function IsValidFileName(const S: String): Boolean;
-const
- Forbidden: set of Char = ['<', '>', '|', '"', ':', '*', '?'];
-var
- I: Integer;
-begin
- Result := S <> '';
- for I := 1 to Length(S) do
- Result := Result and (not(S[I] in Forbidden));
-end;
-
-function IsValidFilePath(const S: String): Boolean;
-var
- I: Integer;
-begin
- Result := False;
- if not IsValidFileName(S) then exit;
- if FileExists(S) then exit;
- I := LastDelimiter('\/', S);
- if (I > 0) then
- if (not DirectoryExists(Copy(S, 1, I-1))) then
- exit;
- Result := True;
-end;
-
-procedure MC_SEND_MapRequest();
-begin
- NetOut.Write(Byte(NET_MSG_MAP_REQUEST));
- g_Net_Client_Send(True, NET_CHAN_IMPORTANT);
-end;
-
-procedure MC_SEND_ResRequest(const resName: AnsiString);
-begin
- 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; 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);
-
- mapDataMsg := CreateMapDataMsg(MapsDir + gGameSettings.WAD, gExternalResources);
- peer := NetClients[C.ID].Peer;
-
- MapDataMsgToBytes(payload, mapDataMsg);
- g_Net_SendData(payload, peer, True, NET_CHAN_DOWNLOAD);
-
- payload := nil;
- mapDataMsg.FileData := nil;
- mapDataMsg.ExternalResources := nil;
-end;
-
-procedure MH_RECV_ResRequest(C: pTNetClient; var M: TMsg);
-var
- payload: AByte;
- peer: pENetPeer;
- FileName: String;
- resDataMsg: TResDataMsg;
-begin
- FileName := ExtractFileName(M.ReadString());
- e_WriteLog('NET: Received res request: ' + FileName +
- ' from ' + DecodeIPV4(C.Peer.address.host), MSG_NOTIFY);
-
- if not IsValidFilePath(FileName) then
- begin
- e_WriteLog('Invalid filename: ' + FileName, MSG_WARNING);
- exit;
- end;
-
- peer := NetClients[C.ID].Peer;
-
- if gExternalResources.IndexOf(FileName) > -1 then
- begin
- resDataMsg.MsgId := NET_MSG_RES_RESPONSE;
- resDataMsg.FileData := ReadFile(GameDir+'/wads/'+FileName);
- resDataMsg.FileSize := Length(resDataMsg.FileData);
-
- ResDataMsgToBytes(payload, resDataMsg);
- g_Net_SendData(payload, peer, True, NET_CHAN_DOWNLOAD);
- end;
-end;
end.