Merge branch 'master' of https://github.com/ZDoom/gzdoom into gzd-master-experimental
This commit is contained in:
commit
2e09abc4e8
39 changed files with 279 additions and 91 deletions
|
|
@ -169,7 +169,7 @@ static const char *TelefragSounds[] =
|
|||
#endif
|
||||
|
||||
static int LastAnnounceTime;
|
||||
static FRandom pr_bbannounce ("BBAnnounce");
|
||||
static FCRandom pr_bbannounce ("BBAnnounce");
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ enum
|
|||
{
|
||||
DEFAULT_PITCH = 128,
|
||||
};
|
||||
static FRandom pr_soundpitch ("SoundPitch");
|
||||
static FCRandom pr_soundpitch ("SoundPitch");
|
||||
SoundEngine* soundEngine;
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public:
|
|||
void NetInit(const char* message, int playerCount);
|
||||
void NetProgress(int count);
|
||||
void NetDone();
|
||||
void NetClose();
|
||||
|
||||
private:
|
||||
NSWindow* m_window;
|
||||
|
|
|
|||
|
|
@ -531,3 +531,8 @@ void FConsoleWindow::NetDone()
|
|||
m_netAbortButton = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void FConsoleWindow::NetClose()
|
||||
{
|
||||
// TODO: Implement this
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -201,3 +201,8 @@ bool FBasicStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata
|
|||
{
|
||||
return NetStartWindow::RunMessageLoop(timer_callback, userdata);
|
||||
}
|
||||
|
||||
void FBasicStartupScreen::NetClose()
|
||||
{
|
||||
NetStartWindow::CloseNetStartPane();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ FTextureAnimator TexAnim;
|
|||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static FRandom pr_animatepictures ("AnimatePics");
|
||||
static FCRandom pr_animatepictures ("AnimatePics");
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
#include "doommenu.h"
|
||||
#include "g_game.h"
|
||||
|
||||
static FRandom pr_randomspeech("RandomSpeech");
|
||||
static FCRandom pr_randomspeech("RandomSpeech");
|
||||
|
||||
static int ConversationMenuY;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
|
||||
static FMemArena DynLightArena(sizeof(FDynamicLight) * 200);
|
||||
static TArray<FDynamicLight*> FreeList;
|
||||
static FRandom randLight;
|
||||
static FCRandom randLight;
|
||||
|
||||
extern TArray<FLightDefaults *> StateLights;
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
#include "actorinlines.h"
|
||||
#include "animations.h"
|
||||
|
||||
static FRandom pr_switchanim ("AnimSwitch");
|
||||
static FCRandom pr_switchanim ("AnimSwitch");
|
||||
|
||||
class DActiveButton : public DThinker
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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('(');
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 --------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue