Merge branch '4.14.2' into gz_merge

This commit is contained in:
Ricardo Luís Vaz Silva 2025-05-02 17:15:41 -03:00
commit 9aa44fa13b
83 changed files with 927 additions and 270 deletions

View file

@ -170,6 +170,7 @@ CVAR(Bool, am_showmonsters, true, CVAR_ARCHIVE);
CVAR(Bool, am_showitems, true, CVAR_ARCHIVE);
CVAR(Bool, am_showtime, true, CVAR_ARCHIVE);
CVAR(Bool, am_showtotaltime, false, CVAR_ARCHIVE);
CVAR(Bool, am_showlevelname, true, CVAR_ARCHIVE);
CVAR(Int, am_colorset, 0, CVAR_ARCHIVE);
CVAR(Bool, am_customcolors, true, CVAR_ARCHIVE);
CVAR(Int, am_map_secrets, 1, CVAR_ARCHIVE);

View file

@ -594,6 +594,8 @@ class FBoolCVarRef
{
FBoolCVar* ref;
public:
int operator= (const FBoolCVarRef&) = delete;
int operator= (FBoolCVarRef&&) = delete;
inline bool operator= (bool val) { *ref = val; return val; }
inline operator bool () const { return **ref; }
@ -607,7 +609,11 @@ class FIntCVarRef
FIntCVar* ref;
public:
int operator= (const FIntCVarRef&) = delete;
int operator= (FIntCVarRef&&) = delete;
int operator= (int val) { *ref = val; return val; }
inline operator int () const { return **ref; }
inline int operator *() const { return **ref; }
inline FIntCVar* operator->() { return ref; }
@ -618,6 +624,8 @@ class FFloatCVarRef
{
FFloatCVar* ref;
public:
int operator= (const FFloatCVarRef&) = delete;
int operator= (FFloatCVarRef&&) = delete;
float operator= (float val) { *ref = val; return val; }
inline operator float () const { return **ref; }
@ -630,6 +638,8 @@ class FStringCVarRef
{
FStringCVar* ref;
public:
int operator= (const FStringCVarRef&) = delete;
int operator= (FStringCVarRef&&) = delete;
const char* operator= (const char* val) { *ref = val; return val; }
inline operator const char* () const { return **ref; }
@ -642,6 +652,8 @@ class FColorCVarRef
{
FColorCVar* ref;
public:
int operator= (const FColorCVarRef&) = delete;
int operator= (FColorCVarRef&&) = delete;
//uint32_t operator= (uint32_t val) { *ref = val; return val; }
inline operator uint32_t () const { return **ref; }
@ -654,6 +666,9 @@ class FFlagCVarRef
{
FFlagCVar* ref;
public:
int operator= (const FFlagCVarRef&) = delete;
int operator= (FFlagCVarRef&&) = delete;
inline bool operator= (bool val) { *ref = val; return val; }
inline bool operator= (const FFlagCVar& val) { *ref = val; return val; }
inline operator int () const { return **ref; }
@ -665,6 +680,9 @@ class FMaskCVarRef
{
FMaskCVar* ref;
public:
int operator= (const FMaskCVarRef&) = delete;
int operator= (FMaskCVarRef&&) = delete;
//int operator= (int val) { *ref = val; return val; }
inline operator int () const { return **ref; }
inline int operator *() const { return **ref; }

View file

@ -270,8 +270,10 @@ void ScreenJobDraw()
ScaleOverrider ovr(twod);
IFVIRTUALPTRNAME(cutscene.runner, NAME_ScreenJobRunner, RunFrame)
{
int ret = 0;
VMValue parm[] = { cutscene.runner, smoothratio };
VMCall(func, parm, 2, nullptr, 0);
VMReturn rets[] = { &ret };
VMCall(func, parm, 2, rets, 1);
}
}
}

View file

@ -2,7 +2,7 @@
#include "zstring.h"
#ifdef __unix__
#if defined(__unix__) || defined(__HAIKU__)
FString GetUserFile (const char *path);
#endif
FString M_GetAppDataPath(bool create);

View file

@ -85,6 +85,11 @@ public:
ParseVersion = ver;
}
bool CheckParseVersion(VersionInfo ver)
{
return ParseVersion >= ver;
}
void SetCMode(bool cmode);
void SetNoOctals(bool cmode) { NoOctals = cmode; }
void SetNoFatalErrors(bool cmode) { NoFatalErrors = cmode; }

View file

@ -177,6 +177,7 @@ std2:
/* Other keywords from UnrealScript */
'abstract' { RET(TK_Abstract); }
'foreach' { RET(ParseVersion >= MakeVersion(4, 10, 0)? TK_ForEach : TK_Identifier); }
'unsafe' { RET(ParseVersion >= MakeVersion(4, 14, 2)? TK_Unsafe : TK_Identifier); }
'true' { RET(TK_True); }
'false' { RET(TK_False); }
'none' { RET(TK_None); }

View file

@ -80,6 +80,7 @@ xx(TK_Color, "'color'")
xx(TK_Goto, "'goto'")
xx(TK_Abstract, "'abstract'")
xx(TK_ForEach, "'foreach'")
xx(TK_Unsafe, "'unsafe'")
xx(TK_True, "'true'")
xx(TK_False, "'false'")
xx(TK_None, "'none'")

View file

@ -12748,16 +12748,15 @@ ExpEmit FxFunctionPtrCast::Emit(VMFunctionBuilder *build)
FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p)
:FxExpression(EFX_LocalVariableDeclaration, p)
{
// Local FVector isn't different from Vector
if (type == TypeFVector2) type = TypeVector2;
else if (type == TypeFVector3) type = TypeVector3;
else if (type == TypeFVector4) type = TypeVector4;
else if (type == TypeFQuaternion) type = TypeQuaternion;
if(type != type->GetLocalType())
{
ScriptPosition.Message(MSG_WARNING, "Type '%s' not allowed in local variables, changing to '%s'", type->DescriptiveName(), type->GetLocalType()->DescriptiveName());
}
ValueType = type;
ValueType = type->GetLocalType();
VarFlags = varflags;
Name = name;
RegCount = type->RegCount;
RegCount = ValueType->RegCount;
Init = initval;
clearExpr = nullptr;
}

View file

@ -359,6 +359,7 @@ void PType::StaticInit()
TypeVector2->RegType = REGT_FLOAT;
TypeVector2->RegCount = 2;
TypeVector2->isOrdered = true;
TypeVector2->mDescriptiveName = "Vector2";
TypeVector3 = new PStruct(NAME_Vector3, nullptr);
TypeVector3->AddField(NAME_X, TypeFloat64);
@ -373,6 +374,7 @@ void PType::StaticInit()
TypeVector3->RegType = REGT_FLOAT;
TypeVector3->RegCount = 3;
TypeVector3->isOrdered = true;
TypeVector3->mDescriptiveName = "Vector3";
TypeVector4 = new PStruct(NAME_Vector4, nullptr);
TypeVector4->AddField(NAME_X, TypeFloat64);
@ -389,6 +391,7 @@ void PType::StaticInit()
TypeVector4->RegType = REGT_FLOAT;
TypeVector4->RegCount = 4;
TypeVector4->isOrdered = true;
TypeVector4->mDescriptiveName = "Vector4";
TypeFVector2 = new PStruct(NAME_FVector2, nullptr);
@ -401,6 +404,8 @@ void PType::StaticInit()
TypeFVector2->RegType = REGT_FLOAT;
TypeFVector2->RegCount = 2;
TypeFVector2->isOrdered = true;
TypeFVector2->mDescriptiveName = "FVector2";
TypeFVector2->SetLocalType(TypeVector2);
TypeFVector3 = new PStruct(NAME_FVector3, nullptr);
TypeFVector3->AddField(NAME_X, TypeFloat32);
@ -415,6 +420,8 @@ void PType::StaticInit()
TypeFVector3->RegType = REGT_FLOAT;
TypeFVector3->RegCount = 3;
TypeFVector3->isOrdered = true;
TypeFVector3->mDescriptiveName = "FVector3";
TypeFVector3->SetLocalType(TypeVector3);
TypeFVector4 = new PStruct(NAME_FVector4, nullptr);
TypeFVector4->AddField(NAME_X, TypeFloat32);
@ -431,6 +438,8 @@ void PType::StaticInit()
TypeFVector4->RegType = REGT_FLOAT;
TypeFVector4->RegCount = 4;
TypeFVector4->isOrdered = true;
TypeFVector4->mDescriptiveName = "FVector4";
TypeFVector4->SetLocalType(TypeVector4);
TypeQuaternion = new PStruct(NAME_Quat, nullptr);
@ -447,6 +456,7 @@ void PType::StaticInit()
TypeQuaternion->moveOp = OP_MOVEV4;
TypeQuaternion->RegType = REGT_FLOAT;
TypeQuaternion->RegCount = 4;
TypeQuaternion->mDescriptiveName = "Quat";
TypeQuaternion->isOrdered = true;
TypeFQuaternion = new PStruct(NAME_FQuat, nullptr);
@ -464,6 +474,8 @@ void PType::StaticInit()
TypeFQuaternion->RegType = REGT_FLOAT;
TypeFQuaternion->RegCount = 4;
TypeFQuaternion->isOrdered = true;
TypeFQuaternion->mDescriptiveName = "FQuat";
TypeFQuaternion->SetLocalType(TypeQuaternion);
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_sByte, TypeSInt8));

View file

@ -109,6 +109,13 @@ public:
EScopeFlags ScopeFlags = (EScopeFlags)0;
bool SizeKnown = true;
bool VMInternalStruct = false;
PType * LocalType = nullptr;
PType * SetLocalType(PType * LocalType) { this->LocalType = LocalType; return this; }
PType * GetLocalType() { return LocalType ? LocalType : this; }
PType(unsigned int size = 1, unsigned int align = 1);
virtual ~PType();
virtual bool isNumeric() { return false; }

View file

@ -427,11 +427,12 @@ struct_def(X) ::= EXTEND STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRAC
}
%type struct_flags{ClassFlagsBlock}
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) ::= . { X.Flags = 0; X.Version = {0, 0}; }
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Version = A.Version; }
struct_flags(X) ::= struct_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Version = A.Version; }
struct_flags(X) ::= struct_flags(A) CLEARSCOPE. { X.Flags = A.Flags | ZCC_ClearScope; X.Version = A.Version; }
struct_flags(X) ::= struct_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Version = A.Version; }
struct_flags(X) ::= struct_flags(A) UNSAFE LPAREN INTERNAL RPAREN. { X.Flags = A.Flags | ZCC_VMInternalStruct; X.Version = A.Version; }
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; }
@ -957,6 +958,7 @@ type_name(X) ::= DOT dottable_id(A).
/* Aggregate types */
%type aggregate_type {ZCC_Type *}
%type aggregate_type_pre {ZCC_Type *}
%type type {ZCC_Type *}
%type type_list {ZCC_Type *}
%type type_list_or_void {ZCC_Type *}
@ -965,30 +967,92 @@ type_name(X) ::= DOT dottable_id(A).
%type array_size{ZCC_Expression *}
%type array_size_expr{ZCC_Expression *}
aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* ZSMap<K, V> */
aggregate_type_pre(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B). /* ZSMap<K, V> */
{
NEW_AST_NODE(MapType,map,T);
map->KeyType = A;
map->ValueType = B;
X = map;
X->ArraySize = NULL;
}
aggregate_type(X) ::= MAPITERATOR(T) LT type_or_array(A) COMMA type_or_array(B) GT. /* ZSMapIterator<K, V> */
aggregate_type_pre(X) ::= MAPITERATOR(T) LT type_or_array(A) COMMA type_or_array(B). /* ZSMapIterator<K, V> */
{
NEW_AST_NODE(MapIteratorType,map_it,T);
map_it->KeyType = A;
map_it->ValueType = B;
X = map_it;
X->ArraySize = NULL;
}
aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT. /* TArray<type> */
aggregate_type_pre(X) ::= ARRAY(T) LT type_or_array(A). /* TArray<type> */
{
NEW_AST_NODE(DynArrayType,arr,T);
arr->ElementType = A;
X = arr;
X->ArraySize = NULL;
}
aggregate_type(X) ::= func_ptr_type(A). { X = A; /*X-overwrites-A*/ }
aggregate_type_pre(X) ::= func_ptr_type(A). { X = A; /*X-overwrites-A*/ X->ArraySize = NULL; }
aggregate_type_pre(X) ::= CLASS(T) LT dottable_id(A). /* class<type> */
{
NEW_AST_NODE(ClassType,cls,T);
cls->Restriction = A;
X = cls;
X->ArraySize = NULL;
}
aggregate_type(X) ::= aggregate_type_pre(A) GT. { X = A; X->ArraySize = NULL; }
aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA aggregate_type_pre(B) RSH. /* ZSMap<K, V<...>> */
{
if(!stat->sc->CheckParseVersion(MakeVersion(4, 15, 1)))
{
stat->sc->ScriptMessage(">> without space in parametrized types only supported for zscript >= 4.15.1");
FScriptPosition::ErrorCounter++;
}
NEW_AST_NODE(MapType,map,T);
map->KeyType = A;
map->ValueType = B;
X = map;
X->ArraySize = NULL;
}
aggregate_type(X) ::= MAPITERATOR(T) LT type_or_array(A) COMMA aggregate_type_pre(B) RSH. /* ZSMapIterator<K, V<...>> */
{
if(!stat->sc->CheckParseVersion(MakeVersion(4, 15, 1)))
{
stat->sc->ScriptMessage(">> without space in parametrized types only supported for zscript >= 4.15.1");
FScriptPosition::ErrorCounter++;
}
NEW_AST_NODE(MapIteratorType,map_it,T);
map_it->KeyType = A;
map_it->ValueType = B;
X = map_it;
X->ArraySize = NULL;
}
aggregate_type(X) ::= ARRAY(T) LT aggregate_type_pre(A) RSH. /* TArray<T<...>> */
{
if(!stat->sc->CheckParseVersion(MakeVersion(4, 15, 1)))
{
stat->sc->ScriptMessage(">> without space in parametrized types only supported for zscript >= 4.15.1");
FScriptPosition::ErrorCounter++;
}
NEW_AST_NODE(DynArrayType,arr,T);
arr->ElementType = A;
X = arr;
X->ArraySize = NULL;
}
aggregate_type(X) ::= CLASS(T). /* class<type> */
{
NEW_AST_NODE(ClassType,cls,T);
cls->Restriction = NULL;
X = cls;
X->ArraySize = NULL;
}
%type func_ptr_type {ZCC_FuncPtrType *}
%type func_ptr_params {ZCC_FuncPtrParamDecl *}
@ -1002,7 +1066,7 @@ fn_ptr_flag(X) ::= CLEARSCOPE. { X.Int = ZCC_ClearScope; }
//fn_ptr_flag(X) ::= VIRTUALSCOPE. { X.Int = ZCC_VirtualScope; } //virtual scope not allowed
func_ptr_type(X) ::= FNTYPE(T) LT fn_ptr_flag(F) type_list_or_void(A) LPAREN func_ptr_params(B) RPAREN GT. /* Function<...(...)> */
func_ptr_type(X) ::= FNTYPE(T) LT fn_ptr_flag(F) type_list_or_void(A) LPAREN func_ptr_params(B) RPAREN. /* Function<...(...)> */
{
NEW_AST_NODE(FuncPtrType,fn_ptr,T);
fn_ptr->RetType = A;
@ -1011,7 +1075,7 @@ func_ptr_type(X) ::= FNTYPE(T) LT fn_ptr_flag(F) type_list_or_void(A) LPAREN fun
X = fn_ptr;
}
func_ptr_type(X) ::= FNTYPE(T) LT VOID GT. /* Function<void> */
func_ptr_type(X) ::= FNTYPE(T) LT VOID. /* Function<void> */
{
NEW_AST_NODE(FuncPtrType,fn_ptr,T);
fn_ptr->RetType = nullptr;
@ -1053,15 +1117,6 @@ func_ptr_param(X) ::= func_param_flags(A) type(B) AND.
X = parm;
}
aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class<type> */
{
NEW_AST_NODE(ClassType,cls,T);
cls->Restriction = A;
X = cls;
}
class_restrictor(X) ::= . { X = NULL; }
class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; /*X-overwrites-A*/ }
type(X) ::= type_name(A). { X = A; /*X-overwrites-A*/ X->ArraySize = NULL; }
type(X) ::= aggregate_type(A). { X = A; /*X-overwrites-A*/ X->ArraySize = NULL; }
@ -1474,7 +1529,7 @@ primary(X) ::= LPAREN CLASS LT IDENTIFIER(A) GT RPAREN LPAREN func_expr_list(B)
X = expr;
}
primary(X) ::= LPAREN func_ptr_type(A) RPAREN LPAREN expr(B) RPAREN. [DOT] // function pointer type cast
primary(X) ::= LPAREN func_ptr_type(A) GT RPAREN LPAREN expr(B) RPAREN. [DOT] // function pointer type cast
{
NEW_AST_NODE(FunctionPtrCast, expr, A);
expr->Operation = PEX_FunctionPtrCast;

View file

@ -734,6 +734,8 @@ void ZCCCompiler::CreateStructTypes()
syms = &OutNamespace->Symbols;
}
if (s->NodeName() == NAME__ && fileSystem.GetFileContainer(Lump) == 0)
{
// This is just a container for syntactic purposes.
@ -748,11 +750,24 @@ void ZCCCompiler::CreateStructTypes()
{
s->strct->Type = NewStruct(s->NodeName(), outer, false, AST.FileNo);
}
if (s->strct->Flags & ZCC_Version)
{
s->strct->Type->mVersion = s->strct->Version;
}
if (s->strct->Flags & ZCC_VMInternalStruct)
{
if(fileSystem.GetFileContainer(Lump) == 0)
{
s->strct->Type->VMInternalStruct = true;
}
else
{
Error(s->strct, "Internal structs are only allowed in the root pk3");
}
}
auto &sf = s->Type()->ScopeFlags;
if (mVersion >= MakeVersion(2, 4, 0))
{
@ -814,6 +829,12 @@ void ZCCCompiler::CreateClassTypes()
PClass *parent;
auto ParentName = c->cls->ParentName;
if (c->cls->Flags & ZCC_Internal)
{
Error(c->cls, "'Internal' not allowed for classes");
}
// The parent exists, we may create a type for this class
if (ParentName != nullptr && ParentName->SiblingNext == ParentName)
{
parent = PClass::FindClass(ParentName->Id);
@ -850,7 +871,6 @@ void ZCCCompiler::CreateClassTypes()
Error(c->cls, "Class '%s' cannot extend sealed class '%s'", FName(c->NodeName()).GetChars(), parent->TypeName.GetChars());
}
// The parent exists, we may create a type for this class
if (c->cls->Flags & ZCC_Native)
{
// If this is a native class, its own type must also already exist and not be a runtime class.
@ -1873,7 +1893,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
{
Error(field, "%s: @ not allowed for user scripts", name.GetChars());
}
retval = ResolveUserType(btype, btype->UserType, outertype? &outertype->Symbols : nullptr, true);
retval = ResolveUserType(outertype, btype, btype->UserType, outertype? &outertype->Symbols : nullptr, true);
break;
case ZCC_UserType:
@ -1903,7 +1923,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
default:
retval = ResolveUserType(btype, btype->UserType, outertype ? &outertype->Symbols : nullptr, false);
retval = ResolveUserType(outertype, btype, btype->UserType, outertype ? &outertype->Symbols : nullptr, false);
break;
}
break;
@ -2158,7 +2178,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
* @param nativetype Distinguishes between searching for a native type or a user type.
* @returns the PType found for this user type
*/
PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *symt, bool nativetype)
PType *ZCCCompiler::ResolveUserType(PType *outertype, ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *symt, bool nativetype)
{
// Check the symbol table for the identifier.
PSymbol *sym = nullptr;
@ -2175,10 +2195,18 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, ZCC_Identifier *id, PSy
return TypeError;
}
//only allow references to internal types inside internal types
if (ptype->VMInternalStruct && !outertype->VMInternalStruct)
{
Error(type, "Type %s not accessible", FName(type->UserType->Id).GetChars());
return TypeError;
}
if (id->SiblingNext != type->UserType)
{
assert(id->SiblingNext->NodeType == AST_Identifier);
ptype = ResolveUserType(
outertype,
type,
static_cast<ZCC_Identifier *>(id->SiblingNext),
&ptype->Symbols,

View file

@ -134,7 +134,7 @@ protected:
FString FlagsToString(uint32_t flags);
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember);
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize);
PType *ResolveUserType(ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *sym, bool nativetype);
PType *ResolveUserType(PType *outertype, ZCC_BasicType *type, ZCC_Identifier *id, PSymbolTable *sym, bool nativetype);
static FString UserTypeName(ZCC_BasicType *type);
TArray<ZCC_StructWork *> OrderStructs();
void AddStruct(TArray<ZCC_StructWork *> &new_order, ZCC_StructWork *struct_def);

View file

@ -251,6 +251,7 @@ static void InitTokenMap()
TOKENDEF (TK_Do, ZCC_DO);
TOKENDEF (TK_For, ZCC_FOR);
TOKENDEF (TK_ForEach, ZCC_FOREACH);
TOKENDEF (TK_Unsafe, ZCC_UNSAFE);
TOKENDEF (TK_While, ZCC_WHILE);
TOKENDEF (TK_Until, ZCC_UNTIL);
TOKENDEF (TK_If, ZCC_IF);

View file

@ -41,30 +41,31 @@ struct ZCCToken
// Variable / Function / Class modifiers
enum
{
ZCC_Native = 1 << 0,
ZCC_Static = 1 << 1,
ZCC_Private = 1 << 2,
ZCC_Protected = 1 << 3,
ZCC_Latent = 1 << 4,
ZCC_Final = 1 << 5,
ZCC_Meta = 1 << 6,
ZCC_Action = 1 << 7,
ZCC_Deprecated = 1 << 8,
ZCC_ReadOnly = 1 << 9,
ZCC_FuncConst = 1 << 10,
ZCC_Abstract = 1 << 11,
ZCC_Extension = 1 << 12,
ZCC_Virtual = 1 << 13,
ZCC_Override = 1 << 14,
ZCC_Transient = 1 << 15,
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,
ZCC_Internal = 1 << 22,
ZCC_Sealed = 1 << 23,
ZCC_Native = 1 << 0,
ZCC_Static = 1 << 1,
ZCC_Private = 1 << 2,
ZCC_Protected = 1 << 3,
ZCC_Latent = 1 << 4,
ZCC_Final = 1 << 5,
ZCC_Meta = 1 << 6,
ZCC_Action = 1 << 7,
ZCC_Deprecated = 1 << 8,
ZCC_ReadOnly = 1 << 9,
ZCC_FuncConst = 1 << 10,
ZCC_Abstract = 1 << 11,
ZCC_Extension = 1 << 12,
ZCC_Virtual = 1 << 13,
ZCC_Override = 1 << 14,
ZCC_Transient = 1 << 15,
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,
ZCC_Internal = 1 << 22,
ZCC_Sealed = 1 << 23,
ZCC_VMInternalStruct = 1 << 24,
};
// Function parameter modifiers

View file

@ -853,6 +853,27 @@ DEFINE_ACTION_FUNCTION(_Wads, GetLumpFullName)
ACTION_RETURN_STRING(fileSystem.GetFileFullName(lump));
}
DEFINE_ACTION_FUNCTION(_Wads, GetLumpContainer)
{
PARAM_PROLOGUE;
PARAM_INT(lump);
ACTION_RETURN_INT(fileSystem.GetFileContainer(lump));
}
DEFINE_ACTION_FUNCTION(_Wads, GetContainerName)
{
PARAM_PROLOGUE;
PARAM_INT(lump);
ACTION_RETURN_STRING(fileSystem.GetResourceFileName(lump));
}
DEFINE_ACTION_FUNCTION(_Wads, GetLumpFullPath)
{
PARAM_PROLOGUE;
PARAM_INT(lump);
ACTION_RETURN_STRING(fileSystem.GetFileFullPath(lump));
}
DEFINE_ACTION_FUNCTION(_Wads, GetLumpNamespace)
{
PARAM_PROLOGUE;

View file

@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <memory>
#include <vector>

View file

@ -539,15 +539,9 @@ struct TVector3
return *this;
}
// returns the XY fields as a 2D-vector.
constexpr const Vector2& XY() const
constexpr Vector2 XY() const
{
return *reinterpret_cast<const Vector2*>(this);
}
constexpr Vector2& XY()
{
return *reinterpret_cast<Vector2*>(this);
return Vector2(X, Y);
}
// Add a 3D vector and a 2D vector.
@ -792,28 +786,16 @@ struct TVector4
}
// returns the XY fields as a 2D-vector.
constexpr const Vector2& XY() const
constexpr Vector2 XY() const
{
return *reinterpret_cast<const Vector2*>(this);
return Vector2(X, Y);
}
constexpr Vector2& XY()
constexpr Vector3 XYZ() const
{
return *reinterpret_cast<Vector2*>(this);
return Vector3(X, Y, Z);
}
// returns the XY fields as a 2D-vector.
constexpr const Vector3& XYZ() const
{
return *reinterpret_cast<const Vector3*>(this);
}
constexpr Vector3& XYZ()
{
return *reinterpret_cast<Vector3*>(this);
}
// Test for approximate equality
bool ApproximatelyEquals(const TVector4 &other) const
{
@ -1796,7 +1778,9 @@ struct TRotator
template<class T>
inline TVector3<T>::TVector3 (const TRotator<T> &rot)
{
XY() = rot.Pitch.Cos() * rot.Yaw.ToVector();
auto XY = rot.Pitch.Cos() * rot.Yaw.ToVector();
X = XY.X;
Y = XY.Y;
Z = rot.Pitch.Sin();
}

View file

@ -251,14 +251,18 @@ void CT_Drawer (void)
{
// [MK] allow the status bar to take over chat prompt drawing
bool skip = false;
IFVIRTUALPTR(StatusBar, DBaseStatusBar, DrawChat)
if(StatusBar)
{
FString txt = ChatQueue;
VMValue params[] = { (DObject*)StatusBar, &txt };
int rv;
VMReturn ret(&rv);
VMCall(func, params, countof(params), &ret, 1);
if (!!rv) return;
IFVIRTUALPTR(StatusBar, DBaseStatusBar, DrawChat)
{
FString txt = ChatQueue;
VMValue params[] = { (DObject*)StatusBar, &txt };
int rv;
VMReturn ret(&rv);
VMCall(func, params, countof(params), &ret, 1);
if (!!rv) return;
}
}
FStringf prompt("%s ", GStrings.GetString("TXT_SAY"));
@ -269,8 +273,8 @@ void CT_Drawer (void)
scalex = 1;
int scale = active_con_scale(drawer);
int screen_width = twod->GetWidth() / scale;
int screen_height= twod->GetHeight() / scale;
int st_y = StatusBar->GetTopOfStatusbar() / scale;
int screen_height = twod->GetHeight() / scale;
int st_y = StatusBar ? (StatusBar->GetTopOfStatusbar() / scale) : screen_height;
y += ((twod->GetHeight() == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y;

View file

@ -316,7 +316,6 @@ CUSTOM_CVAR(Int, I_FriendlyWindowTitle, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_N
CVAR(Bool, cl_nointros, false, CVAR_ARCHIVE)
bool RunningAsTool = false;
bool hud_toggled = false;
bool wantToRestart;
bool DrawFSHUD; // [RH] Draw fullscreen HUD?
bool devparm; // started game with -devparm
@ -361,16 +360,18 @@ static int pagetic;
//
//==========================================================================
CVAR(Int, saved_screenblocks, 10, CVAR_ARCHIVE)
CVAR(Bool, saved_drawplayersprite, true, CVAR_ARCHIVE)
CVAR(Bool, saved_showmessages, true, CVAR_ARCHIVE)
CVAR(Bool, hud_toggled, false, CVAR_ARCHIVE)
void D_ToggleHud()
{
static int saved_screenblocks;
static bool saved_drawplayersprite, saved_showmessages;
if ((hud_toggled = !hud_toggled))
{
saved_screenblocks = screenblocks;
saved_drawplayersprite = r_drawplayersprites;
saved_showmessages = show_messages;
saved_screenblocks = *screenblocks;
saved_drawplayersprite = *r_drawplayersprites;
saved_showmessages = *show_messages;
screenblocks = 12;
r_drawplayersprites = false;
show_messages = false;
@ -379,9 +380,9 @@ void D_ToggleHud()
}
else
{
screenblocks = saved_screenblocks;
r_drawplayersprites = saved_drawplayersprite;
show_messages = saved_showmessages;
screenblocks =*saved_screenblocks;
r_drawplayersprites = *saved_drawplayersprite;
show_messages = *saved_showmessages;
}
}
CCMD(togglehud)

View file

@ -34,7 +34,7 @@
#include "c_cvars.h"
extern bool advancedemo;
extern bool hud_toggled;
EXTERN_CVAR(Bool, hud_toggled);
void D_ToggleHud();
struct event_t;

View file

@ -300,7 +300,7 @@ CCMD (turnspeeds)
}
if (i <= 4)
{
*angleturn[3] = *angleturn[2];
*angleturn[3] = **angleturn[2];
}
}
}
@ -1000,6 +1000,8 @@ bool G_Responder (event_t *ev)
if (gameaction == ga_nothing &&
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL))
{
if (chatmodeon) chatmodeon = 0;
const char *cmd = Bindings.GetBind (ev->data1);
if (ev->type == EV_KeyDown)

View file

@ -150,7 +150,7 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, CVAR_NOINITCALL)
CUSTOM_CVAR(Int, gl_maplightmode, -1, CVAR_NOINITCALL | CVAR_CHEAT) // this is just for testing. -1 means 'inactive'
{
if (self > 5 || self < -1) self = -1;
if (self > 4 || self < -1) self = -1;
}
CUSTOM_CVARD(Int, gl_lightmode, 1, CVAR_ARCHIVE, "Select lighting mode. 2 is vanilla accurate, 1 is accurate to the ZDoom software renderer and 0 is a less demanding non-shader implementation")

View file

@ -1441,10 +1441,10 @@ class CommandDrawNumber : public CommandDrawString
static VMFunction *func = nullptr;
if (func == nullptr) PClass::FindFunction(&func, NAME_PlayerPawn, "GetEffectTicsForItem");
VMValue params[] = { statusBar->CPlayer->mo, inventoryItem };
int retv;
VMReturn ret(&retv);
VMCall(func, params, 2, &ret, 1);
num = retv < 0? 0 : retv / TICRATE + 1;
int ret1 = 0, ret2 = 0;
VMReturn rets[] = { &ret1, &ret2 };
VMCall(func, params, 2, rets, 2);
num = ret1 < 0? 0 : ret1 / TICRATE + 1;
break;
}
case INVENTORY:

