Merge branch 'master' of https://github.com/ZDoom/gzdoom into gzd-master-experimental

This commit is contained in:
nashmuhandes 2024-11-16 13:16:21 +08:00
commit 2e09abc4e8
39 changed files with 279 additions and 91 deletions

View file

@ -169,7 +169,7 @@ static const char *TelefragSounds[] =
#endif
static int LastAnnounceTime;
static FRandom pr_bbannounce ("BBAnnounce");
static FCRandom pr_bbannounce ("BBAnnounce");
// CODE --------------------------------------------------------------------

View file

@ -61,7 +61,7 @@ enum
{
DEFAULT_PITCH = 128,
};
static FRandom pr_soundpitch ("SoundPitch");
static FCRandom pr_soundpitch ("SoundPitch");
SoundEngine* soundEngine;
//==========================================================================

View file

@ -132,7 +132,8 @@ enum
PRE_CONACK, // Sent from host to guest to acknowledge PRE_CONNECT receipt
PRE_ALLFULL, // Sent from host to an unwanted guest
PRE_ALLHEREACK, // Sent from guest to host to acknowledge PRE_ALLHEREACK receipt
PRE_GO // Sent from host to guest to continue game startup
PRE_GO, // Sent from host to guest to continue game startup
PRE_IN_PROGRESS, // Sent from host to guest if the game has already started
};
// Set PreGamePacket.fake to this so that the game rejects any pregame packets
@ -269,6 +270,8 @@ void PacketSend (void)
// I_Error ("SendPacket error: %s",strerror(errno));
}
void PreSend(const void* buffer, int bufferlen, const sockaddr_in* to);
void SendConAck(int num_connected, int num_needed);
//
// PacketGet
@ -303,7 +306,7 @@ void PacketGet (void)
GetPlayerName(node).GetChars());
}
doomcom.data[0] = 0x80; // NCMD_EXIT
doomcom.data[0] = NCMD_EXIT;
c = 1;
}
else if (err != WSAEWOULDBLOCK)
@ -341,10 +344,11 @@ void PacketGet (void)
}
else if (c > 0)
{ //The packet is not from any in-game node, so we might as well discard it.
// Don't show the message for disconnect notifications.
if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT)
if (TransmitBuffer[0] == PRE_FAKE)
{
DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port);
// If it's someone waiting in the lobby, let them know the game already started
uint8_t msg[] = { PRE_FAKE, PRE_IN_PROGRESS };
PreSend(msg, 2, &fromaddress);
}
doomcom.remotenode = -1;
return;
@ -369,7 +373,22 @@ sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort)
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || (noabort && err == WSAECONNRESET))
return NULL; // no packet
I_Error ("PreGet: %s", neterror ());
if (doomcom.consoleplayer == 0)
{
int node = FindNode(&fromaddress);
I_NetMessage("Got unexpected disconnect.");
doomcom.numnodes--;
for (; node < doomcom.numnodes; ++node)
sendaddress[node] = sendaddress[node + 1];
// Let remaining guests know that somebody left.
SendConAck(doomcom.numnodes, doomcom.numplayers);
}
else
{
I_NetError("The host disbanded the game unexpectedly");
}
}
return &fromaddress;
}
@ -499,7 +518,7 @@ void SendAbort (void)
}
}
static void SendConAck (int num_connected, int num_needed)
void SendConAck (int num_connected, int num_needed)
{
PreGamePacket packet;
@ -708,7 +727,7 @@ bool HostGame (int i)
doomcom.numnodes = 1;
I_NetInit ("Waiting for players", numplayers);
I_NetInit ("Hosting game", numplayers);
// Wait for numplayers-1 different connections
if (!I_NetLoop (Host_CheckForConnects, (void *)(intptr_t)numplayers))
@ -783,13 +802,15 @@ bool Guest_ContactHost (void *userdata)
}
else if (packet.Message == PRE_DISCONNECT)
{
doomcom.numnodes = 0;
I_FatalError ("The host cancelled the game.");
I_NetError("The host cancelled the game.");
}
else if (packet.Message == PRE_ALLFULL)
{
doomcom.numnodes = 0;
I_FatalError ("The game is full.");
I_NetError("The game is full.");
}
else if (packet.Message == PRE_IN_PROGRESS)
{
I_NetError("The game was already started.");
}
}
}
@ -850,7 +871,7 @@ bool Guest_WaitForOthers (void *userdata)
return true;
case PRE_DISCONNECT:
I_FatalError ("The host cancelled the game.");
I_NetError("The host cancelled the game.");
break;
}
}
@ -875,6 +896,7 @@ bool JoinGame (int i)
BuildAddress (&sendaddress[1], Args->GetArg(i+1));
sendplayer[1] = 0;
doomcom.numnodes = 2;
doomcom.consoleplayer = -1;
// Let host know we are here
@ -1046,6 +1068,13 @@ void I_NetMessage(const char* text, ...)
#endif
}
void I_NetError(const char* error)
{
doomcom.numnodes = 0;
StartWindow->NetClose();
I_FatalError(error);
}
// todo: later these must be dispatched by the main menu, not the start screen.
void I_NetProgress(int val)
{

View file

@ -7,6 +7,7 @@
int I_InitNetwork (void);
void I_NetCmd (void);
void I_NetMessage(const char*, ...);
void I_NetError(const char* error);
void I_NetProgress(int val);
void I_NetInit(const char* msg, int num);
bool I_NetLoop(bool (*timer_callback)(void*), void* userdata);

View file

@ -83,7 +83,7 @@ FRandom pr_exrandom("EX_Random");
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FRandom M_Random;
FCRandom M_Random;
// Global seed. This is modified predictably to initialize every RNG.
uint32_t rngseed;
@ -126,8 +126,8 @@ CCMD(rngseed)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
FRandom *FRandom::RNGList;
static TDeletingArray<FRandom *> NewRNGs;
FRandom *FRandom::RNGList, *FRandom::CRNGList;
static TDeletingArray<FRandom *> NewRNGs, NewCRNGs;
// CODE --------------------------------------------------------------------
@ -139,14 +139,22 @@ static TDeletingArray<FRandom *> NewRNGs;
//
//==========================================================================
FRandom::FRandom ()
: NameCRC (0)
FRandom::FRandom (bool client)
: NameCRC (0), bClient(client)
{
#ifndef NDEBUG
Name = NULL;
#endif
Next = RNGList;
RNGList = this;
if (bClient)
{
Next = CRNGList;
CRNGList = this;
}
else
{
Next = RNGList;
RNGList = this;
}
Init(0);
}
@ -158,7 +166,7 @@ FRandom::FRandom ()
//
//==========================================================================
FRandom::FRandom (const char *name)
FRandom::FRandom (const char *name, bool client) : bClient(client)
{
NameCRC = CalcCRC32 ((const uint8_t *)name, (unsigned int)strlen (name));
#ifndef NDEBUG
@ -170,7 +178,7 @@ FRandom::FRandom (const char *name)
#endif
// Insert the RNG in the list, sorted by CRC
FRandom **prev = &RNGList, *probe = RNGList;
FRandom **prev = (bClient ? &CRNGList : &RNGList), * probe = (bClient ? CRNGList : RNGList);
while (probe != NULL && probe->NameCRC < NameCRC)
{
@ -205,8 +213,8 @@ FRandom::~FRandom ()
FRandom *last = NULL;
prev = &RNGList;
rng = RNGList;
prev = bClient ? &CRNGList : &RNGList;
rng = bClient ? CRNGList : RNGList;
while (rng != NULL && rng != this)
{
@ -237,6 +245,11 @@ void FRandom::StaticClearRandom ()
{
rng->Init(rngseed);
}
for (FRandom* rng = FRandom::CRNGList; rng != NULL; rng = rng->Next)
{
rng->Init(rngseed);
}
}
//==========================================================================
@ -345,15 +358,15 @@ void FRandom::StaticReadRNGState(FSerializer &arc)
//
//==========================================================================
FRandom *FRandom::StaticFindRNG (const char *name)
FRandom *FRandom::StaticFindRNG (const char *name, bool client)
{
uint32_t NameCRC = CalcCRC32 ((const uint8_t *)name, (unsigned int)strlen (name));
// Use the default RNG if this one happens to have a CRC of 0.
if (NameCRC == 0) return &pr_exrandom;
if (NameCRC == 0) return client ? &M_Random : &pr_exrandom;
// Find the RNG in the list, sorted by CRC
FRandom **prev = &RNGList, *probe = RNGList;
FRandom **prev = (client ? &CRNGList : &RNGList), *probe = (client ? CRNGList : RNGList);
while (probe != NULL && probe->NameCRC < NameCRC)
{
@ -364,14 +377,32 @@ FRandom *FRandom::StaticFindRNG (const char *name)
if (probe == NULL || probe->NameCRC != NameCRC)
{
// A matching RNG doesn't exist yet so create it.
probe = new FRandom(name);
probe = new FRandom(name, client);
// Store the new RNG for destruction when ZDoom quits.
NewRNGs.Push(probe);
if (client)
NewCRNGs.Push(probe);
else
NewRNGs.Push(probe);
}
return probe;
}
void FRandom::SaveRNGState(TArray<FRandom>& backups)
{
for (auto cur = RNGList; cur != nullptr; cur = cur->Next)
backups.Push(*cur);
}
void FRandom::RestoreRNGState(TArray<FRandom>& backups)
{
unsigned int i = 0u;
for (auto cur = RNGList; cur != nullptr; cur = cur->Next)
*cur = backups[i++];
backups.Clear();
}
//==========================================================================
//
// FRandom :: StaticPrintSeeds

View file

@ -44,9 +44,9 @@ class FSerializer;
class FRandom : public SFMTObj
{
public:
FRandom ();
FRandom (const char *name);
~FRandom ();
FRandom() : FRandom(false) {}
FRandom(const char* name) : FRandom(name, false) {}
~FRandom();
int Seed() const
{
@ -170,20 +170,34 @@ public:
static void StaticClearRandom ();
static void StaticReadRNGState (FSerializer &arc);
static void StaticWriteRNGState (FSerializer &file);
static FRandom *StaticFindRNG(const char *name);
static FRandom *StaticFindRNG(const char *name, bool client);
static void SaveRNGState(TArray<FRandom>& backups);
static void RestoreRNGState(TArray<FRandom>& backups);
#ifndef NDEBUG
static void StaticPrintSeeds ();
#endif
protected:
FRandom(bool client);
FRandom(const char* name, bool client);
private:
#ifndef NDEBUG
const char *Name;
#endif
FRandom *Next;
uint32_t NameCRC;
bool bClient;
static FRandom *RNGList;
static FRandom *RNGList, *CRNGList;
};
class FCRandom : public FRandom
{
public:
FCRandom() : FRandom(true) {}
FCRandom(const char* name) : FRandom(name, true) {}
};
extern uint32_t rngseed; // The starting seed (not part of state)
@ -193,6 +207,6 @@ extern bool use_staticrng;
// M_Random can be used for numbers that do not affect gameplay
extern FRandom M_Random;
extern FCRandom M_Random;
#endif

View file

@ -41,6 +41,12 @@ xx(Random2)
xx(RandomPick)
xx(FRandomPick)
xx(SetRandomSeed)
xx(CRandom)
xx(CFRandom)
xx(CRandom2)
xx(CRandomPick)
xx(CFRandomPick)
xx(CSetRandomSeed)
xx(BuiltinRandomSeed)
xx(BuiltinNew)
xx(GetClass)

View file

@ -55,6 +55,7 @@ public:
virtual void NetInit(const char *message, int num_players) {}
virtual void NetProgress(int count) {}
virtual void NetDone() {}
virtual void NetClose() {}
virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata) { return false; }
virtual void AppendStatusLine(const char* status) {}
virtual void LoadingStatus(const char* message, int colors) {}
@ -74,6 +75,7 @@ public:
void NetProgress(int count);
void NetMessage(const char* format, ...); // cover for printf
void NetDone();
void NetClose();
bool NetLoop(bool (*timer_callback)(void*), void* userdata);
protected:
int NetMaxPos, NetCurPos;

View file

@ -66,6 +66,7 @@ public:
void NetInit(const char* message, int playerCount);
void NetProgress(int count);
void NetDone();
void NetClose();
private:
NSWindow* m_window;

View file

@ -531,3 +531,8 @@ void FConsoleWindow::NetDone()
m_netAbortButton = nil;
}
}
void FConsoleWindow::NetClose()
{
// TODO: Implement this
}

View file

@ -110,6 +110,11 @@ void FBasicStartupScreen::NetDone()
FConsoleWindow::GetInstance().NetDone();
}
void FBasicStartupScreen::NetClose()
{
FConsoleWindow::GetInstance().NetClose();
}
bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData)
{
while (true)

View file

@ -57,6 +57,7 @@ class FTTYStartupScreen : public FStartupScreen
void NetInit(const char *message, int num_players);
void NetProgress(int count);
void NetDone();
void NetClose();
bool NetLoop(bool (*timer_callback)(void *), void *userdata);
protected:
bool DidNetInit;
@ -237,6 +238,11 @@ void FTTYStartupScreen::NetProgress(int count)
}
}
void FTTYStartupScreen::NetClose()
{
// TODO: Implement this
}
//===========================================================================
//
// FTTYStartupScreen :: NetLoop

