diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f0bf8293..9d7da1644 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,11 @@ list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ) include( CreateLaunchers ) include( FindPackageHandleStandardArgs ) +# Produce a warning if XP support will be missing. +if( MSVC14 AND NOT CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" ) + message( WARNING "This project supports Windows XP (including XP x64), but you must set the optional toolset to v140_xp manually to have it in your build! Use -T \"v140_xp\" from the command prompt." ) +endif() + # Support cross compiling option( FORCE_CROSSCOMPILE "Turn on cross compiling." NO ) if( FORCE_CROSSCOMPILE ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd08d9e1c..dc8034a43 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,59 +114,49 @@ if( WIN32 ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NASM_NAMES nasmw nasm ) - if( NOT MSVC ) - find_path( D3D_INCLUDE_DIR d3d9.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) - else() - include_directories( ${D3D_INCLUDE_DIR} ) - endif() - - find_path( XINPUT_INCLUDE_DIR xinput.h - 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 ) - 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} ) - - set( DX_LIBS_FOUND YES ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() - - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) - endif() - - set( DX_LIBS - "${DX_dxguid_LIBRARY}" - "${DX_dinput8_LIBRARY}" - ) + find_path( D3D_INCLUDE_DIR d3d9.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT D3D_INCLUDE_DIR ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) else() - set( DX_LIBS - dxguid - dinput8 - ) + include_directories( ${D3D_INCLUDE_DIR} ) + endif() + + find_path( XINPUT_INCLUDE_DIR xinput.h + 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 ) + else() + include_directories( ${XINPUT_INCLUDE_DIR} ) endif() - set( ZDOOM_LIBS ${DX_LIBS} + 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} ) + + set( DX_LIBS_FOUND YES ) + if( NOT DX_dxguid_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + if( NOT DX_dinput8_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif() + + if( NOT DX_LIBS_FOUND ) + message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + endif() + + set( ZDOOM_LIBS wsock32 winmm + "${DX_dxguid_LIBRARY}" + "${DX_dinput8_LIBRARY}" ole32 user32 gdi32 @@ -272,6 +262,10 @@ if( NOT NO_FMOD ) if( FMOD_INCLUDE_DIR ) message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) include_directories( "${FMOD_INCLUDE_DIR}" ) + + if( EXISTS "${FMOD_INCLUDE_DIR}/fmod_common.h" ) + set( FMOD_STUDIO YES ) + endif() else() message( STATUS "Could not find FMOD include files" ) set( NO_FMOD ON ) @@ -1341,7 +1335,16 @@ endif() if( MSVC ) option( ZDOOM_GENERATE_MAPFILE "Generate .map file for debugging." OFF ) - set( LINKERSTUFF "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\"" ) + set( LINKERSTUFF "/MANIFEST:NO" ) + + if( NOT NO_FMOD ) + if( FMOD_STUDIO ) + set( LINKERSTUFF "${LINKERSTUFF} /DELAYLOAD:\"fmod${X64}.dll\"" ) + else() + set( LINKERSTUFF "${LINKERSTUFF} /DELAYLOAD:\"fmodex${X64}.dll\"" ) + endif() + endif() + if( ZDOOM_GENERATE_MAPFILE ) set( LINKERSTUFF "${LINKERSTUFF} /MAP" ) endif() @@ -1381,17 +1384,23 @@ if( APPLE ) MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" ) if( NOT NO_FMOD ) + if( FMOD_STUDIO ) + set( FMOD_DYLIB libfmod.dylib ) + else() + set( FMOD_DYLIB libfmodex.dylib ) + endif() + # Fix fmod link so that it can be found in the app bundle. find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) find_program( INSTALL_NAME_TOOL install_name_tool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) execute_process( COMMAND "${OTOOL}" -L "${FMOD_LIBRARY}" - COMMAND grep "libfmodex.dylib (compat" + COMMAND grep "${FMOD_DYLIB} (compat" COMMAND head -n1 COMMAND awk "{print $1}" OUTPUT_VARIABLE FMOD_LINK OUTPUT_STRIP_TRAILING_WHITESPACE ) add_custom_command( TARGET zdoom POST_BUILD - COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/libfmodex.dylib "$" + COMMAND "${INSTALL_NAME_TOOL}" -change "${FMOD_LINK}" @executable_path/../Frameworks/${FMOD_DYLIB} "$" COMMENT "Relinking FMOD Ex" ) endif() endif() diff --git a/src/actor.h b/src/actor.h index 89c747880..d01f8db88 100644 --- a/src/actor.h +++ b/src/actor.h @@ -111,6 +111,8 @@ struct FPortalGroupArray; // Any questions? // + + // --- mobj.flags --- enum ActorFlag { @@ -1015,7 +1017,9 @@ public: SDWORD tics; // state tic counter FState *state; - VMFunction *Damage; // For missiles and monster railgun + //VMFunction *Damage; // For missiles and monster railgun + int DamageVal; + VMFunction *DamageFunc; int projectileKickback; ActorFlags flags; ActorFlags2 flags2; // Heretic flags @@ -1203,6 +1207,23 @@ public: FState *GetRaiseState(); void Revive(); + void SetDamage(int dmg) + { + DamageVal = dmg; + DamageFunc = nullptr; + } + + bool IsZeroDamage() const + { + return DamageVal == 0 && DamageFunc == nullptr; + } + + void RestoreDamage() + { + DamageVal = GetDefault()->DamageVal; + DamageFunc = GetDefault()->DamageFunc; + } + FState *FindState (FName label) const { return GetClass()->FindState(1, &label); diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index d72fc79a2..03a7495e4 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -923,10 +923,21 @@ static bool IsActorACountItem(AActor *mo) return mo->IsKindOf(RUNTIME_CLASS(AInventory)) && mo->flags&MF_SPECIAL && mo->flags&MF_COUNTITEM; } -static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const char *FilterName) +// [SP] for all actors +static bool IsActor(AActor *mo) +{ + if (mo->IsKindOf(RUNTIME_CLASS(AInventory))) + return static_cast(mo)->Owner == NULL; // [SP] Exclude inventory-owned items + else + return true; +} + +// [SP] modified - now allows showing count only, new arg must be passed. Also now still counts regardless, if lists are printed. +static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const char *FilterName, bool countOnly) { AActor *mo; const PClass *FilterClass = NULL; + int counter = 0; if (FilterName != NULL) { @@ -943,10 +954,32 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { if ((FilterClass == NULL || mo->IsA(FilterClass)) && IsActorType(mo)) { - Printf ("%s at (%f,%f,%f)\n", - mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + counter++; + if (!countOnly) + Printf ("%s at (%f,%f,%f)\n", + mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); } } + Printf("%i match(s) found.\n", counter); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(actorlist) // [SP] print all actors (this can get quite big?) +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActor, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(actornum) // [SP] count all actors +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActor, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -958,7 +991,14 @@ CCMD(monster) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(monsternum) // [SP] count monsters +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorAMonster, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -970,7 +1010,14 @@ CCMD(items) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(itemsnum) // [SP] # of any items +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorAnItem, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- @@ -982,7 +1029,14 @@ CCMD(countitems) { if (CheckCheatmode ()) return; - PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL); + PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL, false); +} + +CCMD(countitemsnum) // [SP] # of counted items +{ + if (CheckCheatmode ()) return; + + PrintFilteredActorList(IsActorACountItem, argv.argc() > 1 ? argv[1] : NULL, true); } //----------------------------------------------------------------------------- diff --git a/src/c_console.cpp b/src/c_console.cpp index 086861229..2d164c478 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1747,6 +1747,14 @@ void C_AddTabCommand (const char *name) void C_RemoveTabCommand (const char *name) { + if (TabCommands.Size() == 0) + { + // There are no tab commands that can be removed. + // This is important to skip construction of aname + // in case the NameManager has already been destroyed. + return; + } + FName aname(name, true); if (aname == NAME_None) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 4beb5c25a..dfa4f56f0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -915,7 +915,7 @@ static int PatchThing (int thingy) } else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0) { - info->Damage = CreateDamageFunction(val); + info->SetDamage(val); } else if (linelen == 5) { diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 5d10e0138..e6fd5f16d 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -47,7 +47,7 @@ static void BrainishExplosion (const DVector3 &pos) boom->SetState (state); } boom->effects = 0; - boom->Damage = NULL; // disables collision detection which is not wanted here + boom->SetDamage(0); // disables collision detection which is not wanted here boom->tics -= pr_brainscream() & 7; if (boom->tics < 1) boom->tics = 1; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 7f33fb57a..a88748407 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -115,7 +115,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) fire->target = baseFire->target; fire->Angles.Yaw = baseFire->Angles.Yaw; fire->Vel = baseFire->Vel; - fire->Damage = NULL; + fire->SetDamage(0); fire->health = (i+1) * 2; P_CheckMissileSpawn (fire, self->radius); } @@ -205,7 +205,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow) self->AddZ(9.); if (self->health == 0) { - self->Damage = self->GetDefault()->Damage; + self->RestoreDamage(); self->SetState (self->FindState("NoGrow")); } return 0; diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index b5718f4d7..896384f4e 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -340,7 +340,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap) { mo->SetState (mo->FindState (NAME_Death)); mo->Vel.Z = 40; - mo->Damage = NULL; + mo->SetDamage(0); } return 0; } diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index aae006ca7..63394e02a 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -291,10 +291,9 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger if (!(quake->m_Flags & QF_WAVE)) { - jiggers.Falloff = MAX(falloff, jiggers.Falloff); - jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * jiggers.Falloff; + jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * falloff; - intensity *= jiggers.Falloff; + intensity *= falloff; if (quake->m_Flags & QF_RELATIVE) { jiggers.RelIntensity.X = MAX(intensity.X, jiggers.RelIntensity.X); @@ -310,14 +309,13 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger } else { - jiggers.Falloff = MAX(falloff, jiggers.Falloff); - jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * jiggers.Falloff * strength; + jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * falloff * strength; intensity.X *= quake->GetModWave(quake->m_WaveSpeed.X); intensity.Y *= quake->GetModWave(quake->m_WaveSpeed.Y); intensity.Z *= quake->GetModWave(quake->m_WaveSpeed.Z); - intensity *= strength * jiggers.Falloff; + intensity *= strength * falloff; // [RH] This only gives effect to the last sine quake. I would // prefer if some way was found to make multiples coexist diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 314061f04..029653bb1 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -153,7 +153,6 @@ struct FQuakeJiggers DVector3 RelIntensity; DVector3 Offset; DVector3 RelOffset; - double Falloff; double RollIntensity, RollWave; }; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index a9fac2ee1..b7827f6bd 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1914,7 +1914,7 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl { SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); - SetTruth(ratioMap[CheckRatio(screen->GetWidth(), screen->GetHeight())] == ratio, block, statusBar); + SetTruth(ratioMap[FindRatio()] == ratio, block, statusBar); } protected: enum Ratio @@ -1931,6 +1931,37 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl static Ratio ratioMap[5]; Ratio ratio; + + private: + int FindRatio() + { + float aspect = ActiveRatio(screen->GetWidth(), screen->GetHeight()); + + static std::pair ratioTypes[] = + { + { 21 / 9.0f , ASPECTRATIO_16_9 }, + { 16 / 9.0f , ASPECTRATIO_16_9 }, + { 17 / 10.0f , ASPECTRATIO_17_10 }, + { 16 / 10.0f , ASPECTRATIO_16_10 }, + { 4 / 3.0f , ASPECTRATIO_4_3 }, + { 5 / 4.0f , ASPECTRATIO_5_4 }, + { 0.0f, 0 } + }; + + int ratio = ratioTypes[0].second; + float distance = fabs(ratioTypes[0].first - aspect); + for (int i = 1; ratioTypes[i].first != 0.0f; i++) + { + float d = fabs(ratioTypes[i].first - aspect); + if (d < distance) + { + ratio = ratioTypes[i].second; + distance = d; + } + } + + return ratio; + } }; CommandAspectRatio::Ratio CommandAspectRatio::ratioMap[5] = {ASPECTRATIO_4_3,ASPECTRATIO_16_9,ASPECTRATIO_16_10,ASPECTRATIO_16_10,ASPECTRATIO_5_4}; diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 25a88cb35..c4d8ec1ed 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1108,13 +1108,13 @@ void DrawHUD() } else { - if (WidescreenRatio == 4) + if (AspectTallerThanWide(WidescreenRatio)) { - hudheight = hudwidth * 30 / BaseRatioSizes[WidescreenRatio][3]; // BaseRatioSizes is inverted for this mode + hudheight = hudwidth * 30 / AspectMultiplier(WidescreenRatio); // BaseRatioSizes is inverted for this mode } else { - hudheight = hudwidth * 30 / (48*48/BaseRatioSizes[WidescreenRatio][3]); + hudheight = hudwidth * 30 / (48*48/AspectMultiplier(WidescreenRatio)); } } } diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 4631a99aa..f66ec187d 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -299,14 +299,15 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) { ST_X = 0; ST_Y = VirticalResolution - RelTop; - if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) != 4) + float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT); + if (!AspectTallerThanWide(aspect)) { // Normal resolution ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution); } else { // 5:4 resolution - ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, BaseRatioSizes[4][1], 200)) + SCREENHEIGHT/2 - + (SCREENHEIGHT - SCREENHEIGHT * BaseRatioSizes[4][3] / 48) / 2; + ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, AspectBaseHeight(aspect), 200)) + SCREENHEIGHT/2 + + (SCREENHEIGHT - SCREENHEIGHT * AspectMultiplier(aspect) / 48) / 2; } Displacement = 0; } @@ -1035,10 +1036,10 @@ void DBaseStatusBar::DrSmallNumberOuter (int val, int x, int y, bool center) con void DBaseStatusBar::RefreshBackground () const { - int x, x2, y, ratio; + int x, x2, y; - ratio = CheckRatio (SCREENWIDTH, SCREENHEIGHT); - x = (!IsRatioWidescreen(ratio) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2); + float ratio = ActiveRatio (SCREENWIDTH, SCREENHEIGHT); + x = (ratio < 1.5f || !Scaled) ? ST_X : SCREENWIDTH*(48-AspectMultiplier(ratio))/(48*2); y = x == ST_X && x > 0 ? ST_Y : ::ST_Y; if(!CompleteBorder) @@ -1058,8 +1059,8 @@ void DBaseStatusBar::RefreshBackground () const { if(!CompleteBorder) { - x2 = !IsRatioWidescreen(ratio) || !Scaled ? ST_X+HorizontalResolution : - SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2); + x2 = ratio < 1.5f || !Scaled ? ST_X+HorizontalResolution : + SCREENWIDTH - (SCREENWIDTH*(48-AspectMultiplier(ratio))+48*2-1)/(48*2); } else { diff --git a/src/info.cpp b/src/info.cpp index f70124f8b..79c8e4268 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -344,7 +344,7 @@ size_t PClassActor::PropagateMark() // Mark damage function if (Defaults != NULL) { - GC::Mark(((AActor *)Defaults)->Damage); + GC::Mark(((AActor *)Defaults)->DamageFunc); } // marked += ActorInfo->NumOwnedStates * sizeof(FState); diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 1328e2f7a..b1b4d792f 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -95,7 +95,7 @@ CUSTOM_CVAR (Int, menu_screenratios, -1, CVAR_ARCHIVE) } else { - BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + BuildModesList (screen->VideoWidth, screen->VideoHeight, DisplayBits); } } @@ -139,7 +139,7 @@ public: DVideoModeMenu() { - SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits); } bool MenuEvent(int mkey, bool fromcontroller) @@ -163,13 +163,13 @@ public: { if (!GetSelectedSize (&NewWidth, &NewHeight)) { - NewWidth = SCREENWIDTH; - NewHeight = SCREENHEIGHT; + NewWidth = screen->VideoWidth; + NewHeight = screen->VideoHeight; } else { - OldWidth = SCREENWIDTH; - OldHeight = SCREENHEIGHT; + OldWidth = screen->VideoWidth; + OldHeight = screen->VideoHeight; OldBits = DisplayBits; NewBits = BitTranslate[DummyDepthCvar]; setmodeneeded = true; @@ -297,11 +297,11 @@ void M_RestoreMode () void M_SetDefaultMode () { // Make current resolution the default - vid_defwidth = SCREENWIDTH; - vid_defheight = SCREENHEIGHT; + vid_defwidth = screen->VideoWidth; + vid_defheight = screen->VideoHeight; vid_defbits = DisplayBits; testingmode = 0; - SetModesMenu (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits); } @@ -314,7 +314,7 @@ void M_SetDefaultMode () void M_RefreshModesList () { - BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); + BuildModesList (screen->VideoWidth, screen->VideoHeight, DisplayBits); } void M_InitVideoModesMenu () @@ -385,8 +385,8 @@ void M_SetVideoMode() { if (!GetSelectedSize (&NewWidth, &NewHeight)) { - NewWidth = SCREENWIDTH; - NewHeight = SCREENHEIGHT; + NewWidth = screen->VideoWidth; + NewHeight = screen->VideoHeight; } else { diff --git a/src/name.cpp b/src/name.cpp index 8140829c6..ecedcf0f3 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -35,6 +35,7 @@ #include #include "name.h" #include "c_dispatch.h" +#include "c_console.h" // MACROS ------------------------------------------------------------------ @@ -268,6 +269,8 @@ FName::NameManager::~NameManager() { NameBlock *block, *next; + C_ClearTabCommands(); + for (block = Blocks; block != NULL; block = next) { next = block->NextBlock; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 67ae37771..ffac7a78f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3791,7 +3791,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) break; case APROP_Damage: - actor->Damage = CreateDamageFunction(value); + actor->SetDamage(value); break; case APROP_Alpha: diff --git a/src/p_map.cpp b/src/p_map.cpp index 7316e1c96..5cc9bdf72 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1320,7 +1320,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // [RH] What is the point of this check, again? In Hexen, it is unconditional, // but here we only do it if the missile's damage is 0. // MBF bouncer might have a non-0 damage value, but they must not deal damage on impact either. - if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->Damage == 0 || !(tm.thing->flags & MF_MISSILE))) + if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->IsZeroDamage() || !(tm.thing->flags & MF_MISSILE))) { return (tm.thing->target == thing || !(thing->flags & MF_SOLID)); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e4702bf80..3ecf5c76c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -139,7 +139,8 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (LastHeard) DECLARE_POINTER (master) DECLARE_POINTER (Poisoner) - DECLARE_POINTER (Damage) + DECLARE_POINTER (DamageFunc) + DECLARE_POINTER (alternative) END_POINTERS AActor::~AActor () @@ -148,73 +149,6 @@ AActor::~AActor () // Use Destroy() instead. } -//========================================================================== -// -// CalcDamageValue -// -// Given a script function, returns an integer to represent it in a -// savegame. This encoding is compatible with previous incarnations -// where damage was an integer. -// -// 0 : use null function -// 0x40000000 : use default function -// anything else : use function that returns this number -// -//========================================================================== - -static int CalcDamageValue(VMFunction *func) -{ - if (func == NULL) - { - return 0; - } - VMScriptFunction *sfunc = dyn_cast(func); - if (sfunc == NULL) - { - return 0x40000000; - } - VMOP *op = sfunc->Code; - // If the function was created by CreateDamageFunction(), extract - // the value used to create it and return that. Otherwise, return - // indicating to use the default function. - if (op->op == OP_RETI && op->a == 0) - { - return op->i16; - } - if (op->op == OP_RET && op->a == 0 && op->b == (REGT_INT | REGT_KONST)) - { - return sfunc->KonstD[op->c]; - } - return 0x40000000; -} - -//========================================================================== -// -// UncalcDamageValue -// -// Given a damage integer, returns a script function for it. -// -//========================================================================== - -static VMFunction *UncalcDamageValue(int dmg, VMFunction *def) -{ - if (dmg == 0) - { - return NULL; - } - if ((dmg & 0xC0000000) == 0x40000000) - { - return def; - } - // Does the default version return this? If so, use it. Otherwise, - // create a new function. - if (CalcDamageValue(def) == dmg) - { - return def; - } - return CreateDamageFunction(dmg); -} - //========================================================================== // // AActor :: Serialize @@ -262,18 +196,16 @@ void AActor::Serialize(FArchive &arc) << projectilepassheight << Vel << tics - << state; - if (arc.IsStoring()) + << state + << DamageVal; + if (DamageVal == 0x40000000 || DamageVal == -1) { - int dmg; - dmg = CalcDamageValue(Damage); - arc << dmg; + DamageVal = -1; + DamageFunc = GetDefault()->DamageFunc; } else { - int dmg; - arc << dmg; - Damage = UncalcDamageValue(dmg, GetDefault()->Damage); + DamageFunc = nullptr; } P_SerializeTerrain(arc, floorterrain); arc << projectileKickback @@ -2974,8 +2906,21 @@ CCMD(utid) int AActor::GetMissileDamage (int mask, int add) { - if (Damage == NULL) + if (DamageVal >= 0) { + if (mask == 0) + { + return add * DamageVal; + } + else + { + return ((pr_missiledamage() & mask) + add) * DamageVal; + } + } + if (DamageFunc == nullptr) + { + // This should never happen + assert(false && "No damage function found"); return 0; } VMFrameStack stack; @@ -2987,22 +2932,11 @@ int AActor::GetMissileDamage (int mask, int add) results[0].IntAt(&amount); results[1].IntAt(&calculated); - if (stack.Call(Damage, ¶m, 1, results, 2) < 1) + if (stack.Call(DamageFunc, ¶m, 1, results, 2) < 1) { // No results return 0; } - if (calculated) - { - return amount; - } - else if (mask == 0) - { - return add * amount; - } - else - { - return ((pr_missiledamage() & mask) + add) * amount; - } + return amount; } void AActor::Howl () @@ -3694,7 +3628,7 @@ void AActor::Tick () // still have missiles that go straight up and down through actors without // damaging anything. // (for backwards compatibility this must check for lack of damage function, not for zero damage!) - if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && Damage != NULL) + if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage()) { Vel.X = MinVel; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 0b054247e..c09debc51 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -309,6 +309,11 @@ void FUDMFKeys::Sort() FUDMFKey *FUDMFKeys::Find(FName key) { + if (!mSorted) + { + mSorted = true; + Sort(); + } int min = 0, max = Size()-1; while (min <= max) diff --git a/src/r_defs.h b/src/r_defs.h index 44114de3c..de8bd2c95 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -220,6 +220,7 @@ struct FUDMFKey class FUDMFKeys : public TArray { + bool mSorted = false; public: void Sort(); FUDMFKey *Find(FName key); diff --git a/src/r_main.cpp b/src/r_main.cpp index ecbd4cb34..040b57b71 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -232,7 +232,7 @@ void R_SetVisibility(double vis) else r_WallVisibility = r_BaseVisibility; - r_WallVisibility = (InvZtoScale * SCREENWIDTH*BaseRatioSizes[WidescreenRatio][1] / + r_WallVisibility = (InvZtoScale * SCREENWIDTH*AspectBaseHeight(WidescreenRatio) / (viewwidth*SCREENHEIGHT*3)) * (r_WallVisibility * FocalTangent); // Prevent overflow on floors/ceilings. Note that the calculation of @@ -295,7 +295,7 @@ CCMD (r_visibility) // //========================================================================== -void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) +void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) { int virtheight, virtwidth, virtwidth2, virtheight2; @@ -318,22 +318,22 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, virtwidth = virtwidth2 = fullWidth; virtheight = virtheight2 = fullHeight; - if (Is54Aspect(trueratio)) + if (AspectTallerThanWide(trueratio)) { - virtheight2 = virtheight2 * BaseRatioSizes[trueratio][3] / 48; + virtheight2 = virtheight2 * AspectMultiplier(trueratio) / 48; } else { - virtwidth2 = virtwidth2 * BaseRatioSizes[trueratio][3] / 48; + virtwidth2 = virtwidth2 * AspectMultiplier(trueratio) / 48; } - if (Is54Aspect(WidescreenRatio)) + if (AspectTallerThanWide(WidescreenRatio)) { - virtheight = virtheight * BaseRatioSizes[WidescreenRatio][3] / 48; + virtheight = virtheight * AspectMultiplier(WidescreenRatio) / 48; } else { - virtwidth = virtwidth * BaseRatioSizes[WidescreenRatio][3] / 48; + virtwidth = virtwidth * AspectMultiplier(WidescreenRatio) / 48; } BaseYaspectMul = 320.0 * virtheight2 / (r_Yaspect * virtwidth2); @@ -948,7 +948,7 @@ void R_RenderViewToCanvas (AActor *actor, DCanvas *canvas, RenderTarget = canvas; bRenderingToCanvas = true; - R_SetWindow (12, width, height, height); + R_SetWindow (12, width, height, height, true); viewwindowx = x; viewwindowy = y; viewactive = true; diff --git a/src/r_renderer.h b/src/r_renderer.h index 6c65fc12f..a39520b49 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -55,7 +55,7 @@ struct FRenderer virtual void ErrorCleanup () {} virtual void ClearBuffer(int color) = 0; virtual void Init() = 0; - virtual void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) {} + virtual void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) {} virtual void SetupFrame(player_t *player) {} virtual void CopyStackedViewParameters() {} virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) = 0; diff --git a/src/r_swrenderer.cpp b/src/r_swrenderer.cpp index 07edf25e9..4d1fd0371 100644 --- a/src/r_swrenderer.cpp +++ b/src/r_swrenderer.cpp @@ -45,7 +45,7 @@ class FArchive; -void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio); +void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio); void R_SetupColormap(player_t *); void R_SetupFreelook(); void R_InitRenderer(); @@ -275,7 +275,7 @@ void FSoftwareRenderer::ClearBuffer(int color) // //=========================================================================== -void FSoftwareRenderer::SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio) +void FSoftwareRenderer::SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) { R_SWRSetWindow(windowSize, fullWidth, fullHeight, stHeight, trueratio); } diff --git a/src/r_swrenderer.h b/src/r_swrenderer.h index 3e5fed9bc..2856d9586 100644 --- a/src/r_swrenderer.h +++ b/src/r_swrenderer.h @@ -30,7 +30,7 @@ struct FSoftwareRenderer : public FRenderer void ErrorCleanup (); void ClearBuffer(int color); void Init(); - void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, int trueratio); + void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio); void SetupFrame(player_t *player); void CopyStackedViewParameters(); void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov); diff --git a/src/r_things.cpp b/src/r_things.cpp index 28b52129b..a62525d08 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1393,7 +1393,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } if (pspr->GetID() < PSP_TARGETCENTER) { // Move the weapon down for 1280x1024. - vis->texturemid -= BaseRatioSizes[WidescreenRatio][2]; + vis->texturemid -= AspectPspriteOffset(WidescreenRatio); } vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth : x2; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 00ac91c97..ebe36dc9d 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -138,7 +138,7 @@ angle_t LocalViewAngle; int LocalViewPitch; bool LocalKeyboardTurner; -int WidescreenRatio; +float WidescreenRatio; int setblocks; int extralight; bool setsizeneeded; @@ -198,9 +198,9 @@ void R_SetViewSize (int blocks) // //========================================================================== -void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) +void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, bool renderingToCanvas) { - int trueratio; + float trueratio; if (windowSize >= 11) { @@ -220,8 +220,15 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) freelookviewheight = ((setblocks*fullHeight)/10)&~7; } - // If the screen is approximately 16:9 or 16:10, consider it widescreen. - WidescreenRatio = CheckRatio (fullWidth, fullHeight, &trueratio); + if (renderingToCanvas) + { + WidescreenRatio = fullWidth / (float)fullHeight; + trueratio = WidescreenRatio; + } + else + { + WidescreenRatio = ActiveRatio(fullWidth, fullHeight, &trueratio); + } DrawFSHUD = (windowSize == 11); @@ -230,13 +237,13 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) centery = viewheight/2; centerx = viewwidth/2; - if (Is54Aspect(WidescreenRatio)) + if (AspectTallerThanWide(WidescreenRatio)) { centerxwide = centerx; } else { - centerxwide = centerx * BaseRatioSizes[WidescreenRatio][3] / 48; + centerxwide = centerx * AspectMultiplier(WidescreenRatio) / 48; } diff --git a/src/r_utility.h b/src/r_utility.h index 8cabfa600..09a8b5667 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -33,7 +33,7 @@ extern int validcount; extern angle_t LocalViewAngle; // [RH] Added to consoleplayer's angle extern int LocalViewPitch; // [RH] Used directly instead of consoleplayer's pitch extern bool LocalKeyboardTurner; // [RH] The local player used the keyboard to turn, so interpolate -extern int WidescreenRatio; +extern float WidescreenRatio; extern double r_TicFracF; extern DWORD r_FrameTime; @@ -95,7 +95,7 @@ void R_ExecuteSetViewSize (void); // Called by M_Responder. void R_SetViewSize (int blocks); -void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight); +void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, bool renderingToCanvas = false); extern void R_FreePastViewers (); diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 2db5a98a1..c130b7e6a 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -971,6 +971,7 @@ bool FMODSoundRenderer::Init() #if FMOD_STUDIO FMOD_ADVANCEDSETTINGS advSettings = {}; + advSettings.cbSize = sizeof advSettings; advSettings.resamplerMethod = resampler; result = Sys->setAdvancedSettings(&advSettings); if (result != FMOD_OK) @@ -1370,11 +1371,8 @@ void FMODSoundRenderer::PrintStatus() { FMOD_OUTPUTTYPE output; FMOD_SPEAKERMODE speakermode; - FMOD_SOUND_FORMAT format; - FMOD_DSP_RESAMPLER resampler; int driver; int samplerate; - int numoutputchannels; unsigned int bufferlength; int numbuffers; @@ -1413,6 +1411,9 @@ void FMODSoundRenderer::PrintStatus() #endif } #if !FMOD_STUDIO + FMOD_SOUND_FORMAT format; + FMOD_DSP_RESAMPLER resampler; + int numoutputchannels; if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL)) { Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); @@ -2758,6 +2759,16 @@ std::pair FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int l exinfo.defaultfrequency = frequency; switch (bits) { +#if FMOD_STUDIO + case -8: + // Need to convert sample data from signed to unsigned. + for (int i = 0; i < length; i++) + { + sfxdata[i] ^= 0x80; + } + + case 8: +#else // !FMOD_STUDIO case 8: // Need to convert sample data from unsigned to signed. for (int i = 0; i < length; ++i) @@ -2766,6 +2777,7 @@ std::pair FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int l } case -8: +#endif // FMOD_STUDIO exinfo.format = FMOD_SOUND_FORMAT_PCM8; numsamples = length; break; diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 5fa994262..3ea0c4788 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -496,8 +496,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("Damage")) { sc.MustGetNumber (); - FxDamageValue *x = new FxDamageValue(new FxConstant(sc.Number, sc), false); - defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(x) + 1); + defaults->SetDamage(sc.Number); } else if (def == DEF_Projectile && sc.Compare ("DamageType")) { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index dfc960627..635637149 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -348,12 +348,12 @@ static void FinishThingdef() continue; } - if (def->Damage != NULL) + if (def->DamageFunc != nullptr) { - FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->Damage - 1]; + FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->DamageFunc - 1]; VMScriptFunction *sfunc; sfunc = dmg->GetFunction(); - if (sfunc == NULL) + if (sfunc == nullptr) { FCompileContext ctx(ti); dmg = static_cast(dmg->Resolve(ctx)); @@ -365,15 +365,15 @@ static void FinishThingdef() dmg->Emit(&buildit); sfunc = buildit.MakeFunction(); sfunc->NumArgs = 1; - sfunc->Proto = NULL; ///FIXME: Need a proper prototype here + sfunc->Proto = nullptr; ///FIXME: Need a proper prototype here // Save this function in case this damage value was reused // (which happens quite easily with inheritance). dmg->SetFunction(sfunc); } } - def->Damage = sfunc; + def->DamageFunc = sfunc; - if (dump != NULL && sfunc != NULL) + if (dump != nullptr && sfunc != nullptr) { char label[64]; int labellen = mysnprintf(label, countof(label), "Function %s.Damage", diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 642f132af..21551364b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -231,6 +231,38 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass) return 0; } +//========================================================================== +// +// CheckClass +// +// NON-ACTION function to calculate missile damage for the given actor +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(mask); + PARAM_INT(add) + PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + + self = COPY_AAPTR(self, pick_pointer); + if (self == NULL) + { + ret->SetInt(0); + } + else + { + ret->SetInt(self->GetMissileDamage(mask, add)); + } + return 1; + } + return 0; +} + //========================================================================== // // IsPointerEqual diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 756c56a1a..8248634a3 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -666,4 +666,5 @@ void InitThingdef() symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); + symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal))); } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 2f06e085e..5fe8f252f 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -854,20 +854,6 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; -//========================================================================== -// -// FxDamage -// -//========================================================================== - -class FxDamage : public FxExpression -{ -public: - FxDamage(const FScriptPosition&); - FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - //========================================================================== // // FxArrayElement @@ -1188,12 +1174,11 @@ public: class FxDamageValue : public FxExpression { FxExpression *val; - bool Calculated; VMScriptFunction *MyFunction; public: - FxDamageValue(FxExpression *v, bool calc); + FxDamageValue(FxExpression *v); ~FxDamageValue(); FxExpression *Resolve(FCompileContext&); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 034c304c2..ce603f261 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3218,11 +3218,6 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); } } - // the damage property needs special handling - else if (Identifier == NAME_Damage) - { - newex = new FxDamage(ScriptPosition); - } // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { @@ -3316,65 +3311,6 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) } -//========================================================================== -// -// -// -//========================================================================== - -FxDamage::FxDamage(const FScriptPosition &pos) -: FxExpression(pos) -{ -} - -//========================================================================== -// -// FxDamage :: Resolve -// -//========================================================================== - -FxExpression *FxDamage::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - ValueType = TypeSInt32; - return this; -} - -//========================================================================== -// -// FxDamage :: Emit -// -// Call this actor's damage function, if it has one -// -//========================================================================== - -ExpEmit FxDamage::Emit(VMFunctionBuilder *build) -{ - ExpEmit dmgval(build, REGT_INT); - - // Get damage function - ExpEmit dmgfunc(build, REGT_POINTER); - build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage))); - - // If it's non-null... - build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - size_t nulljump = build->Emit(OP_JMP, 0); - - // ...call it - build->Emit(OP_PARAM, 0, REGT_POINTER, 0/*self*/); - build->Emit(OP_CALL, dmgfunc.RegNum, 1, 1); - build->Emit(OP_RESULT, 0, REGT_INT, dmgval.RegNum); - size_t notnulljump = build->Emit(OP_JMP, 0); - - // Otherwise, use 0 - build->BackpatchToHere(nulljump); - build->EmitLoadInt(dmgval.RegNum, 0); - build->BackpatchToHere(notnulljump); - - return dmgval; -} - - //========================================================================== // // @@ -5225,18 +5161,12 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) // //========================================================================== -FxDamageValue::FxDamageValue(FxExpression *v, bool calc) +FxDamageValue::FxDamageValue(FxExpression *v) : FxExpression(v->ScriptPosition) { val = v; ValueType = TypeVoid; - Calculated = calc; MyFunction = NULL; - - if (!calc) - { - assert(v->isConstant() && "Non-calculated damage must be constant"); - } } FxDamageValue::~FxDamageValue() @@ -5272,7 +5202,7 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) assert(emitval.RegType == REGT_INT); build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum); } - build->Emit(OP_RETI, 1 | RET_FINAL, Calculated); + build->Emit(OP_RETI, 1 | RET_FINAL, true); return ExpEmit(); } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index b99f1a384..963165ab1 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -865,19 +865,21 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau if (sc.CheckString ("(")) { - x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true); + conv.i = -1; + params.Push(conv); + x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info))); sc.MustGetStringName(")"); + conv.exp = x; + params.Push(conv); + } else { sc.MustGetNumber(); - if (sc.Number != 0) - { - x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false); - } + conv.i = sc.Number; + params.Push(conv); + conv.exp = nullptr; } - conv.exp = x; - params.Push(conv); } break; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index f6ad511af..52194435b 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -636,7 +636,8 @@ DEFINE_PROPERTY(threshold, I, Actor) //========================================================================== DEFINE_PROPERTY(damage, X, Actor) { - PROP_EXP_PARM(id, 0); + PROP_INT_PARM(dmgval, 0); + PROP_EXP_PARM(id, 1); // Damage can either be a single number, in which case it is subject // to the original damage calculation rules. Or, it can be an expression @@ -646,13 +647,15 @@ DEFINE_PROPERTY(damage, X, Actor) // Store this expression here for now. It will be converted to a function // later once all actors have been processed. - if (id == NULL) + defaults->DamageVal = dmgval; + + if (id == nullptr) { - defaults->Damage = NULL; + defaults->DamageFunc = nullptr; } else { - defaults->Damage = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); + defaults->DamageFunc = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index dada0cd57..4677c4b08 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -863,37 +863,37 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag void DCanvas::VirtualToRealCoords(double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom, bool handleaspect) const { - int myratio = handleaspect ? CheckRatio (Width, Height) : 0; + float myratio = handleaspect ? ActiveRatio (Width, Height) : (4.0f / 3.0f); // if 21:9 AR, map to 16:9 for all callers. // this allows for black bars and stops the stretching of fullscreen images - if (myratio == 6) { - myratio = 2; + if (myratio > 1.7f) { + myratio = 16.0f / 9.0f; } double right = x + w; double bottom = y + h; - if (myratio != 0 && myratio != 4) + if (myratio > 1.334f) { // The target surface is either 16:9 or 16:10, so expand the // specified virtual size to avoid undesired stretching of the // image. Does not handle non-4:3 virtual sizes. I'll worry about // those if somebody expresses a desire to use them. - x = (x - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5; - w = (right - vwidth * 0.5) * Width * 960 / (vwidth * BaseRatioSizes[myratio][0]) + Width * 0.5 - x; + x = (x - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5; + w = (right - vwidth * 0.5) * Width * 960 / (vwidth * AspectBaseWidth(myratio)) + Width * 0.5 - x; } else { x = x * Width / vwidth; w = right * Width / vwidth - x; } - if (myratio == 4) + if (AspectTallerThanWide(myratio)) { // The target surface is 5:4 - y = (y - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5; - h = (bottom - vheight * 0.5) * Height * 600 / (vheight * BaseRatioSizes[myratio][1]) + Height * 0.5 - y; + y = (y - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5; + h = (bottom - vheight * 0.5) * Height * 600 / (vheight * AspectBaseHeight(myratio)) + Height * 0.5 - y; if (vbottom) { - y += (Height - Height * BaseRatioSizes[myratio][3] / 48.0) * 0.5; + y += (Height - Height * AspectMultiplier(myratio) / 48.0) * 0.5; } } else @@ -937,30 +937,30 @@ void DCanvas::VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, void DCanvas::FillBorder (FTexture *img) { - int myratio = CheckRatio (Width, Height); + float myratio = ActiveRatio (Width, Height); // if 21:9 AR, fill borders akin to 16:9, since all fullscreen // images are being drawn to that scale. - if (myratio == 6) { - myratio = 2; + if (myratio > 1.7f) { + myratio = 16 / 9.0f; } - if (myratio == 0) + if (myratio >= 1.3f && myratio <= 1.4f) { // This is a 4:3 display, so no border to show return; } int bordtop, bordbottom, bordleft, bordright, bord; - if (Is54Aspect(myratio)) + if (AspectTallerThanWide(myratio)) { // Screen is taller than it is wide bordleft = bordright = 0; - bord = Height - Height * BaseRatioSizes[myratio][3] / 48; + bord = Height - Height * AspectMultiplier(myratio) / 48; bordtop = bord / 2; bordbottom = bord - bordtop; } else { // Screen is wider than it is tall bordtop = bordbottom = 0; - bord = Width - Width * BaseRatioSizes[myratio][3] / 48; + bord = Width - Width * AspectMultiplier(myratio) / 48; bordleft = bord / 2; bordright = bord - bordleft; } diff --git a/src/v_video.cpp b/src/v_video.cpp index b9917a1cb..b1f1ced9c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -725,6 +725,21 @@ void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256]) DSimpleCanvas::DSimpleCanvas (int width, int height) : DCanvas (width, height) { + MemBuffer = nullptr; + Resize(width, height); +} + +void DSimpleCanvas::Resize(int width, int height) +{ + Width = width; + Height = height; + + if (MemBuffer != NULL) + { + delete[] MemBuffer; + MemBuffer = NULL; + } + // Making the pitch a power of 2 is very bad for performance // Try to maximize the number of cache lines that can be filled // for each column drawing operation by making the pitch slightly @@ -761,7 +776,7 @@ DSimpleCanvas::DSimpleCanvas (int width, int height) } } MemBuffer = new BYTE[Pitch * height]; - memset (MemBuffer, 0, Pitch * height); + memset(MemBuffer, 0, Pitch * height); } //========================================================================== @@ -835,6 +850,9 @@ DFrameBuffer::DFrameBuffer (int width, int height) { LastMS = LastSec = FrameCount = LastCount = LastTic = 0; Accel2D = false; + + VideoWidth = width; + VideoHeight = height; } //========================================================================== @@ -1259,7 +1277,6 @@ CCMD(clean) bool V_DoModeSetup (int width, int height, int bits) { DFrameBuffer *buff = I_SetMode (width, height, screen); - int cx1, cx2; if (buff == NULL) { @@ -1274,6 +1291,17 @@ bool V_DoModeSetup (int width, int height, int bits) // if D3DFB is being used for the display. FFont::StaticPreloadFonts(); + DisplayBits = bits; + V_UpdateModeSize(width, height); + + M_RefreshModesList (); + + return true; +} + +void V_UpdateModeSize (int width, int height) +{ + int cx1, cx2; V_CalcCleanFacs(320, 200, width, height, &CleanXfac, &CleanYfac, &cx1, &cx2); CleanWidth = width / CleanXfac; @@ -1314,32 +1342,38 @@ bool V_DoModeSetup (int width, int height, int bits) DisplayWidth = width; DisplayHeight = height; - DisplayBits = bits; R_OldBlend = ~0; Renderer->OnModeSet(); - - M_RefreshModesList (); +} - return true; +void V_OutputResized (int width, int height) +{ + V_UpdateModeSize(width, height); + setsizeneeded = true; + if (StatusBar != NULL) + { + StatusBar->ScreenSizeChanged(); + } + C_NewModeAdjust(); } void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *_cx1, int *_cx2) { - int ratio; + float ratio; int cwidth; int cheight; int cx1, cy1, cx2, cy2; - ratio = CheckRatio(realwidth, realheight); - if (Is54Aspect(ratio)) + ratio = ActiveRatio(realwidth, realheight); + if (AspectTallerThanWide(ratio)) { cwidth = realwidth; - cheight = realheight * BaseRatioSizes[ratio][3] / 48; + cheight = realheight * AspectMultiplier(ratio) / 48; } else { - cwidth = realwidth * BaseRatioSizes[ratio][3] / 48; + cwidth = realwidth * AspectMultiplier(ratio) / 48; cheight = realheight; } // Use whichever pair of cwidth/cheight or width/height that produces less difference @@ -1573,20 +1607,10 @@ CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) } } -// Tries to guess the physical dimensions of the screen based on the -// screen's pixel dimensions. Can return: -// 0: 4:3 -// 1: 16:9 -// 2: 16:10 -// 3: 17:10 -// 4: 5:4 -// 5: 17:10 (redundant) -// 6: 21:9 -int CheckRatio (int width, int height, int *trueratio) +// Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. +int ActiveFakeRatio(int width, int height) { int fakeratio = -1; - int ratio; - if ((vid_aspect >= 1) && (vid_aspect <= 6)) { // [SP] User wants to force aspect ratio; let them. @@ -1598,7 +1622,7 @@ int CheckRatio (int width, int height, int *trueratio) else if (fakeratio == 5) { fakeratio = 3; - } + } } if (vid_nowidescreen) { @@ -1608,74 +1632,112 @@ int CheckRatio (int width, int height, int *trueratio) } else { - fakeratio = (height * 5/4 == width) ? 4 : 0; + fakeratio = (height * 5 / 4 == width) ? 4 : 0; } } - // If the size is approximately 16:9, consider it so. - if (abs (height * 16/9 - width) < 10) - { - ratio = 1; - } - // Consider 17:10 as well. - else if (abs (height * 17/10 - width) < 10) - { - ratio = 3; - } - // 16:10 has more variance in the pixel dimensions. Grr. - else if (abs (height * 16/10 - width) < 60) - { - // 320x200 and 640x400 are always 4:3, not 16:10 - if ((width == 320 && height == 200) || (width == 640 && height == 400)) - { - ratio = 0; - } - else - { - ratio = 2; - } - } - // Unless vid_tft is set, 1280x1024 is 4:3, not 5:4. - else if (height * 5/4 == width && vid_tft) - { - ratio = 4; - } - // test for 21:9 (actually 64:27, 21:9 is a semi-accurate ratio used in marketing) - else if (abs (height * 64/27 - width) < 30) - { - ratio = 6; - } - // Assume anything else is 4:3. (Which is probably wrong these days...) - else - { - ratio = 0; - } - - if (trueratio != NULL) - { - *trueratio = ratio; - } - return (fakeratio >= 0) ? fakeratio : ratio; + return fakeratio; } -// First column: Base width -// Second column: Base height (used for wall visibility multiplier) -// Third column: Psprite offset (needed for "tallscreen" modes) -// Fourth column: Width or height multiplier - -// For widescreen aspect ratio x:y ... -// base_width = 240 * x / y -// multiplier = 320 / base_width -// base_height = 200 * multiplier -const int BaseRatioSizes[7][4] = +// Active screen ratio based on cvars and size +float ActiveRatio(int width, int height, float *trueratio) { - { 960, 600, 0, 48 }, // 4:3 320, 200, multiplied by three - { 1280, 450, 0, 48*3/4 }, // 16:9 426.6667, 150, multiplied by three - { 1152, 500, 0, 48*5/6 }, // 16:10 386, 166.6667, multiplied by three - { 1224, 471, 0, 48*40/51 }, // 17:10 408, 156.8627, multiplied by three - { 960, 640, (int)(6.5*FRACUNIT), 48*15/16 }, // 5:4 320, 213.3333, multiplied by three - { 1224, 471, 0, 48*40/51 }, // 17:10 408, 156.8627, multiplied by three (REDUNDANT) - { 1707, 338, 0, 48*9/16 } // 21:9 568.8889, 337.5, multiplied by three -}; + static float forcedRatioTypes[] = + { + 4 / 3.0f, + 16 / 9.0f, + 16 / 10.0f, + 17 / 10.0f, + 5 / 4.0f, + 17 / 10.0f, + 21 / 9.0f + }; + + float ratio = width / (float)height; + int fakeratio = ActiveFakeRatio(width, height); + + if (trueratio) + *trueratio = ratio; + return (fakeratio != -1) ? forcedRatioTypes[fakeratio] : ratio; +} + +// Tries to guess the physical dimensions of the screen based on the +// screen's pixel dimensions. Can return: +// 0: 4:3 +// 1: 16:9 +// 2: 16:10 +// 3: 17:10 +// 4: 5:4 +// 5: 17:10 (redundant, never returned) +// 6: 21:9 +int CheckRatio (int width, int height, int *trueratio) +{ + float aspect = width / (float)height; + + static std::pair ratioTypes[] = + { + { 21 / 9.0f , 6 }, + { 16 / 9.0f , 1 }, + { 17 / 10.0f , 3 }, + { 16 / 10.0f , 2 }, + { 4 / 3.0f , 0 }, + { 5 / 4.0f , 4 }, + { 0.0f, 0 } + }; + + int ratio = ratioTypes[0].second; + float distance = fabs(ratioTypes[0].first - aspect); + for (int i = 1; ratioTypes[i].first != 0.0f; i++) + { + float d = fabs(ratioTypes[i].first - aspect); + if (d < distance) + { + ratio = ratioTypes[i].second; + distance = d; + } + } + + int fakeratio = ActiveFakeRatio(width, height); + if (fakeratio == -1) + fakeratio = ratio; + + if (trueratio) + *trueratio = ratio; + return fakeratio; +} + +int AspectBaseWidth(float aspect) +{ + return (int)round(240.0f * aspect * 3.0f); +} + +int AspectBaseHeight(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(200.0f * (320.0f / (AspectBaseWidth(aspect) / 3.0f)) * 3.0f); + else + return (int)round((200.0f * (4.0f / 3.0f)) / aspect * 3.0f); +} + +double AspectPspriteOffset(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return 0.0; + else + return ((4.0 / 3.0) / aspect - 1.0) * 97.5; +} + +int AspectMultiplier(float aspect) +{ + if (!AspectTallerThanWide(aspect)) + return (int)round(320.0f / (AspectBaseWidth(aspect) / 3.0f) * 48.0f); + else + return (int)round(200.0f / (AspectBaseHeight(aspect) / 3.0f) * 48.0f); +} + +bool AspectTallerThanWide(float aspect) +{ + return aspect < 1.333f; +} void IVideo::DumpAdapters () { diff --git a/src/v_video.h b/src/v_video.h index 4f0a78675..d19a3b06e 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -47,6 +47,8 @@ extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1; extern int DisplayWidth, DisplayHeight, DisplayBits; bool V_DoModeSetup (int width, int height, int bits); +void V_UpdateModeSize (int width, int height); +void V_OutputResized (int width, int height); void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int realheight, int *cleanx, int *cleany, int *cx1=NULL, int *cx2=NULL); class FTexture; @@ -300,6 +302,8 @@ public: void Unlock (); protected: + void Resize(int width, int height); + BYTE *MemBuffer; DSimpleCanvas() {} @@ -418,6 +422,10 @@ public: virtual bool Is8BitMode() = 0; #endif + // The original size of the framebuffer as selected in the video menu. + int VideoWidth = 0; + int VideoHeight = 0; + protected: void DrawRateStuff (); void CopyFromBuff (BYTE *src, int srcPitch, int width, int height, BYTE *dest); @@ -512,15 +520,16 @@ extern "C" void ASM_PatchPitch (void); int CheckRatio (int width, int height, int *trueratio=NULL); static inline int CheckRatio (double width, double height) { return CheckRatio(int(width), int(height)); } -extern const int BaseRatioSizes[7][4]; +inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; } -inline bool IsRatioWidescreen(int ratio) { - return (ratio & 3)!=0; -} +float ActiveRatio (int width, int height, float *trueratio = NULL); +static inline double ActiveRatio (double width, double height) { return ActiveRatio(int(width), int(height)); } -inline bool Is54Aspect(int ratio) { - return ratio == 4; -} +int AspectBaseWidth(float aspect); +int AspectBaseHeight(float aspect); +double AspectPspriteOffset(float aspect); +int AspectMultiplier(float aspect); +bool AspectTallerThanWide(float aspect); EXTERN_CVAR(Int, uiscale); diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index efdced151..06bfa0569 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1220,6 +1220,24 @@ void D3DFB::Flip() CurrRenderTexture ^= RenderTextureToggle; TempRenderTexture = RenderTexture[CurrRenderTexture]; } + + if (Windowed) + { + RECT box; + GetClientRect(Window, &box); + if (box.right > 0 && box.right > 0 && (Width != box.right || Height != box.bottom)) + { + Resize(box.right, box.bottom); + + TrueHeight = Height; + PixelDoubling = 0; + LBOffsetI = 0; + LBOffset = 0.0f; + Reset(); + + V_OutputResized(Width, Height); + } + } } //========================================================================== diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 2b0659c83..1e6390392 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -537,10 +537,18 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (screen && !VidResizing) { LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; - RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; - AdjustWindowRectEx(&rect, WS_VISIBLE|WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); - mmi->ptMinTrackSize.x = rect.right - rect.left; - mmi->ptMinTrackSize.y = rect.bottom - rect.top; + if (screen->IsFullscreen()) + { + RECT rect = { 0, 0, screen->GetWidth(), screen->GetHeight() }; + AdjustWindowRectEx(&rect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW); + mmi->ptMinTrackSize.x = rect.right - rect.left; + mmi->ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + mmi->ptMinTrackSize.x = 320; + mmi->ptMinTrackSize.y = 200; + } return 0; } break; diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 52b354028..0d45ad90a 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -156,6 +156,15 @@ enum ATAG_RNG, // pointer to FRandom }; +enum EVMAbortException +{ + X_READ_NIL, + X_WRITE_NIL, + X_TOO_MANY_TRIES, + X_ARRAY_OUT_OF_BOUNDS, + X_DIVISION_BY_ZERO, +}; + class VMFunction : public DObject { DECLARE_ABSTRACT_CLASS(VMFunction, DObject); diff --git a/src/zscript/vmexec.cpp b/src/zscript/vmexec.cpp index 070aeb30a..454f02d03 100644 --- a/src/zscript/vmexec.cpp +++ b/src/zscript/vmexec.cpp @@ -44,7 +44,7 @@ #define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) #define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) -#define THROW(x) +#define THROW(x) throw(EVMAbortException(x)) #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ @@ -54,14 +54,6 @@ pc += 1; \ } -enum -{ - X_READ_NIL, - X_WRITE_NIL, - X_TOO_MANY_TRIES, - X_ARRAY_OUT_OF_BOUNDS -}; - #define GETADDR(a,o,x) \ if (a == NULL) { THROW(x); } \ ptr = (VM_SBYTE *)a + o diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 8232340a0..42a374030 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -786,27 +786,51 @@ begin: OP(DIV_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; OP(DIV_RK): ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; OP(DIV_KR): ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; OP(MOD_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; OP(MOD_RK): ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; OP(MOD_KR): ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + THROW(X_DIVISION_BY_ZERO); + } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; @@ -981,14 +1005,26 @@ begin: OP(DIVF_RR): ASSERTF(a); ASSERTF(B); ASSERTF(C); + if (reg.f[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; OP(DIVF_RK): ASSERTF(a); ASSERTF(B); ASSERTKF(C); + if (konstf[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; OP(DIVF_KR): ASSERTF(a); ASSERTKF(B); ASSERTF(C); + if (reg.f[C] == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -996,6 +1032,10 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); fb = reg.f[B]; fc = reg.f[C]; Do_MODF: + if (fc == 0.) + { + THROW(X_DIVISION_BY_ZERO); + } reg.f[a] = luai_nummod(fb, fc); NEXTOP; OP(MODF_RK): diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index c7d9cb87d..29da0c5b9 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -407,6 +407,44 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } + catch (EVMAbortException exception) + { + if (allocated) + { + PopFrame(); + } + if (trap != nullptr) + { + *trap = nullptr; + } + + Printf("VM execution aborted: "); + switch (exception) + { + case X_READ_NIL: + Printf("tried to read from address zero."); + break; + + case X_WRITE_NIL: + Printf("tried to write to address zero."); + break; + + case X_TOO_MANY_TRIES: + Printf("too many try-catch blocks."); + break; + + case X_ARRAY_OUT_OF_BOUNDS: + Printf("array access out of bounds."); + break; + + case X_DIVISION_BY_ZERO: + Printf("division by zero."); + break; + } + Printf("\n"); + + return -1; + } catch (...) { if (allocated) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b8bbcab14..b8b805219 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -53,6 +53,7 @@ ACTOR Actor native //: Thinker native int CountProximity(class classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT); 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 functions // Meh, MBF redundant functions. Only for DeHackEd support.