View file

@ -85,6 +85,7 @@ EXTERN_CVAR (Bool, am_showsecrets)
EXTERN_CVAR (Bool, am_showitems)
EXTERN_CVAR (Bool, am_showtime)
EXTERN_CVAR (Bool, am_showtotaltime)
EXTERN_CVAR (Bool, am_showlevelname)
EXTERN_CVAR(Bool, inter_subtitles)
EXTERN_CVAR(Bool, ui_screenborder_classic_scaling)
@ -598,6 +599,8 @@ void DBaseStatusBar::DoDrawAutomapHUD(int crdefault, int highlight)
}
FormatMapName(primaryLevel, crdefault, &textbuffer);
if (textbuffer.IsEmpty())
return;
if (!generic_ui)
{

View file

@ -139,6 +139,7 @@ static PClassActor* FindInfoName(int index, bool mustexist = false)
cls = static_cast<PClassActor*>(RUNTIME_CLASS(AActor)->CreateDerivedClass(name.GetChars(), (unsigned)sizeof(AActor)));
NewClassType(cls, -1); // This needs a VM type to work as intended.
cls->InitializeDefaults();
PClassActor::AllActorClasses.Push(cls);
}
if (cls)
{
@ -1203,6 +1204,8 @@ static int PatchThing (int thingy, int flags)
AActor *info;
uint8_t dummy[sizeof(AActor)];
bool hadHeight = false;
bool hadProjHeight = false;
bool hadPhysHeight = false;
bool hadTranslucency = false;
bool hadStyle = false;
FStateDefinitions statedef;
@ -1262,8 +1265,17 @@ static int PatchThing (int thingy, int flags)
}
else if (linelen == 6 && stricmp (Line1, "Height") == 0)
{
info->Height = DEHToDouble(val);
info->projectilepassheight = 0; // needs to be disabled
// [XA] This is a bit more complex now, since projectilepassheight
// and "physical height" now both exist. if either of these are
// defined, then override the Height field accordingly.
if(!hadPhysHeight)
{
info->Height = DEHToDouble(val);
}
if(!hadProjHeight)
{
info->projectilepassheight = 0; // needs to be disabled
}
hadHeight = true;
}
else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0)
@ -1459,6 +1471,47 @@ static int PatchThing (int thingy, int flags)
info->missilechancemult = DEHToDouble(val);
}
// [XA] Fields for common GZDoom-specific values that
// are desirable to set in a cross-port DEHACKED mod.
// adding these prevents users from having to reimplement
// actors in zscript just to define these few fields.
else if (!stricmp(Line1, "Projectile pass height"))
{
info->projectilepassheight = DEHToDouble(val);
hadProjHeight = true;
}
else if (!stricmp(Line1, "Physical height"))
{
// [XA] This is a synonym for Height that is intended
// to be ignored in any ports that don't support
// projectilepassheight -- this is needed because
// other ports' "Height x" is actually equivalent
// to Zdoom's "ProjectilePassHeight x; Height y",
// i.e. the definition of the Height var is different.
info->Height = DEHToDouble(val);
hadPhysHeight = true;
}
else if (!stricmp(Line1, "Tag"))
{
stripwhite(Line2);
info->SetTag(Line2);
}
else if (!stricmp(Line1, "Obituary"))
{
stripwhite(Line2);
info->StringVar(NAME_Obituary) = Line2;
}
else if (!stricmp(Line1, "Melee obituary"))
{
stripwhite(Line2);
info->StringVar(NAME_HitObituary) = Line2;
}
else if (!stricmp(Line1, "Self obituary"))
{
stripwhite(Line2);
info->StringVar(NAME_SelfObituary) = Line2;
}
else if (linelen > 6)
{
if (stricmp (Line1 + linelen - 6, " frame") == 0)
@ -1727,12 +1780,23 @@ static int PatchThing (int thingy, int flags)
else Printf (unknown_str, Line1, "Thing", thingy);
}
// [XA] sanity check: to avoid ambiguity, an actor that defines
// ProjectilePassHeight must also define PhysicalHeight, and vice-versa.
if(hadPhysHeight && !hadProjHeight)
{
I_Error("Thing %d: DEHACKED actors that set 'Physical height' must also set 'Projectile pass height'\n", thingy);
}
else if(!hadPhysHeight && hadProjHeight)
{
I_Error("Thing %d: DEHACKED actors that set 'Projectile pass height' must also set 'Physical height'\n", thingy);
}
if (info != (AActor *)&dummy)
{
// Reset heights for things hanging from the ceiling that
// don't specify a new height.
if (info->flags & MF_SPAWNCEILING &&
!hadHeight &&
!hadHeight && !hadPhysHeight &&
thingy <= (int)OrgHeights.Size() && thingy > 0)
{
info->Height = OrgHeights[thingy - 1];
@ -3714,7 +3778,11 @@ void FinishDehPatch ()
mysnprintf(typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", nameindex++);
bool newlycreated;
subclass = static_cast<PClassActor *>(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size, &newlycreated, 0));
if (newlycreated) subclass->InitializeDefaults();
if (newlycreated)
{
subclass->InitializeDefaults();
PClassActor::AllActorClasses.Push(subclass);
}
}
while (subclass == nullptr);
NewClassType(subclass, 0); // This needs a VM type to work as intended.

View file

@ -1582,7 +1582,7 @@ DEFINE_MAP_OPTION(lightmode, false)
parse.sc.MustGetNumber();
if (parse.sc.Number == 8 || parse.sc.Number == 16) info->lightmode = ELightMode::NotSet;
else if (parse.sc.Number >= 0 && parse.sc.Number <= 5)
else if (parse.sc.Number >= 0 && parse.sc.Number < 5)
{
info->lightmode = ELightMode(parse.sc.Number);
}

View file

@ -325,8 +325,10 @@ void DIntermissionScreenCutscene::Drawer ()
ScaleOverrider ovr(twod);
IFVIRTUALPTRNAME(mScreenJobRunner, NAME_ScreenJobRunner, RunFrame)
{
int res = 0;
VMValue parm[] = { mScreenJobRunner, I_GetTimeFrac() };
VMCall(func, parm, 2, nullptr, 0);
VMReturn ret[] = { &res };
VMCall(func, parm, 2, ret, 1);
}
}

View file

@ -483,6 +483,9 @@ xx(PowerupType)
xx(PlayerPawn)
xx(RipSound)
xx(Archvile)
xx(Obituary)
xx(HitObituary)
xx(SelfObituary)
xx(ResolveState)

View file

@ -218,8 +218,10 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount)
IFVM(Actor, TakeInventory)
{
int taken = false;
VMValue params[] = { player->mo, itemtype, amount, false, false };
VMCall(func, params, 5, nullptr, 0);
VMReturn rets[] = { &taken };
VMCall(func, params, 5, rets, 1);
}
}

View file

@ -509,6 +509,7 @@ enum ActorRenderFlag2
RF2_ISOMETRICSPRITES = 0x0080,
RF2_SQUAREPIXELS = 0x0100, // apply +ROLLSPRITE scaling math so that non rolling sprites get the same scaling
RF2_STRETCHPIXELS = 0x0200, // don't apply SQUAREPIXELS for ROLLSPRITES
RF2_LIGHTMULTALPHA = 0x0400, // attached lights use alpha as intensity multiplier
};
// This translucency value produces the closest match to Heretic's TINTTAB.

View file

@ -355,12 +355,12 @@ void FThinkerCollection::SerializeThinkers(FSerializer &arc, bool hubLoad)
else if (thinker->ObjectFlags & OF_JustSpawned)
{
FreshThinkers[i].AddTail(thinker);
thinker->PostSerialize();
thinker->CallPostSerialize();
}
else
{
Thinkers[i].AddTail(thinker);
thinker->PostSerialize();
thinker->CallPostSerialize();
}
}
}
@ -773,6 +773,16 @@ void DThinker::PostSerialize()
{
}
void DThinker::CallPostSerialize()
{
PostSerialize();
IFOVERRIDENVIRTUALPTRNAME(this, NAME_Thinker, OnLoad)
{
VMValue params[] = { this };
VMCall(func, params, 1, nullptr, 0);
}
}
//==========================================================================
//
//

