mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- redirect most references to the global players array through FLevelLocals.
The Map loader may not access any global state at all - everything it can touch must be exchangable. Furthermore, if we want to sandbox each level, there may be no direct access to any kind of global state whatsoever from the play code.
This commit is contained in:
parent
c15212ca82
commit
8bbdee5c28
19 changed files with 259 additions and 189 deletions
|
@ -35,6 +35,7 @@
|
|||
#include "actor.h"
|
||||
#include "d_player.h"
|
||||
#include "p_local.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -61,14 +62,18 @@
|
|||
Only one selector of each type can be used.
|
||||
*/
|
||||
|
||||
#define AAPTR_RESOLVE_PLAYERNUM(playernum) (playeringame[playernum] ? players[playernum].mo : NULL)
|
||||
|
||||
AActor *COPY_AAPTR(AActor *origin, int selector)
|
||||
{
|
||||
if (selector == AAPTR_DEFAULT) return origin;
|
||||
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
auto Level = origin->Level;
|
||||
auto AAPTR_RESOLVE_PLAYERNUM = [=](int playernum) -> AActor*
|
||||
{
|
||||
return (Level->PlayerInGame(playernum) ? Level->Players[playernum]->mo : nullptr);
|
||||
};
|
||||
|
||||
if (origin)
|
||||
{
|
||||
if (origin->player)
|
||||
|
|
|
@ -154,12 +154,12 @@ void FS_EmulateCmd(FLevelLocals *Level, char * string)
|
|||
{
|
||||
sc.MustGetFloat();
|
||||
double playerviewheight = sc.Float;
|
||||
for(int i=0;i<MAXPLAYERS;i++)
|
||||
for (auto p : Level->Players)
|
||||
{
|
||||
// No, this is not correct. But this is the way Legacy WADs expect it to be handled!
|
||||
if (players[i].mo != NULL) players[i].mo->FloatVar(NAME_ViewHeight) = playerviewheight;
|
||||
players[i].viewheight = playerviewheight;
|
||||
players[i].Uncrouch();
|
||||
if (p->mo != nullptr) p->mo->FloatVar(NAME_ViewHeight) = playerviewheight;
|
||||
p->viewheight = playerviewheight;
|
||||
p->Uncrouch();
|
||||
}
|
||||
while (sc.GetString())
|
||||
{
|
||||
|
|
|
@ -278,7 +278,7 @@ int FParser::T_GetPlayerNum(const svalue_t &arg)
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
if(!playeringame[playernum]) // no error, just return -1
|
||||
if(!Level->PlayerInGame(playernum)) // no error, just return -1
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ int FParser::T_GetPlayerNum(const svalue_t &arg)
|
|||
AActor *FParser::T_GetPlayerActor(const svalue_t &arg)
|
||||
{
|
||||
int num = T_GetPlayerNum(arg);
|
||||
return num == -1 ? nullptr : players[num].mo;
|
||||
return num == -1 ? nullptr : Level->Players[num]->mo;
|
||||
}
|
||||
|
||||
PClassActor *T_ClassType(const svalue_t &arg)
|
||||
|
@ -659,7 +659,7 @@ void FParser::SF_PlayerTip(void)
|
|||
if (CheckArgs(1))
|
||||
{
|
||||
int plnum = T_GetPlayerNum(t_argv[0]);
|
||||
if (plnum!=-1 && players[plnum].mo->CheckLocalView(consoleplayer))
|
||||
if (plnum!=-1 && Level->Players[plnum]->mo->CheckLocalView(consoleplayer))
|
||||
{
|
||||
C_MidPrint(SmallFont, GetFormatString(1).GetChars());
|
||||
}
|
||||
|
@ -692,7 +692,7 @@ void FParser::SF_PlayerMsg(void)
|
|||
if (CheckArgs(1))
|
||||
{
|
||||
int plnum = T_GetPlayerNum(t_argv[0]);
|
||||
if (plnum!=-1 && players[plnum].mo->CheckLocalView(consoleplayer))
|
||||
if (plnum!=-1 && Level->Players[plnum]->mo->CheckLocalView(consoleplayer))
|
||||
{
|
||||
Printf(PRINT_HIGH, "%s\n", GetFormatString(1).GetChars());
|
||||
}
|
||||
|
@ -714,7 +714,7 @@ void FParser::SF_PlayerInGame(void)
|
|||
if (plnum!=-1)
|
||||
{
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = playeringame[plnum];
|
||||
t_return.value.i = Level->PlayerInGame(plnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -742,7 +742,7 @@ void FParser::SF_PlayerName(void)
|
|||
if(plnum !=-1)
|
||||
{
|
||||
t_return.type = svt_string;
|
||||
t_return.string = players[plnum].userinfo.GetName();
|
||||
t_return.string = Level->Players[plnum]->userinfo.GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -773,7 +773,7 @@ void FParser::SF_PlayerObj(void)
|
|||
if(plnum !=-1)
|
||||
{
|
||||
t_return.type = svt_mobj;
|
||||
t_return.value.mobj = players[plnum].mo;
|
||||
t_return.value.mobj = Level->Players[plnum]->mo;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1403,7 +1403,7 @@ void FParser::SF_SetCamera(void)
|
|||
if (CheckArgs(1))
|
||||
{
|
||||
player = Script->trigger->player;
|
||||
if (!player) player=&players[0];
|
||||
if (!player) player = Level->Players[0];
|
||||
|
||||
newcamera = actorvalue(t_argv[0]);
|
||||
if(!newcamera)
|
||||
|
@ -1436,7 +1436,7 @@ void FParser::SF_ClearCamera(void)
|
|||
{
|
||||
player_t * player;
|
||||
player = Script->trigger->player;
|
||||
if (!player) player=&players[0];
|
||||
if (!player) player = Level->Players[0];
|
||||
|
||||
AActor * cam=player->camera;
|
||||
if (cam)
|
||||
|
@ -2419,13 +2419,13 @@ void FParser::SF_PlayerKeys(void)
|
|||
if(t_argc == 2)
|
||||
{
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = CheckInventory(players[playernum].mo, keyname);
|
||||
t_return.value.i = CheckInventory(Level->Players[playernum]->mo, keyname);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
givetake = intvalue(t_argv[2]);
|
||||
ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, keyname.GetIndex(), ScriptUtil::Int, 1, ScriptUtil::End);
|
||||
ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, keyname.GetIndex(), ScriptUtil::Int, 1, ScriptUtil::End);
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = 0;
|
||||
}
|
||||
|
@ -2504,14 +2504,14 @@ void FParser::SF_PlayerWeapon()
|
|||
|
||||
if (t_argc == 2)
|
||||
{
|
||||
AActor * wp = players[playernum].mo->FindInventory(ti);
|
||||
AActor * wp = Level->Players[playernum]->mo->FindInventory(ti);
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = wp!=NULL;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
AActor * wp = players[playernum].mo->FindInventory(ti);
|
||||
AActor * wp = Level->Players[playernum]->mo->FindInventory(ti);
|
||||
|
||||
newweapon = !!intvalue(t_argv[2]);
|
||||
if (!newweapon)
|
||||
|
@ -2520,14 +2520,14 @@ void FParser::SF_PlayerWeapon()
|
|||
{
|
||||
wp->Destroy();
|
||||
// If the weapon is active pick a replacement. Legacy didn't do this!
|
||||
if (players[playernum].PendingWeapon==wp) players[playernum].PendingWeapon=WP_NOCHANGE;
|
||||
if (players[playernum].ReadyWeapon==wp)
|
||||
if (Level->Players[playernum]->PendingWeapon==wp) Level->Players[playernum]->PendingWeapon=WP_NOCHANGE;
|
||||
if (Level->Players[playernum]->ReadyWeapon==wp)
|
||||
{
|
||||
players[playernum].ReadyWeapon=nullptr;
|
||||
Level->Players[playernum]->ReadyWeapon=nullptr;
|
||||
|
||||
IFVM(PlayerPawn, PickNewWeapon)
|
||||
{
|
||||
VMValue param[] = { players[playernum].mo, (void*)nullptr };
|
||||
VMValue param[] = { Level->Players[playernum]->mo, (void*)nullptr };
|
||||
VMCall(func, param, 2, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
@ -2537,9 +2537,9 @@ void FParser::SF_PlayerWeapon()
|
|||
{
|
||||
if (!wp)
|
||||
{
|
||||
auto pw=players[playernum].PendingWeapon;
|
||||
players[playernum].mo->GiveInventoryType(ti);
|
||||
players[playernum].PendingWeapon=pw;
|
||||
auto pw=Level->Players[playernum]->PendingWeapon;
|
||||
Level->Players[playernum]->mo->GiveInventoryType(ti);
|
||||
Level->Players[playernum]->PendingWeapon=pw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2588,13 +2588,13 @@ void FParser::SF_PlayerSelectedWeapon()
|
|||
return;
|
||||
}
|
||||
|
||||
players[playernum].PendingWeapon = players[playernum].mo->FindInventory(ti);
|
||||
Level->Players[playernum]->PendingWeapon = Level->Players[playernum]->mo->FindInventory(ti);
|
||||
|
||||
}
|
||||
t_return.type = svt_int;
|
||||
for(int i=0;i<9;i++)
|
||||
{
|
||||
if (players[playernum].ReadyWeapon->GetClass ()->TypeName == FName(WeaponNames[i]))
|
||||
if (Level->Players[playernum]->ReadyWeapon->GetClass ()->TypeName == FName(WeaponNames[i]))
|
||||
{
|
||||
t_return.value.i=i;
|
||||
break;
|
||||
|
@ -2620,7 +2620,7 @@ void FParser::SF_GiveInventory(void)
|
|||
|
||||
if(t_argc == 2) count=1;
|
||||
else count=intvalue(t_argv[2]);
|
||||
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
|
||||
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = 0;
|
||||
}
|
||||
|
@ -2643,7 +2643,7 @@ void FParser::SF_TakeInventory(void)
|
|||
|
||||
if(t_argc == 2) count=32767;
|
||||
else count=intvalue(t_argv[2]);
|
||||
ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
|
||||
ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = 0;
|
||||
}
|
||||
|
@ -2668,7 +2668,7 @@ void FParser::SF_CheckInventory(void)
|
|||
return;
|
||||
}
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = CheckInventory(players[playernum].mo, stringvalue(t_argv[1]));
|
||||
t_return.value.i = CheckInventory(Level->Players[playernum]->mo, stringvalue(t_argv[1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3221,10 +3221,10 @@ void FParser::SF_PlayerAddFrag()
|
|||
{
|
||||
playernum1 = T_GetPlayerNum(t_argv[0]);
|
||||
|
||||
players[playernum1].fragcount++;
|
||||
Level->Players[playernum1]->fragcount++;
|
||||
|
||||
t_return.type = svt_int;
|
||||
t_return.value.f = players[playernum1].fragcount;
|
||||
t_return.value.f = Level->Players[playernum1]->fragcount;
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -3232,10 +3232,10 @@ void FParser::SF_PlayerAddFrag()
|
|||
playernum1 = T_GetPlayerNum(t_argv[0]);
|
||||
playernum2 = T_GetPlayerNum(t_argv[1]);
|
||||
|
||||
players[playernum1].frags[playernum2]++;
|
||||
Level->Players[playernum1]->frags[playernum2]++;
|
||||
|
||||
t_return.type = svt_int;
|
||||
t_return.value.f = players[playernum1].frags[playernum2];
|
||||
t_return.value.f = Level->Players[playernum1]->frags[playernum2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -616,7 +616,7 @@ void T_PreprocessScripts(FLevelLocals *Level)
|
|||
// get the other scripts
|
||||
|
||||
// levelscript started by player 0 'superplayer'
|
||||
th->LevelScript->trigger = players[0].mo;
|
||||
th->LevelScript->trigger = Level->Players[0]->mo;
|
||||
|
||||
th->LevelScript->Preprocess(Level);
|
||||
th->LevelScript->ParseScript(nullptr, th);
|
||||
|
|
|
@ -494,7 +494,7 @@ int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet)
|
|||
|
||||
// If we get here, that means the actor isn't holding an appropriate key.
|
||||
|
||||
if (owner == players[consoleplayer].camera)
|
||||
if (owner->CheckLocalView(consoleplayer))
|
||||
{
|
||||
PrintMessage(failtext);
|
||||
|
||||
|
|
|
@ -835,12 +835,12 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo)
|
|||
|
||||
for (i=0 ; i<MAXPLAYERS ; i++)
|
||||
{
|
||||
wminfo.plyr[i].skills = players[i].killcount;
|
||||
wminfo.plyr[i].sitems = players[i].itemcount;
|
||||
wminfo.plyr[i].ssecret = players[i].secretcount;
|
||||
wminfo.plyr[i].skills = Players[i]->killcount;
|
||||
wminfo.plyr[i].sitems = Players[i]->itemcount;
|
||||
wminfo.plyr[i].ssecret = Players[i]->secretcount;
|
||||
wminfo.plyr[i].stime = time;
|
||||
memcpy (wminfo.plyr[i].frags, players[i].frags, sizeof(wminfo.plyr[i].frags));
|
||||
wminfo.plyr[i].fragcount = players[i].fragcount;
|
||||
memcpy (wminfo.plyr[i].frags, Players[i]->frags, sizeof(wminfo.plyr[i].frags));
|
||||
wminfo.plyr[i].fragcount = Players[i]->fragcount;
|
||||
}
|
||||
|
||||
// [RH] If we're in a hub and staying within that hub, take a snapshot.
|
||||
|
@ -1035,11 +1035,11 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && (deathmatch || players[i].playerstate == PST_DEAD))
|
||||
players[i].playerstate = PST_ENTER; // [BC]
|
||||
memset (players[i].frags,0,sizeof(players[i].frags));
|
||||
if (PlayerInGame(i) && (deathmatch || Players[i]->playerstate == PST_DEAD))
|
||||
Players[i]->playerstate = PST_ENTER; // [BC]
|
||||
memset (Players[i]->frags,0,sizeof(Players[i]->frags));
|
||||
if (!(dmflags2 & DF2_YES_KEEPFRAGS) && (alwaysapplydmflags || deathmatch))
|
||||
players[i].fragcount = 0;
|
||||
Players[i]->fragcount = 0;
|
||||
}
|
||||
|
||||
if (changeflags & CHANGELEVEL_NOMONSTERS)
|
||||
|
@ -1093,19 +1093,19 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au
|
|||
{
|
||||
for (int i = 0; i<MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo != NULL)
|
||||
P_PlayerStartStomp(players[i].mo);
|
||||
if (PlayerInGame(i) && Players[i]->mo != nullptr)
|
||||
P_PlayerStartStomp(Players[i]->mo);
|
||||
}
|
||||
}
|
||||
|
||||
// For each player, if they are viewing through a player, make sure it is themselves.
|
||||
for (int ii = 0; ii < MAXPLAYERS; ++ii)
|
||||
{
|
||||
if (playeringame[ii])
|
||||
if (PlayerInGame(ii))
|
||||
{
|
||||
if (players[ii].camera == NULL || players[ii].camera->player != NULL)
|
||||
if (Players[ii]->camera == nullptr || Players[ii]->camera->player != nullptr)
|
||||
{
|
||||
players[ii].camera = players[ii].mo;
|
||||
Players[ii]->camera = Players[ii]->mo;
|
||||
}
|
||||
|
||||
if (savegamerestore)
|
||||
|
@ -1119,7 +1119,7 @@ void FLevelLocals::DoLoadLevel(const FString &nextmapname, int position, bool au
|
|||
if (fromSnapshot)
|
||||
{
|
||||
// ENTER scripts are being handled when the player gets spawned, this cannot be changed due to its effect on voodoo dolls.
|
||||
Behaviors.StartTypedScripts(SCRIPT_Return, players[ii].mo, true);
|
||||
Behaviors.StartTypedScripts(SCRIPT_Return, Players[ii]->mo, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1181,8 +1181,8 @@ void FLevelLocals::WorldDone (void)
|
|||
// Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere.
|
||||
if (endsequence == NAME_Inter_Strife)
|
||||
{
|
||||
if (players[0].mo->FindInventory (NAME_QuestItem25) ||
|
||||
players[0].mo->FindInventory (NAME_QuestItem28))
|
||||
if (Players[0]->mo->FindInventory (NAME_QuestItem25) ||
|
||||
Players[0]->mo->FindInventory (NAME_QuestItem28))
|
||||
{
|
||||
endsequence = NAME_Inter_Strife_Good;
|
||||
}
|
||||
|
@ -1317,12 +1317,12 @@ void FLevelLocals::StartTravel ()
|
|||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
AActor *pawn = players[i].mo;
|
||||
AActor *pawn = Players[i]->mo;
|
||||
AActor *inv;
|
||||
players[i].camera = nullptr;
|
||||
Players[i]->camera = nullptr;
|
||||
|
||||
// Only living players travel. Dead ones get a new body on the new level.
|
||||
if (players[i].health > 0)
|
||||
if (Players[i]->health > 0)
|
||||
{
|
||||
pawn->UnlinkFromWorld (nullptr);
|
||||
int tid = pawn->tid; // Save TID
|
||||
|
@ -1721,14 +1721,14 @@ void FLevelLocals::UnSnapshotLevel (bool hubLoad)
|
|||
while ((pawn = next) != 0)
|
||||
{
|
||||
next = it.Next();
|
||||
if (pawn->player == NULL || pawn->player->mo == NULL || !playeringame[pawn->player - players])
|
||||
if (pawn->player == nullptr || pawn->player->mo == nullptr || !PlayerInGame(pawn->player))
|
||||
{
|
||||
int i;
|
||||
|
||||
// If this isn't the unmorphed original copy of a player, destroy it, because it's extra.
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].morphTics && players[i].mo->alternative == pawn)
|
||||
if (PlayerInGame(i) && Players[i]->morphTics && Players[i]->mo->alternative == pawn)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "p_spec.h"
|
||||
#include "actor.h"
|
||||
#include "p_effect.h"
|
||||
#include "d_player.h"
|
||||
#include "p_destructible.h"
|
||||
#include "r_data/r_sections.h"
|
||||
#include "r_data/r_canvastexture.h"
|
||||
|
@ -102,7 +103,15 @@ struct FLevelLocals
|
|||
{
|
||||
void *level;
|
||||
void *Level; // bug catchers.
|
||||
FLevelLocals() : Behaviors(this), tagManager(this) {}
|
||||
FLevelLocals() : Behaviors(this), tagManager(this)
|
||||
{
|
||||
// Make sure that these point to the right data all the time.
|
||||
// This will be needed for as long as it takes to completely separate global UI state from per-level play state.
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
Players[i] = &players[i];
|
||||
}
|
||||
}
|
||||
|
||||
friend class MapLoader;
|
||||
|
||||
|
@ -494,6 +503,42 @@ public:
|
|||
TObjPtr<DAutomapBase*> automap = nullptr;
|
||||
int bodyqueslot;
|
||||
|
||||
// For now this merely points to the global player array, but with this in place, access to this array can be moved over to the level.
|
||||
// As things progress each level needs to be able to point to different players,
|
||||
// but even then the level will not own the player - the player merely links to the level.
|
||||
// This should also be made a real object eventually.
|
||||
player_t *Players[MAXPLAYERS];
|
||||
|
||||
// This is to allow refactoring without refactoring the data right away.
|
||||
bool PlayerInGame(int pnum)
|
||||
{
|
||||
return playeringame[pnum];
|
||||
}
|
||||
|
||||
// This needs to be done better, but for now it should be good enough.
|
||||
bool PlayerInGame(player_t *player)
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (player == Players[i]) return PlayerInGame(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int PlayerNum(player_t *player)
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (player == Players[i]) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool isPrimaryLevel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int NumMapSections;
|
||||
|
||||
uint32_t flags;
|
||||
|
|
|
@ -122,9 +122,9 @@ void DEarthquake::Tick ()
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !(players[i].cheats & CF_NOCLIP))
|
||||
if (Level->PlayerInGame(i) && !(Level->Players[i]->cheats & CF_NOCLIP))
|
||||
{
|
||||
AActor *victim = players[i].mo;
|
||||
AActor *victim = Level->Players[i]->mo;
|
||||
double dist;
|
||||
|
||||
dist = m_Spot->Distance2D(victim, true);
|
||||
|
|
|
@ -3247,8 +3247,8 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
|
|||
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo != nullptr)
|
||||
players[i].health = players[i].mo->health;
|
||||
if (Level->PlayerInGame(i) && Level->Players[i]->mo != nullptr)
|
||||
Level->Players[i]->health = Level->Players[i]->mo->health;
|
||||
}
|
||||
if (!map->HasBehavior && !map->isText)
|
||||
TranslateTeleportThings(); // [RH] Assign teleport destination TIDs
|
||||
|
|
|
@ -1725,7 +1725,7 @@ static bool DoUseInv (AActor *actor, PClassActor *info)
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
static int UseInventory (AActor *activator, const char *type)
|
||||
static int UseInventory (FLevelLocals *Level, AActor *activator, const char *type)
|
||||
{
|
||||
PClassActor *info;
|
||||
int ret = 0;
|
||||
|
@ -1743,8 +1743,8 @@ static int UseInventory (AActor *activator, const char *type)
|
|||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
ret += DoUseInv (players[i].mo, info);
|
||||
if (Level->PlayerInGame(i))
|
||||
ret += DoUseInv (Level->Players[i]->mo, info);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1759,6 +1759,7 @@ static int UseInventory (AActor *activator, const char *type)
|
|||
// CheckInventory
|
||||
//
|
||||
// Returns how much of a particular item an actor has.
|
||||
// This also gets called from FraggleScript.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
|
@ -3672,7 +3673,7 @@ int DLevelScript::CountPlayers ()
|
|||
int count = 0, i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
|
@ -3850,9 +3851,9 @@ void DLevelScript::DoFadeRange (int r1, int g1, int b1, int a1,
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
viewer = &players[i];
|
||||
viewer = Level->Players[i];
|
||||
showme:
|
||||
if (ftime <= 0.f)
|
||||
{
|
||||
|
@ -3965,7 +3966,7 @@ int DoGetMasterTID (AActor *self)
|
|||
if (self->master) return self->master->tid;
|
||||
else if (self->FriendPlayer)
|
||||
{
|
||||
player_t *player = &players[(self->FriendPlayer)-1];
|
||||
player_t *player = self->Level->Players[(self->FriendPlayer)-1];
|
||||
return player->mo->tid;
|
||||
}
|
||||
else return 0;
|
||||
|
@ -4504,13 +4505,13 @@ int DLevelScript::GetPlayerInput(int playernum, int inputnum)
|
|||
}
|
||||
p = activator->player;
|
||||
}
|
||||
else if (playernum >= MAXPLAYERS || !playeringame[playernum])
|
||||
else if (playernum >= MAXPLAYERS || !Level->PlayerInGame(playernum))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = &players[playernum];
|
||||
p = Level->Players[playernum];
|
||||
}
|
||||
if (p == NULL)
|
||||
{
|
||||
|
@ -4961,11 +4962,11 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string)
|
|||
|
||||
int DLevelScript::SetUserCVar(int playernum, const char *cvarname, int value, bool is_string)
|
||||
{
|
||||
if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum])
|
||||
if ((unsigned)playernum >= MAXPLAYERS || !Level->PlayerInGame(playernum))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true));
|
||||
FBaseCVar **cvar_p = Level->Players[playernum]->userinfo.CheckKey(FName(cvarname, true));
|
||||
FBaseCVar *cvar;
|
||||
// Only mod-created cvars may be set.
|
||||
if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE) || !(cvar->GetFlags() & CVAR_MOD))
|
||||
|
@ -4975,7 +4976,7 @@ int DLevelScript::SetUserCVar(int playernum, const char *cvarname, int value, bo
|
|||
DoSetCVar(cvar, value, is_string);
|
||||
|
||||
// If we are this player, then also reflect this change in the local version of this cvar.
|
||||
if (playernum == consoleplayer)
|
||||
if (playernum == consoleplayer && Level->isPrimaryLevel())
|
||||
{
|
||||
FBaseCVar *cvar = FindCVar(cvarname, NULL);
|
||||
// If we can find it in the userinfo, then we should also be able to find it in the normal cvar list,
|
||||
|
@ -5004,7 +5005,9 @@ int DLevelScript::SetCVar(AActor *activator, const char *cvarname, int value, bo
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
return SetUserCVar(int(activator->player - players), cvarname, value, is_string);
|
||||
auto pnum = Level->PlayerNum(activator->player);
|
||||
if (pnum < 0) return 0;
|
||||
return SetUserCVar(pnum, cvarname, value, is_string);
|
||||
}
|
||||
DoSetCVar(cvar, value, is_string);
|
||||
return 1;
|
||||
|
@ -5388,25 +5391,25 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
|
|||
|
||||
case ACSF_GetAirSupply:
|
||||
{
|
||||
if (args[0] < 0 || args[0] >= MAXPLAYERS || !playeringame[args[0]])
|
||||
if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return players[args[0]].air_finished - Level->time;
|
||||
return Level->Players[args[0]]->air_finished - Level->time;
|
||||
}
|
||||
}
|
||||
|
||||
case ACSF_SetAirSupply:
|
||||
{
|
||||
if (args[0] < 0 || args[0] >= MAXPLAYERS || !playeringame[args[0]])
|
||||
if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[args[0]].air_finished = args[1] + Level->time;
|
||||
Level->Players[args[0]]->air_finished = args[1] + Level->time;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -5420,14 +5423,14 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
|
|||
|
||||
case ACSF_GetArmorType:
|
||||
{
|
||||
if (args[1] < 0 || args[1] >= MAXPLAYERS || !playeringame[args[1]])
|
||||
if (args[1] < 0 || args[1] >= MAXPLAYERS || !Level->PlayerInGame(args[1]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FName p(Level->Behaviors.LookupString(args[0]));
|
||||
auto armor = players[args[1]].mo->FindInventory(NAME_BasicArmor);
|
||||
auto armor = Level->Players[args[1]]->mo->FindInventory(NAME_BasicArmor);
|
||||
if (armor && armor->NameVar(NAME_ArmorType) == p) return armor->IntVar(NAME_Amount);
|
||||
}
|
||||
return 0;
|
||||
|
@ -8454,9 +8457,9 @@ scriptwait:
|
|||
player = activator->player;
|
||||
}
|
||||
}
|
||||
else if (playeringame[STACK(1)-1])
|
||||
else if (Level->PlayerInGame(STACK(1)-1))
|
||||
{
|
||||
player = &players[STACK(1)-1];
|
||||
player = Level->Players[STACK(1)-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -8610,6 +8613,7 @@ scriptwait:
|
|||
{
|
||||
optstart = sp;
|
||||
}
|
||||
if (Level->isPrimaryLevel())
|
||||
{
|
||||
AActor *screen = activator;
|
||||
if (screen != NULL &&
|
||||
|
@ -9198,7 +9202,7 @@ scriptwait:
|
|||
break;
|
||||
|
||||
case PCD_USEINVENTORY:
|
||||
STACK(1) = UseInventory (activator, Level->Behaviors.LookupString (STACK(1)));
|
||||
STACK(1) = UseInventory (Level, activator, Level->Behaviors.LookupString (STACK(1)));
|
||||
break;
|
||||
|
||||
case PCD_USEACTORINVENTORY:
|
||||
|
@ -9207,7 +9211,7 @@ scriptwait:
|
|||
const char *type = Level->Behaviors.LookupString(STACK(1));
|
||||
if (STACK(2) == 0)
|
||||
{
|
||||
ret = UseInventory(NULL, type);
|
||||
ret = UseInventory(Level, NULL, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -9215,7 +9219,7 @@ scriptwait:
|
|||
AActor *actor;
|
||||
for (actor = it.Next(); actor != NULL; actor = it.Next())
|
||||
{
|
||||
ret += UseInventory(actor, type);
|
||||
ret += UseInventory(Level, actor, type);
|
||||
}
|
||||
}
|
||||
STACK(2) = ret;
|
||||
|
@ -9655,18 +9659,18 @@ scriptwait:
|
|||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = playeringame[STACK(1)];
|
||||
STACK(1) = Level->PlayerInGame(STACK(1));
|
||||
}
|
||||
break;
|
||||
|
||||
case PCD_PLAYERISBOT:
|
||||
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !playeringame[STACK(1)])
|
||||
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !Level->PlayerInGame(STACK(1)))
|
||||
{
|
||||
STACK(1) = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = (players[STACK(1)].Bot != NULL);
|
||||
STACK(1) = (Level->Players[STACK(1)]->Bot != nullptr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -9858,24 +9862,24 @@ scriptwait:
|
|||
break;
|
||||
|
||||
case PCD_PLAYERCLASS: // [GRB]
|
||||
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !playeringame[STACK(1)])
|
||||
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !Level->PlayerInGame(STACK(1)))
|
||||
{
|
||||
STACK(1) = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = players[STACK(1)].CurrentPlayerClass;
|
||||
STACK(1) = Level->Players[STACK(1)]->CurrentPlayerClass;
|
||||
}
|
||||
break;
|
||||
|
||||
case PCD_GETPLAYERINFO: // [GRB]
|
||||
if (STACK(2) < 0 || STACK(2) >= MAXPLAYERS || !playeringame[STACK(2)])
|
||||
if (STACK(2) < 0 || STACK(2) >= MAXPLAYERS || !Level->PlayerInGame(STACK(2)))
|
||||
{
|
||||
STACK(2) = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
player_t *pl = &players[STACK(2)];
|
||||
player_t *pl = Level->Players[STACK(2)];
|
||||
userinfo_t *userinfo = &pl->userinfo;
|
||||
switch (STACK(1))
|
||||
{
|
||||
|
@ -9973,13 +9977,14 @@ scriptwait:
|
|||
{
|
||||
int playernum = STACK(1);
|
||||
|
||||
if (playernum < 0 || playernum >= MAXPLAYERS || !playeringame[playernum] || players[playernum].camera == NULL || players[playernum].camera->player != NULL)
|
||||
if (playernum < 0 || playernum >= MAXPLAYERS || !Level->PlayerInGame(playernum) ||
|
||||
Level->Players[playernum]->camera == nullptr || Level->Players[playernum]->camera->player != nullptr)
|
||||
{
|
||||
STACK(1) = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = players[playernum].camera->tid;
|
||||
STACK(1) = Level->Players[playernum]->camera->tid;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -10301,8 +10306,8 @@ void FLevelLocals::DoDeferedScripts ()
|
|||
if (scriptdata)
|
||||
{
|
||||
P_GetScriptGoing (this, (unsigned)def->playernum < MAXPLAYERS &&
|
||||
playeringame[def->playernum] ? players[def->playernum].mo : NULL,
|
||||
NULL, def->script,
|
||||
PlayerInGame(def->playernum) ? Players[def->playernum]->mo : nullptr,
|
||||
nullptr, def->script,
|
||||
scriptdata, module,
|
||||
def->args, 3,
|
||||
def->type == acsdefered_t::defexealways ? ACS_ALWAYS : 0);
|
||||
|
|
|
@ -1684,18 +1684,20 @@ DEFINE_ACTION_FUNCTION(AActor, CheckIfSeen)
|
|||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
auto Level = self->Level;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
auto p = Level->Players[i];
|
||||
// Always check sight from each player.
|
||||
if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY))
|
||||
if (P_CheckSight(p->mo, self, SF_IGNOREVISIBILITY))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
// If a player is viewing from a non-player, then check that too.
|
||||
if (players[i].camera != NULL && players[i].camera->player == NULL &&
|
||||
P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY))
|
||||
if (p->camera != nullptr && p->camera->player == NULL &&
|
||||
P_CheckSight(p->camera, self, SF_IGNOREVISIBILITY))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
|
@ -1755,18 +1757,20 @@ DEFINE_ACTION_FUNCTION(AActor, CheckSightOrRange)
|
|||
PARAM_BOOL(twodi);
|
||||
|
||||
range *= range;
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
auto Level = self->Level;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
auto p = Level->Players[i];
|
||||
// Always check from each player.
|
||||
if (DoCheckSightOrRange(self, players[i].mo, range, twodi, true))
|
||||
if (DoCheckSightOrRange(self, p->mo, range, twodi, true))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
// If a player is viewing from a non-player, check that too.
|
||||
if (players[i].camera != NULL && players[i].camera->player == NULL &&
|
||||
DoCheckSightOrRange(self, players[i].camera, range, twodi, true))
|
||||
if (p->camera != nullptr && p->camera->player == nullptr &&
|
||||
DoCheckSightOrRange(self, p->camera, range, twodi, true))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
|
@ -1783,18 +1787,20 @@ DEFINE_ACTION_FUNCTION(AActor, CheckRange)
|
|||
PARAM_BOOL(twodi);
|
||||
|
||||
range *= range;
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
auto Level = self->Level;
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
auto p = Level->Players[i];
|
||||
// Always check from each player.
|
||||
if (DoCheckSightOrRange(self, players[i].mo, range, twodi, false))
|
||||
if (DoCheckSightOrRange(self, p->mo, range, twodi, false))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
// If a player is viewing from a non-player, check that too.
|
||||
if (players[i].camera != NULL && players[i].camera->player == NULL &&
|
||||
DoCheckSightOrRange(self, players[i].camera, range, twodi, false))
|
||||
if (p->camera != nullptr && p->camera->player == nullptr &&
|
||||
DoCheckSightOrRange(self, p->camera, range, twodi, false))
|
||||
{
|
||||
ACTION_RETURN_BOOL(false);
|
||||
}
|
||||
|
|
|
@ -738,7 +738,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
int i;
|
||||
|
||||
// Make sure this is actually a player.
|
||||
if (pc == nullptr || pc->player == nullptr || npc == nullptr) return;
|
||||
if (pc == nullptr || pc->player == nullptr || npc == nullptr || pc->Level != currentUILevel) return;
|
||||
auto Level = pc->Level;
|
||||
|
||||
// [CW] If an NPC is talking to a PC already, then don't let
|
||||
|
|
|
@ -324,10 +324,6 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
|
|||
//
|
||||
void P_RunEffects (FLevelLocals *Level)
|
||||
{
|
||||
if (players[consoleplayer].camera == NULL) return;
|
||||
|
||||
int pnum = players[consoleplayer].camera->Sector->Index() * Level->sectors.Size();
|
||||
|
||||
AActor *actor;
|
||||
auto iterator = Level->GetThinkerIterator<AActor>();
|
||||
|
||||
|
|
|
@ -1005,12 +1005,12 @@ void P_RandomChaseDir (AActor *actor)
|
|||
{
|
||||
i = 0;
|
||||
}
|
||||
else for (i = pr_newchasedir() & (MAXPLAYERS-1); !playeringame[i]; i = (i+1) & (MAXPLAYERS-1))
|
||||
else for (i = pr_newchasedir() & (MAXPLAYERS-1); !actor->Level->PlayerInGame(i); i = (i+1) & (MAXPLAYERS-1))
|
||||
{
|
||||
}
|
||||
player = players[i].mo;
|
||||
player = actor->Level->Players[i]->mo;
|
||||
}
|
||||
if (player != NULL && playeringame[i])
|
||||
if (player != NULL && actor->Level->PlayerInGame(i))
|
||||
{
|
||||
if (pr_newchasedir() & 1 || !P_CheckSight (actor, player))
|
||||
{
|
||||
|
@ -1203,7 +1203,7 @@ int P_LookForMonsters (AActor *actor)
|
|||
AActor *mo;
|
||||
auto iterator = actor->Level->GetThinkerIterator<AActor>();
|
||||
|
||||
if (!P_CheckSight (players[0].mo, actor, SF_SEEPASTBLOCKEVERYTHING))
|
||||
if (!P_CheckSight (actor->Level->Players[0]->mo, actor, SF_SEEPASTBLOCKEVERYTHING))
|
||||
{ // Player can't see monster
|
||||
return false;
|
||||
}
|
||||
|
@ -1592,11 +1592,13 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
|||
// Go back to a player, no matter whether it's visible or not
|
||||
for (int anyone=0; anyone<=1; anyone++)
|
||||
{
|
||||
auto Level = actor->Level;
|
||||
for (int c=0; c<MAXPLAYERS; c++)
|
||||
{
|
||||
if (playeringame[c] && players[c].playerstate==PST_LIVE &&
|
||||
actor->IsFriend(players[c].mo) &&
|
||||
(anyone || P_IsVisible(actor, players[c].mo, allaround)))
|
||||
auto p = Level->Players[i];
|
||||
if (Level->PlayerInGame(c) && p->playerstate==PST_LIVE &&
|
||||
actor->IsFriend(p->mo) &&
|
||||
(anyone || P_IsVisible(actor, p->mo, allaround)))
|
||||
{
|
||||
actor->target = players[c].mo;
|
||||
|
||||
|
@ -1623,8 +1625,9 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
|||
} // [SP] if false, and in deathmatch, intentional fall-through
|
||||
|
||||
if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
|
||||
actor->Level->isPrimaryLevel() &&
|
||||
!multiplayer &&
|
||||
players[0].health <= 0 &&
|
||||
actor->Level->Players[0]->health <= 0 &&
|
||||
actor->goal == NULL &&
|
||||
gamestate != GS_TITLELEVEL
|
||||
)
|
||||
|
@ -1648,7 +1651,7 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
|||
if (c++ < MAXPLAYERS)
|
||||
{
|
||||
pnum = (pnum + 1) & (MAXPLAYERS - 1);
|
||||
if (!playeringame[pnum])
|
||||
if (!actor->Level->PlayerInGame(pnum))
|
||||
continue;
|
||||
|
||||
if (actor->TIDtoHate == 0)
|
||||
|
@ -1686,12 +1689,12 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
|||
return actor->target == actor->goal && actor->goal != NULL;
|
||||
}
|
||||
|
||||
player = &players[pnum];
|
||||
player = actor->Level->Players[pnum];
|
||||
|
||||
if (!(player->mo->flags & MF_SHOOTABLE))
|
||||
continue; // not shootable (observer or dead)
|
||||
|
||||
if (!((actor->flags ^ player->mo->flags) & MF_FRIENDLY))
|
||||
if (actor->IsFriend(player->mo))
|
||||
continue; // same +MF_FRIENDLY, ignore
|
||||
|
||||
if (player->cheats & CF_NOTARGET)
|
||||
|
@ -2284,7 +2287,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
|
||||
if (actor->FriendPlayer != 0)
|
||||
{
|
||||
player = &players[actor->FriendPlayer - 1];
|
||||
player = actor->Level->Players[actor->FriendPlayer - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2293,10 +2296,10 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
{
|
||||
i = 0;
|
||||
}
|
||||
else for (i = pr_newchasedir() & (MAXPLAYERS-1); !playeringame[i]; i = (i+1) & (MAXPLAYERS-1))
|
||||
else for (i = pr_newchasedir() & (MAXPLAYERS-1); !actor->Level->PlayerInGame(i); i = (i+1) & (MAXPLAYERS-1))
|
||||
{
|
||||
}
|
||||
player = &players[i];
|
||||
player = actor->Level->Players[i];
|
||||
}
|
||||
if (player->attacker && player->attacker->health > 0 && player->attacker->flags & MF_SHOOTABLE && pr_newchasedir() < 80)
|
||||
{
|
||||
|
@ -3037,7 +3040,7 @@ int CheckBossDeath (AActor *actor)
|
|||
|
||||
// make sure there is a player alive for victory
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].health > 0)
|
||||
if (actor->Level->PlayerInGame(i) && actor->Level->Players[i]->health > 0)
|
||||
break;
|
||||
|
||||
if (i == MAXPLAYERS)
|
||||
|
|
|
@ -547,11 +547,11 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!multiplayer && CountsAsKill())
|
||||
else if (!multiplayer && CountsAsKill() && Level->isPrimaryLevel())
|
||||
{
|
||||
// count all monster deaths,
|
||||
// even those caused by other monsters
|
||||
players[0].killcount++;
|
||||
Level->Players[0]->killcount++;
|
||||
}
|
||||
|
||||
if (player)
|
||||
|
@ -577,11 +577,12 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
|
|||
//Added by MC: Discard enemies.
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (players[i].Bot != NULL && this == players[i].Bot->enemy)
|
||||
DBot *Bot = Level->Players[i]->Bot;
|
||||
if (Bot != nullptr && this == Bot->enemy)
|
||||
{
|
||||
if (players[i].Bot->dest == players[i].Bot->enemy)
|
||||
players[i].Bot->dest = nullptr;
|
||||
players[i].Bot->enemy = nullptr;
|
||||
if (Bot->dest == Bot->enemy)
|
||||
Bot->dest = nullptr;
|
||||
Bot->enemy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2835,24 +2835,25 @@ FUNC(LS_ChangeCamera)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
if (!Level->PlayerInGame(i))
|
||||
continue;
|
||||
|
||||
AActor *oldcamera = players[i].camera;
|
||||
auto p = Level->Players[i];
|
||||
AActor *oldcamera = p->camera;
|
||||
if (camera)
|
||||
{
|
||||
players[i].camera = camera;
|
||||
p->camera = camera;
|
||||
if (arg2)
|
||||
players[i].cheats |= CF_REVERTPLEASE;
|
||||
p->cheats |= CF_REVERTPLEASE;
|
||||
}
|
||||
else
|
||||
{
|
||||
players[i].camera = players[i].mo;
|
||||
players[i].cheats &= ~CF_REVERTPLEASE;
|
||||
p->camera = p->mo;
|
||||
p->cheats &= ~CF_REVERTPLEASE;
|
||||
}
|
||||
if (oldcamera != players[i].camera)
|
||||
if (oldcamera != p->camera)
|
||||
{
|
||||
R_ClearPastViewer (players[i].camera);
|
||||
R_ClearPastViewer (p->camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2977,14 +2978,15 @@ FUNC(LS_SetPlayerProperty)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].mo == NULL)
|
||||
auto p = Level->Players[i];
|
||||
if (!Level->PlayerInGame(i) || p->mo == nullptr)
|
||||
continue;
|
||||
|
||||
if (arg1)
|
||||
{ // Give power
|
||||
if (power != 4)
|
||||
{
|
||||
auto item = players[i].mo->GiveInventoryType ((PClass::FindActor(powers[power])));
|
||||
auto item = p->mo->GiveInventoryType ((PClass::FindActor(powers[power])));
|
||||
if (item != NULL && power == 0 && arg1 == 1)
|
||||
{
|
||||
item->ColorVar(NAME_BlendColor) = MakeSpecialColormap(INVERSECOLORMAP);
|
||||
|
@ -2999,7 +3001,7 @@ FUNC(LS_SetPlayerProperty)
|
|||
{ // Take power
|
||||
if (power != 4)
|
||||
{
|
||||
auto item = players[i].mo->FindInventory (PClass::FindActor(powers[power]));
|
||||
auto item = p->mo->FindInventory (PClass::FindActor(powers[power]));
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Destroy ();
|
||||
|
@ -3072,25 +3074,26 @@ FUNC(LS_SetPlayerProperty)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
if (!Level->PlayerInGame(i))
|
||||
continue;
|
||||
|
||||
auto p = Level->Players[i];
|
||||
if (arg1)
|
||||
{
|
||||
players[i].cheats |= mask;
|
||||
p->cheats |= mask;
|
||||
if (arg2 == PROP_FLY)
|
||||
{
|
||||
players[i].mo->flags2 |= MF2_FLY;
|
||||
players[i].mo->flags |= MF_NOGRAVITY;
|
||||
p->mo->flags2 |= MF2_FLY;
|
||||
p->mo->flags |= MF_NOGRAVITY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
players[i].cheats &= ~mask;
|
||||
p->cheats &= ~mask;
|
||||
if (arg2 == PROP_FLY)
|
||||
{
|
||||
players[i].mo->flags2 &= ~MF2_FLY;
|
||||
players[i].mo->flags &= ~MF_NOGRAVITY;
|
||||
p->mo->flags2 &= ~MF2_FLY;
|
||||
p->mo->flags &= ~MF_NOGRAVITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3310,9 +3313,9 @@ FUNC(LS_GlassBreak)
|
|||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
it = players[i].mo;
|
||||
it = Level->Players[i]->mo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -945,16 +945,17 @@ DEFINE_ACTION_FUNCTION(AActor, GiveBody)
|
|||
|
||||
bool AActor::CheckLocalView (int playernum) const
|
||||
{
|
||||
if (players[playernum].camera == this)
|
||||
auto p = &players[playernum];
|
||||
if (p->camera == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (players[playernum].mo != this || players[playernum].camera == NULL)
|
||||
if (p->mo != this || p->camera == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (players[playernum].camera->player == NULL &&
|
||||
!(players[playernum].camera->flags3 & MF3_ISMONSTER))
|
||||
if (p->camera->player == NULL &&
|
||||
!(p->camera->flags3 & MF3_ISMONSTER))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -985,6 +986,10 @@ bool AActor::IsInsideVisibleAngles() const
|
|||
if (players[consoleplayer].camera == nullptr)
|
||||
return true;
|
||||
|
||||
// Not detectable.
|
||||
if (!Level->isPrimaryLevel())
|
||||
return true;
|
||||
|
||||
DAngle anglestart = VisibleStartAngle;
|
||||
DAngle angleend = VisibleEndAngle;
|
||||
DAngle pitchstart = VisibleStartPitch;
|
||||
|
@ -3264,7 +3269,7 @@ bool AActor::IsOkayToAttack (AActor *link)
|
|||
AActor * Friend;
|
||||
if (flags5 & MF5_SUMMONEDMONSTER) Friend = tracer;
|
||||
else if (flags2 & MF2_SEEKERMISSILE) Friend = target;
|
||||
else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = players[FriendPlayer-1].mo;
|
||||
else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = Level->Players[FriendPlayer-1]->mo;
|
||||
else Friend = this;
|
||||
|
||||
// Friend checks
|
||||
|
@ -5052,9 +5057,9 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
|
|||
|
||||
for (int ii = 0; ii < MAXPLAYERS; ++ii)
|
||||
{
|
||||
if (playeringame[ii] && players[ii].camera == oldactor)
|
||||
if (PlayerInGame(ii) && Players[ii]->camera == oldactor)
|
||||
{
|
||||
players[ii].camera = mobj;
|
||||
Players[ii]->camera = mobj;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6825,13 +6830,13 @@ bool AActor::IsFriend (AActor *other)
|
|||
if (deathmatch && teamplay)
|
||||
return IsTeammate(other) ||
|
||||
(FriendPlayer != 0 && other->FriendPlayer != 0 &&
|
||||
players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo));
|
||||
Level->Players[FriendPlayer-1]->mo->IsTeammate(Level->Players[other->FriendPlayer-1]->mo));
|
||||
|
||||
return !deathmatch ||
|
||||
FriendPlayer == other->FriendPlayer ||
|
||||
FriendPlayer == 0 ||
|
||||
other->FriendPlayer == 0 ||
|
||||
players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo);
|
||||
Level->Players[FriendPlayer-1]->mo->IsTeammate(Level->Players[other->FriendPlayer-1]->mo);
|
||||
}
|
||||
// [SP] If friendly flags match, then they are on the same team.
|
||||
/*if (!((flags ^ other->flags) & MF_FRIENDLY))
|
||||
|
@ -6858,13 +6863,13 @@ bool AActor::IsHostile (AActor *other)
|
|||
if (deathmatch && teamplay)
|
||||
return !IsTeammate(other) &&
|
||||
!(FriendPlayer != 0 && other->FriendPlayer != 0 &&
|
||||
players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo));
|
||||
Level->Players[FriendPlayer-1]->mo->IsTeammate(Level->Players[other->FriendPlayer-1]->mo));
|
||||
|
||||
return deathmatch &&
|
||||
FriendPlayer != other->FriendPlayer &&
|
||||
FriendPlayer !=0 &&
|
||||
other->FriendPlayer != 0 &&
|
||||
!players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo);
|
||||
!Level->Players[FriendPlayer-1]->mo->IsTeammate(Level->Players[other->FriendPlayer-1]->mo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -573,7 +573,7 @@ void P_SerializePlayers(FLevelLocals *Level, FSerializer &arc, bool skipload)
|
|||
// Count the number of players present right now.
|
||||
for (numPlayersNow = 0, i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
++numPlayersNow;
|
||||
}
|
||||
|
@ -879,16 +879,16 @@ void FLevelLocals::SpawnExtraPlayers()
|
|||
// be sure to spawn the extra players.
|
||||
int i;
|
||||
|
||||
if (deathmatch)
|
||||
if (deathmatch || !isPrimaryLevel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo == NULL)
|
||||
if (PlayerInGame(i) && Players[i]->mo == NULL)
|
||||
{
|
||||
players[i].playerstate = PST_ENTER;
|
||||
Players[i]->playerstate = PST_ENTER;
|
||||
SpawnPlayer(&playerstarts[i], i, (flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0);
|
||||
}
|
||||
}
|
||||
|
@ -1019,9 +1019,9 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
|
|||
}
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo != nullptr)
|
||||
if (PlayerInGame(i) && Players[i]->mo != nullptr)
|
||||
{
|
||||
FWeaponSlots::SetupWeaponSlots(players[i].mo);
|
||||
FWeaponSlots::SetupWeaponSlots(Players[i]->mo);
|
||||
}
|
||||
}
|
||||
RecreateAllAttachedLights();
|
||||
|
|
|
@ -378,13 +378,13 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
|||
Level->SetMusicVolume(Level->MusicVolume);
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
players[i].killcount = players[i].secretcount
|
||||
= players[i].itemcount = 0;
|
||||
Level->Players[i]->killcount = Level->Players[i]->secretcount
|
||||
= Level->Players[i]->itemcount = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
players[i].mo = nullptr;
|
||||
Level->Players[i]->mo = nullptr;
|
||||
}
|
||||
// [RH] Clear any scripted translation colors the previous level may have set.
|
||||
for (i = 0; i < int(translationtables[TRANSLATION_LevelScripted].Size()); ++i)
|
||||
|
@ -439,9 +439,9 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
players[i].mo = nullptr;
|
||||
Level->Players[i]->mo = nullptr;
|
||||
Level->DeathMatchSpawnPlayer(i);
|
||||
}
|
||||
}
|
||||
|
@ -451,9 +451,9 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
if (Level->PlayerInGame(i))
|
||||
{
|
||||
players[i].mo = nullptr;
|
||||
Level->Players[i]->mo = nullptr;
|
||||
FPlayerStart *mthing = Level->PickPlayerStart(i);
|
||||
Level->SpawnPlayer(mthing, i, (Level->flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0);
|
||||
}
|
||||
|
@ -466,11 +466,12 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo != nullptr)
|
||||
auto p = Level->Players[i];
|
||||
if (Level->PlayerInGame(i) && p->mo != nullptr)
|
||||
{
|
||||
if (!(players[i].mo->flags & MF_FRIENDLY))
|
||||
if (!(p->mo->flags & MF_FRIENDLY))
|
||||
{
|
||||
AActor * oldSpawn = players[i].mo;
|
||||
AActor * oldSpawn = p->mo;
|
||||
Level->DeathMatchSpawnPlayer(i);
|
||||
oldSpawn->Destroy();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue