diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index 244b2ebd716ef55a21674fbd4b375f9c2324aad8..c49ffaa6aa6ae4a192465faad13ef82a7e3e3973 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
NET_EV_PLAYER_TOUCH = 18;
NET_EV_SECRET = 19;
NET_EV_INTER_READY = 20;
+ NET_EV_LMS_NOSPAWN = 21;
NET_VE_STARTED = 1;
NET_VE_PASSED = 2;
implementation
uses
- Math, ENet, e_input, e_graphics, e_log,
- g_textures, g_gfx, g_sound, g_console, g_basic, g_options, g_main,
+ Math, ENet, e_input, e_log, g_base, g_basic,
+ g_textures, g_gfx, g_sound, g_console, g_options,
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;
Name := PName;
FClientID := C^.ID;
// round in progress, don't spawn
- if (gGameSettings.MaxLives > 0) and (gLMSRespawn = LMS_RESPAWN_NONE) then
- begin
- Lives := 0;
- FNoRespawn := True;
- Spectate;
- FWantsInGame := True; // TODO: look into this later
- C^.WaitForFirstSpawn := true;
- end
- else
- 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;
+ 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 "request full state" packet
+ Lives := 0;
+ Spectate;
+ FNoRespawn := True;
+ // `FWantsInGame` seems to mean "spawn the player on the next occasion".
+ // that is, if we'll set it to `true`, the player can be spawned after
+ // warmup time ran out, for example, regardless of the real player state.
+ // also, this seems to work only for the initial connection. further
+ // map changes could initiate resource downloading, but the player will
+ // be spawned immediately.
+ // the proper solution will require another player state, "ephemeral".
+ // the player should start any map in "ephemeral" state, and turned into
+ // real mobj only when they sent a special "i am ready" packet. this packet
+ // must be sent after receiving the full state, so the player will get a full
+ // map view before going into game.
+ FWantsInGame := false;
+ C^.WaitForFirstSpawn := true;
end;
//if not C^.WaitForFirstSpawn then
if gState in [STATE_INTERCUSTOM, STATE_FOLD] then
MH_SEND_GameEvent(NET_EV_MAPEND, 0, 'N', C^.ID);
- if NetUseMaster then g_Net_Slist_Update;
+ if NetUseMaster then
+ begin
+ //g_Net_Slist_Update;
+ g_Net_Slist_Pulse();
+ end;
end;
if not C.WaitForFirstSpawn then exit;
plr := g_Player_Get(C^.Player);
if not assigned(plr) then exit;
+ g_Net_Slist_ServerPlayerComes();
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);
+
+ if (gGameSettings.MaxLives > 0) and (gLMSRespawn = LMS_RESPAWN_NONE) then
+ begin
+ plr.Spectate;
+ MH_SEND_GameEvent(NET_EV_LMS_NOSPAWN, 0, 'N', C.ID);
+ end
+ else
+ begin
+ plr.Respawn(False);
+ if gLMSRespawn > LMS_RESPAWN_NONE then
+ MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime, 'N', C.ID);
+ end;
end;
NET_CHEAT_SPECTATE:
begin
if Pl.FSpectator then
- Pl.Respawn(False)
+ begin
+ if (gGameSettings.MaxLives = 0) or (gLMSRespawn > LMS_RESPAWN_NONE) then
+ Pl.Respawn(False)
+ else
+ MH_SEND_GameEvent(NET_EV_LMS_NOSPAWN, Pl.UID);
+ end
else
Pl.Spectate;
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);
-var
- Map: string;
begin
- Map := g_ExtractFileName(gMapInfo.Map);
-
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(ExtractFileName(gGameSettings.WAD));
+ NetOut.Write(g_ExtractFileName(gMapInfo.Map));
NetOut.Write(gWADHash);
NetOut.Write(gGameSettings.GameMode);
NetOut.Write(gGameSettings.GoalLimit);
if IsKeyPressed(KEY_UP) then kByte := kByte or NET_KEY_UP;
if IsKeyPressed(KEY_DOWN) then kByte := kByte or NET_KEY_DOWN;
if IsKeyPressed(KEY_JUMP) then kByte := kByte or NET_KEY_JUMP;
- if JustTeleported then kByte := kByte or NET_KEY_FORCEDIR;
end;
+ if JustTeleported then kByte := kByte or NET_KEY_FORCEDIR;
+
NetOut.Write(kByte);
if Direction = TDirection.D_LEFT then NetOut.Write(Byte(0)) else NetOut.Write(Byte(1));
NetOut.Write(GameX);
NetOut.Write(Byte(FJetpack));
NetOut.Write(FFireTime);
NetOut.Write(Byte(FFlaming));
+ NetOut.Write(FSpawnInvul);
end;
g_Net_Host_Send(ID, True, NET_CHAN_PLAYER);
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), TMsgType.Notify);
- g_Game_ChatSound(b_Text_Unformat(Txt));
- end else
- if (Mode = NET_CHAT_TEAM) and (gPlayer1 <> nil) then
+ if NetDeafLevel = 0 then
begin
- if gPlayer1.Team = TEAM_RED then
- 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), TMsgType.Notify);
- g_Game_ChatSound(b_Text_Unformat(Txt));
+ if Mode = NET_CHAT_PLAYER then
+ begin
+ g_Console_Add(Txt, True);
+ 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
+ if gPlayer1.Team = TEAM_RED then
+ 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), TMsgType.Notify);
+ g_Game_ChatSound(b_Text_Unformat(Txt));
+ end;
end;
- end else
+ end else if (NetDeafLevel < 2) then
g_Console_Add(Txt, True);
end;
NET_EV_MAPEND: goodCmd := true;
NET_EV_PLAYER_KICK: goodCmd := true;
NET_EV_PLAYER_BAN: goodCmd := true;
+ NET_EV_LMS_WARMUP: goodCmd := true;
end;
if not goodCmd then exit;
end;
gGameSettings.GameMode := gSwitchGameMode;
gWADHash := EvHash;
- if not g_Game_StartMap(EvStr, True) then
+ if not g_Game_StartMap(false{asMegawad}, EvStr, True) then
begin
if not isWadPath(EvStr) then
g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + EvStr]))
NET_EV_MAPEND:
begin
+ gLMSRespawn := LMS_RESPAWN_NONE;
+ gLMSRespawnTime := 0;
if (g_Res_received_map_start <> 0) then
begin
g_Res_received_map_start := -1;
NET_EV_CHANGE_TEAM:
begin
- if EvNum = TEAM_RED then
- g_Console_Add(Format(_lc[I_PLAYER_CHTEAM_RED], [EvStr]), True);
- if EvNum = TEAM_BLUE then
- g_Console_Add(Format(_lc[I_PLAYER_CHTEAM_BLUE], [EvStr]), True);
+ if NetDeafLevel < 2 then
+ begin
+ if EvNum = TEAM_RED then
+ g_Console_Add(Format(_lc[I_PLAYER_CHTEAM_RED], [EvStr]), True);
+ if EvNum = TEAM_BLUE then
+ g_Console_Add(Format(_lc[I_PLAYER_CHTEAM_BLUE], [EvStr]), True);
+ end;
end;
NET_EV_PLAYER_KICK:
end;
NET_EV_LMS_WARMUP:
- g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [EvNum]), True);
+ begin
+ if EvNum > 0 then
+ begin
+ gLMSRespawn := LMS_RESPAWN_WARMUP;
+ gLMSRespawnTime := gTime + EvNum;
+ g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [EvNum div 1000]), True);
+ end
+ else if gPlayer1 = nil then
+ begin
+ g_Console_Add(_lc[I_PLAYER_SPECT4], True);
+ end;
+ end;
NET_EV_LMS_SURVIVOR:
g_Console_Add('*** ' + _lc[I_MESSAGE_LMS_SURVIVOR] + ' ***', True);
NET_EV_BIGTEXT:
- g_Game_Message(AnsiUpperCase(EvStr), Word(EvNum));
+ if NetDeafLevel < 2 then g_Game_Message(AnsiUpperCase(EvStr), Word(EvNum));
NET_EV_SCORE:
begin
NET_EV_LMS_START:
begin
g_Player_RemoveAllCorpses;
+ gLMSRespawn := LMS_RESPAWN_NONE;
g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
end;
NET_EV_LMS_DRAW:
g_Game_Message(_lc[I_GAME_WIN_DRAW], 144);
+ NET_EV_LMS_NOSPAWN:
+ g_Console_Add(_lc[I_PLAYER_SPECT4], True);
+
NET_EV_KILLCOMBO:
g_Game_Announce_KillCombo(EvNum);
end;
end;
- g_Console_Add(Format(_lc[I_PLAYER_JOIN], [PName]), True);
+ if NetDeafLevel < 3 then
+ g_Console_Add(Format(_lc[I_PLAYER_JOIN], [PName]), True);
e_WriteLog('NET: Player ' + PName + ' [' + IntToStr(PID) + '] added.', TMsgType.Notify);
Result := PID;
end;
ReleaseKeys;
- if (kByte = NET_KEY_CHAT) then
+ if LongBool(kByte and NET_KEY_CHAT) then
PressKey(KEY_CHAT, 10000)
else
begin
if LongBool(kByte and NET_KEY_JUMP) then PressKey(KEY_JUMP, 10000);
end;
- if ((Pl <> gPlayer1) and (Pl <> gPlayer2)) or LongBool(kByte and NET_KEY_FORCEDIR) then
+ JustTeleported := LongBool(kByte and NET_KEY_FORCEDIR);
+
+ if ((Pl <> gPlayer1) and (Pl <> gPlayer2)) or JustTeleported then
SetDirection(TDirection(Dir));
GameVelX := M.ReadLongInt();
FSpectator := M.ReadByte() <> 0;
if FSpectator then
begin
- if Pl = gPlayer1 then
+ if UID = NetPlrUID1 then
begin
- gLMSPID1 := UID;
+ gSpectLatchPID1 := UID;
gPlayer1 := nil;
end;
- if Pl = gPlayer2 then
+ if UID = NetPlrUID2 then
begin
- gLMSPID2 := UID;
+ gSpectLatchPID2 := UID;
gPlayer2 := nil;
end;
end
else
begin
- if (gPlayer1 = nil) and (gLMSPID1 > 0) then
- gPlayer1 := g_Player_Get(gLMSPID1);
- if (gPlayer2 = nil) and (gLMSPID2 > 0) then
- gPlayer2 := g_Player_Get(gLMSPID2);
+ if (gPlayer1 = nil) and (gSpectLatchPID1 > 0) and (UID = gSpectLatchPID1) then
+ begin
+ gPlayer1 := Pl;
+ gSpectLatchPID1 := 0;
+ end;
+ if (gPlayer2 = nil) and (gSpectLatchPID2 > 0) and (UID = gSpectLatchPID2) then
+ begin
+ gPlayer2 := Pl;
+ gSpectLatchPID2 := 0;
+ end;
end;
FGhost := M.ReadByte() <> 0;
FPhysics := M.ReadByte() <> 0;
if (OldFire <= 0) and (FFireTime > 0) then
g_Sound_PlayExAt('SOUND_IGNITE', Obj.X, Obj.Y);
Flam := M.ReadByte() <> 0;
+ FSpawnInvul := M.ReadLongInt();
if OldJet and not FJetpack then
JetpackOff
else if not OldJet and FJetpack then
Result := 0;
if Pl = nil then Exit;
- g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
+ if NetDeafLevel < 3 then
+ g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
e_WriteLog('NET: Player ' + Pl.Name + ' [' + IntToStr(PID) + '] removed.', TMsgType.Notify);
g_Player_Remove(PID);
if Pl.Name <> TmpName then
begin
- g_Console_Add(Format(_lc[I_PLAYER_NAME], [Pl.Name, TmpName]), True);
+ if NetDeafLevel < 3 then
+ g_Console_Add(Format(_lc[I_PLAYER_NAME], [Pl.Name, TmpName]), True);
Pl.Name := TmpName;
end;
Str1 := M.ReadString();
Str2 := M.ReadString();
- case EvID of
- NET_VE_STARTED:
- g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Str1, Str2, Int1]), True);
- NET_VE_PASSED:
- g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [Str1]), True);
- NET_VE_FAILED:
- g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
- NET_VE_VOTE:
- g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [Str1, Int1, Int2]), True);
- NET_VE_INPROGRESS:
- g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [Str1]), True);
- end;
+ if NetDeafLevel < 2 then
+ case EvID of
+ NET_VE_STARTED:
+ g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Str1, Str2, Int1]), True);
+ NET_VE_PASSED:
+ g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [Str1]), True);
+ NET_VE_FAILED:
+ g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
+ NET_VE_VOTE:
+ g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [Str1, Int1, Int2]), True);
+ NET_VE_INPROGRESS:
+ g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [Str1]), True);
+ end;
end;
// CLIENT SEND