View file

@ -104,6 +104,7 @@ public:
virtual void PostBeginPlay (); // Called just before the first tick
virtual void CallPostBeginPlay(); // different in actor.
virtual void PostSerialize();
void CallPostSerialize();
void Serialize(FSerializer &arc) override;
size_t PropagateMark();

View file

@ -2532,8 +2532,10 @@ void FParser::SF_PlayerWeapon()
IFVM(PlayerPawn, PickNewWeapon)
{
AActor* weap = nullptr;
VMValue param[] = { Level->Players[playernum]->mo, (void*)nullptr };
VMCall(func, param, 2, nullptr, 0);
VMReturn rets[] = { (void**)&weap };
VMCall(func, param, 2, rets, 1);
}
}
}

View file

@ -72,6 +72,31 @@ void DCeiling::Serialize(FSerializer &arc)
.Enum("crushmode", m_CrushMode);
}
DEFINE_FIELD(DCeiling, m_Type)
DEFINE_FIELD(DCeiling, m_BottomHeight)
DEFINE_FIELD(DCeiling, m_TopHeight)
DEFINE_FIELD(DCeiling, m_Speed)
DEFINE_FIELD(DCeiling, m_Speed1)
DEFINE_FIELD(DCeiling, m_Speed2)
DEFINE_FIELD(DCeiling, m_Silent)
DEFINE_FIELD(DCeiling, m_CrushMode)
DEFINE_ACTION_FUNCTION(DCeiling, getCrush)
{
PARAM_SELF_PROLOGUE(DCeiling);
ACTION_RETURN_INT(self->getCrush());
}
DEFINE_ACTION_FUNCTION(DCeiling, getDirection)
{
PARAM_SELF_PROLOGUE(DCeiling);
ACTION_RETURN_INT(self->getDirection());
}
DEFINE_ACTION_FUNCTION(DCeiling, getOldDirection)
{
PARAM_SELF_PROLOGUE(DCeiling);
ACTION_RETURN_INT(self->getOldDirection());
}
//============================================================================
//
//

View file

@ -47,6 +47,14 @@ public:
crushSlowdown = 2
};
ECeiling m_Type;
double m_BottomHeight;
double m_TopHeight;
double m_Speed;
double m_Speed1; // [RH] dnspeed of crushers
double m_Speed2; // [RH] upspeed of crushers
ECrushMode m_CrushMode;
int m_Silent;
void Construct(sector_t *sec);
void Construct(sector_t *sec, double speed1, double speed2, int silent);
@ -56,17 +64,10 @@ public:
int getCrush() const { return m_Crush; }
int getDirection() const { return m_Direction; }
int getOldDirection() const { return m_OldDirection; }
protected:
ECeiling m_Type;
double m_BottomHeight;
double m_TopHeight;
double m_Speed;
double m_Speed1; // [RH] dnspeed of crushers
double m_Speed2; // [RH] upspeed of crushers
int m_Crush;
ECrushMode m_CrushMode;
int m_Silent;
int m_Direction; // 1 = up, 0 = waiting, -1 = down
// [RH] Need these for BOOM-ish transferring ceilings

View file

@ -40,6 +40,7 @@
#include "g_levellocals.h"
#include "animations.h"
#include "texturemanager.h"
#include "vm.h"
//============================================================================
//
@ -64,6 +65,17 @@ void DDoor::Serialize(FSerializer &arc)
("lighttag", m_LightTag);
}
DEFINE_FIELD(DDoor, m_Type)
DEFINE_FIELD(DDoor, m_TopDist)
DEFINE_FIELD(DDoor, m_BotSpot)
DEFINE_FIELD(DDoor, m_BotDist)
DEFINE_FIELD(DDoor, m_OldFloorDist)
DEFINE_FIELD(DDoor, m_Speed)
DEFINE_FIELD(DDoor, m_Direction)
DEFINE_FIELD(DDoor, m_TopWait)
DEFINE_FIELD(DDoor, m_TopCountdown)
DEFINE_FIELD(DDoor, m_LightTag)
//============================================================================
//
// T_VerticalDoor

View file

@ -17,16 +17,10 @@ public:
doorWaitClose,
};
void Construct(sector_t *sector);
void Construct(sector_t *sec, EVlDoor type, double speed, int delay, int lightTag, int topcountdown);
void Serialize(FSerializer &arc);
void Tick ();
protected:
EVlDoor m_Type;
double m_TopDist;
double m_BotDist, m_OldFloorDist;
vertex_t *m_BotSpot;
vertex_t* m_BotSpot;
double m_Speed;
// 1 = up, 0 = waiting at top, -1 = down
@ -40,6 +34,12 @@ protected:
int m_LightTag;
void Construct(sector_t *sector);
void Construct(sector_t *sec, EVlDoor type, double speed, int delay, int lightTag, int topcountdown);
void Serialize(FSerializer &arc);
void Tick ();
protected:
void DoorSound (bool raise, class DSeqNode *curseq=NULL) const;
private:

View file

@ -96,6 +96,22 @@ void DFloor::Serialize(FSerializer &arc)
("instant", m_Instant);
}
DEFINE_FIELD(DFloor, m_Type)
DEFINE_FIELD(DFloor, m_Crush)
DEFINE_FIELD(DFloor, m_Direction)
DEFINE_FIELD(DFloor, m_NewSpecial)
DEFINE_FIELD(DFloor, m_Texture)
DEFINE_FIELD(DFloor, m_FloorDestDist)
DEFINE_FIELD(DFloor, m_Speed)
DEFINE_FIELD(DFloor, m_ResetCount)
DEFINE_FIELD(DFloor, m_OrgDist)
DEFINE_FIELD(DFloor, m_Delay)
DEFINE_FIELD(DFloor, m_PauseTime)
DEFINE_FIELD(DFloor, m_StepTime)
DEFINE_FIELD(DFloor, m_PerStepTime)
DEFINE_FIELD(DFloor, m_Hexencrush)
DEFINE_FIELD(DFloor, m_Instant)
//==========================================================================
//
// MOVE A FLOOR TO ITS DESTINATION (UP OR DOWN)
@ -887,6 +903,12 @@ void DElevator::Serialize(FSerializer &arc)
("interp_ceiling", m_Interp_Ceiling);
}
DEFINE_FIELD(DElevator, m_Type)
DEFINE_FIELD(DElevator, m_Direction)
DEFINE_FIELD(DElevator, m_FloorDestDist)
DEFINE_FIELD(DElevator, m_CeilingDestDist)
DEFINE_FIELD(DElevator, m_Speed)
//==========================================================================
//
//
@ -957,7 +979,7 @@ void DElevator::Tick ()
}
}
if (res == EMoveResult::pastdest) // if destination height acheived
if (res == EMoveResult::pastdest) // if destination height achieved
{
// make floor stop sound
SN_StopSequence (m_Sector, CHAN_FLOOR);

View file

@ -105,6 +105,13 @@ public:
elevateLower
};
EElevator m_Type;
int m_Direction;
double m_FloorDestDist;
double m_CeilingDestDist;
double m_Speed;
void Construct(sector_t *sec);
void OnDestroy() override;
@ -112,11 +119,6 @@ public:
void Tick ();
protected:
EElevator m_Type;
int m_Direction;
double m_FloorDestDist;
double m_CeilingDestDist;
double m_Speed;
TObjPtr<DInterpolation*> m_Interp_Ceiling;
TObjPtr<DInterpolation*> m_Interp_Floor;

View file

@ -36,6 +36,7 @@
#include "serializer.h"
#include "p_spec.h"
#include "g_levellocals.h"
#include "vm.h"
static FRandom pr_doplat ("DoPlat");
@ -62,6 +63,17 @@ void DPlat::Serialize(FSerializer &arc)
("tag", m_Tag);
}
DEFINE_FIELD(DPlat, m_Type)
DEFINE_FIELD(DPlat, m_Speed)
DEFINE_FIELD(DPlat, m_Low)
DEFINE_FIELD(DPlat, m_High)
DEFINE_FIELD(DPlat, m_Wait)
DEFINE_FIELD(DPlat, m_Count)
DEFINE_FIELD(DPlat, m_Status)
DEFINE_FIELD(DPlat, m_OldStatus)
DEFINE_FIELD(DPlat, m_Crush)
DEFINE_FIELD(DPlat, m_Tag)
//-----------------------------------------------------------------------------
//
//

View file

@ -38,8 +38,6 @@ public:
bool IsLift() const { return m_Type == platDownWaitUpStay || m_Type == platDownWaitUpStayStone; }
void Construct(sector_t *sector);
protected:
double m_Speed;
double m_Low;
double m_High;
@ -50,6 +48,7 @@ protected:
int m_Crush;
int m_Tag;
EPlatType m_Type;
protected:
void PlayPlatSound (const char *sound);
const char *GetSoundByType () const;

View file

