diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 611a667af..9662af1bb 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -214,6 +214,19 @@ Note: All fields default to false unless mentioned otherwise. damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.' ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.' + + portal_ceil_alpha = // translucency of ceiling portal (default is 0 (not visible)) + portal_ceil_blocksound = // ceiling portal blocks sound. + portal_ceil_disabled = // ceiling portal disabled. + portal_ceil_nopass = // ceiling portal blocks movement if true. + portal_ceil_norender = // ceiling portal not rendered. + portal_ceil_overlaytype = // defines translucency style, can either be "translucent" or "additive". Default is "translucent". + portal_floor_alpha = // translucency of floor portal (default is 0 (not visible)) + portal_floor_blocksound = // floor portal blocks sound. + portal_floor_disabled = // floor portal disabled. + portal_floor_nopass = // ceiling portal blocks movement if true. + portal_floor_norender = // ceiling portal not rendered. + portal_floor_overlaytype = // defines translucency style, can either be "translucent" or "additive". Default is "translucent". * Note about dropactors diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19e5c9a0c..de3316ced 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,8 @@ endif() include( CheckCXXSourceCompiles ) include( CheckFunctionExists ) include( CheckCXXCompilerFlag ) +include( CheckIncludeFile ) +include( CheckIncludeFiles ) include( CheckLibraryExists ) include( FindPkgConfig ) include( FindOpenGL ) @@ -119,7 +121,13 @@ if( WIN32 ) PATHS ENV DXSDK_DIR PATH_SUFFIXES Include ) if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) + # Modern versions of the Windows SDK include d3d9.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILE. + CHECK_INCLUDE_FILE( d3d9.h D3D9_H_FOUND ) + if ( NOT D3D9_H_FOUND ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) + endif() else() include_directories( ${D3D_INCLUDE_DIR} ) endif() @@ -128,35 +136,41 @@ if( WIN32 ) PATHS ENV DXSDK_DIR PATH_SUFFIXES Include ) if( NOT XINPUT_INCLUDE_DIR ) - message( WARNING "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) + # Modern versions of the Windows SDK include xinput.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILES. windows.h must be included before xinput.h. + CHECK_INCLUDE_FILES( "windows.h;xinput.h" XINPUT_H_FOUND ) + if( NOT XINPUT_H_FOUND ) + message( WARNING "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + endif() else() include_directories( ${XINPUT_INCLUDE_DIR} ) endif() - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) find_library( DX_dinput8_LIBRARY dinput8 PATHS ENV DXSDK_DIR PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) - set( DX_LIBS_FOUND YES ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() + # Modern versions of the Windows SDK include dinput8.lib. Unfortunately, + # CMake cannot find these libraries via find_library. if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) + # If we got this far, assume dinput8.lib is in the system library path. + set( DX_dinput8_LIBRARY dinput8 ) endif() - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + # Modern versions of the Windows SDK do NOT include dxguid.lib. Its contents + # were moved to dinput8.lib. + if( NOT DX_dxguid_LIBRARY ) + message( STATUS "Could not find dxguid.lib. Build may fail on old Windows SDKs.") endif() set( ZDOOM_LIBS wsock32 winmm - "${DX_dxguid_LIBRARY}" "${DX_dinput8_LIBRARY}" ole32 user32 @@ -167,6 +181,9 @@ if( WIN32 ) setupapi oleaut32 DelayImp ) + if( DX_dxguid_LIBRARY ) + list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" ) + endif() else() if( APPLE ) set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) diff --git a/src/actor.h b/src/actor.h index 2ae26e7ef..800548d2c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -755,6 +755,9 @@ public: // What species am I? virtual FName GetSpecies(); + // set translation + void SetTranslation(const char *trname); + double GetBobOffset(double ticfrac = 0) const { if (!(flags2 & MF2_FLOATBOB)) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2dbf1273c..dad2b86d9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2439,6 +2439,7 @@ void D_DoomMain (void) if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); + R_ParseTrnslate(); PClassActor::StaticInit (); // [GRB] Initialize player class list diff --git a/src/dobject.cpp b/src/dobject.cpp index 8fba75aa6..4acb86ce4 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -330,7 +330,11 @@ DObject::~DObject () } } } - type->DestroySpecials(this); + + if (nullptr != type) + { + type->DestroySpecials(this); + } } } diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index c1253f966..82349c1a7 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -54,6 +54,12 @@ void AFastProjectile::Tick () // Handle movement if (!Vel.isZero() || (Z() != floorz)) { + // force some lateral movement so that collision detection works as intended. + if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage()) + { + Vel.X = MinVel; + } + frac = Vel / count; changexy = frac.X != 0 || frac.Y != 0; int ripcount = count / 8; @@ -124,7 +130,7 @@ void AFastProjectile::Tick () P_ExplodeMissile (this, NULL, NULL); return; } - if (changexy && ripcount <= 0) + if (!frac.isZero() && ripcount <= 0) { ripcount = count >> 3; Effect(); diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index b7827f6bd..13c98d833 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1021,7 +1021,7 @@ class CommandDrawNumber : public CommandDrawString usePrefix(false), interpolationSpeed(0), drawValue(0), length(3), lowValue(-1), lowTranslation(CR_UNTRANSLATED), highValue(-1), highTranslation(CR_UNTRANSLATED), value(CONSTANT), - inventoryItem(NULL) + inventoryItem(NULL), cvarName(nullptr) { } @@ -1166,6 +1166,37 @@ class CommandDrawNumber : public CommandDrawString if(parenthesized) sc.MustGetToken(')'); } + else if (sc.Compare("intcvar")) + { + bool parenthesized = sc.CheckToken('('); + + value = INTCVAR; + + if (!parenthesized || !sc.CheckToken(TK_StringConst)) + sc.MustGetToken(TK_Identifier); + + cvarName = sc.String; + + // We have a name, but make sure it exists. If not, send notification so modders + // are aware of the situation. + FBaseCVar *CVar = FindCVar(cvarName, nullptr); + + if (CVar != nullptr) + { + ECVarType cvartype = CVar->GetRealType(); + + if (!(cvartype == CVAR_Bool || cvartype == CVAR_Int)) + { + sc.ScriptMessage("CVar '%s' is not an int or bool", cvarName); + } + } + else + { + sc.ScriptMessage("CVar '%s' does not exist", cvarName); + } + + if (parenthesized) sc.MustGetToken(')'); + } } if(value == INVENTORY) { @@ -1444,6 +1475,24 @@ class CommandDrawNumber : public CommandDrawString num++; } break; + case INTCVAR: + { + FBaseCVar *CVar = GetCVar(statusBar->CPlayer->mo, cvarName); + if (CVar != nullptr) + { + ECVarType cvartype = CVar->GetRealType(); + + if (cvartype == CVAR_Bool || cvartype == CVAR_Int) + { + num = CVar->GetGenericRep(CVAR_Int).Int; + break; + } + } + + // Fallback in case of bad cvar/type. Unset can remove a cvar at will. + num = 0; + break; + } default: break; } if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) @@ -1522,6 +1571,7 @@ class CommandDrawNumber : public CommandDrawString ACCURACY, STAMINA, KEYS, + INTCVAR, CONSTANT }; @@ -1544,6 +1594,7 @@ class CommandDrawNumber : public CommandDrawString PClassActor *inventoryItem; FString prefixPadding; + FString cvarName; friend class CommandDrawInventoryBar; }; diff --git a/src/namedef.h b/src/namedef.h index c8b0d1524..36953e385 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -507,6 +507,21 @@ xx(Alphaceiling) xx(Renderstylefloor) xx(Renderstyleceiling) xx(Waterzone) +xx(portal_ceil_alpha) +xx(portal_ceil_blocksound) +xx(portal_ceil_disabled) +xx(portal_ceil_nopass) +xx(portal_ceil_norender) +xx(portal_ceil_overlaytype) +xx(portal_ceil_useglobaltex) +xx(portal_floor_alpha) +xx(portal_floor_blocksound) +xx(portal_floor_disabled) +xx(portal_floor_nopass) +xx(portal_floor_norender) +xx(portal_floor_overlaytype) +xx(portal_floor_useglobaltex) + xx(offsetx_top) xx(offsety_top) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1b52f5a93..0a2ccddac 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4379,10 +4379,11 @@ enum EACSFunctions ACSF_CheckClass = 200, ACSF_DamageActor, // [arookas] ACSF_SetActorFlag, + ACSF_SetTranslation, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) - ACSF_SetTeamScore, // (int team, int value) + ACSF_SetTeamScore, // (int team, int value }; int DLevelScript::SideFromID(int id, int side) @@ -6002,6 +6003,26 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return count; } + case ACSF_SetTranslation: + { + int tid = args[0]; + const char *trname = FBehavior::StaticLookupString(args[1]); + if (tid == 0) + { + if (activator != nullptr) + activator->SetTranslation(trname); + } + else + { + FActorIterator it(tid); + while ((actor = it.Next()) != nullptr) + { + actor->SetTranslation(trname); + } + } + return 1; + } + default: break; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 90a800fa7..496f52e86 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3526,7 +3526,7 @@ void AActor::Tick () sector_t *sec = node->m_sector; DVector2 scrollv; - if (level.Scrolls.Size() > (sec-sectors)) + if (level.Scrolls.Size() > unsigned(sec-sectors)) { scrollv = level.Scrolls[sec - sectors]; } @@ -6525,6 +6525,23 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const } +void AActor::SetTranslation(const char *trname) +{ + if (*trname == 0) + { + // an empty string resets to the default + Translation = GetDefault()->Translation; + return; + } + + int tnum = R_FindCustomTranslation(trname); + if (tnum >= 0) + { + Translation = tnum; + } + // silently ignore if the name does not exist, this would create some insane message spam otherwise. +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 67a447f61..fab7e38d8 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1049,6 +1049,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) return 0; } +//--------------------------------------------------------------------------- +// +// PROC OverlayID +// Because non-action functions cannot acquire the ID of the overlay... +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, OverlayID) +{ + PARAM_ACTION_PROLOGUE; + + if (ACTION_CALL_FROM_PSPRITE()) + { + ACTION_RETURN_INT(stateinfo->mPSPIndex); + } + ACTION_RETURN_INT(0); +} + + + //--------------------------------------------------------------------------- // // PROC A_Lower diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index c09debc51..c1a64f84b 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1568,6 +1568,60 @@ public: tagstring = CheckString(key); break; + case NAME_portal_ceil_alpha: + sec->planes[sector_t::ceiling].alpha = CheckFloat(key); + break; + + case NAME_portal_ceil_blocksound: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_BLOCKSOUND, key); + break; + + case NAME_portal_ceil_disabled: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_DISABLED, key); + break; + + case NAME_portal_ceil_nopass: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_NOPASS, key); + break; + + case NAME_portal_ceil_norender: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_NORENDER, key); + break; + + case NAME_portal_ceil_overlaytype: + if (!stricmp(CheckString(key), "translucent")) sec->planes[sector_t::ceiling].Flags &= ~PLANEF_ADDITIVE; + else if (!stricmp(CheckString(key), "additive")) sec->planes[sector_t::ceiling].Flags |= PLANEF_ADDITIVE; + break; + + case NAME_portal_floor_alpha: + sec->planes[sector_t::floor].alpha = CheckFloat(key); + break; + + case NAME_portal_floor_blocksound: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_BLOCKSOUND, key); + break; + + case NAME_portal_floor_disabled: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_DISABLED, key); + break; + + case NAME_portal_floor_nopass: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_NOPASS, key); + break; + + case NAME_portal_floor_norender: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_NORENDER, key); + break; + + case NAME_portal_floor_overlaytype: + if (!stricmp(CheckString(key), "translucent")) sec->planes[sector_t::floor].Flags &= ~PLANEF_ADDITIVE; + else if (!stricmp(CheckString(key), "additive")) sec->planes[sector_t::floor].Flags |= PLANEF_ADDITIVE; + break; + + // These two are used by Eternity for something I do not understand. + //case NAME_portal_ceil_useglobaltex: + //case NAME_portal_floor_useglobaltex: + default: break; } diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index 1ee5e0b06..59dc00e32 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -609,26 +609,26 @@ void FRemapTable::AddToTranslation(const char *range) // //---------------------------------------------------------------------------- -int FRemapTable::StoreTranslation() +int FRemapTable::StoreTranslation(int slot) { unsigned int i; - for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) + for (i = 0; i < translationtables[slot].Size(); i++) { - if (*this == *translationtables[TRANSLATION_Decorate][i]) + if (*this == *translationtables[slot][i]) { // A duplicate of this translation already exists - return TRANSLATION(TRANSLATION_Decorate, i); + return TRANSLATION(slot, i); } } - if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) + if (translationtables[slot].Size() >= MAX_DECORATE_TRANSLATIONS) { I_Error("Too many DECORATE translations"); } FRemapTable *newtrans = new FRemapTable; *newtrans = *this; - i = translationtables[TRANSLATION_Decorate].Push(newtrans); - return TRANSLATION(TRANSLATION_Decorate, i); + i = translationtables[slot].Push(newtrans); + return TRANSLATION(slot, i); } @@ -1197,3 +1197,90 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer R_CreatePlayerTranslation (h, s, v, colorset, skin, table, NULL, NULL); } + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- +static TMap customTranslationMap; + +int R_FindCustomTranslation(const char *name) +{ + if (name == nullptr) + { + return -1; + } + // Ice is a special case which will remain in its original slot. + if (!stricmp(name, "Ice")) + { + return TRANSLATION(TRANSLATION_Standard, 7); + } + int *t = customTranslationMap.CheckKey(FName(name, true)); + return (t != nullptr)? *t : -1; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void R_ParseTrnslate() +{ + customTranslationMap.Clear(); + translationtables[TRANSLATION_Custom].Clear(); + + int lump; + int lastlump = 0; + while (-1 != (lump = Wads.FindLump("TRNSLATE", &lastlump))) + { + FScanner sc(lump); + while (sc.GetToken()) + { + sc.TokenMustBe(TK_Identifier); + + FName newtrans = sc.String; + FRemapTable *base = nullptr; + if (sc.CheckToken(':')) + { + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + int max = 6; + if (sc.Number < 0 || sc.Number > max) + { + sc.ScriptError("Translation must be in the range [0,%d]", max); + } + base = translationtables[TRANSLATION_Standard][sc.Number]; + } + else if (sc.TokenType == TK_Identifier) + { + int tnum = R_FindCustomTranslation(sc.String); + if (tnum == -1) + { + sc.ScriptError("Base translation '%s' not found in '%s'", sc.String, newtrans.GetChars()); + } + base = translationtables[GetTranslationType(tnum)][GetTranslationIndex(tnum)]; + } + else + { + // error out. + sc.TokenMustBe(TK_Identifier); + } + } + sc.MustGetToken('='); + FRemapTable NewTranslation; + if (base != nullptr) NewTranslation = *base; + else NewTranslation.MakeIdentity(); + do + { + sc.MustGetToken(TK_StringConst); + NewTranslation.AddToTranslation(sc.String); + } while (sc.CheckToken(',')); + + int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); + customTranslationMap[newtrans] = trans; + } + } +} diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index a549f0759..4ca2f203f 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -19,6 +19,7 @@ enum TRANSLATION_Decorate, TRANSLATION_Blood, TRANSLATION_RainPillar, + TRANSLATION_Custom, NUM_TRANSLATION_TABLES }; @@ -42,7 +43,7 @@ struct FRemapTable void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); void AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); void AddToTranslation(const char * range); - int StoreTranslation(); + int StoreTranslation(int slot); BYTE *Remap; // For the software renderer PalEntry *Palette; // The ideal palette this maps to @@ -109,6 +110,9 @@ extern TArray BloodTranslationColors; int CreateBloodTranslation(PalEntry color); +int R_FindCustomTranslation(const char *name); +void R_ParseTrnslate(); + #endif // __R_TRANSLATE_H diff --git a/src/rapidjson/writer.h b/src/rapidjson/writer.h index c5a3b98a9..a8eeab66d 100644 --- a/src/rapidjson/writer.h +++ b/src/rapidjson/writer.h @@ -321,23 +321,31 @@ protected: } bool WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; + bool ret = true; + if (internal::Double(d).IsNanOrInf()) { + if (!(writeFlags & kWriteNanAndInfFlag)) + { + // if we abort here, the writer is left in a broken state, unable to recover, so better write a 0 in addition to returning an error. + ret = false; + d = 0; + } + else + { + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } } char buffer[25]; @@ -345,7 +353,7 @@ protected: PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); - return true; + return ret; } bool WriteString(const Ch* str, SizeType length) { diff --git a/src/serializer.cpp b/src/serializer.cpp index 47e096b7b..7861701c0 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -217,11 +217,11 @@ struct FWriter { if (mWriter1) { - if (!mWriter1->Double(k)) mWriter1->Double(0); + mWriter1->Double(k); } else if (mWriter2) { - if (!mWriter2->Double(k)) mWriter2->Double(0); + mWriter2->Double(k); } } @@ -821,7 +821,6 @@ void FSerializer::WriteObjects() for (unsigned i = 0; i < w->mDObjects.Size(); i++) { auto obj = w->mDObjects[i]; - player_t *player; BeginObject(nullptr); w->Key("classtype"); diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 635637149..32d4f1ce0 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -288,7 +288,7 @@ static void FinishThingdef() if (func == nullptr) { - VMFunctionBuilder buildit; + VMFunctionBuilder buildit(true); assert(tcall->Proto != nullptr); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 153c3b597..3b4e6203e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3322,6 +3322,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) return 0; } +//=========================================================================== +// +// A_SetRenderStyle +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRenderStyle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(alpha); + PARAM_INT_OPT(mode) { mode = 0; } + + self->Alpha = clamp(alpha, 0., 1.); + self->RenderStyle = ERenderStyle(mode); + return 0; +} + //=========================================================================== // // A_FadeIn @@ -7396,3 +7412,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) ACTION_RETURN_BOOL(true); } + +//========================================================================== +// +// +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslation) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(trname); + + self->SetTranslation(trname); + return 0; +} diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 695b12799..700ac94bb 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3373,7 +3373,7 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) { - if (~membervar->Flags & VARF_Native) + if (build->IsActionFunc && ~membervar->Flags & VARF_Native) { // Check if this is a user-defined variable. // As of right now, FxClassMember is only ever used with FxSelf. // This very user variable was defined in stateowner so if @@ -3948,15 +3948,16 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== // -// Assumption: This call is being made to generate code inside an action -// method, so the first three address registers are all set up for such a -// function. (self, stateowner, callingstate) +// Assumption: This call is being generated inside a function whose a0 +// register is a self pointer. For action functions, a1 maps to stateowner +// and a2 maps to callingstate. (self, stateowner, callingstate) // //========================================================================== ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { - assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) || + (!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1)); int count = (ArgList ? ArgList->Size() : 0); if (count == 1) @@ -3975,8 +3976,18 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } if (Function->Flags & VARF_Action) { - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); - build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + static_assert(NAP == 3, "This code needs to be updated if NAP changes"); + if (build->IsActionFunc) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + } + else + { + int null = build->GetConstantAddress(nullptr, ATAG_GENERIC); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); + } count += 2; } // Emit code to pass explicit parameters @@ -4967,7 +4978,8 @@ static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numpa ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) { - assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + assert(build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 3 && + "FxRuntimeStateIndex is only valid inside action functions"); ExpEmit out(build, REGT_POINTER); @@ -5139,7 +5151,14 @@ int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, V ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) { ExpEmit dest(build, REGT_POINTER); - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + if (build->IsActionFunc) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + } + else + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + } for (unsigned i = 0; i < names.Size(); ++i) { build->EmitParamInt(names[i]); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 927e3e537..d60cda823 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1100,9 +1100,10 @@ DEFINE_PROPERTY(translation, L, Actor) for(int i = 1; i < PROP_PARM_COUNT; i++) { PROP_STRING_PARM(str, i); - if (i== 1 && PROP_PARM_COUNT == 2 && !stricmp(str, "Ice")) + int tnum; + if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != -1) { - defaults->Translation = TRANSLATION(TRANSLATION_Standard, 7); + defaults->Translation = tnum; return; } else @@ -1110,7 +1111,7 @@ DEFINE_PROPERTY(translation, L, Actor) CurrentTranslation.AddToTranslation(str); } } - defaults->Translation = CurrentTranslation.StoreTranslation (); + defaults->Translation = CurrentTranslation.StoreTranslation (TRANSLATION_Decorate); } } diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index b00b4c510..1180f9f32 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -27,6 +27,12 @@ // MACROS ------------------------------------------------------------------ +// This macro is defined by newer versions of xinput.h. In case we are +// compiling with an older version, define it here. +#ifndef XUSER_MAX_COUNT +#define XUSER_MAX_COUNT 4 +#endif + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index eb49ffb14..8d7b5a8c1 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -6,7 +6,7 @@ // //========================================================================== -VMFunctionBuilder::VMFunctionBuilder() +VMFunctionBuilder::VMFunctionBuilder(bool selfcheck) { NumIntConstants = 0; NumFloatConstants = 0; @@ -14,6 +14,7 @@ VMFunctionBuilder::VMFunctionBuilder() NumStringConstants = 0; MaxParam = 0; ActiveParam = 0; + IsActionFunc = selfcheck; } //========================================================================== diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 2d8721acc..ed2516c2a 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -23,7 +23,7 @@ public: friend class VMFunctionBuilder; }; - VMFunctionBuilder(); + VMFunctionBuilder(bool checkself = false); ~VMFunctionBuilder(); VMScriptFunction *MakeFunction(); @@ -60,6 +60,9 @@ public: // Track available registers. RegAvailability Registers[4]; + // For use by DECORATE's self/stateowner sanitizer. + bool IsActionFunc; + private: struct AddrKonst { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 3354b91d6..44b801f51 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -57,6 +57,7 @@ ACTOR Actor native //: Thinker native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); + action native int OverlayID(); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. @@ -218,6 +219,7 @@ ACTOR Actor native //: Thinker native void A_LogInt(int whattoprint); native void A_LogFloat(float whattoprint); native void A_SetTranslucent(float alpha, int style = 0); + native void A_SetRenderStyle(float alpha, int style); action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true native void A_FadeTo(float target, float amount = 0.1, int flags = 0); @@ -343,6 +345,7 @@ ACTOR Actor native //: Thinker action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT); action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT); action native bool A_SetVisibleRotation(float anglestart = 0, float angleend = 0, float pitchstart = 0, float pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetTranslation(string transname); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index bd6d65643..dce2488c2 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -689,4 +689,22 @@ enum VRF_NOANGLE = VRF_NOANGLESTART|VRF_NOANGLEEND, VRF_NOPITCH = VRF_NOPITCHSTART|VRF_NOPITCHEND, -}; \ No newline at end of file +}; + +enum +{ + STYLE_None, + STYLE_Normal, + STYLE_Fuzzy, + STYLE_SoulTrans, + STYLE_OptFuzzy, + STYLE_Stencil, + STYLE_Translucent, + STYLE_Add, + STYLE_Shaded, + STYLE_TranslucentStencil, + STYLE_Shadow, + STYLE_Subtract, + STYLE_AddStencil, + STYLE_AddShaded, +};