mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-03-19 08:21:40 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
This commit is contained in:
commit
3bd6a94749
67 changed files with 1680 additions and 403 deletions
|
@ -992,6 +992,7 @@ set (PCH_SOURCES
|
|||
scripting/thingdef_data.cpp
|
||||
scripting/thingdef_properties.cpp
|
||||
scripting/backend/codegen.cpp
|
||||
scripting/backend/scopebarrier.cpp
|
||||
scripting/backend/dynarrays.cpp
|
||||
scripting/backend/vmbuilder.cpp
|
||||
scripting/backend/vmdisasm.cpp
|
||||
|
|
|
@ -644,8 +644,12 @@ bool FConfigFile::ReadConfig (void *file)
|
|||
continue;
|
||||
}
|
||||
// Do not process tail of long line
|
||||
const bool longline = 255 == strlen(readbuf) && '\n' != readbuf[254];
|
||||
if (!longline)
|
||||
const bool longline = (READBUFFERSIZE - 1) == strlen(readbuf) && '\n' != readbuf[READBUFFERSIZE - 2];
|
||||
if (longline)
|
||||
{
|
||||
endpt = start + READBUFFERSIZE - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove white space at end of line
|
||||
endpt = start + strlen (start) - 1;
|
||||
|
|
|
@ -207,7 +207,9 @@ enum EObjectFlags
|
|||
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
||||
OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning)
|
||||
OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function
|
||||
OF_Abstract = 1 << 14, // Marks a class that cannot be created with CreateNew
|
||||
OF_Abstract = 1 << 14, // Marks a class that cannot be created with new() function at all
|
||||
OF_UI = 1 << 15, // Marks a class that defaults to VARF_UI for it's fields/methods
|
||||
OF_Play = 1 << 16, // Marks a class that defaults to VARF_Play for it's fields/methods
|
||||
};
|
||||
|
||||
template<class T> class TObjPtr;
|
||||
|
|
|
@ -1316,6 +1316,7 @@ PPointer::PPointer(PType *pointsat, bool isconst)
|
|||
: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst)
|
||||
{
|
||||
mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : "");
|
||||
mVersion = pointsat->mVersion;
|
||||
SetOps();
|
||||
}
|
||||
|
||||
|
@ -1396,6 +1397,10 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con
|
|||
ar(key, *(DObject **)addr);
|
||||
}
|
||||
}
|
||||
else if (writer != nullptr)
|
||||
{
|
||||
writer(ar, key, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName());
|
||||
|
@ -1425,6 +1430,10 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
|||
}
|
||||
return res;
|
||||
}
|
||||
else if (reader != nullptr)
|
||||
{
|
||||
return reader(ar, key, addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1510,6 +1519,7 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
// This means we can use the cheapoer non-barriered opcodes here.
|
||||
loadOp = OP_LOS;
|
||||
storeOp = OP_SP;
|
||||
mVersion = restrict->mVersion;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -2514,6 +2524,14 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue
|
|||
else BitValue = -1;
|
||||
}
|
||||
|
||||
VersionInfo PField::GetVersion()
|
||||
{
|
||||
VersionInfo Highest = { 0,0,0 };
|
||||
if (!(Flags & VARF_Deprecated)) Highest = mVersion;
|
||||
if (Type->mVersion > Highest) Highest = Type->mVersion;
|
||||
return Highest;
|
||||
}
|
||||
|
||||
/* PProperty *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PProperty, false, false)
|
||||
|
@ -3138,6 +3156,9 @@ void PClass::Derive(PClass *newclass, FName name)
|
|||
newclass->Symbols.SetParentTable(&this->Symbols);
|
||||
newclass->TypeName = name;
|
||||
newclass->mDescriptiveName.Format("Class<%s>", name.GetChars());
|
||||
newclass->mVersion = mVersion;
|
||||
newclass->MetaSize = MetaSize;
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3284,7 +3305,6 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
type->bRuntimeClass = true;
|
||||
Derive(type, name);
|
||||
type->Size = size;
|
||||
type->MetaSize = MetaSize;
|
||||
if (size != TentativeClass)
|
||||
{
|
||||
type->InitializeDefaults();
|
||||
|
|
|
@ -37,6 +37,10 @@ enum
|
|||
VARF_Transient = (1<<17), // don't auto serialize field.
|
||||
VARF_Meta = (1<<18), // static class data (by necessity read only.)
|
||||
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
||||
VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim)
|
||||
VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui)
|
||||
VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only)
|
||||
VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data.
|
||||
};
|
||||
|
||||
// An action function -------------------------------------------------------
|
||||
|
@ -87,6 +91,7 @@ public:
|
|||
PSymbolTable Symbols;
|
||||
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
|
||||
FString mDescriptiveName;
|
||||
VersionInfo mVersion = { 0,0,0 };
|
||||
BYTE loadOp, storeOp, moveOp, RegType, RegCount;
|
||||
|
||||
PType(unsigned int size = 1, unsigned int align = 1);
|
||||
|
@ -362,13 +367,26 @@ public:
|
|||
class PPointer : public PBasicType
|
||||
{
|
||||
DECLARE_CLASS(PPointer, PBasicType);
|
||||
|
||||
public:
|
||||
typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr);
|
||||
typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr);
|
||||
|
||||
PPointer();
|
||||
PPointer(PType *pointsat, bool isconst = false);
|
||||
|
||||
PType *PointedType;
|
||||
bool IsConst;
|
||||
|
||||
WriteHandler writer = nullptr;
|
||||
ReadHandler reader = nullptr;
|
||||
|
||||
void InstallHandlers(WriteHandler w, ReadHandler r)
|
||||
{
|
||||
writer = w;
|
||||
reader = r;
|
||||
}
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) const override;
|
||||
|
|
|
@ -194,6 +194,38 @@ public:
|
|||
};
|
||||
|
||||
|
||||
struct VersionInfo
|
||||
{
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint32_t revision;
|
||||
|
||||
bool operator <=(const VersionInfo &o) const
|
||||
{
|
||||
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision >= this->revision);
|
||||
}
|
||||
bool operator >=(const VersionInfo &o) const
|
||||
{
|
||||
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision <= this->revision);
|
||||
}
|
||||
bool operator > (const VersionInfo &o) const
|
||||
{
|
||||
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision < this->revision);
|
||||
}
|
||||
bool operator < (const VersionInfo &o) const
|
||||
{
|
||||
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision > this->revision);
|
||||
}
|
||||
void operator=(const char *string);
|
||||
};
|
||||
|
||||
// Cannot be a constructor because Lemon would puke on it.
|
||||
inline VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0)
|
||||
{
|
||||
return{ (uint16_t)ma, (uint16_t)mi, (uint32_t)re };
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Screenshot buffer image data types
|
||||
enum ESSType
|
||||
|
|
|
@ -117,6 +117,21 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3)
|
||||
{
|
||||
if (gamestate != GS_LEVEL)
|
||||
return false;
|
||||
|
||||
Net_WriteByte(DEM_NETEVENT);
|
||||
Net_WriteString(name);
|
||||
Net_WriteByte(3);
|
||||
Net_WriteLong(arg1);
|
||||
Net_WriteLong(arg2);
|
||||
Net_WriteLong(arg3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E_CheckHandler(DStaticEventHandler* handler)
|
||||
{
|
||||
for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next)
|
||||
|
@ -521,6 +536,18 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(name);
|
||||
PARAM_INT(arg1);
|
||||
PARAM_INT(arg2);
|
||||
PARAM_INT(arg3);
|
||||
//
|
||||
|
||||
ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DEventHandler, Create)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
|
@ -658,6 +685,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, UiProcess);
|
|||
DEFINE_EMPTY_HANDLER(DStaticEventHandler, InputProcess);
|
||||
|
||||
DEFINE_EMPTY_HANDLER(DStaticEventHandler, ConsoleProcess);
|
||||
DEFINE_EMPTY_HANDLER(DStaticEventHandler, NetworkProcess);
|
||||
|
||||
// ===========================================
|
||||
//
|
||||
|
@ -1068,22 +1096,45 @@ static DConsoleEvent* E_SetupConsoleEvent()
|
|||
|
||||
void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3)
|
||||
{
|
||||
IFVIRTUAL(DStaticEventHandler, ConsoleProcess)
|
||||
if (player < 0)
|
||||
{
|
||||
// don't create excessive DObjects if not going to be processed anyway
|
||||
if (func == DStaticEventHandler_ConsoleProcess_VMPtr)
|
||||
return;
|
||||
DConsoleEvent* e = E_SetupConsoleEvent();
|
||||
IFVIRTUAL(DStaticEventHandler, ConsoleProcess)
|
||||
{
|
||||
// don't create excessive DObjects if not going to be processed anyway
|
||||
if (func == DStaticEventHandler_ConsoleProcess_VMPtr)
|
||||
return;
|
||||
DConsoleEvent* e = E_SetupConsoleEvent();
|
||||
|
||||
//
|
||||
e->Player = player;
|
||||
e->Name = name;
|
||||
e->Args[0] = arg1;
|
||||
e->Args[1] = arg2;
|
||||
e->Args[2] = arg3;
|
||||
//
|
||||
e->Player = player;
|
||||
e->Name = name;
|
||||
e->Args[0] = arg1;
|
||||
e->Args[1] = arg2;
|
||||
e->Args[2] = arg3;
|
||||
|
||||
VMValue params[2] = { (DStaticEventHandler*)this, e };
|
||||
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
|
||||
VMValue params[2] = { (DStaticEventHandler*)this, e };
|
||||
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IFVIRTUAL(DStaticEventHandler, NetworkProcess)
|
||||
{
|
||||
// don't create excessive DObjects if not going to be processed anyway
|
||||
if (func == DStaticEventHandler_NetworkProcess_VMPtr)
|
||||
return;
|
||||
DConsoleEvent* e = E_SetupConsoleEvent();
|
||||
|
||||
//
|
||||
e->Player = player;
|
||||
e->Name = name;
|
||||
e->Args[0] = arg1;
|
||||
e->Args[1] = arg2;
|
||||
e->Args[2] = arg3;
|
||||
|
||||
VMValue params[2] = { (DStaticEventHandler*)this, e };
|
||||
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1136,10 +1187,6 @@ CCMD(netevent)
|
|||
for (int i = 0; i < argn; i++)
|
||||
arg[i] = atoi(argv[2 + i]);
|
||||
// call networked
|
||||
Net_WriteByte(DEM_NETEVENT);
|
||||
Net_WriteString(argv[1]);
|
||||
Net_WriteByte(argn);
|
||||
for (int i = 0; i < 3; i++)
|
||||
Net_WriteLong(arg[i]);
|
||||
E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,9 @@ bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess
|
|||
// this executes on console/net events.
|
||||
void E_Console(int player, FString name, int arg1, int arg2, int arg3);
|
||||
|
||||
// send networked event. unified function.
|
||||
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3);
|
||||
|
||||
// check if there is anything that should receive GUI events
|
||||
bool E_CheckUiProcessors();
|
||||
// check if we need native mouse due to UiProcessors
|
||||
|
|
|
@ -1351,7 +1351,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags)
|
|||
if (item->ItemFlags & IF_INVBAR && item->Amount > item->InterHubAmount)
|
||||
{
|
||||
item->Amount = item->InterHubAmount;
|
||||
if ((level.flags3 & LEVEL3_RESETINVENTORY) && !(item->ItemFlags & IF_UNDROPPABLE))
|
||||
if ((level.flags3 & LEVEL3_REMOVEITEMS) && !(item->ItemFlags & IF_UNDROPPABLE))
|
||||
{
|
||||
todelete.Push(item);
|
||||
}
|
||||
|
|
|
@ -1462,6 +1462,8 @@ void G_InitLevelLocals ()
|
|||
level.NextMap = info->NextMap;
|
||||
level.NextSecretMap = info->NextSecretMap;
|
||||
level.F1Pic = info->F1Pic;
|
||||
level.hazardcolor = info->hazardcolor;
|
||||
level.hazardflash = info->hazardflash;
|
||||
|
||||
compatflags.Callback();
|
||||
compatflags2.Callback();
|
||||
|
|
|
@ -223,7 +223,7 @@ enum ELevelFlags : unsigned int
|
|||
|
||||
// More flags!
|
||||
LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled
|
||||
LEVEL3_RESETINVENTORY = 0x00000002, // kills all INVBAR items on map change.
|
||||
LEVEL3_REMOVEITEMS = 0x00000002, // kills all INVBAR items on map change.
|
||||
};
|
||||
|
||||
|
||||
|
@ -315,6 +315,8 @@ struct level_info_t
|
|||
FName Intermission;
|
||||
FName deathsequence;
|
||||
FName slideshow;
|
||||
DWORD hazardcolor;
|
||||
DWORD hazardflash;
|
||||
|
||||
// Redirection: If any player is carrying the specified item, then
|
||||
// you go to the RedirectMap instead of this one.
|
||||
|
|
|
@ -43,6 +43,9 @@ struct FLevelLocals
|
|||
DWORD fadeto; // The color the palette fades to (usually black)
|
||||
DWORD outsidefog; // The fog for sectors with sky ceilings
|
||||
|
||||
DWORD hazardcolor; // what color strife hazard blends the screen color as
|
||||
DWORD hazardflash; // what color strife hazard flashes the screen color as
|
||||
|
||||
FString Music;
|
||||
int musicorder;
|
||||
int cdtrack;
|
||||
|
|
|
@ -273,6 +273,8 @@ void level_info_t::Reset()
|
|||
SndSeq = "";
|
||||
BorderTexture = "";
|
||||
teamdamage = 0.f;
|
||||
hazardcolor = 0xff004200;
|
||||
hazardflash = 0xff00ff00;
|
||||
specialactions.Clear();
|
||||
DefaultEnvironment = 0;
|
||||
PrecacheSounds.Clear();
|
||||
|
@ -1200,6 +1202,20 @@ DEFINE_MAP_OPTION(defaultenvironment, false)
|
|||
info->DefaultEnvironment = id;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(hazardcolor, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->hazardcolor = V_GetColor(NULL, parse.sc);
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(hazardflash, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->hazardflash = V_GetColor(NULL, parse.sc);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -1277,7 +1293,7 @@ MapFlagHandlers[] =
|
|||
{ "laxmonsteractivation", MITYPE_SETFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO },
|
||||
{ "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL, 0 },
|
||||
{ "keepfullinventory", MITYPE_SETFLAG2, LEVEL2_KEEPFULLINVENTORY, 0 },
|
||||
{ "resetitems", MITYPE_SETFLAG3, LEVEL2_RESETINVENTORY, 0 },
|
||||
{ "resetitems", MITYPE_SETFLAG3, LEVEL3_REMOVEITEMS, 0 },
|
||||
{ "monsterfallingdamage", MITYPE_SETFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
|
||||
{ "nomonsterfallingdamage", MITYPE_CLRFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
|
||||
{ "clipmidtextures", MITYPE_SETFLAG2, LEVEL2_CLIPMIDTEX, 0 },
|
||||
|
|
|
@ -143,17 +143,26 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
|
|||
glFinish();
|
||||
wipestartscreen->Bind(0, false, false);
|
||||
|
||||
const auto copyPixels = [&viewport]()
|
||||
{
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
};
|
||||
|
||||
if (FGLRenderBuffers::IsEnabled())
|
||||
{
|
||||
GLRenderer->mBuffers->BindCurrentFB();
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
copyPixels();
|
||||
}
|
||||
else if (gl.legacyMode)
|
||||
{
|
||||
copyPixels();
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint readbuffer = 0;
|
||||
glGetIntegerv(GL_READ_BUFFER, &readbuffer);
|
||||
glReadBuffer(GL_FRONT);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
|
||||
copyPixels();
|
||||
glReadBuffer(readbuffer);
|
||||
}
|
||||
|
||||
|
|
|
@ -796,7 +796,16 @@ void M_ClearMenus()
|
|||
|
||||
void M_Init (void)
|
||||
{
|
||||
M_ParseMenuDefs();
|
||||
try
|
||||
{
|
||||
M_ParseMenuDefs();
|
||||
}
|
||||
catch (CVMAbortException &err)
|
||||
{
|
||||
err.MaybePrintMessage();
|
||||
Printf("%s", err.stacktrace.GetChars());
|
||||
I_FatalError("Failed to initialize menus");
|
||||
}
|
||||
M_CreateMenus();
|
||||
}
|
||||
|
||||
|
|
|
@ -4765,24 +4765,24 @@ static int ScriptCall(unsigned argc, int32_t *args)
|
|||
auto cls = PClass::FindClass(clsname);
|
||||
if (!cls)
|
||||
{
|
||||
I_Error("ACS call to unknown class in script function %s.%s", cls, funcname);
|
||||
I_Error("ACS call to unknown class in script function %s.%s", clsname, funcname);
|
||||
}
|
||||
auto funcsym = dyn_cast<PFunction>(cls->Symbols.FindSymbol(funcname, true));
|
||||
if (funcsym == nullptr)
|
||||
{
|
||||
I_Error("ACS call to unknown script function %s.%s", cls, funcname);
|
||||
I_Error("ACS call to unknown script function %s.%s", clsname, funcname);
|
||||
}
|
||||
auto func = funcsym->Variants[0].Implementation;
|
||||
if (func->ImplicitArgs > 0)
|
||||
{
|
||||
I_Error("ACS call to non-static script function %s.%s", cls, funcname);
|
||||
I_Error("ACS call to non-static script function %s.%s", clsname, funcname);
|
||||
}
|
||||
TArray<VMValue> params;
|
||||
for (unsigned i = 2; i < argc; i++)
|
||||
{
|
||||
if (func->Proto->ArgumentTypes.Size() < i - 1)
|
||||
{
|
||||
I_Error("Too many parameters in call to %s.%s", cls, funcname);
|
||||
I_Error("Too many parameters in call to %s.%s", clsname, funcname);
|
||||
}
|
||||
auto argtype = func->Proto->ArgumentTypes[i - 2];
|
||||
// The only types allowed are int, bool, double, Name, Sound, Color and String
|
||||
|
@ -4812,7 +4812,7 @@ static int ScriptCall(unsigned argc, int32_t *args)
|
|||
}
|
||||
else
|
||||
{
|
||||
I_Error("Invalid type %s in call to %s.%s", argtype->DescriptiveName(), cls, funcname);
|
||||
I_Error("Invalid type %s in call to %s.%s", argtype->DescriptiveName(), clsname, funcname);
|
||||
}
|
||||
}
|
||||
if (func->Proto->ArgumentTypes.Size() > params.Size())
|
||||
|
@ -4820,7 +4820,7 @@ static int ScriptCall(unsigned argc, int32_t *args)
|
|||
// Check if we got enough parameters. That means we either cover the full argument list of the function or the next argument is optional.
|
||||
if (!(funcsym->Variants[0].ArgFlags[params.Size()] & VARF_Optional))
|
||||
{
|
||||
I_Error("Insufficient parameters in call to %s.%s", cls, funcname);
|
||||
I_Error("Insufficient parameters in call to %s.%s", clsname, funcname);
|
||||
}
|
||||
}
|
||||
// The return value can be the same types as the parameter types, plus void
|
||||
|
@ -9088,6 +9088,35 @@ scriptwait:
|
|||
}
|
||||
break;
|
||||
|
||||
case PCD_TRANSLATIONRANGE4:
|
||||
{ // Colourise translation
|
||||
int start = STACK(5);
|
||||
int end = STACK(4);
|
||||
int r = STACK(3);
|
||||
int g = STACK(2);
|
||||
int b = STACK(1);
|
||||
sp -= 5;
|
||||
|
||||
if (translation != NULL)
|
||||
translation->AddColourisation(start, end, r, g, b);
|
||||
}
|
||||
break;
|
||||
|
||||
case PCD_TRANSLATIONRANGE5:
|
||||
{ // Tint translation
|
||||
int start = STACK(6);
|
||||
int end = STACK(5);
|
||||
int a = STACK(4);
|
||||
int r = STACK(3);
|
||||
int g = STACK(2);
|
||||
int b = STACK(1);
|
||||
sp -= 6;
|
||||
|
||||
if (translation != NULL)
|
||||
translation->AddTint(start, end, r, g, b, a);
|
||||
}
|
||||
break;
|
||||
|
||||
case PCD_ENDTRANSLATION:
|
||||
if (translation != NULL)
|
||||
{
|
||||
|
|
|
@ -779,6 +779,8 @@ public:
|
|||
/*380*/ PCD_STRCPYTOSCRIPTCHRANGE,
|
||||
PCD_LSPEC5EX,
|
||||
PCD_LSPEC5EXRESULT,
|
||||
PCD_TRANSLATIONRANGE4,
|
||||
PCD_TRANSLATIONRANGE5,
|
||||
|
||||
/*381*/ PCODE_COMMAND_COUNT
|
||||
};
|
||||
|
|
|
@ -487,6 +487,56 @@ void FRemapTable::AddDesaturation(int start, int end, double r1, double g1, doub
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FRemapTable::AddColourisation(int start, int end, int r, int g, int b)
|
||||
{
|
||||
for (int i = start; i < end; ++i)
|
||||
{
|
||||
float br = GPalette.BaseColors[i].r;
|
||||
float bg = GPalette.BaseColors[i].g;
|
||||
float bb = GPalette.BaseColors[i].b;
|
||||
float grey = (br * 0.299 + bg * 0.587 + bb * 0.114) / 255.0f;
|
||||
if (grey > 1.0) grey = 1.0;
|
||||
br = r * grey;
|
||||
bg = g * grey;
|
||||
bb = b * grey;
|
||||
|
||||
int j = GPalette.Remap[i];
|
||||
Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb));
|
||||
Remap[j] = ColorMatcher.Pick(Palette[j]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FRemapTable::AddTint(int start, int end, int r, int g, int b, int amount)
|
||||
{
|
||||
for (int i = start; i < end; ++i)
|
||||
{
|
||||
float br = GPalette.BaseColors[i].r;
|
||||
float bg = GPalette.BaseColors[i].g;
|
||||
float bb = GPalette.BaseColors[i].b;
|
||||
float a = amount * 0.01f;
|
||||
float ia = 1.0f - a;
|
||||
br = br * ia + r * a;
|
||||
bg = bg * ia + g * a;
|
||||
bb = bb * ia + b * a;
|
||||
|
||||
int j = GPalette.Remap[i];
|
||||
Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb));
|
||||
Remap[j] = ColorMatcher.Pick(Palette[j]);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void FRemapTable::AddToTranslation(const char *range)
|
||||
{
|
||||
int start,end;
|
||||
|
@ -511,19 +561,9 @@ void FRemapTable::AddToTranslation(const char *range)
|
|||
}
|
||||
|
||||
sc.MustGetAnyToken();
|
||||
Printf(0, "token type: %d", sc.TokenType);
|
||||
|
||||
if (sc.TokenType != '[' && sc.TokenType != '%')
|
||||
{
|
||||
int pal1,pal2;
|
||||
|
||||
sc.TokenMustBe(TK_IntConst);
|
||||
pal1 = sc.Number;
|
||||
sc.MustGetToken(':');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
pal2 = sc.Number;
|
||||
AddIndexRange(start, end, pal1, pal2);
|
||||
}
|
||||
else if (sc.TokenType == '[')
|
||||
if (sc.TokenType == '[')
|
||||
{
|
||||
// translation using RGB values
|
||||
int r1,g1,b1,r2,g2,b2;
|
||||
|
@ -596,6 +636,54 @@ void FRemapTable::AddToTranslation(const char *range)
|
|||
|
||||
AddDesaturation(start, end, r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
else if (sc.TokenType == '#')
|
||||
{
|
||||
// Colourise translation
|
||||
int r, g, b;
|
||||
sc.MustGetToken('[');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
r = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
g = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
b = sc.Number;
|
||||
sc.MustGetToken(']');
|
||||
|
||||
AddColourisation(start, end, r, g, b);
|
||||
}
|
||||
else if (sc.TokenType == '@')
|
||||
{
|
||||
// Tint translation
|
||||
int a, r, g, b;
|
||||
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
a = sc.Number;
|
||||
sc.MustGetToken('[');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
r = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
g = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
b = sc.Number;
|
||||
sc.MustGetToken(']');
|
||||
|
||||
AddTint(start, end, r, g, b, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
int pal1, pal2;
|
||||
|
||||
sc.TokenMustBe(TK_IntConst);
|
||||
pal1 = sc.Number;
|
||||
sc.MustGetToken(':');
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
pal2 = sc.Number;
|
||||
AddIndexRange(start, end, pal1, pal2);
|
||||
}
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,8 @@ struct FRemapTable
|
|||
void AddIndexRange(int start, int end, int pal1, int pal2);
|
||||
void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2);
|
||||
void AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2);
|
||||
void AddColourisation(int start, int end, int r, int g, int b);
|
||||
void AddTint(int start, int end, int r, int g, int b, int amount);
|
||||
void AddToTranslation(const char * range);
|
||||
int StoreTranslation(int slot);
|
||||
|
||||
|
|
|
@ -42,6 +42,31 @@
|
|||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
void VersionInfo::operator=(const char *string)
|
||||
{
|
||||
char *endp;
|
||||
major = (int16_t)clamp<unsigned long long>(strtoull(string, &endp, 10), 0, USHRT_MAX);
|
||||
if (*endp == '.')
|
||||
{
|
||||
minor = (int16_t)clamp<unsigned long long>(strtoull(endp + 1, &endp, 10), 0, USHRT_MAX);
|
||||
if (*endp == '.')
|
||||
{
|
||||
revision = (int16_t)clamp<unsigned long long>(strtoull(endp + 1, &endp, 10), 0, USHRT_MAX);
|
||||
if (*endp != 0) major = USHRT_MAX;
|
||||
}
|
||||
else if (*endp == 0)
|
||||
{
|
||||
revision = 0;
|
||||
}
|
||||
else major = USHRT_MAX;
|
||||
}
|
||||
else if (*endp == 0)
|
||||
{
|
||||
minor = revision = 0;
|
||||
}
|
||||
else major = USHRT_MAX;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FScanner Constructor
|
||||
|
|
|
@ -24,6 +24,10 @@ public:
|
|||
void OpenString(const char *name, FString buffer);
|
||||
void OpenLumpNum(int lump);
|
||||
void Close();
|
||||
void SetParseVersion(VersionInfo ver)
|
||||
{
|
||||
ParseVersion = ver;
|
||||
}
|
||||
|
||||
void SetCMode(bool cmode);
|
||||
void SetEscape(bool esc);
|
||||
|
@ -102,6 +106,7 @@ protected:
|
|||
BYTE StateMode;
|
||||
bool StateOptions;
|
||||
bool Escape;
|
||||
VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
@ -143,46 +143,38 @@ std2:
|
|||
'false' { RET(TK_False); }
|
||||
'none' { RET(TK_None); }
|
||||
'auto' { RET(TK_Auto); }
|
||||
'exec' { RET(TK_Exec); }
|
||||
'property' { RET(TK_Property); }
|
||||
'native' { RET(TK_Native); }
|
||||
'var' { RET(TK_Var); }
|
||||
'out' { RET(TK_Out); }
|
||||
'ref' { RET(TK_Ref); }
|
||||
'event' { RET(TK_Event); }
|
||||
'out' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Out : TK_Identifier); }
|
||||
'static' { RET(TK_Static); }
|
||||
'transient' { RET(TK_Transient); }
|
||||
'final' { RET(TK_Final); }
|
||||
'throws' { RET(TK_Throws); }
|
||||
'extend' { RET(TK_Extend); }
|
||||
'public' { RET(TK_Public); }
|
||||
'protected' { RET(TK_Protected); }
|
||||
'private' { RET(TK_Private); }
|
||||
'transient' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Transient : TK_Identifier); }
|
||||
'final' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Final : TK_Identifier); }
|
||||
'extend' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Extend : TK_Identifier); }
|
||||
'protected' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Protected : TK_Identifier); }
|
||||
'private' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Private : TK_Identifier); }
|
||||
'dot' { RET(TK_Dot); }
|
||||
'cross' { RET(TK_Cross); }
|
||||
'localized' { RET(TK_Localized); }
|
||||
'latent' { RET(TK_Latent); }
|
||||
'singular' { RET(TK_Singular); }
|
||||
'config' { RET(TK_Config); }
|
||||
'coerce' { RET(TK_Coerce); }
|
||||
'optional' { RET(TK_Optional); }
|
||||
'export' { RET(TK_Export); }
|
||||
'virtual' { RET(TK_Virtual); }
|
||||
'override' { RET(TK_Override); }
|
||||
'vararg' { RET(TK_VarArg); }
|
||||
'super' { RET(TK_Super); }
|
||||
'global' { RET(TK_Global); }
|
||||
'virtual' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Virtual : TK_Identifier); }
|
||||
'override' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Override : TK_Identifier); }
|
||||
'vararg' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_VarArg : TK_Identifier); }
|
||||
'ui' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_UI : TK_Identifier); }
|
||||
'play' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_Play : TK_Identifier); }
|
||||
'clearscope' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_ClearScope : TK_Identifier); }
|
||||
'virtualscope' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_VirtualScope : TK_Identifier); }
|
||||
'super' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Super : TK_Identifier); }
|
||||
'stop' { RET(TK_Stop); }
|
||||
'null' { RET(TK_Null); }
|
||||
|
||||
'is' { RET(TK_Is); }
|
||||
'replaces' { RET(TK_Replaces); }
|
||||
'is' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Is : TK_Identifier); }
|
||||
'replaces' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Replaces : TK_Identifier); }
|
||||
'states' { RET(TK_States); }
|
||||
'meta' { RET(TK_Meta); }
|
||||
'deprecated' { RET(TK_Deprecated); }
|
||||
'action' { RET(TK_Action); }
|
||||
'readonly' { RET(TK_ReadOnly); }
|
||||
'let' { RET(TK_Let); }
|
||||
'meta' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Meta : TK_Identifier); }
|
||||
'deprecated' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Deprecated : TK_Identifier); }
|
||||
'version' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_Version : TK_Identifier); }
|
||||
'action' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Action : TK_Identifier); }
|
||||
'readonly' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_ReadOnly : TK_Identifier); }
|
||||
'let' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Let : TK_Identifier); }
|
||||
|
||||
/* Actor state options */
|
||||
'bright' { RET(StateOptions ? TK_Bright : TK_Identifier); }
|
||||
|
@ -263,6 +255,8 @@ std2:
|
|||
"^" { RET('^'); }
|
||||
"|" { RET('|'); }
|
||||
"?" { RET('?'); }
|
||||
"#" { RET('#'); }
|
||||
"@" { RET('@'); }
|
||||
|
||||
[ \t\v\f\r]+ { goto std1; }
|
||||
"\n" { goto newline; }
|
||||
|
|
|
@ -108,10 +108,12 @@ xx(TK_Singular, "'singular'")
|
|||
xx(TK_Config, "'config'")
|
||||
xx(TK_Coerce, "'coerce'")
|
||||
xx(TK_Iterator, "'iterator'")
|
||||
xx(TK_Optional, "'optional'")
|
||||
xx(TK_Export, "'expert'")
|
||||
xx(TK_Virtual, "'virtual'")
|
||||
xx(TK_VarArg, "'vararg'")
|
||||
xx(TK_UI, "'ui'")
|
||||
xx(TK_Play, "'play'")
|
||||
xx(TK_ClearScope, "'clearscope'")
|
||||
xx(TK_VirtualScope, "'virtualscope'")
|
||||
xx(TK_Override, "'override'")
|
||||
xx(TK_Super, "'super'")
|
||||
xx(TK_Null, "'null'")
|
||||
|
@ -134,6 +136,7 @@ xx(TK_Fail, "'fail'")
|
|||
xx(TK_Wait, "'wait'")
|
||||
xx(TK_Meta, "'meta'")
|
||||
xx(TK_Deprecated, "'deprecated'")
|
||||
xx(TK_Version, "'version'")
|
||||
xx(TK_ReadOnly, "'readonly'")
|
||||
|
||||
xx(TK_CanRaise, "'canraise'")
|
||||
|
|
|
@ -89,15 +89,25 @@ static const FLOP FxFlops[] =
|
|||
{ NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } },
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FCompileContext
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump)
|
||||
: ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg)
|
||||
FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver)
|
||||
: ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg), Version(ver)
|
||||
{
|
||||
if (Version >= MakeVersion(2, 3))
|
||||
{
|
||||
VersionString.Format("ZScript version %d.%d.%d", Version.major, Version.minor, Version.revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionString = "DECORATE";
|
||||
}
|
||||
|
||||
if (fnc != nullptr) Class = fnc->OwningClass;
|
||||
}
|
||||
|
||||
|
@ -167,7 +177,8 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
|
|||
}
|
||||
}
|
||||
|
||||
bool FCompileContext::CheckReadOnly(int flags)
|
||||
// [ZZ] I find it really dumb that something called CheckReadOnly returns false for readonly. renamed.
|
||||
bool FCompileContext::CheckWritable(int flags)
|
||||
{
|
||||
if (!(flags & VARF_ReadOnly)) return false;
|
||||
if (!(flags & VARF_InternalAccess)) return true;
|
||||
|
@ -377,7 +388,7 @@ bool FxExpression::isConstant() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
VMFunction *FxExpression::GetDirectFunction()
|
||||
VMFunction *FxExpression::GetDirectFunction(const VersionInfo &ver)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -5023,6 +5034,7 @@ FxNew::FxNew(FxExpression *v)
|
|||
{
|
||||
val = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), v, false);
|
||||
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
||||
CallingFunction = nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -5047,6 +5059,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
|
|||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(val, ctx);
|
||||
|
||||
CallingFunction = ctx.Function;
|
||||
if (!val->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Class type expected");
|
||||
|
@ -5056,8 +5069,28 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
|
|||
if (val->isConstant())
|
||||
{
|
||||
auto cls = static_cast<PClass *>(static_cast<FxConstant*>(val)->GetValue().GetPointer());
|
||||
if (cls->ObjectFlags & OF_Abstract)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
int outerside = ctx.Function && ctx.Function->Variants.Size() ? FScopeBarrier::SideFromFlags(ctx.Function->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
|
||||
if (outerside == FScopeBarrier::Side_Virtual)
|
||||
outerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags);
|
||||
int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
|
||||
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context"
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside));
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ValueType = NewPointer(cls);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -5072,7 +5105,7 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit from = val->Emit(build);
|
||||
from.Free(build);
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum);
|
||||
build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum, build->GetConstantAddress(CallingFunction, ATAG_OBJECT));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -5932,6 +5965,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
|||
}
|
||||
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||
{
|
||||
PField *vsym = static_cast<PField*>(sym);
|
||||
|
||||
if (vsym->GetVersion() > ctx.Version)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// internally defined global variable
|
||||
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable\n", Identifier.GetChars());
|
||||
newex = new FxGlobalVariable(static_cast<PField *>(sym), ScriptPosition);
|
||||
|
@ -5991,7 +6033,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
|
|||
if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type.");
|
||||
delete this;
|
||||
delete object;
|
||||
object = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -6013,21 +6056,66 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
|
|||
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||
{
|
||||
PField *vsym = static_cast<PField*>(sym);
|
||||
if (vsym->GetVersion() > ctx.Version)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars());
|
||||
delete object;
|
||||
object = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
if ((vsym->Flags & VARF_Deprecated) && sym->mVersion >= ctx.Version)
|
||||
{
|
||||
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s - deprecated since %d.%d.%d", sym->SymbolName.GetChars(), vsym->mVersion.major, vsym->mVersion.minor, vsym->mVersion.revision);
|
||||
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
||||
}
|
||||
|
||||
// We have 4 cases to consider here:
|
||||
// 1. The symbol is a static/meta member (not implemented yet) which is always accessible.
|
||||
// 1. The symbol is a static/meta member which is always accessible.
|
||||
// 2. This is a static function
|
||||
// 3. This is an action function with a restricted self pointer
|
||||
// 4. This is a normal member or unrestricted action function.
|
||||
if (vsym->Flags & VARF_Deprecated && !ctx.FromDecorate)
|
||||
{
|
||||
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
||||
}
|
||||
if ((vsym->Flags & VARF_Private) && symtbl != &classctx->Symbols)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars());
|
||||
delete object;
|
||||
object = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
PClass* cls_ctx = dyn_cast<PClass>(classctx);
|
||||
PClass* cls_target = dyn_cast<PClass>(objtype);
|
||||
// [ZZ] neither PSymbol, PField or PSymbolTable have the necessary information. so we need to do the more complex check here.
|
||||
if (vsym->Flags & VARF_Protected)
|
||||
{
|
||||
// early break.
|
||||
if (!cls_ctx || !cls_target)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars());
|
||||
delete object;
|
||||
object = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// find the class that declared this field.
|
||||
PClass* p = cls_target;
|
||||
while (p)
|
||||
{
|
||||
if (&p->Symbols == symtbl)
|
||||
{
|
||||
cls_target = p;
|
||||
break;
|
||||
}
|
||||
|
||||
p = p->ParentClass;
|
||||
}
|
||||
|
||||
if (!cls_ctx->IsDescendantOf(cls_target))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars());
|
||||
delete object;
|
||||
object = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition) : new FxStructMember(object, vsym, ScriptPosition);
|
||||
object = nullptr;
|
||||
|
@ -6245,7 +6333,7 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx)
|
|||
bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
|
||||
{
|
||||
AddressRequested = true;
|
||||
if (writable != nullptr) *writable = !ctx.CheckReadOnly(Variable->VarFlags);
|
||||
if (writable != nullptr) *writable = !ctx.CheckWritable(Variable->VarFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6463,7 +6551,7 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
|
|||
bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
|
||||
{
|
||||
AddressRequested = true;
|
||||
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags);
|
||||
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6653,7 +6741,7 @@ FxStackVariable::~FxStackVariable()
|
|||
bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable)
|
||||
{
|
||||
AddressRequested = true;
|
||||
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags);
|
||||
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6751,8 +6839,28 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
|
|||
return false;
|
||||
}
|
||||
AddressRequested = true;
|
||||
if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckReadOnly(membervar->Flags) &&
|
||||
(!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst));
|
||||
if (writable != nullptr)
|
||||
{
|
||||
// [ZZ] original check.
|
||||
bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
|
||||
(!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst));
|
||||
// [ZZ] implement write barrier between different scopes
|
||||
if (bWritable)
|
||||
{
|
||||
int outerflags = 0;
|
||||
if (ctx.Function)
|
||||
{
|
||||
outerflags = ctx.Function->Variants[0].Flags;
|
||||
if (((outerflags & (VARF_VirtualScope | VARF_Virtual)) == (VARF_VirtualScope | VARF_Virtual)) && ctx.Class)
|
||||
outerflags = FScopeBarrier::FlagsFromSide(FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags));
|
||||
}
|
||||
FScopeBarrier scopeBarrier(outerflags, FScopeBarrier::FlagsFromSide(BarrierSide), membervar->SymbolName.GetChars());
|
||||
if (!scopeBarrier.writable)
|
||||
bWritable = false;
|
||||
}
|
||||
|
||||
*writable = bWritable;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6772,7 +6880,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))
|
||||
|| !static_cast<PPointer *>(classx->ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type.");
|
||||
ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -6782,12 +6890,36 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
return x->Resolve(ctx);
|
||||
}
|
||||
|
||||
// [ZZ] support magic
|
||||
int outerflags = 0;
|
||||
if (ctx.Function)
|
||||
{
|
||||
outerflags = ctx.Function->Variants[0].Flags;
|
||||
if (((outerflags & (VARF_VirtualScope | VARF_Virtual)) == (VARF_VirtualScope | VARF_Virtual)) && ctx.Class)
|
||||
outerflags = FScopeBarrier::FlagsFromSide(FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags));
|
||||
}
|
||||
FScopeBarrier scopeBarrier(outerflags, membervar->Flags, membervar->SymbolName.GetChars());
|
||||
if (!scopeBarrier.readable)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "%s", scopeBarrier.readerror.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BarrierSide = scopeBarrier.sidelast;
|
||||
if (classx->ExprType == EFX_StructMember && ExprType == EFX_StructMember) // note: only do this for structs now
|
||||
{
|
||||
FxStructMember* pmember = (FxStructMember*)classx;
|
||||
if (BarrierSide == FScopeBarrier::Side_PlainData && pmember)
|
||||
BarrierSide = pmember->BarrierSide;
|
||||
}
|
||||
|
||||
if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
||||
{
|
||||
PPointer *ptrtype = dyn_cast<PPointer>(classx->ValueType);
|
||||
if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object.");
|
||||
ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -6799,7 +6931,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
auto parentfield = static_cast<FxMemberBase *>(classx)->membervar;
|
||||
// PFields are garbage collected so this will be automatically taken care of later.
|
||||
auto newfield = new PField(NAME_None, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||
// [ZZ] call ChangeSideInFlags to ensure that we don't get ui+play
|
||||
auto newfield = new PField(NAME_None, membervar->Type, FScopeBarrier::ChangeSideInFlags(membervar->Flags | parentfield->Flags, BarrierSide), membervar->Offset + parentfield->Offset);
|
||||
newfield->BitValue = membervar->BitValue;
|
||||
static_cast<FxMemberBase *>(classx)->membervar = newfield;
|
||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
|
@ -6841,7 +6974,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
if (!(classx->RequestAddress(ctx, &AddressWritable)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "unable to dereference left side of %s", membervar->SymbolName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference left side of %s", membervar->SymbolName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7371,6 +7504,32 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// [ZZ] validate call
|
||||
PClass* cls = (PClass*)ctx.Class;
|
||||
int outerflags = 0;
|
||||
if (ctx.Function)
|
||||
{
|
||||
outerflags = ctx.Function->Variants[0].Flags;
|
||||
if (((outerflags & (VARF_VirtualScope | VARF_Virtual)) == (VARF_VirtualScope | VARF_Virtual)) && ctx.Class)
|
||||
outerflags = FScopeBarrier::FlagsFromSide(FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags));
|
||||
}
|
||||
int innerflags = afd->Variants[0].Flags;
|
||||
int innerside = FScopeBarrier::SideFromFlags(innerflags);
|
||||
// [ZZ] check this at compile time. this would work for most legit cases.
|
||||
if (innerside == FScopeBarrier::Side_Virtual)
|
||||
{
|
||||
innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
|
||||
innerflags = FScopeBarrier::FlagsFromSide(innerside);
|
||||
}
|
||||
FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars());
|
||||
if (!scopeBarrier.callable)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "%s", scopeBarrier.callerror.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// [ZZ] this is only checked for VARF_Methods in the other place. bug?
|
||||
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
||||
{
|
||||
delete this;
|
||||
|
@ -7593,8 +7752,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
break;
|
||||
|
||||
case NAME_New:
|
||||
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
|
||||
if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition))
|
||||
{
|
||||
// [ZZ] allow implicit new() call to mean "create current class instance"
|
||||
if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else if (!ArgList.Size())
|
||||
ArgList.Push(new FxConstant((PClass*)ctx.Class, NewClassPointer((PClass*)ctx.Class), ScriptPosition));
|
||||
|
||||
func = new FxNew(ArgList[0]);
|
||||
ArgList[0] = nullptr;
|
||||
}
|
||||
|
@ -7651,13 +7820,14 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
PStruct *cls;
|
||||
bool staticonly = false;
|
||||
bool novirtual = false;
|
||||
bool isreadonly = false;
|
||||
|
||||
PStruct *ccls = nullptr;
|
||||
|
||||
if (ctx.Class == nullptr)
|
||||
{
|
||||
// There's no way that a member function call can resolve to a constant so abort right away.
|
||||
ScriptPosition.Message(MSG_ERROR, "Expression is not constant.");
|
||||
ScriptPosition.Message(MSG_ERROR, "Expression is not constant");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7666,7 +7836,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (a == nullptr)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Empty function argument.");
|
||||
ScriptPosition.Message(MSG_ERROR, "Empty function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7677,6 +7847,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
auto id = static_cast<FxIdentifier *>(Self)->Identifier;
|
||||
// If the left side is a class name for a static member function call it needs to be resolved manually
|
||||
// because the resulting value type would cause problems in nearly every other place where identifiers are being used.
|
||||
// [ZZ] substitute ccls for String internal type.
|
||||
if (id == NAME_String) ccls = TypeStringStruct;
|
||||
else ccls = FindStructType(id, ctx);
|
||||
if (ccls != nullptr) static_cast<FxIdentifier *>(Self)->noglobal = true;
|
||||
|
@ -7688,7 +7859,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (ccls != nullptr)
|
||||
{
|
||||
// [ZZ] substitute ccls for String internal type.
|
||||
if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast<PClass *>(ccls)->bExported)
|
||||
{
|
||||
cls = ccls;
|
||||
|
@ -7717,6 +7887,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
Self = new FxSelf(ScriptPosition);
|
||||
Self->ValueType = NewPointer(cls);
|
||||
}
|
||||
else novirtual = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7757,7 +7928,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7801,7 +7972,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7895,7 +8066,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7945,7 +8116,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
auto x = new FxGetParentClass(Self);
|
||||
return x->Resolve(ctx);
|
||||
}
|
||||
|
||||
|
||||
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
{
|
||||
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
|
||||
|
@ -7955,7 +8126,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Too many parameters in call to %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7968,7 +8139,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Left hand side of %s must point to a class object\n", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Left hand side of %s must point to a class object", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -7976,22 +8147,15 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
bool writable;
|
||||
if (Self->RequestAddress(ctx, &writable) && writable)
|
||||
{
|
||||
cls = static_cast<PStruct*>(Self->ValueType);
|
||||
Self->ValueType = NewPointer(Self->ValueType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cannot be made writable so we cannot use its methods.
|
||||
ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// [ZZ] allow const method to be called on a readonly struct
|
||||
isreadonly = !(Self->RequestAddress(ctx, &writable) && writable);
|
||||
cls = static_cast<PStruct*>(Self->ValueType);
|
||||
Self->ValueType = NewPointer(Self->ValueType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -8009,7 +8173,50 @@ isresolved:
|
|||
|
||||
if (afd == nullptr)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Unknown function %s\n", MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Unknown function %s", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isreadonly && !(afd->Variants[0].Flags & VARF_ReadOnly))
|
||||
{
|
||||
// Cannot be made writable so we cannot use its methods.
|
||||
// [ZZ] Why this esoteric message?
|
||||
ScriptPosition.Message(MSG_ERROR, "Readonly struct on left hand side of %s not allowed", MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// [ZZ] if self is a struct or a class member, check if it's valid to call this function at all.
|
||||
// implement more magic
|
||||
int outerflags = 0;
|
||||
if (ctx.Function)
|
||||
{
|
||||
outerflags = ctx.Function->Variants[0].Flags;
|
||||
if (((outerflags & (VARF_VirtualScope | VARF_Virtual)) == (VARF_VirtualScope | VARF_Virtual)) && ctx.Class)
|
||||
outerflags = FScopeBarrier::FlagsFromSide(FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags));
|
||||
}
|
||||
int innerflags = afd->Variants[0].Flags;
|
||||
int innerside = FScopeBarrier::SideFromFlags(innerflags);
|
||||
// [ZZ] check this at compile time. this would work for most legit cases.
|
||||
if (innerside == FScopeBarrier::Side_Virtual)
|
||||
{
|
||||
innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
|
||||
innerflags = FScopeBarrier::FlagsFromSide(innerside);
|
||||
}
|
||||
else if (innerside != FScopeBarrier::Side_Clear)
|
||||
{
|
||||
if (Self->ExprType == EFX_StructMember)
|
||||
{
|
||||
FxStructMember* pmember = (FxStructMember*)Self;
|
||||
if (innerside == FScopeBarrier::Side_PlainData)
|
||||
innerflags = FScopeBarrier::ChangeSideInFlags(innerflags, pmember->BarrierSide);
|
||||
}
|
||||
}
|
||||
FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars());
|
||||
if (!scopeBarrier.callable)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "%s", scopeBarrier.callerror.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -8022,14 +8229,14 @@ isresolved:
|
|||
auto ccls = dyn_cast<PClass>(cls);
|
||||
if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.)
|
||||
ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented", cls->TypeName.GetChars(), MethodName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -8057,7 +8264,7 @@ isresolved:
|
|||
// Functions with no Actor usage may not be called through a pointer because they will lose their context.
|
||||
if (!(afd->Variants[0].UseFlags & SUF_ACTOR))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object\n", afd->SymbolName.GetChars());
|
||||
ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object", afd->SymbolName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -8264,6 +8471,7 @@ FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumen
|
|||
ArgList = std::move(args);
|
||||
EmitTail = false;
|
||||
NoVirtual = novirtual;
|
||||
CallingFunction = nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -8288,19 +8496,44 @@ PPrototype *FxVMFunctionCall::ReturnProto()
|
|||
return Function->Variants[0].Proto;
|
||||
}
|
||||
|
||||
|
||||
bool FxVMFunctionCall::CheckAccessibility(const VersionInfo &ver)
|
||||
{
|
||||
if (Function->mVersion > ver && !(Function->Variants[0].Flags & VARF_Deprecated))
|
||||
{
|
||||
FString VersionString;
|
||||
if (ver >= MakeVersion(2, 3))
|
||||
{
|
||||
VersionString.Format("ZScript version %d.%d.%d", ver.major, ver.minor, ver.revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionString = "DECORATE";
|
||||
}
|
||||
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", Function->SymbolName.GetChars(), VersionString.GetChars());
|
||||
return false;
|
||||
}
|
||||
if ((Function->Variants[0].Flags & VARF_Deprecated) && Function->mVersion >= ver)
|
||||
{
|
||||
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated function %s - deprecated since %d.%d.%d", Function->SymbolName.GetChars(), Function->mVersion.major, Function->mVersion.minor, Function->mVersion.revision);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
VMFunction *FxVMFunctionCall::GetDirectFunction()
|
||||
VMFunction *FxVMFunctionCall::GetDirectFunction(const VersionInfo &ver)
|
||||
{
|
||||
// If this return statement calls a non-virtual function with no arguments,
|
||||
// then it can be a "direct" function. That is, the DECORATE
|
||||
// definition can call that function directly without wrapping
|
||||
// it inside VM code.
|
||||
if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual))
|
||||
|
||||
if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual) && CheckAccessibility(ver))
|
||||
{
|
||||
unsigned imp = Function->GetImplicitArgs();
|
||||
if (Function->Variants[0].ArgFlags.Size() > imp && !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr;
|
||||
|
@ -8329,6 +8562,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
int implicit = Function->GetImplicitArgs();
|
||||
|
||||
if (!CheckAccessibility(ctx.Version))
|
||||
{
|
||||
delete this;
|
||||
return false;
|
||||
}
|
||||
// This should never happen.
|
||||
if (Self == nullptr && (Function->Variants[0].Flags & VARF_Method))
|
||||
{
|
||||
|
@ -8337,6 +8575,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CallingFunction = ctx.Function;
|
||||
if (ArgList.Size() > 0)
|
||||
{
|
||||
bool foundvarargs = false;
|
||||
|
@ -8537,13 +8776,24 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
|||
}
|
||||
|
||||
VMFunction *vmfunc = Function->Variants[0].Implementation;
|
||||
bool staticcall = (vmfunc->Final || vmfunc->VirtualIndex == ~0u || NoVirtual);
|
||||
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
|
||||
|
||||
count = 0;
|
||||
// Emit code to pass implied parameters
|
||||
ExpEmit selfemit;
|
||||
if (Function->Variants[0].Flags & VARF_Method)
|
||||
{
|
||||
#if 0
|
||||
// [ZZ]
|
||||
if (Function->Variants[0].Implementation && Function->Variants[0].Implementation->BarrierSide == FScopeBarrier::Side_Virtual)
|
||||
{
|
||||
// pass this even before Self, because otherwise we can't silently advance the arguments.
|
||||
// this is not even implicit arguments.
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(Function, ATAG_OBJECT));
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(CallingFunction, ATAG_OBJECT));
|
||||
count += 2;
|
||||
}
|
||||
#endif
|
||||
assert(Self != nullptr);
|
||||
selfemit = Self->Emit(build);
|
||||
assert((selfemit.RegType == REGT_POINTER) || (selfemit.Fixed && selfemit.Target));
|
||||
|
@ -9153,11 +9403,11 @@ ExpEmit FxSequence::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
VMFunction *FxSequence::GetDirectFunction()
|
||||
VMFunction *FxSequence::GetDirectFunction(const VersionInfo &ver)
|
||||
{
|
||||
if (Expressions.Size() == 1)
|
||||
{
|
||||
return Expressions[0]->GetDirectFunction();
|
||||
return Expressions[0]->GetDirectFunction(ver);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -10139,11 +10389,11 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
|||
return out;
|
||||
}
|
||||
|
||||
VMFunction *FxReturnStatement::GetDirectFunction()
|
||||
VMFunction *FxReturnStatement::GetDirectFunction(const VersionInfo &ver)
|
||||
{
|
||||
if (Args.Size() == 1)
|
||||
{
|
||||
return Args[0]->GetDirectFunction();
|
||||
return Args[0]->GetDirectFunction(ver);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "s_sound.h"
|
||||
#include "actor.h"
|
||||
#include "vmbuilder.h"
|
||||
#include "scopebarrier.h"
|
||||
|
||||
|
||||
#define CHECKRESOLVED() if (isresolved) return this; isresolved=true;
|
||||
|
@ -85,8 +86,10 @@ struct FCompileContext
|
|||
bool Unsafe = false;
|
||||
TDeletingArray<FxLocalVariableDeclaration *> FunctionArgs;
|
||||
PNamespace *CurGlobals;
|
||||
VersionInfo Version;
|
||||
FString VersionString;
|
||||
|
||||
FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump);
|
||||
FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver);
|
||||
FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants!
|
||||
|
||||
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
|
||||
|
@ -95,7 +98,7 @@ struct FCompileContext
|
|||
|
||||
void HandleJumps(int token, FxExpression *handler);
|
||||
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
|
||||
bool CheckReadOnly(int flags);
|
||||
bool CheckWritable(int flags);
|
||||
FxLocalVariableDeclaration *FindLocalVariable(FName name);
|
||||
};
|
||||
|
||||
|
@ -321,7 +324,7 @@ public:
|
|||
virtual bool isConstant() const;
|
||||
virtual bool RequestAddress(FCompileContext &ctx, bool *writable);
|
||||
virtual PPrototype *ReturnProto();
|
||||
virtual VMFunction *GetDirectFunction();
|
||||
virtual VMFunction *GetDirectFunction(const VersionInfo &ver);
|
||||
virtual bool CheckReturn() { return false; }
|
||||
virtual int GetBitValue() { return -1; }
|
||||
bool IsNumeric() const { return ValueType->isNumeric(); }
|
||||
|
@ -1208,6 +1211,7 @@ private:
|
|||
class FxNew : public FxExpression
|
||||
{
|
||||
FxExpression *val;
|
||||
PFunction *CallingFunction;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -1326,6 +1330,7 @@ public:
|
|||
PField *membervar;
|
||||
bool AddressRequested = false;
|
||||
bool AddressWritable = true;
|
||||
int BarrierSide = -1; // [ZZ] some magic
|
||||
FxMemberBase(EFxType type, PField *f, const FScriptPosition &p);
|
||||
};
|
||||
|
||||
|
@ -1707,13 +1712,16 @@ class FxVMFunctionCall : public FxExpression
|
|||
// for multi assignment
|
||||
int AssignCount = 0;
|
||||
TArray<ExpEmit> ReturnRegs;
|
||||
PFunction *CallingFunction;
|
||||
|
||||
bool CheckAccessibility(const VersionInfo &ver);
|
||||
|
||||
public:
|
||||
FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual);
|
||||
~FxVMFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
PPrototype *ReturnProto();
|
||||
VMFunction *GetDirectFunction();
|
||||
VMFunction *GetDirectFunction(const VersionInfo &ver);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®);
|
||||
TArray<PType*> &GetReturnTypes() const
|
||||
|
@ -1738,7 +1746,7 @@ public:
|
|||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
|
||||
VMFunction *GetDirectFunction();
|
||||
VMFunction *GetDirectFunction(const VersionInfo &ver);
|
||||
bool CheckReturn();
|
||||
};
|
||||
|
||||
|
@ -1945,7 +1953,7 @@ public:
|
|||
~FxReturnStatement();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
VMFunction *GetDirectFunction();
|
||||
VMFunction *GetDirectFunction(const VersionInfo &ver);
|
||||
bool CheckReturn() { return true; }
|
||||
};
|
||||
|
||||
|
|
197
src/scripting/backend/scopebarrier.cpp
Normal file
197
src/scripting/backend/scopebarrier.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
#include "dobject.h"
|
||||
#include "scopebarrier.h"
|
||||
|
||||
|
||||
// Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found.
|
||||
int FScopeBarrier::SideFromFlags(int flags)
|
||||
{
|
||||
if (flags & VARF_UI)
|
||||
return Side_UI;
|
||||
if (flags & VARF_Play)
|
||||
return Side_Play;
|
||||
if (flags & VARF_VirtualScope)
|
||||
return Side_Virtual;
|
||||
if (flags & VARF_ClearScope)
|
||||
return Side_Clear;
|
||||
return Side_PlainData;
|
||||
}
|
||||
|
||||
// same as above, but from object flags
|
||||
int FScopeBarrier::SideFromObjectFlags(int flags)
|
||||
{
|
||||
if (flags & OF_UI)
|
||||
return Side_UI;
|
||||
if (flags & OF_Play)
|
||||
return Side_Play;
|
||||
return Side_PlainData;
|
||||
}
|
||||
|
||||
//
|
||||
int FScopeBarrier::FlagsFromSide(int side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case Side_Play:
|
||||
return VARF_Play;
|
||||
case Side_UI:
|
||||
return VARF_UI;
|
||||
case Side_Virtual:
|
||||
return VARF_VirtualScope;
|
||||
case Side_Clear:
|
||||
return VARF_ClearScope;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int FScopeBarrier::ObjectFlagsFromSide(int side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case Side_Play:
|
||||
return OF_Play;
|
||||
case Side_UI:
|
||||
return OF_UI;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// used for errors
|
||||
const char* FScopeBarrier::StringFromSide(int side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case Side_PlainData:
|
||||
return "data";
|
||||
case Side_UI:
|
||||
return "ui";
|
||||
case Side_Play:
|
||||
return "play";
|
||||
case Side_Virtual:
|
||||
return "virtualscope"; // should not happen!
|
||||
case Side_Clear:
|
||||
return "clearscope"; // should not happen!
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// this modifies VARF_ flags and sets the side properly.
|
||||
int FScopeBarrier::ChangeSideInFlags(int flags, int side)
|
||||
{
|
||||
flags &= ~(VARF_UI | VARF_Play | VARF_VirtualScope | VARF_ClearScope);
|
||||
flags |= FlagsFromSide(side);
|
||||
return flags;
|
||||
}
|
||||
|
||||
// this modifies OF_ flags and sets the side properly.
|
||||
int FScopeBarrier::ChangeSideInObjectFlags(int flags, int side)
|
||||
{
|
||||
flags &= ~(OF_UI | OF_Play);
|
||||
flags |= ObjectFlagsFromSide(side);
|
||||
return flags;
|
||||
}
|
||||
|
||||
FScopeBarrier::FScopeBarrier()
|
||||
{
|
||||
sidefrom = -1;
|
||||
sidelast = -1;
|
||||
callable = true;
|
||||
readable = true;
|
||||
writable = true;
|
||||
}
|
||||
|
||||
FScopeBarrier::FScopeBarrier(int flags1, int flags2, const char* name)
|
||||
{
|
||||
sidefrom = -1;
|
||||
sidelast = -1;
|
||||
callable = true;
|
||||
readable = true;
|
||||
writable = true;
|
||||
|
||||
AddFlags(flags1, flags2, name);
|
||||
}
|
||||
|
||||
// AddFlags modifies ALLOWED actions by flags1->flags2.
|
||||
// This is used for comparing a.b.c.d access - if non-allowed field is seen anywhere in the chain, anything after it is non-allowed.
|
||||
// This struct is used so that the logic is in a single place.
|
||||
void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name)
|
||||
{
|
||||
// note: if it's already non-readable, don't even try advancing
|
||||
if (!readable)
|
||||
return;
|
||||
|
||||
// we aren't interested in any other flags
|
||||
// - update: including VARF_VirtualScope. inside the function itself, we treat it as if it's PlainData.
|
||||
flags1 &= VARF_UI | VARF_Play;
|
||||
flags2 &= VARF_UI | VARF_Play | VARF_ReadOnly;
|
||||
|
||||
if (sidefrom < 0) sidefrom = SideFromFlags(flags1);
|
||||
if (sidelast < 0) sidelast = sidefrom;
|
||||
|
||||
// flags1 = what's trying to access
|
||||
// flags2 = what's being accessed
|
||||
|
||||
int sideto = SideFromFlags(flags2);
|
||||
|
||||
// plain data inherits whatever scope modifiers that context or field container has.
|
||||
// i.e. play String bla; is play, and all non-specified methods/fields inside it are play as well.
|
||||
if (sideto != Side_PlainData)
|
||||
sidelast = sideto;
|
||||
else sideto = sidelast;
|
||||
|
||||
if ((sideto == Side_UI) && (sidefrom != Side_UI)) // only ui -> ui is readable
|
||||
{
|
||||
readable = false;
|
||||
if (name) readerror.Format("Can't read %s field %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom));
|
||||
}
|
||||
|
||||
if (!readable)
|
||||
{
|
||||
writable = false;
|
||||
callable = false;
|
||||
if (name)
|
||||
{
|
||||
writeerror.Format("Can't write %s field %s from %s context (not readable)", StringFromSide(sideto), name, StringFromSide(sidefrom));
|
||||
callerror.Format("Can't call %s function %s from %s context (not readable)", StringFromSide(sideto), name, StringFromSide(sidefrom));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (writable && (sidefrom != sideto)) // only matching types are writable (plain data implicitly takes context type by default, unless overridden)
|
||||
{
|
||||
writable = false;
|
||||
if (name) writeerror.Format("Can't write %s field %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom));
|
||||
}
|
||||
|
||||
if (callable && (sidefrom != sideto) && !(flags2 & VARF_ReadOnly)) // readonly on methods is used for plain data stuff that can be called from ui/play context.
|
||||
{
|
||||
callable = false;
|
||||
if (name) callerror.Format("Can't call %s function %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom));
|
||||
}
|
||||
}
|
||||
|
||||
// these are for vmexec.h
|
||||
void FScopeBarrier::ValidateNew(PClass* cls, PFunction* callingfunc)
|
||||
{
|
||||
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
|
||||
if (outerside == FScopeBarrier::Side_Virtual)
|
||||
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
|
||||
int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
|
||||
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context"
|
||||
ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside));
|
||||
}
|
||||
// this can be imported in vmexec.h
|
||||
void FScopeBarrier::ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype)
|
||||
{
|
||||
// [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual.
|
||||
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
|
||||
if (outerside == FScopeBarrier::Side_Virtual)
|
||||
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
|
||||
int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags);
|
||||
if (innerside == FScopeBarrier::Side_Virtual)
|
||||
innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags);
|
||||
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData))
|
||||
ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside));
|
||||
}
|
59
src/scripting/backend/scopebarrier.h
Normal file
59
src/scripting/backend/scopebarrier.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
//
|
||||
// [ZZ] this really should be in codegen.h, but vmexec needs to access it
|
||||
struct FScopeBarrier
|
||||
{
|
||||
bool callable;
|
||||
bool readable;
|
||||
bool writable;
|
||||
|
||||
// this is the error message
|
||||
FString callerror;
|
||||
FString readerror;
|
||||
FString writeerror;
|
||||
|
||||
// this is used to make the error message.
|
||||
enum Side
|
||||
{
|
||||
Side_PlainData = 0,
|
||||
Side_UI = 1,
|
||||
Side_Play = 2,
|
||||
Side_Virtual = 3, // do NOT change the value
|
||||
Side_Clear = 4
|
||||
};
|
||||
int sidefrom;
|
||||
int sidelast;
|
||||
|
||||
// Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found.
|
||||
static int SideFromFlags(int flags);
|
||||
|
||||
// same as above, but from object flags
|
||||
static int SideFromObjectFlags(int flags);
|
||||
|
||||
//
|
||||
static int FlagsFromSide(int side);
|
||||
static int ObjectFlagsFromSide(int side);
|
||||
|
||||
// used for errors
|
||||
static const char* StringFromSide(int side);
|
||||
|
||||
// this modifies VARF_ flags and sets the side properly.
|
||||
static int ChangeSideInFlags(int flags, int side);
|
||||
// this modifies OF_ flags and sets the side properly.
|
||||
static int ChangeSideInObjectFlags(int flags, int side);
|
||||
FScopeBarrier();
|
||||
FScopeBarrier(int flags1, int flags2, const char* name);
|
||||
|
||||
// AddFlags modifies ALLOWED actions by flags1->flags2.
|
||||
// This is used for comparing a.b.c.d access - if non-allowed field is seen anywhere in the chain, anything after it is non-allowed.
|
||||
// This struct is used so that the logic is in a single place.
|
||||
void AddFlags(int flags1, int flags2, const char* name);
|
||||
|
||||
// this is called from vmexec.h
|
||||
static void ValidateNew(PClass* cls, PFunction* callingfunc);
|
||||
static void ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype);
|
||||
};
|
||||
|
|
@ -802,9 +802,9 @@ void VMFunctionBuilder::BackpatchListToHere(TArray<size_t> &locs)
|
|||
//==========================================================================
|
||||
FFunctionBuildList FunctionBuildList;
|
||||
|
||||
VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum)
|
||||
VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo &ver, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum)
|
||||
{
|
||||
auto func = code->GetDirectFunction();
|
||||
auto func = code->GetDirectFunction(ver);
|
||||
if (func != nullptr)
|
||||
{
|
||||
delete code;
|
||||
|
@ -828,6 +828,7 @@ VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, PFunction *functy
|
|||
it.StateIndex = stateindex;
|
||||
it.StateCount = statecount;
|
||||
it.Lump = lumpnum;
|
||||
it.Version = ver;
|
||||
assert(it.Func->Variants.Size() == 1);
|
||||
it.Func->Variants[0].Implementation = it.Function;
|
||||
|
||||
|
@ -856,7 +857,7 @@ void FFunctionBuildList::Build()
|
|||
assert(item.Code != NULL);
|
||||
|
||||
// We don't know the return type in advance for anonymous functions.
|
||||
FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump);
|
||||
FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump, item.Version);
|
||||
|
||||
// Allocate registers for the function's arguments and create local variable nodes before starting to resolve it.
|
||||
VMFunctionBuilder buildit(item.Func->GetImplicitArgs());
|
||||
|
|
|
@ -146,13 +146,14 @@ class FFunctionBuildList
|
|||
int StateIndex;
|
||||
int StateCount;
|
||||
int Lump;
|
||||
VersionInfo Version;
|
||||
bool FromDecorate;
|
||||
};
|
||||
|
||||
TArray<Item> mItems;
|
||||
|
||||
public:
|
||||
VMFunction *AddFunction(PNamespace *curglobals, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum);
|
||||
VMFunction *AddFunction(PNamespace *curglobals, const VersionInfo &ver, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum);
|
||||
void Build();
|
||||
};
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
|
|||
bag.Namespace = ns;
|
||||
bag.Info = type;
|
||||
bag.fromDecorate = true;
|
||||
bag.Version = { 2, 0, 0 };
|
||||
#ifdef _DEBUG
|
||||
bag.ClassName = type->TypeName;
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,10 @@ EXTERN_CVAR(Bool, strictdecorate);
|
|||
|
||||
PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName)
|
||||
{
|
||||
if (parent->mVersion > MakeVersion(2, 0))
|
||||
{
|
||||
sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->GetClass()->TypeName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
PClassActor *type = static_cast<PClassActor *>(parent->CreateDerivedClass(typeName, parent->Size));
|
||||
if (type == nullptr)
|
||||
{
|
||||
|
@ -1125,6 +1129,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns)
|
|||
Baggage bag;
|
||||
|
||||
bag.Namespace = ns;
|
||||
bag.Version = { 2, 0, 0 };
|
||||
bag.fromDecorate = true;
|
||||
info = ParseActorHeader(sc, &bag);
|
||||
sc.MustGetToken('{');
|
||||
|
|
|
@ -340,7 +340,7 @@ endofstate:
|
|||
if (ScriptCode != nullptr)
|
||||
{
|
||||
auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags);
|
||||
state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum);
|
||||
state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, bag.Version, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum);
|
||||
}
|
||||
int count = bag.statedef.AddStates(&state, statestring, scp);
|
||||
if (count < 0)
|
||||
|
|
|
@ -26,6 +26,7 @@ class PSymbol : public DObject
|
|||
DECLARE_ABSTRACT_CLASS(PSymbol, DObject);
|
||||
public:
|
||||
FName SymbolName;
|
||||
VersionInfo mVersion = { 0,0,0 };
|
||||
|
||||
protected:
|
||||
PSymbol(FName name) { SymbolName = name; }
|
||||
|
@ -76,6 +77,7 @@ class PField : public PSymbol
|
|||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0);
|
||||
VersionInfo GetVersion();
|
||||
|
||||
size_t Offset;
|
||||
PType *Type;
|
||||
|
|
|
@ -110,12 +110,13 @@ void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FNam
|
|||
if (funcflags & VARF_Method)
|
||||
{
|
||||
// implied self pointer
|
||||
if (args != nullptr) args->Push(NewPointer(cls));
|
||||
if (args != nullptr) args->Push(NewPointer(cls, !!(funcflags & VARF_ReadOnly)));
|
||||
if (argflags != nullptr) argflags->Push(VARF_Implicit | VARF_ReadOnly);
|
||||
if (argnames != nullptr) argnames->Push(NAME_self);
|
||||
}
|
||||
if (funcflags & VARF_Action)
|
||||
{
|
||||
assert(!(funcflags & VARF_ReadOnly));
|
||||
// implied caller and callingstate pointers
|
||||
if (args != nullptr)
|
||||
{
|
||||
|
@ -163,6 +164,10 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i
|
|||
// Functions that only get flagged for actors do not need the additional two context parameters.
|
||||
int fflags = (flags& (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) ? VARF_Action | VARF_Method : VARF_Method;
|
||||
|
||||
// [ZZ] give anonymous functions the scope of their class
|
||||
// (just give them VARF_Play, whatever)
|
||||
fflags |= VARF_Play;
|
||||
|
||||
rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet.
|
||||
SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags);
|
||||
|
||||
|
@ -190,15 +195,22 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
|
|||
|
||||
if (symbol != nullptr)
|
||||
{
|
||||
PClass* cls_ctx = dyn_cast<PClass>(funccls);
|
||||
PClass* cls_target = funcsym?dyn_cast<PClass>(funcsym->OwningClass):nullptr;
|
||||
if (funcsym == nullptr)
|
||||
{
|
||||
sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars());
|
||||
}
|
||||
else if (funcsym->Variants[0].Flags & VARF_Private && symtable != &funccls->Symbols)
|
||||
else if ((funcsym->Variants[0].Flags & VARF_Private) && symtable != &funccls->Symbols)
|
||||
{
|
||||
// private access is only allowed if the symbol table belongs to the class in which the current function is being defined.
|
||||
sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars());
|
||||
}
|
||||
else if ((funcsym->Variants[0].Flags & VARF_Protected) && (!cls_ctx || !cls_target || !cls_ctx->IsDescendantOf((PClass*)cls_target)))
|
||||
{
|
||||
sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
else if (funcsym->Variants[0].Flags & VARF_Deprecated)
|
||||
{
|
||||
sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars());
|
||||
|
@ -216,7 +228,7 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void CreateDamageFunction(PNamespace *OutNamespace, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum)
|
||||
void CreateDamageFunction(PNamespace *OutNamespace, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum)
|
||||
{
|
||||
if (id == nullptr)
|
||||
{
|
||||
|
@ -226,7 +238,7 @@ void CreateDamageFunction(PNamespace *OutNamespace, PClassActor *info, AActor *d
|
|||
{
|
||||
auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition);
|
||||
auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0);
|
||||
defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum);
|
||||
defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, ver, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ struct Baggage
|
|||
bool fromDecorate;
|
||||
int CurrentState;
|
||||
int Lumpnum;
|
||||
VersionInfo Version;
|
||||
FStateDefinitions statedef;
|
||||
|
||||
FDropItem *DropItemList;
|
||||
|
@ -161,7 +162,7 @@ FName CheckCastKludges(FName in);
|
|||
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FName> *argnames, PStruct *cls, DWORD funcflags, int useflags);
|
||||
PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags);
|
||||
PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error);
|
||||
void CreateDamageFunction(PNamespace *ns, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum);
|
||||
void CreateDamageFunction(PNamespace *ns, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "menu/menu.h"
|
||||
#include "teaminfo.h"
|
||||
#include "r_data/sprites.h"
|
||||
#include "serializer.h"
|
||||
|
||||
static TArray<FPropertyInfo*> properties;
|
||||
static TArray<AFuncDesc> AFTable;
|
||||
|
@ -741,7 +742,7 @@ static int fieldcmp(const void * a, const void * b)
|
|||
void InitThingdef()
|
||||
{
|
||||
// Create all global variables here because this cannot be done on the script side and really isn't worth adding support for.
|
||||
// Also create all special fields here that cannot be declared by script syntax.
|
||||
// Also create all special fields here that cannot be declared by script syntax plus the pointer serializers. Doing all these with class overrides would be a bit messy.
|
||||
|
||||
auto secplanestruct = NewNativeStruct("Secplane", nullptr);
|
||||
secplanestruct->Size = sizeof(secplane_t);
|
||||
|
@ -750,18 +751,62 @@ void InitThingdef()
|
|||
auto sectorstruct = NewNativeStruct("Sector", nullptr);
|
||||
sectorstruct->Size = sizeof(sector_t);
|
||||
sectorstruct->Align = alignof(sector_t);
|
||||
NewPointer(sectorstruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(sector_t **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<sector_t>(ar, key, *(sector_t **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
auto linestruct = NewNativeStruct("Line", nullptr);
|
||||
linestruct->Size = sizeof(line_t);
|
||||
linestruct->Align = alignof(line_t);
|
||||
NewPointer(linestruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(line_t **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<line_t>(ar, key, *(line_t **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
auto sidestruct = NewNativeStruct("Side", nullptr);
|
||||
sidestruct->Size = sizeof(side_t);
|
||||
sidestruct->Align = alignof(side_t);
|
||||
NewPointer(sidestruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(side_t **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<side_t>(ar, key, *(side_t **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
auto vertstruct = NewNativeStruct("Vertex", nullptr);
|
||||
vertstruct->Size = sizeof(vertex_t);
|
||||
vertstruct->Align = alignof(vertex_t);
|
||||
NewPointer(vertstruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(vertex_t **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<vertex_t>(ar, key, *(vertex_t **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
auto sectorportalstruct = NewNativeStruct("SectorPortal", nullptr);
|
||||
sectorportalstruct->Size = sizeof(FSectorPortal);
|
||||
|
@ -779,12 +824,42 @@ void InitThingdef()
|
|||
teamstruct->Size = sizeof(FTeam);
|
||||
teamstruct->Align = alignof(FTeam);
|
||||
|
||||
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
|
||||
pstruct->Size = sizeof(player_t);
|
||||
pstruct->Align = alignof(player_t);
|
||||
NewPointer(pstruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(player_t **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<player_t>(ar, key, *(player_t **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
auto fontstruct = NewNativeStruct("FFont", nullptr);
|
||||
fontstruct->Size = sizeof(FFont);
|
||||
fontstruct->Align = alignof(FFont);
|
||||
NewPointer(fontstruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(FFont **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<FFont>(ar, key, *(FFont **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
// set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well...
|
||||
// As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up.
|
||||
sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native);
|
||||
|
||||
sectorstruct->AddNativeField("ceilingplane", secplanestruct, myoffsetof(sector_t, ceilingplane), VARF_Native);
|
||||
sectorstruct->AddNativeField("floorplane", secplanestruct, myoffsetof(sector_t, floorplane), VARF_Native);
|
||||
sectorstruct->AddNativeField("ceilingplane", secplanestruct, myoffsetof(sector_t, ceilingplane), VARF_Native | VARF_ReadOnly);
|
||||
sectorstruct->AddNativeField("floorplane", secplanestruct, myoffsetof(sector_t, floorplane), VARF_Native | VARF_ReadOnly);
|
||||
|
||||
|
||||
|
||||
|
@ -843,9 +918,6 @@ void InitThingdef()
|
|||
Namespaces.GlobalNamespace->Symbols.AddSymbol(gi);
|
||||
|
||||
// set up a variable for the global players array.
|
||||
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
|
||||
pstruct->Size = sizeof(player_t);
|
||||
pstruct->Align = alignof(player_t);
|
||||
PArray *parray = NewArray(pstruct, MAXPLAYERS);
|
||||
PField *fieldptr = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players);
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
|
||||
|
|
|
@ -679,7 +679,7 @@ DEFINE_PROPERTY(damage, X, Actor)
|
|||
|
||||
defaults->DamageVal = dmgval;
|
||||
// Only DECORATE can get here with a valid expression.
|
||||
CreateDamageFunction(bag.Namespace, bag.Info, defaults, id, true, bag.Lumpnum);
|
||||
CreateDamageFunction(bag.Namespace, bag.Version, bag.Info, defaults, id, true, bag.Lumpnum);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "cmdlib.h"
|
||||
#include "doomerrors.h"
|
||||
#include "memarena.h"
|
||||
#include "scripting/backend/scopebarrier.h"
|
||||
|
||||
class DObject;
|
||||
|
||||
|
@ -701,9 +702,8 @@ do_double: if (inexact)
|
|||
class VMFunction
|
||||
{
|
||||
public:
|
||||
bool Native;
|
||||
bool Final = false; // cannot be overridden
|
||||
bool Unsafe = false; // Contains references to class fields that are unsafe for psp and item state calls.
|
||||
bool Unsafe = false;
|
||||
int VarFlags = 0; // [ZZ] this replaces 5+ bool fields
|
||||
BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action
|
||||
unsigned VirtualIndex = ~0u;
|
||||
FName Name;
|
||||
|
@ -712,7 +712,7 @@ public:
|
|||
|
||||
class PPrototype *Proto;
|
||||
|
||||
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL)
|
||||
VMFunction(FName name = NAME_None) : ImplicitArgs(0), Name(name), Proto(NULL)
|
||||
{
|
||||
AllFunctions.Push(this);
|
||||
}
|
||||
|
@ -936,9 +936,10 @@ class VMNativeFunction : public VMFunction
|
|||
public:
|
||||
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
|
||||
|
||||
VMNativeFunction() : NativeCall(NULL) { Native = true; }
|
||||
VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; }
|
||||
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { Native = true; }
|
||||
// 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype.
|
||||
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; }
|
||||
VMNativeFunction(NativeCallType call) : NativeCall(call) { VarFlags = 8; }
|
||||
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { VarFlags = 8; }
|
||||
|
||||
// Return value is the number of results.
|
||||
NativeCallType NativeCall;
|
||||
|
|
|
@ -201,7 +201,7 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
|
|||
VMScriptFunction *calleefunc = static_cast<VMScriptFunction *>(callee->Func);
|
||||
const VMRegisters calleereg(callee);
|
||||
|
||||
assert(calleefunc != NULL && !calleefunc->Native);
|
||||
assert(calleefunc != NULL && !(calleefunc->VarFlags & VARF_Native));
|
||||
assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs));
|
||||
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
|
|||
const FVoidObj *konsta;
|
||||
const VM_ATAG *konstatag;
|
||||
|
||||
if (f->Func != NULL && !f->Func->Native)
|
||||
if (f->Func != NULL && !(f->Func->VarFlags & VARF_Native))
|
||||
{
|
||||
sfunc = static_cast<VMScriptFunction *>(f->Func);
|
||||
konstd = sfunc->KonstD;
|
||||
|
@ -664,13 +664,27 @@ begin:
|
|||
VMReturn returns[MAX_RETURNS];
|
||||
int numret;
|
||||
|
||||
b = B;
|
||||
#if 0
|
||||
// [ZZ] hax!
|
||||
if (call->BarrierSide == 3) // :( - this is Side_Virtual. Side_Virtual should receive special arguments.
|
||||
{
|
||||
PFunction* calledfunc = (PFunction*)(reg.param + f->NumParam - b)[0].a;
|
||||
PFunction* callingfunc = (PFunction*)(reg.param + f->NumParam - b)[1].a;
|
||||
DObject* dobj = (DObject*)(reg.param + f->NumParam - b)[2].a; // this is the self pointer. it should be in, since Side_Virtual functions are always non-static methods.
|
||||
PClass* selftype = dobj->GetClass();
|
||||
FScopeBarrier::ValidateCall(calledfunc, callingfunc, selftype);
|
||||
b -= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
FillReturns(reg, f, returns, pc+1, C);
|
||||
if (call->Native)
|
||||
if (call->VarFlags & VARF_Native)
|
||||
{
|
||||
try
|
||||
{
|
||||
VMCycles[0].Unclock();
|
||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C);
|
||||
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - b, call->DefaultArgs, b, returns, C);
|
||||
VMCycles[0].Clock();
|
||||
}
|
||||
catch (CVMAbortException &err)
|
||||
|
@ -686,7 +700,7 @@ begin:
|
|||
VMCalls[0]++;
|
||||
VMScriptFunction *script = static_cast<VMScriptFunction *>(call);
|
||||
VMFrame *newf = stack->AllocFrame(script);
|
||||
VMFillParams(reg.param + f->NumParam - B, newf, B);
|
||||
VMFillParams(reg.param + f->NumParam - b, newf, b);
|
||||
try
|
||||
{
|
||||
numret = Exec(stack, script->Code, returns, C);
|
||||
|
@ -722,7 +736,7 @@ begin:
|
|||
{
|
||||
VMFunction *call = (VMFunction *)ptr;
|
||||
|
||||
if (call->Native)
|
||||
if (call->VarFlags & VARF_Native)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -803,7 +817,11 @@ begin:
|
|||
{
|
||||
b = B;
|
||||
PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v);
|
||||
PFunction *callingfunc = (PFunction*)konsta[C].o; // [ZZ] due to how this is set, it's always const
|
||||
if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
|
||||
// [ZZ] validate readonly and between scope construction
|
||||
if (callingfunc)
|
||||
FScopeBarrier::ValidateNew(cls, callingfunc);
|
||||
reg.a[a] = cls->CreateNew();
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
@ -1948,7 +1966,7 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_
|
|||
const void *src;
|
||||
VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func);
|
||||
|
||||
assert(func != NULL && !func->Native);
|
||||
assert(func != NULL && !(func->VarFlags & VARF_Native));
|
||||
assert((regtype & ~REGT_KONST) == ret->RegType);
|
||||
|
||||
switch (regtype & REGT_TYPE)
|
||||
|
|
|
@ -48,7 +48,6 @@ TArray<VMFunction *> VMFunction::AllFunctions;
|
|||
|
||||
VMScriptFunction::VMScriptFunction(FName name)
|
||||
{
|
||||
Native = false;
|
||||
Name = name;
|
||||
LineInfo = nullptr;
|
||||
Code = NULL;
|
||||
|
@ -438,7 +437,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
|
|||
bool allocated = false;
|
||||
try
|
||||
{
|
||||
if (func->Native)
|
||||
if (func->VarFlags & VARF_Native)
|
||||
{
|
||||
return static_cast<VMNativeFunction *>(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line)
|
|||
struct ClassFlagsBlock {
|
||||
VM_UWORD Flags;
|
||||
ZCC_Identifier *Replaces;
|
||||
VersionInfo Version;
|
||||
};
|
||||
|
||||
struct StateOpts {
|
||||
|
@ -188,6 +189,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A).
|
|||
head->ParentName = nullptr;
|
||||
head->Flags = ZCC_Extension;
|
||||
head->Replaces = nullptr;
|
||||
head->Version = {0, 0};
|
||||
head->Type = nullptr;
|
||||
head->Symbol = nullptr;
|
||||
X = head;
|
||||
|
@ -200,6 +202,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
|
|||
head->ParentName = B;
|
||||
head->Flags = C.Flags;
|
||||
head->Replaces = C.Replaces;
|
||||
head->Version = C.Version;
|
||||
head->Type = nullptr;
|
||||
head->Symbol = nullptr;
|
||||
X = head;
|
||||
|
@ -210,10 +213,13 @@ class_ancestry(X) ::= . { X = NULL; }
|
|||
class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
|
||||
|
||||
%type class_flags{ClassFlagsBlock}
|
||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
|
||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; }
|
||||
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
|
||||
class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); }
|
||||
|
||||
/*----- Dottable Identifier -----*/
|
||||
// This can be either a single identifier or two identifiers connected by a .
|
||||
|
@ -320,13 +326,18 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body
|
|||
def->Body = B;
|
||||
def->Type = nullptr;
|
||||
def->Symbol = nullptr;
|
||||
def->Version = S.Version;
|
||||
def->Flags = S.Flags;
|
||||
X = def;
|
||||
}
|
||||
|
||||
%type struct_flags{ClassFlagsBlock}
|
||||
struct_flags(X) ::= . { X.Flags = 0; }
|
||||
struct_flags(X) ::= NATIVE. { X.Flags = ZCC_Native; }
|
||||
struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; }
|
||||
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; }
|
||||
struct_flags(X) ::= struct_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; }
|
||||
struct_flags(X) ::= struct_flags(A) CLEARSCOPE. { X.Flags = A.Flags | ZCC_ClearScope; }
|
||||
struct_flags(X) ::= struct_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; }
|
||||
struct_flags(X) ::= struct_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Version = C.String->GetChars(); }
|
||||
|
||||
opt_struct_body(X) ::= . { X = NULL; }
|
||||
opt_struct_body(X) ::= struct_body(X).
|
||||
|
@ -862,6 +873,9 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
|
|||
decl->Name = C.FuncName;
|
||||
decl->UseFlags = A == nullptr? nullptr : A->Id;
|
||||
decl->Flags = (A == nullptr? 0 : A->Flags) | C.FuncFlags;
|
||||
if (A == nullptr) decl->Version = {0,0,0};
|
||||
else decl->Version = A->Version;
|
||||
|
||||
decl->Body = C.FuncBody;
|
||||
X = decl;
|
||||
}
|
||||
|
@ -870,7 +884,16 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
|
|||
NEW_AST_NODE(VarDeclarator, decl, A == nullptr? B->SourceLoc : A->SourceLoc);
|
||||
decl->Type = B;
|
||||
decl->Names = C.VarNames;
|
||||
decl->Flags = (A == nullptr? 0 : A->Flags);
|
||||
if (A == nullptr)
|
||||
{
|
||||
decl->Flags = 0;
|
||||
decl->Version = {0,0,0};
|
||||
}
|
||||
else
|
||||
{
|
||||
decl->Flags = A->Flags;
|
||||
decl->Version = A->Version;
|
||||
}
|
||||
X = decl;
|
||||
}
|
||||
else
|
||||
|
@ -961,6 +984,7 @@ decl_flags(X) ::= decl_flags(F) decl_flag(A).
|
|||
X = nil_f;
|
||||
X->Id = nullptr;
|
||||
X->Flags = A.Int;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -977,6 +1001,8 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
|
|||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Action;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -986,6 +1012,42 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
|
|||
X->Id = A;
|
||||
}
|
||||
|
||||
decl_flags(X) ::= decl_flags(F) DEPRECATED(B) LPAREN STRCONST(A) RPAREN.
|
||||
{
|
||||
if (F == nullptr)
|
||||
{
|
||||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Deprecated;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
X = F;
|
||||
X->Flags |= ZCC_Deprecated;
|
||||
}
|
||||
X->Version = A.String->GetChars();
|
||||
}
|
||||
|
||||
decl_flags(X) ::= decl_flags(F) VERSION(B) LPAREN STRCONST(A) RPAREN.
|
||||
{
|
||||
if (F == nullptr)
|
||||
{
|
||||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Version;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
X = F;
|
||||
X->Flags |= ZCC_Version;
|
||||
}
|
||||
X->Version = A.String->GetChars();
|
||||
}
|
||||
|
||||
decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; }
|
||||
|
@ -995,10 +1057,13 @@ decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
|
|||
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= TRANSIENT(T). { X.Int = ZCC_Transient; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= UI(T). { X.Int = ZCC_UIFlag; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= PLAY(T). { X.Int = ZCC_Play; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= CLEARSCOPE(T). { X.Int = ZCC_ClearScope; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VIRTUALSCOPE(T). { X.Int = ZCC_VirtualScope; X.SourceLoc = T.SourceLoc; }
|
||||
|
||||
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
|
||||
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
|
||||
|
|
|
@ -275,8 +275,8 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum)
|
||||
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum)
|
||||
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum, const VersionInfo &ver)
|
||||
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum), mVersion(ver)
|
||||
{
|
||||
FScriptPosition::ResetErrorCounter();
|
||||
// Group top-level nodes by type
|
||||
|
@ -495,6 +495,32 @@ void ZCCCompiler::CreateStructTypes()
|
|||
{
|
||||
s->strct->Type = NewStruct(s->NodeName(), outer);
|
||||
}
|
||||
if (s->strct->Flags & ZCC_Version)
|
||||
{
|
||||
s->strct->Type->mVersion = s->strct->Version;
|
||||
}
|
||||
|
||||
if (mVersion >= MakeVersion(2, 4, 0))
|
||||
{
|
||||
if ((s->strct->Flags & (ZCC_UIFlag | ZCC_Play)) == (ZCC_UIFlag | ZCC_Play))
|
||||
{
|
||||
Error(s->strct, "Struct %s has incompatible flags", s->NodeName().GetChars());
|
||||
}
|
||||
|
||||
if (outer != OutNamespace) s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(outer->ObjectFlags));
|
||||
else if (s->strct->Flags & ZCC_ClearScope) Warn(s->strct, "Useless 'ClearScope' on struct %s not inside a class", s->NodeName().GetChars());
|
||||
if (s->strct->Flags & ZCC_UIFlag)
|
||||
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_UI);
|
||||
if (s->strct->Flags & ZCC_Play)
|
||||
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_Play);
|
||||
if (s->strct->Flags & ZCC_ClearScope)
|
||||
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_PlainData); // don't inherit the scope from the outer class
|
||||
}
|
||||
else
|
||||
{
|
||||
// old versions force 'play'.
|
||||
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_Play);
|
||||
}
|
||||
s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type());
|
||||
syms->AddSymbol(s->strct->Symbol);
|
||||
|
||||
|
@ -583,6 +609,10 @@ void ZCCCompiler::CreateClassTypes()
|
|||
// We will never get here if the name is a duplicate, so we can just do the assignment.
|
||||
try
|
||||
{
|
||||
if (parent->mVersion > mVersion)
|
||||
{
|
||||
Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
||||
}
|
||||
c->cls->Type = parent->CreateDerivedClass(c->NodeName(), TentativeClass);
|
||||
if (c->Type() == nullptr)
|
||||
{
|
||||
|
@ -597,11 +627,45 @@ void ZCCCompiler::CreateClassTypes()
|
|||
c->cls->Type = nullptr;
|
||||
}
|
||||
}
|
||||
if (c->cls->Flags & ZCC_Abstract)
|
||||
{
|
||||
c->Type()->ObjectFlags |= OF_Abstract;
|
||||
}
|
||||
if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName());
|
||||
if (c->cls->Flags & ZCC_Abstract)
|
||||
c->Type()->ObjectFlags |= OF_Abstract;
|
||||
|
||||
if (c->cls->Flags & ZCC_Version)
|
||||
{
|
||||
c->Type()->mVersion = c->cls->Version;
|
||||
}
|
||||
//
|
||||
if (mVersion >= MakeVersion(2, 4, 0))
|
||||
{
|
||||
static int incompatible[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope };
|
||||
int incompatiblecnt = 0;
|
||||
for (size_t k = 0; k < countof(incompatible); k++)
|
||||
if (incompatible[k] & c->cls->Flags) incompatiblecnt++;
|
||||
|
||||
if (incompatiblecnt > 1)
|
||||
{
|
||||
Error(c->cls, "Class %s has incompatible flags", c->NodeName().GetChars());
|
||||
}
|
||||
|
||||
if (c->cls->Flags & ZCC_UIFlag)
|
||||
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI;
|
||||
if (c->cls->Flags & ZCC_Play)
|
||||
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play;
|
||||
if (parent->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play
|
||||
{
|
||||
if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play))
|
||||
{
|
||||
Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars());
|
||||
}
|
||||
c->Type()->ObjectFlags = (c->Type()->ObjectFlags & ~(OF_UI | OF_Play)) | (parent->ObjectFlags & (OF_UI | OF_Play));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play;
|
||||
}
|
||||
|
||||
c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.)
|
||||
c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
|
||||
OutNamespace->Symbols.AddSymbol(c->cls->Symbol);
|
||||
|
@ -1050,8 +1114,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
|
||||
// For structs only allow 'deprecated', for classes exclude function qualifiers.
|
||||
int notallowed = forstruct?
|
||||
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension :
|
||||
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension;
|
||||
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope :
|
||||
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope;
|
||||
|
||||
if (field->Flags & notallowed)
|
||||
{
|
||||
|
@ -1066,12 +1130,46 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
|
||||
if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly;
|
||||
if (field->Flags & ZCC_Transient) varflags |= VARF_Transient;
|
||||
if (mVersion >= MakeVersion(2, 4, 0))
|
||||
{
|
||||
if (type->ObjectFlags & OF_UI)
|
||||
varflags |= VARF_UI;
|
||||
if (type->ObjectFlags & OF_Play)
|
||||
varflags |= VARF_Play;
|
||||
if (field->Flags & ZCC_UIFlag)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
|
||||
if (field->Flags & ZCC_Play)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
|
||||
if (field->Flags & ZCC_ClearScope)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData);
|
||||
}
|
||||
else
|
||||
{
|
||||
varflags |= VARF_Play;
|
||||
}
|
||||
|
||||
if (field->Flags & ZCC_Native)
|
||||
{
|
||||
varflags |= VARF_Native | VARF_Transient;
|
||||
}
|
||||
|
||||
static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope };
|
||||
int excludeflags = 0;
|
||||
int fc = 0;
|
||||
for (size_t i = 0; i < countof(excludescope); i++)
|
||||
{
|
||||
if (field->Flags & excludescope[i])
|
||||
{
|
||||
fc++;
|
||||
excludeflags |= excludescope[i];
|
||||
}
|
||||
}
|
||||
if (fc > 1)
|
||||
{
|
||||
Error(field, "Invalid combination of scope qualifiers %s on field %s", FlagsToString(excludeflags).GetChars(), FName(field->Names->Name).GetChars());
|
||||
varflags &= ~(VARF_UI | VARF_Play); // make plain data
|
||||
}
|
||||
|
||||
if (field->Flags & ZCC_Meta)
|
||||
{
|
||||
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
|
||||
|
@ -1115,17 +1213,19 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
{
|
||||
// for bit fields the type must point to the source variable.
|
||||
if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32;
|
||||
type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
|
||||
auto f = type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
|
||||
if (field->Flags & (ZCC_Version | ZCC_Deprecated)) f->mVersion = field->Version;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hasnativechildren)
|
||||
{
|
||||
Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars());
|
||||
Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
type->AddField(name->Name, thisfieldtype, varflags);
|
||||
auto f = type->AddField(name->Name, thisfieldtype, varflags);
|
||||
if (field->Flags & (ZCC_Version | ZCC_Deprecated)) f->mVersion = field->Version;
|
||||
}
|
||||
}
|
||||
name = static_cast<ZCC_VarName*>(name->SiblingNext);
|
||||
|
@ -1218,7 +1318,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
|
|||
FString ZCCCompiler::FlagsToString(uint32_t flags)
|
||||
{
|
||||
|
||||
const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "funcconst", "abstract", "extension", "virtual", "override", "transient", "vararg" };
|
||||
const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "const", "abstract", "extend", "virtual", "override", "transient", "vararg", "ui", "play", "clearscope", "virtualscope" };
|
||||
FString build;
|
||||
|
||||
for (size_t i = 0; i < countof(flagnames); i++)
|
||||
|
@ -1408,6 +1508,11 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
|
|||
Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars());
|
||||
return TypeError;
|
||||
}
|
||||
if (typesym->Type->mVersion > mVersion)
|
||||
{
|
||||
Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
||||
return TypeError;
|
||||
}
|
||||
retval = NewClassPointer(static_cast<PClass *>(typesym->Type));
|
||||
}
|
||||
break;
|
||||
|
@ -1441,6 +1546,12 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt)
|
|||
if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
|
||||
{
|
||||
auto ptype = static_cast<PSymbolType *>(sym)->Type;
|
||||
if (ptype->mVersion > mVersion)
|
||||
{
|
||||
Error(type, "Type %s not accessible to ZScript version %d.%d.%d", FName(type->UserType->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
||||
return TypeError;
|
||||
}
|
||||
|
||||
if (ptype->IsKindOf(RUNTIME_CLASS(PEnum)))
|
||||
{
|
||||
return TypeSInt32; // hack this to an integer until we can resolve the enum mess.
|
||||
|
@ -1787,7 +1898,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
|
|||
if (namenode->Id == NAME_DamageFunction)
|
||||
{
|
||||
auto x = ConvertNode(prop->Values);
|
||||
CreateDamageFunction(OutNamespace, cls, (AActor *)bag.Info->Defaults, x, false, Lump);
|
||||
CreateDamageFunction(OutNamespace, mVersion, cls, (AActor *)bag.Info->Defaults, x, false, Lump);
|
||||
((AActor *)bag.Info->Defaults)->DamageVal = -1;
|
||||
return;
|
||||
}
|
||||
|
@ -1942,6 +2053,7 @@ void ZCCCompiler::InitDefaults()
|
|||
#ifdef _DEBUG
|
||||
bag.ClassName = c->Type()->TypeName;
|
||||
#endif
|
||||
bag.Version = mVersion;
|
||||
bag.Namespace = OutNamespace;
|
||||
bag.Info = ti;
|
||||
bag.DropItemSet = false;
|
||||
|
@ -2017,7 +2129,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
} while (t != f->Type);
|
||||
}
|
||||
|
||||
int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_FuncConst | ZCC_Abstract;
|
||||
int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_Abstract;
|
||||
|
||||
if (f->Flags & notallowed)
|
||||
{
|
||||
|
@ -2064,12 +2176,44 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual;
|
||||
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
|
||||
if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg;
|
||||
if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly
|
||||
if (mVersion >= MakeVersion(2, 4, 0))
|
||||
{
|
||||
if (c->Type()->ObjectFlags & OF_UI)
|
||||
varflags |= VARF_UI;
|
||||
if (c->Type()->ObjectFlags & OF_Play)
|
||||
varflags |= VARF_Play;
|
||||
//if (f->Flags & ZCC_FuncConst)
|
||||
// varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag.
|
||||
if (f->Flags & ZCC_UIFlag)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
|
||||
if (f->Flags & ZCC_Play)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
|
||||
if (f->Flags & ZCC_ClearScope)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Clear);
|
||||
if (f->Flags & ZCC_VirtualScope)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual);
|
||||
}
|
||||
else
|
||||
{
|
||||
varflags |= VARF_Play;
|
||||
}
|
||||
|
||||
if ((f->Flags & ZCC_VarArg) && !(f->Flags & ZCC_Native))
|
||||
{
|
||||
Error(f, "'VarArg' can only be used with native methods");
|
||||
}
|
||||
if (f->Flags & ZCC_Action)
|
||||
{
|
||||
if (varflags & VARF_ReadOnly)
|
||||
{
|
||||
Error(f, "Action functions cannot be declared const");
|
||||
varflags &= ~VARF_ReadOnly;
|
||||
}
|
||||
if (varflags & VARF_UI)
|
||||
{
|
||||
Error(f, "Action functions cannot be declared UI");
|
||||
}
|
||||
// Non-Actors cannot have action functions.
|
||||
if (!c->Type()->IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||
{
|
||||
|
@ -2089,36 +2233,62 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
}
|
||||
if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final.
|
||||
|
||||
|
||||
if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'.
|
||||
// Only one of these flags may be used.
|
||||
static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static };
|
||||
static const char * print[] = { "virtual", "override", "action", "static" };
|
||||
int excludeflags = 0;
|
||||
int fc = 0;
|
||||
FString build;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (size_t i = 0; i < countof(exclude); i++)
|
||||
{
|
||||
if (f->Flags & exclude[i])
|
||||
{
|
||||
fc++;
|
||||
if (build.Len() > 0) build += ", ";
|
||||
build += print[i];
|
||||
excludeflags |= exclude[i];
|
||||
}
|
||||
}
|
||||
if (fc > 1)
|
||||
{
|
||||
Error(f, "Invalid combination of qualifiers %s on function %s.", FName(f->Name).GetChars(), build.GetChars());
|
||||
Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars());
|
||||
varflags |= VARF_Method;
|
||||
}
|
||||
if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well.
|
||||
|
||||
// [ZZ] this doesn't make sense either.
|
||||
if ((varflags&(VARF_ReadOnly | VARF_Method)) == VARF_ReadOnly) // non-method const function
|
||||
{
|
||||
Error(f, "'Const' on a static method is not supported");
|
||||
}
|
||||
|
||||
// [ZZ] neither this
|
||||
if ((varflags&(VARF_VirtualScope | VARF_Method)) == VARF_VirtualScope) // non-method virtualscope function
|
||||
{
|
||||
Error(f, "'VirtualScope' on a static method is not supported");
|
||||
}
|
||||
|
||||
static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope, ZCC_VirtualScope };
|
||||
excludeflags = 0;
|
||||
fc = 0;
|
||||
for (size_t i = 0; i < countof(excludescope); i++)
|
||||
{
|
||||
if (f->Flags & excludescope[i])
|
||||
{
|
||||
fc++;
|
||||
excludeflags |= excludescope[i];
|
||||
}
|
||||
}
|
||||
if (fc > 1)
|
||||
{
|
||||
Error(f, "Invalid combination of scope qualifiers %s on function %s", FlagsToString(excludeflags).GetChars(), FName(f->Name).GetChars());
|
||||
varflags &= ~(VARF_UI | VARF_Play); // make plain data
|
||||
}
|
||||
|
||||
if (f->Flags & ZCC_Native)
|
||||
{
|
||||
varflags |= VARF_Native;
|
||||
afd = FindFunction(c->Type(), FName(f->Name).GetChars());
|
||||
if (afd == nullptr)
|
||||
{
|
||||
Error(f, "The function '%s.%s' has not been exported from the executable.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars());
|
||||
Error(f, "The function '%s.%s' has not been exported from the executable", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2232,7 +2402,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
}
|
||||
else if (hasoptionals)
|
||||
{
|
||||
Error(p, "All arguments after the first optional one need also be optional.");
|
||||
Error(p, "All arguments after the first optional one need also be optional");
|
||||
}
|
||||
// TBD: disallow certain types? For now, let everything pass that isn't an array.
|
||||
args.Push(type);
|
||||
|
@ -2265,6 +2435,14 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
if (imp != nullptr) vindex = imp->VirtualIndex;
|
||||
else Error(f, "Virtual base function %s not found in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars());
|
||||
}
|
||||
if (f->Flags & (ZCC_Version | ZCC_Deprecated))
|
||||
{
|
||||
sym->mVersion = f->Version;
|
||||
if (varflags & VARF_Override)
|
||||
{
|
||||
Error(f, "Overridden function %s may not alter version restriction in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (!(f->Flags & ZCC_Native))
|
||||
{
|
||||
|
@ -2278,7 +2456,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
auto code = ConvertAST(c->Type(), f->Body);
|
||||
if (code != nullptr)
|
||||
{
|
||||
FunctionBuildList.AddFunction(OutNamespace, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
|
||||
FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2287,18 +2465,21 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults);
|
||||
}
|
||||
|
||||
if (sym->Variants[0].Implementation != nullptr)
|
||||
{
|
||||
// [ZZ] unspecified virtual function inherits old scope. virtual function scope can't be changed.
|
||||
sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags;
|
||||
}
|
||||
|
||||
PClass *clstype = static_cast<PClass *>(c->Type());
|
||||
if (varflags & VARF_Virtual)
|
||||
{
|
||||
if (sym->Variants[0].Implementation == nullptr)
|
||||
{
|
||||
Error(f, "Virtual function %s.%s not present.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars());
|
||||
Error(f, "Virtual function %s.%s not present", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars());
|
||||
return;
|
||||
}
|
||||
if (varflags & VARF_Final)
|
||||
{
|
||||
sym->Variants[0].Implementation->Final = true;
|
||||
}
|
||||
|
||||
if (forclass)
|
||||
{
|
||||
int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto);
|
||||
|
@ -2312,12 +2493,41 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
else
|
||||
{
|
||||
auto oldfunc = clstype->Virtuals[vindex];
|
||||
if (oldfunc->Final)
|
||||
auto parentfunc = dyn_cast<PFunction>(clstype->ParentClass->Symbols.FindSymbol(sym->SymbolName, true));
|
||||
if (parentfunc && parentfunc->mVersion > mVersion)
|
||||
{
|
||||
Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
||||
}
|
||||
if (oldfunc->VarFlags & VARF_Final)
|
||||
{
|
||||
Error(f, "Attempt to override final function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// you can't change ui/play/clearscope for a virtual method.
|
||||
if (f->Flags & (ZCC_UIFlag|ZCC_Play|ZCC_ClearScope|ZCC_VirtualScope))
|
||||
{
|
||||
Error(f, "Attempt to change scope for virtual function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// you can't change const qualifier for a virtual method
|
||||
if ((sym->Variants[0].Implementation->VarFlags & VARF_ReadOnly) && !(oldfunc->VarFlags & VARF_ReadOnly))
|
||||
{
|
||||
Error(f, "Attempt to add const qualifier to virtual function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// you can't change protected qualifier for a virtual method (i.e. putting private), because this cannot be reliably checked without runtime stuff
|
||||
if (f->Flags & (ZCC_Private | ZCC_Protected))
|
||||
{
|
||||
Error(f, "Attempt to change private/protected qualifiers for virtual function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// inherit scope of original function if override not specified
|
||||
sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, FScopeBarrier::SideFromFlags(oldfunc->VarFlags));
|
||||
// inherit const from original function
|
||||
if (oldfunc->VarFlags & VARF_ReadOnly)
|
||||
sym->Variants[0].Flags |= VARF_ReadOnly;
|
||||
if (oldfunc->VarFlags & VARF_Protected)
|
||||
sym->Variants[0].Flags |= VARF_Protected;
|
||||
|
||||
clstype->Virtuals[vindex] = sym->Variants[0].Implementation;
|
||||
sym->Variants[0].Implementation->VirtualIndex = vindex;
|
||||
sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2587,7 +2797,7 @@ void ZCCCompiler::CompileStates()
|
|||
if (code != nullptr)
|
||||
{
|
||||
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags);
|
||||
state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump);
|
||||
state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ struct ZCC_ConstantWork
|
|||
class ZCCCompiler
|
||||
{
|
||||
public:
|
||||
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum);
|
||||
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum, const VersionInfo & ver);
|
||||
~ZCCCompiler();
|
||||
int Compile();
|
||||
|
||||
|
@ -127,6 +127,7 @@ private:
|
|||
TArray<ZCC_StructWork *> Structs;
|
||||
TArray<ZCC_ClassWork *> Classes;
|
||||
TArray<ZCC_PropertyWork *> Properties;
|
||||
VersionInfo mVersion;
|
||||
|
||||
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "v_text.h"
|
||||
#include "version.h"
|
||||
#include "zcc_parser.h"
|
||||
#include "zcc_compile.h"
|
||||
|
||||
|
@ -137,10 +138,15 @@ static void InitTokenMap()
|
|||
TOKENDEF (TK_Latent, ZCC_LATENT);
|
||||
TOKENDEF (TK_Virtual, ZCC_VIRTUAL);
|
||||
TOKENDEF (TK_VarArg, ZCC_VARARG);
|
||||
TOKENDEF (TK_UI, ZCC_UI);
|
||||
TOKENDEF (TK_Play, ZCC_PLAY);
|
||||
TOKENDEF (TK_ClearScope, ZCC_CLEARSCOPE);
|
||||
TOKENDEF (TK_VirtualScope, ZCC_VIRTUALSCOPE);
|
||||
TOKENDEF (TK_Override, ZCC_OVERRIDE);
|
||||
TOKENDEF (TK_Final, ZCC_FINAL);
|
||||
TOKENDEF (TK_Meta, ZCC_META);
|
||||
TOKENDEF (TK_Deprecated, ZCC_DEPRECATED);
|
||||
TOKENDEF (TK_Version, ZCC_VERSION);
|
||||
TOKENDEF (TK_ReadOnly, ZCC_READONLY);
|
||||
TOKENDEF ('{', ZCC_LBRACE);
|
||||
TOKENDEF ('}', ZCC_RBRACE);
|
||||
|
@ -175,7 +181,6 @@ static void InitTokenMap()
|
|||
TOKENDEF (']', ZCC_RBRACKET);
|
||||
TOKENDEF (TK_In, ZCC_IN);
|
||||
TOKENDEF (TK_Out, ZCC_OUT);
|
||||
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
||||
TOKENDEF (TK_Super, ZCC_SUPER);
|
||||
TOKENDEF (TK_Null, ZCC_NULLPTR);
|
||||
TOKENDEF ('~', ZCC_TILDE);
|
||||
|
@ -228,29 +233,36 @@ static void InitTokenMap()
|
|||
|
||||
//**--------------------------------------------------------------------------
|
||||
|
||||
static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCParseState &state)
|
||||
static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void *parser, ZCCParseState &state)
|
||||
{
|
||||
int tokentype;
|
||||
//bool failed;
|
||||
ZCCToken value;
|
||||
FScanner sc;
|
||||
FScanner lsc;
|
||||
|
||||
if (filename != nullptr)
|
||||
if (pSC == nullptr)
|
||||
{
|
||||
lump = Wads.CheckNumForFullName(filename, true);
|
||||
if (lump >= 0)
|
||||
if (filename != nullptr)
|
||||
{
|
||||
sc.OpenLumpNum(lump);
|
||||
lump = Wads.CheckNumForFullName(filename, true);
|
||||
if (lump >= 0)
|
||||
{
|
||||
lsc.OpenLumpNum(lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not find script lump '%s'\n", filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not find script lump '%s'\n", filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else sc.OpenLumpNum(lump);
|
||||
else lsc.OpenLumpNum(lump);
|
||||
|
||||
pSC = &lsc;
|
||||
}
|
||||
FScanner &sc = *pSC;
|
||||
sc.SetParseVersion(state.ParseVersion);
|
||||
state.sc = ≻
|
||||
|
||||
while (sc.GetToken())
|
||||
{
|
||||
value.SourceLoc = sc.GetMessageLine();
|
||||
|
@ -339,9 +351,47 @@ static void DoParse(int lumpnum)
|
|||
#endif
|
||||
|
||||
sc.OpenLumpNum(lumpnum);
|
||||
sc.SetParseVersion({ 2, 4 }); // To get 'version' we need parse version 2.4 for the initial test
|
||||
auto saved = sc.SavePos();
|
||||
|
||||
ParseSingleFile(nullptr, lumpnum, parser, state);
|
||||
if (sc.GetToken())
|
||||
{
|
||||
if (sc.TokenType == TK_Version)
|
||||
{
|
||||
char *endp;
|
||||
sc.MustGetString();
|
||||
state.ParseVersion.major = (int16_t)clamp<unsigned long long>(strtoull(sc.String, &endp, 10), 0, USHRT_MAX);
|
||||
if (*endp != '.')
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
state.ParseVersion.minor = (int16_t)clamp<unsigned long long>(strtoll(endp + 1, &endp, 10), 0, USHRT_MAX);
|
||||
if (*endp == '.')
|
||||
{
|
||||
state.ParseVersion.revision = (int16_t)clamp<unsigned long long>(strtoll(endp + 1, &endp, 10), 0, USHRT_MAX);
|
||||
}
|
||||
else state.ParseVersion.revision = 0;
|
||||
if (*endp != 0)
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
if (state.ParseVersion.major == USHRT_MAX || state.ParseVersion.minor == USHRT_MAX || state.ParseVersion.revision == USHRT_MAX)
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
if (state.ParseVersion > MakeVersion(VER_MAJOR, VER_MINOR, VER_REVISION))
|
||||
{
|
||||
sc.ScriptError("Version mismatch. %d.%d.%d expected but only %d.%d.%d supported", state.ParseVersion.major, state.ParseVersion.minor, state.ParseVersion.revision, VER_MAJOR, VER_MINOR, VER_REVISION);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ParseVersion = MakeVersion(2, 3); // 2.3 is the first version of ZScript.
|
||||
sc.RestorePos(saved);
|
||||
}
|
||||
}
|
||||
|
||||
ParseSingleFile(&sc, nullptr, lumpnum, parser, state);
|
||||
for (unsigned i = 0; i < Includes.Size(); i++)
|
||||
{
|
||||
lumpnum = Wads.CheckNumForFullName(Includes[i], true);
|
||||
|
@ -358,7 +408,7 @@ static void DoParse(int lumpnum)
|
|||
Wads.GetWadFullName(Wads.GetLumpFile(baselump)), Includes[i].GetChars());
|
||||
}
|
||||
|
||||
ParseSingleFile(nullptr, lumpnum, parser, state);
|
||||
ParseSingleFile(nullptr, nullptr, lumpnum, parser, state);
|
||||
}
|
||||
}
|
||||
Includes.Clear();
|
||||
|
@ -401,7 +451,7 @@ static void DoParse(int lumpnum)
|
|||
|
||||
PSymbolTable symtable;
|
||||
auto newns = Wads.GetLumpFile(lumpnum) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(lumpnum));
|
||||
ZCCCompiler cc(state, NULL, symtable, newns, lumpnum);
|
||||
ZCCCompiler cc(state, NULL, symtable, newns, lumpnum, state.ParseVersion);
|
||||
cc.Compile();
|
||||
|
||||
if (FScriptPosition::ErrorCounter > 0)
|
||||
|
@ -432,16 +482,6 @@ void ParseScripts()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CCMD(parse)
|
||||
{
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
DoParse(argv[1]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static FString ZCCTokenName(int terminal)
|
||||
{
|
||||
if (terminal == ZCC_EOF)
|
||||
|
|
|
@ -36,7 +36,12 @@ enum
|
|||
ZCC_Virtual = 1 << 13,
|
||||
ZCC_Override = 1 << 14,
|
||||
ZCC_Transient = 1 << 15,
|
||||
ZCC_VarArg = 1 << 16
|
||||
ZCC_VarArg = 1 << 16,
|
||||
ZCC_UIFlag = 1 << 17, // there's also token called ZCC_UI
|
||||
ZCC_Play = 1 << 18,
|
||||
ZCC_ClearScope = 1 << 19,
|
||||
ZCC_VirtualScope = 1 << 20,
|
||||
ZCC_Version = 1 << 21,
|
||||
};
|
||||
|
||||
// Function parameter modifiers
|
||||
|
@ -190,6 +195,7 @@ struct ZCC_Struct : ZCC_NamedNode
|
|||
VM_UWORD Flags;
|
||||
ZCC_TreeNode *Body;
|
||||
PStruct *Type;
|
||||
VersionInfo Version;
|
||||
};
|
||||
|
||||
struct ZCC_Property : ZCC_NamedNode
|
||||
|
@ -479,6 +485,7 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode
|
|||
struct ZCC_DeclFlags : ZCC_TreeNode
|
||||
{
|
||||
ZCC_Identifier *Id;
|
||||
VersionInfo Version;
|
||||
int Flags;
|
||||
};
|
||||
|
||||
|
@ -493,6 +500,7 @@ struct ZCC_Declarator : ZCC_TreeNode
|
|||
{
|
||||
ZCC_Type *Type;
|
||||
int Flags;
|
||||
VersionInfo Version;
|
||||
};
|
||||
|
||||
// A variable in a class or struct.
|
||||
|
@ -538,6 +546,7 @@ struct ZCC_AST
|
|||
FSharedStringArena Strings;
|
||||
FMemArena SyntaxArena;
|
||||
struct ZCC_TreeNode *TopNode;
|
||||
VersionInfo ParseVersion;
|
||||
};
|
||||
|
||||
struct ZCCParseState : public ZCC_AST
|
||||
|
|
|
@ -1208,7 +1208,7 @@ DEFINE_ACTION_FUNCTION(_TexMan, GetSize)
|
|||
}
|
||||
else x = y = -1;
|
||||
if (numret > 0) ret[0].SetInt(x);
|
||||
if (numret > 1) ret[1].SetInt(x);
|
||||
if (numret > 1) ret[1].SetInt(y);
|
||||
return MIN(numret, 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "colormatcher.h"
|
||||
#include "v_palette.h"
|
||||
#include "d_player.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
CVAR( Float, blood_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Pulled from Skulltag - changed default from 0.5 to 1.0
|
||||
CVAR( Float, pickup_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Uses same logic as blood_fade_scalar except for pickups
|
||||
|
@ -168,13 +169,19 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
|
|||
{
|
||||
if (CPlayer->hazardcount > 16*TICRATE || (CPlayer->hazardcount & 8))
|
||||
{
|
||||
V_AddBlend (0.f, 1.f, 0.f, 0.125f, blend);
|
||||
float r = ((level.hazardflash & 0xff0000) >> 16) / 255.f;
|
||||
float g = ((level.hazardflash & 0xff00) >> 8) / 255.f;
|
||||
float b = ((level.hazardflash & 0xff)) / 255.f;
|
||||
V_AddBlend (r, g, b, 0.125f, blend);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt= MIN(CPlayer->hazardcount/8, 64);
|
||||
V_AddBlend (0.f, 0.2571f, 0.f, cnt/93.2571428571f, blend);
|
||||
float r = ((level.hazardcolor & 0xff0000) >> 16) / 255.f;
|
||||
float g = ((level.hazardcolor & 0xff00) >> 8) / 255.f;
|
||||
float b = ((level.hazardcolor & 0xff)) / 255.f;
|
||||
V_AddBlend (r, g, b, cnt/93.2571428571f, blend);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ FRenderer *Renderer;
|
|||
|
||||
IMPLEMENT_CLASS(DCanvas, true, false)
|
||||
IMPLEMENT_CLASS(DFrameBuffer, true, false)
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
|
||||
#if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__)
|
||||
#define DBGBREAK { __asm int 3 }
|
||||
|
@ -1490,6 +1491,9 @@ CCMD (vid_setmode)
|
|||
goodmode = true;
|
||||
}
|
||||
|
||||
if (!fullscreen)
|
||||
goodmode = true;
|
||||
|
||||
if (goodmode)
|
||||
{
|
||||
// The actual change of resolution will take place
|
||||
|
|
|
@ -53,6 +53,10 @@ const char *GetVersionString();
|
|||
#define RC_FILEVERSION 2,3,9999,0
|
||||
#define RC_PRODUCTVERSION 2,3,9999,0
|
||||
#define RC_PRODUCTVERSION2 VERSIONSTR
|
||||
// These are for content versioning. The current state is '2.4'.
|
||||
#define VER_MAJOR 2
|
||||
#define VER_MINOR 4
|
||||
#define VER_REVISION 0
|
||||
|
||||
// Version identifier for network games.
|
||||
// Bump it every time you do a release unless you're certain you
|
||||
|
|
|
@ -450,13 +450,4 @@ template<> struct THashTraits<FString>
|
|||
int Compare(const FString &left, const FString &right) { return left.Compare(right); }
|
||||
};
|
||||
|
||||
class FStringNoInit
|
||||
{
|
||||
char mem[sizeof(FString)];
|
||||
operator FString&()
|
||||
{
|
||||
return *reinterpret_cast<FString*>(&mem);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
version "2.4"
|
||||
#include "zscript/base.txt"
|
||||
#include "zscript/sounddata.txt"
|
||||
#include "zscript/mapdata.txt"
|
||||
|
|
|
@ -237,17 +237,17 @@ class Actor : Thinker native
|
|||
//int ConversationRoot; // THe root of the current dialogue
|
||||
|
||||
// deprecated things.
|
||||
native readonly deprecated double X;
|
||||
native readonly deprecated double Y;
|
||||
native readonly deprecated double Z;
|
||||
native readonly deprecated double VelX;
|
||||
native readonly deprecated double VelY;
|
||||
native readonly deprecated double VelZ;
|
||||
native readonly deprecated double MomX;
|
||||
native readonly deprecated double MomY;
|
||||
native readonly deprecated double MomZ;
|
||||
native deprecated double ScaleX;
|
||||
native deprecated double ScaleY;
|
||||
native readonly deprecated("2.3") double X;
|
||||
native readonly deprecated("2.3") double Y;
|
||||
native readonly deprecated("2.3") double Z;
|
||||
native readonly deprecated("2.3") double VelX;
|
||||
native readonly deprecated("2.3") double VelY;
|
||||
native readonly deprecated("2.3") double VelZ;
|
||||
native readonly deprecated("2.3") double MomX;
|
||||
native readonly deprecated("2.3") double MomY;
|
||||
native readonly deprecated("2.3") double MomZ;
|
||||
native deprecated("2.3") double ScaleX;
|
||||
native deprecated("2.3") double ScaleY;
|
||||
|
||||
//FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.;
|
||||
|
||||
|
@ -450,13 +450,13 @@ class Actor : Thinker native
|
|||
native static int FindUniqueTid(int start = 0, int limit = 0);
|
||||
native void SetShade(color col);
|
||||
|
||||
native string GetTag(string defstr = "");
|
||||
native string GetTag(string defstr = "") const;
|
||||
native void SetTag(string defstr = "");
|
||||
native double GetBobOffset(double frac = 0);
|
||||
native void ClearCounters();
|
||||
native bool GiveBody (int num, int max=0);
|
||||
native bool HitFloor();
|
||||
native bool isTeammate(Actor other);
|
||||
native bool isTeammate(Actor other) const;
|
||||
native int PlayerNumber();
|
||||
native void SetFriendPlayer(PlayerInfo player);
|
||||
native void SoundAlert(Actor target, bool splash = false, double maxdist = 0);
|
||||
|
@ -468,15 +468,15 @@ class Actor : Thinker native
|
|||
native bool UpdateWaterLevel (bool splash = true);
|
||||
native bool IsZeroDamage();
|
||||
native void ClearInterpolation();
|
||||
native Vector3 PosRelative(sector sec);
|
||||
native Vector3 PosRelative(sector sec) const;
|
||||
|
||||
native void HandleSpawnFlags();
|
||||
native void ExplodeMissile(line lin = null, Actor target = null, bool onsky = false);
|
||||
native void RestoreDamage();
|
||||
native int SpawnHealth();
|
||||
native int SpawnHealth() const;
|
||||
native void SetDamage(int dmg);
|
||||
native double Distance2D(Actor other);
|
||||
native double Distance3D(Actor other);
|
||||
native double Distance2D(Actor other) const;
|
||||
native double Distance3D(Actor other) const;
|
||||
native void SetOrigin(vector3 newpos, bool moving);
|
||||
native void SetXYZ(vector3 newpos);
|
||||
native Actor GetPointer(int aaptr);
|
||||
|
@ -511,7 +511,7 @@ class Actor : Thinker native
|
|||
native void BloodSplatter (Vector3 pos, double hitangle, bool axe = false);
|
||||
native bool HitWater (sector sec, Vector3 pos, bool checkabove = false, bool alert = true, bool force = false);
|
||||
native void PlaySpawnSound(Actor missile);
|
||||
native bool CountsAsKill();
|
||||
native bool CountsAsKill() const;
|
||||
|
||||
native bool Teleport(Vector3 pos, double angle, int flags);
|
||||
native void TraceBleed(int damage, Actor missile);
|
||||
|
@ -559,21 +559,21 @@ class Actor : Thinker native
|
|||
native void LinkToWorld(LinkContext ctx = null);
|
||||
native void UnlinkFromWorld(out LinkContext ctx = null);
|
||||
native bool CanSeek(Actor target);
|
||||
native double AngleTo(Actor target, bool absolute = false);
|
||||
native double AngleTo(Actor target, bool absolute = false) const;
|
||||
native void AddZ(double zadd, bool moving = true);
|
||||
native void SetZ(double z);
|
||||
native vector2 Vec2To(Actor other);
|
||||
native vector3 Vec3To(Actor other);
|
||||
native vector3 Vec3Offset(double x, double y, double z, bool absolute = false);
|
||||
native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false);
|
||||
native vector2 Vec2Angle(double length, double angle, bool absolute = false);
|
||||
native vector2 Vec2Offset(double x, double y, bool absolute = false);
|
||||
native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false);
|
||||
native void VelFromAngle(double speed = 0, double angle = 0);
|
||||
native void Vel3DFromAngle(double speed, double angle, double pitch);
|
||||
native vector2 Vec2To(Actor other) const;
|
||||
native vector3 Vec3To(Actor other) const;
|
||||
native vector3 Vec3Offset(double x, double y, double z, bool absolute = false) const;
|
||||
native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false) const;
|
||||
native vector2 Vec2Angle(double length, double angle, bool absolute = false) const;
|
||||
native vector2 Vec2Offset(double x, double y, bool absolute = false) const;
|
||||
native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const;
|
||||
native void VelFromAngle(double speed = 0, double angle = 0) const;
|
||||
native void Vel3DFromAngle(double speed, double angle, double pitch) const;
|
||||
native void Thrust(double speed = 0, double angle = 0);
|
||||
native bool isFriend(Actor other);
|
||||
native bool isHostile(Actor other);
|
||||
native bool isFriend(Actor other) const;
|
||||
native bool isHostile(Actor other) const;
|
||||
native void AdjustFloorClip();
|
||||
native DropItem GetDropItems();
|
||||
native void CopyFriendliness (Actor other, bool changeTarget, bool resetHealth = true);
|
||||
|
@ -588,8 +588,8 @@ class Actor : Thinker native
|
|||
native void Howl();
|
||||
native void DrawSplash (int count, double angle, int kind);
|
||||
native void GiveSecret(bool printmsg = true, bool playsound = true);
|
||||
native double GetCameraHeight();
|
||||
native double GetGravity();
|
||||
native double GetCameraHeight() const;
|
||||
native double GetGravity() const;
|
||||
|
||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
||||
native void AddInventory(Inventory inv);
|
||||
|
@ -597,7 +597,7 @@ class Actor : Thinker native
|
|||
native void ClearInventory();
|
||||
native bool GiveInventory(class<Inventory> type, int amount, bool givecheat = false);
|
||||
native bool TakeInventory(class<Inventory> itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false);
|
||||
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false);
|
||||
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false) const;
|
||||
native Inventory GiveInventoryType(class<Inventory> itemtype);
|
||||
native Inventory DropInventory (Inventory item, int amt = -1);
|
||||
native bool UseInventory(Inventory item);
|
||||
|
@ -613,7 +613,7 @@ class Actor : Thinker native
|
|||
native double GetDistance(bool checkz, int ptr = AAPTR_TARGET);
|
||||
native double GetAngle(int flags, int ptr = AAPTR_TARGET);
|
||||
native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT);
|
||||
native int GetSpawnHealth();
|
||||
native int GetSpawnHealth() const;
|
||||
native double GetCrouchFactor(int ptr = AAPTR_PLAYER1);
|
||||
native double GetCVar(string cvar);
|
||||
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
|
||||
|
@ -716,7 +716,7 @@ class Actor : Thinker native
|
|||
return true;
|
||||
}
|
||||
|
||||
deprecated void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
|
||||
deprecated("2.3") void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
|
||||
|
||||
void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0)
|
||||
{
|
||||
|
@ -867,18 +867,18 @@ class Actor : Thinker native
|
|||
}
|
||||
}
|
||||
|
||||
deprecated void A_MeleeAttack()
|
||||
deprecated("2.3") void A_MeleeAttack()
|
||||
{
|
||||
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
}
|
||||
|
||||
deprecated void A_MissileAttack()
|
||||
deprecated("2.3") void A_MissileAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
deprecated void A_ComboAttack()
|
||||
deprecated("2.3") void A_ComboAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
|
||||
|
@ -918,13 +918,13 @@ class Actor : Thinker native
|
|||
native void A_Wander(int flags = 0);
|
||||
native void A_Look2();
|
||||
|
||||
deprecated native void A_BulletAttack();
|
||||
deprecated("2.3") native void A_BulletAttack();
|
||||
native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class<Actor> pufftype = "BulletPuff");
|
||||
native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false);
|
||||
deprecated void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); }
|
||||
deprecated("2.3") void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); }
|
||||
native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was...
|
||||
deprecated native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
|
||||
deprecated native void A_StopSoundEx(name slot);
|
||||
deprecated("2.3") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
|
||||
deprecated("2.3") native void A_StopSoundEx(name slot);
|
||||
native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
|
||||
native action state A_Jump(int chance, statelabel label, ...);
|
||||
native Actor A_SpawnProjectile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET);
|
||||
|
@ -950,7 +950,7 @@ class Actor : Thinker native
|
|||
native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
|
||||
native void A_DropInventory(class<Inventory> itemtype, int amount = -1);
|
||||
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0);
|
||||
deprecated native void A_ChangeFlag(string flagname, bool value);
|
||||
deprecated("2.3") native void A_ChangeFlag(string flagname, bool value);
|
||||
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
|
||||
native void A_RaiseMaster(int flags = 0);
|
||||
native void A_RaiseChildren(int flags = 0);
|
||||
|
@ -989,10 +989,10 @@ class Actor : Thinker native
|
|||
native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
native void A_ScaleVelocity(double scale, int ptr = AAPTR_DEFAULT);
|
||||
native void A_ChangeVelocity(double x = 0, double y = 0, double z = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
deprecated native void A_SetUserVar(name varname, int value);
|
||||
deprecated native void A_SetUserArray(name varname, int index, int value);
|
||||
deprecated native void A_SetUserVarFloat(name varname, double value);
|
||||
deprecated native void A_SetUserArrayFloat(name varname, int index, double value);
|
||||
deprecated("2.3") native void A_SetUserVar(name varname, int value);
|
||||
deprecated("2.3") native void A_SetUserArray(name varname, int index, int value);
|
||||
deprecated("2.3") native void A_SetUserVarFloat(name varname, double value);
|
||||
deprecated("2.3") native void A_SetUserArrayFloat(name varname, int index, double value);
|
||||
native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake");
|
||||
native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0);
|
||||
action native void A_SetTics(int tics);
|
||||
|
@ -1090,7 +1090,7 @@ class Actor : Thinker native
|
|||
}
|
||||
|
||||
// Internal functions
|
||||
deprecated private native int __decorate_internal_int__(int i);
|
||||
deprecated private native bool __decorate_internal_bool__(bool b);
|
||||
deprecated private native double __decorate_internal_float__(double f);
|
||||
deprecated("2.3") private native int __decorate_internal_int__(int i);
|
||||
deprecated("2.3") private native bool __decorate_internal_bool__(bool b);
|
||||
deprecated("2.3") private native double __decorate_internal_float__(double f);
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ extend class Actor
|
|||
|
||||
private native bool CheckFlag(string flagname, int check_pointer = AAPTR_DEFAULT);
|
||||
|
||||
deprecated action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
|
||||
deprecated("2.3") action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
|
||||
{
|
||||
return CheckFlag(flagname, check_pointer)? ResolveState(label) : null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct InputEventData native
|
||||
struct InputEventData native version("2.4")
|
||||
{
|
||||
native uint8 type;
|
||||
native uint8 subtype;
|
||||
|
@ -244,7 +244,7 @@ struct Font native
|
|||
native BrokenLines BreakLines(String text, int maxlen);
|
||||
}
|
||||
|
||||
struct Translation
|
||||
struct Translation version("2.4")
|
||||
{
|
||||
Color colors[256];
|
||||
|
||||
|
@ -290,7 +290,7 @@ struct CVar native
|
|||
native int ResetToDefault();
|
||||
}
|
||||
|
||||
struct GIFont
|
||||
struct GIFont version("2.4")
|
||||
{
|
||||
Name fontname;
|
||||
Name color;
|
||||
|
@ -331,20 +331,20 @@ class Object native
|
|||
native static uint MSTime();
|
||||
|
||||
native Name GetClassName();
|
||||
native void Destroy();
|
||||
native virtualscope void Destroy();
|
||||
|
||||
// This does not call into the native method of the same name to avoid problems with objects that get garbage collected late on shutdown.
|
||||
virtual void OnDestroy() {}
|
||||
virtual virtualscope void OnDestroy() {}
|
||||
}
|
||||
|
||||
class BrokenLines : Object native
|
||||
class BrokenLines : Object native version("2.4")
|
||||
{
|
||||
native int Count();
|
||||
native int StringWidth(int line);
|
||||
native String StringAt(int line);
|
||||
}
|
||||
|
||||
class Thinker : Object native
|
||||
class Thinker : Object native play
|
||||
{
|
||||
enum EStatnums
|
||||
{
|
||||
|
@ -386,7 +386,6 @@ class Thinker : Object native
|
|||
|
||||
class ThinkerIterator : Object native
|
||||
{
|
||||
|
||||
native static ThinkerIterator Create(class<Object> type = "Actor", int statnum=Thinker.MAX_STATNUM+1);
|
||||
native Thinker Next(bool exact = false);
|
||||
native void Reinit();
|
||||
|
@ -459,23 +458,23 @@ struct LevelLocals native
|
|||
native int found_items;
|
||||
native int total_monsters;
|
||||
native int killed_monsters;
|
||||
native double gravity;
|
||||
native double aircontrol;
|
||||
native double airfriction;
|
||||
native int airsupply;
|
||||
native double teamdamage;
|
||||
native bool monsterstelefrag;
|
||||
native bool actownspecial;
|
||||
native bool sndseqtotalctrl;
|
||||
native play double gravity;
|
||||
native play double aircontrol;
|
||||
native play double airfriction;
|
||||
native play int airsupply;
|
||||
native readonly double teamdamage;
|
||||
native readonly bool monsterstelefrag;
|
||||
native readonly bool actownspecial;
|
||||
native readonly bool sndseqtotalctrl;
|
||||
native bool allmap;
|
||||
native bool missilesactivateimpact;
|
||||
native bool monsterfallingdamage;
|
||||
native bool checkswitchrange;
|
||||
native bool polygrind;
|
||||
native bool nomonsters;
|
||||
native readonly bool missilesactivateimpact;
|
||||
native readonly bool monsterfallingdamage;
|
||||
native readonly bool checkswitchrange;
|
||||
native readonly bool polygrind;
|
||||
native readonly bool nomonsters;
|
||||
native bool frozen;
|
||||
native bool infinite_flight;
|
||||
native bool no_dlg_freeze;
|
||||
native readonly bool infinite_flight;
|
||||
native readonly bool no_dlg_freeze;
|
||||
// level_info_t *info cannot be done yet.
|
||||
|
||||
native String GetUDMFString(int type, int index, Name key);
|
||||
|
@ -619,7 +618,7 @@ class Floor : Thinker native
|
|||
floorRaiseInstant,
|
||||
floorMoveToValue,
|
||||
floorRaiseToLowestCeiling,
|
||||
floorRaiseuint8xture,
|
||||
floorRaiseByTexture,
|
||||
|
||||
floorLowerAndChange,
|
||||
floorRaiseAndChange,
|
||||
|
@ -627,7 +626,7 @@ class Floor : Thinker native
|
|||
floorRaiseToLowest,
|
||||
floorRaiseToCeiling,
|
||||
floorLowerToLowestCeiling,
|
||||
floorLoweruint8xture,
|
||||
floorLowerByTexture,
|
||||
floorLowerToCeiling,
|
||||
|
||||
donutRaise,
|
||||
|
@ -670,8 +669,8 @@ class Ceiling : Thinker native
|
|||
ceilLowerToNearest,
|
||||
ceilRaiseToHighestFloor,
|
||||
ceilRaiseToFloor,
|
||||
ceilRaiseuint8xture,
|
||||
ceilLoweruint8xture,
|
||||
ceilRaiseByTexture,
|
||||
ceilLowerByTexture,
|
||||
|
||||
genCeilingChg0,
|
||||
genCeilingChgT,
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
extend class Object
|
||||
{
|
||||
deprecated static int GameType() // deprecated for 2.4.x
|
||||
deprecated("2.4") static int GameType()
|
||||
{
|
||||
return gameinfo.gametype;
|
||||
}
|
||||
|
||||
deprecated static void C_MidPrint(string fontname, string textlabel, bool bold = false) // deprecated for 2.4.x
|
||||
deprecated("2.4") static void C_MidPrint(string fontname, string textlabel, bool bold = false)
|
||||
{
|
||||
let f = Font.GetFont(fontname);
|
||||
if (f == null) return;
|
||||
|
@ -18,7 +18,7 @@ extend class Object
|
|||
|
||||
extend class Actor
|
||||
{
|
||||
deprecated void A_CustomMissile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET)
|
||||
deprecated("2.3") void A_CustomMissile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET)
|
||||
{
|
||||
A_SpawnProjectile(missiletype, spawnheight, spawnofs_xy, angle, flags|CMF_BADPITCH, pitch, ptr);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ extend class Actor
|
|||
|
||||
extend class StateProvider
|
||||
{
|
||||
deprecated action void A_FireCustomMissile(class<Actor> missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0)
|
||||
deprecated("2.3") action void A_FireCustomMissile(class<Actor> missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0)
|
||||
{
|
||||
A_FireProjectile(missiletype, angle, useammo, spawnofs_xy, spawnheight, flags, -pitch);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class BaseEvent native { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything.
|
||||
class BaseEvent native version("2.4") { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything.
|
||||
|
||||
class RenderEvent : BaseEvent native
|
||||
class RenderEvent : BaseEvent native ui version("2.4")
|
||||
{
|
||||
native readonly Vector3 ViewPos;
|
||||
native readonly double ViewAngle;
|
||||
|
@ -10,7 +10,7 @@ class RenderEvent : BaseEvent native
|
|||
native readonly Actor Camera;
|
||||
}
|
||||
|
||||
class WorldEvent : BaseEvent native
|
||||
class WorldEvent : BaseEvent native play version("2.4")
|
||||
{
|
||||
// for loaded/unloaded
|
||||
native readonly bool IsSaveGame;
|
||||
|
@ -28,7 +28,7 @@ class WorldEvent : BaseEvent native
|
|||
native readonly double DamageAngle;
|
||||
}
|
||||
|
||||
class PlayerEvent : BaseEvent native
|
||||
class PlayerEvent : BaseEvent native play version("2.4")
|
||||
{
|
||||
// this is the player number that caused the event.
|
||||
// note: you can get player struct from this by using players[e.PlayerNumber]
|
||||
|
@ -37,7 +37,7 @@ class PlayerEvent : BaseEvent native
|
|||
native readonly bool IsReturn;
|
||||
}
|
||||
|
||||
class UiEvent : BaseEvent native
|
||||
class UiEvent : BaseEvent native ui version("2.4")
|
||||
{
|
||||
// d_gui.h
|
||||
enum EGUIEvent
|
||||
|
@ -121,7 +121,7 @@ class UiEvent : BaseEvent native
|
|||
native readonly bool IsAlt;
|
||||
}
|
||||
|
||||
class InputEvent : BaseEvent native
|
||||
class InputEvent : BaseEvent native play version("2.4")
|
||||
{
|
||||
enum EGenericEvent
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ class InputEvent : BaseEvent native
|
|||
native readonly int MouseY;
|
||||
}
|
||||
|
||||
class ConsoleEvent : BaseEvent native
|
||||
class ConsoleEvent : BaseEvent native version("2.4")
|
||||
{
|
||||
// for net events, this will be the activator.
|
||||
// for UI events, this is always -1, and you need to check if level is loaded and use players[consoleplayer].
|
||||
|
@ -279,16 +279,16 @@ class ConsoleEvent : BaseEvent native
|
|||
native readonly int Args[3];
|
||||
}
|
||||
|
||||
class StaticEventHandler : Object native
|
||||
class StaticEventHandler : Object native play version("2.4")
|
||||
{
|
||||
// static event handlers CAN register other static event handlers.
|
||||
// unlike EventHandler.Create that will not create them.
|
||||
protected static native StaticEventHandler Create(class<StaticEventHandler> type);
|
||||
protected static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
|
||||
protected static native StaticEventHandler Find(Class<StaticEventHandler> type); // just for convenience. who knows.
|
||||
clearscope static native StaticEventHandler Create(class<StaticEventHandler> type);
|
||||
clearscope static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
|
||||
clearscope static native StaticEventHandler Find(Class<StaticEventHandler> type); // just for convenience. who knows.
|
||||
|
||||
protected static native bool Register(StaticEventHandler handler);
|
||||
protected static native bool Unregister(StaticEventHandler handler);
|
||||
clearscope static native bool Register(StaticEventHandler handler);
|
||||
clearscope static native bool Unregister(StaticEventHandler handler);
|
||||
|
||||
// these are called when the handler gets registered or unregistered
|
||||
// you can set Order/IsUiProcessor here.
|
||||
|
@ -307,8 +307,8 @@ class StaticEventHandler : Object native
|
|||
virtual native void WorldTick(WorldEvent e);
|
||||
|
||||
//
|
||||
virtual native void RenderFrame(RenderEvent e);
|
||||
virtual native void RenderOverlay(RenderEvent e);
|
||||
virtual native ui void RenderFrame(RenderEvent e);
|
||||
virtual native ui void RenderOverlay(RenderEvent e);
|
||||
|
||||
//
|
||||
virtual native void PlayerEntered(PlayerEvent e);
|
||||
|
@ -317,11 +317,12 @@ class StaticEventHandler : Object native
|
|||
virtual native void PlayerDisconnected(PlayerEvent e);
|
||||
|
||||
//
|
||||
virtual native bool UiProcess(UiEvent e);
|
||||
virtual native ui bool UiProcess(UiEvent e);
|
||||
virtual native bool InputProcess(InputEvent e);
|
||||
|
||||
//
|
||||
virtual native void ConsoleProcess(ConsoleEvent e);
|
||||
virtual native ui void ConsoleProcess(ConsoleEvent e);
|
||||
virtual native void NetworkProcess(ConsoleEvent e);
|
||||
|
||||
// this value will be queried on Register() to decide the relative order of this handler to every other.
|
||||
// this is most useful in UI systems.
|
||||
|
@ -334,12 +335,14 @@ class StaticEventHandler : Object native
|
|||
native bool RequireMouse;
|
||||
}
|
||||
|
||||
class EventHandler : StaticEventHandler native
|
||||
class EventHandler : StaticEventHandler native version("2.4")
|
||||
{
|
||||
static native StaticEventHandler Create(class<StaticEventHandler> type);
|
||||
static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
|
||||
static native StaticEventHandler Find(class<StaticEventHandler> type);
|
||||
clearscope static native StaticEventHandler Create(class<StaticEventHandler> type);
|
||||
clearscope static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
|
||||
clearscope static native StaticEventHandler Find(class<StaticEventHandler> type);
|
||||
|
||||
static native bool Register(StaticEventHandler handler);
|
||||
static native bool Unregister(StaticEventHandler handler);
|
||||
clearscope static native bool Register(StaticEventHandler handler);
|
||||
clearscope static native bool Unregister(StaticEventHandler handler);
|
||||
|
||||
clearscope static native void SendNetworkEvent(String name, int arg1 = 0, int arg2 = 0, int arg3 = 0);
|
||||
}
|
||||
|
|
|
@ -751,7 +751,7 @@ class Inventory : Actor native
|
|||
virtual bool Use (bool pickup) { return false; }
|
||||
virtual double GetSpeedFactor() { return 1; }
|
||||
virtual bool GetNoTeleportFreeze() { return false; }
|
||||
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
|
||||
virtual version("2.4") ui void AlterWeaponSprite(VisStyle vis, in out int changed) {}
|
||||
virtual void OwnerDied() {}
|
||||
virtual Color GetBlend () { return 0; }
|
||||
|
||||
|
@ -818,7 +818,7 @@ class Inventory : Actor native
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
virtual bool DrawPowerup(int x, int y) { return false; }
|
||||
virtual ui version("2.4") bool DrawPowerup(int x, int y) { return false; }
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
|
@ -285,7 +285,7 @@ class Powerup : Inventory
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
virtual bool isBlinking()
|
||||
virtual bool isBlinking() const
|
||||
{
|
||||
return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !bNoScreenBlink);
|
||||
}
|
||||
|
@ -934,7 +934,7 @@ class PowerFlight : Powerup
|
|||
+INVENTORY.HUBPOWER
|
||||
}
|
||||
|
||||
bool HitCenterFrame;
|
||||
ui bool HitCenterFrame;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
|
@ -31,10 +31,10 @@ class CustomInventory : StateProvider
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
// This is only here, because these functions were originally exported on Inventory, despite only working for weapons, so this is here to satisfy some potential old mods having called it through CustomInventory.
|
||||
deprecated action void A_GunFlash(statelabel flash = null, int flags = 0) {}
|
||||
deprecated action void A_Lower() {}
|
||||
deprecated action void A_Raise() {}
|
||||
deprecated action void A_CheckReload() {}
|
||||
deprecated("2.3") action void A_GunFlash(statelabel flash = null, int flags = 0) {}
|
||||
deprecated("2.3") action void A_Lower() {}
|
||||
deprecated("2.3") action void A_Raise() {}
|
||||
deprecated("2.3") action void A_CheckReload() {}
|
||||
native bool CallStateChain (Actor actor, State state);
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
struct SectorPortal native
|
||||
struct SectorPortal native play
|
||||
{
|
||||
enum EType
|
||||
{
|
||||
|
@ -31,12 +31,12 @@ struct SectorPortal native
|
|||
};
|
||||
|
||||
|
||||
struct Vertex native
|
||||
struct Vertex native play
|
||||
{
|
||||
native readonly Vector2 p;
|
||||
}
|
||||
|
||||
struct Side native
|
||||
struct Side native play
|
||||
{
|
||||
enum ETexpart
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ struct Side native
|
|||
|
||||
};
|
||||
|
||||
struct Line native
|
||||
struct Line native play
|
||||
{
|
||||
enum ELineFlags
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ struct Line native
|
|||
native int special;
|
||||
native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
|
||||
native double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque)
|
||||
native Side sidedef[2];
|
||||
native readonly Side sidedef[2];
|
||||
native readonly double bbox[4]; // bounding box, for the extent of the LineDef.
|
||||
native readonly Sector frontsector, backsector;
|
||||
native int validcount; // if == validcount, already checked
|
||||
|
@ -171,25 +171,25 @@ struct Line native
|
|||
}
|
||||
}
|
||||
|
||||
struct SecPlane native
|
||||
struct SecPlane native play
|
||||
{
|
||||
native Vector3 Normal;
|
||||
native double D;
|
||||
native double negiC;
|
||||
|
||||
native bool isSlope();
|
||||
native int PointOnSide(Vector3 pos);
|
||||
native double ZatPoint (Vector2 v);
|
||||
native double ZatPointDist(Vector2 v, double dist);
|
||||
native bool isEqual(Secplane other);
|
||||
native bool isSlope() const;
|
||||
native int PointOnSide(Vector3 pos) const;
|
||||
native double ZatPoint (Vector2 v) const;
|
||||
native double ZatPointDist(Vector2 v, double dist) const;
|
||||
native bool isEqual(Secplane other) const;
|
||||
native void ChangeHeight(double hdiff);
|
||||
native double GetChangedHeight(double hdiff);
|
||||
native double GetChangedHeight(double hdiff) const;
|
||||
native double HeightDiff(double oldd, double newd = 0.0);
|
||||
native double PointToDist(Vector2 xy, double z);
|
||||
native double PointToDist(Vector2 xy, double z) const;
|
||||
}
|
||||
|
||||
// This encapsulates all info Doom's original 'special' field contained - for saving and transferring.
|
||||
struct SecSpecial
|
||||
struct SecSpecial play
|
||||
{
|
||||
Name damagetype;
|
||||
int damageamount;
|
||||
|
@ -199,7 +199,7 @@ struct SecSpecial
|
|||
int Flags;
|
||||
}
|
||||
|
||||
struct Sector native
|
||||
struct Sector native play
|
||||
{
|
||||
//secplane_t floorplane, ceilingplane; // defined internally
|
||||
//FDynamicColormap *ColorMap;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
**
|
||||
*/
|
||||
|
||||
struct StrifeDialogueNode native
|
||||
struct StrifeDialogueNode native version("2.4")
|
||||
{
|
||||
native Class<Actor> DropType;
|
||||
native int ThisNodeNum;
|
||||
|
@ -49,7 +49,7 @@ struct StrifeDialogueNode native
|
|||
}
|
||||
|
||||
// FStrifeDialogueReply holds responses the player can give to the NPC
|
||||
struct StrifeDialogueReply native
|
||||
struct StrifeDialogueReply native version("2.4")
|
||||
{
|
||||
native StrifeDialogueReply Next;
|
||||
native Class<Actor> GiveType;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
struct KeyBindings native
|
||||
struct KeyBindings native version("2.4")
|
||||
{
|
||||
native static String NameKeys(int k1, int k2);
|
||||
|
||||
|
@ -8,7 +8,7 @@ struct KeyBindings native
|
|||
native void UnbindACommand (String str);
|
||||
}
|
||||
|
||||
struct OptionValues native
|
||||
struct OptionValues native version("2.4")
|
||||
{
|
||||
native static int GetCount(Name group);
|
||||
native static String GetText(Name group, int index);
|
||||
|
@ -16,7 +16,7 @@ struct OptionValues native
|
|||
native static String GetTextValue(Name group, int index);
|
||||
}
|
||||
|
||||
struct JoystickConfig native
|
||||
struct JoystickConfig native version("2.4")
|
||||
{
|
||||
enum EJoyAxis
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ struct JoystickConfig native
|
|||
|
||||
}
|
||||
|
||||
class Menu : Object native
|
||||
class Menu : Object native ui version("2.4")
|
||||
{
|
||||
enum EMenuKey
|
||||
{
|
||||
|
@ -287,7 +287,7 @@ class Menu : Object native
|
|||
|
||||
}
|
||||
|
||||
class MenuDescriptor : Object native
|
||||
class MenuDescriptor : Object native ui version("2.4")
|
||||
{
|
||||
native Name mMenuName;
|
||||
native String mNetgameMessage;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
class MenuItemBase : Object native
|
||||
class MenuItemBase : Object native ui version("2.4")
|
||||
{
|
||||
protected native double mXpos, mYpos;
|
||||
protected native Name mAction;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
**
|
||||
*/
|
||||
|
||||
struct FOptionMenuSettings
|
||||
struct FOptionMenuSettings version("2.4")
|
||||
{
|
||||
int mTitleColor;
|
||||
int mFontColor;
|
||||
|
|
|
@ -150,7 +150,7 @@ class PlayerPawn : Actor native
|
|||
}
|
||||
|
||||
// This is for SBARINFO.
|
||||
int, int GetEffectTicsForItem(class<Inventory> item)
|
||||
int, int GetEffectTicsForItem(class<Inventory> item) const
|
||||
{
|
||||
let pg = (class<PowerupGiver>)(item);
|
||||
if (pg != null)
|
||||
|
@ -167,10 +167,10 @@ class PlayerPawn : Actor native
|
|||
return -1, -1;
|
||||
}
|
||||
|
||||
native int GetMaxHealth(bool withupgrades = false);
|
||||
native int GetMaxHealth(bool withupgrades = false) const;
|
||||
native bool ResetAirSupply (bool playgasp = false);
|
||||
native void CheckWeaponSwitch(class<Inventory> item);
|
||||
native static String GetPrintableDisplayName(Class<Actor> cls);
|
||||
native clearscope static String GetPrintableDisplayName(Class<Actor> cls);
|
||||
|
||||
}
|
||||
|
||||
|
@ -192,7 +192,7 @@ class PlayerChunk : PlayerPawn
|
|||
}
|
||||
}
|
||||
|
||||
class PSprite : Object native
|
||||
class PSprite : Object native play
|
||||
{
|
||||
enum PSPLayers
|
||||
{
|
||||
|
@ -237,7 +237,7 @@ enum EPlayerState
|
|||
PST_GONE // Player has left the game
|
||||
}
|
||||
|
||||
struct PlayerInfo native // this is what internally is known as player_t
|
||||
struct PlayerInfo native play // this is what internally is known as player_t
|
||||
{
|
||||
// technically engine constants but the only part of the playsim using them is the player.
|
||||
const NOFIXEDCOLORMAP = -1;
|
||||
|
@ -338,22 +338,22 @@ usercmd_t original_cmd;
|
|||
native void PoisonDamage(Actor source, int damage, bool playPainSound);
|
||||
native void SetPsprite(int id, State stat, bool pending = false);
|
||||
native void SetSafeFlash(Weapon weap, State flashstate, int index);
|
||||
native PSprite GetPSprite(int id);
|
||||
native PSprite FindPSprite(int id);
|
||||
native PSprite GetPSprite(int id) const;
|
||||
native PSprite FindPSprite(int id) const;
|
||||
native void SetLogNumber (int text);
|
||||
native void SetLogText (String text);
|
||||
native void DropWeapon();
|
||||
native void BringUpWeapon();
|
||||
|
||||
native String GetUserName();
|
||||
native Color GetColor();
|
||||
native int GetColorSet();
|
||||
native int GetPlayerClassNum();
|
||||
native int GetSkin();
|
||||
native bool GetNeverSwitch();
|
||||
native int GetGender();
|
||||
native int GetTeam();
|
||||
native float GetAutoaim();
|
||||
native String GetUserName() const;
|
||||
native Color GetColor() const;
|
||||
native int GetColorSet() const;
|
||||
native int GetPlayerClassNum() const;
|
||||
native int GetSkin() const;
|
||||
native bool GetNeverSwitch() const;
|
||||
native int GetGender() const;
|
||||
native int GetTeam() const;
|
||||
native float GetAutoaim() const;
|
||||
native void SetFOV(float fov);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// INTERMISSION
|
||||
// Structure passed e.g. to WI_Start(wb)
|
||||
//
|
||||
struct WBPlayerStruct native
|
||||
struct WBPlayerStruct native version("2.4")
|
||||
{
|
||||
// Player stats, kills, collected items etc.
|
||||
native int skills;
|
||||
|
@ -14,7 +14,7 @@ struct WBPlayerStruct native
|
|||
native int fragcount; // [RH] Cumulative frags for this player
|
||||
}
|
||||
|
||||
struct WBStartStruct native
|
||||
struct WBStartStruct native version("2.4")
|
||||
{
|
||||
native int finished_ep;
|
||||
native int next_ep;
|
||||
|
|
Loading…
Reference in a new issue