@ -1108,7 +1108,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnVisualThinker, SpawnVisualThink
void DVisualThinker::UpdateSpriteInfo()
{
PT.style = ERenderStyle(GetRenderStyle());
if((PT.flags & SPF_LOCAL_ANIM) && PT.texture != AnimatedTexture)
if ((PT.flags & SPF_LOCAL_ANIM) && PT.texture != AnimatedTexture)
{
AnimatedTexture = PT.texture;
TexAnim.InitStandaloneAnimation(PT.animData, PT.texture, Level->maptime);
@ -1127,6 +1128,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, UpdateSpriteInfo, UpdateSpriteInfo
return 0;
}
bool DVisualThinker::ValidTexture()
{
return ((flags & VTF_IsParticle) || PT.texture.isValid());
}
// This runs just like Actor's, make sure to call Super.Tick() in ZScript.
void DVisualThinker::Tick()
@ -1134,10 +1139,8 @@ void DVisualThinker::Tick()
if (ObjectFlags & OF_EuthanizeMe)
return;
// There won't be a standard particle for this, it's only for graphics.
if (!PT.texture.isValid())
if (!ValidTexture())
{
Printf("No valid texture, destroyed");
Destroy();
return;
}
@ -1156,7 +1159,6 @@ void DVisualThinker::Tick()
PT.Pos.X = newxy.X;
PT.Pos.Y = newxy.Y;
PT.Pos.Z += PT.Vel.Z;
subsector_t * ss = Level->PointInRenderSubsector(PT.Pos);
// Handle crossing a sector portal.
@ -1246,7 +1248,33 @@ DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetTranslation, SetTranslation)
return 0;
}
static int IsFrozen(DVisualThinker * self)
int DVisualThinker::GetParticleType() const
{
int flag = (flags & VTF_IsParticle);
switch (flag)
{
case VTF_ParticleSquare:
return PT_SQUARE;
case VTF_ParticleRound:
return PT_ROUND;
case VTF_ParticleSmooth:
return PT_SMOOTH;
}
return PT_DEFAULT;
}
static int GetParticleType(DVisualThinker* self)
{
return self->GetParticleType();
}
DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, GetParticleType, GetParticleType)
{
PARAM_SELF_PROLOGUE(DVisualThinker);
ACTION_RETURN_INT(self->GetParticleType());
}
static int IsFrozen(DVisualThinker* self)
{
return !!(self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE));
}

View file

@ -53,6 +53,14 @@ struct FLevelLocals;
// [RH] Particle details
enum EParticleStyle
{
PT_DEFAULT = -1, // Use gl_particles_style
PT_SQUARE = 0,
PT_ROUND = 1,
PT_SMOOTH = 2,
};
enum EParticleFlags
{
SPF_FULLBRIGHT = 1 << 0,

View file

@ -336,7 +336,10 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
}
}
VMCall(func, params, 1, nullptr, 0);
AActor* unused = nullptr;
int unused2 = 0, unused3 = 0;
VMReturn ret[] = { (void**)&unused, &unused2, &unused3 };
VMCall(func, params, 1, ret, 3);
// Kill the dummy Actor if it didn't unmorph, otherwise checking the morph flags. Player pawns need
// to stay, otherwise they won't respawn correctly.

View file

@ -106,7 +106,7 @@ enum EPuffFlags
};
AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const DVector3 &pos, DAngle hitdir, DAngle particledir, int updown, int flags = 0, AActor *vict = NULL);
void P_SpawnBlood (const DVector3 &pos, DAngle angle, int damage, AActor *originator);
AActor *P_SpawnBlood (const DVector3 &pos, DAngle angle, int damage, AActor *originator);
void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle);
void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle);
void P_RipperBlood (AActor *mo, AActor *bleeder);

View file

@ -215,7 +215,7 @@ bool P_CanCrossLine(AActor *mo, line_t *line, DVector3 next)
assert(VIndex != ~0u);
}
VMValue params[] = { mo, line, next.X, next.Y, next.Z, false };
VMValue params[] = { mo, line, next.X, next.Y, next.Z };
VMReturn ret;
int retval;
ret.IntAt(&retval);

View file

@ -217,7 +217,6 @@ void AActor::Serialize(FSerializer &arc)
A("angles", Angles)
A("frame", frame)
A("scale", Scale)
A("nolocalrender", NoLocalRender) // Note: This will probably be removed later since a better solution is needed
A("renderstyle", RenderStyle)
A("renderflags", renderflags)
A("renderflags2", renderflags2)
@ -5751,8 +5750,10 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
IFVIRTUALPTRNAME(p->mo, NAME_PlayerPawn, ResetAirSupply)
{
int drowning = 0;
VMValue params[] = { p->mo, false };
VMCall(func, params, 2, nullptr, 0);
VMReturn rets[] = { &drowning };
VMCall(func, params, 2, rets, 1);
}
for (int ii = 0; ii < MAXPLAYERS; ++ii)
@ -5787,7 +5788,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
IFVM(PlayerPawn, FilterCoopRespawnInventory)
{
VMValue params[] = { p->mo, oldactor, ((heldWeap == nullptr || (heldWeap->ObjectFlags & OF_EuthanizeMe)) ? nullptr : heldWeap) };
VMCall(func, params, 2, nullptr, 0);
VMCall(func, params, 3, nullptr, 0);
}
}
if (oldactor != NULL)
@ -6441,9 +6442,9 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPuff)
//
//---------------------------------------------------------------------------
void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *originator)
AActor *P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *originator)
{
AActor *th;
AActor *th = nullptr;
PClassActor *bloodcls = originator->GetBloodType();
DVector3 pos = pos1;
pos.Z += pr_spawnblood.Random2() / 64.;
@ -6528,6 +6529,8 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina
if (bloodtype >= 1)
P_DrawSplash2 (originator->Level, 40, pos, dir, 2, originator->BloodColor);
return th;
}
DEFINE_ACTION_FUNCTION(AActor, SpawnBlood)
@ -6538,8 +6541,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnBlood)
PARAM_FLOAT(z);
PARAM_ANGLE(dir);
PARAM_INT(damage);
P_SpawnBlood(DVector3(x, y, z), dir, damage, self);
return 0;
ACTION_RETURN_OBJECT(P_SpawnBlood(DVector3(x, y, z), dir, damage, self));
}

View file

@ -249,7 +249,7 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags)
IFVIRTUALPTR(thing, AActor, PostTeleport)
{
VMValue params[] = { thing, pos.X, pos.Y, pos.Z, angle.Degrees(), flags };
VMCall(func, params, countof(params), nullptr, 1);
VMCall(func, params, countof(params), nullptr, 0);
}
}
return true;

View file

@ -20,6 +20,12 @@ enum EVisualThinkerFlags
VTF_FlipY = 1 << 3, // flip the sprite on the x/y axis.
VTF_DontInterpolate = 1 << 4, // disable all interpolation
VTF_AddLightLevel = 1 << 5, // adds sector light level to 'LightLevel'
VTF_ParticleDefault = 0x40,
VTF_ParticleSquare = 0x80,
VTF_ParticleRound = 0xC0,
VTF_ParticleSmooth = 0x100,
VTF_IsParticle = 0x1C0, // Renders as a particle instead
};
class DVisualThinker : public DThinker
@ -54,6 +60,8 @@ public:
void SetTranslation(FName trname);
int GetRenderStyle() const;
bool isFrozen();
bool ValidTexture();
int GetParticleType() const;
int GetLightLevel(sector_t *rendersector) const;
FVector3 InterpolatedPosition(double ticFrac) const;
float InterpolatedRoll(double ticFrac) const;

View file

@ -96,7 +96,7 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
cs = 1.0f;
}
if (light->target)
if (light->target && (light->target->renderflags2 & RF2_LIGHTMULTALPHA))
cs *= (float)light->target->Alpha;
info.r = light->GetRed() / 255.0f * cs;

View file