View file

@ -201,3 +201,8 @@ bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata
{
return NetStartWindow::RunMessageLoop(timer_callback, userdata);
}
void FBasicStartupScreen::NetClose()
{
NetStartWindow::CloseNetStartPane();
}

View file

@ -8268,8 +8268,12 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos)
: FxExpression(EFX_FunctionCall, pos)
{
const bool isClient = methodname == NAME_CRandom || methodname == NAME_CFRandom
|| methodname == NAME_CRandomPick || methodname == NAME_CFRandomPick
|| methodname == NAME_CRandom2 || methodname == NAME_CSetRandomSeed;
MethodName = methodname;
RNG = &pr_exrandom;
RNG = isClient ? &M_Random : &pr_exrandom;
ArgList = std::move(args);
if (rngname != NAME_None)
{
@ -8281,7 +8285,16 @@ FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&
case NAME_FRandomPick:
case NAME_Random2:
case NAME_SetRandomSeed:
RNG = FRandom::StaticFindRNG(rngname.GetChars());
RNG = FRandom::StaticFindRNG(rngname.GetChars(), false);
break;
case NAME_CRandom:
case NAME_CFRandom:
case NAME_CRandomPick:
case NAME_CFRandomPick:
case NAME_CRandom2:
case NAME_CSetRandomSeed:
RNG = FRandom::StaticFindRNG(rngname.GetChars(), true);
break;
default:
@ -8547,13 +8560,22 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
break;
case NAME_CSetRandomSeed:
if (CheckArgSize(NAME_CRandom, ArgList, 1, 1, ScriptPosition))
{
func = new FxRandomSeed(RNG, ArgList[0], ScriptPosition, ctx.FromDecorate);
ArgList[0] = nullptr;
}
break;
case NAME_Random:
case NAME_CRandom:
// allow calling Random without arguments to default to (0, 255)
if (ArgList.Size() == 0)
{
func = new FxRandom(RNG, new FxConstant(0, ScriptPosition), new FxConstant(255, ScriptPosition), ScriptPosition, ctx.FromDecorate);
}
else if (CheckArgSize(NAME_Random, ArgList, 2, 2, ScriptPosition))
else if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition))
{
func = new FxRandom(RNG, ArgList[0], ArgList[1], ScriptPosition, ctx.FromDecorate);
ArgList[0] = ArgList[1] = nullptr;
@ -8561,7 +8583,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
break;
case NAME_FRandom:
if (CheckArgSize(NAME_FRandom, ArgList, 2, 2, ScriptPosition))
case NAME_CFRandom:
if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition))
{
func = new FxFRandom(RNG, ArgList[0], ArgList[1], ScriptPosition);
ArgList[0] = ArgList[1] = nullptr;
@ -8570,14 +8593,17 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
case NAME_RandomPick:
case NAME_FRandomPick:
case NAME_CRandomPick:
case NAME_CFRandomPick:
if (CheckArgSize(MethodName, ArgList, 1, -1, ScriptPosition))
{
func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate);
func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick || MethodName == NAME_CFRandomPick, ScriptPosition, ctx.FromDecorate);
}
break;
case NAME_Random2:
if (CheckArgSize(NAME_Random2, ArgList, 0, 1, ScriptPosition))
case NAME_CRandom2:
if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition))
{
func = new FxRandom2(RNG, ArgList.Size() == 0? nullptr : ArgList[0], ScriptPosition, ctx.FromDecorate);
if (ArgList.Size() > 0) ArgList[0] = nullptr;

View file

@ -31,6 +31,11 @@ void NetStartWindow::HideNetStartPane()
Instance = nullptr;
}
void NetStartWindow::CloseNetStartPane()
{
NetStartWindow::NetClose();
}
void NetStartWindow::SetNetStartProgress(int pos)
{
if (Instance)
@ -64,6 +69,12 @@ bool NetStartWindow::RunMessageLoop(bool (*newtimer_callback)(void*), void* newu
return Instance->exitreason;
}
void NetStartWindow::NetClose()
{
if (Instance != nullptr)
Instance->OnClose();
}
NetStartWindow::NetStartWindow() : Widget(nullptr, WidgetType::Window)
{
SetWindowBackground(Colorf::fromRgba8(51, 51, 51));

View file

@ -12,8 +12,10 @@ class NetStartWindow : public Widget
public:
static void ShowNetStartPane(const char* message, int maxpos);
static void HideNetStartPane();
static void CloseNetStartPane();
static void SetNetStartProgress(int pos);
static bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata);
static void NetClose();
private:
NetStartWindow();

View file

@ -199,7 +199,7 @@ public:
void ClearDynamic3DFloorData();
void WorldDone(void);
void AirControlChanged();
AActor *SelectTeleDest(int tid, int tag, bool norandom);
AActor *SelectTeleDest(int tid, int tag, bool norandom, bool isPlayer);
bool AlignFlat(int linenum, int side, int fc);
void ReplaceTextures(const char *fromname, const char *toname, int flags);

View file

@ -3225,9 +3225,9 @@ class CommandDrawGem : public SBarInfoCommand
int goalValue;
private:
int chainWiggle;
static FRandom pr_chainwiggle;
static FCRandom pr_chainwiggle;
};
FRandom CommandDrawGem::pr_chainwiggle; //use the same method of chain wiggling as heretic.
FCRandom CommandDrawGem::pr_chainwiggle; //use the same method of chain wiggling as heretic.
////////////////////////////////////////////////////////////////////////////////

View file

@ -60,8 +60,8 @@ static TArray<uint8_t> DecalTranslations;
// Sometimes two machines in a game will disagree on the state of
// decals. I do not know why.
static FRandom pr_decalchoice ("DecalChoice");
static FRandom pr_decal ("Decal");
static FCRandom pr_decalchoice ("DecalChoice");
static FCRandom pr_decal ("Decal");
class FDecalGroup : public FDecalBase
{

View file

@ -56,7 +56,7 @@ FTextureAnimator TexAnim;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FRandom pr_animatepictures ("AnimatePics");
static FCRandom pr_animatepictures ("AnimatePics");
// CODE --------------------------------------------------------------------

View file

@ -62,7 +62,7 @@
#include "doommenu.h"
#include "g_game.h"
static FRandom pr_randomspeech("RandomSpeech");
static FCRandom pr_randomspeech("RandomSpeech");
static int ConversationMenuY;

View file

@ -67,7 +67,7 @@
static FMemArena DynLightArena(sizeof(FDynamicLight) * 200);
static TArray<FDynamicLight*> FreeList;
static FRandom randLight;
static FCRandom randLight;
extern TArray<FLightDefaults *> StateLights;

View file

@ -43,10 +43,10 @@
// State.
#include "serializer.h"
static FRandom pr_flicker ("Flicker");
static FRandom pr_lightflash ("LightFlash");
static FRandom pr_strobeflash ("StrobeFlash");
static FRandom pr_fireflicker ("FireFlicker");
static FCRandom pr_flicker ("Flicker");
static FCRandom pr_lightflash ("LightFlash");
static FCRandom pr_strobeflash ("StrobeFlash");
static FCRandom pr_fireflicker ("FireFlicker");
//-----------------------------------------------------------------------------

View file

@ -36,7 +36,7 @@
#include "actorinlines.h"
#include <p_maputl.h>
static FRandom pr_quake ("Quake");
static FCRandom pr_quake ("Quake");
IMPLEMENT_CLASS(DEarthquake, false, true)

View file

@ -65,7 +65,7 @@ CVAR (Int, r_rail_trailsparsity, 1, CVAR_ARCHIVE);
CVAR (Bool, r_particles, true, 0);
EXTERN_CVAR(Int, r_maxparticles);
FRandom pr_railtrail("RailTrail");
FCRandom pr_railtrail("RailTrail");
#define FADEFROMTTL(a) (1.f/(a))

View file

@ -121,13 +121,20 @@ TArray<spechit_t> portalhit;
//
//==========================================================================
bool P_ShouldPassThroughPlayer(AActor *self, AActor *other)
static int P_ShouldPassThroughPlayer(AActor *self, AActor *other)
{
return (dmflags3 & DF3_NO_PLAYER_CLIP) &&
other->player && other->player->mo == other &&
self->IsFriend(other);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, ShouldPassThroughPlayer, P_ShouldPassThroughPlayer)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_BOOL(P_ShouldPassThroughPlayer(self, other));
}
//==========================================================================
//
// CanCollideWith

View file

@ -49,7 +49,7 @@
#include "actorinlines.h"
#include "animations.h"
static FRandom pr_switchanim ("AnimSwitch");
static FCRandom pr_switchanim ("AnimSwitch");
class DActiveButton : public DThinker
{

View file

@ -37,6 +37,7 @@
#define FUDGEFACTOR 10
static FRandom pr_teleport ("Teleport");
static FRandom pr_playerteleport("PlayerTeleport");
CVAR (Bool, telezoom, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
@ -271,7 +272,7 @@ DEFINE_ACTION_FUNCTION(AActor, Teleport)
//
//-----------------------------------------------------------------------------
AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom)
AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom, bool isPlayer)
{
AActor *searcher;
@ -323,7 +324,8 @@ AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom)
{
if (count != 1 && !norandom)
{
count = 1 + (pr_teleport() % count);
// Players get their own RNG seed to reduce likelihood of breaking prediction.
count = 1 + ((isPlayer ? pr_playerteleport() : pr_teleport()) % count);
}
searcher = NULL;
while (count > 0)
@ -394,7 +396,7 @@ bool FLevelLocals::EV_Teleport (int tid, int tag, line_t *line, int side, AActor
{ // Don't teleport if hit back of line, so you can get out of teleporter.
return 0;
}
searcher = SelectTeleDest(tid, tag, predicting);
searcher = SelectTeleDest(tid, tag, false, thing->player != nullptr && thing->player->mo == thing);
if (searcher == NULL)
{
return false;

View file

@ -144,6 +144,8 @@ static DVector3 LastPredictedPosition;
static int LastPredictedPortalGroup;
static int LastPredictedTic;
static TArray<FRandom> PredictionRNG;
static player_t PredictionPlayerBackup;
static AActor *PredictionActor;
static TArray<uint8_t> PredictionActorBackupArray;
@ -1461,6 +1463,8 @@ void P_PredictPlayer (player_t *player)
return;
}
FRandom::SaveRNGState(PredictionRNG);
// Save original values for restoration later
PredictionPlayerBackup.CopyFrom(*player, false);
@ -1600,6 +1604,8 @@ void P_UnPredictPlayer ()
// Q: Can this happen? If yes, can we continue?
}
FRandom::RestoreRNGState(PredictionRNG);
AActor *savedcamera = player->camera;
auto &actInvSel = act->PointerVar<AActor*>(NAME_InvSel);

View file

@ -94,8 +94,8 @@ struct InterpolationViewer
// PRIVATE DATA DECLARATIONS -----------------------------------------------
static TArray<InterpolationViewer> PastViewers;
static FRandom pr_torchflicker ("TorchFlicker");
static FRandom pr_hom;
static FCRandom pr_torchflicker ("TorchFlicker");
static FCRandom pr_hom;
bool NoInterpolateView; // GL needs access to this.
static TArray<DVector3a> InterpolationPath;

View file

@ -47,9 +47,9 @@
extern FRandom pr_exrandom;
static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls);
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls);
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls, bool client);
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls, bool client);
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls, bool client);
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls);
static FxExpression *ParseAtan2(FScanner &sc, FName identifier, PClassActor *cls);
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls);
@ -491,12 +491,17 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
{
case NAME_Random:
case NAME_FRandom:
return ParseRandom(sc, identifier, cls);
case NAME_CRandom:
case NAME_CFRandom:
return ParseRandom(sc, identifier, cls, identifier == NAME_CRandom || identifier == NAME_CFRandom);
case NAME_RandomPick:
case NAME_FRandomPick:
return ParseRandomPick(sc, identifier, cls);
case NAME_CRandomPick:
case NAME_CFRandomPick:
return ParseRandomPick(sc, identifier, cls, identifier == NAME_CRandomPick || identifier == NAME_CFRandomPick);
case NAME_Random2:
return ParseRandom2(sc, cls);
case NAME_CRandom2:
return ParseRandom2(sc, cls, identifier == NAME_CRandom2);
default:
if (cls != nullptr)
{
@ -559,26 +564,26 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
return NULL;
}
static FRandom *ParseRNG(FScanner &sc)
static FRandom *ParseRNG(FScanner &sc, bool client)
{
FRandom *rng;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
rng = FRandom::StaticFindRNG(sc.String, client);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
rng = client ? &M_Random : &pr_exrandom;
}
return rng;
}
static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls)
static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cls, bool client)
{
FRandom *rng = ParseRNG(sc);
FRandom *rng = ParseRNG(sc, client);
sc.MustGetToken('(');
FxExpression *min = ParseExpressionM (sc, cls);
@ -586,7 +591,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl
FxExpression *max = ParseExpressionM (sc, cls);
sc.MustGetToken(')');
if (identifier == NAME_Random)
if (identifier == NAME_Random || identifier == NAME_CRandom)
{
return new FxRandom(rng, min, max, sc, true);
}
@ -596,7 +601,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl
}
}
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls)
static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor *cls, bool client)
{
bool floaty = identifier == NAME_FRandomPick;
FRandom *rng;
@ -604,7 +609,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
list.Clear();
int index = 0;
rng = ParseRNG(sc);
rng = ParseRNG(sc, client);
sc.MustGetToken('(');
for (;;)
@ -618,9 +623,9 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
return new FxRandomPick(rng, list, floaty, sc, true);
}
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls)
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls, bool client)
{
FRandom *rng = ParseRNG(sc);
FRandom *rng = ParseRNG(sc, client);
FxExpression *mask = NULL;
sc.MustGetToken('(');

View file

@ -1163,7 +1163,7 @@ TArray<uint8_t> DoomSoundEngine::ReadSound(int lumpnum)
// This is overridden to use a synchronized RNG.
//
//==========================================================================
static FRandom pr_randsound("RandSound");
static FCRandom pr_randsound("RandSound");
FSoundID DoomSoundEngine::PickReplacement(FSoundID refid)
{

View file

@ -288,7 +288,7 @@ static const hexenseq_t HexenSequences[] = {
static int SeqTrans[MAX_SNDSEQS*3];
static FRandom pr_sndseq ("SndSeq");
static FCRandom pr_sndseq ("SndSeq");
// CODE --------------------------------------------------------------------

View file

@ -844,6 +844,7 @@ class Actor : Thinker native
native void Thrust(double speed = 1e37, double angle = 1e37);
native clearscope bool isFriend(Actor other) const;
native clearscope bool isHostile(Actor other) const;
native clearscope bool ShouldPassThroughPlayer(Actor other) const;
native void AdjustFloorClip();
native clearscope DropItem GetDropItems() const;
native void CopyFriendliness (Actor other, bool changeTarget, bool resetHealth = true);

View file

@ -139,6 +139,11 @@ extend class Actor
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
if (player && ShouldPassThroughPlayer(mo))
{
// Don't blast friendly players if collision is disabled.
continue;
}
if (Distance2D(mo) > radius)
{ // Out of range
continue;

View file

@ -59,6 +59,13 @@ class WeaponPiece : Inventory
property number: PieceValue;
property weapon: WeaponClass;
// Account for weapon replacers, but make sure it's still a Weapon
clearscope class<Weapon> GetWeaponClass() const
{
class<Weapon> type = WeaponClass ? (class<Weapon>)(GetReplacement(WeaponClass)) : null;
return type ? type : WeaponClass;
}
//==========================================================================
//
@ -74,7 +81,11 @@ class WeaponPiece : Inventory
return false;
}
let Defaults = GetDefaultByType(WeaponClass);
class<Weapon> type = GetWeaponClass();
if (!type)
return false;
let Defaults = GetDefaultByType(type);
bool gaveSome = !!(toucher.GiveAmmo (Defaults.AmmoType1, Defaults.AmmoGive1) +
toucher.GiveAmmo (Defaults.AmmoType2, Defaults.AmmoGive2));
@ -94,11 +105,15 @@ class WeaponPiece : Inventory
override bool TryPickup (in out Actor toucher)
{
class<Weapon> type = GetWeaponClass();
if (!type)
return false;
Inventory item;
WeaponHolder hold = NULL;
bool shouldStay = ShouldStay ();
int gaveAmmo;
let Defaults = GetDefaultByType(WeaponClass);
let Defaults = GetDefaultByType(type);
FullWeapon = NULL;
for(item=toucher.Inv; item; item=item.Inv)
@ -106,6 +121,7 @@ class WeaponPiece : Inventory
hold = WeaponHolder(item);
if (hold != null)
{
// Intentionally check against the unreplaced class
if (hold.PieceWeapon == WeaponClass)
{
break;
@ -153,9 +169,9 @@ class WeaponPiece : Inventory
// Check if weapon assembled
if (hold.PieceMask == (1 << Defaults.health) - 1)
{
if (!toucher.FindInventory (WeaponClass))
if (!toucher.FindInventory (type))
{
FullWeapon= Weapon(Spawn(WeaponClass));
FullWeapon= Weapon(Spawn(type));
// The weapon itself should not give more ammo to the player.
FullWeapon.AmmoGive1 = 0;

View file

@ -788,7 +788,9 @@ class Object native
//
// Intrinsic random number generation functions. Note that the square
// bracket syntax for specifying an RNG ID is only available for these
// functions.
// functions. If the function is prefixed with a C, this is a client-side RNG
// call that isn't backed up while predicting and has a unique name space from
// regular RNG calls. This should be used for things like HUD elements.
// clearscope void SetRandomSeed[Name rngId = 'None'](int seed); // Set the seed for the given RNG.
// clearscope int Random[Name rngId = 'None'](int min, int max); // Use the given RNG to generate a random integer number in the range (min, max) inclusive.
// clearscope int Random2[Name rngId = 'None'](int mask); // Use the given RNG to generate a random integer number, and do a "union" (bitwise AND, AKA &) operation with the bits in the mask integer.

View file

@ -216,11 +216,11 @@ class ConversationMenu : Menu
let goodbyestr = mCurNode.Goodbye;
if (goodbyestr.Length() == 0)
{
goodbyestr = String.Format("$TXT_RANDOMGOODBYE_%d", Random[RandomSpeech](1, NUM_RANDOM_GOODBYES));
goodbyestr = String.Format("$TXT_RANDOMGOODBYE_%d", CRandom[RandomSpeech](1, NUM_RANDOM_GOODBYES));
}
else if (goodbyestr.Left(7) == "RANDOM_")
{
goodbyestr = String.Format("$TXT_%s_%02d", goodbyestr, Random[RandomSpeech](1, NUM_RANDOM_LINES));
goodbyestr = String.Format("$TXT_%s_%02d", goodbyestr, CRandom[RandomSpeech](1, NUM_RANDOM_LINES));
}
goodbyestr = Stringtable.Localize(goodbyestr);
if (goodbyestr.Length() == 0 || goodbyestr.Left(1) == "$") goodbyestr = "Bye.";
@ -254,7 +254,7 @@ class ConversationMenu : Menu
String toSay = mCurNode.Dialogue;
if (toSay.Left(7) == "RANDOM_")
{
let dlgtext = String.Format("$TXT_%s_%02d", toSay, random[RandomSpeech](1, NUM_RANDOM_LINES));
let dlgtext = String.Format("$TXT_%s_%02d", toSay, crandom[RandomSpeech](1, NUM_RANDOM_LINES));
toSay = Stringtable.Localize(dlgtext);
if (toSay.Left(1) == "$") toSay = Stringtable.Localize("$TXT_GOAWAY");
}

View file

@ -45,7 +45,7 @@ class HereticStatusBar : BaseStatusBar
// wiggle the chain if it moves
if (Level.time & 1)
{
wiggle = (mHealthInterpolator.GetValue() != CPlayer.health) && Random[ChainWiggle](0, 1);
wiggle = (mHealthInterpolator.GetValue() != CPlayer.health) && CRandom[ChainWiggle](0, 1);
}
}