From da3da61b67e52e0b8f5c7b9c4929b6d692800118 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 11 Jan 2017 18:36:20 +0100 Subject: [PATCH 01/15] - Make OpenGL library link fully dynamic on Unix. Also, remove all the OpenGL CMake checks, because they're not needed anymore. --- src/CMakeLists.txt | 10 ---------- src/gl/system/gl_load.c | 12 +++++++----- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2668356cf..c51998874 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,6 @@ include( CheckIncludeFile ) include( CheckIncludeFiles ) include( CheckLibraryExists ) include( FindPkgConfig ) -include( FindOpenGL ) if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) @@ -255,15 +254,6 @@ else() endif() endif() -# Check if we have OpenGL - -if( NOT OPENGL_FOUND ) - message( FATAL_ERROR "OpenGL is required for building." ) -endif( NOT OPENGL_FOUND ) - -set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENGL_LIBRARIES} ) -include_directories( ${OPENGL_INCLUDE_DIR} ) - if( NOT NO_OPENAL ) find_package( OpenAL ) mark_as_advanced(CLEAR OPENAL_INCLUDE_DIR) diff --git a/src/gl/system/gl_load.c b/src/gl/system/gl_load.c index f390b5cc9..643b79013 100644 --- a/src/gl/system/gl_load.c +++ b/src/gl/system/gl_load.c @@ -17,11 +17,12 @@ static void* AppleGLGetProcAddress (const char *name) } #endif /* __APPLE__ */ -#if defined(__sgi) || defined (__sun) +/* BEGINNING OF MANUAL CHANGES, DO NOT REMOVE! */ +#if defined(__sgi) || defined (__sun) || defined(__unix__) #include #include -static void* SunGetProcAddress (const GLubyte* name) +static void* PosixGetProcAddress (const GLubyte* name) { static void* h = NULL; static void* gpa; @@ -37,7 +38,7 @@ static void* SunGetProcAddress (const GLubyte* name) else return dlsym(h, (const char*)name); } -#endif /* __sgi || __sun */ +#endif /* __sgi || __sun || __unix__ */ #if defined(_WIN32) @@ -77,8 +78,9 @@ static PROC WinGetProcAddress(const char *name) #if defined(__APPLE__) #define IntGetProcAddress(name) AppleGLGetProcAddress(name) #else - #if defined(__sgi) || defined(__sun) - #define IntGetProcAddress(name) SunGetProcAddress(name) + #if defined(__sgi) || defined(__sun) || defined(__unix__) + #define IntGetProcAddress(name) PosixGetProcAddress((const GLubyte*)name) +/* END OF MANUAL CHANGES, DO NOT REMOVE! */ #else /* GLX */ #include From 6f5fff00a02618bba5507ecc8f2be26a4d8efe7b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sat, 21 Jan 2017 02:07:44 +0200 Subject: [PATCH 02/15] Implemented static methods in String struct. Implemented String.Format and String.AppendFormat. Implemented native vararg methods for the future. --- src/dobjtype.h | 1 + src/sc_man_scanner.re | 1 + src/sc_man_tokens.h | 1 + src/scripting/codegeneration/codegen.cpp | 301 ++---------------- src/scripting/codegeneration/codegen.h | 21 -- src/scripting/thingdef_data.cpp | 173 ++++++++++ src/scripting/zscript/zcc-parse.lemon | 3 +- src/scripting/zscript/zcc_compile.cpp | 10 +- src/scripting/zscript/zcc_parser.cpp | 1 + src/scripting/zscript/zcc_parser.h | 1 + wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/shared/player_cheat.txt | 6 +- wadsrc/static/zscript/shared/sharedmisc.txt | 2 +- wadsrc/static/zscript/shared/skies.txt | 2 +- 14 files changed, 213 insertions(+), 312 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index 316a2bccc..79aee5849 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -35,6 +35,7 @@ enum VARF_Ref = (1<<16), // argument is passed by reference. 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 }; // Symbol information ------------------------------------------------------- diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 31a9c022f..ae35935f5 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -171,6 +171,7 @@ std2: 'export' { RET(TK_Export); } 'virtual' { RET(TK_Virtual); } 'override' { RET(TK_Override); } + 'vararg' { RET(TK_VarArg); } 'super' { RET(TK_Super); } 'global' { RET(TK_Global); } 'stop' { RET(TK_Stop); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index fb8f1c5ae..9f88e2242 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -112,6 +112,7 @@ xx(TK_Iterator, "'iterator'") xx(TK_Optional, "'optional'") xx(TK_Export, "'expert'") xx(TK_Virtual, "'virtual'") +xx(TK_VarArg, "'vararg'") xx(TK_Override, "'override'") xx(TK_Super, "'super'") xx(TK_Null, "'null'") diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4395d123e..fc59b0e97 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -7188,14 +7188,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } } - // [ZZ] string formatting function - if (MethodName == NAME_Format) - { - FxExpression *x = new FxFormat(ArgList, ScriptPosition); - delete this; - return x->Resolve(ctx); - } - int min, max, special; if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS) { @@ -7466,6 +7458,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { + // [ZZ] substitute ccls for String internal type. + if (ccls->TypeName == NAME_String) + ccls = TypeStringStruct; if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) { cls = ccls; @@ -8056,6 +8051,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) for (unsigned i = 0; i < ArgList.Size(); i++) { // Varargs must all have the same type as the last typed argument. A_Jump is the only function using it. + // [ZZ] Varargs MAY have arbitrary types if the method is marked vararg. if (!foundvarargs) { if (argtypes[i + implicit] == nullptr) foundvarargs = true; @@ -8129,7 +8125,20 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } FxExpression *x; - if (!(flag & (VARF_Ref|VARF_Out))) + if (foundvarargs && (Function->Variants[0].Flags & VARF_VarArg)) + { + // only cast implicit-string types for vararg, leave everything else as-is + // this was outright copypasted from FxFormat + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i]->ValueType == TypeName || + ArgList[i]->ValueType == TypeSound) + { + FxExpression* x = new FxStringCast(ArgList[i]); + x = x->Resolve(ctx); + } + else x = ArgList[i]; + } + else if (!(flag & (VARF_Ref|VARF_Out))) { x = new FxTypeCast(ArgList[i], type, false); x = x->Resolve(ctx); @@ -8475,280 +8484,6 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) return to; } - -//========================================================================== -// -// -// -//========================================================================== - -FxFormat::FxFormat(FArgumentList &args, const FScriptPosition &pos) - : FxExpression(EFX_Format, pos) -{ - EmitTail = false; - ArgList = std::move(args); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFormat::~FxFormat() -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxFormat::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxFormat::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - - for (unsigned i = 0; i < ArgList.Size(); i++) - { - ArgList[i] = ArgList[i]->Resolve(ctx); - if (ArgList[i] == nullptr) - { - delete this; - return nullptr; - } - - // first argument should be a string - if (!i && ArgList[i]->ValueType != TypeString) - { - ScriptPosition.Message(MSG_ERROR, "String was expected for format"); - delete this; - return nullptr; - } - - if (ArgList[i]->ValueType == TypeName || - ArgList[i]->ValueType == TypeSound) - { - FxExpression* x = new FxStringCast(ArgList[i]); - x = x->Resolve(ctx); - if (x == nullptr) - { - delete this; - return nullptr; - } - ArgList[i] = x; - } - } - - ValueType = TypeString; - return this; -} - -//========================================================================== -// -// -//========================================================================== - -static int BuiltinFormat(VMValue *args, TArray &defaultparam, int numparam, VMReturn *ret, int numret) -{ - assert(args[0].Type == REGT_STRING); - FString fmtstring = args[0].s().GetChars(); - - // note: we don't need a real printf format parser. - // enough to simply find the subtitution tokens and feed them to the real printf after checking types. - // https://en.wikipedia.org/wiki/Printf_format_string#Format_placeholder_specification - FString output; - bool in_fmt = false; - FString fmt_current; - int argnum = 1; - int argauto = 1; - // % = starts - // [0-9], -, +, \s, 0, #, . continue - // %, s, d, i, u, fF, eE, gG, xX, o, c, p, aA terminate - // various type flags are not supported. not like stuff like 'hh' modifier is to be used in the VM. - // the only combination that is parsed locally is %n$... - bool haveargnums = false; - for (size_t i = 0; i < fmtstring.Len(); i++) - { - char c = fmtstring[i]; - if (in_fmt) - { - if ((c >= '0' && c <= '9') || - c == '-' || c == '+' || (c == ' ' && fmt_current[fmt_current.Len() - 1] != ' ') || c == '#' || c == '.') - { - fmt_current += c; - } - else if (c == '$') // %number$format - { - if (!haveargnums && argauto > 1) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - FString argnumstr = fmt_current.Mid(1); - if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars()); - argnum = argnumstr.ToLong(); - if (argnum < 1 || argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum, numparam); - fmt_current = "%"; - haveargnums = true; - } - else - { - fmt_current += c; - - switch (c) - { - // string - case 's': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not a string - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (args[argnum].Type != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), args[argnum].s().GetChars()); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } - - // pointer - case 'p': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not a string - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (args[argnum].Type != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), args[argnum].a); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } - - // int formats (including char) - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'c': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not an int - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (args[argnum].Type != REGT_INT && - args[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), args[argnum].ToInt()); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } - - // double formats - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - { - if (argnum < 0 && haveargnums) - ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); - in_fmt = false; - // fail if something was found, but it's not a float - if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (args[argnum].Type != REGT_INT && - args[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); - // append - output.AppendFormat(fmt_current.GetChars(), args[argnum].ToDouble()); - if (!haveargnums) argnum = ++argauto; - else argnum = -1; - break; - } - - default: - // invalid character - output += fmt_current; - in_fmt = false; - break; - } - } - } - else - { - if (c == '%') - { - if (i + 1 < fmtstring.Len() && fmtstring[i + 1] == '%') - { - output += '%'; - i++; - } - else - { - in_fmt = true; - fmt_current = "%"; - } - } - else - { - output += c; - } - } - } - - ACTION_RETURN_STRING(output); -} - -ExpEmit FxFormat::Emit(VMFunctionBuilder *build) -{ - // Call DecoRandom to generate a random number. - VMFunction *callfunc; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFormat, BuiltinFormat); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - - for (unsigned i = 0; i < ArgList.Size(); i++) - EmitParameter(build, ArgList[i], ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), ArgList.Size(), 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit out(build, REGT_STRING); - build->Emit(OP_RESULT, 0, REGT_STRING, out.RegNum); - return out; -} - - //========================================================================== // // diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 8b43d28fa..3dac463eb 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -255,7 +255,6 @@ enum EFxType EFX_MemberFunctionCall, EFX_ActionSpecialCall, EFX_FlopFunctionCall, - EFX_Format, EFX_VMFunctionCall, EFX_Sequence, EFX_CompoundStatement, @@ -1534,26 +1533,6 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; -//========================================================================== -// -// FxFormat -// -//========================================================================== - -class FxFormat : public FxExpression -{ - FArgumentList ArgList; - bool EmitTail; - -public: - - FxFormat(FArgumentList &args, const FScriptPosition &pos); - ~FxFormat(); - FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); - ExpEmit Emit(VMFunctionBuilder *build); -}; - //========================================================================== // // FxVectorBuiltin diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 21e4f46d9..1dd8d6263 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -945,3 +945,176 @@ DEFINE_ACTION_FUNCTION(FString, Replace) return 0; } +static FString FStringFormat(VM_ARGS) +{ + assert(param[0].Type == REGT_STRING); + FString fmtstring = param[0].s().GetChars(); + + // note: we don't need a real printf format parser. + // enough to simply find the subtitution tokens and feed them to the real printf after checking types. + // https://en.wikipedia.org/wiki/Printf_format_string#Format_placeholder_specification + FString output; + bool in_fmt = false; + FString fmt_current; + int argnum = 1; + int argauto = 1; + // % = starts + // [0-9], -, +, \s, 0, #, . continue + // %, s, d, i, u, fF, eE, gG, xX, o, c, p, aA terminate + // various type flags are not supported. not like stuff like 'hh' modifier is to be used in the VM. + // the only combination that is parsed locally is %n$... + bool haveargnums = false; + for (size_t i = 0; i < fmtstring.Len(); i++) + { + char c = fmtstring[i]; + if (in_fmt) + { + if ((c >= '0' && c <= '9') || + c == '-' || c == '+' || (c == ' ' && fmt_current[fmt_current.Len() - 1] != ' ') || c == '#' || c == '.') + { + fmt_current += c; + } + else if (c == '$') // %number$format + { + if (!haveargnums && argauto > 1) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + FString argnumstr = fmt_current.Mid(1); + if (!argnumstr.IsInt()) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for argument number, got '%s'.", argnumstr.GetChars()); + argnum = argnumstr.ToLong(); + if (argnum < 1 || argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format (tried to access argument %d, %d total).", argnum, numparam); + fmt_current = "%"; + haveargnums = true; + } + else + { + fmt_current += c; + + switch (c) + { + // string + case 's': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not a string + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (param[argnum].Type != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars()); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // pointer + case 'p': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not a string + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (param[argnum].Type != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].a); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // int formats (including char) + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'c': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not an int + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (param[argnum].Type != REGT_INT && + param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt()); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + // double formats + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + { + if (argnum < 0 && haveargnums) + ThrowAbortException(X_FORMAT_ERROR, "Cannot mix explicit and implicit arguments."); + in_fmt = false; + // fail if something was found, but it's not a float + if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); + if (param[argnum].Type != REGT_INT && + param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + // append + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble()); + if (!haveargnums) argnum = ++argauto; + else argnum = -1; + break; + } + + default: + // invalid character + output += fmt_current; + in_fmt = false; + break; + } + } + } + else + { + if (c == '%') + { + if (i + 1 < fmtstring.Len() && fmtstring[i + 1] == '%') + { + output += '%'; + i++; + } + else + { + in_fmt = true; + fmt_current = "%"; + } + } + else + { + output += c; + } + } + } + + return output; +} + +DEFINE_ACTION_FUNCTION(FString, Format) +{ + PARAM_PROLOGUE; + FString s = FStringFormat(param, defaultparam, numparam, ret, numret); + ACTION_RETURN_STRING(s); +} + +DEFINE_ACTION_FUNCTION(FString, AppendFormat) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + // first parameter is the self pointer + FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret); + (*self) += s; + return 0; +} \ No newline at end of file diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index d0ff03625..bae828493 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -722,7 +722,7 @@ type_name1(X) ::= BOOL(T). { X.Int = ZCC_Bool; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= int_type(X). type_name1(X) ::= FLOAT(T). { X.Int = ZCC_FloatAuto; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= DOUBLE(T). { X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc; } -type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } +//type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } // [ZZ] it's handled elsewhere. this particular line only causes troubles in the form of String.Format being invalid. type_name1(X) ::= VECTOR2(T). { X.Int = ZCC_Vector2; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= VECTOR3(T). { X.Int = ZCC_Vector3; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; } @@ -994,6 +994,7 @@ 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; } func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); } func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ab96813bd..eccd12833 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1423,10 +1423,11 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper FString ZCCCompiler::FlagsToString(uint32_t flags) { - const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "funcconst", "abstract" }; + + const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "funcconst", "abstract", "extension", "virtual", "override", "transient", "vararg" }; FString build; - for (int i = 0; i < 12; i++) + for (int i = 0; i < countof(flagnames); i++) { if (flags & (1 << i)) { @@ -2287,6 +2288,11 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; 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_VarArg) && !(f->Flags & ZCC_Native)) + { + Error(f, "'VarArg' can only be used with native methods"); + } if (f->Flags & ZCC_Action) { // Non-Actors cannot have action functions. diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index a0ecbe06c..95f75aea6 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -136,6 +136,7 @@ static void InitTokenMap() TOKENDEF (TK_Protected, ZCC_PROTECTED); TOKENDEF (TK_Latent, ZCC_LATENT); TOKENDEF (TK_Virtual, ZCC_VIRTUAL); + TOKENDEF (TK_VarArg, ZCC_VARARG); TOKENDEF (TK_Override, ZCC_OVERRIDE); TOKENDEF (TK_Final, ZCC_FINAL); TOKENDEF (TK_Meta, ZCC_META); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 19c327fc9..b80686bb0 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -36,6 +36,7 @@ enum ZCC_Virtual = 1 << 13, ZCC_Override = 1 << 14, ZCC_Transient = 1 << 15, + ZCC_VarArg = 1 << 16 }; // Function parameter modifiers diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index d5e58f653..eab046372 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -308,6 +308,8 @@ enum EPickStart struct String native { native void Replace(String pattern, String replacement); + native static vararg String Format(String fmt, ...); + native vararg void AppendFormat(String fmt, ...); } class Floor : Thinker native diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index b8c24b30f..3dba4ac2d 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -50,7 +50,7 @@ extend class PlayerPawn let player = self.player; if (PlayerNumber() != consoleplayer) - A_Log(format ("%s is a cheater: give %s\n", player.GetUserName(), name)); + A_Log(String.Format ("%s is a cheater: give %s\n", player.GetUserName(), name)); if (player.mo == NULL || player.health <= 0) { @@ -254,7 +254,7 @@ extend class PlayerPawn if (type == NULL) { if (PlayerNumber() == consoleplayer) - A_Log(format("Unknown item \"%s\"\n", name)); + A_Log(String.Format("Unknown item \"%s\"\n", name)); } else { @@ -391,7 +391,7 @@ extend class PlayerPawn if (type == NULL) { if (PlayerNumber() == consoleplayer) - A_Log(format("Unknown item \"%s\"\n", name)); + A_Log(String.Format("Unknown item \"%s\"\n", name)); } else { diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index bc410e3f0..7403edec3 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -159,7 +159,7 @@ class CustomSprite : Actor String name; Super.BeginPlay (); - format(name, "BTIL%04d", args[0] & 0xffff); + //format(name, "BTIL%04d", args[0] & 0xffff); // note: this does NOTHING and did NOTHING. what? picnum = TexMan.CheckForTexture (name, TexMan.TYPE_Build); if (!picnum.Exists()) { diff --git a/wadsrc/static/zscript/shared/skies.txt b/wadsrc/static/zscript/shared/skies.txt index c817a3994..0bb0a78ef 100644 --- a/wadsrc/static/zscript/shared/skies.txt +++ b/wadsrc/static/zscript/shared/skies.txt @@ -115,7 +115,7 @@ class SkyPicker : Actor if (box == null && args[0] != 0) { - A_Log(format("Can't find SkyViewpoint %d for sector %d\n", args[0], CurSector.Index())); + A_Log(String.Format("Can't find SkyViewpoint %d for sector %d\n", args[0], CurSector.Index())); } else { From 59472d6f632e4ac197b02fe49d1b4ad684f3ed5e Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sat, 21 Jan 2017 05:19:59 +0200 Subject: [PATCH 03/15] Fixed CustomSprite actor --- wadsrc/static/zscript/shared/sharedmisc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index 7403edec3..73f33c060 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -159,7 +159,7 @@ class CustomSprite : Actor String name; Super.BeginPlay (); - //format(name, "BTIL%04d", args[0] & 0xffff); // note: this does NOTHING and did NOTHING. what? + name = String.Format("BTIL%04d", args[0] & 0xffff); picnum = TexMan.CheckForTexture (name, TexMan.TYPE_Build); if (!picnum.Exists()) { From df1a90fb1bd1e8bacf447ee0312471b3deec53a4 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sat, 21 Jan 2017 05:23:00 +0200 Subject: [PATCH 04/15] Apparently 'name = something' gets parsed as a Type. Fixed CustomSprite actor again. --- wadsrc/static/zscript/shared/sharedmisc.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt index 73f33c060..c837f5f1e 100644 --- a/wadsrc/static/zscript/shared/sharedmisc.txt +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -156,10 +156,9 @@ class CustomSprite : Actor override void BeginPlay () { - String name; Super.BeginPlay (); - name = String.Format("BTIL%04d", args[0] & 0xffff); + String name = String.Format("BTIL%04d", args[0] & 0xffff); picnum = TexMan.CheckForTexture (name, TexMan.TYPE_Build); if (!picnum.Exists()) { From 5158b1c337ffda2bc7431f774ac10b307800adbb Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 21 Jan 2017 11:40:22 +0200 Subject: [PATCH 05/15] Fixed undefined behavior of DropInventory() See https://mantis.zdoom.org/view.php?id=93 --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0cdd197a8..210c0cd5b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1041,7 +1041,7 @@ AInventory *AActor::DropInventory (AInventory *item) AInventory *drop = nullptr; IFVIRTUALPTR(item, AInventory, CreateTossable) { - VMValue params[1] = { (DObject*)this }; + VMValue params[1] = { (DObject*)item }; VMReturn ret((void**)&drop); GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); } From 19df603f92b314d33dbf444ea0eb7d5a56112b7b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 10:55:19 +0100 Subject: [PATCH 06/15] - fixed: P_RailAttack did not make adjustments for the shooter's floorclip. --- src/g_level.cpp | 6 ++++++ src/p_map.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 019106d75..a71b481c9 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -432,10 +432,16 @@ void G_InitNew (const char *mapname, bool bTitleLevel) StatusBar->Destroy(); StatusBar = NULL; } + auto cls = PClass::FindClass("DoomStatusBar"); + if (bTitleLevel) { StatusBar = new DBaseStatusBar (0); } + else if (cls && gameinfo.gametype == GAME_Doom) + { + StatusBar = (DBaseStatusBar*)cls->CreateNew(); + } else if (SBarInfoScript[SCRIPT_CUSTOM] != NULL) { int cstype = SBarInfoScript[SCRIPT_CUSTOM]->GetGameType(); diff --git a/src/p_map.cpp b/src/p_map.cpp index ae3dfd0f2..ac5ca10a7 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5011,7 +5011,7 @@ void P_RailAttack(FRailParams *p) DAngle angle = source->Angles.Yaw + p->angleoffset; DVector3 vec(DRotator(-pitch, angle, angle)); - double shootz = source->Center() - source->FloatSpeed + p->offset_z; + double shootz = source->Center() - source->FloatSpeed + p->offset_z - source->Floorclip; if (!(p->flags & RAF_CENTERZ)) { From cbdf9870ecfcd5e410f76e49a11ee6efe196248b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 11:46:23 +0100 Subject: [PATCH 07/15] - fix uninitialized variable. --- src/scripting/codegeneration/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index fc59b0e97..ff2d3f8eb 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8124,7 +8124,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) flag = argflags[i + implicit]; } - FxExpression *x; + FxExpression *x = nullptr; if (foundvarargs && (Function->Variants[0].Flags & VARF_VarArg)) { // only cast implicit-string types for vararg, leave everything else as-is From 4dc1d117f2b58dcd260acf3c777e8eb30fe1e2cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 11:50:53 +0100 Subject: [PATCH 08/15] - fixed: Without letting CMake find OpenGL, under Windows the library must be added manually to the project or linker errors will happen. --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c51998874..870275324 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -161,6 +161,7 @@ if( WIN32 ) endif() set( ZDOOM_LIBS + opengl32 wsock32 winmm "${DX_dinput8_LIBRARY}" From 2a6fafa15eab3958f4fa1f60d3080858e1e20d55 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 13:12:34 +0100 Subject: [PATCH 09/15] - don't let P_DamageMobj return negative values. This serves no purpose, there's not a single place in the code which checks for it, but if that negative values goes unchecked to functions that expect an actually meaningful value for damage inflicted, some bad results can happen. If no damage is inflicted, a proper 0 needs to be returned so that the value can actually be worked with. The return value was a ZDoom invention, it is completely unclear why -1 was chosen if some kind of protection rendered the damage ineffective. --- src/p_interaction.cpp | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 0320b0feb..c33cfb080 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -979,7 +979,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) { // Shouldn't happen - return -1; + return 0; } //Rather than unnecessarily call the function over and over again, let's be a little more efficient. @@ -991,14 +991,14 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL)) { - return -1; + return 0; } } if (target->health <= 0) { if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER)) { - return -1; + return 0; } else if (target->flags & MF_ICECORPSE) // frozen { @@ -1006,7 +1006,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da target->flags6 |= MF6_SHATTERING; target->Vel.Zero(); } - return -1; + return 0; } // [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything // different here. At any rate, invulnerable is being checked before type factoring, which is then being @@ -1027,7 +1027,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da goto fakepain; } else - return -1; + return 0; } } else @@ -1038,7 +1038,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (fakedPain) plrDontThrust = 1; else - return -1; + return 0; } } @@ -1068,7 +1068,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (target->flags2 & MF2_DORMANT) { // Invulnerable, and won't wake up - return -1; + return 0; } if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect. @@ -1086,19 +1086,19 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (player != NULL) { if (!deathmatch && inflictor->FriendPlayer > 0) - return -1; + return 0; } else if (target->flags4 & MF4_SPECTRAL) { if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor)) - return -1; + return 0; } } damage = inflictor->CallDoSpecialDamage(target, damage, mod); if (damage < 0) { - return -1; + return 0; } } @@ -1141,7 +1141,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { goto fakepain; } - return -1; + return 0; } } } @@ -1153,7 +1153,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (damage < 0) { // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain. - return -1; + return 0; } // Push the target unless the source's weapon's kickback is 0. // (i.e. Gauntlets/Chainsaw) @@ -1244,7 +1244,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da damage = (int)(damage * level.teamdamage); if (damage < 0) { - return damage; + return 0; } else if (damage == 0) { @@ -1256,7 +1256,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { goto fakepain; } - return -1; + return 0; } } } @@ -1294,14 +1294,14 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da //Make sure no godmodes and NOPAIN flags are found first. //Then, check to see if the player has NODAMAGE or ALLOWPAIN, or inflictor has CAUSEPAIN. if ((player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN)) - return -1; + return 0; else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)))) { invulpain = true; goto fakepain; } else - return -1; + return 0; } // Armor for players. if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) @@ -1321,7 +1321,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { // [MC] Godmode doesn't need checking here, it's already being handled above. if ((target->flags5 & MF5_NOPAIN) || (inflictor && (inflictor->flags5 & MF5_PAINLESS))) - return damage; + return 0; // If MF6_FORCEPAIN is set, make the player enter the pain state. if ((inflictor && (inflictor->flags6 & MF6_FORCEPAIN))) @@ -1332,7 +1332,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da invulpain = true; goto fakepain; } - return damage; + return 0; } } @@ -1396,7 +1396,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (fakedPain) goto fakepain; else - return damage; + return 0; } } @@ -1468,7 +1468,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } } target->CallDie (source, inflictor, flags); - return damage; + return MAX(0, damage); } } @@ -1480,7 +1480,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (target->health <= woundhealth) { target->SetState (woundstate); - return damage; + return MAX(0, damage); } } @@ -1579,9 +1579,9 @@ dopain: if (invulpain) //Note that this takes into account all the cheats a player has, in terms of invulnerability. { - return -1; //NOW we return -1! + return 0; //NOW we return -1! } - return damage; + return MAX(0, damage); } DEFINE_ACTION_FUNCTION(AActor, DamageMobj) From 45d3b58cc61d689a42e86427aade357ed7e4169e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 13:26:26 +0100 Subject: [PATCH 10/15] - fixed redundant variable declaration shadowing an outer one. --- src/scripting/codegeneration/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index ff2d3f8eb..cb5944ade 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8133,7 +8133,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (ArgList[i]->ValueType == TypeName || ArgList[i]->ValueType == TypeSound) { - FxExpression* x = new FxStringCast(ArgList[i]); + x = new FxStringCast(ArgList[i]); x = x->Resolve(ctx); } else x = ArgList[i]; From 2358b6592134b14fa7fb3a5a8f0aafed81539aaa Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 21 Jan 2017 14:47:10 +0200 Subject: [PATCH 11/15] Fixed compiler warning reported by GGC/Clang No more 'warning: comparison of integers of different signs: int and unsigned long' --- src/scripting/zscript/zcc_compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index eccd12833..ddf08fbc4 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1427,7 +1427,7 @@ 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" }; FString build; - for (int i = 0; i < countof(flagnames); i++) + for (size_t i = 0; i < countof(flagnames); i++) { if (flags & (1 << i)) { From 06ad2351d3ec4b8054a9a79f935eb1187549a9d3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 19:54:53 +0100 Subject: [PATCH 12/15] - fixed error in vertical velocity calculation for A_SkullAttack. --- wadsrc/static/zscript/doom/lostsoul.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wadsrc/static/zscript/doom/lostsoul.txt b/wadsrc/static/zscript/doom/lostsoul.txt index 89cefc42a..7d918aa10 100644 --- a/wadsrc/static/zscript/doom/lostsoul.txt +++ b/wadsrc/static/zscript/doom/lostsoul.txt @@ -90,19 +90,19 @@ class BetaSkull : LostSoul extend class Actor { - const SKULLSPEED = 20; + const DEFSKULLSPEED = 20; - void A_SkullAttack(double skullspeed = SKULLSPEED) + void A_SkullAttack(double skullspeed = DEFSKULLSPEED) { if (target == null) return; - if (skullspeed <= 0) skullspeed = SKULLSPEED; + if (skullspeed <= 0) skullspeed = DEFSKULLSPEED; bSkullfly = true; A_PlaySound(AttackSound, CHAN_VOICE); A_FaceTarget(); VelFromAngle(skullspeed); - Vel.Z = (target.pos.Z + target.Height/2 - pos.Z) / DistanceBySpeed(target, speed); + Vel.Z = (target.pos.Z + target.Height/2 - pos.Z) / DistanceBySpeed(target, skullspeed); } void A_BetaSkullAttack() From aaae52c60b646aca0be97abeaf44883c14942d36 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 20:15:06 +0100 Subject: [PATCH 13/15] - fixed: FResourceFile::OpenResourceFile did not close the opened file in case it contained invalid data. --- src/resourcefiles/resourcefile.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 603606341..c9f2f7446 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -291,11 +291,13 @@ static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, Ch FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader *file, bool quiet, bool containeronly) { + bool mustclose = false; if (file == NULL) { try { file = new FileReader(filename); + mustclose = true; } catch (CRecoverableError &) { @@ -307,6 +309,7 @@ FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader FResourceFile *resfile = funcs[i](filename, file, quiet); if (resfile != NULL) return resfile; } + if (mustclose) delete file; return NULL; } From 659c11514bac6de25123ca79cf2312d9dbc49afb Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sat, 21 Jan 2017 23:58:16 +0200 Subject: [PATCH 14/15] OpenGL: Added picnum override handling for actors --- src/gl/scene/gl_sprite.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 92416f88b..adbc626ed 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -646,8 +646,14 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) sector_t rs; sector_t * rendersector; + if (thing == nullptr) + return; + + // [ZZ] allow CustomSprite-style direct picnum specification + bool isPicnumOverride = thing->picnum.isValid(); + // Don't waste time projecting sprites that are definitely not visible. - if (thing == nullptr || thing->sprite == 0 || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles()) + if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles()) { return; } @@ -752,13 +758,19 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) z += fz; } - modelframe = gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); if (!modelframe) { bool mirror; DAngle ang = (thingpos - ViewPos).Angle(); FTextureID patch; - if (thing->flags7 & MF7_SPRITEANGLE) + // [ZZ] add direct picnum override + if (isPicnumOverride) + { + patch = thing->picnum; + mirror = false; + } + else if (thing->flags7 & MF7_SPRITEANGLE) { patch = gl_GetSpriteFrame(spritenum, thing->frame, -1, (thing->SpriteAngle).BAMs(), &mirror); } @@ -775,7 +787,8 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (!patch.isValid()) return; int type = thing->renderflags & RF_SPRITETYPEMASK; gltexture = FMaterial::ValidateTexture(patch, (type == RF_FACESPRITE), false); - if (!gltexture) return; + if (!gltexture) + return; vt = gltexture->GetSpriteVT(); vb = gltexture->GetSpriteVB(); From ee40135d559f8bf05a0ed45df79867a719229b95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Jan 2017 23:26:27 +0100 Subject: [PATCH 15/15] - removed the bogus SetPointer method from PClassPointer. This was blocking proper bookkeeping of class pointer variables, in particular it rendered PointerSubstitution ineffective. --- src/dobjtype.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index 79aee5849..d38c42c58 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -598,8 +598,6 @@ public: class PClass *ClassRestriction; - // this is only here to block PPointer's implementation - void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override {} bool isCompatible(PType *type); virtual bool IsMatch(intptr_t id1, intptr_t id2) const;