@ -288,19 +288,25 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state)
angle_t startAngle = clipper.GetClipAngle(seg->v2);
angle_t endAngle = clipper.GetClipAngle(seg->v1);
auto &clipperr = *rClipper;
angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
angle_t startAngleR = 0;
angle_t endAngleR = 0;
angle_t paddingR = 0x00200000; // Make radar clipping more aggressive (reveal less)
if(Viewpoint.IsAllowedOoB() && r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180))
if(Viewpoint.IsAllowedOoB() && r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR))
{
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum))
startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY());
endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY());
if (startAngleR - endAngleR >= ANGLE_180)
{
if (in_area == area_default) in_area = hw_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector);
backsector = hw_FakeFlat(drawctx, seg->backsector, in_area, true);
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
backsector = nullptr;
if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum))
{
if (in_area == area_default) in_area = hw_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector);
backsector = hw_FakeFlat(drawctx, seg->backsector, in_area, true);
if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR);
backsector = nullptr;
}
}
}
@ -711,7 +717,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state)
if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return;
// cull everything if subsector outside all relevant clippers
if ((sub->polys == nullptr))
if (Viewpoint.IsAllowedOoB() && (sub->polys == nullptr))
{
auto &clipper = *mClipper;
auto &clipperv = *vClipper;

View file

@ -224,8 +224,8 @@ void HWDrawInfo::ClearBuffers()
void HWDrawInfo::UpdateCurrentMapSection()
{
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
if (Viewpoint.IsAllowedOoB())
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
if (Viewpoint.IsAllowedOoB() || Viewpoint.IsOrtho())
mapsection = Level->PointInRenderSubsector(Viewpoint.OffPos)->mapsection;
CurrentMapSections.Set(mapsection);
}
@ -319,20 +319,19 @@ int HWDrawInfo::SetFullbrightFlags(player_t *player)
//
//-----------------------------------------------------------------------------
angle_t HWDrawInfo::FrustumAngle()
angle_t OoBFrustumAngle(FRenderViewpoint* Viewpoint)
{
// If pitch is larger than this you can look all around at an FOV of 90 degrees
if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff;
else if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 46.0 && !Viewpoint.IsAllowedOoB()) return 0xffffffff; // Just like 4.12.2 and older did
if (fabs(Viewpoint->HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff;
int aspMult = AspectMultiplier(r_viewwindow.WidescreenRatio); // 48 == square window
double absPitch = fabs(Viewpoint.HWAngles.Pitch.Degrees());
double absPitch = fabs(Viewpoint->HWAngles.Pitch.Degrees());
// Smaller aspect ratios still clip too much. Need a better solution
if (aspMult > 36 && absPitch > 30.0) return 0xffffffff;
else if (aspMult > 40 && absPitch > 25.0) return 0xffffffff;
else if (aspMult > 45 && absPitch > 20.0) return 0xffffffff;
else if (aspMult > 47 && absPitch > 10.0) return 0xffffffff;
double xratio = r_viewwindow.FocalTangent / Viewpoint.PitchCos;
double xratio = r_viewwindow.FocalTangent / Viewpoint->PitchCos;
double floatangle = 0.05 + atan ( xratio ) * 48.0 / aspMult; // this is radians
angle_t a1 = DAngle::fromRad(floatangle).BAMs();
@ -340,6 +339,28 @@ angle_t HWDrawInfo::FrustumAngle()
return a1;
}
angle_t HWDrawInfo::FrustumAngle()
{
if (Viewpoint.IsAllowedOoB())
{
return OoBFrustumAngle(&Viewpoint);
}
else
{
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees());
// If the pitch is larger than this you can look all around at a FOV of 90°
if (tilt > 46.0f) return 0xffffffff;
// ok, this is a gross hack that barely works...
// but at least it doesn't overestimate too much...
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees() * 48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
angle_t a1 = DAngle::fromDeg(floatangle).BAMs();
if (a1 >= ANGLE_180) return 0xffffffff;
return a1;
}
}
//-----------------------------------------------------------------------------
//
// Setup the modelview matrix
@ -425,7 +446,9 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
{
double a2 = 20.0 + 0.5*Viewpoint.FieldOfView.Degrees(); // FrustumPitch for vertical clipping
if (a2 > 179.0) a2 = 179.0;
vClipper->SafeAddClipRangeDegPitches(vp.HWAngles.Pitch.Degrees() - a2, vp.HWAngles.Pitch.Degrees() + a2); // clip the suplex range
double pitchmult = !!(portalState.PlaneMirrorFlag & 1) ? -1.0 : 1.0;
vClipper->SafeAddClipRangeDegPitches(pitchmult * vp.HWAngles.Pitch.Degrees() - a2, pitchmult * vp.HWAngles.Pitch.Degrees() + a2); // clip the suplex range
Viewpoint.PitchSin *= pitchmult;
}
// reset the portal manager
@ -1292,8 +1315,8 @@ void HWDrawInfo::ProcessScene(bool toscreen, FRenderState& state)
drawctx->portalState.BeginScene();
int mapsection = Level->PointInRenderSubsector(Viewpoint.Pos)->mapsection;
if (Viewpoint.IsAllowedOoB())
mapsection = Level->PointInRenderSubsector(Viewpoint.camera->Pos())->mapsection;
if (Viewpoint.IsAllowedOoB() || Viewpoint.IsOrtho())
mapsection = Level->PointInRenderSubsector(Viewpoint.OffPos)->mapsection;
CurrentMapSections.Set(mapsection);
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN, state);

View file

@ -48,6 +48,7 @@
#include "hw_renderstate.h"
#include "texturemanager.h"
#include "hw_flatdispatcher.h"
#include "hw_viewpointbuffer.h"
EXTERN_CVAR(Bool, lm_dynlights);

View file

@ -332,6 +332,7 @@ void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestenci
bool needdepth = NeedDepthBuffer();
// Restore the old view
auto &vp = di->Viewpoint;
if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility;

View file

@ -165,7 +165,6 @@ void HWWall::SkyPlane(HWWallDispatcher *di, FRenderState& state, sector_t *secto
if (glport != NULL)
{
if (sector->PortalBlocksView(plane)) return;
if (di->di && screen->instack[1 - plane]) return;
ptype = PORTALTYPE_SECTORSTACK;
portal = glport;

View file

@ -217,7 +217,7 @@ void HWDrawInfo::GetDynSpriteLight(AActor *self, sun_trace_cache_t * traceCache,
lg = light->GetGreen() / 255.0f;
lb = light->GetBlue() / 255.0f;
if (light->target)
if (light->target && (light->target->renderflags2 & RF2_LIGHTMULTALPHA))
{
float alpha = (float)light->target->Alpha;
lr *= alpha;

View file

@ -1494,7 +1494,7 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, FRenderState& state, particle_t *
if (!particle || particle->alpha <= 0)
return;
if (spr && spr->PT.texture.isNull())
if (spr && !spr->ValidTexture())
return;
lightlevel = hw_ClampLight(spr ? spr->GetLightLevel(sector) : sector->GetSpriteLight());
@ -1563,17 +1563,29 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, FRenderState& state, particle_t *
if (paused || (di->Level->isFrozen() && !(particle->flags & SPF_NOTIMEFREEZE)))
timefrac = 0.;
if (spr)
if (spr && !(spr->flags & VTF_IsParticle))
{
AdjustVisualThinker(di, spr, sector);
}
else
{
bool has_texture = particle->texture.isValid();
bool custom_animated_texture = (particle->flags & SPF_LOCAL_ANIM) && particle->animData.ok;
int particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles
bool has_texture = false;
bool custom_animated_texture = false;
int particle_style = 0;
float size = particle->size;
if (!spr)
{
has_texture = particle->texture.isValid();
custom_animated_texture = (particle->flags & SPF_LOCAL_ANIM) && particle->animData.ok;
particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles
}
else
{
size = float(spr->Scale.X);
const int ptype = spr->GetParticleType();
particle_style = (ptype != PT_DEFAULT) ? ptype : gl_particles_style;
}
// [BB] Load the texture for round or smooth particles
if (particle_style)
{
@ -1635,7 +1647,7 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, FRenderState& state, particle_t *
if (particle_style == 1) factor = 1.3f / 7.f;
else if (particle_style == 2) factor = 2.5f / 7.f;
else factor = 1 / 7.f;
float scalefac=particle->size * factor;
float scalefac= size * factor;
float ps = di->Level->pixelstretch;

View file

@ -389,6 +389,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF2, ISOMETRICSPRITES, AActor, renderflags2),
DEFINE_FLAG(RF2, SQUAREPIXELS, AActor, renderflags2),
DEFINE_FLAG(RF2, STRETCHPIXELS, AActor, renderflags2),
DEFINE_FLAG(RF2, LIGHTMULTALPHA, AActor, renderflags2),
// Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

View file

@ -2269,6 +2269,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetSpotState, GetSpotState)
//---------------------------------------------------------------------------
EXTERN_CVAR(Int, am_showmaplabel)
EXTERN_CVAR(Bool, am_showlevelname)
void FormatMapName(FLevelLocals *self, int cr, FString *result)
{
@ -2282,13 +2283,19 @@ void FormatMapName(FLevelLocals *self, int cr, FString *result)
if (self->info->MapLabel.IsNotEmpty())
{
if (self->info->MapLabel.Compare("*"))
*result << self->info->MapLabel << ": ";
*result << self->info->MapLabel;
}
else if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub))
{
*result << self->MapName << ": ";
*result << self->MapName;
}
if (am_showlevelname)
{
if (!result->IsEmpty())
*result << ": ";
*result << mapnamecolor << self->LevelName;
}
*result << mapnamecolor << self->LevelName;
}
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, FormatMapName, FormatMapName)