mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-02-16 16:41:23 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
# Conflicts: # docs/licenses/README.TXT # src/gl/dynlights/gl_dynlight.cpp # src/r_bsp.cpp # src/r_draw.cpp # src/r_plane.h # src/r_things.cpp # src/r_things.h # src/win32/fb_d3d9.cpp # src/win32/win32video.cpp # src/win32/zdoom.rc
This commit is contained in:
commit
032ad95b0f
363 changed files with 18221 additions and 17499 deletions
|
@ -1,8 +1,14 @@
|
|||
The original Doom source code was released by id Software under the
|
||||
Doom Source Code License. See doomlic.txt.
|
||||
|
||||
Parts of the voxel code in the software renderer use code from the
|
||||
BUILD engine by Ken Silverman. See buildlic.txt.
|
||||
|
||||
The majority of original code uses a BSD-like lincese. See bsd.txt.
|
||||
|
||||
The OpenGL renderer is released under the LGPL v3, except some bits
|
||||
of code that were inherited fro ZDoomGL.
|
||||
|
||||
This software is based in part on the work of the Independent JPEG Group.
|
||||
|
||||
This software uses the 'zlib' general purpose compression library by
|
||||
|
|
|
@ -216,13 +216,20 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
ceilingterrain = <string>; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.'
|
||||
floor_reflect = <float>; // reflectiveness of floor (OpenGL only, not functional on sloped sectors)
|
||||
ceiling_reflect = <float>; // reflectiveness of ceiling (OpenGL only, not functional on sloped sectors)
|
||||
floorglowcolor = <integer>; // Sector's floor glow color as RRGGBB value, default = 'use texture's definition'. Set to -1 to disable glowing.
|
||||
floorglowheight = <float>; // Height of floor glow. This only has an effect for the sector's own glow color, but not for a texture based glow.
|
||||
ceilingglowcolor = <integer>; // Sector's ceiling glow color as RRGGBB value, default = 'use texture's definition'. Set to -1 to disable glowing.
|
||||
ceilingglowheight = <float>; // Height of ceiling glow. This only has an effect for the sector's own glow color, but not for a texture based glow.
|
||||
fogdensity = <integer>; // Sets an explicit fog density for the sector, overriding the default calculation from the light level. Value range is 0-510,
|
||||
// 0 meaning that the default is to be used, 2 equalling the density of a light level of 250, and 255 equalling the density of
|
||||
// a light level of 0.
|
||||
// a light level of 0. (OpenGL only)
|
||||
floorglowcolor = <integer>; // Sector's floor glow color as RRGGBB value, default = 'use texture's definition'. Set to -1 to disable glowing. (OpenGL 3.x and newer only)
|
||||
floorglowheight = <float>; // Height of floor glow. This only has an effect for the sector's own glow color, but not for a texture based glow. (OpenGL 3.x and newer only)
|
||||
ceilingglowcolor = <integer>; // Sector's ceiling glow color as RRGGBB value, default = 'use texture's definition'. Set to -1 to disable glowing. (OpenGL 3.x and newer only)
|
||||
ceilingglowheight = <float>; // Height of ceiling glow. This only has an effect for the sector's own glow color, but not for a texture based glow. (OpenGL 3.x and newer only)
|
||||
color_floor = <int>; // Material color of sector's floor (OpenGL only, dynamic lighting only works properly in OpenGL 3.x and later) Default is white (0xffffff)
|
||||
color_ceiling = <int>; // Material color of sector's ceiling (OpenGL only, dynamic lighting only works properly in OpenGL 3.x and later) Default is white (0xffffff)
|
||||
color_walltop = <int>; // Material color of top of sector's sidedefs (OpenGL only, dynamic lighting only works properly in OpenGL 3.x and later,
|
||||
in OpenGL 2.x this will define the entire wall's color) Default is white (0xffffff)
|
||||
color_wallbottom = <int>; // Material color of bottom of sector's sidedefs (OpenGL 3.x and later only) Default is white (0xffffff)
|
||||
color_sprites = <int>; // Material color of sprites in sector (OpenGL only.) Default is white (0xffffff)
|
||||
|
||||
|
||||
portal_ceil_blocksound = <bool> // ceiling portal blocks sound.
|
||||
portal_ceil_disabled = <bool> // ceiling portal disabled.
|
||||
|
@ -413,9 +420,12 @@ Added 'moreids' for linedefs and sectors.
|
|||
added clarification about character encoding
|
||||
added sector damage properties.
|
||||
|
||||
1.27 05.01.2016
|
||||
1.27 05.01.2017
|
||||
floor_reflect and ceiling_reflect.
|
||||
|
||||
1.28 28.01.2017
|
||||
sector material colors.
|
||||
|
||||
===============================================================================
|
||||
EOF
|
||||
===============================================================================
|
||||
|
|
|
@ -13,7 +13,6 @@ include( CheckIncludeFile )
|
|||
include( CheckIncludeFiles )
|
||||
include( CheckLibraryExists )
|
||||
include( FindPkgConfig )
|
||||
include( FindOpenGL )
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
option( NO_STRIP "Do not strip Release or MinSizeRel builds" )
|
||||
|
@ -102,6 +101,7 @@ if( WIN32 )
|
|||
endif()
|
||||
|
||||
set( ZDOOM_LIBS
|
||||
opengl32
|
||||
wsock32
|
||||
winmm
|
||||
"${DX_dinput8_LIBRARY}"
|
||||
|
@ -181,15 +181,6 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# Check if we have OpenGL
|
||||
|
||||
if( NOT OPENGL_FOUND )
|
||||
message( FATAL_ERROR "OpenGL is required for building." )
|
||||
endif( NOT OPENGL_FOUND )
|
||||
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENGL_LIBRARIES} )
|
||||
include_directories( ${OPENGL_INCLUDE_DIR} )
|
||||
|
||||
if( NOT NO_OPENAL )
|
||||
find_package( OpenAL )
|
||||
mark_as_advanced(CLEAR OPENAL_INCLUDE_DIR)
|
||||
|
@ -445,7 +436,7 @@ add_custom_target( revision_check ALL
|
|||
# Libraries ZDoom needs
|
||||
|
||||
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" "${CMAKE_DL_LIBS}" )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" )
|
||||
|
||||
if( SNDFILE_FOUND )
|
||||
|
@ -461,8 +452,6 @@ if( NOT DYN_FLUIDSYNTH )
|
|||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
||||
include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" )
|
||||
endif()
|
||||
else()
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${CMAKE_DL_LIBS} )
|
||||
endif()
|
||||
|
||||
# Start defining source files for ZDoom
|
||||
|
@ -479,7 +468,6 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/i_rawps2.cpp
|
||||
win32/i_xinput.cpp
|
||||
win32/i_main.cpp
|
||||
win32/i_movie.cpp
|
||||
win32/i_system.cpp
|
||||
win32/i_specialpaths.cpp
|
||||
win32/st_start.cpp
|
||||
|
@ -487,7 +475,6 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/win32video.cpp )
|
||||
set( PLAT_POSIX_SOURCES
|
||||
posix/i_cd.cpp
|
||||
posix/i_movie.cpp
|
||||
posix/i_steam.cpp )
|
||||
set( PLAT_SDL_SOURCES
|
||||
posix/sdl/crashcatcher.c
|
||||
|
@ -621,8 +608,8 @@ file( GLOB HEADER_FILES
|
|||
${EXTRA_HEADER_DIRS}
|
||||
fragglescript/*.h
|
||||
g_shared/*.h
|
||||
g_statusbar/*.h
|
||||
g_inventory/*.h
|
||||
g_strife/*.h
|
||||
intermission/*.h
|
||||
menu/*.h
|
||||
posix/*.h
|
||||
|
@ -664,7 +651,7 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
${OTHER_SYSTEM_SOURCES}
|
||||
sc_man_scanner.h
|
||||
sc_man_scanner.re
|
||||
g_shared/sbarinfo_commands.cpp
|
||||
g_statusbar/sbarinfo_commands.cpp
|
||||
xlat/xlat_parser.y
|
||||
xlat_parser.c
|
||||
xlat_parser.h
|
||||
|
@ -945,7 +932,6 @@ set (PCH_SOURCES
|
|||
p_udmf.cpp
|
||||
p_usdf.cpp
|
||||
p_user.cpp
|
||||
p_writemap.cpp
|
||||
p_xlat.cpp
|
||||
parsecontext.cpp
|
||||
po_man.cpp
|
||||
|
@ -970,37 +956,22 @@ set (PCH_SOURCES
|
|||
w_wad.cpp
|
||||
wi_stuff.cpp
|
||||
zstrformat.cpp
|
||||
g_inventory/a_ammo.cpp
|
||||
g_inventory/a_armor.cpp
|
||||
g_inventory/a_artifacts.cpp
|
||||
g_inventory/a_health.cpp
|
||||
g_inventory/a_keys.cpp
|
||||
g_inventory/a_pickups.cpp
|
||||
g_inventory/a_puzzleitems.cpp
|
||||
g_inventory/a_weaponpiece.cpp
|
||||
g_inventory/a_weapons.cpp
|
||||
g_strife/strife_sbar.cpp
|
||||
g_shared/a_action.cpp
|
||||
g_shared/a_bridge.cpp
|
||||
g_shared/a_decals.cpp
|
||||
g_shared/a_fastprojectile.cpp
|
||||
g_shared/a_flashfader.cpp
|
||||
g_shared/a_fountain.cpp
|
||||
g_shared/a_lightning.cpp
|
||||
g_shared/a_morph.cpp
|
||||
g_shared/a_movingcamera.cpp
|
||||
g_shared/a_quake.cpp
|
||||
g_shared/a_randomspawner.cpp
|
||||
g_shared/a_sectoraction.cpp
|
||||
g_shared/a_skies.cpp
|
||||
g_shared/a_soundenvironment.cpp
|
||||
g_shared/a_soundsequence.cpp
|
||||
g_shared/a_specialspot.cpp
|
||||
g_shared/hudmessages.cpp
|
||||
g_shared/sbarinfo.cpp
|
||||
g_shared/sbar_mugshot.cpp
|
||||
g_shared/shared_hud.cpp
|
||||
g_shared/shared_sbar.cpp
|
||||
g_statusbar/sbarinfo.cpp
|
||||
g_statusbar/sbar_mugshot.cpp
|
||||
g_statusbar/shared_sbar.cpp
|
||||
g_statusbar/strife_sbar.cpp
|
||||
resourcefiles/ancientzip.cpp
|
||||
resourcefiles/file_7z.cpp
|
||||
resourcefiles/file_grp.cpp
|
||||
|
@ -1049,6 +1020,7 @@ set (PCH_SOURCES
|
|||
scripting/thingdef_data.cpp
|
||||
scripting/thingdef_properties.cpp
|
||||
scripting/codegeneration/codegen.cpp
|
||||
scripting/codegeneration/dynarrays.cpp
|
||||
scripting/decorate/olddecorations.cpp
|
||||
scripting/decorate/thingdef_exp.cpp
|
||||
scripting/decorate/thingdef_parse.cpp
|
||||
|
@ -1059,7 +1031,6 @@ set (PCH_SOURCES
|
|||
scripting/vm/vmframe.cpp
|
||||
scripting/zscript/ast.cpp
|
||||
scripting/zscript/zcc_compile.cpp
|
||||
scripting/zscript/zcc_expr.cpp
|
||||
scripting/zscript/zcc_parser.cpp
|
||||
sfmt/SFMT.cpp
|
||||
)
|
||||
|
@ -1113,7 +1084,7 @@ endif()
|
|||
|
||||
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
|
||||
include_directories( .
|
||||
g_strife
|
||||
g_statusbar
|
||||
g_shared
|
||||
g_inventory
|
||||
sound
|
||||
|
@ -1205,7 +1176,6 @@ source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/m
|
|||
source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+")
|
||||
source_group("External\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+")
|
||||
source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+")
|
||||
source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+")
|
||||
source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+")
|
||||
source_group("Inventory" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_inventory/.+")
|
||||
source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+")
|
||||
|
@ -1242,6 +1212,7 @@ source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_S
|
|||
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
|
||||
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
|
||||
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")
|
||||
source_group("Statusbar" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_statusbar/.+")
|
||||
source_group("Versioning" FILES version.h win32/zdoom.rc)
|
||||
source_group("Xlat" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/xlat/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h)
|
||||
source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h sc_man_scanner.re)
|
||||
|
|
36
src/actor.h
36
src/actor.h
|
@ -45,10 +45,9 @@
|
|||
#include "portal.h"
|
||||
|
||||
struct subsector_t;
|
||||
class PClassAmmo;
|
||||
struct FBlockNode;
|
||||
struct FPortalGroupArray;
|
||||
|
||||
struct visstyle_t;
|
||||
//
|
||||
// NOTES: AActor
|
||||
//
|
||||
|
@ -426,6 +425,7 @@ enum ActorRenderFlag
|
|||
RF_MASKROTATION = 0x00200000, // [MC] Only draw the actor when viewed from a certain angle range.
|
||||
RF_ABSMASKANGLE = 0x00400000, // [MC] The mask rotation does not offset by the actor's angle.
|
||||
RF_ABSMASKPITCH = 0x00800000, // [MC] The mask rotation does not offset by the actor's pitch.
|
||||
RF_INTERPOLATEANGLES = 0x01000000, // [MC] Allow interpolation of the actor's angle, pitch and roll.
|
||||
|
||||
RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
|
||||
RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)
|
||||
|
@ -597,7 +597,7 @@ public:
|
|||
AActor &operator= (const AActor &other);
|
||||
~AActor ();
|
||||
|
||||
virtual void Destroy() override;
|
||||
virtual void OnDestroy() override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual void PostSerialize() override;
|
||||
virtual void PostBeginPlay() override; // Called immediately before the actor's first tick
|
||||
|
@ -618,6 +618,8 @@ public:
|
|||
// Adjusts the angle for deflection/reflection of incoming missiles
|
||||
// Returns true if the missile should be allowed to explode anyway
|
||||
bool AdjustReflectionAngle (AActor *thing, DAngle &angle);
|
||||
int AbsorbDamage(int damage, FName dmgtype);
|
||||
void AlterWeaponSprite(visstyle_t *vis);
|
||||
|
||||
// Returns true if this actor is within melee range of its target
|
||||
bool CheckMeleeRange();
|
||||
|
@ -628,7 +630,7 @@ public:
|
|||
void CallBeginPlay();
|
||||
|
||||
void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
|
||||
virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.
|
||||
void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.
|
||||
|
||||
virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching.
|
||||
|
||||
|
@ -721,7 +723,7 @@ public:
|
|||
|
||||
// Finds the first item of a particular type.
|
||||
AInventory *FindInventory (PClassActor *type, bool subclass=false);
|
||||
AInventory *FindInventory (FName type);
|
||||
AInventory *FindInventory (FName type, bool subclass = false);
|
||||
template<class T> T *FindInventory ()
|
||||
{
|
||||
return static_cast<T *> (FindInventory (RUNTIME_TEMPLATE_CLASS(T)));
|
||||
|
@ -734,7 +736,7 @@ public:
|
|||
AInventory *FirstInv ();
|
||||
|
||||
// Tries to give the actor some ammo.
|
||||
bool GiveAmmo (PClassAmmo *type, int amount);
|
||||
bool GiveAmmo (PClassInventory *type, int amount);
|
||||
|
||||
// Destroys all the inventory the actor is holding.
|
||||
void DestroyAllInventory ();
|
||||
|
@ -780,14 +782,7 @@ public:
|
|||
// set translation
|
||||
void SetTranslation(FName trname);
|
||||
|
||||
double GetBobOffset(double ticfrac = 0) const
|
||||
{
|
||||
if (!(flags2 & MF2_FLOATBOB))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return BobSin(FloatBobPhase + level.maptime + ticfrac);
|
||||
}
|
||||
double GetBobOffset(double ticfrac = 0) const;
|
||||
|
||||
// Enter the crash state
|
||||
void Crash();
|
||||
|
@ -1023,12 +1018,13 @@ public:
|
|||
double FloatSpeed;
|
||||
|
||||
int sprite; // used to find patch_t and flip value
|
||||
BYTE frame; // sprite frame to draw
|
||||
uint8_t frame; // sprite frame to draw
|
||||
uint8_t effects; // [RH] see p_effect.h
|
||||
uint8_t fountaincolor; // Split out of 'effect' to have easier access.
|
||||
DVector2 Scale; // Scaling values; 1 is normal size
|
||||
FRenderStyle RenderStyle; // Style to draw this actor with
|
||||
ActorRenderFlags renderflags; // Different rendering flags
|
||||
FTextureID picnum; // Draw this instead of sprite if valid
|
||||
DWORD effects; // [RH] see p_effect.h
|
||||
double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double.
|
||||
DWORD fillcolor; // Color to draw when STYLE_Shaded
|
||||
|
||||
|
@ -1324,6 +1320,14 @@ public:
|
|||
{
|
||||
return Prev + (ticFrac * (Pos() - Prev));
|
||||
}
|
||||
DRotator InterpolatedAngles(double ticFrac) const
|
||||
{
|
||||
DRotator result;
|
||||
result.Yaw = PrevAngles.Yaw + deltaangle(PrevAngles.Yaw, Angles.Yaw) * ticFrac;
|
||||
result.Pitch = PrevAngles.Pitch + deltaangle(PrevAngles.Pitch, Angles.Pitch) * ticFrac;
|
||||
result.Roll = PrevAngles.Roll + deltaangle(PrevAngles.Roll, Angles.Roll) * ticFrac;
|
||||
return result;
|
||||
}
|
||||
DVector3 PosPlusZ(double zadd) const
|
||||
{
|
||||
return { X(), Y(), Z() + zadd };
|
||||
|
|
120
src/am_map.cpp
120
src/am_map.cpp
|
@ -67,10 +67,10 @@
|
|||
#include "gstrings.h"
|
||||
|
||||
#include "am_map.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "po_man.h"
|
||||
#include "a_keys.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
@ -602,23 +602,21 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it.
|
|||
{
|
||||
int flagged = 0;
|
||||
int total = 0;
|
||||
if (self > 0 && numlines > 0)
|
||||
if (self > 0 && level.lines.Size() > 0)
|
||||
{
|
||||
for(int i=0;i<numlines;i++)
|
||||
for(auto &line : level.lines)
|
||||
{
|
||||
line_t *line = &lines[i];
|
||||
|
||||
// disregard intra-sector lines
|
||||
if (line->frontsector == line->backsector) continue;
|
||||
if (line.frontsector == line.backsector) continue;
|
||||
|
||||
// disregard control sectors for deep water
|
||||
if (line->frontsector->e->FakeFloor.Sectors.Size() > 0) continue;
|
||||
if (line.frontsector->e->FakeFloor.Sectors.Size() > 0) continue;
|
||||
|
||||
// disregard control sectors for 3D-floors
|
||||
if (line->frontsector->e->XFloor.attached.Size() > 0) continue;
|
||||
if (line.frontsector->e->XFloor.attached.Size() > 0) continue;
|
||||
|
||||
total++;
|
||||
if (line->flags & ML_DONTDRAW) flagged++;
|
||||
if (line.flags & ML_DONTDRAW) flagged++;
|
||||
}
|
||||
am_showallenabled = (flagged * 100 / total >= self);
|
||||
}
|
||||
|
@ -1031,17 +1029,17 @@ static void AM_findMinMaxBoundaries ()
|
|||
min_x = min_y = FLT_MAX;
|
||||
max_x = max_y = FIXED_MIN;
|
||||
|
||||
for (int i = 0; i < numvertexes; i++)
|
||||
for (auto &vert : level.vertexes)
|
||||
{
|
||||
if (vertexes[i].fX() < min_x)
|
||||
min_x = vertexes[i].fX();
|
||||
else if (vertexes[i].fX() > max_x)
|
||||
max_x = vertexes[i].fX();
|
||||
if (vert.fX() < min_x)
|
||||
min_x = vert.fX();
|
||||
else if (vert.fX() > max_x)
|
||||
max_x = vert.fX();
|
||||
|
||||
if (vertexes[i].fY() < min_y)
|
||||
min_y = vertexes[i].fY();
|
||||
else if (vertexes[i].fY() > max_y)
|
||||
max_y = vertexes[i].fY();
|
||||
if (vert.fY() < min_y)
|
||||
min_y = vert.fY();
|
||||
else if (vert.fY() > max_y)
|
||||
max_y = vert.fY();
|
||||
}
|
||||
|
||||
max_w = max_x - min_x;
|
||||
|
@ -1062,7 +1060,7 @@ static void AM_findMinMaxBoundaries ()
|
|||
static void AM_calcMinMaxMtoF()
|
||||
{
|
||||
double a = SCREENWIDTH / max_w;
|
||||
double b = ::ST_Y / max_h;
|
||||
double b = gST_Y / max_h;
|
||||
|
||||
min_scale_mtof = a < b ? a : b;
|
||||
max_scale_mtof = SCREENHEIGHT / (2*PLAYERRADIUS);
|
||||
|
@ -1420,7 +1418,7 @@ void AM_NewResolution()
|
|||
else if (scale_mtof > max_scale_mtof)
|
||||
AM_maxOutWindowScale();
|
||||
f_w = screen->GetWidth();
|
||||
f_h = ST_Y;
|
||||
f_h = gST_Y;
|
||||
AM_activateNewScale();
|
||||
}
|
||||
|
||||
|
@ -1901,6 +1899,7 @@ void AM_drawSubsectors()
|
|||
double scalex, scaley;
|
||||
double originx, originy;
|
||||
FDynamicColormap *colormap;
|
||||
PalEntry flatcolor;
|
||||
mpoint_t originpt;
|
||||
|
||||
screen->StartSimplePolys();
|
||||
|
@ -1944,6 +1943,7 @@ void AM_drawSubsectors()
|
|||
colormap = sec->ColorMap;
|
||||
|
||||
FTextureID maptex = sec->GetTexture(sector_t::floor);
|
||||
flatcolor = sec->SpecialColors[sector_t::floor];
|
||||
|
||||
scalex = sec->GetXScale(sector_t::floor);
|
||||
scaley = sec->GetYScale(sector_t::floor);
|
||||
|
@ -1992,6 +1992,7 @@ void AM_drawSubsectors()
|
|||
if (roverz < cmpz)
|
||||
{
|
||||
maptex = *(rover->top.texture);
|
||||
flatcolor = *(rover->top.flatcolor);
|
||||
floorplane = rover->top.plane;
|
||||
sector_t *model = rover->top.model;
|
||||
int selector = (rover->flags & FF_INVERTPLANES) ? sector_t::floor : sector_t::ceiling;
|
||||
|
@ -2052,6 +2053,7 @@ void AM_drawSubsectors()
|
|||
scale / scaley,
|
||||
rotation,
|
||||
colormap,
|
||||
flatcolor,
|
||||
floorlight,
|
||||
f_y + f_h
|
||||
);
|
||||
|
@ -2230,11 +2232,13 @@ bool AM_Check3DFloors(line_t *line)
|
|||
// If needUseActivated is true, the special must be activated by use.
|
||||
bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated)
|
||||
{
|
||||
for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast<ASectorAction *>(action->tracer))
|
||||
// This code really stands in the way of a more generic and flexible implementation of sector actions because it makes far too many assumptions
|
||||
// about their internal workings. Well, it can't be helped. Let's just hope that nobody abuses the special and the health field in a way that breaks this.
|
||||
for (AActor* action = sector->SecActTarget; action; action = action->tracer)
|
||||
{
|
||||
if ((action->IsActivatedByUse() || false == needUseActivated)
|
||||
if (((action->health & (SECSPAC_Use | SECSPAC_UseWall)) || false == needUseActivated)
|
||||
&& (*function)(action->special, action->args)
|
||||
&& action->CanTrigger (players[consoleplayer].mo))
|
||||
&& !(action->flags & MF_FRIENDLY))
|
||||
{
|
||||
*specialptr = action->special;
|
||||
*argsptr = action->args;
|
||||
|
@ -2383,7 +2387,6 @@ bool AM_isLockBoundary (line_t &line, int *lockptr = NULL)
|
|||
|
||||
void AM_drawWalls (bool allmap)
|
||||
{
|
||||
int i;
|
||||
static mline_t l;
|
||||
int lock, color;
|
||||
|
||||
|
@ -2394,18 +2397,18 @@ void AM_drawWalls (bool allmap)
|
|||
if (p == MapPortalGroup) continue;
|
||||
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
for (auto &line : level.lines)
|
||||
{
|
||||
int pg;
|
||||
|
||||
if (lines[i].sidedef[0]->Flags & WALLF_POLYOBJ)
|
||||
if (line.sidedef[0]->Flags & WALLF_POLYOBJ)
|
||||
{
|
||||
// For polyobjects we must test the surrounding sector to get the proper group.
|
||||
pg = P_PointInSector(lines[i].v1->fX() + lines[i].Delta().X / 2, lines[i].v1->fY() + lines[i].Delta().Y / 2)->PortalGroup;
|
||||
pg = P_PointInSector(line.v1->fX() + line.Delta().X / 2, line.v1->fY() + line.Delta().Y / 2)->PortalGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
pg = lines[i].frontsector->PortalGroup;
|
||||
pg = line.frontsector->PortalGroup;
|
||||
}
|
||||
DVector2 offset;
|
||||
bool portalmode = numportalgroups > 0 && pg != MapPortalGroup;
|
||||
|
@ -2419,10 +2422,10 @@ void AM_drawWalls (bool allmap)
|
|||
}
|
||||
else continue;
|
||||
|
||||
l.a.x = (lines[i].v1->fX() + offset.X);
|
||||
l.a.y = (lines[i].v1->fY() + offset.Y);
|
||||
l.b.x = (lines[i].v2->fX() + offset.X);
|
||||
l.b.y = (lines[i].v2->fY() + offset.Y);
|
||||
l.a.x = (line.v1->fX() + offset.X);
|
||||
l.a.y = (line.v1->fY() + offset.Y);
|
||||
l.b.x = (line.v2->fX() + offset.X);
|
||||
l.b.y = (line.v2->fY() + offset.Y);
|
||||
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
|
@ -2430,9 +2433,9 @@ void AM_drawWalls (bool allmap)
|
|||
AM_rotatePoint(&l.b.x, &l.b.y);
|
||||
}
|
||||
|
||||
if (am_cheat != 0 || (lines[i].flags & ML_MAPPED))
|
||||
if (am_cheat != 0 || (line.flags & ML_MAPPED))
|
||||
{
|
||||
if ((lines[i].flags & ML_DONTDRAW) && (am_cheat == 0 || am_cheat >= 4))
|
||||
if ((line.flags & ML_DONTDRAW) && (am_cheat == 0 || am_cheat >= 4))
|
||||
{
|
||||
if (!am_showallenabled || CheckCheatmode(false))
|
||||
{
|
||||
|
@ -2444,27 +2447,27 @@ void AM_drawWalls (bool allmap)
|
|||
{
|
||||
AM_drawMline(&l, AMColors.PortalColor);
|
||||
}
|
||||
else if (AM_CheckSecret(&lines[i]))
|
||||
else if (AM_CheckSecret(&line))
|
||||
{
|
||||
// map secret sectors like Boom
|
||||
AM_drawMline(&l, AMColors.SecretSectorColor);
|
||||
}
|
||||
else if (lines[i].flags & ML_SECRET)
|
||||
else if (line.flags & ML_SECRET)
|
||||
{ // secret door
|
||||
if (am_cheat != 0 && lines[i].backsector != NULL)
|
||||
if (am_cheat != 0 && line.backsector != NULL)
|
||||
AM_drawMline(&l, AMColors.SecretWallColor);
|
||||
else
|
||||
AM_drawMline(&l, AMColors.WallColor);
|
||||
}
|
||||
else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor))
|
||||
else if (AM_isTeleportBoundary(line) && AMColors.isValid(AMColors.IntraTeleportColor))
|
||||
{ // intra-level teleporters
|
||||
AM_drawMline(&l, AMColors.IntraTeleportColor);
|
||||
}
|
||||
else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor))
|
||||
else if (AM_isExitBoundary(line) && AMColors.isValid(AMColors.InterTeleportColor))
|
||||
{ // inter-level/game-ending teleporters
|
||||
AM_drawMline(&l, AMColors.InterTeleportColor);
|
||||
}
|
||||
else if (AM_isLockBoundary(lines[i], &lock))
|
||||
else if (AM_isLockBoundary(line, &lock))
|
||||
{
|
||||
if (AMColors.displayLocks)
|
||||
{
|
||||
|
@ -2484,25 +2487,25 @@ void AM_drawWalls (bool allmap)
|
|||
}
|
||||
else if (am_showtriggerlines
|
||||
&& AMColors.isValid(AMColors.SpecialWallColor)
|
||||
&& AM_isTriggerBoundary(lines[i]))
|
||||
&& AM_isTriggerBoundary(line))
|
||||
{
|
||||
AM_drawMline(&l, AMColors.SpecialWallColor); // wall with special non-door action the player can do
|
||||
}
|
||||
else if (lines[i].backsector == NULL)
|
||||
else if (line.backsector == NULL)
|
||||
{
|
||||
AM_drawMline(&l, AMColors.WallColor); // one-sided wall
|
||||
}
|
||||
else if (lines[i].backsector->floorplane
|
||||
!= lines[i].frontsector->floorplane)
|
||||
else if (line.backsector->floorplane
|
||||
!= line.frontsector->floorplane)
|
||||
{
|
||||
AM_drawMline(&l, AMColors.FDWallColor); // floor level change
|
||||
}
|
||||
else if (lines[i].backsector->ceilingplane
|
||||
!= lines[i].frontsector->ceilingplane)
|
||||
else if (line.backsector->ceilingplane
|
||||
!= line.frontsector->ceilingplane)
|
||||
{
|
||||
AM_drawMline(&l, AMColors.CDWallColor); // ceiling level change
|
||||
}
|
||||
else if (AM_Check3DFloors(&lines[i]))
|
||||
else if (AM_Check3DFloors(&line))
|
||||
{
|
||||
AM_drawMline(&l, AMColors.EFWallColor); // Extra floor border
|
||||
}
|
||||
|
@ -2513,7 +2516,7 @@ void AM_drawWalls (bool allmap)
|
|||
}
|
||||
else if (allmap)
|
||||
{
|
||||
if ((lines[i].flags & ML_DONTDRAW) && (am_cheat == 0 || am_cheat >= 4))
|
||||
if ((line.flags & ML_DONTDRAW) && (am_cheat == 0 || am_cheat >= 4))
|
||||
{
|
||||
if (!am_showallenabled || CheckCheatmode(false))
|
||||
{
|
||||
|
@ -2742,8 +2745,8 @@ void AM_drawKeys ()
|
|||
mpoint_t p;
|
||||
DAngle angle;
|
||||
|
||||
TThinkerIterator<AKey> it;
|
||||
AKey *key;
|
||||
TThinkerIterator<AInventory> it(NAME_Key);
|
||||
AInventory *key;
|
||||
|
||||
while ((key = it.Next()) != NULL)
|
||||
{
|
||||
|
@ -2782,14 +2785,13 @@ void AM_drawKeys ()
|
|||
void AM_drawThings ()
|
||||
{
|
||||
AMColor color;
|
||||
int i;
|
||||
AActor* t;
|
||||
mpoint_t p;
|
||||
DAngle angle;
|
||||
|
||||
for (i=0;i<numsectors;i++)
|
||||
for (auto &sec : level.sectors)
|
||||
{
|
||||
t = sectors[i].thinglist;
|
||||
t = sec.thinglist;
|
||||
while (t)
|
||||
{
|
||||
if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP))
|
||||
|
@ -2856,7 +2858,7 @@ void AM_drawThings ()
|
|||
// Find the key's own color.
|
||||
// Only works correctly if single-key locks have lower numbers than any-key locks.
|
||||
// That is the case for all default keys, however.
|
||||
if (t->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
if (t->IsKindOf(PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
if (G_SkillProperty(SKILLP_EasyKey))
|
||||
{
|
||||
|
@ -2866,7 +2868,7 @@ void AM_drawThings ()
|
|||
else if (am_showkeys)
|
||||
{
|
||||
int P_GetMapColorForKey (AInventory * key);
|
||||
int c = P_GetMapColorForKey(static_cast<AKey *>(t));
|
||||
int c = P_GetMapColorForKey(static_cast<AInventory *>(t));
|
||||
|
||||
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
|
||||
else color = AMColors[AMColors.ThingColor_CountItem];
|
||||
|
@ -2933,8 +2935,8 @@ static void DrawMarker (FTexture *tex, double x, double y, int yadjust,
|
|||
DTA_ClipLeft, f_x,
|
||||
DTA_ClipRight, f_x + f_w,
|
||||
DTA_FlipX, flip,
|
||||
DTA_Translation, TranslationToTable(translation),
|
||||
DTA_AlphaF, alpha,
|
||||
DTA_TranslationIndex, translation,
|
||||
DTA_Alpha, alpha,
|
||||
DTA_FillColor, fillcolor,
|
||||
DTA_RenderStyle, DWORD(renderstyle),
|
||||
TAG_DONE);
|
||||
|
@ -3051,7 +3053,7 @@ void AM_Drawer ()
|
|||
return;
|
||||
|
||||
bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0;
|
||||
bool allthings = allmap && players[consoleplayer].mo->FindInventory(PClass::FindActor(NAME_PowerScanner), true) != nullptr;
|
||||
bool allthings = allmap && players[consoleplayer].mo->FindInventory(NAME_PowerScanner, true) != nullptr;
|
||||
|
||||
if (am_portaloverlay)
|
||||
{
|
||||
|
@ -3069,7 +3071,7 @@ void AM_Drawer ()
|
|||
// and view size adjustments.
|
||||
f_x = f_y = 0;
|
||||
f_w = screen->GetWidth ();
|
||||
f_h = ST_Y;
|
||||
f_h = gST_Y;
|
||||
f_p = screen->GetPitch ();
|
||||
|
||||
AM_clearFB(AMColors[AMColors.Background]);
|
||||
|
|
|
@ -26,6 +26,8 @@ IMPLEMENT_POINTERS_START(DBot)
|
|||
IMPLEMENT_POINTER(last_mate)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
DEFINE_FIELD(DBot, dest)
|
||||
|
||||
DBot::DBot ()
|
||||
: DThinker(STAT_BOT)
|
||||
{
|
||||
|
|
|
@ -110,8 +110,8 @@ public:
|
|||
bool IsDangerous (sector_t *sec);
|
||||
|
||||
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
|
||||
BYTE freeze:1; //Game in freeze mode.
|
||||
BYTE changefreeze:1; //Game wants to change freeze mode.
|
||||
BYTE freeze; //Game in freeze mode.
|
||||
BYTE changefreeze; //Game wants to change freeze mode.
|
||||
int botnum;
|
||||
botinfo_t *botinfo;
|
||||
int spawn_tries;
|
||||
|
|
|
@ -65,11 +65,11 @@ bool DBot::Move (ticcmd_t *cmd)
|
|||
bool try_ok;
|
||||
int good;
|
||||
|
||||
if (player->mo->movedir == DI_NODIR)
|
||||
if (player->mo->movedir >= DI_NODIR)
|
||||
{
|
||||
player->mo->movedir = DI_NODIR; // make sure it's valid.
|
||||
return false;
|
||||
|
||||
if ((unsigned)player->mo->movedir >= 8)
|
||||
I_Error ("Weird bot movedir!");
|
||||
}
|
||||
|
||||
tryx = player->mo->X() + 8*xspeed[player->mo->movedir];
|
||||
tryy = player->mo->Y() + 8*yspeed[player->mo->movedir];
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "d_event.h"
|
||||
#include "d_player.h"
|
||||
#include "vectors.h"
|
||||
#include "a_ammo.h"
|
||||
#include "a_health.h"
|
||||
|
||||
static FRandom pr_botmove ("BotMove");
|
||||
|
||||
|
@ -347,12 +345,12 @@ void DBot::WhatToGet (AActor *item)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (item->IsKindOf (RUNTIME_CLASS(AAmmo)))
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Ammo)))
|
||||
{
|
||||
AAmmo *ammo = static_cast<AAmmo *> (item);
|
||||
PClassActor *parent = ammo->GetParentAmmo ();
|
||||
AInventory *holdingammo = player->mo->FindInventory (parent);
|
||||
|
||||
auto ac = PClass::FindActor(NAME_Ammo);
|
||||
auto parent = item->GetClass();
|
||||
while (parent->ParentClass != ac) parent = (PClassActor*)(parent->ParentClass);
|
||||
AInventory *holdingammo = player->mo->FindInventory(parent);
|
||||
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
|
||||
{
|
||||
return;
|
||||
|
@ -360,7 +358,7 @@ void DBot::WhatToGet (AActor *item)
|
|||
}
|
||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
||||
return;
|
||||
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
||||
return;
|
||||
|
||||
if ((dest == NULL ||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "d_player.h"
|
||||
#include "g_level.h"
|
||||
#include "doomstat.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "r_data/r_interpolate.h"
|
||||
#include "c_functions.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
extern FILE *Logfile;
|
||||
extern bool insave;
|
||||
|
@ -403,9 +404,9 @@ CCMD (give)
|
|||
Net_WriteByte (DEM_GIVECHEAT);
|
||||
Net_WriteString (argv[1]);
|
||||
if (argv.argc() > 2)
|
||||
Net_WriteWord (clamp (atoi (argv[2]), 1, 32767));
|
||||
Net_WriteLong(atoi(argv[2]));
|
||||
else
|
||||
Net_WriteWord (0);
|
||||
Net_WriteLong(0);
|
||||
}
|
||||
|
||||
CCMD (take)
|
||||
|
@ -416,9 +417,9 @@ CCMD (take)
|
|||
Net_WriteByte (DEM_TAKECHEAT);
|
||||
Net_WriteString (argv[1]);
|
||||
if (argv.argc() > 2)
|
||||
Net_WriteWord (clamp (atoi (argv[2]), 1, 32767));
|
||||
Net_WriteLong(atoi (argv[2]));
|
||||
else
|
||||
Net_WriteWord (0);
|
||||
Net_WriteLong (0);
|
||||
}
|
||||
|
||||
CCMD (gameversion)
|
||||
|
@ -1189,18 +1190,18 @@ static void PrintSecretString(const char *string, bool thislevel)
|
|||
{
|
||||
if (string[1] == 'S' || string[1] == 's')
|
||||
{
|
||||
long secnum = strtol(string+2, (char**)&string, 10);
|
||||
auto secnum = (unsigned)strtoull(string+2, (char**)&string, 10);
|
||||
if (*string == ';') string++;
|
||||
if (thislevel && secnum >= 0 && secnum < numsectors)
|
||||
if (thislevel && secnum < level.sectors.Size())
|
||||
{
|
||||
if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
|
||||
else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
|
||||
if (level.sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
|
||||
else if (level.sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
|
||||
else colstr = TEXTCOLOR_ORANGE;
|
||||
}
|
||||
}
|
||||
else if (string[1] == 'T' || string[1] == 't')
|
||||
{
|
||||
long tid = strtol(string+2, (char**)&string, 10);
|
||||
long tid = (long)strtoll(string+2, (char**)&string, 10);
|
||||
if (*string == ';') string++;
|
||||
FActorIterator it(tid);
|
||||
AActor *actor;
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "d_player.h"
|
||||
#include "gstrings.h"
|
||||
#include "c_consolebuffer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include "gi.h"
|
||||
|
||||
|
@ -1002,23 +1003,23 @@ void FNotifyBuffer::Draw()
|
|||
{
|
||||
if (!center)
|
||||
screen->DrawText (SmallFont, color, 0, line, notify.Text,
|
||||
DTA_CleanNoMove, true, DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_CleanNoMove, true, DTA_Alpha, alpha, TAG_DONE);
|
||||
else
|
||||
screen->DrawText (SmallFont, color, (SCREENWIDTH -
|
||||
SmallFont->StringWidth (notify.Text)*CleanXfac)/2,
|
||||
line, notify.Text, DTA_CleanNoMove, true,
|
||||
DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_Alpha, alpha, TAG_DONE);
|
||||
}
|
||||
else if (active_con_scaletext() == 1)
|
||||
{
|
||||
if (!center)
|
||||
screen->DrawText (SmallFont, color, 0, line, notify.Text,
|
||||
DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_Alpha, alpha, TAG_DONE);
|
||||
else
|
||||
screen->DrawText (SmallFont, color, (SCREENWIDTH -
|
||||
SmallFont->StringWidth (notify.Text))/2,
|
||||
line, notify.Text,
|
||||
DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_Alpha, alpha, TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1027,7 +1028,7 @@ void FNotifyBuffer::Draw()
|
|||
DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(),
|
||||
DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(),
|
||||
DTA_KeepRatio, true,
|
||||
DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_Alpha, alpha, TAG_DONE);
|
||||
else
|
||||
screen->DrawText (SmallFont, color, (screen->GetWidth() -
|
||||
SmallFont->StringWidth (notify.Text) * active_con_scaletext()) / 2 / active_con_scaletext(),
|
||||
|
@ -1035,7 +1036,7 @@ void FNotifyBuffer::Draw()
|
|||
DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(),
|
||||
DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(),
|
||||
DTA_KeepRatio, true,
|
||||
DTA_AlphaF, alpha, TAG_DONE);
|
||||
DTA_Alpha, alpha, TAG_DONE);
|
||||
}
|
||||
line += lineadv;
|
||||
canskip = false;
|
||||
|
@ -1116,7 +1117,7 @@ void C_DrawConsole (bool hw2d)
|
|||
DTA_DestWidth, screen->GetWidth(),
|
||||
DTA_DestHeight, screen->GetHeight(),
|
||||
DTA_ColorOverlay, conshade,
|
||||
DTA_AlphaF, (hw2d && gamestate != GS_FULLCONSOLE) ? (double)con_alpha : 1.,
|
||||
DTA_Alpha, (hw2d && gamestate != GS_FULLCONSOLE) ? (double)con_alpha : 1.,
|
||||
DTA_Masked, false,
|
||||
TAG_DONE);
|
||||
if (conline && visheight < screen->GetHeight())
|
||||
|
@ -1325,6 +1326,12 @@ void C_HideConsole ()
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Console, HideConsole)
|
||||
{
|
||||
C_HideConsole();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
||||
{
|
||||
int data1 = ev->data1;
|
||||
|
@ -1742,7 +1749,7 @@ void C_MidPrintBold (FFont *font, const char *msg)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DObject, C_MidPrint)
|
||||
DEFINE_ACTION_FUNCTION(_Console, MidPrint)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(font);
|
||||
|
|
|
@ -200,7 +200,7 @@ bool FBaseCVar::ToBool (UCVarValue value, ECVarType type)
|
|||
else if (stricmp (value.String, "false") == 0)
|
||||
return false;
|
||||
else
|
||||
return !!strtol (value.String, NULL, 0);
|
||||
return !!strtoll (value.String, NULL, 0);
|
||||
|
||||
case CVAR_GUID:
|
||||
return false;
|
||||
|
@ -233,7 +233,7 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
|
|||
else if (stricmp (value.String, "false") == 0)
|
||||
res = 0;
|
||||
else
|
||||
res = strtol (value.String, NULL, 0);
|
||||
res = (int)strtoll (value.String, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CVAR_GUID: res = 0; break;
|
||||
|
@ -458,7 +458,7 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
|
|||
else if (stricmp (value, "false") == 0)
|
||||
ret.Bool = false;
|
||||
else
|
||||
ret.Bool = strtol (value, NULL, 0) != 0;
|
||||
ret.Bool = strtoll (value, NULL, 0) != 0;
|
||||
break;
|
||||
|
||||
case CVAR_Int:
|
||||
|
@ -467,7 +467,7 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
|
|||
else if (stricmp (value, "false") == 0)
|
||||
ret.Int = 0;
|
||||
else
|
||||
ret.Int = strtol (value, NULL, 0);
|
||||
ret.Int = (int)strtoll (value, NULL, 0);
|
||||
break;
|
||||
|
||||
case CVAR_Float:
|
||||
|
@ -1617,8 +1617,16 @@ void C_ArchiveCVars (FConfigFile *f, uint32 filter)
|
|||
}
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Bool, sv_cheats);
|
||||
|
||||
void FBaseCVar::CmdSet (const char *newval)
|
||||
{
|
||||
if ((GetFlags() & CVAR_CHEAT) && !sv_cheats)
|
||||
{
|
||||
Printf("sv_cheats must be true to set this console variable.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
UCVarValue val;
|
||||
|
||||
// Casting away the const is safe in this case.
|
||||
|
|
|
@ -63,6 +63,7 @@ enum
|
|||
CVAR_NOSAVE = 4096, // when used with CVAR_SERVERINFO, do not save var to savegame
|
||||
CVAR_MOD = 8192, // cvar was defined by a mod
|
||||
CVAR_IGNORE = 16384,// do not send cvar across the network/inaccesible from ACS (dummy mod cvar)
|
||||
CVAR_CHEAT = 32768,// can be set only when sv_cheats is enabled
|
||||
};
|
||||
|
||||
union UCVarValue
|
||||
|
|
|
@ -705,7 +705,7 @@ void AddCommandString (char *cmd, int keynum)
|
|||
|
||||
if (cmd[4] == ' ')
|
||||
{
|
||||
tics = strtol (cmd + 5, NULL, 0);
|
||||
tics = (int)strtoll (cmd + 5, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "p_tags.h"
|
||||
#include "r_state.h"
|
||||
#include "w_wad.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -475,9 +476,9 @@ void SetCompatibilityParams()
|
|||
{
|
||||
case CP_CLEARFLAGS:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line_t *line = &level.lines[CompatParams[i+1]];
|
||||
line->flags &= ~CompatParams[i+2];
|
||||
}
|
||||
i+=3;
|
||||
|
@ -485,9 +486,9 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SETFLAGS:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line_t *line = &level.lines[CompatParams[i+1]];
|
||||
line->flags |= CompatParams[i+2];
|
||||
}
|
||||
i+=3;
|
||||
|
@ -495,9 +496,9 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SETSPECIAL:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line_t *line = &level.lines[CompatParams[i+1]];
|
||||
line->special = CompatParams[i+2];
|
||||
for(int ii=0;ii<5;ii++)
|
||||
{
|
||||
|
@ -509,9 +510,9 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_CLEARSPECIAL:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line_t *line = &level.lines[CompatParams[i+1]];
|
||||
line->special = 0;
|
||||
memset(line->args, 0, sizeof(line->args));
|
||||
}
|
||||
|
@ -520,9 +521,9 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SETACTIVATION:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line_t *line = &level.lines[CompatParams[i+1]];
|
||||
line->activation = CompatParams[i+2];
|
||||
}
|
||||
i += 3;
|
||||
|
@ -530,9 +531,9 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SECTORFLOOROFFSET:
|
||||
{
|
||||
if (CompatParams[i+1] < numsectors)
|
||||
if ((unsigned)CompatParams[i+1] < level.sectors.Size())
|
||||
{
|
||||
sector_t *sec = §ors[CompatParams[i+1]];
|
||||
sector_t *sec = &level.sectors[CompatParams[i+1]];
|
||||
const double delta = CompatParams[i + 2] / 65536.0;
|
||||
sec->floorplane.ChangeHeight(delta);
|
||||
sec->ChangePlaneTexZ(sector_t::floor, delta);
|
||||
|
@ -542,19 +543,19 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SETSECTORSPECIAL:
|
||||
{
|
||||
const int index = CompatParams[i + 1];
|
||||
if (index < numsectors)
|
||||
const unsigned index = CompatParams[i + 1];
|
||||
if (index < level.sectors.Size())
|
||||
{
|
||||
sectors[index].special = CompatParams[i + 2];
|
||||
level.sectors[index].special = CompatParams[i + 2];
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
case CP_SETWALLYSCALE:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
if ((unsigned)CompatParams[i+1] < level.lines.Size())
|
||||
{
|
||||
side_t *side = lines[CompatParams[i+1]].sidedef[CompatParams[i+2]];
|
||||
side_t *side = level.lines[CompatParams[i+1]].sidedef[CompatParams[i+2]];
|
||||
if (side != NULL)
|
||||
{
|
||||
side->SetTextureYScale(CompatParams[i+3], CompatParams[i+4] / 65536.);
|
||||
|
@ -575,7 +576,7 @@ void SetCompatibilityParams()
|
|||
}
|
||||
case CP_SETTAG:
|
||||
{
|
||||
if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors)
|
||||
if ((unsigned)CompatParams[i + 1] < level.sectors.Size())
|
||||
{
|
||||
// this assumes that the sector does not have any tags yet!
|
||||
if (CompatParams[i + 2] == 0)
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "templates.h"
|
||||
#include "d_net.h"
|
||||
#include "d_event.h"
|
||||
#include "a_armor.h"
|
||||
|
||||
#define QUEUESIZE 128
|
||||
#define MESSAGESIZE 128
|
||||
|
@ -242,13 +241,13 @@ void CT_Drawer (void)
|
|||
{
|
||||
screen_width = SCREENWIDTH;
|
||||
screen_height = SCREENHEIGHT;
|
||||
st_y = ST_Y;
|
||||
st_y = gST_Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
screen_width = SCREENWIDTH / active_con_scaletext();
|
||||
screen_height = SCREENHEIGHT / active_con_scaletext();
|
||||
st_y = ST_Y / active_con_scaletext();
|
||||
st_y = gST_Y / active_con_scaletext();
|
||||
}
|
||||
|
||||
y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y;
|
||||
|
@ -434,7 +433,7 @@ static bool DoSubstitution (FString &out, const char *in)
|
|||
{
|
||||
if (strnicmp(a, "armor", 5) == 0)
|
||||
{
|
||||
AInventory *armor = player->mo->FindInventory<ABasicArmor>();
|
||||
AInventory *armor = player->mo->FindInventory(NAME_BasicArmor);
|
||||
out.AppendFormat("%d", armor != NULL ? armor->Amount : 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,9 +74,6 @@
|
|||
#include "info.h"
|
||||
#include "v_text.h"
|
||||
#include "vmbuilder.h"
|
||||
#include "a_armor.h"
|
||||
#include "a_ammo.h"
|
||||
#include "a_health.h"
|
||||
|
||||
// [SO] Just the way Randy said to do it :)
|
||||
// [RH] Made this CVAR_SERVERINFO
|
||||
|
@ -147,7 +144,7 @@ struct StyleName
|
|||
|
||||
static TArray<StyleName> StyleNames;
|
||||
|
||||
static TArray<PClassAmmo *> AmmoNames;
|
||||
static TArray<PClassActor *> AmmoNames;
|
||||
static TArray<PClassActor *> WeaponNames;
|
||||
|
||||
// DeHackEd trickery to support MBF-style parameters
|
||||
|
@ -220,27 +217,22 @@ DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionStyle)
|
|||
DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionAlpha)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, NoAutofreeze)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, BFGCells)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, BlueAC)
|
||||
|
||||
// Doom identified pickup items by their sprites. ZDoom prefers to use their
|
||||
// class type to identify them instead. To support the traditional Doom
|
||||
// behavior, for every thing touched by dehacked that has the MF_PICKUP flag,
|
||||
// a new subclass of ADehackedPickup will be created with properties copied
|
||||
// a new subclass of DehackedPickup will be created with properties copied
|
||||
// from the original actor's defaults. The original actor is then changed to
|
||||
// spawn the new class.
|
||||
|
||||
IMPLEMENT_CLASS(ADehackedPickup, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(ADehackedPickup)
|
||||
IMPLEMENT_POINTER(RealPickup)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
TArray<PClassActor *> TouchedActors;
|
||||
|
||||
char *UnchangedSpriteNames;
|
||||
int NumUnchangedSprites;
|
||||
bool changedStates;
|
||||
|
||||
// Sprite<->Class map for ADehackedPickup::DetermineType
|
||||
// Sprite<->Class map for DehackedPickup::DetermineType
|
||||
static struct DehSpriteMap
|
||||
{
|
||||
char Sprite[5];
|
||||
|
@ -798,7 +790,7 @@ void SetDehParams(FState *state, int codepointer)
|
|||
|
||||
// Let's identify the codepointer we're dealing with.
|
||||
PFunction *sym;
|
||||
sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true));
|
||||
sym = dyn_cast<PFunction>(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true));
|
||||
if (sym == NULL) return;
|
||||
|
||||
if (codepointer < 0 || (unsigned)codepointer >= countof(MBFCodePointerFactories))
|
||||
|
@ -893,7 +885,7 @@ static int PatchThing (int thingy)
|
|||
while ((result = GetLine ()) == 1)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long val = strtoul (Line2, &endptr, 10);
|
||||
unsigned long val = (unsigned long)strtoull (Line2, &endptr, 10);
|
||||
size_t linelen = strlen (Line1);
|
||||
|
||||
if (linelen == 10 && stricmp (Line1, "Hit points") == 0)
|
||||
|
@ -1072,11 +1064,7 @@ static int PatchThing (int thingy)
|
|||
{
|
||||
if (IsNum (strval))
|
||||
{
|
||||
// I have no idea why everyone insists on using strtol here even though it fails
|
||||
// dismally if a value is parsed where the highest bit it set. Do people really
|
||||
// use negative values here? Let's better be safe and check both.
|
||||
if (strchr(strval, '-')) value[0] |= (unsigned long)strtol(strval, NULL, 10);
|
||||
else value[0] |= (unsigned long)strtoul(strval, NULL, 10);
|
||||
value[0] |= (unsigned long)strtoll(strval, NULL, 10);
|
||||
vchanged[0] = true;
|
||||
}
|
||||
else
|
||||
|
@ -1535,8 +1523,8 @@ static int PatchSprite (int sprNum)
|
|||
|
||||
static int PatchAmmo (int ammoNum)
|
||||
{
|
||||
PClassAmmo *ammoType = NULL;
|
||||
AAmmo *defaultAmmo = NULL;
|
||||
PClassActor *ammoType = NULL;
|
||||
AInventory *defaultAmmo = NULL;
|
||||
int result;
|
||||
int oldclip;
|
||||
int dummy;
|
||||
|
@ -1549,7 +1537,7 @@ static int PatchAmmo (int ammoNum)
|
|||
ammoType = AmmoNames[ammoNum];
|
||||
if (ammoType != NULL)
|
||||
{
|
||||
defaultAmmo = (AAmmo *)GetDefaultByType (ammoType);
|
||||
defaultAmmo = (AInventory*)GetDefaultByType (ammoType);
|
||||
if (defaultAmmo != NULL)
|
||||
{
|
||||
max = &defaultAmmo->MaxAmount;
|
||||
|
@ -1575,8 +1563,8 @@ static int PatchAmmo (int ammoNum)
|
|||
// Calculate the new backpack-given amounts for this ammo.
|
||||
if (ammoType != NULL)
|
||||
{
|
||||
defaultAmmo->BackpackMaxAmount = defaultAmmo->MaxAmount * 2;
|
||||
defaultAmmo->BackpackAmount = defaultAmmo->Amount;
|
||||
defaultAmmo->IntVar("BackpackMaxAmount") = defaultAmmo->MaxAmount * 2;
|
||||
defaultAmmo->IntVar("BackpackAmount") = defaultAmmo->Amount;
|
||||
}
|
||||
|
||||
// Fix per-ammo/max-ammo amounts for descendants of the base ammo class
|
||||
|
@ -1591,7 +1579,7 @@ static int PatchAmmo (int ammoNum)
|
|||
|
||||
if (type->IsDescendantOf (ammoType))
|
||||
{
|
||||
defaultAmmo = (AAmmo *)GetDefaultByType (type);
|
||||
defaultAmmo = (AInventory *)GetDefaultByType (type);
|
||||
defaultAmmo->MaxAmount = *max;
|
||||
defaultAmmo->Amount = Scale (defaultAmmo->Amount, *per, oldclip);
|
||||
}
|
||||
|
@ -1670,10 +1658,10 @@ static int PatchWeapon (int weapNum)
|
|||
{
|
||||
val = 5;
|
||||
}
|
||||
info->AmmoType1 = AmmoNames[val];
|
||||
info->AmmoType1 = (PClassInventory*)AmmoNames[val];
|
||||
if (info->AmmoType1 != NULL)
|
||||
{
|
||||
info->AmmoGive1 = ((AAmmo*)GetDefaultByType (info->AmmoType1))->Amount * 2;
|
||||
info->AmmoGive1 = ((AInventory*)GetDefaultByType (info->AmmoType1))->Amount * 2;
|
||||
if (info->AmmoUse1 == 0)
|
||||
{
|
||||
info->AmmoUse1 = 1;
|
||||
|
@ -1928,7 +1916,7 @@ static int PatchMisc (int dummy)
|
|||
}
|
||||
else if (a > 0)
|
||||
{
|
||||
static_cast<APowerup *>(GetDefaultByName (types[i]))->BlendColor = PalEntry(
|
||||
GetDefaultByName (types[i])->ColorVar(NAME_BlendColor) = PalEntry(
|
||||
BYTE(clamp(a,0.f,1.f)*255.f),
|
||||
clamp(r,0,255),
|
||||
clamp(g,0,255),
|
||||
|
@ -1936,7 +1924,7 @@ static int PatchMisc (int dummy)
|
|||
}
|
||||
else
|
||||
{
|
||||
static_cast<APowerup *>(GetDefaultByName (types[i]))->BlendColor = 0;
|
||||
GetDefaultByName (types[i])->ColorVar(NAME_BlendColor) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1949,43 +1937,41 @@ static int PatchMisc (int dummy)
|
|||
|
||||
// Update default item properties by patching the affected items
|
||||
// Note: This won't have any effect on DECORATE derivates of these items!
|
||||
ABasicArmorPickup *armor;
|
||||
|
||||
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("GreenArmor"));
|
||||
auto armor = GetDefaultByName ("GreenArmor");
|
||||
if (armor!=NULL)
|
||||
{
|
||||
armor->SaveAmount = 100 * deh.GreenAC;
|
||||
armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5;
|
||||
armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC;
|
||||
armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5;
|
||||
}
|
||||
armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor"));
|
||||
armor = GetDefaultByName ("BlueArmor");
|
||||
if (armor!=NULL)
|
||||
{
|
||||
armor->SaveAmount = 100 * deh.BlueAC;
|
||||
armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5;
|
||||
armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC;
|
||||
armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5;
|
||||
}
|
||||
|
||||
ABasicArmorBonus *barmor;
|
||||
barmor = static_cast<ABasicArmorBonus *> (GetDefaultByName ("ArmorBonus"));
|
||||
auto barmor = GetDefaultByName ("ArmorBonus");
|
||||
if (barmor!=NULL)
|
||||
{
|
||||
barmor->MaxSaveAmount = deh.MaxArmor;
|
||||
barmor->IntVar("MaxSaveAmount") = deh.MaxArmor;
|
||||
}
|
||||
|
||||
AHealth *health;
|
||||
health = static_cast<AHealth *> (GetDefaultByName ("HealthBonus"));
|
||||
AInventory *health;
|
||||
health = static_cast<AInventory *> (GetDefaultByName ("HealthBonus"));
|
||||
if (health!=NULL)
|
||||
{
|
||||
health->MaxAmount = 2 * deh.MaxHealth;
|
||||
}
|
||||
|
||||
health = static_cast<AHealth *> (GetDefaultByName ("Soulsphere"));
|
||||
health = static_cast<AInventory *> (GetDefaultByName ("Soulsphere"));
|
||||
if (health!=NULL)
|
||||
{
|
||||
health->Amount = deh.SoulsphereHealth;
|
||||
health->MaxAmount = deh.MaxSoulsphere;
|
||||
}
|
||||
|
||||
health = static_cast<AHealth *> (GetDefaultByName ("MegasphereHealth"));
|
||||
health = static_cast<AInventory *> (GetDefaultByName ("MegasphereHealth"));
|
||||
if (health!=NULL)
|
||||
{
|
||||
health->Amount = health->MaxAmount = deh.MegasphereHealth;
|
||||
|
@ -2118,7 +2104,7 @@ static int PatchCodePtrs (int dummy)
|
|||
|
||||
// This skips the action table and goes directly to the internal symbol table
|
||||
// DEH compatible functions are easy to recognize.
|
||||
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(symname, true));
|
||||
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(symname, true));
|
||||
if (sym == NULL)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Frame %d: Unknown code pointer '%s'\n", frame, Line2);
|
||||
|
@ -2727,11 +2713,11 @@ static bool LoadDehSupp ()
|
|||
}
|
||||
else
|
||||
{
|
||||
// all relevant code pointers are either defined in AStateProvider
|
||||
// all relevant code pointers are either defined in AWeapon
|
||||
// or AActor so this will find all of them.
|
||||
FString name = "A_";
|
||||
name << sc.String;
|
||||
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(name, true));
|
||||
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(name, true));
|
||||
if (sym == NULL)
|
||||
{
|
||||
sc.ScriptError("Unknown code pointer '%s'", sc.String);
|
||||
|
@ -2929,8 +2915,8 @@ static bool LoadDehSupp ()
|
|||
}
|
||||
else
|
||||
{
|
||||
PClassAmmo *cls = dyn_cast<PClassAmmo>(PClass::FindClass(sc.String));
|
||||
if (cls == NULL)
|
||||
auto cls = PClass::FindActor(sc.String);
|
||||
if (cls == NULL || !cls->IsDescendantOf(PClass::FindActor(NAME_Ammo)))
|
||||
{
|
||||
sc.ScriptError("Unknown ammo type '%s'", sc.String);
|
||||
}
|
||||
|
@ -3013,12 +2999,12 @@ void FinishDehPatch ()
|
|||
// Create a new class that will serve as the actual pickup
|
||||
char typeNameBuilder[32];
|
||||
//
|
||||
auto dehtype = PClass::FindActor(NAME_DehackedPickup);
|
||||
do
|
||||
{
|
||||
// Retry until we find a free name. This is unlikely to happen but not impossible.
|
||||
mysnprintf(typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", nameindex++);
|
||||
subclass = static_cast<PClassActor *>(RUNTIME_CLASS(ADehackedPickup)->
|
||||
CreateDerivedClass(typeNameBuilder, sizeof(ADehackedPickup)));
|
||||
subclass = static_cast<PClassActor *>(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size));
|
||||
}
|
||||
while (subclass == nullptr);
|
||||
|
||||
|
@ -3103,7 +3089,7 @@ void FinishDehPatch ()
|
|||
{
|
||||
if (AmmoPerAttacks[j].ptr == nullptr)
|
||||
{
|
||||
auto p = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(AmmoPerAttacks[j].func, true));
|
||||
auto p = dyn_cast<PFunction>(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(AmmoPerAttacks[j].func, true));
|
||||
if (p != nullptr) AmmoPerAttacks[j].ptr = p->Variants[0].Implementation;
|
||||
}
|
||||
if (state->ActionFunc == AmmoPerAttacks[j].ptr)
|
||||
|
@ -3124,93 +3110,10 @@ void FinishDehPatch ()
|
|||
WeaponNames.ShrinkToFit();
|
||||
}
|
||||
|
||||
void ModifyDropAmount(AInventory *inv, int dropamount);
|
||||
|
||||
bool ADehackedPickup::TryPickup (AActor *&toucher)
|
||||
DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType)
|
||||
{
|
||||
PClassActor *type = DetermineType ();
|
||||
if (type == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RealPickup = static_cast<AInventory *>(Spawn (type, Pos(), NO_REPLACE));
|
||||
if (RealPickup != NULL)
|
||||
{
|
||||
// The internally spawned item should never count towards statistics.
|
||||
RealPickup->ClearCounters();
|
||||
if (!(flags & MF_DROPPED))
|
||||
{
|
||||
RealPickup->flags &= ~MF_DROPPED;
|
||||
}
|
||||
// If this item has been dropped by a monster the
|
||||
// amount of ammo this gives must be adjusted.
|
||||
if (droppedbymonster)
|
||||
{
|
||||
ModifyDropAmount(RealPickup, 0);
|
||||
}
|
||||
if (!RealPickup->CallTryPickup (toucher))
|
||||
{
|
||||
RealPickup->Destroy ();
|
||||
RealPickup = NULL;
|
||||
return false;
|
||||
}
|
||||
GoAwayAndDie ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PARAM_SELF_PROLOGUE(AInventory);
|
||||
|
||||
FString ADehackedPickup::PickupMessage ()
|
||||
{
|
||||
if (RealPickup != nullptr)
|
||||
return RealPickup->PickupMessage ();
|
||||
else return "";
|
||||
}
|
||||
|
||||
bool ADehackedPickup::ShouldStay ()
|
||||
{
|
||||
if (RealPickup != nullptr)
|
||||
return RealPickup->CallShouldStay ();
|
||||
else return true;
|
||||
}
|
||||
|
||||
bool ADehackedPickup::ShouldRespawn ()
|
||||
{
|
||||
if (RealPickup != nullptr)
|
||||
return RealPickup->ShouldRespawn ();
|
||||
else return false;
|
||||
}
|
||||
|
||||
void ADehackedPickup::PlayPickupSound (AActor *toucher)
|
||||
{
|
||||
if (RealPickup != nullptr)
|
||||
RealPickup->PlayPickupSound (toucher);
|
||||
}
|
||||
|
||||
void ADehackedPickup::DoPickupSpecial (AActor *toucher)
|
||||
{
|
||||
Super::DoPickupSpecial (toucher);
|
||||
// If the real pickup hasn't joined the toucher's inventory, make sure it
|
||||
// doesn't stick around.
|
||||
if (RealPickup != nullptr && RealPickup->Owner != toucher)
|
||||
{
|
||||
RealPickup->Destroy ();
|
||||
}
|
||||
RealPickup = nullptr;
|
||||
}
|
||||
|
||||
void ADehackedPickup::Destroy ()
|
||||
{
|
||||
if (RealPickup != nullptr)
|
||||
{
|
||||
RealPickup->Destroy ();
|
||||
RealPickup = nullptr;
|
||||
}
|
||||
Super::Destroy ();
|
||||
}
|
||||
|
||||
PClassActor *ADehackedPickup::DetermineType ()
|
||||
{
|
||||
// Look at the actor's current sprite to determine what kind of
|
||||
// item to pretend to me.
|
||||
int min = 0;
|
||||
|
@ -3219,10 +3122,10 @@ PClassActor *ADehackedPickup::DetermineType ()
|
|||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[sprite].name, 4);
|
||||
int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[self->sprite].name, 4);
|
||||
if (lex == 0)
|
||||
{
|
||||
return PClass::FindActor(DehSpriteMappings[mid].ClassName);
|
||||
ACTION_RETURN_OBJECT(PClass::FindActor(DehSpriteMappings[mid].ClassName));
|
||||
}
|
||||
else if (lex < 0)
|
||||
{
|
||||
|
@ -3233,11 +3136,6 @@ PClassActor *ADehackedPickup::DetermineType ()
|
|||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
ACTION_RETURN_OBJECT(nullptr);
|
||||
}
|
||||
|
||||
void ADehackedPickup::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
arc("droppedbymonster", droppedbymonster);
|
||||
}
|
||||
|
|
|
@ -34,29 +34,6 @@
|
|||
#ifndef __D_DEHACK_H__
|
||||
#define __D_DEHACK_H__
|
||||
|
||||
#include "a_pickups.h"
|
||||
|
||||
class ADehackedPickup : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (ADehackedPickup, AInventory)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
void Destroy() override;
|
||||
FString PickupMessage ();
|
||||
bool ShouldRespawn ();
|
||||
bool ShouldStay ();
|
||||
bool TryPickup (AActor *&toucher);
|
||||
void PlayPickupSound (AActor *toucher);
|
||||
void DoPickupSpecial (AActor *toucher);
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
private:
|
||||
PClassActor *DetermineType ();
|
||||
AInventory *RealPickup;
|
||||
public:
|
||||
bool droppedbymonster;
|
||||
};
|
||||
|
||||
int D_LoadDehLumps();
|
||||
bool D_LoadDehLump(int lumpnum);
|
||||
bool D_LoadDehFile(const char *filename);
|
||||
|
|
|
@ -110,6 +110,7 @@
|
|||
#include "p_local.h"
|
||||
#include "autosegs.h"
|
||||
#include "fragglescript/t_fs.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
EXTERN_CVAR(Bool, hud_althud)
|
||||
void DrawHUD();
|
||||
|
@ -787,13 +788,13 @@ void D_Display ()
|
|||
screen->DrawBlendingRect();
|
||||
if (automapactive)
|
||||
{
|
||||
int saved_ST_Y = ST_Y;
|
||||
int saved_ST_Y = gST_Y;
|
||||
if (hud_althud && viewheight == SCREENHEIGHT)
|
||||
{
|
||||
ST_Y = viewheight;
|
||||
gST_Y = viewheight;
|
||||
}
|
||||
AM_Drawer ();
|
||||
ST_Y = saved_ST_Y;
|
||||
gST_Y = saved_ST_Y;
|
||||
}
|
||||
if (!automapactive || viewactive)
|
||||
{
|
||||
|
@ -1062,6 +1063,7 @@ void D_PageTicker (void)
|
|||
|
||||
void D_PageDrawer (void)
|
||||
{
|
||||
screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0);
|
||||
if (Page != NULL)
|
||||
{
|
||||
screen->DrawTexture (Page, 0, 0,
|
||||
|
@ -1069,11 +1071,9 @@ void D_PageDrawer (void)
|
|||
DTA_Masked, false,
|
||||
DTA_BilinearFilter, true,
|
||||
TAG_DONE);
|
||||
screen->FillBorder (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->Clear (0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0);
|
||||
if (!PageBlank)
|
||||
{
|
||||
screen->DrawText (SmallFont, CR_WHITE, 0, 0, "Page graphic goes here", TAG_DONE);
|
||||
|
@ -1398,6 +1398,10 @@ void ParseCVarInfo()
|
|||
{
|
||||
cvarflags &= ~CVAR_ARCHIVE;
|
||||
}
|
||||
else if (stricmp(sc.String, "cheat") == 0)
|
||||
{
|
||||
cvarflags |= CVAR_CHEAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown cvar attribute '%s'", sc.String);
|
||||
|
@ -2517,6 +2521,9 @@ void D_DoomMain (void)
|
|||
|
||||
// Create replacements for dehacked pickups
|
||||
FinishDehPatch();
|
||||
|
||||
// clean up the compiler symbols which are not needed any longer.
|
||||
RemoveUnusedSymbols();
|
||||
|
||||
InitActorNumsFromMapinfo();
|
||||
InitSpawnablesFromMapinfo();
|
||||
|
@ -2704,6 +2711,7 @@ void D_DoomMain (void)
|
|||
S_Shutdown(); // free all channels and delete playlist
|
||||
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
|
||||
DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods
|
||||
FS_Close(); // destroy the global FraggleScript.
|
||||
|
||||
GC::FullGC(); // clean up before taking down the object list.
|
||||
|
||||
|
@ -2715,7 +2723,6 @@ void D_DoomMain (void)
|
|||
*(afunc->VMPointer) = NULL;
|
||||
}
|
||||
|
||||
ReleaseGlobalSymbols();
|
||||
PClass::StaticShutdown();
|
||||
|
||||
GC::FullGC(); // perform one final garbage collection after shutdown
|
||||
|
@ -2727,6 +2734,7 @@ void D_DoomMain (void)
|
|||
|
||||
restart++;
|
||||
PClass::bShutdown = false;
|
||||
PClass::bVMOperational = false;
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "a_keys.h"
|
||||
#include "intermission/intermission.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
EXTERN_CVAR (Int, disableautosave)
|
||||
EXTERN_CVAR (Int, autosavecount)
|
||||
|
@ -2109,6 +2110,11 @@ static int RemoveClass(const PClass *cls)
|
|||
player = true;
|
||||
continue;
|
||||
}
|
||||
// [SP] Don't remove owned inventory objects.
|
||||
if (actor->IsKindOf(RUNTIME_CLASS(AInventory)) && static_cast<AInventory *>(actor)->Owner != NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
removecount++;
|
||||
actor->ClearCounters();
|
||||
actor->Destroy();
|
||||
|
@ -2193,12 +2199,12 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
|
||||
case DEM_GIVECHEAT:
|
||||
s = ReadString (stream);
|
||||
cht_Give (&players[player], s, ReadWord (stream));
|
||||
cht_Give (&players[player], s, ReadLong (stream));
|
||||
break;
|
||||
|
||||
case DEM_TAKECHEAT:
|
||||
s = ReadString (stream);
|
||||
cht_Take (&players[player], s, ReadWord (stream));
|
||||
cht_Take (&players[player], s, ReadLong (stream));
|
||||
break;
|
||||
|
||||
case DEM_WARPCHEAT:
|
||||
|
@ -2248,11 +2254,11 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
if (gamestate == GS_LEVEL && !paused)
|
||||
{
|
||||
AInventory *item = players[player].mo->Inventory;
|
||||
|
||||
auto pitype = PClass::FindActor(NAME_PuzzleItem);
|
||||
while (item != NULL)
|
||||
{
|
||||
AInventory *next = item->Inventory;
|
||||
if (item->ItemFlags & IF_INVBAR && !(item->IsKindOf(RUNTIME_CLASS(APuzzleItem))))
|
||||
if (item->ItemFlags & IF_INVBAR && !(item->IsKindOf(pitype)))
|
||||
{
|
||||
players[player].mo->UseInventory (item);
|
||||
}
|
||||
|
@ -2716,7 +2722,7 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
|
||||
case DEM_GIVECHEAT:
|
||||
case DEM_TAKECHEAT:
|
||||
skip = strlen ((char *)(*stream)) + 3;
|
||||
skip = strlen ((char *)(*stream)) + 5;
|
||||
break;
|
||||
|
||||
case DEM_SUMMON2:
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "d_ticcmd.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
#include "a_artifacts.h"
|
||||
#include "a_weapons.h"
|
||||
|
||||
// The player data structure depends on a number
|
||||
|
@ -121,9 +120,9 @@ public:
|
|||
void TweakSpeeds (double &forwardmove, double &sidemove);
|
||||
void MorphPlayerThink ();
|
||||
void ActivateMorphWeapon ();
|
||||
AWeapon *PickNewWeapon (PClassAmmo *ammotype);
|
||||
AWeapon *BestWeapon (PClassAmmo *ammotype);
|
||||
void CheckWeaponSwitch(PClassAmmo *ammotype);
|
||||
AWeapon *PickNewWeapon (PClassInventory *ammotype);
|
||||
AWeapon *BestWeapon (PClassInventory *ammotype);
|
||||
void CheckWeaponSwitch(PClassInventory *ammotype);
|
||||
void GiveDeathmatchInventory ();
|
||||
void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
|
||||
|
||||
|
@ -152,6 +151,7 @@ public:
|
|||
int MugShotMaxHealth;
|
||||
int RunHealth;
|
||||
int PlayerFlags;
|
||||
double FullHeight;
|
||||
TObjPtr<AInventory> InvFirst; // first inventory item displayed on inventory bar
|
||||
TObjPtr<AInventory> InvSel; // selected inventory item
|
||||
|
||||
|
@ -179,11 +179,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class APlayerChunk : public APlayerPawn
|
||||
{
|
||||
DECLARE_CLASS (APlayerChunk, APlayerPawn)
|
||||
};
|
||||
|
||||
//
|
||||
// PlayerPawn flags
|
||||
//
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "colormatcher.h"
|
||||
#include "b_bot.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
FDecalLib DecalLibrary;
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "dsectoreffect.h"
|
||||
#include "serializer.h"
|
||||
#include "virtual.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -274,6 +275,7 @@ DObject::DObject ()
|
|||
{
|
||||
ObjectFlags = GC::CurrentWhite & OF_WhiteBits;
|
||||
ObjNext = GC::Root;
|
||||
GCNext = nullptr;
|
||||
GC::Root = this;
|
||||
}
|
||||
|
||||
|
@ -282,6 +284,7 @@ DObject::DObject (PClass *inClass)
|
|||
{
|
||||
ObjectFlags = GC::CurrentWhite & OF_WhiteBits;
|
||||
ObjNext = GC::Root;
|
||||
GCNext = nullptr;
|
||||
GC::Root = this;
|
||||
}
|
||||
|
||||
|
@ -350,8 +353,18 @@ DObject::~DObject ()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DObject::Destroy ()
|
||||
void DObject:: Destroy ()
|
||||
{
|
||||
// We cannot call the VM during shutdown because all the needed data has been or is in the process of being deleted.
|
||||
if (PClass::bVMOperational)
|
||||
{
|
||||
IFVIRTUAL(DObject, OnDestroy)
|
||||
{
|
||||
VMValue params[1] = { (DObject*)this };
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0);
|
||||
}
|
||||
}
|
||||
OnDestroy();
|
||||
ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe;
|
||||
}
|
||||
|
||||
|
@ -445,9 +458,7 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool s
|
|||
auto def = GetDefaultByType(p);
|
||||
if (def != nullptr)
|
||||
{
|
||||
def->Class = p;
|
||||
def->DObject::PointerSubstitution(old, notOld);
|
||||
def->Class = nullptr; // reset pointer. Defaults should not have a valid class pointer.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,29 +480,26 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool s
|
|||
changed += players[i].FixPointers (old, notOld);
|
||||
}
|
||||
|
||||
for (auto &s : sectorPortals)
|
||||
for (auto &s : level.sectorPortals)
|
||||
{
|
||||
if (s.mSkybox == old)
|
||||
{
|
||||
s.mSkybox = static_cast<ASkyViewpoint*>(notOld);
|
||||
s.mSkybox = static_cast<AActor*>(notOld);
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through sectors.
|
||||
if (sectors != NULL)
|
||||
for (auto &sec : level.sectors)
|
||||
{
|
||||
for (i = 0; i < numsectors; ++i)
|
||||
{
|
||||
#define SECTOR_CHECK(f,t) \
|
||||
if (sectors[i].f.p == static_cast<t *>(old)) { sectors[i].f = static_cast<t *>(notOld); changed++; }
|
||||
SECTOR_CHECK( SoundTarget, AActor );
|
||||
SECTOR_CHECK( SecActTarget, ASectorAction );
|
||||
SECTOR_CHECK( floordata, DSectorEffect );
|
||||
SECTOR_CHECK( ceilingdata, DSectorEffect );
|
||||
SECTOR_CHECK( lightingdata, DSectorEffect );
|
||||
if (sec.f.p == static_cast<t *>(old)) { sec.f = static_cast<t *>(notOld); changed++; }
|
||||
SECTOR_CHECK( SoundTarget, AActor );
|
||||
SECTOR_CHECK( SecActTarget, AActor );
|
||||
SECTOR_CHECK( floordata, DSectorEffect );
|
||||
SECTOR_CHECK( ceilingdata, DSectorEffect );
|
||||
SECTOR_CHECK( lightingdata, DSectorEffect );
|
||||
#undef SECTOR_CHECK
|
||||
}
|
||||
}
|
||||
|
||||
// Go through bot stuff.
|
||||
|
@ -557,4 +565,17 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName)
|
|||
{
|
||||
PARAM_SELF_PROLOGUE(DObject);
|
||||
ACTION_RETURN_INT(self->GetClass()->TypeName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *DObject::ScriptVar(FName field, PType *type)
|
||||
{
|
||||
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
|
||||
if (sym && (sym->Type == type || type == nullptr))
|
||||
{
|
||||
return (((char*)this) + sym->Offset);
|
||||
}
|
||||
// This is only for internal use so I_Error is fine.
|
||||
I_Error("Variable %s not found in %s\n", field.GetChars(), GetClass()->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "i_system.h"
|
||||
|
||||
class PClass;
|
||||
|
||||
class PType;
|
||||
class FSerializer;
|
||||
|
||||
class DObject;
|
||||
|
@ -94,15 +94,10 @@ enum
|
|||
CLASSREG_PClass,
|
||||
CLASSREG_PClassActor,
|
||||
CLASSREG_PClassInventory,
|
||||
CLASSREG_PClassAmmo,
|
||||
CLASSREG_PClassHealth,
|
||||
CLASSREG_PClassPuzzleItem,
|
||||
CLASSREG_PClassWeapon,
|
||||
CLASSREG_PClassPlayerPawn,
|
||||
CLASSREG_PClassType,
|
||||
CLASSREG_PClassClass,
|
||||
CLASSREG_PClassWeaponPiece,
|
||||
CLASSREG_PClassPowerupGiver
|
||||
};
|
||||
|
||||
struct ClassReg
|
||||
|
@ -213,7 +208,6 @@ enum EObjectFlags
|
|||
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
|
||||
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
|
||||
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
||||
OF_SuperCall = 1 << 12, // A super call from the VM is about to be performed
|
||||
};
|
||||
|
||||
template<class T> class TObjPtr;
|
||||
|
@ -456,6 +450,10 @@ public:
|
|||
DObject *GCNext; // Next object in this collection list
|
||||
uint32 ObjectFlags; // Flags for this object
|
||||
|
||||
void *ScriptVar(FName field, PType *type);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
DObject ();
|
||||
DObject (PClass *inClass);
|
||||
|
@ -476,7 +474,16 @@ public:
|
|||
// that don't call their base class.
|
||||
void CheckIfSerialized () const;
|
||||
|
||||
virtual void Destroy();
|
||||
virtual void OnDestroy() {}
|
||||
void Destroy();
|
||||
|
||||
// Add other types as needed.
|
||||
bool &BoolVar(FName field);
|
||||
int &IntVar(FName field);
|
||||
PalEntry &ColorVar(FName field);
|
||||
FName &NameVar(FName field);
|
||||
double &FloatVar(FName field);
|
||||
template<class T> T*& PointerVar(FName field);
|
||||
|
||||
// If you need to replace one object with another and want to
|
||||
// change any pointers from the old object to the new object,
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "menu/menu.h"
|
||||
#include "intermission/intermission.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -323,12 +324,12 @@ static void MarkRoot()
|
|||
Mark(Args);
|
||||
Mark(screen);
|
||||
Mark(StatusBar);
|
||||
Mark(DMenu::CurrentMenu);
|
||||
M_MarkMenus();
|
||||
Mark(DIntermissionController::CurrentIntermission);
|
||||
DThinker::MarkRoots();
|
||||
FCanvasTextureInfo::Mark();
|
||||
Mark(DACSThinker::ActiveThinker);
|
||||
for (auto &s : sectorPortals)
|
||||
for (auto &s : level.sectorPortals)
|
||||
{
|
||||
Mark(s.mSkybox);
|
||||
}
|
||||
|
@ -346,13 +347,13 @@ static void MarkRoot()
|
|||
// Mark sound sequences.
|
||||
DSeqNode::StaticMarkHead();
|
||||
// Mark sectors.
|
||||
if (SectorMarker == NULL && sectors != NULL)
|
||||
if (SectorMarker == nullptr && level.sectors.Size() > 0)
|
||||
{
|
||||
SectorMarker = new DSectorMarker;
|
||||
}
|
||||
else if (sectors == NULL)
|
||||
else if (level.sectors.Size() == 0)
|
||||
{
|
||||
SectorMarker = NULL;
|
||||
SectorMarker = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -378,7 +379,7 @@ static void MarkRoot()
|
|||
Mark(PClass::AllClasses[i]);
|
||||
}
|
||||
// Mark global symbols
|
||||
GlobalSymbols.MarkSymbols();
|
||||
Namespaces.MarkSymbols();
|
||||
// Mark bot stuff.
|
||||
Mark(bglobal.firstthing);
|
||||
Mark(bglobal.body1);
|
||||
|
@ -677,26 +678,25 @@ size_t DSectorMarker::PropagateMark()
|
|||
int i;
|
||||
int marked = 0;
|
||||
bool moretodo = false;
|
||||
int numsectors = level.sectors.Size();
|
||||
|
||||
if (sectors != NULL)
|
||||
for (i = 0; i < SECTORSTEPSIZE && SecNum + i < numsectors; ++i)
|
||||
{
|
||||
for (i = 0; i < SECTORSTEPSIZE && SecNum + i < numsectors; ++i)
|
||||
{
|
||||
sector_t *sec = §ors[SecNum + i];
|
||||
GC::Mark(sec->SoundTarget);
|
||||
GC::Mark(sec->SecActTarget);
|
||||
GC::Mark(sec->floordata);
|
||||
GC::Mark(sec->ceilingdata);
|
||||
GC::Mark(sec->lightingdata);
|
||||
for(int j=0;j<4;j++) GC::Mark(sec->interpolations[j]);
|
||||
}
|
||||
marked += i * sizeof(sector_t);
|
||||
if (SecNum + i < numsectors)
|
||||
{
|
||||
SecNum += i;
|
||||
moretodo = true;
|
||||
}
|
||||
sector_t *sec = &level.sectors[SecNum + i];
|
||||
GC::Mark(sec->SoundTarget);
|
||||
GC::Mark(sec->SecActTarget);
|
||||
GC::Mark(sec->floordata);
|
||||
GC::Mark(sec->ceilingdata);
|
||||
GC::Mark(sec->lightingdata);
|
||||
for(int j=0;j<4;j++) GC::Mark(sec->interpolations[j]);
|
||||
}
|
||||
marked += i * sizeof(sector_t);
|
||||
if (SecNum + i < numsectors)
|
||||
{
|
||||
SecNum += i;
|
||||
moretodo = true;
|
||||
}
|
||||
|
||||
if (!moretodo && polyobjs != NULL)
|
||||
{
|
||||
for (i = 0; i < POLYSTEPSIZE && PolyNum + i < po_NumPolyobjs; ++i)
|
||||
|
@ -710,15 +710,15 @@ size_t DSectorMarker::PropagateMark()
|
|||
moretodo = true;
|
||||
}
|
||||
}
|
||||
if (!moretodo && sides != NULL)
|
||||
if (!moretodo && level.sides.Size() > 0)
|
||||
{
|
||||
for (i = 0; i < SIDEDEFSTEPSIZE && SideNum + i < numsides; ++i)
|
||||
for (i = 0; i < SIDEDEFSTEPSIZE && SideNum + i < (int)level.sides.Size(); ++i)
|
||||
{
|
||||
side_t *side = &sides[SideNum + i];
|
||||
side_t *side = &level.sides[SideNum + i];
|
||||
for(int j=0;j<3;j++) GC::Mark(side->textures[j].interpolation);
|
||||
}
|
||||
marked += i * sizeof(side_t);
|
||||
if (SideNum + i < numsides)
|
||||
if (SideNum + i < (int)level.sides.Size())
|
||||
{
|
||||
SideNum += i;
|
||||
moretodo = true;
|
||||
|
|
459
src/dobjtype.cpp
459
src/dobjtype.cpp
|
@ -45,13 +45,10 @@
|
|||
#include "autosegs.h"
|
||||
#include "v_text.h"
|
||||
#include "a_pickups.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "a_weaponpiece.h"
|
||||
#include "d_player.h"
|
||||
#include "doomerrors.h"
|
||||
#include "fragglescript/t_fs.h"
|
||||
#include "a_keys.h"
|
||||
#include "a_health.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -68,10 +65,13 @@ EXTERN_CVAR(Bool, strictdecorate);
|
|||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
FNamespaceManager Namespaces;
|
||||
|
||||
FTypeTable TypeTable;
|
||||
PSymbolTable GlobalSymbols;
|
||||
TArray<PClass *> PClass::AllClasses;
|
||||
TArray<VMFunction**> PClass::FunctionPtrList;
|
||||
bool PClass::bShutdown;
|
||||
bool PClass::bVMOperational;
|
||||
|
||||
PErrorType *TypeError;
|
||||
PErrorType *TypeAuto;
|
||||
|
@ -94,6 +94,7 @@ PStruct *TypeVector3;
|
|||
PStruct *TypeColorStruct;
|
||||
PStruct *TypeStringStruct;
|
||||
PPointer *TypeNullPtr;
|
||||
PPointer *TypeVoidPtr;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
|
@ -118,7 +119,7 @@ void DumpTypeTable()
|
|||
Printf("%4zu:", i);
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext)
|
||||
{
|
||||
Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast<PNamedType*>(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars());
|
||||
Printf(" -> %s", ty->DescriptiveName());
|
||||
len++;
|
||||
all++;
|
||||
}
|
||||
|
@ -241,159 +242,6 @@ size_t PType::PropagateMark()
|
|||
return marked + Super::PropagateMark();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: AddConversion
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &))
|
||||
{
|
||||
// Make sure a conversion hasn't already been registered
|
||||
for (unsigned i = 0; i < Conversions.Size(); ++i)
|
||||
{
|
||||
if (Conversions[i].TargetType == target)
|
||||
return false;
|
||||
}
|
||||
Conversions.Push(Conversion(target, convertconst));
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: FindConversion
|
||||
//
|
||||
// Returns <0 if there is no path to target. Otherwise, returns the distance
|
||||
// to target and fills slots (if non-NULL) with the necessary conversions
|
||||
// to get there. A result of 0 means this is the target.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots)
|
||||
{
|
||||
if (this == target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// The queue is implemented as a ring buffer
|
||||
VisitQueue queue;
|
||||
VisitedNodeSet visited;
|
||||
|
||||
// Use a breadth-first search to find the shortest path to the target.
|
||||
MarkPred(NULL, -1, -1);
|
||||
queue.Push(this);
|
||||
visited.Insert(this);
|
||||
while (!queue.IsEmpty())
|
||||
{
|
||||
PType *t = queue.Pop();
|
||||
if (t == target)
|
||||
{ // found it
|
||||
if (slots != NULL)
|
||||
{
|
||||
if (t->Distance >= numslots)
|
||||
{ // Distance is too far for the output
|
||||
return -2;
|
||||
}
|
||||
t->FillConversionPath(slots);
|
||||
}
|
||||
return t->Distance + 1;
|
||||
}
|
||||
for (unsigned i = 0; i < t->Conversions.Size(); ++i)
|
||||
{
|
||||
PType *succ = t->Conversions[i].TargetType;
|
||||
if (!visited.Check(succ))
|
||||
{
|
||||
succ->MarkPred(t, i, t->Distance + 1);
|
||||
visited.Insert(succ);
|
||||
queue.Push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: FillConversionPath
|
||||
//
|
||||
// Traces backwards from the target type to the original type and fills in
|
||||
// the conversions necessary to get between them. slots must point to an
|
||||
// array large enough to contain the entire path.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::FillConversionPath(const PType::Conversion **slots)
|
||||
{
|
||||
for (PType *node = this; node->Distance >= 0; node = node->PredType)
|
||||
{
|
||||
assert(node->PredType != NULL);
|
||||
slots[node->Distance] = &node->PredType->Conversions[node->PredConv];
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitQueue :: Push
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::VisitQueue::Push(PType *type)
|
||||
{
|
||||
Queue[In] = type;
|
||||
Advance(In);
|
||||
assert(!IsEmpty() && "Queue overflowed");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitQueue :: Pop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PType *PType::VisitQueue::Pop()
|
||||
{
|
||||
if (IsEmpty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
PType *node = Queue[Out];
|
||||
Advance(Out);
|
||||
return node;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitedNodeSet :: Insert
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::VisitedNodeSet::Insert(PType *node)
|
||||
{
|
||||
assert(!Check(node) && "Node was already inserted");
|
||||
size_t buck = Hash(node) & (countof(Buckets) - 1);
|
||||
node->VisitNext = Buckets[buck];
|
||||
Buckets[buck] = node;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: VisitedNodeSet :: Check
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::VisitedNodeSet::Check(const PType *node)
|
||||
{
|
||||
size_t buck = Hash(node) & (countof(Buckets) - 1);
|
||||
for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext)
|
||||
{
|
||||
if (probe == node)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: WriteValue
|
||||
|
@ -533,16 +381,9 @@ const char *PType::DescriptiveName() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void ReleaseGlobalSymbols()
|
||||
{
|
||||
TypeTable.Clear();
|
||||
GlobalSymbols.ReleaseSymbols();
|
||||
}
|
||||
|
||||
void PType::StaticInit()
|
||||
{
|
||||
// Add types to the global symbol table.
|
||||
atterm(ReleaseGlobalSymbols);
|
||||
|
||||
// Set up TypeTable hash keys.
|
||||
RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType);
|
||||
|
@ -593,8 +434,9 @@ void PType::StaticInit()
|
|||
TypeTable.AddType(TypeSpriteID = new PSpriteID);
|
||||
TypeTable.AddType(TypeTextureID = new PTextureID);
|
||||
|
||||
TypeVoidPtr = NewPointer(TypeVoid, false);
|
||||
TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
|
||||
TypeStringStruct = NewNativeStruct(NAME_String, nullptr);
|
||||
TypeStringStruct = NewNativeStruct("Stringstruct", nullptr);
|
||||
#ifdef __BIG_ENDIAN__
|
||||
TypeColorStruct->AddField(NAME_a, TypeUInt8);
|
||||
TypeColorStruct->AddField(NAME_r, TypeUInt8);
|
||||
|
@ -632,24 +474,24 @@ void PType::StaticInit()
|
|||
|
||||
|
||||
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_String, TypeString));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Name, TypeName));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_State, TypeState));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2));
|
||||
GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_String, TypeString));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Name, TypeName));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_State, TypeState));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2));
|
||||
Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1787,6 +1629,18 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
else mDescriptiveName = "ClassPointer";
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - isCompatible
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PClassPointer::isCompatible(PType *type)
|
||||
{
|
||||
auto other = dyn_cast<PClassPointer>(type);
|
||||
return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer :: IsMatch
|
||||
|
@ -1840,7 +1694,7 @@ PClassPointer *NewClassPointer(PClass *restrict)
|
|||
IMPLEMENT_CLASS(PEnum, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(PEnum)
|
||||
IMPLEMENT_POINTER(ValueType)
|
||||
IMPLEMENT_POINTER(Outer)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1850,7 +1704,7 @@ IMPLEMENT_POINTERS_END
|
|||
//==========================================================================
|
||||
|
||||
PEnum::PEnum()
|
||||
: ValueType(NULL)
|
||||
: PInt(4, false)
|
||||
{
|
||||
mDescriptiveName = "Enum";
|
||||
}
|
||||
|
@ -1862,8 +1716,10 @@ PEnum::PEnum()
|
|||
//==========================================================================
|
||||
|
||||
PEnum::PEnum(FName name, PTypeBase *outer)
|
||||
: PNamedType(name, outer), ValueType(NULL)
|
||||
: PInt(4, false)
|
||||
{
|
||||
EnumName = name;
|
||||
Outer = outer;
|
||||
mDescriptiveName.Format("Enum<%s>", name.GetChars());
|
||||
}
|
||||
|
||||
|
@ -1879,6 +1735,7 @@ PEnum::PEnum(FName name, PTypeBase *outer)
|
|||
PEnum *NewEnum(FName name, PTypeBase *outer)
|
||||
{
|
||||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (etype == NULL)
|
||||
{
|
||||
|
@ -2521,6 +2378,7 @@ size_t PStruct::PropagateMark()
|
|||
PStruct *NewStruct(FName name, PTypeBase *outer)
|
||||
{
|
||||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (stype == NULL)
|
||||
{
|
||||
|
@ -2540,8 +2398,8 @@ IMPLEMENT_CLASS(PNativeStruct, false, false)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
PNativeStruct::PNativeStruct(FName name)
|
||||
: PStruct(name, nullptr)
|
||||
PNativeStruct::PNativeStruct(FName name, PTypeBase *outer)
|
||||
: PStruct(name, outer)
|
||||
{
|
||||
mDescriptiveName.Format("NativeStruct<%s>", name.GetChars());
|
||||
Size = 0;
|
||||
|
@ -2559,10 +2417,11 @@ PNativeStruct::PNativeStruct(FName name)
|
|||
PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer)
|
||||
{
|
||||
size_t bucket;
|
||||
if (outer == nullptr) outer = Namespaces.GlobalNamespace;
|
||||
PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket);
|
||||
if (stype == NULL)
|
||||
{
|
||||
stype = new PNativeStruct(name);
|
||||
stype = new PNativeStruct(name, outer);
|
||||
TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket);
|
||||
}
|
||||
return static_cast<PNativeStruct *>(stype);
|
||||
|
@ -2613,6 +2472,27 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue
|
|||
else BitValue = -1;
|
||||
}
|
||||
|
||||
/* PProperty *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PProperty, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PField - Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PProperty::PProperty()
|
||||
: PSymbol(NAME_None)
|
||||
{
|
||||
}
|
||||
|
||||
PProperty::PProperty(FName name, TArray<PField *> &fields)
|
||||
: PSymbol(name)
|
||||
{
|
||||
Variables = std::move(fields);
|
||||
}
|
||||
|
||||
/* PPrototype *************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PPrototype, false, false)
|
||||
|
@ -2923,6 +2803,7 @@ void PClass::StaticInit ()
|
|||
atterm (StaticShutdown);
|
||||
|
||||
StaticBootstrap();
|
||||
Namespaces.GlobalNamespace = Namespaces.NewNamespace(0);
|
||||
|
||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||
|
||||
|
@ -2960,7 +2841,24 @@ void PClass::StaticShutdown ()
|
|||
TArray<size_t *> uniqueFPs(64);
|
||||
unsigned int i, j;
|
||||
|
||||
FS_Close(); // this must be done before the classes get deleted.
|
||||
// delete all variables containing pointers to script functions.
|
||||
for (auto p : FunctionPtrList)
|
||||
{
|
||||
*p = nullptr;
|
||||
}
|
||||
FunctionPtrList.Clear();
|
||||
|
||||
// Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down.
|
||||
GC::FullGC();
|
||||
|
||||
// From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now.
|
||||
// This flags DObject::Destroy not to call any scripted OnDestroy methods anymore.
|
||||
bVMOperational = false;
|
||||
|
||||
// Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts.
|
||||
TypeTable.Clear();
|
||||
Namespaces.ReleaseSymbols();
|
||||
|
||||
for (i = 0; i < PClass::AllClasses.Size(); ++i)
|
||||
{
|
||||
PClass *type = PClass::AllClasses[i];
|
||||
|
@ -2987,7 +2885,6 @@ void PClass::StaticShutdown ()
|
|||
{
|
||||
delete[] uniqueFPs[i];
|
||||
}
|
||||
TypeTable.Clear();
|
||||
bShutdown = true;
|
||||
|
||||
AllClasses.Clear();
|
||||
|
@ -3000,7 +2897,7 @@ void PClass::StaticShutdown ()
|
|||
auto cr = ((ClassReg *)*probe);
|
||||
cr->MyClass = nullptr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3088,9 +2985,6 @@ PClass *ClassReg::RegisterClass()
|
|||
&PClass::RegistrationInfo,
|
||||
&PClassActor::RegistrationInfo,
|
||||
&PClassInventory::RegistrationInfo,
|
||||
&PClassAmmo::RegistrationInfo,
|
||||
&PClassHealth::RegistrationInfo,
|
||||
&PClassPuzzleItem::RegistrationInfo,
|
||||
&PClassWeapon::RegistrationInfo,
|
||||
&PClassPlayerPawn::RegistrationInfo,
|
||||
&PClassType::RegistrationInfo,
|
||||
|
@ -3159,14 +3053,14 @@ void PClass::InsertIntoHash ()
|
|||
size_t bucket;
|
||||
PType *found;
|
||||
|
||||
found = TypeTable.FindType(RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, &bucket);
|
||||
found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket);
|
||||
if (found != NULL)
|
||||
{ // This type has already been inserted
|
||||
I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeTable.AddType(this, RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, bucket);
|
||||
TypeTable.AddType(this, RUNTIME_CLASS(PClass), 0, TypeName, bucket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3204,8 +3098,7 @@ PClass *PClass::FindClass (FName zaname)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass),
|
||||
/*FIXME:Outer*/0, zaname, NULL));
|
||||
return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3229,7 +3122,7 @@ DObject *PClass::CreateNew() const
|
|||
|
||||
ConstructNative (mem);
|
||||
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
||||
InitializeSpecials(mem);
|
||||
InitializeSpecials(mem, Defaults);
|
||||
return (DObject *)mem;
|
||||
}
|
||||
|
||||
|
@ -3241,7 +3134,7 @@ DObject *PClass::CreateNew() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::InitializeSpecials(void *addr) const
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults) const
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle initialization natively.
|
||||
|
@ -3250,10 +3143,10 @@ void PClass::InitializeSpecials(void *addr) const
|
|||
return;
|
||||
}
|
||||
assert(ParentClass != NULL);
|
||||
ParentClass->InitializeSpecials(addr);
|
||||
ParentClass->InitializeSpecials(addr, defaults);
|
||||
for (auto tao : SpecialInits)
|
||||
{
|
||||
tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults == nullptr? nullptr : Defaults + tao.second);
|
||||
tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3308,26 +3201,44 @@ void PClass::Derive(PClass *newclass, FName name)
|
|||
|
||||
void PClass::InitializeDefaults()
|
||||
{
|
||||
assert(Defaults == NULL);
|
||||
Defaults = (BYTE *)M_Malloc(Size);
|
||||
if (ParentClass->Defaults != NULL)
|
||||
if (IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||
{
|
||||
memcpy(Defaults, ParentClass->Defaults, ParentClass->Size);
|
||||
if (Size > ParentClass->Size)
|
||||
assert(Defaults == NULL);
|
||||
Defaults = (BYTE *)M_Malloc(Size);
|
||||
|
||||
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
|
||||
// Temporarily setting bSerialOverride prevents linking into the thinker chains.
|
||||
auto s = DThinker::bSerialOverride;
|
||||
DThinker::bSerialOverride = true;
|
||||
ConstructNative(Defaults);
|
||||
DThinker::bSerialOverride = s;
|
||||
// We must unlink the defaults from the class list because it's just a static block of data to the engine.
|
||||
DObject *optr = (DObject*)Defaults;
|
||||
GC::Root = optr->ObjNext;
|
||||
optr->ObjNext = nullptr;
|
||||
optr->SetClass(this);
|
||||
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Defaults != NULL)
|
||||
{
|
||||
memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size);
|
||||
memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject));
|
||||
if (Size > ParentClass->Size)
|
||||
{
|
||||
memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Defaults, 0, Size);
|
||||
}
|
||||
|
||||
if (bRuntimeClass)
|
||||
{
|
||||
// Copy parent values from the parent defaults.
|
||||
assert(ParentClass != NULL);
|
||||
ParentClass->InitializeSpecials(Defaults);
|
||||
ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
|
@ -3481,7 +3392,7 @@ PClass *PClass::FindClassTentative(FName name)
|
|||
|
||||
Derive(type, name);
|
||||
type->Size = TentativeClass;
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket);
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -3643,6 +3554,16 @@ VMFunction *PClass::FindFunction(FName clsname, FName funcname)
|
|||
return func->Variants[0].Implementation;
|
||||
}
|
||||
|
||||
void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname)
|
||||
{
|
||||
auto cls = PClass::FindActor(clsname);
|
||||
if (!cls) return;
|
||||
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(funcname, true));
|
||||
if (!func) return;
|
||||
*pptr = func->Variants[0].Implementation;
|
||||
FunctionPtrList.Push(pptr);
|
||||
}
|
||||
|
||||
|
||||
/* FTypeTable **************************************************************/
|
||||
|
||||
|
@ -3918,6 +3839,13 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
|
|||
return sym;
|
||||
}
|
||||
|
||||
void PSymbolTable::RemoveSymbol(PSymbol *sym)
|
||||
{
|
||||
auto mysym = Symbols.CheckKey(sym->SymbolName);
|
||||
if (mysym == nullptr || *mysym != sym) return;
|
||||
Symbols.Remove(sym->SymbolName);
|
||||
}
|
||||
|
||||
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
||||
{
|
||||
// If a symbol with a matching name exists, take its place and return it.
|
||||
|
@ -3933,3 +3861,102 @@ PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
|||
Symbols.Insert(newsym->SymbolName, newsym);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(PNamespace, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(PNamespace)
|
||||
IMPLEMENT_POINTER(Parent)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
PNamespace::PNamespace(int filenum, PNamespace *parent)
|
||||
{
|
||||
Parent = parent;
|
||||
if (parent) Symbols.SetParentTable(&parent->Symbols);
|
||||
FileNum = filenum;
|
||||
}
|
||||
|
||||
size_t PNamespace::PropagateMark()
|
||||
{
|
||||
GC::Mark(Parent);
|
||||
return Symbols.MarkSymbols() + 1;
|
||||
}
|
||||
|
||||
FNamespaceManager::FNamespaceManager()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
}
|
||||
|
||||
PNamespace *FNamespaceManager::NewNamespace(int filenum)
|
||||
{
|
||||
PNamespace *parent = nullptr;
|
||||
// The parent will be the last namespace with this or a lower filenum.
|
||||
// This ensures that DECORATE won't see the symbols of later files.
|
||||
for (int i = AllNamespaces.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (AllNamespaces[i]->FileNum <= filenum)
|
||||
{
|
||||
parent = AllNamespaces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto newns = new PNamespace(filenum, parent);
|
||||
AllNamespaces.Push(newns);
|
||||
return newns;
|
||||
}
|
||||
|
||||
size_t FNamespaceManager::MarkSymbols()
|
||||
{
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
GC::Mark(ns);
|
||||
}
|
||||
return AllNamespaces.Size();
|
||||
}
|
||||
|
||||
void FNamespaceManager::ReleaseSymbols()
|
||||
{
|
||||
GlobalNamespace = nullptr;
|
||||
AllNamespaces.Clear();
|
||||
}
|
||||
|
||||
// removes all symbols from the symbol tables.
|
||||
// After running the compiler these are not needed anymore.
|
||||
// Only the namespaces themselves are kept because the type table references them.
|
||||
int FNamespaceManager::RemoveSymbols()
|
||||
{
|
||||
int count = 0;
|
||||
for (auto ns : AllNamespaces)
|
||||
{
|
||||
count += ns->Symbols.Symbols.CountUsed();
|
||||
ns->Symbols.ReleaseSymbols();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void RemoveUnusedSymbols()
|
||||
{
|
||||
// Global symbols are not needed anymore after running the compiler.
|
||||
int count = Namespaces.RemoveSymbols();
|
||||
|
||||
// We do not need any non-field and non-function symbols in structs and classes anymore.
|
||||
for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i)
|
||||
{
|
||||
for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext)
|
||||
{
|
||||
if (ty->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
auto it = ty->Symbols.GetIterator();
|
||||
PSymbolTable::MapType::Pair *pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction)))
|
||||
{
|
||||
ty->Symbols.RemoveSymbol(pair->Value);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DPrintf(DMSG_SPAMMY, "%d symbols removed after compilation\n", count);
|
||||
}
|
||||
|
|
210
src/dobjtype.h
210
src/dobjtype.h
|
@ -29,11 +29,13 @@ enum
|
|||
VARF_In = (1<<10),
|
||||
VARF_Out = (1<<11),
|
||||
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
|
||||
VARF_Static = (1<<13), // static class data (by necessity read only.)
|
||||
VARF_Static = (1<<13),
|
||||
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
|
||||
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
|
||||
VARF_Ref = (1<<16), // argument is passed by reference.
|
||||
VARF_Transient = (1<<17) // don't auto serialize field.
|
||||
VARF_Transient = (1<<17), // don't auto serialize field.
|
||||
VARF_Meta = (1<<18), // static class data (by necessity read only.)
|
||||
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
|
||||
};
|
||||
|
||||
// Symbol information -------------------------------------------------------
|
||||
|
@ -74,6 +76,7 @@ class VMFrameStack;
|
|||
struct VMValue;
|
||||
struct VMReturn;
|
||||
class VMFunction;
|
||||
struct FNamespaceManager;
|
||||
|
||||
// A VM function ------------------------------------------------------------
|
||||
|
||||
|
@ -137,6 +140,8 @@ struct PSymbolTable
|
|||
// to be in the table with this name, if any.
|
||||
PSymbol *ReplaceSymbol(PSymbol *sym);
|
||||
|
||||
void RemoveSymbol(PSymbol *sym);
|
||||
|
||||
// Frees all symbols from this table.
|
||||
void ReleaseSymbols();
|
||||
|
||||
|
@ -153,6 +158,7 @@ private:
|
|||
MapType Symbols;
|
||||
|
||||
friend class DObject;
|
||||
friend struct FNamespaceManager;
|
||||
};
|
||||
|
||||
// A symbol for a compiler tree node ----------------------------------------
|
||||
|
@ -167,8 +173,6 @@ public:
|
|||
PSymbolTreeNode() : PSymbol(NAME_None) {}
|
||||
};
|
||||
|
||||
extern PSymbolTable GlobalSymbols;
|
||||
|
||||
// Basic information shared by all types ------------------------------------
|
||||
|
||||
// Only one copy of a type is ever instantiated at one time.
|
||||
|
@ -210,15 +214,6 @@ public:
|
|||
typedef PClassType MetaClass;
|
||||
MetaClass *GetClass() const;
|
||||
|
||||
struct Conversion
|
||||
{
|
||||
Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &))
|
||||
: TargetType(target), ConvertConstant(convert) {}
|
||||
|
||||
PType *TargetType;
|
||||
void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump);
|
||||
};
|
||||
|
||||
unsigned int Size; // this type's size
|
||||
unsigned int Align; // this type's preferred alignment
|
||||
PType *HashNext; // next type in this type table
|
||||
|
@ -231,10 +226,6 @@ public:
|
|||
virtual ~PType();
|
||||
virtual bool isNumeric() { return false; }
|
||||
|
||||
bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &));
|
||||
|
||||
int FindConversion(PType *target, const Conversion **slots, int numslots);
|
||||
|
||||
// Writes the value of a variable of this type at (addr) to an archive, preceded by
|
||||
// a tag indicating its type. The tag is there so that variable types can be changed
|
||||
// without completely breaking savegames, provided that the change isn't between
|
||||
|
@ -314,54 +305,6 @@ public:
|
|||
size_t PropagateMark();
|
||||
|
||||
static void StaticInit();
|
||||
|
||||
private:
|
||||
// Stuff for type conversion searches
|
||||
class VisitQueue
|
||||
{
|
||||
public:
|
||||
VisitQueue() : In(0), Out(0) {}
|
||||
void Push(PType *type);
|
||||
PType *Pop();
|
||||
bool IsEmpty() { return In == Out; }
|
||||
|
||||
private:
|
||||
// This is a fixed-sized ring buffer.
|
||||
PType *Queue[64];
|
||||
int In, Out;
|
||||
|
||||
void Advance(int &ptr)
|
||||
{
|
||||
ptr = (ptr + 1) & (countof(Queue) - 1);
|
||||
}
|
||||
};
|
||||
|
||||
class VisitedNodeSet
|
||||
{
|
||||
public:
|
||||
VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); }
|
||||
void Insert(PType *node);
|
||||
bool Check(const PType *node);
|
||||
|
||||
private:
|
||||
PType *Buckets[32];
|
||||
|
||||
size_t Hash(const PType *type) { return size_t(type) >> 4; }
|
||||
};
|
||||
|
||||
TArray<Conversion> Conversions;
|
||||
PType *PredType;
|
||||
PType *VisitNext;
|
||||
short PredConv;
|
||||
short Distance;
|
||||
|
||||
void MarkPred(PType *pred, int conv, int dist)
|
||||
{
|
||||
PredType = pred;
|
||||
PredConv = conv;
|
||||
Distance = dist;
|
||||
}
|
||||
void FillConversionPath(const Conversion **slots);
|
||||
};
|
||||
|
||||
// Not-really-a-type types --------------------------------------------------
|
||||
|
@ -594,8 +537,7 @@ public:
|
|||
|
||||
class PClass *ClassRestriction;
|
||||
|
||||
// this is only here to block PPointer's implementation
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) const override {}
|
||||
bool isCompatible(PType *type);
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
@ -621,17 +563,45 @@ protected:
|
|||
PField();
|
||||
};
|
||||
|
||||
// Struct/class fields ------------------------------------------------------
|
||||
|
||||
// A PField describes a symbol that takes up physical space in the struct.
|
||||
class PProperty : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PProperty, PSymbol);
|
||||
public:
|
||||
PProperty(FName name, TArray<PField *> &variables);
|
||||
|
||||
TArray<PField *> Variables;
|
||||
|
||||
protected:
|
||||
PProperty();
|
||||
};
|
||||
|
||||
class PPropFlag : public PSymbol
|
||||
{
|
||||
DECLARE_CLASS(PPropFlag, PSymbol);
|
||||
public:
|
||||
PPropFlag(FName name, PField *offset, int bitval);
|
||||
|
||||
PField *Offset;
|
||||
int bitval;
|
||||
|
||||
protected:
|
||||
PPropFlag();
|
||||
};
|
||||
|
||||
// Compound types -----------------------------------------------------------
|
||||
|
||||
class PEnum : public PNamedType
|
||||
class PEnum : public PInt
|
||||
{
|
||||
DECLARE_CLASS(PEnum, PNamedType);
|
||||
DECLARE_CLASS(PEnum, PInt);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PEnum(FName name, PTypeBase *outer);
|
||||
|
||||
PType *ValueType;
|
||||
TMap<FName, int> Values;
|
||||
PTypeBase *Outer;
|
||||
FName EnumName;
|
||||
protected:
|
||||
PEnum();
|
||||
};
|
||||
|
@ -708,11 +678,15 @@ protected:
|
|||
class PStruct : public PNamedType
|
||||
{
|
||||
DECLARE_CLASS(PStruct, PNamedType);
|
||||
|
||||
public:
|
||||
PStruct(FName name, PTypeBase *outer);
|
||||
|
||||
TArray<PField *> Fields;
|
||||
bool HasNativeFields;
|
||||
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it.
|
||||
VMFunction *mConstructor = nullptr;
|
||||
VMFunction *mDestructor = nullptr;
|
||||
|
||||
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
|
||||
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
|
||||
|
@ -736,7 +710,7 @@ class PNativeStruct : public PStruct
|
|||
{
|
||||
DECLARE_CLASS(PNativeStruct, PStruct);
|
||||
public:
|
||||
PNativeStruct(FName name = NAME_None);
|
||||
PNativeStruct(FName name = NAME_None, PTypeBase *outer = nullptr);
|
||||
};
|
||||
|
||||
class PPrototype : public PCompoundType
|
||||
|
@ -803,7 +777,7 @@ protected:
|
|||
enum { MetaClassNum = CLASSREG_PClassClass };
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
void Derive(PClass *newclass, FName name);
|
||||
void InitializeSpecials(void *addr) const;
|
||||
void InitializeSpecials(void *addr, void *defaults) const;
|
||||
void SetSuper();
|
||||
public:
|
||||
typedef PClassClass MetaClass;
|
||||
|
@ -874,11 +848,14 @@ public:
|
|||
static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); }
|
||||
static PClassActor *FindActor(FName name);
|
||||
static VMFunction *FindFunction(FName cls, FName func);
|
||||
static void FindFunction(VMFunction **pptr, FName cls, FName func);
|
||||
PClass *FindClassTentative(FName name);
|
||||
|
||||
static TArray<PClass *> AllClasses;
|
||||
static TArray<VMFunction**> FunctionPtrList;
|
||||
|
||||
static bool bShutdown;
|
||||
static bool bVMOperational;
|
||||
};
|
||||
|
||||
class PClassType : public PClass
|
||||
|
@ -965,6 +942,7 @@ extern PStruct *TypeStringStruct;
|
|||
extern PStatePointer *TypeState;
|
||||
extern PStateLabel *TypeStateLabel;
|
||||
extern PPointer *TypeNullPtr;
|
||||
extern PPointer *TypeVoidPtr;
|
||||
|
||||
// A constant value ---------------------------------------------------------
|
||||
|
||||
|
@ -1006,35 +984,75 @@ class PSymbolConstString : public PSymbolConst
|
|||
public:
|
||||
FString Str;
|
||||
|
||||
PSymbolConstString(FName name, FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
||||
PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
||||
PSymbolConstString() {}
|
||||
};
|
||||
|
||||
void ReleaseGlobalSymbols();
|
||||
// Namespaces --------------------------------------------------
|
||||
|
||||
class PNamespace : public PTypeBase
|
||||
{
|
||||
DECLARE_CLASS(PNamespace, PTypeBase)
|
||||
HAS_OBJECT_POINTERS;
|
||||
|
||||
public:
|
||||
PSymbolTable Symbols;
|
||||
PNamespace *Parent;
|
||||
int FileNum; // This is for blocking DECORATE access to later files.
|
||||
|
||||
PNamespace() {}
|
||||
PNamespace(int filenum, PNamespace *parent);
|
||||
size_t PropagateMark();
|
||||
};
|
||||
|
||||
struct FNamespaceManager
|
||||
{
|
||||
PNamespace *GlobalNamespace;
|
||||
TArray<PNamespace *> AllNamespaces;
|
||||
|
||||
FNamespaceManager();
|
||||
PNamespace *NewNamespace(int filenum);
|
||||
size_t MarkSymbols();
|
||||
void ReleaseSymbols();
|
||||
int RemoveSymbols();
|
||||
};
|
||||
|
||||
extern FNamespaceManager Namespaces;
|
||||
|
||||
|
||||
// Enumerations for serializing types in an archive -------------------------
|
||||
|
||||
enum ETypeVal : BYTE
|
||||
inline bool &DObject::BoolVar(FName field)
|
||||
{
|
||||
VAL_Int8,
|
||||
VAL_UInt8,
|
||||
VAL_Int16,
|
||||
VAL_UInt16,
|
||||
VAL_Int32,
|
||||
VAL_UInt32,
|
||||
VAL_Int64,
|
||||
VAL_UInt64,
|
||||
VAL_Zero,
|
||||
VAL_One,
|
||||
VAL_Float32,
|
||||
VAL_Float64,
|
||||
VAL_String,
|
||||
VAL_Name,
|
||||
VAL_Struct,
|
||||
VAL_Array,
|
||||
VAL_Object,
|
||||
VAL_State,
|
||||
VAL_Class,
|
||||
};
|
||||
return *(bool*)ScriptVar(field, TypeBool);
|
||||
}
|
||||
|
||||
inline int &DObject::IntVar(FName field)
|
||||
{
|
||||
return *(int*)ScriptVar(field, TypeSInt32);
|
||||
}
|
||||
|
||||
inline PalEntry &DObject::ColorVar(FName field)
|
||||
{
|
||||
return *(PalEntry*)ScriptVar(field, TypeColor);
|
||||
}
|
||||
|
||||
inline FName &DObject::NameVar(FName field)
|
||||
{
|
||||
return *(FName*)ScriptVar(field, TypeName);
|
||||
}
|
||||
|
||||
inline double &DObject::FloatVar(FName field)
|
||||
{
|
||||
return *(double*)ScriptVar(field, TypeFloat64);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T *&DObject::PointerVar(FName field)
|
||||
{
|
||||
return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
|
||||
}
|
||||
|
||||
void RemoveUnusedSymbols();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "i_system.h"
|
||||
#include "g_level.h"
|
||||
#include "p_local.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
int SaveVersion;
|
||||
|
||||
|
|
|
@ -187,6 +187,13 @@ private:
|
|||
int texnum;
|
||||
};
|
||||
|
||||
// This is for the script interface which needs to do casts from int to texture.
|
||||
class FSetTextureID : public FTextureID
|
||||
{
|
||||
public:
|
||||
FSetTextureID(int v) : FTextureID(v) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Screenshot buffer image data types
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "dsectoreffect.h"
|
||||
#include "gi.h"
|
||||
#include "p_local.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "p_3dmidtex.h"
|
||||
#include "r_data/r_interpolate.h"
|
||||
#include "statnums.h"
|
||||
|
@ -40,7 +41,7 @@ DSectorEffect::DSectorEffect ()
|
|||
m_Sector = NULL;
|
||||
}
|
||||
|
||||
void DSectorEffect::Destroy()
|
||||
void DSectorEffect::OnDestroy()
|
||||
{
|
||||
if (m_Sector)
|
||||
{
|
||||
|
@ -57,7 +58,7 @@ void DSectorEffect::Destroy()
|
|||
m_Sector->lightingdata = NULL;
|
||||
}
|
||||
}
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
DSectorEffect::DSectorEffect (sector_t *sector)
|
||||
|
@ -88,10 +89,10 @@ DMover::DMover (sector_t *sector)
|
|||
interpolation = NULL;
|
||||
}
|
||||
|
||||
void DMover::Destroy()
|
||||
void DMover::OnDestroy()
|
||||
{
|
||||
StopInterpolation();
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void DMover::Serialize(FSerializer &arc)
|
||||
|
@ -279,6 +280,19 @@ EMoveResult sector_t::MoveFloor(double speed, double dest, int crush, int direct
|
|||
return EMoveResult::ok;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Sector, MoveFloor)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
|
||||
PARAM_FLOAT(speed);
|
||||
PARAM_FLOAT(dest);
|
||||
PARAM_INT(crush);
|
||||
PARAM_INT(dir);
|
||||
PARAM_BOOL(hex);
|
||||
PARAM_BOOL_DEF(inst);
|
||||
ACTION_RETURN_INT((int)self->MoveFloor(speed, dest, crush, dir, hex, inst));
|
||||
}
|
||||
|
||||
|
||||
EMoveResult sector_t::MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush)
|
||||
{
|
||||
bool flag;
|
||||
|
@ -392,3 +406,14 @@ EMoveResult sector_t::MoveCeiling(double speed, double dest, int crush, int dire
|
|||
}
|
||||
return EMoveResult::ok;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Sector, MoveCeiling)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
|
||||
PARAM_FLOAT(speed);
|
||||
PARAM_FLOAT(dest);
|
||||
PARAM_INT(crush);
|
||||
PARAM_INT(dir);
|
||||
PARAM_BOOL(hex);
|
||||
ACTION_RETURN_INT((int)self->MoveCeiling(speed, dest, crush, dir, hex));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
sector_t *GetSector() const { return m_Sector; }
|
||||
|
||||
|
@ -35,7 +35,7 @@ protected:
|
|||
DMover ();
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
};
|
||||
|
||||
class DMovingFloor : public DMover
|
||||
|
|
|
@ -253,7 +253,7 @@ DThinker::~DThinker ()
|
|||
assert(NextThinker == NULL && PrevThinker == NULL);
|
||||
}
|
||||
|
||||
void DThinker::Destroy ()
|
||||
void DThinker::OnDestroy ()
|
||||
{
|
||||
assert((NextThinker != NULL && PrevThinker != NULL) ||
|
||||
(NextThinker == NULL && PrevThinker == NULL));
|
||||
|
@ -261,7 +261,7 @@ void DThinker::Destroy ()
|
|||
{
|
||||
Remove();
|
||||
}
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -710,8 +710,12 @@ class DThinkerIterator : public DObject, public FThinkerIterator
|
|||
{
|
||||
DECLARE_CLASS(DThinkerIterator, DObject)
|
||||
|
||||
DThinkerIterator()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
DThinkerIterator(PClass *cls = nullptr, int statnum = MAX_STATNUM + 1)
|
||||
DThinkerIterator(PClass *cls, int statnum = MAX_STATNUM + 1)
|
||||
: FThinkerIterator(cls, statnum)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ class DThinker : public DObject
|
|||
DECLARE_CLASS (DThinker, DObject)
|
||||
public:
|
||||
DThinker (int statnum = STAT_DEFAULT) throw();
|
||||
void Destroy () override;
|
||||
void OnDestroy () override;
|
||||
virtual ~DThinker ();
|
||||
virtual void Tick ();
|
||||
void CallTick();
|
||||
|
@ -125,6 +125,9 @@ public:
|
|||
FThinkerIterator (const PClass *type, int statnum, DThinker *prev);
|
||||
DThinker *Next (bool exact = false);
|
||||
void Reinit ();
|
||||
|
||||
protected:
|
||||
FThinkerIterator() {}
|
||||
};
|
||||
|
||||
template <class T> class TThinkerIterator : public FThinkerIterator
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "v_palette.h"
|
||||
#include "p_acs.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
struct FEDOptions : public FOptionalMapinfoData
|
||||
|
@ -705,7 +706,7 @@ void ProcessEDLinedef(line_t *ld, int recordnum)
|
|||
ld->flags = (ld->flags&~fmask) | eld->flags;
|
||||
ld->setAlpha(eld->alpha);
|
||||
memcpy(ld->args, eld->args, sizeof(ld->args));
|
||||
tagManager.AddLineID(int(ld - lines), eld->tag);
|
||||
tagManager.AddLineID(ld->Index(), eld->tag);
|
||||
}
|
||||
|
||||
void ProcessEDSector(sector_t *sec, int recordnum)
|
||||
|
@ -753,27 +754,26 @@ void ProcessEDSector(sector_t *sec, int recordnum)
|
|||
|
||||
void ProcessEDSectors()
|
||||
{
|
||||
int i;
|
||||
|
||||
InitED();
|
||||
if (EDSectors.CountUsed() == 0) return; // don't waste time if there's no records.
|
||||
|
||||
// collect all Extradata sector records up front so we do not need to search the complete line array for each sector separately.
|
||||
auto numsectors = level.sectors.Size();
|
||||
int *sectorrecord = new int[numsectors];
|
||||
memset(sectorrecord, -1, numsectors * sizeof(int));
|
||||
for (i = 0; i < numlines; i++)
|
||||
for (auto &line : level.lines)
|
||||
{
|
||||
if (lines[i].special == Static_Init && lines[i].args[1] == Init_EDSector)
|
||||
if (line.special == Static_Init && line.args[1] == Init_EDSector)
|
||||
{
|
||||
sectorrecord[lines[i].frontsector - sectors] = lines[i].args[0];
|
||||
lines[i].special = 0;
|
||||
sectorrecord[line.frontsector->Index()] = line.args[0];
|
||||
line.special = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < numsectors; i++)
|
||||
for (unsigned i = 0; i < numsectors; i++)
|
||||
{
|
||||
if (sectorrecord[i] >= 0)
|
||||
{
|
||||
ProcessEDSector(§ors[i], sectorrecord[i]);
|
||||
ProcessEDSector(&level.sectors[i], sectorrecord[i]);
|
||||
}
|
||||
}
|
||||
delete[] sectorrecord;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "g_level.h"
|
||||
#include "r_renderer.h"
|
||||
#include "d_player.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -191,7 +192,7 @@ void FS_EmulateCmd(char * string)
|
|||
else if (sc.Compare("gr_fogcolor"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
level.fadeto = strtol(sc.String, NULL, 16);
|
||||
level.fadeto = (uint32_t)strtoull(sc.String, NULL, 16);
|
||||
}
|
||||
|
||||
else
|
||||
|
|
|
@ -69,8 +69,8 @@
|
|||
#include "p_setup.h"
|
||||
#include "p_spec.h"
|
||||
#include "r_utility.h"
|
||||
#include "a_ammo.h"
|
||||
#include "math/cmath.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
static FRandom pr_script("FScript");
|
||||
|
||||
|
@ -321,7 +321,7 @@ public:
|
|||
if (tag < 0)
|
||||
{
|
||||
searchtag = INT_MIN;
|
||||
start = tag == -32768? 0 : -tag < numsectors? -tag : -1;
|
||||
start = tag == -32768? 0 : -tag < (int)level.sectors.Size()? -tag : -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -340,7 +340,7 @@ inline int T_FindFirstSectorFromTag(int tagnum)
|
|||
// Doom index is only supported for the 4 original ammo types
|
||||
//
|
||||
//==========================================================================
|
||||
static PClassAmmo * T_GetAmmo(const svalue_t &t)
|
||||
static PClassInventory * T_GetAmmo(const svalue_t &t)
|
||||
{
|
||||
const char * p;
|
||||
|
||||
|
@ -361,7 +361,7 @@ static PClassAmmo * T_GetAmmo(const svalue_t &t)
|
|||
}
|
||||
p=DefAmmo[ammonum];
|
||||
}
|
||||
PClassAmmo * am=dyn_cast<PClassAmmo>(PClass::FindActor(p));
|
||||
PClassInventory * am=dyn_cast<PClassInventory>(PClass::FindActor(p));
|
||||
if (am == NULL)
|
||||
{
|
||||
script_error("unknown ammo type : %s", p);
|
||||
|
@ -1531,7 +1531,7 @@ void FParser::SF_StartSectorSound(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sector = §ors[i];
|
||||
sector = &level.sectors[i];
|
||||
S_Sound(sector, CHAN_BODY, T_FindSound(stringvalue(t_argv[1])), 1.0f, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
|
@ -1568,13 +1568,14 @@ void FParser::SF_FloorHeight(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
if (sectors[i].floordata) continue; // don't move floors that are active!
|
||||
auto &sec = level.sectors[i];
|
||||
if (sec.floordata) continue; // don't move floors that are active!
|
||||
|
||||
if (sectors[i].MoveFloor(
|
||||
fabs(dest - sectors[i].CenterFloor()),
|
||||
sectors[i].floorplane.PointToDist (sectors[i].centerspot, dest),
|
||||
if (sec.MoveFloor(
|
||||
fabs(dest - sec.CenterFloor()),
|
||||
sec.floorplane.PointToDist (sec.centerspot, dest),
|
||||
crush? 10:-1,
|
||||
(dest > sectors[i].CenterFloor()) ? 1 : -1,
|
||||
(dest > sec.CenterFloor()) ? 1 : -1,
|
||||
false) == EMoveResult::crushed)
|
||||
{
|
||||
returnval = 0;
|
||||
|
@ -1589,7 +1590,7 @@ void FParser::SF_FloorHeight(void)
|
|||
script_error("sector not found with tagnum %i\n", tagnum);
|
||||
return;
|
||||
}
|
||||
returnval = sectors[secnum].CenterFloor();
|
||||
returnval = level.sectors[secnum].CenterFloor();
|
||||
}
|
||||
|
||||
// return floor height
|
||||
|
@ -1622,7 +1623,7 @@ void FParser::SF_MoveFloor(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((secnum = itr.Next()) >= 0)
|
||||
{
|
||||
P_CreateFloor(§ors[secnum], DFloor::floorMoveToValue, NULL, platspeed, destheight, crush, 0, false, false);
|
||||
P_CreateFloor(&level.sectors[secnum], DFloor::floorMoveToValue, NULL, platspeed, destheight, crush, 0, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1657,13 +1658,14 @@ void FParser::SF_CeilingHeight(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
if (sectors[i].ceilingdata) continue; // don't move ceilings that are active!
|
||||
auto &sec = level.sectors[i];
|
||||
if (sec.ceilingdata) continue; // don't move ceilings that are active!
|
||||
|
||||
if (sectors[i].MoveCeiling(
|
||||
fabs(dest - sectors[i].CenterCeiling()),
|
||||
sectors[i].ceilingplane.PointToDist (sectors[i].centerspot, dest),
|
||||
if (sec.MoveCeiling(
|
||||
fabs(dest - sec.CenterCeiling()),
|
||||
sec.ceilingplane.PointToDist (sec.centerspot, dest),
|
||||
crush? 10:-1,
|
||||
(dest > sectors[i].CenterCeiling()) ? 1 : -1,
|
||||
(dest > sec.CenterCeiling()) ? 1 : -1,
|
||||
false) == EMoveResult::crushed)
|
||||
{
|
||||
returnval = 0;
|
||||
|
@ -1678,7 +1680,7 @@ void FParser::SF_CeilingHeight(void)
|
|||
script_error("sector not found with tagnum %i\n", tagnum);
|
||||
return;
|
||||
}
|
||||
returnval = sectors[secnum].CenterCeiling();
|
||||
returnval = level.sectors[secnum].CenterCeiling();
|
||||
}
|
||||
|
||||
// return ceiling height
|
||||
|
@ -1713,7 +1715,7 @@ void FParser::SF_MoveCeiling(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((secnum = itr.Next()) >= 0)
|
||||
{
|
||||
P_CreateCeiling(§ors[secnum], DCeiling::ceilMoveToValue, NULL, tagnum, platspeed, platspeed, destheight, crush, silent | 4, 0, DCeiling::ECrushMode::crushDoom);
|
||||
P_CreateCeiling(&level.sectors[secnum], DCeiling::ceilMoveToValue, NULL, tagnum, platspeed, platspeed, destheight, crush, silent | 4, 0, DCeiling::ECrushMode::crushDoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1742,7 +1744,7 @@ void FParser::SF_LightLevel(void)
|
|||
return;
|
||||
}
|
||||
|
||||
sector = §ors[secnum];
|
||||
sector = &level.sectors[secnum];
|
||||
|
||||
if(t_argc > 1) // > 1: set light level
|
||||
{
|
||||
|
@ -1752,7 +1754,7 @@ void FParser::SF_LightLevel(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sectors[i].SetLightLevel(intvalue(t_argv[1]));
|
||||
level.sectors[i].SetLightLevel(intvalue(t_argv[1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1783,7 +1785,7 @@ public:
|
|||
DLightLevel(sector_t * s,int destlevel,int speed);
|
||||
void Serialize(FSerializer &arc);
|
||||
void Tick ();
|
||||
void Destroy() { Super::Destroy(); m_Sector->lightingdata=NULL; }
|
||||
void OnDestroy() { Super::OnDestroy(); m_Sector->lightingdata = nullptr; }
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DLightLevel, false, false)
|
||||
|
@ -1870,7 +1872,7 @@ void FParser::SF_FadeLight(void)
|
|||
FSectorTagIterator it(sectag);
|
||||
while ((i = it.Next()) >= 0)
|
||||
{
|
||||
if (!sectors[i].lightingdata) new DLightLevel(§ors[i],destlevel,speed);
|
||||
if (!level.sectors[i].lightingdata) new DLightLevel(&level.sectors[i],destlevel,speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1895,7 +1897,7 @@ void FParser::SF_FloorTexture(void)
|
|||
if(secnum < 0)
|
||||
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
||||
|
||||
sector = §ors[secnum];
|
||||
sector = &level.sectors[secnum];
|
||||
|
||||
if(t_argc > 1)
|
||||
{
|
||||
|
@ -1906,7 +1908,7 @@ void FParser::SF_FloorTexture(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sectors[i].SetTexture(sector_t::floor, picnum);
|
||||
level.sectors[i].SetTexture(sector_t::floor, picnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1947,7 +1949,7 @@ void FParser::SF_SectorColormap(void)
|
|||
if(secnum < 0)
|
||||
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
||||
|
||||
sector = §ors[secnum];
|
||||
sector = &level.sectors[secnum];
|
||||
|
||||
if (t_argv[1].type==svt_string)
|
||||
{
|
||||
|
@ -1957,7 +1959,7 @@ void FParser::SF_SectorColormap(void)
|
|||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sectors[i].midmap=cm;
|
||||
sectors[i].heightsec=§ors[i];
|
||||
sectors[i].heightsec=&level.sectors[i];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -1985,7 +1987,7 @@ void FParser::SF_CeilingTexture(void)
|
|||
if(secnum < 0)
|
||||
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
||||
|
||||
sector = §ors[secnum];
|
||||
sector = &level.sectors[secnum];
|
||||
|
||||
if(t_argc > 1)
|
||||
{
|
||||
|
@ -1996,7 +1998,7 @@ void FParser::SF_CeilingTexture(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sectors[i].SetTexture(sector_t::ceiling, picnum);
|
||||
level.sectors[i].SetTexture(sector_t::ceiling, picnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2169,7 +2171,7 @@ void FParser::SF_SetLineBlocking(void)
|
|||
int i;
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
lines[i].flags = (lines[i].flags & ~(ML_BLOCKING | ML_BLOCKEVERYTHING)) | blocking;
|
||||
level.lines[i].flags = (level.lines[i].flags & ~(ML_BLOCKING | ML_BLOCKEVERYTHING)) | blocking;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2192,7 +2194,7 @@ void FParser::SF_SetLineMonsterBlocking(void)
|
|||
int i;
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
lines[i].flags = (lines[i].flags & ~ML_BLOCKMONSTERS) | blocking;
|
||||
level.lines[i].flags = (level.lines[i].flags & ~ML_BLOCKMONSTERS) | blocking;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2249,11 +2251,11 @@ void FParser::SF_SetLineTexture(void)
|
|||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
// bad sidedef, Hexen just SEGV'd here!
|
||||
if (lines[i].sidedef[side] != NULL)
|
||||
if (level.lines[i].sidedef[side] != NULL)
|
||||
{
|
||||
if (position >= 0 && position <= 2)
|
||||
{
|
||||
lines[i].sidedef[side]->SetTexture(position, texturenum);
|
||||
level.lines[i].sidedef[side]->SetTexture(position, texturenum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2268,7 +2270,7 @@ void FParser::SF_SetLineTexture(void)
|
|||
FLineIdIterator itr(tag);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
side_t *sided = lines[i].sidedef[side];
|
||||
side_t *sided = level.lines[i].sidedef[side];
|
||||
if(sided != NULL)
|
||||
{
|
||||
if(sections & 1) sided->SetTexture(side_t::top, picnum);
|
||||
|
@ -2475,14 +2477,7 @@ static void FS_TakeInventory (AActor *actor, const char * type, int amount)
|
|||
// If it's not ammo, destroy it. Ammo needs to stick around, even
|
||||
// when it's zero for the benefit of the weapons that use it and
|
||||
// to maintain the maximum ammo amounts a backpack might have given.
|
||||
if (item->GetClass()->ParentClass != RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
item->Destroy ();
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Amount = 0;
|
||||
}
|
||||
item->DepleteOrDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2569,7 +2564,7 @@ void FParser::SF_PlayerKeys(void)
|
|||
void FParser::SF_PlayerAmmo(void)
|
||||
{
|
||||
int playernum, amount;
|
||||
PClassAmmo * ammotype;
|
||||
PClassInventory * ammotype;
|
||||
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
|
@ -2605,7 +2600,7 @@ void FParser::SF_PlayerAmmo(void)
|
|||
void FParser::SF_MaxPlayerAmmo()
|
||||
{
|
||||
int playernum, amount;
|
||||
PClassAmmo * ammotype;
|
||||
PClassInventory * ammotype;
|
||||
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
|
@ -2620,34 +2615,34 @@ void FParser::SF_MaxPlayerAmmo()
|
|||
}
|
||||
else if(t_argc >= 3)
|
||||
{
|
||||
AAmmo * iammo = (AAmmo*)players[playernum].mo->FindInventory(ammotype);
|
||||
auto iammo = players[playernum].mo->FindInventory(ammotype);
|
||||
amount = intvalue(t_argv[2]);
|
||||
if(amount < 0) amount = 0;
|
||||
if (!iammo)
|
||||
{
|
||||
iammo = static_cast<AAmmo *>(Spawn (ammotype));
|
||||
players[playernum].mo->GiveAmmo(ammotype, 1);
|
||||
iammo = players[playernum].mo->FindInventory(ammotype);
|
||||
iammo->Amount = 0;
|
||||
iammo->AttachToOwner (players[playernum].mo);
|
||||
}
|
||||
iammo->MaxAmount = amount;
|
||||
|
||||
|
||||
for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->IsKindOf(RUNTIME_CLASS(ABackpackItem)))
|
||||
if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem)))
|
||||
{
|
||||
if (t_argc>=4) amount = intvalue(t_argv[3]);
|
||||
else amount*=2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iammo->BackpackMaxAmount=amount;
|
||||
iammo->IntVar("BackpackMaxAmount") = amount;
|
||||
}
|
||||
|
||||
t_return.type = svt_int;
|
||||
AInventory * iammo = players[playernum].mo->FindInventory(ammotype);
|
||||
if (iammo) t_return.value.i = iammo->MaxAmount;
|
||||
else t_return.value.i = ((AAmmo*)GetDefaultByType(ammotype))->MaxAmount;
|
||||
else t_return.value.i = ((AInventory*)GetDefaultByType(ammotype))->MaxAmount;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3361,19 +3356,19 @@ void FParser::SF_ObjState()
|
|||
void FParser::SF_LineFlag()
|
||||
{
|
||||
line_t* line;
|
||||
int linenum;
|
||||
unsigned linenum;
|
||||
int flagnum;
|
||||
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
linenum = intvalue(t_argv[0]);
|
||||
if(linenum < 0 || linenum > numlines)
|
||||
if(linenum >= level.lines.Size())
|
||||
{
|
||||
script_error("LineFlag: Invalid line number.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
line = lines + linenum;
|
||||
line = &level.lines[linenum];
|
||||
|
||||
flagnum = intvalue(t_argv[1]);
|
||||
if(flagnum < 0 || (flagnum > 8 && flagnum!=15))
|
||||
|
@ -3880,7 +3875,7 @@ void FParser::SF_SetColor(void)
|
|||
color.r=intvalue(t_argv[1]);
|
||||
color.g=intvalue(t_argv[2]);
|
||||
color.b=intvalue(t_argv[3]);
|
||||
color.a=0;
|
||||
color.a = 0;
|
||||
}
|
||||
else return;
|
||||
|
||||
|
@ -3888,7 +3883,17 @@ void FParser::SF_SetColor(void)
|
|||
FSSectorTagIterator itr(tagnum);
|
||||
while ((i = itr.Next()) >= 0)
|
||||
{
|
||||
sectors[i].ColorMap = GetSpecialLights (color, sectors[i].ColorMap->Fade, 0);
|
||||
if (!DFraggleThinker::ActiveThinker->setcolormaterial)
|
||||
level.sectors[i].ColorMap = GetSpecialLights(color, level.sectors[i].ColorMap->Fade, 0);
|
||||
else
|
||||
{
|
||||
// little hack for testing the D64 color stuff.
|
||||
for (int j = 0; j < 4; j++) level.sectors[i].SpecialColors[j] = color;
|
||||
// simulates 'nocoloredspritelighting' settings.
|
||||
int v = (color.r + color.g + color.b) / 3;
|
||||
v = (255 + v + v) / 3;
|
||||
level.sectors[i].SpecialColors[sector_t::sprites] = PalEntry(255, v, v, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3985,9 +3990,9 @@ void FParser::SF_SetLineTrigger()
|
|||
mld.special = spec;
|
||||
mld.tag = tag;
|
||||
mld.flags = 0;
|
||||
int f = lines[i].flags;
|
||||
P_TranslateLineDef(&lines[i], &mld);
|
||||
lines[i].flags = (lines[i].flags & (ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)) |
|
||||
int f = level.lines[i].flags;
|
||||
P_TranslateLineDef(&level.lines[i], &mld);
|
||||
level.lines[i].flags = (level.lines[i].flags & (ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY)) |
|
||||
(f & ~(ML_MONSTERSCANACTIVATE | ML_REPEAT_SPECIAL | ML_SPAC_MASK | ML_FIRSTSIDEONLY));
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "cmdlib.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "gi.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "xlat/xlat.h"
|
||||
|
||||
void T_Init();
|
||||
|
@ -72,15 +73,18 @@ struct FFsOptions : public FOptionalMapinfoData
|
|||
{
|
||||
identifier = "fragglescript";
|
||||
nocheckposition = false;
|
||||
setcolormaterial = false;
|
||||
}
|
||||
virtual FOptionalMapinfoData *Clone() const
|
||||
{
|
||||
FFsOptions *newopt = new FFsOptions;
|
||||
newopt->identifier = identifier;
|
||||
newopt->nocheckposition = nocheckposition;
|
||||
newopt->setcolormaterial = setcolormaterial;
|
||||
return newopt;
|
||||
}
|
||||
bool nocheckposition;
|
||||
bool setcolormaterial;
|
||||
};
|
||||
|
||||
DEFINE_MAP_OPTION(fs_nocheckposition, false)
|
||||
|
@ -98,6 +102,21 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(fs_setcolormaterial, false)
|
||||
{
|
||||
FFsOptions *opt = info->GetOptData<FFsOptions>("fragglescript");
|
||||
|
||||
if (parse.CheckAssign())
|
||||
{
|
||||
parse.sc.MustGetNumber();
|
||||
opt->setcolormaterial = !!parse.sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt->setcolormaterial = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Process the lump to strip all unneeded information from it
|
||||
|
@ -306,6 +325,7 @@ bool FScriptLoader::ParseInfo(MapData * map)
|
|||
if (opt != NULL)
|
||||
{
|
||||
DFraggleThinker::ActiveThinker->nocheckposition = opt->nocheckposition;
|
||||
DFraggleThinker::ActiveThinker->setcolormaterial = opt->setcolormaterial;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "doomerrors.h"
|
||||
#include "doomstat.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -183,7 +184,7 @@ DFsScript::~DFsScript()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::Destroy()
|
||||
void DFsScript::OnDestroy()
|
||||
{
|
||||
ClearVariables(true);
|
||||
ClearSections();
|
||||
|
@ -193,7 +194,7 @@ void DFsScript::Destroy()
|
|||
data = NULL;
|
||||
parent = NULL;
|
||||
trigger = NULL;
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -333,7 +334,7 @@ DRunningScript::DRunningScript(AActor *trigger, DFsScript *owner, int index)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DRunningScript::Destroy()
|
||||
void DRunningScript::OnDestroy()
|
||||
{
|
||||
int i;
|
||||
DFsVariable *current, *next;
|
||||
|
@ -351,7 +352,7 @@ void DRunningScript::Destroy()
|
|||
}
|
||||
variables[i] = NULL;
|
||||
}
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -420,7 +421,7 @@ DFraggleThinker::DFraggleThinker()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::Destroy()
|
||||
void DFraggleThinker::OnDestroy()
|
||||
{
|
||||
DRunningScript *p = RunningScripts;
|
||||
while (p)
|
||||
|
@ -437,7 +438,7 @@ void DFraggleThinker::Destroy()
|
|||
|
||||
SpawnedThings.Clear();
|
||||
ActiveThinker = NULL;
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -489,7 +490,7 @@ bool DFraggleThinker::wait_finished(DRunningScript *script)
|
|||
FSectorTagIterator itr(script->wait_data);
|
||||
while ((secnum = itr.Next()) >= 0)
|
||||
{
|
||||
sector_t *sec = §ors[secnum];
|
||||
sector_t *sec = &level.sectors[secnum];
|
||||
if(sec->floordata || sec->ceilingdata || sec->lightingdata)
|
||||
return false; // not finished
|
||||
}
|
||||
|
|
|
@ -347,7 +347,7 @@ public:
|
|||
|
||||
DFsScript();
|
||||
~DFsScript();
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
void Serialize(FSerializer &ar);
|
||||
|
||||
DFsVariable *NewVariable(const char *name, int vtype);
|
||||
|
@ -662,7 +662,7 @@ class DRunningScript : public DObject
|
|||
|
||||
public:
|
||||
DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
TObjPtr<DFsScript> script;
|
||||
|
@ -695,9 +695,10 @@ public:
|
|||
TObjPtr<DRunningScript> RunningScripts;
|
||||
TArray<TObjPtr<AActor> > SpawnedThings;
|
||||
bool nocheckposition;
|
||||
bool setcolormaterial;
|
||||
|
||||
DFraggleThinker();
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
|
||||
void Serialize(FSerializer & arc);
|
||||
|
|
305
src/g_game.cpp
305
src/g_game.cpp
|
@ -72,7 +72,6 @@
|
|||
#include "m_png.h"
|
||||
#include "gi.h"
|
||||
#include "a_keys.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "cmdlib.h"
|
||||
#include "d_net.h"
|
||||
|
@ -92,6 +91,7 @@
|
|||
#include <zlib.h>
|
||||
|
||||
#include "g_hub.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
static FRandom pr_dmspawn ("DMSpawn");
|
||||
|
@ -448,7 +448,7 @@ CCMD (use)
|
|||
{
|
||||
if (argv.argc() > 1 && who != NULL)
|
||||
{
|
||||
SendItemUse = who->FindInventory(PClass::FindActor(argv[1]));
|
||||
SendItemUse = who->FindInventory(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,7 +469,7 @@ CCMD (drop)
|
|||
{
|
||||
if (argv.argc() > 1 && who != NULL)
|
||||
{
|
||||
SendItemDrop = who->FindInventory(PClass::FindActor(argv[1]));
|
||||
SendItemDrop = who->FindInventory(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,7 +514,7 @@ CCMD (select)
|
|||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
AInventory *item = who->FindInventory(PClass::FindActor(argv[1]));
|
||||
AInventory *item = who->FindInventory(argv[1]);
|
||||
if (item != NULL)
|
||||
{
|
||||
who->InvSel = item;
|
||||
|
@ -1263,10 +1263,11 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags)
|
|||
|
||||
// Strip all current powers, unless moving in a hub and the power is okay to keep.
|
||||
item = p->mo->Inventory;
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
next = item->Inventory;
|
||||
if (item->IsKindOf (RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf (ptype))
|
||||
{
|
||||
if (deathmatch || ((mode != FINISH_SameHub || !(item->ItemFlags & IF_HUBPOWER))
|
||||
&& !(item->ItemFlags & IF_PERSISTENTPOWER))) // Keep persistent powers in non-deathmatch games
|
||||
|
@ -1891,168 +1892,150 @@ void G_DoLoadGame ()
|
|||
hidecon = gameaction == ga_loadgamehidecon;
|
||||
gameaction = ga_nothing;
|
||||
|
||||
FResourceFile *resfile = FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true);
|
||||
std::unique_ptr<FResourceFile> resfile(FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true));
|
||||
if (resfile == nullptr)
|
||||
{
|
||||
Printf ("Could not read savegame '%s'\n", savename.GetChars());
|
||||
return;
|
||||
}
|
||||
try
|
||||
FResourceLump *info = resfile->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
FResourceLump *info = resfile->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
delete resfile;
|
||||
Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars());
|
||||
return;
|
||||
}
|
||||
|
||||
SaveVersion = 0;
|
||||
|
||||
void *data = info->CacheLump();
|
||||
FSerializer arc;
|
||||
if (!arc.OpenReader((const char *)data, info->LumpSize))
|
||||
{
|
||||
Printf("Failed to access savegame info\n");
|
||||
delete resfile;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether this savegame actually has been created by a compatible engine.
|
||||
// Since there are ZDoom derivates using the exact same savegame format but
|
||||
// with mutual incompatibilities this check simplifies things significantly.
|
||||
FString savever, engine, map;
|
||||
arc("Save Version", SaveVersion);
|
||||
arc("Engine", engine);
|
||||
arc("Current Map", map);
|
||||
|
||||
if (engine.CompareNoCase(GAMESIG) != 0)
|
||||
{
|
||||
// Make a special case for the message printed for old savegames that don't
|
||||
// have this information.
|
||||
if (engine.IsEmpty())
|
||||
{
|
||||
Printf("Savegame is from an incompatible version\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars());
|
||||
}
|
||||
delete resfile;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER)
|
||||
{
|
||||
delete resfile;
|
||||
Printf("Savegame is from an incompatible version");
|
||||
if (SaveVersion < MINSAVEVER)
|
||||
{
|
||||
Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER);
|
||||
}
|
||||
Printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!G_CheckSaveGameWads(arc, true))
|
||||
{
|
||||
delete resfile;
|
||||
return;
|
||||
}
|
||||
|
||||
if (map.IsEmpty())
|
||||
{
|
||||
Printf("Savegame is missing the current map\n");
|
||||
delete resfile;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that it looks like we can load this save, hide the fullscreen console if it was up
|
||||
// when the game was selected from the menu.
|
||||
if (hidecon && gamestate == GS_FULLCONSOLE)
|
||||
{
|
||||
gamestate = GS_HIDECONSOLE;
|
||||
}
|
||||
// we are done with info.json.
|
||||
arc.Close();
|
||||
|
||||
info = resfile->FindLump("globals.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
delete resfile;
|
||||
Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars());
|
||||
return;
|
||||
}
|
||||
|
||||
data = info->CacheLump();
|
||||
if (!arc.OpenReader((const char *)data, info->LumpSize))
|
||||
{
|
||||
Printf("Failed to access savegame info\n");
|
||||
delete resfile;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Read intermission data for hubs
|
||||
G_SerializeHub(arc);
|
||||
|
||||
bglobal.RemoveAllBots(true);
|
||||
|
||||
FString cvar;
|
||||
arc("importantcvars", cvar);
|
||||
if (!cvar.IsEmpty())
|
||||
{
|
||||
BYTE *vars_p = (BYTE *)cvar.GetChars();
|
||||
C_ReadCVars(&vars_p);
|
||||
}
|
||||
|
||||
DWORD time[2] = { 1,0 };
|
||||
|
||||
arc("ticrate", time[0])
|
||||
("leveltime", time[1]);
|
||||
// dearchive all the modifications
|
||||
level.time = Scale(time[1], TICRATE, time[0]);
|
||||
|
||||
G_ReadSnapshots(resfile);
|
||||
delete resfile; // we no longer need the resource file below this point
|
||||
resfile = nullptr;
|
||||
G_ReadVisited(arc);
|
||||
|
||||
// load a base level
|
||||
savegamerestore = true; // Use the player actors in the savegame
|
||||
bool demoplaybacksave = demoplayback;
|
||||
G_InitNew(map, false);
|
||||
demoplayback = demoplaybacksave;
|
||||
savegamerestore = false;
|
||||
|
||||
STAT_Serialize(arc);
|
||||
FRandom::StaticReadRNGState(arc);
|
||||
P_ReadACSDefereds(arc);
|
||||
P_ReadACSVars(arc);
|
||||
|
||||
NextSkill = -1;
|
||||
arc("nextskill", NextSkill);
|
||||
|
||||
if (level.info != nullptr)
|
||||
level.info->Snapshot.Clean();
|
||||
|
||||
BackupSaveName = savename;
|
||||
|
||||
// At this point, the GC threshold is likely a lot higher than the
|
||||
// amount of memory in use, so bring it down now by starting a
|
||||
// collection.
|
||||
GC::StartCollection();
|
||||
Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars());
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
|
||||
SaveVersion = 0;
|
||||
|
||||
void *data = info->CacheLump();
|
||||
FSerializer arc;
|
||||
if (!arc.OpenReader((const char *)data, info->LumpSize))
|
||||
{
|
||||
// delete the resource file if anything goes wrong in here.
|
||||
if (resfile != nullptr) delete resfile;
|
||||
throw;
|
||||
Printf("Failed to access savegame info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether this savegame actually has been created by a compatible engine.
|
||||
// Since there are ZDoom derivates using the exact same savegame format but
|
||||
// with mutual incompatibilities this check simplifies things significantly.
|
||||
FString savever, engine, map;
|
||||
arc("Save Version", SaveVersion);
|
||||
arc("Engine", engine);
|
||||
arc("Current Map", map);
|
||||
|
||||
if (engine.CompareNoCase(GAMESIG) != 0)
|
||||
{
|
||||
// Make a special case for the message printed for old savegames that don't
|
||||
// have this information.
|
||||
if (engine.IsEmpty())
|
||||
{
|
||||
Printf("Savegame is from an incompatible version\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER)
|
||||
{
|
||||
Printf("Savegame is from an incompatible version");
|
||||
if (SaveVersion < MINSAVEVER)
|
||||
{
|
||||
Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER);
|
||||
}
|
||||
Printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!G_CheckSaveGameWads(arc, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (map.IsEmpty())
|
||||
{
|
||||
Printf("Savegame is missing the current map\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that it looks like we can load this save, hide the fullscreen console if it was up
|
||||
// when the game was selected from the menu.
|
||||
if (hidecon && gamestate == GS_FULLCONSOLE)
|
||||
{
|
||||
gamestate = GS_HIDECONSOLE;
|
||||
}
|
||||
// we are done with info.json.
|
||||
arc.Close();
|
||||
|
||||
info = resfile->FindLump("globals.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars());
|
||||
return;
|
||||
}
|
||||
|
||||
data = info->CacheLump();
|
||||
if (!arc.OpenReader((const char *)data, info->LumpSize))
|
||||
{
|
||||
Printf("Failed to access savegame info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Read intermission data for hubs
|
||||
G_SerializeHub(arc);
|
||||
|
||||
bglobal.RemoveAllBots(true);
|
||||
|
||||
FString cvar;
|
||||
arc("importantcvars", cvar);
|
||||
if (!cvar.IsEmpty())
|
||||
{
|
||||
BYTE *vars_p = (BYTE *)cvar.GetChars();
|
||||
C_ReadCVars(&vars_p);
|
||||
}
|
||||
|
||||
DWORD time[2] = { 1,0 };
|
||||
|
||||
arc("ticrate", time[0])
|
||||
("leveltime", time[1]);
|
||||
// dearchive all the modifications
|
||||
level.time = Scale(time[1], TICRATE, time[0]);
|
||||
|
||||
G_ReadSnapshots(resfile.get());
|
||||
resfile.reset(nullptr); // we no longer need the resource file below this point
|
||||
G_ReadVisited(arc);
|
||||
|
||||
// load a base level
|
||||
savegamerestore = true; // Use the player actors in the savegame
|
||||
bool demoplaybacksave = demoplayback;
|
||||
G_InitNew(map, false);
|
||||
demoplayback = demoplaybacksave;
|
||||
savegamerestore = false;
|
||||
|
||||
STAT_Serialize(arc);
|
||||
FRandom::StaticReadRNGState(arc);
|
||||
P_ReadACSDefereds(arc);
|
||||
P_ReadACSVars(arc);
|
||||
|
||||
NextSkill = -1;
|
||||
arc("nextskill", NextSkill);
|
||||
|
||||
if (level.info != nullptr)
|
||||
level.info->Snapshot.Clean();
|
||||
|
||||
BackupSaveName = savename;
|
||||
|
||||
// At this point, the GC threshold is likely a lot higher than the
|
||||
// amount of memory in use, so bring it down now by starting a
|
||||
// collection.
|
||||
GC::StartCollection();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2128,8 +2111,6 @@ CUSTOM_CVAR (Int, autosavecount, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
if (self > 20)
|
||||
self = 20;
|
||||
}
|
||||
|
||||
extern void P_CalcHeight (player_t *);
|
||||
|
@ -2242,7 +2223,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
|
||||
// Do not even try, if we're not in a level. (Can happen after
|
||||
// a demo finishes playback.)
|
||||
if (lines == NULL || sectors == NULL || gamestate != GS_LEVEL)
|
||||
if (level.lines.Size() == 0 || level.sectors.Size() == 0 || gamestate != GS_LEVEL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -2802,7 +2783,7 @@ void G_DoPlayDemo (void)
|
|||
{
|
||||
G_InitNew (mapname, false);
|
||||
}
|
||||
else if (numsectors == 0)
|
||||
else if (level.sectors.Size() == 0)
|
||||
{
|
||||
I_Error("Cannot play demo without its savegame\n");
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "gstrings.h"
|
||||
#include "wi_stuff.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
** a_ammo.cpp
|
||||
** Implements ammo and backpack items.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "c_dispatch.h"
|
||||
#include "d_player.h"
|
||||
#include "serializer.h"
|
||||
|
||||
IMPLEMENT_CLASS(PClassAmmo, false, false)
|
||||
|
||||
PClassAmmo::PClassAmmo()
|
||||
{
|
||||
DropAmount = 0;
|
||||
}
|
||||
|
||||
void PClassAmmo::DeriveData(PClass *newclass)
|
||||
{
|
||||
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo)));
|
||||
Super::DeriveData(newclass);
|
||||
PClassAmmo *newc = static_cast<PClassAmmo *>(newclass);
|
||||
|
||||
newc->DropAmount = DropAmount;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(AAmmo, false, false)
|
||||
|
||||
DEFINE_FIELD(AAmmo, BackpackAmount)
|
||||
DEFINE_FIELD(AAmmo, BackpackMaxAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AAmmo::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AAmmo*)GetDefault();
|
||||
arc("backpackamount", BackpackAmount, def->BackpackAmount)
|
||||
("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: GetParentAmmo
|
||||
//
|
||||
// Returns the least-derived ammo type that this ammo is a descendant of.
|
||||
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
|
||||
// type is returned. If this ammo's superclass is not Ammo, then this
|
||||
// function travels up the inheritance chain until it finds a type that is
|
||||
// an immediate subclass of Ammo and returns that.
|
||||
//
|
||||
// The intent of this is that all unique ammo types will be immediate
|
||||
// subclasses of Ammo. To make different pickups with different ammo amounts,
|
||||
// you subclass the type of ammo you want a different amount for and edit
|
||||
// that.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
PClassActor *AAmmo::GetParentAmmo () const
|
||||
{
|
||||
PClass *type = GetClass();
|
||||
|
||||
while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL)
|
||||
{
|
||||
type = type->ParentClass;
|
||||
}
|
||||
return static_cast<PClassActor *>(type);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
EXTERN_CVAR(Bool, sv_unlimited_pickup)
|
||||
|
||||
bool AAmmo::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (GetClass() == item->GetClass() ||
|
||||
(item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast<AAmmo*>(item)->GetParentAmmo() == GetClass()))
|
||||
{
|
||||
if (Amount < MaxAmount || sv_unlimited_pickup)
|
||||
{
|
||||
int receiving = item->Amount;
|
||||
|
||||
if (!(item->ItemFlags & IF_IGNORESKILL))
|
||||
{ // extra ammo in baby mode and nightmare mode
|
||||
receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
int oldamount = Amount;
|
||||
|
||||
if (Amount > 0 && Amount + receiving < 0)
|
||||
{
|
||||
Amount = 0x7fffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
Amount += receiving;
|
||||
}
|
||||
if (Amount > MaxAmount && !sv_unlimited_pickup)
|
||||
{
|
||||
Amount = MaxAmount;
|
||||
}
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
|
||||
// If the player previously had this ammo but ran out, possibly switch
|
||||
// to a weapon that uses it, but only if the player doesn't already
|
||||
// have a weapon pending.
|
||||
|
||||
assert (Owner != NULL);
|
||||
|
||||
if (oldamount == 0 && Owner != NULL && Owner->player != NULL)
|
||||
{
|
||||
barrier_cast<APlayerPawn *>(Owner)->CheckWeaponSwitch(GetClass());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AAmmo::CreateCopy (AActor *other)
|
||||
{
|
||||
AInventory *copy;
|
||||
int amount = Amount;
|
||||
|
||||
// extra ammo in baby mode and nightmare mode
|
||||
if (!(ItemFlags&IF_IGNORESKILL))
|
||||
{
|
||||
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
|
||||
if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
PClassActor *type = GetParentAmmo();
|
||||
if (!GoAway ())
|
||||
{
|
||||
Destroy ();
|
||||
}
|
||||
|
||||
copy = static_cast<AInventory *>(Spawn (type));
|
||||
copy->Amount = amount;
|
||||
copy->BecomeItem ();
|
||||
}
|
||||
else
|
||||
{
|
||||
copy = Super::CreateCopy (other);
|
||||
copy->Amount = amount;
|
||||
}
|
||||
if (copy->Amount > copy->MaxAmount)
|
||||
{ // Don't pick up more ammo than you're supposed to be able to carry.
|
||||
copy->Amount = copy->MaxAmount;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AAmmo :: CreateTossable
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AAmmo::CreateTossable()
|
||||
{
|
||||
AInventory *copy = Super::CreateTossable();
|
||||
if (copy != NULL)
|
||||
{ // Do not increase ammo by dropping it and picking it back up at
|
||||
// certain skill levels.
|
||||
copy->ItemFlags |= IF_IGNORESKILL;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
// Backpack -----------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(ABackpackItem, false, false)
|
||||
|
||||
DEFINE_FIELD(ABackpackItem, bDepleted)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABackpackItem :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABackpackItem::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (ABackpackItem*)GetDefault();
|
||||
arc("bdepleted", bDepleted, def->bDepleted);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABackpackItem :: CreateCopy
|
||||
//
|
||||
// A backpack is being added to a player who doesn't yet have one. Give them
|
||||
// every kind of ammo, and increase their max amounts.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABackpackItem::CreateCopy (AActor *other)
|
||||
{
|
||||
// Find every unique type of ammo. Give it to the player if
|
||||
// he doesn't have it already, and double its maximum capacity.
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
PClass *type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->ParentClass == RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
PClassActor *atype = static_cast<PClassActor *>(type);
|
||||
AAmmo *ammo = static_cast<AAmmo *>(other->FindInventory(atype));
|
||||
int amount = static_cast<AAmmo *>(GetDefaultByType(type))->BackpackAmount;
|
||||
// extra ammo in baby mode and nightmare mode
|
||||
if (!(ItemFlags&IF_IGNORESKILL))
|
||||
{
|
||||
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
if (amount < 0) amount = 0;
|
||||
if (ammo == NULL)
|
||||
{ // The player did not have the ammo. Add it.
|
||||
ammo = static_cast<AAmmo *>(Spawn(atype));
|
||||
ammo->Amount = bDepleted ? 0 : amount;
|
||||
if (ammo->BackpackMaxAmount > ammo->MaxAmount)
|
||||
{
|
||||
ammo->MaxAmount = ammo->BackpackMaxAmount;
|
||||
}
|
||||
if (ammo->Amount > ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
ammo->AttachToOwner (other);
|
||||
}
|
||||
else
|
||||
{ // The player had the ammo. Give some more.
|
||||
if (ammo->MaxAmount < ammo->BackpackMaxAmount)
|
||||
{
|
||||
ammo->MaxAmount = ammo->BackpackMaxAmount;
|
||||
}
|
||||
if (!bDepleted && ammo->Amount < ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount += amount;
|
||||
if (ammo->Amount > ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Super::CreateCopy (other);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABackpackItem :: HandlePickup
|
||||
//
|
||||
// When the player picks up another backpack, just give them more ammo.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABackpackItem::HandlePickup (AInventory *item)
|
||||
{
|
||||
// Since you already have a backpack, that means you already have every
|
||||
// kind of ammo in your inventory, so we don't need to look at the
|
||||
// entire PClass list to discover what kinds of ammo exist, and we don't
|
||||
// have to alter the MaxAmount either.
|
||||
if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem)))
|
||||
{
|
||||
for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory)
|
||||
{
|
||||
if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup)
|
||||
{
|
||||
int amount = static_cast<AAmmo*>(probe->GetDefault())->BackpackAmount;
|
||||
// extra ammo in baby mode and nightmare mode
|
||||
if (!(item->ItemFlags&IF_IGNORESKILL))
|
||||
{
|
||||
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
probe->Amount += amount;
|
||||
if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup)
|
||||
{
|
||||
probe->Amount = probe->MaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The pickup always succeeds, even if you didn't get anything
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABackpackItem :: CreateTossable
|
||||
//
|
||||
// The tossed backpack must not give out any more ammo, otherwise a player
|
||||
// could cheat by dropping their backpack and picking it up for more ammo.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABackpackItem::CreateTossable ()
|
||||
{
|
||||
ABackpackItem *pack = static_cast<ABackpackItem *>(Super::CreateTossable());
|
||||
if (pack != NULL)
|
||||
{
|
||||
pack->bDepleted = true;
|
||||
}
|
||||
return pack;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABackpackItem :: DetachFromOwner
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABackpackItem::DetachFromOwner ()
|
||||
{
|
||||
// When removing a backpack, drop the player's ammo maximums to normal
|
||||
AInventory *item;
|
||||
|
||||
for (item = Owner->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) &&
|
||||
item->MaxAmount == static_cast<AAmmo*>(item)->BackpackMaxAmount)
|
||||
{
|
||||
item->MaxAmount = static_cast<AInventory*>(item->GetDefault())->MaxAmount;
|
||||
if (item->Amount > item->MaxAmount)
|
||||
{
|
||||
item->Amount = item->MaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
#include "a_pickups.h"
|
||||
|
||||
// Ammo: Something a weapon needs to operate
|
||||
class PClassAmmo : public PClassInventory
|
||||
{
|
||||
DECLARE_CLASS(PClassAmmo, PClassInventory)
|
||||
protected:
|
||||
virtual void DeriveData(PClass *newclass);
|
||||
public:
|
||||
PClassAmmo();
|
||||
|
||||
int DropAmount; // Specifies the amount for a dropped ammo item.
|
||||
};
|
||||
|
||||
class AAmmo : public AInventory
|
||||
{
|
||||
DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
PClassActor *GetParentAmmo () const;
|
||||
|
||||
int BackpackAmount, BackpackMaxAmount;
|
||||
};
|
||||
|
||||
|
||||
// A backpack gives you one clip of each ammo and doubles your
|
||||
// normal maximum ammo amounts.
|
||||
class ABackpackItem : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (ABackpackItem, AInventory)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
virtual void DetachFromOwner () override;
|
||||
|
||||
bool bDepleted;
|
||||
};
|
||||
|
||||
|
|
@ -1,650 +0,0 @@
|
|||
/*
|
||||
** a_armor.cpp
|
||||
** Implements all variations of armor objects
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "info.h"
|
||||
#include "gi.h"
|
||||
#include "a_pickups.h"
|
||||
#include "a_armor.h"
|
||||
#include "templates.h"
|
||||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "serializer.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
IMPLEMENT_CLASS(AArmor, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmor, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
|
||||
IMPLEMENT_CLASS(ABasicArmorBonus, false, false)
|
||||
IMPLEMENT_CLASS(AHexenArmor, false, false)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmor
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_FIELD(ABasicArmor, AbsorbCount)
|
||||
DEFINE_FIELD(ABasicArmor, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmor, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmor, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmor, BonusCount)
|
||||
DEFINE_FIELD(ABasicArmor, ArmorType)
|
||||
DEFINE_FIELD(ABasicArmor, ActualSaveAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (ABasicArmor *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("bonuscount", BonusCount, def->BonusCount)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb)
|
||||
("absorbcount", AbsorbCount, def->AbsorbCount)
|
||||
("armortype", ArmorType, def->ArmorType)
|
||||
("actualsaveamount", ActualSaveAmount, def->ActualSaveAmount);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: Tick
|
||||
//
|
||||
// If BasicArmor is given to the player by means other than a
|
||||
// BasicArmorPickup, then it may not have an icon set. Fix that here.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::Tick ()
|
||||
{
|
||||
Super::Tick ();
|
||||
AbsorbCount = 0;
|
||||
if (!Icon.isValid())
|
||||
{
|
||||
FString icon = gameinfo.ArmorIcon1;
|
||||
|
||||
if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Len() != 0)
|
||||
icon = gameinfo.ArmorIcon2;
|
||||
|
||||
if (icon[0] != 0)
|
||||
Icon = TexMan.CheckForTexture (icon, FTexture::TEX_Any);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmor::CreateCopy (AActor *other)
|
||||
{
|
||||
// BasicArmor that is in use is stored in the inventory as BasicArmor.
|
||||
// BasicArmor that is in reserve is not.
|
||||
ABasicArmor *copy = Spawn<ABasicArmor> ();
|
||||
copy->SavePercent = SavePercent != 0 ? SavePercent : 0.33335; // slightly more than 1/3 to avoid roundoff errors.
|
||||
copy->Amount = Amount;
|
||||
copy->MaxAmount = MaxAmount;
|
||||
copy->Icon = Icon;
|
||||
copy->BonusCount = BonusCount;
|
||||
copy->ArmorType = ArmorType;
|
||||
copy->ActualSaveAmount = ActualSaveAmount;
|
||||
GoAwayAndDie ();
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmor::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (item->GetClass() == RUNTIME_CLASS(ABasicArmor))
|
||||
{
|
||||
// You shouldn't be picking up BasicArmor anyway.
|
||||
return true;
|
||||
}
|
||||
if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorBonus)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorBonus *armor = static_cast<ABasicArmorBonus*>(item);
|
||||
|
||||
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorPickup)) && !(item->ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
ABasicArmorPickup *armor = static_cast<ABasicArmorPickup*>(item);
|
||||
|
||||
armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmor :: AbsorbDamage
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
||||
{
|
||||
int saved;
|
||||
|
||||
if (!DamageTypeDefinition::IgnoreArmor(damageType))
|
||||
{
|
||||
int full = MAX(0, MaxFullAbsorb - AbsorbCount);
|
||||
if (damage < full)
|
||||
{
|
||||
saved = damage;
|
||||
}
|
||||
else
|
||||
{
|
||||
saved = full + int((damage - full) * SavePercent);
|
||||
if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb)
|
||||
{
|
||||
saved = MAX(0, MaxAbsorb - AbsorbCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (Amount < saved)
|
||||
{
|
||||
saved = Amount;
|
||||
}
|
||||
newdamage -= saved;
|
||||
Amount -= saved;
|
||||
AbsorbCount += saved;
|
||||
if (Amount == 0)
|
||||
{
|
||||
// The armor has become useless
|
||||
SavePercent = 0;
|
||||
ArmorType = NAME_None; // Not NAME_BasicArmor.
|
||||
// Now see if the player has some more armor in their inventory
|
||||
// and use it if so. As in Strife, the best armor is used up first.
|
||||
ABasicArmorPickup *best = NULL;
|
||||
AInventory *probe = Owner->Inventory;
|
||||
while (probe != NULL)
|
||||
{
|
||||
if (probe->IsKindOf (RUNTIME_CLASS(ABasicArmorPickup)))
|
||||
{
|
||||
ABasicArmorPickup *inInv = static_cast<ABasicArmorPickup*>(probe);
|
||||
if (best == NULL || best->SavePercent < inInv->SavePercent)
|
||||
{
|
||||
best = inInv;
|
||||
}
|
||||
}
|
||||
probe = probe->Inventory;
|
||||
}
|
||||
if (best != NULL)
|
||||
{
|
||||
Owner->UseInventory (best);
|
||||
}
|
||||
}
|
||||
damage = newdamage;
|
||||
}
|
||||
|
||||
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
|
||||
if ((damage > 0) && (ArmorType != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
|
||||
{
|
||||
// This code is taken and adapted from APowerProtection::ModifyDamage().
|
||||
// The differences include not using a default value, and of course the way
|
||||
// the damage factor info is obtained.
|
||||
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
|
||||
if (df != NULL)
|
||||
{
|
||||
damage = newdamage = df->Apply(damageType, damage);
|
||||
}
|
||||
}
|
||||
if (Inventory != NULL)
|
||||
{
|
||||
Inventory->AbsorbDamage (damage, damageType, newdamage);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmorPickup
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
DEFINE_FIELD(ABasicArmorPickup, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorPickup, SaveAmount)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmorPickup::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
|
||||
auto def = (ABasicArmorPickup *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("saveamount", SaveAmount, def->SaveAmount)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorPickup :: Use
|
||||
//
|
||||
// Either gives you new armor or replaces the armor you already have (if
|
||||
// the SaveAmount is greater than the amount of armor you own). When the
|
||||
// item is auto-activated, it will only be activated if its max amount is 0
|
||||
// or if you have no armor active already.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmorPickup::Use (bool pickup)
|
||||
{
|
||||
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
|
||||
|
||||
if (armor == NULL)
|
||||
{
|
||||
armor = Spawn<ABasicArmor> ();
|
||||
armor->BecomeItem ();
|
||||
Owner->AddInventory (armor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If you already have more armor than this item gives you, you can't
|
||||
// use it.
|
||||
if (armor->Amount >= SaveAmount + armor->BonusCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Don't use it if you're picking it up and already have some.
|
||||
if (pickup && armor->Amount > 0 && MaxAmount > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
armor->SavePercent = SavePercent;
|
||||
armor->Amount = SaveAmount + armor->BonusCount;
|
||||
armor->MaxAmount = SaveAmount;
|
||||
armor->Icon = Icon;
|
||||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->ActualSaveAmount = SaveAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// BasicArmorBonus
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
DEFINE_FIELD(ABasicArmorBonus, SavePercent)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorBonus, MaxFullAbsorb)
|
||||
DEFINE_FIELD(ABasicArmorBonus, SaveAmount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, BonusCount)
|
||||
DEFINE_FIELD(ABasicArmorBonus, BonusMax)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void ABasicArmorBonus::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (ABasicArmorBonus *)GetDefault();
|
||||
arc("savepercent", SavePercent, def->SavePercent)
|
||||
("saveamount", SaveAmount, def->SaveAmount)
|
||||
("maxsaveamount", MaxSaveAmount, def->MaxSaveAmount)
|
||||
("bonuscount", BonusCount, def->BonusCount)
|
||||
("bonusmax", BonusMax, def->BonusMax)
|
||||
("maxabsorb", MaxAbsorb, def->MaxAbsorb)
|
||||
("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *ABasicArmorBonus::CreateCopy (AActor *other)
|
||||
{
|
||||
ABasicArmorBonus *copy = static_cast<ABasicArmorBonus *> (Super::CreateCopy (other));
|
||||
|
||||
if (!(ItemFlags & IF_IGNORESKILL))
|
||||
{
|
||||
SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
|
||||
}
|
||||
|
||||
copy->SavePercent = SavePercent;
|
||||
copy->SaveAmount = SaveAmount;
|
||||
copy->MaxSaveAmount = MaxSaveAmount;
|
||||
copy->BonusCount = BonusCount;
|
||||
copy->BonusMax = BonusMax;
|
||||
copy->MaxAbsorb = MaxAbsorb;
|
||||
copy->MaxFullAbsorb = MaxFullAbsorb;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ABasicArmorBonus :: Use
|
||||
//
|
||||
// Tries to add to the amount of BasicArmor a player has.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool ABasicArmorBonus::Use (bool pickup)
|
||||
{
|
||||
ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
|
||||
bool result = false;
|
||||
|
||||
if (armor == NULL)
|
||||
{
|
||||
armor = Spawn<ABasicArmor> ();
|
||||
armor->BecomeItem ();
|
||||
armor->Amount = 0;
|
||||
armor->MaxAmount = MaxSaveAmount;
|
||||
Owner->AddInventory (armor);
|
||||
}
|
||||
|
||||
if (BonusCount > 0 && armor->BonusCount < BonusMax)
|
||||
{
|
||||
armor->BonusCount = MIN (armor->BonusCount + BonusCount, BonusMax);
|
||||
result = true;
|
||||
}
|
||||
|
||||
int saveAmount = MIN (SaveAmount, MaxSaveAmount);
|
||||
|
||||
if (saveAmount <= 0)
|
||||
{ // If it can't give you anything, it's as good as used.
|
||||
return BonusCount > 0 ? result : true;
|
||||
}
|
||||
|
||||
// If you already have more armor than this item can give you, you can't
|
||||
// use it.
|
||||
if (armor->Amount >= MaxSaveAmount + armor->BonusCount)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (armor->Amount <= 0)
|
||||
{ // Should never be less than 0, but might as well check anyway
|
||||
armor->Amount = 0;
|
||||
armor->Icon = Icon;
|
||||
armor->SavePercent = SavePercent;
|
||||
armor->MaxAbsorb = MaxAbsorb;
|
||||
armor->ArmorType = this->GetClass()->TypeName;
|
||||
armor->MaxFullAbsorb = MaxFullAbsorb;
|
||||
armor->ActualSaveAmount = MaxSaveAmount;
|
||||
}
|
||||
|
||||
armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
|
||||
armor->MaxAmount = MAX (armor->MaxAmount, MaxSaveAmount);
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
// HexenArmor
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_FIELD(AHexenArmor, Slots)
|
||||
DEFINE_FIELD(AHexenArmor, SlotsIncrement)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AHexenArmor *)GetDefault();
|
||||
arc.Array("slots", Slots, def->Slots, 5, true)
|
||||
.Array("slotsincrement", SlotsIncrement, def->SlotsIncrement, 4);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHexenArmor::CreateCopy (AActor *other)
|
||||
{
|
||||
// Like BasicArmor, HexenArmor is used in the inventory but not the map.
|
||||
// health is the slot this armor occupies.
|
||||
// Amount is the quantity to give (0 = normal max).
|
||||
AHexenArmor *copy = Spawn<AHexenArmor> ();
|
||||
copy->AddArmorToSlot (other, health, Amount);
|
||||
GoAwayAndDie ();
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: CreateTossable
|
||||
//
|
||||
// Since this isn't really a single item, you can't drop it. Ever.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHexenArmor::CreateTossable ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHexenArmor::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AHexenArmor)))
|
||||
{
|
||||
if (AddArmorToSlot (Owner, item->health, item->Amount))
|
||||
{
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: AddArmorToSlot
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
|
||||
{
|
||||
APlayerPawn *ppawn;
|
||||
double hits;
|
||||
|
||||
if (actor->player != NULL)
|
||||
{
|
||||
ppawn = static_cast<APlayerPawn *>(actor);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppawn = NULL;
|
||||
}
|
||||
|
||||
if (slot < 0 || slot > 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (amount <= 0)
|
||||
{
|
||||
hits = SlotsIncrement[slot];
|
||||
if (Slots[slot] < hits)
|
||||
{
|
||||
Slots[slot] = hits;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hits = amount * 5;
|
||||
auto total = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
auto max = SlotsIncrement[0] + SlotsIncrement[1] + SlotsIncrement[2] + SlotsIncrement[3] + Slots[4] + 4 * 5;
|
||||
if (total < max)
|
||||
{
|
||||
Slots[slot] += hits;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: AbsorbDamage
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
||||
{
|
||||
if (!DamageTypeDefinition::IgnoreArmor(damageType))
|
||||
{
|
||||
double savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
|
||||
if (savedPercent)
|
||||
{ // armor absorbed some damage
|
||||
if (savedPercent > 100)
|
||||
{
|
||||
savedPercent = 100;
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (Slots[i])
|
||||
{
|
||||
// 300 damage always wipes out the armor unless some was added
|
||||
// with the dragon skin bracers.
|
||||
if (damage < 10000)
|
||||
{
|
||||
Slots[i] -= damage * SlotsIncrement[i] / 300.;
|
||||
if (Slots[i] < 2)
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
int saved = int(damage * savedPercent / 100.);
|
||||
if (saved > savedPercent*2)
|
||||
{
|
||||
saved = int(savedPercent*2);
|
||||
}
|
||||
newdamage -= saved;
|
||||
damage = newdamage;
|
||||
}
|
||||
}
|
||||
if (Inventory != NULL)
|
||||
{
|
||||
Inventory->AbsorbDamage (damage, damageType, newdamage);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHexenArmor :: DepleteOrDestroy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHexenArmor::DepleteOrDestroy()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Slots[i] = 0;
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "a_pickups.h"
|
||||
|
||||
// Armor absorbs some damage for the player.
|
||||
class AArmor : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (AArmor, AInventory)
|
||||
};
|
||||
|
||||
// Basic armor absorbs a specific percent of the damage. You should
|
||||
// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup
|
||||
// or BasicArmorBonus and those gives you BasicArmor when it activates.
|
||||
class ABasicArmor : public AArmor
|
||||
{
|
||||
DECLARE_CLASS (ABasicArmor, AArmor)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual void Tick () override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
|
||||
|
||||
int AbsorbCount;
|
||||
double SavePercent;
|
||||
int MaxAbsorb;
|
||||
int MaxFullAbsorb;
|
||||
int BonusCount;
|
||||
FNameNoInit ArmorType;
|
||||
int ActualSaveAmount;
|
||||
};
|
||||
|
||||
// BasicArmorPickup replaces the armor you have.
|
||||
class ABasicArmorPickup : public AArmor
|
||||
{
|
||||
DECLARE_CLASS (ABasicArmorPickup, AArmor)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
|
||||
double SavePercent;
|
||||
int MaxAbsorb;
|
||||
int MaxFullAbsorb;
|
||||
int SaveAmount;
|
||||
};
|
||||
|
||||
// BasicArmorBonus adds to the armor you have.
|
||||
class ABasicArmorBonus : public AArmor
|
||||
{
|
||||
DECLARE_CLASS (ABasicArmorBonus, AArmor)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
|
||||
double SavePercent; // The default, for when you don't already have armor
|
||||
int MaxSaveAmount;
|
||||
int MaxAbsorb;
|
||||
int MaxFullAbsorb;
|
||||
int SaveAmount;
|
||||
int BonusCount;
|
||||
int BonusMax;
|
||||
};
|
||||
|
||||
// Hexen armor consists of four separate armor types plus a conceptual armor
|
||||
// type (the player himself) that work together as a single armor.
|
||||
class AHexenArmor : public AArmor
|
||||
{
|
||||
DECLARE_CLASS (AHexenArmor, AArmor)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
|
||||
virtual void DepleteOrDestroy() override;
|
||||
|
||||
double Slots[5];
|
||||
double SlotsIncrement[4];
|
||||
|
||||
protected:
|
||||
bool AddArmorToSlot (AActor *actor, int slot, int amount);
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,191 +0,0 @@
|
|||
#ifndef __A_ARTIFACTS_H__
|
||||
#define __A_ARTIFACTS_H__
|
||||
|
||||
#include "a_pickups.h"
|
||||
|
||||
class player_t;
|
||||
|
||||
// A powerup is a pseudo-inventory item that applies an effect to its
|
||||
// owner while it is present.
|
||||
class APowerup : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (APowerup, AInventory)
|
||||
public:
|
||||
virtual void Tick () override;
|
||||
virtual void Destroy () override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual void OwnerDied () override;
|
||||
virtual PalEntry GetBlend () override;
|
||||
virtual bool DrawPowerup (int x, int y) override;
|
||||
|
||||
int EffectTics;
|
||||
PalEntry BlendColor;
|
||||
FNameNoInit Mode;
|
||||
double Strength;
|
||||
|
||||
public:
|
||||
virtual void InitEffect ();
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect ();
|
||||
|
||||
protected:
|
||||
void CallInitEffect();
|
||||
void CallEndEffect();
|
||||
|
||||
friend void EndAllPowerupEffects(AInventory *item);
|
||||
friend void InitAllPowerupEffects(AInventory *item);
|
||||
};
|
||||
|
||||
// An artifact is an item that gives the player a powerup when activated.
|
||||
class APowerupGiver : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (APowerupGiver, AInventory)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
virtual bool Use (bool pickup) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
|
||||
PClassActor *PowerupType;
|
||||
int EffectTics; // Non-0 to override the powerup's default tics
|
||||
PalEntry BlendColor; // Non-0 to override the powerup's default blend
|
||||
FNameNoInit Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility
|
||||
double Strength; // Meaning depends on powerup - currently used only by Invisibility
|
||||
};
|
||||
|
||||
class APowerInvulnerable : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerInvulnerable, APowerup)
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
virtual int AlterWeaponSprite (visstyle_t *vis) override;
|
||||
};
|
||||
|
||||
class APowerStrength : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerStrength, APowerup)
|
||||
public:
|
||||
PalEntry GetBlend ();
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void Tick () override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
};
|
||||
|
||||
class APowerInvisibility : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerInvisibility, APowerup)
|
||||
protected:
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual void InitEffect () override;
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
virtual int AlterWeaponSprite (visstyle_t *vis) override;
|
||||
};
|
||||
|
||||
class APowerIronFeet : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerIronFeet, APowerup)
|
||||
public:
|
||||
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
|
||||
virtual void DoEffect () override;
|
||||
};
|
||||
|
||||
class APowerMask : public APowerIronFeet
|
||||
{
|
||||
DECLARE_CLASS (APowerMask, APowerIronFeet)
|
||||
public:
|
||||
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
|
||||
virtual void DoEffect () override;
|
||||
};
|
||||
|
||||
class APowerLightAmp : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerLightAmp, APowerup)
|
||||
protected:
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
};
|
||||
|
||||
class APowerTorch : public APowerLightAmp
|
||||
{
|
||||
DECLARE_CLASS (APowerTorch, APowerLightAmp)
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
protected:
|
||||
virtual void DoEffect () override;
|
||||
int NewTorch, NewTorchDelta;
|
||||
};
|
||||
|
||||
class APowerFlight : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerFlight, APowerup)
|
||||
public:
|
||||
virtual bool DrawPowerup (int x, int y) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void Tick () override;
|
||||
virtual void EndEffect () override;
|
||||
|
||||
private:
|
||||
bool HitCenterFrame;
|
||||
};
|
||||
|
||||
class APowerWeaponLevel2 : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerWeaponLevel2, APowerup)
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
};
|
||||
|
||||
class APowerSpeed : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerSpeed, APowerup)
|
||||
protected:
|
||||
virtual void DoEffect () override;
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
public:
|
||||
int SpeedFlags;
|
||||
};
|
||||
|
||||
#define PSF_NOTRAIL 1
|
||||
|
||||
class APowerTargeter : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerTargeter, APowerup)
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
void PositionAccuracy ();
|
||||
virtual void Travelled () override;
|
||||
virtual void AttachToOwner(AActor *other) override;
|
||||
virtual bool HandlePickup(AInventory *item) override;
|
||||
};
|
||||
|
||||
class APowerMorph : public APowerup
|
||||
{
|
||||
DECLARE_CLASS( APowerMorph, APowerup )
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
// Variables
|
||||
PClassPlayerPawn *PlayerClass;
|
||||
PClassActor *MorphFlash, *UnMorphFlash;
|
||||
int MorphStyle;
|
||||
player_t *MorphedPlayer;
|
||||
};
|
||||
|
||||
#endif //__A_ARTIFACTS_H__
|
|
@ -1,301 +0,0 @@
|
|||
/*
|
||||
** a_health.cpp
|
||||
** All health items
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2000-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "d_player.h"
|
||||
#include "a_morph.h"
|
||||
#include "a_health.h"
|
||||
#include "serializer.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FUNC P_GiveBody
|
||||
//
|
||||
// Returns false if the body isn't needed at all.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool P_GiveBody (AActor *actor, int num, int max)
|
||||
{
|
||||
if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD))
|
||||
{ // Do not heal dead things.
|
||||
return false;
|
||||
}
|
||||
|
||||
player_t *player = actor->player;
|
||||
|
||||
num = clamp(num, -65536, 65536); // prevent overflows for bad values
|
||||
if (player != NULL)
|
||||
{
|
||||
// Max is 0 by default, preserving default behavior for P_GiveBody()
|
||||
// calls while supporting AHealth.
|
||||
if (max <= 0)
|
||||
{
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
|
||||
// [MH] First step in predictable generic morph effects
|
||||
if (player->morphTics)
|
||||
{
|
||||
if (player->MorphStyle & MORPH_FULLHEALTH)
|
||||
{
|
||||
if (!(player->MorphStyle & MORPH_ADDSTAMINA))
|
||||
{
|
||||
max -= player->mo->stamina;
|
||||
}
|
||||
}
|
||||
else // old health behaviour
|
||||
{
|
||||
max = MAXMORPHHEALTH;
|
||||
if (player->MorphStyle & MORPH_ADDSTAMINA)
|
||||
{
|
||||
max += player->mo->stamina;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// [RH] For Strife: A negative body sets you up with a percentage
|
||||
// of your full health.
|
||||
if (num < 0)
|
||||
{
|
||||
num = max * -num / 100;
|
||||
if (player->health < num)
|
||||
{
|
||||
player->health = num;
|
||||
actor->health = num;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (num > 0)
|
||||
{
|
||||
if (player->health < max)
|
||||
{
|
||||
num = int(num * G_SkillProperty(SKILLP_HealthFactor));
|
||||
if (num < 1) num = 1;
|
||||
player->health += num;
|
||||
if (player->health > max)
|
||||
{
|
||||
player->health = max;
|
||||
}
|
||||
actor->health = player->health;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parameter value for max is ignored on monsters, preserving original
|
||||
// behaviour on AHealth as well as on existing calls to P_GiveBody().
|
||||
max = actor->SpawnHealth();
|
||||
if (num < 0)
|
||||
{
|
||||
num = max * -num / 100;
|
||||
if (actor->health < num)
|
||||
{
|
||||
actor->health = num;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (actor->health < max)
|
||||
{
|
||||
actor->health += num;
|
||||
if (actor->health > max)
|
||||
{
|
||||
actor->health = max;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GiveBody)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(num);
|
||||
PARAM_INT_DEF(max);
|
||||
ACTION_RETURN_BOOL(P_GiveBody(self, num, max));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Classes
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
IMPLEMENT_CLASS(PClassHealth, false, false)
|
||||
IMPLEMENT_CLASS(AHealth, false, false)
|
||||
DEFINE_FIELD(AHealth, PrevHealth)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PClassHealth Constructor
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
PClassHealth::PClassHealth()
|
||||
{
|
||||
LowHealth = 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PClassHealth :: DeriveData
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void PClassHealth::DeriveData(PClass *newclass)
|
||||
{
|
||||
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth)));
|
||||
Super::DeriveData(newclass);
|
||||
PClassHealth *newc = static_cast<PClassHealth *>(newclass);
|
||||
|
||||
newc->LowHealth = LowHealth;
|
||||
newc->LowHealthMessage = LowHealthMessage;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealth :: PickupMessage
|
||||
//
|
||||
//===========================================================================
|
||||
FString AHealth::PickupMessage ()
|
||||
{
|
||||
int threshold = GetClass()->LowHealth;
|
||||
|
||||
if (PrevHealth < threshold)
|
||||
{
|
||||
FString message = GetClass()->LowHealthMessage;
|
||||
|
||||
if (message.IsNotEmpty())
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
||||
return Super::PickupMessage();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealth :: TryPickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHealth::TryPickup (AActor *&other)
|
||||
{
|
||||
PrevHealth = other->player != NULL ? other->player->health : other->health;
|
||||
|
||||
// P_GiveBody adds one new feature, applied only if it is possible to pick up negative health:
|
||||
// Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount.
|
||||
if (P_GiveBody(other, Amount, MaxAmount))
|
||||
{
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(AHealthPickup, false, false)
|
||||
|
||||
DEFINE_FIELD(AHealthPickup, autousemode)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealthPickup :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHealthPickup::CreateCopy (AActor *other)
|
||||
{
|
||||
AInventory *copy = Super::CreateCopy (other);
|
||||
copy->health = health;
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealthPickup :: CreateTossable
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AHealthPickup::CreateTossable ()
|
||||
{
|
||||
AInventory *copy = Super::CreateTossable ();
|
||||
if (copy != NULL)
|
||||
{
|
||||
copy->health = health;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealthPickup :: HandlePickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHealthPickup::HandlePickup (AInventory *item)
|
||||
{
|
||||
// HealthPickups that are the same type but have different health amounts
|
||||
// do not count as the same item.
|
||||
if (item->health == health)
|
||||
{
|
||||
return Super::HandlePickup (item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealthPickup :: Use
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AHealthPickup::Use (bool pickup)
|
||||
{
|
||||
return P_GiveBody (Owner, health, 0);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AHealthPickup :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AHealthPickup::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
auto def = (AHealthPickup*)GetDefault();
|
||||
arc("autousemode", autousemode, def->autousemode);
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "a_pickups.h"
|
||||
|
||||
// Health is some item that gives the player health when picked up.
|
||||
class PClassHealth : public PClassInventory
|
||||
{
|
||||
DECLARE_CLASS(PClassHealth, PClassInventory)
|
||||
protected:
|
||||
public:
|
||||
PClassHealth();
|
||||
virtual void DeriveData(PClass *newclass);
|
||||
|
||||
FString LowHealthMessage;
|
||||
int LowHealth;
|
||||
};
|
||||
|
||||
class AHealth : public AInventory
|
||||
{
|
||||
DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth)
|
||||
|
||||
public:
|
||||
int PrevHealth;
|
||||
virtual bool TryPickup (AActor *&other) override;
|
||||
virtual FString PickupMessage () override;
|
||||
};
|
||||
|
||||
// HealthPickup is some item that gives the player health when used.
|
||||
class AHealthPickup : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (AHealthPickup, AInventory)
|
||||
public:
|
||||
int autousemode;
|
||||
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
};
|
||||
|
|
@ -51,7 +51,6 @@
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -64,29 +63,24 @@ struct OneKey
|
|||
|
||||
bool check(AActor *owner)
|
||||
{
|
||||
if (owner->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
{
|
||||
// P_GetMapColorForKey() checks the key directly
|
||||
return owner->IsA(key) || owner->GetSpecies() == key->TypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other calls check an actor that may have a key in its inventory.
|
||||
AInventory *item;
|
||||
// P_GetMapColorForKey() checks the key directly
|
||||
if (owner->IsA(key) || owner->GetSpecies() == key->TypeName) return true;
|
||||
|
||||
for (item = owner->Inventory; item != NULL; item = item->Inventory)
|
||||
// Other calls check an actor that may have a key in its inventory.
|
||||
AInventory *item;
|
||||
|
||||
for (item = owner->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->IsA(key))
|
||||
{
|
||||
if (item->IsA(key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (item->GetSpecies() == key->TypeName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (item->GetSpecies() == key->TypeName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -138,9 +132,10 @@ struct Lock
|
|||
// An empty key list means that any key will do
|
||||
if (!keylist.Size())
|
||||
{
|
||||
auto kt = PClass::FindActor(NAME_Key);
|
||||
for (AInventory * item = owner->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AKey)))
|
||||
if (item->IsKindOf (kt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -192,12 +187,12 @@ static void AddOneKey(Keygroup *keygroup, PClassActor *mi, FScanner &sc)
|
|||
keygroup->anykeylist.Push (k);
|
||||
|
||||
//... but only keys get key numbers!
|
||||
if (mi->IsDescendantOf(RUNTIME_CLASS(AKey)))
|
||||
if (mi->IsDescendantOf(PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
if (!ignorekey &&
|
||||
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber == 0)
|
||||
GetDefaultByType(mi)->special1 == 0)
|
||||
{
|
||||
static_cast<AKey*>(GetDefaultByType(mi))->KeyNumber=++currentnumber;
|
||||
GetDefaultByType(mi)->special1 = ++currentnumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,14 +382,15 @@ static void ParseLock(FScanner &sc)
|
|||
static void ClearLocks()
|
||||
{
|
||||
unsigned int i;
|
||||
auto kt = PClass::FindActor(NAME_Key);
|
||||
for(i = 0; i < PClassActor::AllActorClasses.Size(); i++)
|
||||
{
|
||||
if (PClassActor::AllActorClasses[i]->IsDescendantOf(RUNTIME_CLASS(AKey)))
|
||||
if (PClassActor::AllActorClasses[i]->IsDescendantOf(kt))
|
||||
{
|
||||
AKey *key = static_cast<AKey*>(GetDefaultByType(PClassActor::AllActorClasses[i]));
|
||||
auto key = GetDefaultByType(PClassActor::AllActorClasses[i]);
|
||||
if (key != NULL)
|
||||
{
|
||||
key->KeyNumber = 0;
|
||||
key->special1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -523,42 +519,6 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote)
|
|||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AKey implementation
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IMPLEMENT_CLASS(AKey, false, false)
|
||||
|
||||
DEFINE_FIELD(AKey, KeyNumber)
|
||||
|
||||
bool AKey::HandlePickup (AInventory *item)
|
||||
{
|
||||
// In single player, you can pick up an infinite number of keys
|
||||
// even though you can only hold one of each.
|
||||
if (multiplayer)
|
||||
{
|
||||
return Super::HandlePickup (item);
|
||||
}
|
||||
if (GetClass() == item->GetClass())
|
||||
{
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AKey::ShouldStay ()
|
||||
{
|
||||
return !!multiplayer;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// These functions can be used to get color information for
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
#ifndef A_KEYS_H
|
||||
#define A_KEYS_H
|
||||
|
||||
#include "a_pickups.h"
|
||||
|
||||
class AKey : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (AKey, AInventory)
|
||||
public:
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
|
||||
BYTE KeyNumber;
|
||||
|
||||
protected:
|
||||
virtual bool ShouldStay () override;
|
||||
};
|
||||
class AActor;
|
||||
class AInventory;
|
||||
|
||||
bool P_CheckKeys (AActor *owner, int keynum, bool remote);
|
||||
void P_InitKeyMessages ();
|
||||
|
@ -21,28 +10,4 @@ void P_DeinitKeyMessages ();
|
|||
int P_GetMapColorForLock (int lock);
|
||||
int P_GetMapColorForKey (AInventory *key);
|
||||
|
||||
|
||||
// PuzzleItems work in conjunction with the UsePuzzleItem special
|
||||
class PClassPuzzleItem : public PClassInventory
|
||||
{
|
||||
DECLARE_CLASS(PClassPuzzleItem, PClassInventory);
|
||||
protected:
|
||||
public:
|
||||
virtual void DeriveData(PClass *newclass);
|
||||
FString PuzzFailMessage;
|
||||
};
|
||||
|
||||
class APuzzleItem : public AInventory
|
||||
{
|
||||
DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem)
|
||||
public:
|
||||
|
||||
virtual bool ShouldStay () override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
|
||||
int PuzzleItemNumber;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -46,6 +46,7 @@ enum
|
|||
IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag
|
||||
IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper
|
||||
IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting.
|
||||
IF_NOSCREENBLINK = 1<<26, // Does not blink the screen overlay when expiring.
|
||||
};
|
||||
|
||||
|
||||
|
@ -58,7 +59,7 @@ public:
|
|||
virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass);
|
||||
void Finalize(FStateDefinitions &statedef);
|
||||
|
||||
FString PickupMessage;
|
||||
FString PickupMsg;
|
||||
int GiveQuest; // Optionally give one of the quest items.
|
||||
FTextureID AltHUDIcon;
|
||||
TArray<PClassPlayerPawn *> RestrictedToPlayerClass;
|
||||
|
@ -71,86 +72,25 @@ class AInventory : public AActor
|
|||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
||||
virtual void Touch (AActor *toucher) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual void MarkPrecacheSounds() const override;
|
||||
virtual void BeginPlay () override;
|
||||
virtual void Destroy () override;
|
||||
virtual void OnDestroy() override;
|
||||
virtual void Tick() override;
|
||||
virtual bool Grind(bool items) override;
|
||||
|
||||
// virtual methods that only get overridden by special internal classes, like DehackedPickup.
|
||||
// There is no need to expose these to scripts.
|
||||
virtual void DepleteOrDestroy ();
|
||||
virtual bool ShouldRespawn ();
|
||||
virtual void DoPickupSpecial (AActor *toucher);
|
||||
bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // Wrapper for script function.
|
||||
|
||||
// methods that can be overridden by scripts, plus their callers.
|
||||
virtual bool SpecialDropAction (AActor *dropper);
|
||||
bool CallSpecialDropAction(AActor *dropper);
|
||||
void DepleteOrDestroy (); // virtual on the script side.
|
||||
bool CallUse(bool pickup); // virtual on the script side.
|
||||
PalEntry CallGetBlend(); // virtual on the script side.
|
||||
double GetSpeedFactor(); // virtual on the script side.
|
||||
bool GetNoTeleportFreeze(); // virtual on the script side.
|
||||
|
||||
virtual bool TryPickup(AActor *&toucher);
|
||||
virtual bool TryPickupRestricted(AActor *&toucher);
|
||||
bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // This wraps both virtual methods plus a few more checks.
|
||||
|
||||
virtual AInventory *CreateCopy(AActor *other);
|
||||
AInventory *CallCreateCopy(AActor *other);
|
||||
|
||||
virtual AInventory *CreateTossable();
|
||||
AInventory *CallCreateTossable();
|
||||
|
||||
virtual FString PickupMessage();
|
||||
FString GetPickupMessage();
|
||||
|
||||
virtual bool HandlePickup(AInventory *item);
|
||||
bool CallHandlePickup(AInventory *item);
|
||||
|
||||
virtual bool Use(bool pickup);
|
||||
bool CallUse(bool pickup);
|
||||
|
||||
virtual PalEntry GetBlend();
|
||||
PalEntry CallGetBlend();
|
||||
|
||||
virtual bool ShouldStay();
|
||||
bool CallShouldStay();
|
||||
|
||||
virtual void DoEffect();
|
||||
void CallDoEffect();
|
||||
|
||||
virtual void PlayPickupSound(AActor *toucher);
|
||||
void CallPlayPickupSound(AActor *toucher);
|
||||
|
||||
virtual void AttachToOwner(AActor *other);
|
||||
void CallAttachToOwner(AActor *other);
|
||||
|
||||
virtual void DetachFromOwner();
|
||||
void CallDetachFromOwner();
|
||||
|
||||
// still need to be done.
|
||||
virtual void AbsorbDamage(int damage, FName damageType, int &newdamage);
|
||||
void ModifyDamage(int damage, FName damageType, int &newdamage, bool passive);
|
||||
|
||||
// visual stuff is for later. Right now the VM has not yet access to the needed functionality.
|
||||
virtual bool DrawPowerup(int x, int y);
|
||||
virtual int AlterWeaponSprite(visstyle_t *vis);
|
||||
|
||||
|
||||
// virtual on the script side only.
|
||||
double GetSpeedFactor();
|
||||
bool GetNoTeleportFreeze();
|
||||
// Stuff for later when more features are exported.
|
||||
virtual void Travelled();
|
||||
virtual void OwnerDied();
|
||||
|
||||
|
||||
bool GoAway();
|
||||
void GoAwayAndDie();
|
||||
|
||||
void Hide();
|
||||
void BecomeItem ();
|
||||
void BecomePickup ();
|
||||
|
||||
bool DoRespawn();
|
||||
|
||||
AInventory *PrevItem(); // Returns the item preceding this one in the list.
|
||||
AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set.
|
||||
AInventory *NextInv(); // Returns the next item with IF_INVBAR set.
|
||||
|
@ -168,37 +108,13 @@ public:
|
|||
PClassActor *PickupFlash; // actor to spawn as pickup flash
|
||||
|
||||
FSoundIDNoInit PickupSound;
|
||||
|
||||
|
||||
protected:
|
||||
bool CanPickup(AActor * toucher);
|
||||
void GiveQuest(AActor * toucher);
|
||||
|
||||
private:
|
||||
static int StaticLastMessageTic;
|
||||
static FString StaticLastMessage;
|
||||
};
|
||||
|
||||
class AStateProvider : public AInventory
|
||||
{
|
||||
DECLARE_CLASS(AStateProvider, AInventory)
|
||||
};
|
||||
|
||||
// CustomInventory: Supports the Use, Pickup, and Drop states from 96x
|
||||
class ACustomInventory : public AStateProvider
|
||||
{
|
||||
DECLARE_CLASS (ACustomInventory, AStateProvider)
|
||||
DECLARE_CLASS (AStateProvider, AInventory)
|
||||
public:
|
||||
|
||||
// This is used when an inventory item's use state sequence is executed.
|
||||
bool CallStateChain (AActor *actor, FState *state);
|
||||
|
||||
virtual bool TryPickup (AActor *&toucher) override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
virtual bool SpecialDropAction (AActor *dropper) override;
|
||||
bool CallStateChain(AActor *actor, FState *state);
|
||||
};
|
||||
|
||||
extern PClassActor *QuestItemClasses[31];
|
||||
|
||||
|
||||
#endif //__A_PICKUPS_H__
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
** a_puzzleitems.cpp
|
||||
** Implements Hexen's puzzle items.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2016 Randy Heit
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "info.h"
|
||||
#include "a_pickups.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "gstrings.h"
|
||||
#include "p_local.h"
|
||||
#include "s_sound.h"
|
||||
#include "c_console.h"
|
||||
#include "doomstat.h"
|
||||
#include "v_font.h"
|
||||
#include "a_keys.h"
|
||||
|
||||
|
||||
IMPLEMENT_CLASS(PClassPuzzleItem, false, false)
|
||||
IMPLEMENT_CLASS(APuzzleItem, false, false)
|
||||
|
||||
DEFINE_FIELD(APuzzleItem, PuzzleItemNumber)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void PClassPuzzleItem::DeriveData(PClass *newclass)
|
||||
{
|
||||
Super::DeriveData(newclass);
|
||||
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem)));
|
||||
static_cast<PClassPuzzleItem *>(newclass)->PuzzFailMessage = PuzzFailMessage;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool APuzzleItem::HandlePickup (AInventory *item)
|
||||
{
|
||||
// Can't carry more than 1 of each puzzle item in coop netplay
|
||||
if (multiplayer && !deathmatch && item->GetClass() == GetClass())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return Super::HandlePickup (item);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool APuzzleItem::Use (bool pickup)
|
||||
{
|
||||
if (P_UsePuzzleItem (Owner, PuzzleItemNumber))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// [RH] Always play the sound if the use fails.
|
||||
S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE);
|
||||
if (Owner != NULL && Owner->CheckLocalView (consoleplayer))
|
||||
{
|
||||
FString message = GetClass()->PuzzFailMessage;
|
||||
if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]];
|
||||
if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED");
|
||||
C_MidPrintBold (SmallFont, message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool APuzzleItem::ShouldStay ()
|
||||
{
|
||||
return !!multiplayer;
|
||||
}
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
** a_weaponpieces.cpp
|
||||
** Implements generic weapon pieces
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006-2016 Cheistoph Oelckers
|
||||
** Copyright 2006-2016 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "a_pickups.h"
|
||||
#include "a_weaponpiece.h"
|
||||
#include "doomstat.h"
|
||||
#include "serializer.h"
|
||||
|
||||
IMPLEMENT_CLASS(AWeaponHolder, false, false)
|
||||
|
||||
DEFINE_FIELD(AWeaponHolder, PieceMask);
|
||||
DEFINE_FIELD(AWeaponHolder, PieceWeapon);
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponHolder::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
arc("piecemask", PieceMask)
|
||||
("pieceweapon", PieceWeapon);
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(AWeaponPiece, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(AWeaponPiece)
|
||||
IMPLEMENT_POINTER(FullWeapon)
|
||||
IMPLEMENT_POINTER(WeaponClass)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponPiece::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AWeaponPiece*)GetDefault();
|
||||
arc("weaponclass", WeaponClass, def->WeaponClass)
|
||||
("fullweapon", FullWeapon)
|
||||
("piecevalue", PieceValue, def->PieceValue);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool AWeaponPiece::TryPickupRestricted (AActor *&toucher)
|
||||
{
|
||||
// Wrong class, but try to pick up for ammo
|
||||
if (CallShouldStay())
|
||||
{ // Can't pick up weapons for other classes in coop netplay
|
||||
return false;
|
||||
}
|
||||
|
||||
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
|
||||
|
||||
bool gaveSome = !!(toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2));
|
||||
|
||||
if (gaveSome)
|
||||
{
|
||||
GoAwayAndDie ();
|
||||
}
|
||||
return gaveSome;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TryPickupWeaponPiece
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool AWeaponPiece::TryPickup (AActor *&toucher)
|
||||
{
|
||||
AInventory * inv;
|
||||
AWeaponHolder * hold=NULL;
|
||||
bool shouldStay = PrivateShouldStay ();
|
||||
int gaveAmmo;
|
||||
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
|
||||
|
||||
FullWeapon=NULL;
|
||||
for(inv=toucher->Inventory;inv;inv=inv->Inventory)
|
||||
{
|
||||
if (inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder)))
|
||||
{
|
||||
hold=static_cast<AWeaponHolder*>(inv);
|
||||
|
||||
if (hold->PieceWeapon==WeaponClass) break;
|
||||
hold=NULL;
|
||||
}
|
||||
}
|
||||
if (!hold)
|
||||
{
|
||||
hold=static_cast<AWeaponHolder*>(Spawn(RUNTIME_CLASS(AWeaponHolder)));
|
||||
hold->BecomeItem();
|
||||
hold->AttachToOwner(toucher);
|
||||
hold->PieceMask=0;
|
||||
hold->PieceWeapon=WeaponClass;
|
||||
}
|
||||
|
||||
|
||||
if (shouldStay)
|
||||
{
|
||||
// Cooperative net-game
|
||||
if (hold->PieceMask & PieceValue)
|
||||
{
|
||||
// Already has the piece
|
||||
return false;
|
||||
}
|
||||
toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1);
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
|
||||
}
|
||||
else
|
||||
{ // Deathmatch or singleplayer game
|
||||
gaveAmmo = toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
|
||||
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2);
|
||||
|
||||
if (hold->PieceMask & PieceValue)
|
||||
{
|
||||
// Already has the piece, check if mana needed
|
||||
if (!gaveAmmo) return false;
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
hold->PieceMask |= PieceValue;
|
||||
|
||||
// Check if weapon assembled
|
||||
if (hold->PieceMask== (1<<Defaults->health)-1)
|
||||
{
|
||||
if (!toucher->FindInventory (WeaponClass))
|
||||
{
|
||||
FullWeapon= static_cast<AWeapon*>(Spawn(WeaponClass));
|
||||
|
||||
// The weapon itself should not give more ammo to the player!
|
||||
FullWeapon->AmmoGive1=0;
|
||||
FullWeapon->AmmoGive2=0;
|
||||
FullWeapon->AttachToOwner(toucher);
|
||||
FullWeapon->AmmoGive1=Defaults->AmmoGive1;
|
||||
FullWeapon->AmmoGive2=Defaults->AmmoGive2;
|
||||
}
|
||||
}
|
||||
GoAwayAndDie();
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeaponPiece::ShouldStay ()
|
||||
{
|
||||
return PrivateShouldStay ();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeaponPiece::PrivateShouldStay ()
|
||||
{
|
||||
// We want a weapon piece to behave like a weapon, so follow the exact
|
||||
// same logic as weapons when deciding whether or not to stay.
|
||||
if (((multiplayer &&
|
||||
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
|
||||
!(flags&MF_DROPPED))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PickupMessage
|
||||
//
|
||||
// Returns the message to print when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString AWeaponPiece::PickupMessage ()
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
return FullWeapon->PickupMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Super::PickupMessage();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DoPlayPickupSound
|
||||
//
|
||||
// Plays a sound when this actor is picked up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeaponPiece::PlayPickupSound (AActor *toucher)
|
||||
{
|
||||
if (FullWeapon)
|
||||
{
|
||||
FullWeapon->PlayPickupSound(toucher);
|
||||
}
|
||||
else
|
||||
{
|
||||
Super::PlayPickupSound(toucher);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#pragma once
|
||||
#include "a_pickups.h"
|
||||
#include "a_weapons.h"
|
||||
|
||||
class AWeaponPiece : public AInventory
|
||||
{
|
||||
DECLARE_CLASS(AWeaponPiece, AInventory)
|
||||
HAS_OBJECT_POINTERS
|
||||
protected:
|
||||
bool PrivateShouldStay ();
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual bool TryPickup (AActor *&toucher) override;
|
||||
virtual bool TryPickupRestricted (AActor *&toucher) override;
|
||||
virtual bool ShouldStay () override;
|
||||
virtual FString PickupMessage () override;
|
||||
virtual void PlayPickupSound (AActor *toucher) override;
|
||||
|
||||
int PieceValue;
|
||||
PClassActor *WeaponClass;
|
||||
TObjPtr<AWeapon> FullWeapon;
|
||||
};
|
||||
|
||||
// an internal class to hold the information for player class independent weapon piece handling
|
||||
// [BL] Needs to be available for SBarInfo to check weaponpieces
|
||||
class AWeaponHolder : public AInventory
|
||||
{
|
||||
DECLARE_CLASS(AWeaponHolder, AInventory)
|
||||
|
||||
public:
|
||||
int PieceMask;
|
||||
PClassActor * PieceWeapon;
|
||||
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
};
|
|
@ -54,9 +54,7 @@
|
|||
#include "serializer.h"
|
||||
#include "thingdef.h"
|
||||
#include "virtual.h"
|
||||
#include "a_ammo.h"
|
||||
|
||||
#define BONUSADD 6
|
||||
|
||||
extern FFlagDef WeaponFlagDefs[];
|
||||
|
||||
|
@ -249,363 +247,6 @@ void AWeapon::MarkPrecacheSounds() const
|
|||
ReadySound.MarkUsed();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: TryPickup
|
||||
//
|
||||
// If you can't see the weapon when it's active, then you can't pick it up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::TryPickupRestricted (AActor *&toucher)
|
||||
{
|
||||
// Wrong class, but try to pick up for ammo
|
||||
if (CallShouldStay())
|
||||
{ // Can't pick up weapons for other classes in coop netplay
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
|
||||
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
|
||||
if (gaveSome)
|
||||
{
|
||||
GoAwayAndDie ();
|
||||
}
|
||||
return gaveSome;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: TryPickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::TryPickup (AActor *&toucher)
|
||||
{
|
||||
FState * ReadyState = FindState(NAME_Ready);
|
||||
if (ReadyState != NULL &&
|
||||
ReadyState->GetFrame() < sprites[ReadyState->sprite].numframes)
|
||||
{
|
||||
return Super::TryPickup (toucher);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: Use
|
||||
//
|
||||
// Make the player switch to this weapon.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::Use (bool pickup)
|
||||
{
|
||||
AWeapon *useweap = this;
|
||||
|
||||
// Powered up weapons cannot be used directly.
|
||||
if (WeaponFlags & WIF_POWERED_UP) return false;
|
||||
|
||||
// If the player is powered-up, use the alternate version of the
|
||||
// weapon, if one exists.
|
||||
if (SisterWeapon != NULL &&
|
||||
SisterWeapon->WeaponFlags & WIF_POWERED_UP &&
|
||||
Owner->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true))
|
||||
{
|
||||
useweap = SisterWeapon;
|
||||
}
|
||||
if (Owner->player != NULL && Owner->player->ReadyWeapon != useweap)
|
||||
{
|
||||
Owner->player->PendingWeapon = useweap;
|
||||
}
|
||||
// Return false so that the weapon is not removed from the inventory.
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: Destroy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeapon::Destroy()
|
||||
{
|
||||
AWeapon *sister = SisterWeapon;
|
||||
|
||||
if (sister != NULL)
|
||||
{
|
||||
// avoid recursion
|
||||
sister->SisterWeapon = NULL;
|
||||
if (sister != this)
|
||||
{ // In case we are our own sister, don't crash.
|
||||
sister->Destroy();
|
||||
}
|
||||
}
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: HandlePickup
|
||||
//
|
||||
// Try to leach ammo from the weapon if you have it already.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::HandlePickup (AInventory *item)
|
||||
{
|
||||
if (item->GetClass() == GetClass())
|
||||
{
|
||||
if (static_cast<AWeapon *>(item)->PickupForAmmo (this))
|
||||
{
|
||||
item->ItemFlags |= IF_PICKUPGOOD;
|
||||
}
|
||||
if (MaxAmount > 1) //[SP] If amount<maxamount do another pickup test of the weapon itself!
|
||||
{
|
||||
return Super::HandlePickup (item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: PickupForAmmo
|
||||
//
|
||||
// The player already has this weapon, so try to pick it up for ammo.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::PickupForAmmo (AWeapon *ownedWeapon)
|
||||
{
|
||||
bool gotstuff = false;
|
||||
|
||||
// Don't take ammo if the weapon sticks around.
|
||||
if (!CallShouldStay ())
|
||||
{
|
||||
int oldamount1 = 0;
|
||||
int oldamount2 = 0;
|
||||
if (ownedWeapon->Ammo1 != NULL) oldamount1 = ownedWeapon->Ammo1->Amount;
|
||||
if (ownedWeapon->Ammo2 != NULL) oldamount2 = ownedWeapon->Ammo2->Amount;
|
||||
|
||||
if (AmmoGive1 > 0) gotstuff = AddExistingAmmo (ownedWeapon->Ammo1, AmmoGive1);
|
||||
if (AmmoGive2 > 0) gotstuff |= AddExistingAmmo (ownedWeapon->Ammo2, AmmoGive2);
|
||||
|
||||
AActor *Owner = ownedWeapon->Owner;
|
||||
if (gotstuff && Owner != NULL && Owner->player != NULL)
|
||||
{
|
||||
if (ownedWeapon->Ammo1 != NULL && oldamount1 == 0)
|
||||
{
|
||||
static_cast<APlayerPawn *>(Owner)->CheckWeaponSwitch(ownedWeapon->Ammo1->GetClass());
|
||||
}
|
||||
else if (ownedWeapon->Ammo2 != NULL && oldamount2 == 0)
|
||||
{
|
||||
static_cast<APlayerPawn *>(Owner)->CheckWeaponSwitch(ownedWeapon->Ammo2->GetClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return gotstuff;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: CreateCopy
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AWeapon::CreateCopy (AActor *other)
|
||||
{
|
||||
AWeapon *copy = static_cast<AWeapon*>(Super::CreateCopy (other));
|
||||
if (copy != this)
|
||||
{
|
||||
copy->AmmoGive1 = AmmoGive1;
|
||||
copy->AmmoGive2 = AmmoGive2;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: CreateTossable
|
||||
//
|
||||
// A weapon that's tossed out should contain no ammo, so you can't cheat
|
||||
// by dropping it and then picking it back up.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AInventory *AWeapon::CreateTossable ()
|
||||
{
|
||||
// Only drop the weapon that is meant to be placed in a level. That is,
|
||||
// only drop the weapon that normally gives you ammo.
|
||||
if (SisterWeapon != NULL &&
|
||||
((AWeapon*)GetDefault())->AmmoGive1 == 0 &&
|
||||
((AWeapon*)GetDefault())->AmmoGive2 == 0 &&
|
||||
(((AWeapon*)SisterWeapon->GetDefault())->AmmoGive1 > 0 ||
|
||||
((AWeapon*)SisterWeapon->GetDefault())->AmmoGive2 > 0))
|
||||
{
|
||||
return SisterWeapon->CallCreateTossable ();
|
||||
}
|
||||
AWeapon *copy = static_cast<AWeapon *> (Super::CreateTossable ());
|
||||
|
||||
if (copy != NULL)
|
||||
{
|
||||
// If this weapon has a sister, remove it from the inventory too.
|
||||
if (SisterWeapon != NULL)
|
||||
{
|
||||
SisterWeapon->SisterWeapon = NULL;
|
||||
SisterWeapon->Destroy ();
|
||||
}
|
||||
// To avoid exploits, the tossed weapon must not have any ammo.
|
||||
copy->AmmoGive1 = 0;
|
||||
copy->AmmoGive2 = 0;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: AttachToOwner
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeapon::AttachToOwner (AActor *other)
|
||||
{
|
||||
Super::AttachToOwner (other);
|
||||
|
||||
Ammo1 = AddAmmo (Owner, AmmoType1, AmmoGive1);
|
||||
Ammo2 = AddAmmo (Owner, AmmoType2, AmmoGive2);
|
||||
SisterWeapon = AddWeapon (SisterWeaponType);
|
||||
if (Owner->player != NULL)
|
||||
{
|
||||
if (!Owner->player->userinfo.GetNeverSwitch() && !(WeaponFlags & WIF_NO_AUTO_SWITCH))
|
||||
{
|
||||
Owner->player->PendingWeapon = this;
|
||||
}
|
||||
if (Owner->player->mo == players[consoleplayer].camera)
|
||||
{
|
||||
StatusBar->ReceivedWeapon (this);
|
||||
}
|
||||
}
|
||||
GivenAsMorphWeapon = false; // will be set explicitly by morphing code
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: AddAmmo
|
||||
//
|
||||
// Give some ammo to the owner, even if it's just 0.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AAmmo *AWeapon::AddAmmo (AActor *other, PClassActor *ammotype, int amount)
|
||||
{
|
||||
AAmmo *ammo;
|
||||
|
||||
if (ammotype == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// [BC] This behavior is from the original Doom. Give 5/2 times as much ammo when
|
||||
// we pick up a weapon in deathmatch.
|
||||
if (( deathmatch ) && ( gameinfo.gametype & GAME_DoomChex ))
|
||||
amount = amount * 5 / 2;
|
||||
|
||||
// extra ammo in baby mode and nightmare mode
|
||||
if (!(this->ItemFlags&IF_IGNORESKILL))
|
||||
{
|
||||
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
ammo = static_cast<AAmmo *>(other->FindInventory (ammotype));
|
||||
if (ammo == NULL)
|
||||
{
|
||||
ammo = static_cast<AAmmo *>(Spawn (ammotype));
|
||||
ammo->Amount = MIN (amount, ammo->MaxAmount);
|
||||
ammo->AttachToOwner (other);
|
||||
}
|
||||
else if (ammo->Amount < ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount += amount;
|
||||
if (ammo->Amount > ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
}
|
||||
return ammo;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: AddExistingAmmo
|
||||
//
|
||||
// Give the owner some more ammo he already has.
|
||||
//
|
||||
//===========================================================================
|
||||
EXTERN_CVAR(Bool, sv_unlimited_pickup)
|
||||
|
||||
bool AWeapon::AddExistingAmmo (AAmmo *ammo, int amount)
|
||||
{
|
||||
if (ammo != NULL && (ammo->Amount < ammo->MaxAmount || sv_unlimited_pickup))
|
||||
{
|
||||
// extra ammo in baby mode and nightmare mode
|
||||
if (!(ItemFlags&IF_IGNORESKILL))
|
||||
{
|
||||
amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor));
|
||||
}
|
||||
ammo->Amount += amount;
|
||||
if (ammo->Amount > ammo->MaxAmount && !sv_unlimited_pickup)
|
||||
{
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: AddWeapon
|
||||
//
|
||||
// Give the owner a weapon if they don't have it already.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
AWeapon *AWeapon::AddWeapon (PClassWeapon *weapontype)
|
||||
{
|
||||
AWeapon *weap;
|
||||
|
||||
if (weapontype == NULL || !weapontype->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
weap = static_cast<AWeapon *>(Owner->FindInventory (weapontype));
|
||||
if (weap == NULL)
|
||||
{
|
||||
weap = static_cast<AWeapon *>(Spawn (weapontype));
|
||||
weap->AttachToOwner (Owner);
|
||||
}
|
||||
return weap;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: ShouldStay
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AWeapon::ShouldStay ()
|
||||
{
|
||||
if (((multiplayer &&
|
||||
(!deathmatch && !alwaysapplydmflags)) || (dmflags & DF_WEAPONS_STAY)) &&
|
||||
!(flags & MF_DROPPED))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: CheckAmmo
|
||||
|
@ -781,61 +422,6 @@ void AWeapon::PostMorphWeapon ()
|
|||
pspr->SetState(GetUpState());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: EndPowerUp
|
||||
//
|
||||
// The Tome of Power just expired.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AWeapon::EndPowerup ()
|
||||
{
|
||||
if (SisterWeapon != NULL && WeaponFlags&WIF_POWERED_UP)
|
||||
{
|
||||
if (GetReadyState() != SisterWeapon->GetReadyState())
|
||||
{
|
||||
if (Owner->player->PendingWeapon == NULL ||
|
||||
Owner->player->PendingWeapon == WP_NOCHANGE)
|
||||
Owner->player->PendingWeapon = SisterWeapon;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
|
||||
if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
|
||||
{
|
||||
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
|
||||
psp->SetCaller(SisterWeapon);
|
||||
Owner->player->ReadyWeapon = SisterWeapon;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong. Initiate a regular weapon change.
|
||||
Owner->player->PendingWeapon = SisterWeapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AWeapon);
|
||||
self->EndPowerup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AWeapon::CallEndPowerup()
|
||||
{
|
||||
IFVIRTUAL(AWeapon, EndPowerup)
|
||||
{
|
||||
// Without the type cast this picks the 'void *' assignment...
|
||||
VMValue params[1] = { (DObject*)this };
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
else EndPowerup();
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AWeapon :: GetUpState
|
||||
|
@ -948,65 +534,6 @@ FState *AWeapon::GetStateForButtonName (FName button)
|
|||
}
|
||||
|
||||
|
||||
/* Weapon giver ***********************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(AWeaponGiver, false, false)
|
||||
|
||||
DEFINE_FIELD(AWeaponGiver, DropAmmoFactor);
|
||||
|
||||
void AWeaponGiver::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
auto def = (AWeaponGiver *)GetDefault();
|
||||
arc("dropammofactor", DropAmmoFactor, def->DropAmmoFactor);
|
||||
}
|
||||
|
||||
bool AWeaponGiver::TryPickup(AActor *&toucher)
|
||||
{
|
||||
DDropItem *di = GetDropItems();
|
||||
AWeapon *weap;
|
||||
|
||||
if (di != NULL)
|
||||
{
|
||||
PClassWeapon *ti = dyn_cast<PClassWeapon>(PClass::FindClass(di->Name));
|
||||
if (ti != NULL)
|
||||
{
|
||||
if (master == NULL)
|
||||
{
|
||||
master = weap = static_cast<AWeapon*>(Spawn(di->Name));
|
||||
if (weap != NULL)
|
||||
{
|
||||
weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only.
|
||||
weap->flags = (weap->flags & ~MF_DROPPED) | (this->flags & MF_DROPPED);
|
||||
|
||||
// If our ammo gives are non-negative, transfer them to the real weapon.
|
||||
if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1;
|
||||
if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2;
|
||||
|
||||
// If DropAmmoFactor is non-negative, modify the given ammo amounts.
|
||||
if (DropAmmoFactor > 0)
|
||||
{
|
||||
weap->AmmoGive1 = int(weap->AmmoGive1 * DropAmmoFactor);
|
||||
weap->AmmoGive2 = int(weap->AmmoGive2 * DropAmmoFactor);
|
||||
}
|
||||
weap->BecomeItem();
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
weap = barrier_cast<AWeapon*>(master);
|
||||
bool res = weap->CallTryPickup(toucher);
|
||||
if (res)
|
||||
{
|
||||
GoAwayAndDie();
|
||||
master = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Weapon slots ***********************************************************/
|
||||
|
||||
//===========================================================================
|
||||
|
@ -1300,6 +827,19 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FWeaponSlots, LocateWeapon)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots);
|
||||
PARAM_CLASS(weap, AWeapon);
|
||||
int slot = 0, index = 0;
|
||||
bool retv = self->LocateWeapon(weap, &slot, &index);
|
||||
if (numret >= 1) ret[0].SetInt(retv);
|
||||
if (numret >= 2) ret[1].SetInt(slot);
|
||||
if (numret >= 3) ret[2].SetInt(index);
|
||||
return MIN(numret, 3);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindMostRecentWeapon
|
||||
|
@ -2078,48 +1618,3 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream)
|
|||
return Weapons_ntoh[index];
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_ZoomFactor
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AWeapon, A_ZoomFactor)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
PARAM_FLOAT_DEF(zoom);
|
||||
PARAM_INT_DEF(flags);
|
||||
|
||||
if (self->player != NULL && self->player->ReadyWeapon != NULL)
|
||||
{
|
||||
zoom = 1 / clamp(zoom, 0.1, 50.0);
|
||||
if (flags & 1)
|
||||
{ // Make the zoom instant.
|
||||
self->player->FOV = float(self->player->DesiredFOV * zoom);
|
||||
}
|
||||
if (flags & 2)
|
||||
{ // Disable pitch/yaw scaling.
|
||||
zoom = -zoom;
|
||||
}
|
||||
self->player->ReadyWeapon->FOVScale = float(zoom);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_SetCrosshair
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AWeapon, A_SetCrosshair)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
PARAM_INT(xhair);
|
||||
|
||||
if (self->player != NULL && self->player->ReadyWeapon != NULL)
|
||||
{
|
||||
self->player->ReadyWeapon->Crosshair = xhair;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "a_ammo.h"
|
||||
|
||||
#include "a_pickups.h"
|
||||
class PClassWeapon;
|
||||
class AWeapon;
|
||||
|
||||
|
@ -107,7 +106,7 @@ class AWeapon : public AStateProvider
|
|||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
DWORD WeaponFlags;
|
||||
PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
|
||||
PClassInventory *AmmoType1, *AmmoType2; // Types of ammo used by this weapon
|
||||
int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
|
||||
int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon
|
||||
int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
|
||||
|
@ -126,7 +125,7 @@ public:
|
|||
float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
|
||||
|
||||
// In-inventory instance variables
|
||||
TObjPtr<AAmmo> Ammo1, Ammo2;
|
||||
TObjPtr<AInventory> Ammo1, Ammo2;
|
||||
TObjPtr<AWeapon> SisterWeapon;
|
||||
float FOVScale;
|
||||
int Crosshair; // 0 to use player's crosshair
|
||||
|
@ -137,17 +136,7 @@ public:
|
|||
virtual void MarkPrecacheSounds() const;
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
virtual bool ShouldStay () override;
|
||||
virtual void AttachToOwner (AActor *other) override;
|
||||
virtual bool HandlePickup (AInventory *item) override;
|
||||
virtual AInventory *CreateCopy (AActor *other) override;
|
||||
virtual AInventory *CreateTossable () override;
|
||||
virtual bool TryPickup (AActor *&toucher) override;
|
||||
virtual bool TryPickupRestricted (AActor *&toucher) override;
|
||||
virtual bool Use (bool pickup) override;
|
||||
virtual void Destroy() override;
|
||||
|
||||
bool PickupForAmmo(AWeapon *ownedWeapon);
|
||||
void PostMorphWeapon();
|
||||
|
||||
// scripted virtuals.
|
||||
|
@ -159,10 +148,6 @@ public:
|
|||
|
||||
FState *GetStateForButtonName (FName button);
|
||||
|
||||
|
||||
virtual void EndPowerup ();
|
||||
void CallEndPowerup();
|
||||
|
||||
enum
|
||||
{
|
||||
PrimaryFire,
|
||||
|
@ -182,10 +167,6 @@ public:
|
|||
BobInverseSmooth
|
||||
};
|
||||
|
||||
protected:
|
||||
AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount);
|
||||
bool AddExistingAmmo (AAmmo *ammo, int amount);
|
||||
AWeapon *AddWeapon (PClassWeapon *weapon);
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -219,14 +200,3 @@ enum
|
|||
WIF_BOT_BFG = 1<<28, // this is a BFG
|
||||
};
|
||||
|
||||
class AWeaponGiver : public AWeapon
|
||||
{
|
||||
DECLARE_CLASS(AWeaponGiver, AWeapon)
|
||||
|
||||
public:
|
||||
virtual bool TryPickup(AActor *&toucher) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
double DropAmmoFactor;
|
||||
};
|
||||
|
||||
|
|
|
@ -84,10 +84,12 @@
|
|||
#include "r_utility.h"
|
||||
#include "p_spec.h"
|
||||
#include "serializer.h"
|
||||
#include "virtual.h"
|
||||
|
||||
#include "gi.h"
|
||||
|
||||
#include "g_hub.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -430,10 +432,16 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
|
|||
StatusBar->Destroy();
|
||||
StatusBar = NULL;
|
||||
}
|
||||
auto cls = PClass::FindClass("DoomStatusBar");
|
||||
|
||||
if (bTitleLevel)
|
||||
{
|
||||
StatusBar = new DBaseStatusBar (0);
|
||||
}
|
||||
else if (cls && gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
StatusBar = (DBaseStatusBar*)cls->CreateNew();
|
||||
}
|
||||
else if (SBarInfoScript[SCRIPT_CUSTOM] != NULL)
|
||||
{
|
||||
int cstype = SBarInfoScript[SCRIPT_CUSTOM]->GetGameType();
|
||||
|
@ -1091,12 +1099,12 @@ void G_WorldDone (void)
|
|||
|
||||
if (strncmp (nextlevel, "enDSeQ", 6) == 0)
|
||||
{
|
||||
FName endsequence = ENamedName(strtol(nextlevel.GetChars()+6, NULL, 16));
|
||||
FName endsequence = ENamedName(strtoll(nextlevel.GetChars()+6, NULL, 16));
|
||||
// Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere.
|
||||
if (endsequence == NAME_Inter_Strife)
|
||||
{
|
||||
if (players[0].mo->FindInventory (QuestItemClasses[24]) ||
|
||||
players[0].mo->FindInventory (QuestItemClasses[27]))
|
||||
if (players[0].mo->FindInventory (NAME_QuestItem25) ||
|
||||
players[0].mo->FindInventory (NAME_QuestItem28))
|
||||
{
|
||||
endsequence = NAME_Inter_Strife_Good;
|
||||
}
|
||||
|
@ -1312,7 +1320,13 @@ void G_FinishTravel ()
|
|||
{
|
||||
inv->ChangeStatNum (STAT_INVENTORY);
|
||||
inv->LinkToWorld (nullptr);
|
||||
inv->Travelled ();
|
||||
|
||||
IFVIRTUALPTR(inv, AInventory, Travelled)
|
||||
{
|
||||
VMValue params[1] = { inv };
|
||||
VMFrameStack stack;
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED)
|
||||
{
|
||||
|
@ -1841,8 +1855,8 @@ void FLevelLocals::AddScroller (int secnum)
|
|||
}
|
||||
if (Scrolls.Size() == 0)
|
||||
{
|
||||
Scrolls.Resize(numsectors);
|
||||
memset (&Scrolls[0], 0, sizeof(Scrolls[0])*numsectors);
|
||||
Scrolls.Resize(sectors.Size());
|
||||
memset(&Scrolls[0], 0, sizeof(Scrolls[0])*Scrolls.Size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1889,6 +1903,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE
|
|||
DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -148,7 +148,7 @@ enum ELevelFlags : unsigned int
|
|||
LEVEL_MONSTERSTELEFRAG = 0x00000400,
|
||||
LEVEL_ACTOWNSPECIAL = 0x00000800,
|
||||
LEVEL_SNDSEQTOTALCTRL = 0x00001000,
|
||||
LEVEL_FORCENOSKYSTRETCH = 0x00002000,
|
||||
LEVEL_FORCETILEDSKY = 0x00002000,
|
||||
|
||||
LEVEL_CROUCH_NO = 0x00004000,
|
||||
LEVEL_JUMP_NO = 0x00008000,
|
||||
|
@ -376,76 +376,6 @@ struct level_info_t
|
|||
}
|
||||
};
|
||||
|
||||
struct FLevelLocals
|
||||
{
|
||||
void Tick ();
|
||||
void AddScroller (int secnum);
|
||||
|
||||
BYTE md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
|
||||
int time; // time in the hub
|
||||
int maptime; // time in the map
|
||||
int totaltime; // time in the game
|
||||
int starttime;
|
||||
int partime;
|
||||
int sucktime;
|
||||
|
||||
level_info_t *info;
|
||||
int cluster;
|
||||
int clusterflags;
|
||||
int levelnum;
|
||||
int lumpnum;
|
||||
FString LevelName;
|
||||
FString MapName; // the lump name (E1M1, MAP01, etc)
|
||||
FString NextMap; // go here when using the regular exit
|
||||
FString NextSecretMap; // map to go to when used secret exit
|
||||
EMapType maptype;
|
||||
|
||||
DWORD flags;
|
||||
DWORD flags2;
|
||||
DWORD flags3;
|
||||
|
||||
DWORD fadeto; // The color the palette fades to (usually black)
|
||||
DWORD outsidefog; // The fog for sectors with sky ceilings
|
||||
|
||||
FString Music;
|
||||
int musicorder;
|
||||
int cdtrack;
|
||||
unsigned int cdid;
|
||||
FTextureID skytexture1;
|
||||
FTextureID skytexture2;
|
||||
|
||||
float skyspeed1; // Scrolling speed of sky textures, in pixels per ms
|
||||
float skyspeed2;
|
||||
|
||||
int total_secrets;
|
||||
int found_secrets;
|
||||
|
||||
int total_items;
|
||||
int found_items;
|
||||
|
||||
int total_monsters;
|
||||
int killed_monsters;
|
||||
|
||||
double gravity;
|
||||
double aircontrol;
|
||||
double airfriction;
|
||||
int airsupply;
|
||||
int DefaultEnvironment; // Default sound environment.
|
||||
|
||||
TArray<DVector2> Scrolls; // NULL if no DScrollers in this level
|
||||
|
||||
SBYTE WallVertLight; // Light diffs for vert/horiz walls
|
||||
SBYTE WallHorizLight;
|
||||
|
||||
bool FromSnapshot; // The current map was restored from a snapshot
|
||||
|
||||
double teamdamage;
|
||||
|
||||
bool IsJumpingAllowed() const;
|
||||
bool IsCrouchingAllowed() const;
|
||||
bool IsFreelookAllowed() const;
|
||||
};
|
||||
|
||||
|
||||
struct cluster_info_t
|
||||
{
|
||||
|
@ -475,8 +405,6 @@ struct cluster_info_t
|
|||
#define CLUSTER_LOOKUPCLUSTERNAME 0x00000080 // Cluster name is the name of a language string
|
||||
#define CLUSTER_ALLOWINTERMISSION 0x00000100 // Allow intermissions between levels in a hub.
|
||||
|
||||
extern FLevelLocals level;
|
||||
|
||||
extern TArray<level_info_t> wadlevelinfos;
|
||||
extern TArray<cluster_info_t> wadclusterinfos;
|
||||
|
||||
|
|
134
src/g_levellocals.h
Normal file
134
src/g_levellocals.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
#pragma once
|
||||
|
||||
#include "g_level.h"
|
||||
#include "r_defs.h"
|
||||
|
||||
struct FLevelLocals
|
||||
{
|
||||
void Tick ();
|
||||
void AddScroller (int secnum);
|
||||
|
||||
BYTE md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
|
||||
int time; // time in the hub
|
||||
int maptime; // time in the map
|
||||
int totaltime; // time in the game
|
||||
int starttime;
|
||||
int partime;
|
||||
int sucktime;
|
||||
|
||||
level_info_t *info;
|
||||
int cluster;
|
||||
int clusterflags;
|
||||
int levelnum;
|
||||
int lumpnum;
|
||||
FString LevelName;
|
||||
FString MapName; // the lump name (E1M1, MAP01, etc)
|
||||
FString NextMap; // go here when using the regular exit
|
||||
FString NextSecretMap; // map to go to when used secret exit
|
||||
EMapType maptype;
|
||||
|
||||
TStaticArray<vertex_t> vertexes;
|
||||
TStaticArray<sector_t> sectors;
|
||||
TStaticArray<line_t> lines;
|
||||
TStaticArray<side_t> sides;
|
||||
|
||||
TArray<FSectorPortal> sectorPortals;
|
||||
|
||||
|
||||
DWORD flags;
|
||||
DWORD flags2;
|
||||
DWORD flags3;
|
||||
|
||||
DWORD fadeto; // The color the palette fades to (usually black)
|
||||
DWORD outsidefog; // The fog for sectors with sky ceilings
|
||||
|
||||
FString Music;
|
||||
int musicorder;
|
||||
int cdtrack;
|
||||
unsigned int cdid;
|
||||
FTextureID skytexture1;
|
||||
FTextureID skytexture2;
|
||||
|
||||
float skyspeed1; // Scrolling speed of sky textures, in pixels per ms
|
||||
float skyspeed2;
|
||||
|
||||
int total_secrets;
|
||||
int found_secrets;
|
||||
|
||||
int total_items;
|
||||
int found_items;
|
||||
|
||||
int total_monsters;
|
||||
int killed_monsters;
|
||||
|
||||
double gravity;
|
||||
double aircontrol;
|
||||
double airfriction;
|
||||
int airsupply;
|
||||
int DefaultEnvironment; // Default sound environment.
|
||||
|
||||
TArray<DVector2> Scrolls; // NULL if no DScrollers in this level
|
||||
|
||||
SBYTE WallVertLight; // Light diffs for vert/horiz walls
|
||||
SBYTE WallHorizLight;
|
||||
|
||||
bool FromSnapshot; // The current map was restored from a snapshot
|
||||
|
||||
double teamdamage;
|
||||
|
||||
bool IsJumpingAllowed() const;
|
||||
bool IsCrouchingAllowed() const;
|
||||
bool IsFreelookAllowed() const;
|
||||
};
|
||||
|
||||
extern FLevelLocals level;
|
||||
|
||||
inline int vertex_t::Index() const
|
||||
{
|
||||
return int(this - &level.vertexes[0]);
|
||||
}
|
||||
|
||||
inline int side_t::Index() const
|
||||
{
|
||||
return int(this - &level.sides[0]);
|
||||
}
|
||||
|
||||
inline int line_t::Index() const
|
||||
{
|
||||
return int(this - &level.lines[0]);
|
||||
}
|
||||
|
||||
inline FSectorPortal *line_t::GetTransferredPortal()
|
||||
{
|
||||
return portaltransferred >= level.sectorPortals.Size() ? (FSectorPortal*)nullptr : &level.sectorPortals[portaltransferred];
|
||||
}
|
||||
|
||||
inline int sector_t::Index() const
|
||||
{
|
||||
return int(this - &level.sectors[0]);
|
||||
}
|
||||
|
||||
inline FSectorPortal *sector_t::GetPortal(int plane)
|
||||
{
|
||||
return &level.sectorPortals[Portals[plane]];
|
||||
}
|
||||
|
||||
inline double sector_t::GetPortalPlaneZ(int plane)
|
||||
{
|
||||
return level.sectorPortals[Portals[plane]].mPlaneZ;
|
||||
}
|
||||
|
||||
inline DVector2 sector_t::GetPortalDisplacement(int plane)
|
||||
{
|
||||
return level.sectorPortals[Portals[plane]].mDisplacement;
|
||||
}
|
||||
|
||||
inline int sector_t::GetPortalType(int plane)
|
||||
{
|
||||
return level.sectorPortals[Portals[plane]].mType;
|
||||
}
|
||||
|
||||
inline int sector_t::GetOppositePortalGroup(int plane)
|
||||
{
|
||||
return level.sectorPortals[Portals[plane]].mDestination->PortalGroup;
|
||||
}
|
|
@ -51,6 +51,7 @@
|
|||
#include "autosegs.h"
|
||||
#include "version.h"
|
||||
#include "v_text.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
TArray<cluster_info_t> wadclusterinfos;
|
||||
TArray<level_info_t> wadlevelinfos;
|
||||
|
@ -1227,8 +1228,8 @@ MapFlagHandlers[] =
|
|||
{ "smoothlighting", MITYPE_SETFLAG2, LEVEL2_SMOOTHLIGHTING, 0 },
|
||||
{ "noautosequences", MITYPE_SETFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
|
||||
{ "autosequences", MITYPE_CLRFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
|
||||
{ "forcenoskystretch", MITYPE_SETFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
|
||||
{ "skystretch", MITYPE_CLRFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
|
||||
{ "forcenoskystretch", MITYPE_SETFLAG, LEVEL_FORCETILEDSKY, 0 },
|
||||
{ "skystretch", MITYPE_CLRFLAG, LEVEL_FORCETILEDSKY, 0 },
|
||||
{ "allowfreelook", MITYPE_SCFLAGS, LEVEL_FREELOOK_YES, ~LEVEL_FREELOOK_NO },
|
||||
{ "nofreelook", MITYPE_SCFLAGS, LEVEL_FREELOOK_NO, ~LEVEL_FREELOOK_YES },
|
||||
{ "allowjump", MITYPE_CLRFLAG, LEVEL_JUMP_NO, 0 },
|
||||
|
|
|
@ -12,10 +12,6 @@
|
|||
#include "serializer.h"
|
||||
#include "r_data/r_translate.h"
|
||||
|
||||
static FRandom pr_freezedeath ("FreezeDeath");
|
||||
static FRandom pr_freeze ("FreezeDeathChunks");
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// PROC A_NoBlocking
|
||||
|
@ -74,137 +70,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeath
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int t = pr_freezedeath();
|
||||
self->tics = 75+t+pr_freezedeath();
|
||||
self->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_ICECORPSE;
|
||||
self->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE;
|
||||
self->flags3 |= MF3_CRASHED;
|
||||
self->Height = self->GetDefault()->Height;
|
||||
// Remove fuzz effects from frozen actors.
|
||||
if (self->RenderStyle.BlendOp >= STYLEOP_Fuzz && self->RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
|
||||
{
|
||||
self->RenderStyle = STYLE_Normal;
|
||||
}
|
||||
|
||||
S_Sound (self, CHAN_BODY, "misc/freeze", 1, ATTN_NORM);
|
||||
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (self->flags & MF_STEALTH)
|
||||
{
|
||||
self->Alpha = 1;
|
||||
self->visdir = 0;
|
||||
}
|
||||
|
||||
if (self->player)
|
||||
{
|
||||
self->player->damagecount = 0;
|
||||
self->player->poisoncount = 0;
|
||||
self->player->bonuscount = 0;
|
||||
}
|
||||
else if (self->flags3 & MF3_ISMONSTER && self->special)
|
||||
{ // Initiate monster death actions
|
||||
P_ExecuteSpecial(self->special, NULL, self, false, self->args[0],
|
||||
self->args[1], self->args[2], self->args[3], self->args[4]);
|
||||
self->special = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeathChunks
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int i;
|
||||
int numChunks;
|
||||
AActor *mo;
|
||||
|
||||
if (!self->Vel.isZero() && !(self->flags6 & MF6_SHATTERING))
|
||||
{
|
||||
self->tics = 3*TICRATE;
|
||||
return 0;
|
||||
}
|
||||
self->Vel.Zero();
|
||||
S_Sound (self, CHAN_BODY, "misc/icebreak", 1, ATTN_NORM);
|
||||
|
||||
// [RH] In Hexen, this creates a random number of shards (range [24,56])
|
||||
// with no relation to the size of the self shattering. I think it should
|
||||
// base the number of shards on the size of the dead thing, so bigger
|
||||
// things break up into more shards than smaller things.
|
||||
// An actor with radius 20 and height 64 creates ~40 chunks.
|
||||
numChunks = MAX<int>(4, int(self->radius * self->Height)/32);
|
||||
i = (pr_freeze.Random2()) % (numChunks/4);
|
||||
for (i = MAX (24, numChunks + i); i >= 0; i--)
|
||||
{
|
||||
double xo = (pr_freeze() - 128)*self->radius / 128;
|
||||
double yo = (pr_freeze() - 128)*self->radius / 128;
|
||||
double zo = (pr_freeze()*self->Height / 255);
|
||||
|
||||
mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + (pr_freeze()%3));
|
||||
mo->Vel.X = pr_freeze.Random2() / 128.;
|
||||
mo->Vel.Y = pr_freeze.Random2() / 128.;
|
||||
mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4;
|
||||
mo->RenderStyle = self->RenderStyle;
|
||||
mo->Alpha = self->Alpha;
|
||||
}
|
||||
}
|
||||
if (self->player)
|
||||
{ // attach the player's view to a chunk of ice
|
||||
AActor *head = Spawn("IceChunkHead", self->PosPlusZ(self->player->mo->ViewHeight), ALLOW_REPLACE);
|
||||
if (head != NULL)
|
||||
{
|
||||
head->Vel.X = pr_freeze.Random2() / 128.;
|
||||
head->Vel.Y = pr_freeze.Random2() / 128.;
|
||||
head->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4;
|
||||
|
||||
head->health = self->health;
|
||||
head->Angles.Yaw = self->Angles.Yaw;
|
||||
if (head->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
|
||||
{
|
||||
head->player = self->player;
|
||||
head->player->mo = static_cast<APlayerPawn*>(head);
|
||||
self->player = NULL;
|
||||
head->ObtainInventory (self);
|
||||
}
|
||||
head->Angles.Pitch = 0.;
|
||||
head->RenderStyle = self->RenderStyle;
|
||||
head->Alpha = self->Alpha;
|
||||
if (head->player->camera == self)
|
||||
{
|
||||
head->player->camera = head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Do some stuff to make this more useful outside Hexen
|
||||
if (self->flags4 & MF4_BOSSDEATH)
|
||||
{
|
||||
A_BossDeath(self);
|
||||
}
|
||||
A_Unblock(self, true);
|
||||
|
||||
self->SetState(self->FindState(NAME_Null));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// CorpseQueue Routines (used by Hexen)
|
||||
|
@ -219,7 +84,7 @@ class DCorpsePointer : public DThinker
|
|||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
DCorpsePointer (AActor *ptr);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
void Serialize(FSerializer &arc);
|
||||
TObjPtr<AActor> Corpse;
|
||||
DWORD Count; // Only the first corpse pointer's count is valid.
|
||||
|
@ -271,29 +136,33 @@ DCorpsePointer::DCorpsePointer (AActor *ptr)
|
|||
++first->Count;
|
||||
}
|
||||
|
||||
void DCorpsePointer::Destroy ()
|
||||
void DCorpsePointer::OnDestroy ()
|
||||
{
|
||||
// Store the count of corpses in the first thinker in the list
|
||||
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
|
||||
DCorpsePointer *first = iterator.Next ();
|
||||
|
||||
int prevCount = first->Count;
|
||||
|
||||
if (first == this)
|
||||
// During a serialization unwind the thinker list won't be available.
|
||||
if (first != nullptr)
|
||||
{
|
||||
first = iterator.Next ();
|
||||
}
|
||||
int prevCount = first->Count;
|
||||
|
||||
if (first != NULL)
|
||||
{
|
||||
first->Count = prevCount - 1;
|
||||
}
|
||||
if (first == this)
|
||||
{
|
||||
first = iterator.Next();
|
||||
}
|
||||
|
||||
if (first != NULL)
|
||||
{
|
||||
first->Count = prevCount - 1;
|
||||
}
|
||||
|
||||
}
|
||||
if (Corpse != NULL)
|
||||
{
|
||||
Corpse->Destroy ();
|
||||
Corpse->Destroy();
|
||||
}
|
||||
Super::Destroy ();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void DCorpsePointer::Serialize(FSerializer &arc)
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "gi.h"
|
||||
#include "m_random.h"
|
||||
|
||||
static FRandom pr_orbit ("Orbit");
|
||||
|
||||
|
||||
// Custom bridge --------------------------------------------------------
|
||||
/*
|
||||
args[0]: Bridge radius, in mapunits
|
||||
args[1]: Bridge height, in mapunits
|
||||
args[2]: Amount of bridge balls (if 0: Doom bridge)
|
||||
args[3]: Rotation speed of bridge balls, in byte angle per seconds, sorta:
|
||||
Since an arg is only a byte, it can only go from 0 to 255, while ZDoom's
|
||||
BAM go from 0 to 65535. Plus, it needs to be able to go either way. So,
|
||||
up to 128, it goes counterclockwise; 129-255 is clockwise, substracting
|
||||
256 from it to get the angle. A few example values:
|
||||
0: Hexen default
|
||||
11: 15° / seconds
|
||||
21: 30° / seconds
|
||||
32: 45° / seconds
|
||||
64: 90° / seconds
|
||||
128: 180° / seconds
|
||||
192: -90° / seconds
|
||||
223: -45° / seconds
|
||||
233: -30° / seconds
|
||||
244: -15° / seconds
|
||||
This value only matters if args[2] is not zero.
|
||||
args[4]: Rotation radius of bridge balls, in bridge radius %.
|
||||
If 0, use Hexen default: ORBIT_RADIUS, regardless of bridge radius.
|
||||
This value only matters if args[2] is not zero.
|
||||
*/
|
||||
|
||||
class ACustomBridge : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ACustomBridge, AActor)
|
||||
public:
|
||||
void BeginPlay ();
|
||||
void Destroy() override;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ACustomBridge, false, false)
|
||||
|
||||
void ACustomBridge::BeginPlay ()
|
||||
{
|
||||
if (args[2]) // Hexen bridge if there are balls
|
||||
{
|
||||
SetState(SeeState);
|
||||
radius = args[0] ? args[0] : 32;
|
||||
Height = args[1] ? args[1] : 2;
|
||||
}
|
||||
else // No balls? Then a Doom bridge.
|
||||
{
|
||||
radius = args[0] ? args[0] : 36;
|
||||
Height = args[1] ? args[1] : 4;
|
||||
RenderStyle = STYLE_Normal;
|
||||
}
|
||||
}
|
||||
|
||||
void ACustomBridge::Destroy()
|
||||
{
|
||||
// Hexen originally just set a flag to make the bridge balls remove themselves in A_BridgeOrbit.
|
||||
// But this is not safe with custom bridge balls that do not necessarily call that function.
|
||||
// So the best course of action is to look for all bridge balls here and destroy them ourselves.
|
||||
|
||||
TThinkerIterator<AActor> it;
|
||||
AActor *thing;
|
||||
|
||||
while ((thing = it.Next()))
|
||||
{
|
||||
if (thing->target == this)
|
||||
{
|
||||
thing->Destroy();
|
||||
}
|
||||
}
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
// Action functions for the non-Doom bridge --------------------------------
|
||||
|
||||
#define ORBIT_RADIUS 15
|
||||
|
||||
// New bridge stuff
|
||||
// Parent
|
||||
// special1 true == removing from world
|
||||
//
|
||||
// Child
|
||||
// target pointer to center mobj
|
||||
// angle angle of ball
|
||||
|
||||
static void BridgeOrbit(AActor *self)
|
||||
{
|
||||
if (self->target == NULL)
|
||||
{ // Don't crash if somebody spawned this into the world
|
||||
// independantly of a Bridge actor.
|
||||
return;
|
||||
}
|
||||
// Set default values
|
||||
// Every five tics, Hexen moved the ball 3/256th of a revolution.
|
||||
DAngle rotationspeed = 45. / 32 * 3 / 5;
|
||||
double rotationradius = ORBIT_RADIUS;
|
||||
// If the bridge is custom, set non-default values if any.
|
||||
|
||||
// Set angular speed; 1--128: counterclockwise rotation ~=1--180°; 129--255: clockwise rotation ~= 180--1°
|
||||
if (self->target->args[3] > 128) rotationspeed = 45. / 32 * (self->target->args[3] - 256) / TICRATE;
|
||||
else if (self->target->args[3] > 0) rotationspeed = 45. / 32 * (self->target->args[3]) / TICRATE;
|
||||
// Set rotation radius
|
||||
if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / 100);
|
||||
|
||||
self->Angles.Yaw += rotationspeed;
|
||||
self->SetOrigin(self->target->Vec3Angle(rotationradius, self->Angles.Yaw, 0), true);
|
||||
self->floorz = self->target->floorz;
|
||||
self->ceilingz = self->target->ceilingz;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(ABridgeBall, A_BridgeOrbit)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
BridgeOrbit(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ACTION_FUNCTION(ACustomBridge, A_BridgeInit)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_CLASS_DEF(balltype, AActor);
|
||||
|
||||
AActor *ball;
|
||||
|
||||
if (balltype == NULL)
|
||||
{
|
||||
balltype = PClass::FindActor("BridgeBall");
|
||||
}
|
||||
|
||||
DAngle startangle = pr_orbit() * (360./256.);
|
||||
|
||||
// Spawn triad into world -- may be more than a triad now.
|
||||
int ballcount = self->args[2]==0 ? 3 : self->args[2];
|
||||
|
||||
for (int i = 0; i < ballcount; i++)
|
||||
{
|
||||
ball = Spawn(balltype, self->Pos(), ALLOW_REPLACE);
|
||||
ball->Angles.Yaw = startangle + (45./32) * (256/ballcount) * i;
|
||||
ball->target = self;
|
||||
BridgeOrbit(ball);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Invisible bridge --------------------------------------------------------
|
||||
|
||||
class AInvisibleBridge : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AInvisibleBridge, AActor)
|
||||
public:
|
||||
void BeginPlay ();
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AInvisibleBridge, false, false)
|
||||
|
||||
void AInvisibleBridge::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
if (args[0])
|
||||
radius = args[0];
|
||||
if (args[1])
|
||||
Height = args[1];
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@
|
|||
#include "serializer.h"
|
||||
#include "doomdata.h"
|
||||
#include "r_state.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
static double DecalWidth, DecalLeft, DecalRight;
|
||||
static double SpreadZ;
|
||||
|
@ -110,10 +111,10 @@ DBaseDecal::DBaseDecal (const DBaseDecal *basis)
|
|||
{
|
||||
}
|
||||
|
||||
void DBaseDecal::Destroy ()
|
||||
void DBaseDecal::OnDestroy ()
|
||||
{
|
||||
Remove ();
|
||||
Super::Destroy ();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void DBaseDecal::Remove ()
|
||||
|
@ -415,7 +416,7 @@ void DBaseDecal::SpreadLeft (double r, vertex_t *v1, side_t *feelwall, F3DFloor
|
|||
double x = v1->fX();
|
||||
double y = v1->fY();
|
||||
|
||||
feelwall = &sides[feelwall->LeftSide];
|
||||
feelwall = &level.sides[feelwall->LeftSide];
|
||||
GetWallStuff (feelwall, v1, ldx, ldy);
|
||||
double wallsize = Length (ldx, ldy);
|
||||
r += DecalLeft;
|
||||
|
@ -455,7 +456,7 @@ void DBaseDecal::SpreadRight (double r, side_t *feelwall, double wallsize, F3DFl
|
|||
|
||||
while (r > wallsize && feelwall->RightSide != NO_SIDE)
|
||||
{
|
||||
feelwall = &sides[feelwall->RightSide];
|
||||
feelwall = &level.sides[feelwall->RightSide];
|
||||
|
||||
side_t *nextwall = NextWall (feelwall);
|
||||
if (nextwall != NULL && nextwall->LeftSide != NO_SIDE)
|
||||
|
@ -669,10 +670,10 @@ DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, doubl
|
|||
return decal;
|
||||
}
|
||||
|
||||
void DImpactDecal::Destroy ()
|
||||
void DImpactDecal::OnDestroy ()
|
||||
{
|
||||
ImpactCount--;
|
||||
Super::Destroy ();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
CCMD (countdecals)
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
|
||||
#include "a_sharedglobal.h"
|
||||
#include "p_local.h"
|
||||
#include "g_level.h"
|
||||
#include "r_sky.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "b_bot.h"
|
||||
#include "p_checkposition.h"
|
||||
#include "virtual.h"
|
||||
|
||||
IMPLEMENT_CLASS(AFastProjectile, false, false)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// AFastProjectile :: Tick
|
||||
//
|
||||
// Thinker for the ultra-fast projectiles used by Heretic and Hexen
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void AFastProjectile::Tick ()
|
||||
{
|
||||
int i;
|
||||
DVector3 frac;
|
||||
int changexy;
|
||||
|
||||
ClearInterpolation();
|
||||
double oldz = Z();
|
||||
|
||||
if (!(flags5 & MF5_NOTIMEFREEZE))
|
||||
{
|
||||
//Added by MC: Freeze mode.
|
||||
if (bglobal.freeze || level.flags2 & LEVEL2_FROZEN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// [RH] Ripping is a little different than it was in Hexen
|
||||
FCheckPosition tm(!!(flags2 & MF2_RIP));
|
||||
|
||||
int count = 8;
|
||||
if (radius > 0)
|
||||
{
|
||||
while ( fabs(Vel.X) > radius * count || fabs(Vel.Y) > radius * count)
|
||||
{
|
||||
// we need to take smaller steps.
|
||||
count += count;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (changexy)
|
||||
{
|
||||
if (--ripcount <= 0)
|
||||
{
|
||||
tm.LastRipped.Clear(); // [RH] Do rip damage each step, like Hexen
|
||||
}
|
||||
|
||||
if (!P_TryMove (this, Pos() + frac, true, NULL, tm))
|
||||
{ // Blocked move
|
||||
if (!(flags3 & MF3_SKYEXPLODE))
|
||||
{
|
||||
if (tm.ceilingline &&
|
||||
tm.ceilingline->backsector &&
|
||||
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
|
||||
Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline)))
|
||||
{
|
||||
// Hack to prevent missiles exploding against the sky.
|
||||
// Does not handle sky floors.
|
||||
Destroy ();
|
||||
return;
|
||||
}
|
||||
// [RH] Don't explode on horizon lines.
|
||||
if (BlockingLine != NULL && BlockingLine->special == Line_Horizon)
|
||||
{
|
||||
Destroy ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
P_ExplodeMissile (this, BlockingLine, BlockingMobj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
AddZ(frac.Z);
|
||||
UpdateWaterLevel ();
|
||||
oldz = Z();
|
||||
if (oldz <= floorz)
|
||||
{ // Hit the floor
|
||||
|
||||
if (floorpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
|
||||
{
|
||||
// [RH] Just remove the missile without exploding it
|
||||
// if this is a sky floor.
|
||||
Destroy ();
|
||||
return;
|
||||
}
|
||||
|
||||
SetZ(floorz);
|
||||
P_HitFloor (this);
|
||||
P_ExplodeMissile (this, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
if (Top() > ceilingz)
|
||||
{ // Hit the ceiling
|
||||
|
||||
if (ceilingpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
|
||||
{
|
||||
Destroy ();
|
||||
return;
|
||||
}
|
||||
|
||||
SetZ(ceilingz - Height);
|
||||
P_ExplodeMissile (this, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
if (!frac.isZero() && ripcount <= 0)
|
||||
{
|
||||
ripcount = count >> 3;
|
||||
|
||||
// call the scripted 'Effect' method.
|
||||
IFVIRTUAL(AFastProjectile, Effect)
|
||||
{
|
||||
// Without the type cast this picks the 'void *' assignment...
|
||||
VMValue params[1] = { (DObject*)this };
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!CheckNoDelay())
|
||||
return; // freed itself
|
||||
// Advance the state
|
||||
if (tics != -1)
|
||||
{
|
||||
if (tics > 0) tics--;
|
||||
while (!tics)
|
||||
{
|
||||
if (!SetState (state->GetNextState ()))
|
||||
{ // mobj was removed
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include "g_level.h"
|
||||
#include "d_player.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
IMPLEMENT_CLASS(DFlashFader, false, true)
|
||||
|
||||
|
@ -22,10 +23,10 @@ DFlashFader::DFlashFader (float r1, float g1, float b1, float a1,
|
|||
Blends[1][0]=r2; Blends[1][1]=g2; Blends[1][2]=b2; Blends[1][3]=a2;
|
||||
}
|
||||
|
||||
void DFlashFader::Destroy ()
|
||||
void DFlashFader::OnDestroy ()
|
||||
{
|
||||
SetBlend (1.f);
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void DFlashFader::Serialize(FSerializer &arc)
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
** a_fountain.cpp
|
||||
** Actors that make particle fountains
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "p_effect.h"
|
||||
#include "doomdata.h"
|
||||
|
||||
class AParticleFountain : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AParticleFountain, AActor)
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
void Activate (AActor *activator);
|
||||
void Deactivate (AActor *activator);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AParticleFountain, false, false)
|
||||
|
||||
void AParticleFountain::PostBeginPlay ()
|
||||
{
|
||||
Super::PostBeginPlay ();
|
||||
if (!(SpawnFlags & MTF_DORMANT))
|
||||
CallActivate (NULL);
|
||||
}
|
||||
|
||||
void AParticleFountain::Activate (AActor *activator)
|
||||
{
|
||||
Super::Activate (activator);
|
||||
effects &= ~FX_FOUNTAINMASK;
|
||||
effects |= health << FX_FOUNTAINSHIFT;
|
||||
}
|
||||
|
||||
void AParticleFountain::Deactivate (AActor *activator)
|
||||
{
|
||||
Super::Deactivate (activator);
|
||||
effects &= ~FX_FOUNTAINMASK;
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include "g_level.h"
|
||||
#include "r_state.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
static FRandom pr_lightning ("Lightning");
|
||||
|
||||
|
@ -22,8 +23,8 @@ DLightningThinker::DLightningThinker ()
|
|||
LightningFlashCount = 0;
|
||||
NextLightningFlash = ((pr_lightning()&15)+5)*35; // don't flash at level start
|
||||
|
||||
LightningLightLevels.Resize(numsectors);
|
||||
fillshort(&LightningLightLevels[0], numsectors, SHRT_MAX);
|
||||
LightningLightLevels.Resize(level.sectors.Size());
|
||||
fillshort(&LightningLightLevels[0], LightningLightLevels.Size(), SHRT_MAX);
|
||||
}
|
||||
|
||||
DLightningThinker::~DLightningThinker ()
|
||||
|
@ -63,8 +64,8 @@ void DLightningThinker::LightningFlash ()
|
|||
LightningFlashCount--;
|
||||
if (LightningFlashCount)
|
||||
{ // reduce the brightness of the flash
|
||||
tempSec = sectors;
|
||||
for (i = numsectors, j = 0; i > 0; ++j, --i, ++tempSec)
|
||||
tempSec = &level.sectors[0];
|
||||
for (i = level.sectors.Size(), j = 0; i > 0; ++j, --i, ++tempSec)
|
||||
{
|
||||
// [RH] Checking this sector's applicability to lightning now
|
||||
// is not enough to know if we should lower its light level,
|
||||
|
@ -79,15 +80,15 @@ void DLightningThinker::LightningFlash ()
|
|||
}
|
||||
else
|
||||
{ // remove the alternate lightning flash special
|
||||
tempSec = sectors;
|
||||
for (i = numsectors, j = 0; i > 0; ++j, --i, ++tempSec)
|
||||
tempSec = &level.sectors[0];
|
||||
for (i = level.sectors.Size(), j = 0; i > 0; ++j, --i, ++tempSec)
|
||||
{
|
||||
if (LightningLightLevels[j] != SHRT_MAX)
|
||||
{
|
||||
tempSec->SetLightLevel(LightningLightLevels[j]);
|
||||
}
|
||||
}
|
||||
fillshort(&LightningLightLevels[0], numsectors, SHRT_MAX);
|
||||
fillshort(&LightningLightLevels[0], level.sectors.Size(), SHRT_MAX);
|
||||
level.flags &= ~LEVEL_SWAPSKIES;
|
||||
}
|
||||
return;
|
||||
|
@ -95,8 +96,8 @@ void DLightningThinker::LightningFlash ()
|
|||
|
||||
LightningFlashCount = (pr_lightning()&7)+8;
|
||||
flashLight = 200+(pr_lightning()&31);
|
||||
tempSec = sectors;
|
||||
for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec)
|
||||
tempSec = &level.sectors[0];
|
||||
for (i = level.sectors.Size(), j = 0; i > 0; ++j, --i, ++tempSec)
|
||||
{
|
||||
// allow combination of the lightning sector specials with bit masks
|
||||
int special = tempSec->special;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "info.h"
|
||||
#include "a_pickups.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "gstrings.h"
|
||||
#include "p_local.h"
|
||||
#include "gi.h"
|
||||
|
@ -14,8 +13,9 @@
|
|||
#include "serializer.h"
|
||||
#include "p_enemy.h"
|
||||
#include "d_player.h"
|
||||
#include "a_armor.h"
|
||||
#include "r_data/sprites.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "virtual.h"
|
||||
|
||||
static FRandom pr_morphmonst ("MorphMonster");
|
||||
|
||||
|
@ -57,9 +57,9 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
if ((p->mo->GetClass() == spawntype)
|
||||
&& (p->mo->PlayerFlags & PPF_CANSUPERMORPH)
|
||||
&& (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE))
|
||||
&& (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == nullptr))
|
||||
&& (p->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true) == nullptr))
|
||||
{ // Make a super chicken
|
||||
p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
|
||||
p->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
morphed->flags |= actor->flags & (MF_SHADOW|MF_NOGRAVITY);
|
||||
morphed->flags2 |= actor->flags2 & MF2_FLY;
|
||||
morphed->flags3 |= actor->flags3 & MF3_GHOST;
|
||||
AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
|
||||
AActor *eflash = Spawn(((enter_flash) ? enter_flash : PClass::FindActor("TeleportFog")), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
|
||||
actor->player = nullptr;
|
||||
actor->alternative = morphed;
|
||||
actor->flags &= ~(MF_SOLID|MF_SHOOTABLE);
|
||||
|
@ -127,7 +127,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
p->MorphedPlayerClass = spawntype;
|
||||
|
||||
p->MorphStyle = style;
|
||||
p->MorphExitFlash = (exit_flash) ? exit_flash : RUNTIME_CLASS(ATeleportFog);
|
||||
p->MorphExitFlash = (exit_flash) ? exit_flash : PClass::FindActor("TeleportFog");
|
||||
p->health = morphed->health;
|
||||
p->mo = morphed;
|
||||
p->Vel.X = p->Vel.Y = 0;
|
||||
|
@ -136,7 +136,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
for (item = morphed->Inventory; item != nullptr; )
|
||||
{
|
||||
AInventory *next = item->Inventory;
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AArmor)))
|
||||
if (item->IsKindOf (PClass::FindActor(NAME_Armor)))
|
||||
{
|
||||
item->DepleteOrDestroy();
|
||||
}
|
||||
|
@ -157,13 +157,13 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
|
|||
DEFINE_ACTION_FUNCTION(_PlayerInfo, MorphPlayer)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
PARAM_POINTER(victim, player_t);
|
||||
PARAM_POINTER(activator, player_t);
|
||||
PARAM_CLASS(spawntype, APlayerPawn);
|
||||
PARAM_INT(duration);
|
||||
PARAM_INT(style);
|
||||
PARAM_CLASS_DEF(enter_flash, AActor);
|
||||
PARAM_CLASS_DEF(exit_flash, AActor);
|
||||
ACTION_RETURN_BOOL(P_MorphPlayer(self, victim, spawntype, duration, style, enter_flash, exit_flash));
|
||||
ACTION_RETURN_BOOL(P_MorphPlayer(activator, self, spawntype, duration, style, enter_flash, exit_flash));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
|||
player->MorphStyle = 0;
|
||||
player->MorphExitFlash = nullptr;
|
||||
player->viewheight = mo->ViewHeight;
|
||||
AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
|
||||
AInventory *level2 = mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true);
|
||||
if (level2 != nullptr)
|
||||
{
|
||||
level2->Destroy ();
|
||||
|
@ -363,10 +363,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
|
|||
}
|
||||
pmo->Destroy ();
|
||||
// Restore playerclass armor to its normal amount.
|
||||
AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>();
|
||||
auto hxarmor = mo->FindInventory(NAME_HexenArmor);
|
||||
if (hxarmor != nullptr)
|
||||
{
|
||||
hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0];
|
||||
double *Slots = (double*)hxarmor->ScriptVar(NAME_Slots, nullptr);
|
||||
Slots[4] = mo->GetClass()->HexenArmor[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -395,7 +396,7 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st
|
|||
if (actor == NULL || actor->player || spawntype == NULL ||
|
||||
actor->flags3 & MF3_DONTMORPH ||
|
||||
!(actor->flags3 & MF3_ISMONSTER) ||
|
||||
!spawntype->IsDescendantOf (RUNTIME_CLASS(AMorphedMonster)))
|
||||
!spawntype->IsDescendantOf (PClass::FindActor(NAME_MorphedMonster)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -415,7 +416,7 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st
|
|||
|
||||
morphed->UnmorphTime = level.time + ((duration) ? duration : MORPHTICS) + pr_morphmonst();
|
||||
morphed->MorphStyle = style;
|
||||
morphed->MorphExitFlash = (exit_flash) ? exit_flash : RUNTIME_CLASS(ATeleportFog);
|
||||
morphed->MorphExitFlash = (exit_flash) ? exit_flash : PClass::FindActor("TeleportFog");
|
||||
morphed->FlagsSave = actor->flags & ~MF_JUSTHIT;
|
||||
morphed->special = actor->special;
|
||||
memcpy (morphed->args, actor->args, sizeof(actor->args));
|
||||
|
@ -433,12 +434,23 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st
|
|||
actor->flags &= ~(MF_SOLID|MF_SHOOTABLE);
|
||||
actor->flags |= MF_UNMORPHED;
|
||||
actor->renderflags |= RF_INVISIBLE;
|
||||
AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
|
||||
AActor *eflash = Spawn(((enter_flash) ? enter_flash : PClass::FindActor("TeleportFog")), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
|
||||
if (eflash)
|
||||
eflash->target = morphed;
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, MorphMonster)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_CLASS(spawntype, AActor);
|
||||
PARAM_INT(duration);
|
||||
PARAM_INT(style);
|
||||
PARAM_CLASS_DEF(enter_flash, AActor);
|
||||
PARAM_CLASS_DEF(exit_flash, AActor);
|
||||
ACTION_RETURN_BOOL(P_MorphMonster(self, spawntype, duration, style, enter_flash, exit_flash));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// FUNC P_UndoMonsterMorph
|
||||
|
@ -592,11 +604,17 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
|
|||
|
||||
void EndAllPowerupEffects(AInventory *item)
|
||||
{
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf(ptype))
|
||||
{
|
||||
static_cast<APowerup *>(item)->CallEndEffect();
|
||||
IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMFrameStack stack;
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
|
@ -612,60 +630,22 @@ void EndAllPowerupEffects(AInventory *item)
|
|||
|
||||
void InitAllPowerupEffects(AInventory *item)
|
||||
{
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf(ptype))
|
||||
{
|
||||
static_cast<APowerup *>(item)->CallInitEffect();
|
||||
IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMFrameStack stack;
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
}
|
||||
|
||||
// Base class for morphing projectiles --------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(AMorphProjectile, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(AMorphProjectile)
|
||||
IMPLEMENT_POINTER(PlayerClass)
|
||||
IMPLEMENT_POINTER(MonsterClass)
|
||||
IMPLEMENT_POINTER(MorphFlash)
|
||||
IMPLEMENT_POINTER(UnMorphFlash)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
DEFINE_FIELD(AMorphProjectile, PlayerClass)
|
||||
DEFINE_FIELD(AMorphProjectile, MonsterClass)
|
||||
DEFINE_FIELD(AMorphProjectile, MorphFlash)
|
||||
DEFINE_FIELD(AMorphProjectile, UnMorphFlash)
|
||||
DEFINE_FIELD(AMorphProjectile, Duration)
|
||||
DEFINE_FIELD(AMorphProjectile, MorphStyle)
|
||||
|
||||
int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype)
|
||||
{
|
||||
if (target->player)
|
||||
{
|
||||
P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AMorphProjectile::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (AMorphProjectile*)GetDefault();
|
||||
arc("playerclass", PlayerClass, def->PlayerClass)
|
||||
("monsterclass", MonsterClass, def->MonsterClass)
|
||||
("duration", Duration, def->Duration)
|
||||
("morphstyle", MorphStyle, def->MorphStyle)
|
||||
("morphflash", MorphFlash, def->MorphFlash)
|
||||
("unmorphflash", UnMorphFlash, def->UnMorphFlash);
|
||||
}
|
||||
|
||||
|
||||
// Morphed Monster (you must subclass this to do something useful) ---------
|
||||
|
||||
IMPLEMENT_CLASS(AMorphedMonster, false, true)
|
||||
|
@ -689,13 +669,13 @@ void AMorphedMonster::Serialize(FSerializer &arc)
|
|||
("flagsave", FlagsSave);
|
||||
}
|
||||
|
||||
void AMorphedMonster::Destroy ()
|
||||
void AMorphedMonster::OnDestroy ()
|
||||
{
|
||||
if (UnmorphedMe != NULL)
|
||||
{
|
||||
UnmorphedMe->Destroy ();
|
||||
}
|
||||
Super::Destroy ();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void AMorphedMonster::Die (AActor *source, AActor *inflictor, int dmgflags)
|
||||
|
|
|
@ -1,649 +0,0 @@
|
|||
/*
|
||||
** a_movingcamera.cpp
|
||||
** Cameras that move and related neat stuff
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "doomstat.h"
|
||||
#include "serializer.h"
|
||||
|
||||
/*
|
||||
== InterpolationPoint: node along a camera's path
|
||||
==
|
||||
== args[0] = pitch
|
||||
== args[1] = time (in octics) to get here from previous node
|
||||
== args[2] = time (in octics) to stay here before moving to next node
|
||||
== args[3] = low byte of next node's tid
|
||||
== args[4] = high byte of next node's tid
|
||||
*/
|
||||
|
||||
class AInterpolationPoint : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AInterpolationPoint, AActor)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
void BeginPlay ();
|
||||
void HandleSpawnFlags ();
|
||||
void Tick () {} // Nodes do no thinking
|
||||
AInterpolationPoint *ScanForLoop ();
|
||||
void FormChain ();
|
||||
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
TObjPtr<AInterpolationPoint> Next;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AInterpolationPoint, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(AInterpolationPoint)
|
||||
IMPLEMENT_POINTER(Next)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
void AInterpolationPoint::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("next", Next);
|
||||
}
|
||||
|
||||
void AInterpolationPoint::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
Next = NULL;
|
||||
}
|
||||
|
||||
void AInterpolationPoint::HandleSpawnFlags ()
|
||||
{
|
||||
// Spawn flags mean nothing to an interpolation point
|
||||
}
|
||||
|
||||
void AInterpolationPoint::FormChain ()
|
||||
{
|
||||
if (flags & MF_AMBUSH)
|
||||
return;
|
||||
|
||||
flags |= MF_AMBUSH;
|
||||
|
||||
TActorIterator<AInterpolationPoint> iterator (args[3] + 256 * args[4]);
|
||||
Next = iterator.Next ();
|
||||
|
||||
if (Next == this) // Don't link to self
|
||||
Next = iterator.Next ();
|
||||
|
||||
if (Next == NULL && (args[3] | args[4]))
|
||||
Printf ("Can't find target for camera node %d\n", tid);
|
||||
|
||||
Angles.Pitch = (double)clamp<int>((signed char)args[0], -89, 89);
|
||||
|
||||
if (Next != NULL)
|
||||
Next->FormChain ();
|
||||
}
|
||||
|
||||
// Return the node (if any) where a path loops, relative to this one.
|
||||
AInterpolationPoint *AInterpolationPoint::ScanForLoop ()
|
||||
{
|
||||
AInterpolationPoint *node = this;
|
||||
while (node->Next && node->Next != this && node->special1 == 0)
|
||||
{
|
||||
node->special1 = 1;
|
||||
node = node->Next;
|
||||
}
|
||||
return node->Next == this ? node : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
== InterpolationSpecial: Holds a special to execute when a
|
||||
== PathFollower reaches an InterpolationPoint of the same TID.
|
||||
*/
|
||||
|
||||
class AInterpolationSpecial : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AInterpolationSpecial, AActor)
|
||||
public:
|
||||
void Tick () {} // Does absolutely nothing itself
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AInterpolationSpecial, false, false)
|
||||
|
||||
/*
|
||||
== PathFollower: something that follows a camera path
|
||||
== Base class for some moving cameras
|
||||
==
|
||||
== args[0] = low byte of first node in path's tid
|
||||
== args[1] = high byte of first node's tid
|
||||
== args[2] = bit 0 = follow a linear path (rather than curved)
|
||||
== bit 1 = adjust angle
|
||||
== bit 2 = adjust pitch
|
||||
== bit 3 = aim in direction of motion
|
||||
==
|
||||
== Also uses:
|
||||
== target = first node in path
|
||||
== lastenemy = node prior to first node (if looped)
|
||||
*/
|
||||
|
||||
class APathFollower : public AActor
|
||||
{
|
||||
DECLARE_CLASS (APathFollower, AActor)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
void BeginPlay ();
|
||||
void PostBeginPlay ();
|
||||
void Tick ();
|
||||
void Activate (AActor *activator);
|
||||
void Deactivate (AActor *activator);
|
||||
protected:
|
||||
double Splerp (double p1, double p2, double p3, double p4);
|
||||
double Lerp (double p1, double p2);
|
||||
virtual bool Interpolate ();
|
||||
virtual void NewNode ();
|
||||
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
bool bActive, bJustStepped;
|
||||
TObjPtr<AInterpolationPoint> PrevNode, CurrNode;
|
||||
float Time; // Runs from 0.0 to 1.0 between CurrNode and CurrNode->Next
|
||||
int HoldTime;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(APathFollower, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(APathFollower)
|
||||
IMPLEMENT_POINTER(PrevNode)
|
||||
IMPLEMENT_POINTER(CurrNode)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
void APathFollower::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("active", bActive)
|
||||
("juststepped", bJustStepped)
|
||||
("prevnode", PrevNode)
|
||||
("currnode", CurrNode)
|
||||
("time", Time)
|
||||
("holdtime", HoldTime);
|
||||
}
|
||||
|
||||
// Interpolate between p2 and p3 along a Catmull-Rom spline
|
||||
// http://research.microsoft.com/~hollasch/cgindex/curves/catmull-rom.html
|
||||
double APathFollower::Splerp (double p1, double p2, double p3, double p4)
|
||||
{
|
||||
double t = Time;
|
||||
double res = 2*p2;
|
||||
res += (p3 - p1) * Time;
|
||||
t *= Time;
|
||||
res += (2*p1 - 5*p2 + 4*p3 - p4) * t;
|
||||
t *= Time;
|
||||
res += (3*p2 - 3*p3 + p4 - p1) * t;
|
||||
return 0.5f * res;
|
||||
}
|
||||
|
||||
// Linearly interpolate between p1 and p2
|
||||
double APathFollower::Lerp (double p1, double p2)
|
||||
{
|
||||
return p1 + Time * (p2 - p1);
|
||||
}
|
||||
|
||||
void APathFollower::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
PrevNode = CurrNode = NULL;
|
||||
bActive = false;
|
||||
}
|
||||
|
||||
void APathFollower::PostBeginPlay ()
|
||||
{
|
||||
// Find first node of path
|
||||
TActorIterator<AInterpolationPoint> iterator (args[0] + 256 * args[1]);
|
||||
AInterpolationPoint *node = iterator.Next ();
|
||||
AInterpolationPoint *prevnode;
|
||||
|
||||
target = node;
|
||||
|
||||
if (node == NULL)
|
||||
{
|
||||
Printf ("PathFollower %d: Can't find interpolation pt %d\n",
|
||||
tid, args[0] + 256 * args[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify the path has enough nodes
|
||||
node->FormChain ();
|
||||
if (args[2] & 1)
|
||||
{ // linear path; need 2 nodes
|
||||
if (node->Next == NULL)
|
||||
{
|
||||
Printf ("PathFollower %d: Path needs at least 2 nodes\n", tid);
|
||||
return;
|
||||
}
|
||||
lastenemy = NULL;
|
||||
}
|
||||
else
|
||||
{ // spline path; need 4 nodes
|
||||
if (node->Next == NULL ||
|
||||
node->Next->Next == NULL ||
|
||||
node->Next->Next->Next == NULL)
|
||||
{
|
||||
Printf ("PathFollower %d: Path needs at least 4 nodes\n", tid);
|
||||
return;
|
||||
}
|
||||
// If the first node is in a loop, we can start there.
|
||||
// Otherwise, we need to start at the second node in the path.
|
||||
prevnode = node->ScanForLoop ();
|
||||
if (prevnode == NULL || prevnode->Next != node)
|
||||
{
|
||||
lastenemy = target;
|
||||
target = node->Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastenemy = prevnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APathFollower::Deactivate (AActor *activator)
|
||||
{
|
||||
bActive = false;
|
||||
}
|
||||
|
||||
void APathFollower::Activate (AActor *activator)
|
||||
{
|
||||
if (!bActive)
|
||||
{
|
||||
CurrNode = barrier_cast<AInterpolationPoint *>(target);
|
||||
PrevNode = barrier_cast<AInterpolationPoint *>(lastenemy);
|
||||
|
||||
if (CurrNode != NULL)
|
||||
{
|
||||
NewNode ();
|
||||
SetOrigin (CurrNode->Pos(), false);
|
||||
Time = 0.f;
|
||||
HoldTime = 0;
|
||||
bJustStepped = true;
|
||||
bActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APathFollower::Tick ()
|
||||
{
|
||||
if (!bActive)
|
||||
return;
|
||||
|
||||
if (bJustStepped)
|
||||
{
|
||||
bJustStepped = false;
|
||||
if (CurrNode->args[2])
|
||||
{
|
||||
HoldTime = level.time + CurrNode->args[2] * TICRATE / 8;
|
||||
SetXYZ(CurrNode->Pos());
|
||||
}
|
||||
}
|
||||
|
||||
if (HoldTime > level.time)
|
||||
return;
|
||||
|
||||
// Splines must have a previous node.
|
||||
if (PrevNode == NULL && !(args[2] & 1))
|
||||
{
|
||||
bActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// All paths must have a current node.
|
||||
if (CurrNode->Next == NULL)
|
||||
{
|
||||
bActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Interpolate ())
|
||||
{
|
||||
Time += float(8.f / ((double)CurrNode->args[1] * (double)TICRATE));
|
||||
if (Time > 1.f)
|
||||
{
|
||||
Time -= 1.f;
|
||||
bJustStepped = true;
|
||||
PrevNode = CurrNode;
|
||||
CurrNode = CurrNode->Next;
|
||||
if (CurrNode != NULL)
|
||||
NewNode ();
|
||||
if (CurrNode == NULL || CurrNode->Next == NULL)
|
||||
CallDeactivate (this);
|
||||
if ((args[2] & 1) == 0 && CurrNode->Next->Next == NULL)
|
||||
CallDeactivate (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APathFollower::NewNode ()
|
||||
{
|
||||
TActorIterator<AInterpolationSpecial> iterator (CurrNode->tid);
|
||||
AInterpolationSpecial *spec;
|
||||
|
||||
while ( (spec = iterator.Next ()) )
|
||||
{
|
||||
P_ExecuteSpecial(spec->special, NULL, NULL, false, spec->args[0],
|
||||
spec->args[1], spec->args[2], spec->args[3], spec->args[4]);
|
||||
}
|
||||
}
|
||||
|
||||
bool APathFollower::Interpolate ()
|
||||
{
|
||||
DVector3 dpos(0, 0, 0);
|
||||
FLinkContext ctx;
|
||||
|
||||
if ((args[2] & 8) && Time > 0.f)
|
||||
{
|
||||
dpos = Pos();
|
||||
}
|
||||
|
||||
if (CurrNode->Next==NULL) return false;
|
||||
|
||||
UnlinkFromWorld (&ctx);
|
||||
DVector3 newpos;
|
||||
if (args[2] & 1)
|
||||
{ // linear
|
||||
newpos.X = Lerp(CurrNode->X(), CurrNode->Next->X());
|
||||
newpos.Y = Lerp(CurrNode->Y(), CurrNode->Next->Y());
|
||||
newpos.Z = Lerp(CurrNode->Z(), CurrNode->Next->Z());
|
||||
}
|
||||
else
|
||||
{ // spline
|
||||
if (CurrNode->Next->Next==NULL) return false;
|
||||
|
||||
newpos.X = Splerp(PrevNode->X(), CurrNode->X(), CurrNode->Next->X(), CurrNode->Next->Next->X());
|
||||
newpos.Y = Splerp(PrevNode->Y(), CurrNode->Y(), CurrNode->Next->Y(), CurrNode->Next->Next->Y());
|
||||
newpos.Z = Splerp(PrevNode->Z(), CurrNode->Z(), CurrNode->Next->Z(), CurrNode->Next->Next->Z());
|
||||
}
|
||||
SetXYZ(newpos);
|
||||
LinkToWorld (&ctx);
|
||||
|
||||
if (args[2] & 6)
|
||||
{
|
||||
if (args[2] & 8)
|
||||
{
|
||||
if (args[2] & 1)
|
||||
{ // linear
|
||||
dpos.X = CurrNode->Next->X() - CurrNode->X();
|
||||
dpos.Y = CurrNode->Next->Y() - CurrNode->Y();
|
||||
dpos.Z = CurrNode->Next->Z() - CurrNode->Z();
|
||||
}
|
||||
else if (Time > 0.f)
|
||||
{ // spline
|
||||
dpos = newpos - dpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
int realarg = args[2];
|
||||
args[2] &= ~(2|4|8);
|
||||
Time += 0.1f;
|
||||
dpos = newpos;
|
||||
Interpolate ();
|
||||
Time -= 0.1f;
|
||||
args[2] = realarg;
|
||||
dpos = newpos - dpos;
|
||||
newpos -= dpos;
|
||||
SetXYZ(newpos);
|
||||
}
|
||||
if (args[2] & 2)
|
||||
{ // adjust yaw
|
||||
Angles.Yaw = dpos.Angle();
|
||||
}
|
||||
if (args[2] & 4)
|
||||
{ // adjust pitch; use floats for precision
|
||||
double dist = dpos.XY().Length();
|
||||
Angles.Pitch = dist != 0.f ? VecToAngle(dist, -dpos.Z) : 0.;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args[2] & 2)
|
||||
{ // interpolate angle
|
||||
DAngle angle1 = CurrNode->Angles.Yaw.Normalized180();
|
||||
DAngle angle2 = angle1 + deltaangle(angle1, CurrNode->Next->Angles.Yaw);
|
||||
Angles.Yaw = Lerp(angle1.Degrees, angle2.Degrees);
|
||||
}
|
||||
if (args[2] & 1)
|
||||
{ // linear
|
||||
if (args[2] & 4)
|
||||
{ // interpolate pitch
|
||||
Angles.Pitch = Lerp(CurrNode->Angles.Pitch.Degrees, CurrNode->Next->Angles.Pitch.Degrees);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // spline
|
||||
if (args[2] & 4)
|
||||
{ // interpolate pitch
|
||||
Angles.Pitch = Splerp(PrevNode->Angles.Pitch.Degrees, CurrNode->Angles.Pitch.Degrees,
|
||||
CurrNode->Next->Angles.Pitch.Degrees, CurrNode->Next->Next->Angles.Pitch.Degrees);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
== ActorMover: Moves any actor along a camera path
|
||||
==
|
||||
== Same as PathFollower, except
|
||||
== args[2], bit 7: make nonsolid
|
||||
== args[3] = tid of thing to move
|
||||
==
|
||||
== also uses:
|
||||
== tracer = thing to move
|
||||
*/
|
||||
|
||||
class AActorMover : public APathFollower
|
||||
{
|
||||
DECLARE_CLASS (AActorMover, APathFollower)
|
||||
public:
|
||||
void BeginPlay();
|
||||
void PostBeginPlay ();
|
||||
void Activate (AActor *activator);
|
||||
void Deactivate (AActor *activator);
|
||||
protected:
|
||||
bool Interpolate ();
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AActorMover, false, false)
|
||||
|
||||
void AActorMover::BeginPlay()
|
||||
{
|
||||
ChangeStatNum(STAT_ACTORMOVER);
|
||||
}
|
||||
|
||||
void AActorMover::PostBeginPlay ()
|
||||
{
|
||||
Super::PostBeginPlay ();
|
||||
|
||||
TActorIterator<AActor> iterator (args[3]);
|
||||
tracer = iterator.Next ();
|
||||
|
||||
if (tracer == NULL)
|
||||
{
|
||||
Printf ("ActorMover %d: Can't find target %d\n", tid, args[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
special1 = tracer->flags;
|
||||
special2 = tracer->flags2;
|
||||
}
|
||||
}
|
||||
|
||||
bool AActorMover::Interpolate ()
|
||||
{
|
||||
if (tracer == NULL)
|
||||
return true;
|
||||
|
||||
if (Super::Interpolate ())
|
||||
{
|
||||
double savedz = tracer->Z();
|
||||
tracer->SetZ(Z());
|
||||
if (!P_TryMove (tracer, Pos(), true))
|
||||
{
|
||||
tracer->SetZ(savedz);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args[2] & 2)
|
||||
tracer->Angles.Yaw = Angles.Yaw;
|
||||
if (args[2] & 4)
|
||||
tracer->Angles.Pitch = Angles.Pitch;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AActorMover::Activate (AActor *activator)
|
||||
{
|
||||
if (tracer == NULL || bActive)
|
||||
return;
|
||||
|
||||
Super::Activate (activator);
|
||||
special1 = tracer->flags;
|
||||
special2 = tracer->flags2;
|
||||
tracer->flags |= MF_NOGRAVITY;
|
||||
if (args[2] & 128)
|
||||
{
|
||||
FLinkContext ctx;
|
||||
tracer->UnlinkFromWorld (&ctx);
|
||||
tracer->flags |= MF_NOBLOCKMAP;
|
||||
tracer->flags &= ~MF_SOLID;
|
||||
tracer->LinkToWorld (&ctx);
|
||||
}
|
||||
if (tracer->flags3 & MF3_ISMONSTER)
|
||||
{
|
||||
tracer->flags2 |= MF2_INVULNERABLE | MF2_DORMANT;
|
||||
}
|
||||
// Don't let the renderer interpolate between the actor's
|
||||
// old position and its new position.
|
||||
Interpolate ();
|
||||
tracer->ClearInterpolation();
|
||||
}
|
||||
|
||||
void AActorMover::Deactivate (AActor *activator)
|
||||
{
|
||||
if (bActive)
|
||||
{
|
||||
Super::Deactivate (activator);
|
||||
if (tracer != NULL)
|
||||
{
|
||||
FLinkContext ctx;
|
||||
tracer->UnlinkFromWorld (&ctx);
|
||||
tracer->flags = ActorFlags::FromInt (special1);
|
||||
tracer->LinkToWorld (&ctx);
|
||||
tracer->flags2 = ActorFlags2::FromInt (special2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
== MovingCamera: Moves any actor along a camera path
|
||||
==
|
||||
== Same as PathFollower, except
|
||||
== args[3] = tid of thing to look at (0 if none)
|
||||
==
|
||||
== Also uses:
|
||||
== tracer = thing to look at
|
||||
*/
|
||||
|
||||
class AMovingCamera : public APathFollower
|
||||
{
|
||||
DECLARE_CLASS (AMovingCamera, APathFollower)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
protected:
|
||||
bool Interpolate ();
|
||||
|
||||
TObjPtr<AActor> Activator;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AMovingCamera, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(AMovingCamera)
|
||||
IMPLEMENT_POINTER(Activator)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
void AMovingCamera::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("activator", Activator);
|
||||
}
|
||||
|
||||
void AMovingCamera::PostBeginPlay ()
|
||||
{
|
||||
Super::PostBeginPlay ();
|
||||
|
||||
Activator = NULL;
|
||||
if (args[3] != 0)
|
||||
{
|
||||
TActorIterator<AActor> iterator (args[3]);
|
||||
tracer = iterator.Next ();
|
||||
if (tracer == NULL)
|
||||
{
|
||||
Printf ("MovingCamera %d: Can't find thing %d\n", tid, args[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AMovingCamera::Interpolate ()
|
||||
{
|
||||
if (tracer == NULL)
|
||||
return Super::Interpolate ();
|
||||
|
||||
if (Super::Interpolate ())
|
||||
{
|
||||
Angles.Yaw = AngleTo(tracer, true);
|
||||
|
||||
if (args[2] & 4)
|
||||
{ // Also aim camera's pitch;
|
||||
DVector3 diff = Pos() - tracer->PosPlusZ(tracer->Height / 2);
|
||||
double dist = diff.XY().Length();
|
||||
Angles.Pitch = dist != 0.f ? VecToAngle(dist, diff.Z) : 0.;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -124,7 +124,7 @@ void DEarthquake::Tick ()
|
|||
{
|
||||
if (pr_quake() < 50)
|
||||
{
|
||||
P_DamageMobj (victim, NULL, NULL, pr_quake.HitDice (1), NAME_None);
|
||||
P_DamageMobj (victim, NULL, NULL, pr_quake.HitDice (1), NAME_Quake);
|
||||
}
|
||||
// Thrust player around
|
||||
DAngle an = victim->Angles.Yaw + pr_quake();
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
** a_randomspawner.cpp
|
||||
** A thing that randomly spawns one item in a list of many, before disappearing.
|
||||
** bouncecount is used to keep track of recursions (so as to prevent infinite loops).
|
||||
** Species is used to store the index of the spawned actor's name.
|
||||
*/
|
||||
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "m_random.h"
|
||||
#include "p_local.h"
|
||||
#include "p_enemy.h"
|
||||
#include "s_sound.h"
|
||||
#include "statnums.h"
|
||||
#include "gstrings.h"
|
||||
#include "v_text.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomdata.h"
|
||||
|
||||
#define MAX_RANDOMSPAWNERS_RECURSION 32 // Should be largely more than enough, honestly.
|
||||
static FRandom pr_randomspawn("RandomSpawn");
|
||||
|
||||
static bool IsMonster(DDropItem *di)
|
||||
{
|
||||
const PClass *pclass = PClass::FindClass(di->Name);
|
||||
|
||||
if (NULL == pclass)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0 != (GetDefaultByType(pclass)->flags3 & MF3_ISMONSTER);
|
||||
}
|
||||
|
||||
class ARandomSpawner : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ARandomSpawner, AActor)
|
||||
|
||||
// To handle "RandomSpawning" missiles, the code has to be split in two parts.
|
||||
// If the following code is not done in BeginPlay, missiles will use the
|
||||
// random spawner's velocity (0...) instead of their own.
|
||||
void BeginPlay()
|
||||
{
|
||||
DDropItem *di; // di will be our drop item list iterator
|
||||
DDropItem *drop; // while drop stays as the reference point.
|
||||
int n = 0;
|
||||
bool nomonsters = (dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS);
|
||||
|
||||
Super::BeginPlay();
|
||||
drop = di = GetDropItems();
|
||||
if (di != NULL)
|
||||
{
|
||||
while (di != NULL)
|
||||
{
|
||||
if (di->Name != NAME_None)
|
||||
{
|
||||
if (!nomonsters || !IsMonster(di))
|
||||
{
|
||||
if (di->Amount < 0) di->Amount = 1; // default value is -1, we need a positive value.
|
||||
n += di->Amount; // this is how we can weight the list.
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
{ // Nothing left to spawn. They must have all been monsters, and monsters are disabled.
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
// Then we reset the iterator to the start position...
|
||||
di = drop;
|
||||
// Take a random number...
|
||||
n = pr_randomspawn(n);
|
||||
// And iterate in the array up to the random number chosen.
|
||||
while (n > -1 && di != NULL)
|
||||
{
|
||||
if (di->Name != NAME_None &&
|
||||
(!nomonsters || !IsMonster(di)))
|
||||
{
|
||||
n -= di->Amount;
|
||||
if ((di->Next != NULL) && (n > -1))
|
||||
di = di->Next;
|
||||
else
|
||||
n = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
// So now we can spawn the dropped item.
|
||||
if (di == NULL || bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions
|
||||
{
|
||||
Spawn("Unknown", Pos(), NO_REPLACE); // Show that there's a problem.
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
else if (pr_randomspawn() <= di->Probability) // prob 255 = always spawn, prob 0 = almost never spawn.
|
||||
{
|
||||
// Handle replacement here so as to get the proper speed and flags for missiles
|
||||
PClassActor *cls;
|
||||
cls = PClass::FindActor(di->Name);
|
||||
if (cls != NULL)
|
||||
{
|
||||
PClassActor *rep = cls->GetReplacement();
|
||||
if (rep != NULL)
|
||||
{
|
||||
cls = rep;
|
||||
}
|
||||
}
|
||||
if (cls != NULL)
|
||||
{
|
||||
Species = cls->TypeName;
|
||||
AActor *defmobj = GetDefaultByType(cls);
|
||||
this->Speed = defmobj->Speed;
|
||||
this->flags |= (defmobj->flags & MF_MISSILE);
|
||||
this->flags2 |= (defmobj->flags2 & MF2_SEEKERMISSILE);
|
||||
this->flags4 |= (defmobj->flags4 & MF4_SPECTRAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Unknown item class %s to drop from a random spawner\n", di->Name.GetChars());
|
||||
Species = NAME_None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The second half of random spawning. Now that the spawner is initialized, the
|
||||
// real actor can be created. If the following code were in BeginPlay instead,
|
||||
// missiles would not have yet obtained certain information that is absolutely
|
||||
// necessary to them -- such as their source and destination.
|
||||
void PostBeginPlay()
|
||||
{
|
||||
Super::PostBeginPlay();
|
||||
|
||||
AActor *newmobj = NULL;
|
||||
bool boss = false;
|
||||
|
||||
if (Species == NAME_None)
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
PClassActor *cls = PClass::FindActor(Species);
|
||||
if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile.
|
||||
{
|
||||
if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE))
|
||||
{
|
||||
tracer = target->target;
|
||||
}
|
||||
newmobj = P_SpawnMissileXYZ(Pos(), target, target->target, cls, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
newmobj = Spawn(cls, Pos(), NO_REPLACE);
|
||||
}
|
||||
if (newmobj != NULL)
|
||||
{
|
||||
// copy everything relevant
|
||||
newmobj->SpawnAngle = SpawnAngle;
|
||||
newmobj->Angles = Angles;
|
||||
newmobj->SpawnPoint = SpawnPoint;
|
||||
newmobj->special = special;
|
||||
newmobj->args[0] = args[0];
|
||||
newmobj->args[1] = args[1];
|
||||
newmobj->args[2] = args[2];
|
||||
newmobj->args[3] = args[3];
|
||||
newmobj->args[4] = args[4];
|
||||
newmobj->special1 = special1;
|
||||
newmobj->special2 = special2;
|
||||
newmobj->SpawnFlags = SpawnFlags & ~MTF_SECRET; // MTF_SECRET needs special treatment to avoid incrementing the secret counter twice. It had already been processed for the spawner itself.
|
||||
newmobj->HandleSpawnFlags();
|
||||
newmobj->SpawnFlags = SpawnFlags;
|
||||
newmobj->tid = tid;
|
||||
newmobj->AddToHash();
|
||||
newmobj->Vel = Vel;
|
||||
newmobj->master = master; // For things such as DamageMaster/DamageChildren, transfer mastery.
|
||||
newmobj->target = target;
|
||||
newmobj->tracer = tracer;
|
||||
newmobj->CopyFriendliness(this, false);
|
||||
// This handles things such as projectiles with the MF4_SPECTRAL flag that have
|
||||
// a health set to -2 after spawning, for internal reasons.
|
||||
if (health != SpawnHealth()) newmobj->health = health;
|
||||
if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED;
|
||||
// Handle special altitude flags
|
||||
if (newmobj->flags & MF_SPAWNCEILING)
|
||||
{
|
||||
newmobj->SetZ(newmobj->ceilingz - newmobj->Height - SpawnPoint.Z);
|
||||
}
|
||||
else if (newmobj->flags2 & MF2_SPAWNFLOAT)
|
||||
{
|
||||
double space = newmobj->ceilingz - newmobj->Height - newmobj->floorz;
|
||||
if (space > 48)
|
||||
{
|
||||
space -= 40;
|
||||
newmobj->SetZ((space * pr_randomspawn()) / 256. + newmobj->floorz + 40);
|
||||
}
|
||||
newmobj->AddZ(SpawnPoint.Z);
|
||||
}
|
||||
if (newmobj->flags & MF_MISSILE)
|
||||
P_CheckMissileSpawn(newmobj, 0);
|
||||
// Bouncecount is used to count how many recursions we're in.
|
||||
if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner")))
|
||||
newmobj->bouncecount = ++bouncecount;
|
||||
// If the spawned actor has either of those flags, it's a boss.
|
||||
if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS))
|
||||
boss = true;
|
||||
// If a replaced actor has either of those same flags, it's also a boss.
|
||||
AActor *rep = GetDefaultByType(GetClass()->GetReplacee());
|
||||
if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS)))
|
||||
boss = true;
|
||||
}
|
||||
if (boss)
|
||||
this->tracer = newmobj;
|
||||
else // "else" because a boss-replacing spawner must wait until it can call A_BossDeath.
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Tick() // This function is needed for handling boss replacers
|
||||
{
|
||||
Super::Tick();
|
||||
if (tracer == NULL || tracer->health <= 0)
|
||||
{
|
||||
A_BossDeath(this);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ARandomSpawner, false, false)
|
|
@ -1,337 +0,0 @@
|
|||
/*
|
||||
** a_sectoraction.cpp
|
||||
** Actors that hold specials to be executed upon conditions in a sector
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "r_defs.h"
|
||||
#include "p_lnspec.h"
|
||||
|
||||
// The base class for sector actions ----------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(ASectorAction, false, false)
|
||||
|
||||
ASectorAction::ASectorAction (bool activatedByUse) :
|
||||
ActivatedByUse (activatedByUse) {}
|
||||
|
||||
bool ASectorAction::IsActivatedByUse() const
|
||||
{
|
||||
return ActivatedByUse;
|
||||
}
|
||||
|
||||
void ASectorAction::Destroy ()
|
||||
{
|
||||
if (Sector != nullptr)
|
||||
{
|
||||
// Remove ourself from this sector's list of actions
|
||||
AActor *probe = Sector->SecActTarget;
|
||||
union
|
||||
{
|
||||
AActor **act;
|
||||
ASectorAction **secact;
|
||||
} prev;
|
||||
prev.secact = &Sector->SecActTarget;
|
||||
|
||||
while (probe && probe != this)
|
||||
{
|
||||
prev.act = &probe->tracer;
|
||||
probe = probe->tracer;
|
||||
}
|
||||
if (probe != nullptr)
|
||||
{
|
||||
*prev.act = probe->tracer;
|
||||
}
|
||||
Sector = nullptr;
|
||||
}
|
||||
|
||||
Super::Destroy ();
|
||||
}
|
||||
|
||||
void ASectorAction::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
|
||||
// Add ourself to this sector's list of actions
|
||||
tracer = Sector->SecActTarget;
|
||||
Sector->SecActTarget = this;
|
||||
}
|
||||
|
||||
void ASectorAction::Activate (AActor *source)
|
||||
{
|
||||
flags2 &= ~MF2_DORMANT; // Projectiles cannot trigger
|
||||
}
|
||||
|
||||
void ASectorAction::Deactivate (AActor *source)
|
||||
{
|
||||
flags2 |= MF2_DORMANT; // Projectiles can trigger
|
||||
}
|
||||
|
||||
bool ASectorAction::TriggerAction(AActor *triggerer, int activationType)
|
||||
{
|
||||
if (DoTriggerAction(triggerer, activationType))
|
||||
{
|
||||
if (flags4 & MF4_STANDSTILL)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
if (tracer != NULL)
|
||||
return barrier_cast<ASectorAction *>(tracer)->DoTriggerAction (triggerer, activationType);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASectorAction::CanTrigger (AActor *triggerer) const
|
||||
{
|
||||
return special &&
|
||||
((triggerer->player && !(flags & MF_FRIENDLY)) ||
|
||||
((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
|
||||
((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)));
|
||||
}
|
||||
|
||||
bool ASectorAction::CheckTrigger (AActor *triggerer) const
|
||||
{
|
||||
if (CanTrigger(triggerer))
|
||||
{
|
||||
bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1],
|
||||
args[2], args[3], args[4]);
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Triggered when entering sector -------------------------------------------
|
||||
|
||||
class ASecActEnter : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActEnter, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActEnter, false, false)
|
||||
|
||||
|
||||
bool ASecActEnter::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_Enter) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when leaving sector --------------------------------------------
|
||||
|
||||
class ASecActExit : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActExit, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActExit, false, false)
|
||||
|
||||
|
||||
bool ASecActExit::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_Exit) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when hitting sector's floor ------------------------------------
|
||||
|
||||
class ASecActHitFloor : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActHitFloor, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
// Skull Tag uses 9999 for a special that is triggered whenever
|
||||
// the player is on the sector's floor. I think this is more useful.
|
||||
|
||||
IMPLEMENT_CLASS(ASecActHitFloor, false, false)
|
||||
|
||||
|
||||
bool ASecActHitFloor::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_HitFloor) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when hitting sector's ceiling ----------------------------------
|
||||
|
||||
class ASecActHitCeil : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActHitCeil, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActHitCeil, false, false)
|
||||
|
||||
|
||||
bool ASecActHitCeil::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_HitCeiling) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when using inside sector ---------------------------------------
|
||||
|
||||
class ASecActUse : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActUse, ASectorAction)
|
||||
public:
|
||||
ASecActUse() : ASectorAction (true) {}
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActUse, false, false)
|
||||
|
||||
|
||||
bool ASecActUse::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_Use) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when using a sector's wall -------------------------------------
|
||||
|
||||
class ASecActUseWall : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActUseWall, ASectorAction)
|
||||
public:
|
||||
ASecActUseWall() : ASectorAction (true) {}
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActUseWall, false, false)
|
||||
|
||||
|
||||
bool ASecActUseWall::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_UseWall) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when eyes go below fake floor ----------------------------------
|
||||
|
||||
class ASecActEyesDive : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActEyesDive, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActEyesDive, false, false)
|
||||
|
||||
|
||||
bool ASecActEyesDive::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_EyesDive) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when eyes go above fake floor ----------------------------------
|
||||
|
||||
class ASecActEyesSurface : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActEyesSurface, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActEyesSurface, false, false)
|
||||
|
||||
|
||||
bool ASecActEyesSurface::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_EyesSurface) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when eyes go below fake floor ----------------------------------
|
||||
|
||||
class ASecActEyesBelowC : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActEyesBelowC, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActEyesBelowC, false, false)
|
||||
|
||||
|
||||
bool ASecActEyesBelowC::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_EyesBelowC) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when eyes go above fake floor ----------------------------------
|
||||
|
||||
class ASecActEyesAboveC : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActEyesAboveC, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActEyesAboveC, false, false)
|
||||
|
||||
|
||||
bool ASecActEyesAboveC::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_EyesAboveC) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
||||
|
||||
// Triggered when eyes go below fake floor ----------------------------------
|
||||
|
||||
class ASecActHitFakeFloor : public ASectorAction
|
||||
{
|
||||
DECLARE_CLASS (ASecActHitFakeFloor, ASectorAction)
|
||||
public:
|
||||
bool DoTriggerAction (AActor *triggerer, int activationType);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASecActHitFakeFloor, false, false)
|
||||
|
||||
|
||||
bool ASecActHitFakeFloor::DoTriggerAction (AActor *triggerer, int activationType)
|
||||
{
|
||||
bool didit = (activationType & SECSPAC_HitFakeFloor) ? CheckTrigger (triggerer) : false;
|
||||
return didit | Super::DoTriggerAction (triggerer, activationType);
|
||||
}
|
|
@ -24,7 +24,7 @@ public:
|
|||
DBaseDecal (const DBaseDecal *basis);
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
FTextureID StickToWall(side_t *wall, double x, double y, F3DFloor * ffloor);
|
||||
double GetRealZ (const side_t *wall) const;
|
||||
void SetShade (DWORD rgb);
|
||||
|
@ -66,7 +66,7 @@ public:
|
|||
static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
|
||||
|
||||
void BeginPlay ();
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
protected:
|
||||
DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const;
|
||||
|
@ -76,38 +76,6 @@ private:
|
|||
DImpactDecal();
|
||||
};
|
||||
|
||||
class ATeleportFog : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ATeleportFog, AActor)
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
};
|
||||
|
||||
class ASkyViewpoint : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASkyViewpoint, AActor)
|
||||
public:
|
||||
void BeginPlay ();
|
||||
void Destroy() override;
|
||||
};
|
||||
|
||||
// For an EE compatible linedef based definition.
|
||||
class ASkyCamCompat : public ASkyViewpoint
|
||||
{
|
||||
DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint)
|
||||
|
||||
public:
|
||||
void BeginPlay();
|
||||
};
|
||||
|
||||
|
||||
class AStackPoint : public ASkyViewpoint
|
||||
{
|
||||
DECLARE_CLASS (AStackPoint, ASkyViewpoint)
|
||||
public:
|
||||
void BeginPlay ();
|
||||
};
|
||||
|
||||
class DFlashFader : public DThinker
|
||||
{
|
||||
DECLARE_CLASS (DFlashFader, DThinker)
|
||||
|
@ -116,7 +84,7 @@ public:
|
|||
DFlashFader (float r1, float g1, float b1, float a1,
|
||||
float r2, float g2, float b2, float a2,
|
||||
float time, AActor *who);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
void Serialize(FSerializer &arc);
|
||||
void Tick ();
|
||||
AActor *WhoFor() { return ForWho; }
|
||||
|
@ -184,20 +152,6 @@ private:
|
|||
DEarthquake ();
|
||||
};
|
||||
|
||||
class AMorphProjectile : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AMorphProjectile, AActor)
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
PClassPlayerPawn *PlayerClass;
|
||||
PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash;
|
||||
int Duration, MorphStyle;
|
||||
};
|
||||
|
||||
class AMorphedMonster : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AMorphedMonster, AActor)
|
||||
|
@ -207,7 +161,7 @@ public:
|
|||
|
||||
void Serialize(FSerializer &arc);
|
||||
void Die (AActor *source, AActor *inflictor, int dmgflags);
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
TObjPtr<AActor> UnmorphedMe;
|
||||
int UnmorphTime, MorphStyle;
|
||||
|
@ -215,12 +169,4 @@ public:
|
|||
ActorFlags FlagsSave;
|
||||
};
|
||||
|
||||
class AFastProjectile : public AActor
|
||||
{
|
||||
DECLARE_CLASS(AFastProjectile, AActor)
|
||||
public:
|
||||
void Tick ();
|
||||
};
|
||||
|
||||
|
||||
#endif //__A_SHAREDGLOBAL_H__
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
** a_skies.cpp
|
||||
** Skybox-related actors
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "actor.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "r_sky.h"
|
||||
#include "r_state.h"
|
||||
#include "portal.h"
|
||||
|
||||
// arg0 = Visibility*4 for this skybox
|
||||
|
||||
IMPLEMENT_CLASS(ASkyViewpoint, false, false)
|
||||
|
||||
// If this actor has no TID, make it the default sky box
|
||||
void ASkyViewpoint::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
|
||||
if (tid == 0 && sectorPortals[0].mSkybox == nullptr)
|
||||
{
|
||||
sectorPortals[0].mSkybox = this;
|
||||
sectorPortals[0].mDestination = Sector;
|
||||
}
|
||||
}
|
||||
|
||||
void ASkyViewpoint::Destroy ()
|
||||
{
|
||||
// remove all sector references to ourselves.
|
||||
for (auto &s : sectorPortals)
|
||||
{
|
||||
if (s.mSkybox == this)
|
||||
{
|
||||
s.mSkybox = 0;
|
||||
// This is necessary to entirely disable EE-style skyboxes
|
||||
// if their viewpoint gets deleted.
|
||||
s.mFlags |= PORTSF_SKYFLATONLY;
|
||||
}
|
||||
}
|
||||
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(ASkyCamCompat, false, false)
|
||||
|
||||
void ASkyCamCompat::BeginPlay()
|
||||
{
|
||||
// Do not call the SkyViewpoint's super method because it would trash our setup
|
||||
AActor::BeginPlay();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// arg0 = tid of matching SkyViewpoint
|
||||
// A value of 0 means to use a regular stretched texture, in case
|
||||
// there is a default SkyViewpoint in the level.
|
||||
//
|
||||
// arg1 = 0: set both floor and ceiling skybox
|
||||
// = 1: set only ceiling skybox
|
||||
// = 2: set only floor skybox
|
||||
|
||||
class ASkyPicker : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASkyPicker, AActor)
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASkyPicker, false, false)
|
||||
|
||||
void ASkyPicker::PostBeginPlay ()
|
||||
{
|
||||
ASkyViewpoint *box;
|
||||
Super::PostBeginPlay ();
|
||||
|
||||
if (args[0] == 0)
|
||||
{
|
||||
box = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TActorIterator<ASkyViewpoint> iterator (args[0]);
|
||||
box = iterator.Next ();
|
||||
}
|
||||
|
||||
if (box == NULL && args[0] != 0)
|
||||
{
|
||||
Printf ("Can't find SkyViewpoint %d for sector %td\n", args[0], Sector - sectors);
|
||||
}
|
||||
else
|
||||
{
|
||||
int boxindex = P_GetSkyboxPortal(box);
|
||||
// Do not override special portal types, only regular skies.
|
||||
if (0 == (args[1] & 2))
|
||||
{
|
||||
if (Sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT)
|
||||
Sector->Portals[sector_t::ceiling] = boxindex;
|
||||
}
|
||||
if (0 == (args[1] & 1))
|
||||
{
|
||||
if (Sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT)
|
||||
Sector->Portals[sector_t::floor] = boxindex;
|
||||
}
|
||||
}
|
||||
Destroy ();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Stacked sectors.
|
||||
|
||||
// arg0 = opacity of plane; 0 = invisible, 255 = fully opaque
|
||||
|
||||
IMPLEMENT_CLASS(AStackPoint, false, false)
|
||||
|
||||
void AStackPoint::BeginPlay ()
|
||||
{
|
||||
// Skip SkyViewpoint's initialization
|
||||
AActor::BeginPlay ();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class ASectorSilencer : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASectorSilencer, AActor)
|
||||
public:
|
||||
void BeginPlay ();
|
||||
void Destroy() override;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASectorSilencer, false, false)
|
||||
|
||||
void ASectorSilencer::BeginPlay ()
|
||||
{
|
||||
Super::BeginPlay ();
|
||||
Sector->Flags |= SECF_SILENT;
|
||||
}
|
||||
|
||||
void ASectorSilencer::Destroy ()
|
||||
{
|
||||
if (Sector != nullptr)
|
||||
{
|
||||
Sector->Flags &= ~SECF_SILENT;
|
||||
}
|
||||
Super::Destroy ();
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
** a_soundenvironment.cpp
|
||||
** Actor that controls the reverb settings in its zone
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "info.h"
|
||||
#include "r_defs.h"
|
||||
#include "s_sound.h"
|
||||
#include "r_state.h"
|
||||
|
||||
class ASoundEnvironment : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASoundEnvironment, AActor)
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
void Deactivate (AActor *activator);
|
||||
void Activate (AActor *deactivator);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASoundEnvironment, false, false)
|
||||
|
||||
void ASoundEnvironment::PostBeginPlay ()
|
||||
{
|
||||
Super::PostBeginPlay ();
|
||||
if (!(flags2 & MF2_DORMANT))
|
||||
{
|
||||
CallActivate (this);
|
||||
}
|
||||
}
|
||||
|
||||
void ASoundEnvironment::Activate (AActor *activator)
|
||||
{
|
||||
Zones[Sector->ZoneNumber].Environment = S_FindEnvironment ((args[0]<<8) | (args[1]));
|
||||
}
|
||||
|
||||
// Deactivate just exists so that you can flag the thing as dormant in an editor
|
||||
// and not have it take effect. This is so you can use multiple environments in
|
||||
// a single zone, with only one set not-dormant, so you know which one will take
|
||||
// effect at the start.
|
||||
void ASoundEnvironment::Deactivate (AActor *deactivator)
|
||||
{
|
||||
flags2 |= MF2_DORMANT;
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
** a_soundsequence.cpp
|
||||
** Actors for independantly playing sound sequences in a map.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** A SoundSequence actor has two modes of operation:
|
||||
**
|
||||
** 1. If the sound sequence assigned to it has a slot, then a separate
|
||||
** SoundSequenceSlot actor is spawned (if not already present), and
|
||||
** this actor's sound sequence is added to its list of choices. This
|
||||
** actor is then destroyed, never to be heard from again. The sound
|
||||
** sequence for the slot is automatically played on the new
|
||||
** SoundSequenceSlot actor, and it should at some point execute the
|
||||
** randomsequence command so that it can pick one of the other
|
||||
** sequences to play. The slot sequence should also end with restart
|
||||
** so that more than one sequence will have a chance to play.
|
||||
**
|
||||
** In this mode, it is very much like world $ambient sounds defined
|
||||
** in SNDINFO but more flexible.
|
||||
**
|
||||
** 2. If the sound sequence assigned to it has no slot, then it will play
|
||||
** the sequence when activated and cease playing the sequence when
|
||||
** deactivated.
|
||||
**
|
||||
** In this mode, it is very much like point $ambient sounds defined
|
||||
** in SNDINFO but more flexible.
|
||||
**
|
||||
** To assign a sound sequence, set the SoundSequence's first argument to
|
||||
** the ID of the corresponding environment sequence you want to use. If
|
||||
** that sequence is a multiple-choice sequence, then the second argument
|
||||
** selects which choice it picks.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "s_sound.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sndseq.h"
|
||||
#include "serializer.h"
|
||||
|
||||
// SoundSequenceSlot --------------------------------------------------------
|
||||
|
||||
class ASoundSequenceSlot : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASoundSequenceSlot, AActor)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
||||
void Serialize(FSerializer &arc);
|
||||
|
||||
TObjPtr<DSeqNode> Sequence;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASoundSequenceSlot, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(ASoundSequenceSlot)
|
||||
IMPLEMENT_POINTER(Sequence)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequenceSlot :: Serialize
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequenceSlot::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("sequence", Sequence);
|
||||
}
|
||||
|
||||
// SoundSequence ------------------------------------------------------------
|
||||
|
||||
class ASoundSequence : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ASoundSequence, AActor)
|
||||
public:
|
||||
void Destroy() override;
|
||||
void PostBeginPlay ();
|
||||
void Activate (AActor *activator);
|
||||
void Deactivate (AActor *activator);
|
||||
void MarkPrecacheSounds () const;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ASoundSequence, false, false)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequence :: Destroy
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequence::Destroy ()
|
||||
{
|
||||
SN_StopSequence (this);
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequence :: PostBeginPlay
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequence::PostBeginPlay ()
|
||||
{
|
||||
FName slot = SN_GetSequenceSlot (args[0], SEQ_ENVIRONMENT);
|
||||
|
||||
if (slot != NAME_None)
|
||||
{ // This is a slotted sound, so add it to the master for that slot
|
||||
ASoundSequenceSlot *master;
|
||||
TThinkerIterator<ASoundSequenceSlot> locator;
|
||||
|
||||
while (NULL != (master = locator.Next ()))
|
||||
{
|
||||
if (master->Sequence->GetSequenceName() == slot)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (master == NULL)
|
||||
{
|
||||
master = Spawn<ASoundSequenceSlot> ();
|
||||
master->Sequence = SN_StartSequence (master, slot, 0);
|
||||
GC::WriteBarrier(master, master->Sequence);
|
||||
}
|
||||
master->Sequence->AddChoice (args[0], SEQ_ENVIRONMENT);
|
||||
Destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequence :: MarkPrecacheSounds
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequence::MarkPrecacheSounds() const
|
||||
{
|
||||
Super::MarkPrecacheSounds();
|
||||
SN_MarkPrecacheSounds(args[0], SEQ_ENVIRONMENT);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequence :: Activate
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequence::Activate (AActor *activator)
|
||||
{
|
||||
SN_StartSequence (this, args[0], SEQ_ENVIRONMENT, args[1]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ASoundSequence :: Deactivate
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ASoundSequence::Deactivate (AActor *activator)
|
||||
{
|
||||
SN_StopSequence (this);
|
||||
}
|
|
@ -220,13 +220,13 @@ DSpotState::DSpotState ()
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void DSpotState::Destroy ()
|
||||
void DSpotState::OnDestroy ()
|
||||
{
|
||||
SpotLists.Clear();
|
||||
SpotLists.ShrinkToFit();
|
||||
|
||||
SpotState = NULL;
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -389,11 +389,11 @@ void ASpecialSpot::BeginPlay()
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void ASpecialSpot::Destroy()
|
||||
void ASpecialSpot::OnDestroy()
|
||||
{
|
||||
DSpotState *state = DSpotState::GetSpotState(false);
|
||||
if (state != NULL) state->RemoveSpot(this);
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
// Mace spawn spot ----------------------------------------------------------
|
||||
|
|
|
@ -11,7 +11,7 @@ class ASpecialSpot : public AActor
|
|||
public:
|
||||
|
||||
void BeginPlay();
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
|
||||
DSpotState ();
|
||||
void Destroy() override;
|
||||
void OnDestroy() override;
|
||||
void Tick ();
|
||||
static DSpotState *GetSpotState(bool create = true);
|
||||
FSpotList *FindSpotList(PClassActor *type);
|
||||
|
|
|
@ -457,7 +457,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
|
|||
{
|
||||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_CleanNoMove, clean,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -466,7 +466,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
|
|||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
|
||||
DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_RenderStyle, Style,
|
||||
DTA_KeepRatio, true,
|
||||
TAG_DONE);
|
||||
|
@ -481,7 +481,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
|
|||
DTA_ClipRight, ClipRight,
|
||||
DTA_ClipTop, ClipTop,
|
||||
DTA_ClipBottom, ClipBot,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -560,7 +560,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
|
|||
{
|
||||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_CleanNoMove, clean,
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
|
|||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
|
||||
DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
DTA_KeepRatio, true,
|
||||
TAG_DONE);
|
||||
|
@ -584,7 +584,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
|
|||
DTA_ClipRight, ClipRight,
|
||||
DTA_ClipTop, ClipTop,
|
||||
DTA_ClipBottom, ClipBot,
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -660,7 +660,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
|
|||
{
|
||||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_CleanNoMove, clean,
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -669,7 +669,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
|
|||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
|
||||
DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
DTA_KeepRatio, true,
|
||||
TAG_DONE);
|
||||
|
@ -684,7 +684,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
|
|||
DTA_ClipRight, ClipRight,
|
||||
DTA_ClipTop, ClipTop,
|
||||
DTA_ClipBottom, ClipBot,
|
||||
DTA_AlphaF, trans,
|
||||
DTA_Alpha, trans,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -842,7 +842,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
|
|||
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
|
||||
DTA_CleanNoMove, clean,
|
||||
DTA_TextLen, LineVisible,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -853,7 +853,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
|
|||
DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
|
||||
DTA_KeepRatio, true,
|
||||
DTA_TextLen, LineVisible,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
@ -867,7 +867,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
|
|||
DTA_ClipRight, ClipRight,
|
||||
DTA_ClipTop, ClipTop,
|
||||
DTA_ClipBottom, ClipBot,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_TextLen, LineVisible,
|
||||
DTA_RenderStyle, Style,
|
||||
TAG_DONE);
|
||||
|
|
|
@ -43,8 +43,6 @@
|
|||
#include "c_cvars.h"
|
||||
#include "w_wad.h"
|
||||
#include "a_keys.h"
|
||||
#include "a_armor.h"
|
||||
#include "a_ammo.h"
|
||||
#include "sbar.h"
|
||||
#include "sc_man.h"
|
||||
#include "templates.h"
|
||||
|
@ -55,6 +53,7 @@
|
|||
#include "d_player.h"
|
||||
#include "r_utility.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -139,7 +138,7 @@ void SetHUDIcon(PClassInventory *cls, FTextureID tex)
|
|||
// center of the box. The image is scaled down if it doesn't fit
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, int trans=0xc000)
|
||||
static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, double trans = 0.75)
|
||||
{
|
||||
double scale1, scale2;
|
||||
|
||||
|
@ -175,7 +174,7 @@ static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, int trans
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void DrawHudText(FFont *font, int color, char * text, int x, int y, int trans=0xc000)
|
||||
static void DrawHudText(FFont *font, int color, char * text, int x, int y, double trans = 0.75)
|
||||
{
|
||||
int zerowidth;
|
||||
FTexture *tex_zero = font->GetChar('0', &zerowidth);
|
||||
|
@ -208,7 +207,7 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, int t
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void DrawHudNumber(FFont *font, int color, int num, int x, int y, int trans=0xc000)
|
||||
static void DrawHudNumber(FFont *font, int color, int num, int x, int y, double trans = 0.75)
|
||||
{
|
||||
char text[15];
|
||||
|
||||
|
@ -228,11 +227,11 @@ static void DrawStatLine(int x, int &y, const char *prefix, const char *string)
|
|||
y -= SmallFont->GetHeight()-1;
|
||||
screen->DrawText(SmallFont, hudcolor_statnames, x, y, prefix,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0xc000, TAG_DONE);
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.75, TAG_DONE);
|
||||
|
||||
screen->DrawText(SmallFont, hudcolor_stats, x+statspace, y, string,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0xc000, TAG_DONE);
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.75, TAG_DONE);
|
||||
}
|
||||
|
||||
static void DrawStatus(player_t * CPlayer, int x, int y)
|
||||
|
@ -296,8 +295,8 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
|
|||
CR_BLUE;
|
||||
|
||||
const bool haveBerserk = hud_berserk_health
|
||||
&& NULL != berserkpic
|
||||
&& NULL != CPlayer->mo->FindInventory< APowerStrength >();
|
||||
&& nullptr != berserkpic
|
||||
&& nullptr != CPlayer->mo->FindInventory(NAME_PowerStrength);
|
||||
|
||||
DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 17);
|
||||
DrawHudNumber(HudFont, fontcolor, health, x + 33, y + 17);
|
||||
|
@ -310,14 +309,15 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y)
|
||||
static void DrawArmor(AInventory * barmor, AInventory * harmor, int x, int y)
|
||||
{
|
||||
int ap = 0;
|
||||
int bestslot = 4;
|
||||
|
||||
if (harmor)
|
||||
{
|
||||
auto ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]);
|
||||
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||
auto ac = (Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4]);
|
||||
ap += int(ac);
|
||||
|
||||
if (ac)
|
||||
|
@ -326,7 +326,7 @@ static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y)
|
|||
bestslot = 0;
|
||||
for (int i = 1; i < 4; ++i)
|
||||
{
|
||||
if (harmor->Slots[i] > harmor->Slots[bestslot])
|
||||
if (Slots[i] > Slots[bestslot])
|
||||
{
|
||||
bestslot = i;
|
||||
}
|
||||
|
@ -385,9 +385,9 @@ static TArray<PClassActor *> KeyTypes, UnassignedKeyTypes;
|
|||
|
||||
static int ktcmp(const void * a, const void * b)
|
||||
{
|
||||
AKey *key1 = (AKey*)GetDefaultByType ( *(PClassActor **)a );
|
||||
AKey *key2 = (AKey*)GetDefaultByType ( *(PClassActor **)b );
|
||||
return key1->KeyNumber - key2->KeyNumber;
|
||||
auto key1 = GetDefaultByType ( *(PClassActor **)a );
|
||||
auto key2 = GetDefaultByType ( *(PClassActor **)b );
|
||||
return key1->special1 - key2->special1;
|
||||
}
|
||||
|
||||
static void SetKeyTypes()
|
||||
|
@ -395,13 +395,14 @@ static void SetKeyTypes()
|
|||
for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++)
|
||||
{
|
||||
PClass *ti = PClassActor::AllActorClasses[i];
|
||||
auto kt = PClass::FindActor(NAME_Key);
|
||||
|
||||
if (ti->IsDescendantOf(RUNTIME_CLASS(AKey)))
|
||||
if (ti->IsDescendantOf(kt))
|
||||
{
|
||||
PClassActor *tia = static_cast<PClassActor *>(ti);
|
||||
AKey *key = (AKey*)GetDefaultByType(tia);
|
||||
AInventory *key = (AInventory*)(GetDefaultByType(tia));
|
||||
|
||||
if (key->Icon.isValid() && key->KeyNumber>0)
|
||||
if (key->Icon.isValid() && key->special1 > 0)
|
||||
{
|
||||
KeyTypes.Push(tia);
|
||||
}
|
||||
|
@ -418,8 +419,7 @@ static void SetKeyTypes()
|
|||
else
|
||||
{
|
||||
// Don't leave the list empty
|
||||
PClassActor *ti = RUNTIME_CLASS(AKey);
|
||||
KeyTypes.Push(ti);
|
||||
KeyTypes.Push(PClass::FindActor(NAME_Key));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,17 +516,17 @@ static int DrawKeys(player_t * CPlayer, int x, int y)
|
|||
// Drawing Ammo
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static TArray<PClassAmmo *> orderedammos;
|
||||
static TArray<PClassInventory *> orderedammos;
|
||||
|
||||
static void AddAmmoToList(AWeapon * weapdef)
|
||||
{
|
||||
|
||||
for(int i=0; i<2;i++)
|
||||
{
|
||||
PClassAmmo * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2;
|
||||
PClassInventory * ti = i==0? weapdef->AmmoType1 : weapdef->AmmoType2;
|
||||
if (ti)
|
||||
{
|
||||
AAmmo * ammodef=(AAmmo*)GetDefaultByType(ti);
|
||||
auto ammodef=(AInventory*)GetDefaultByType(ti);
|
||||
|
||||
if (ammodef && !(ammodef->ItemFlags&IF_INVBAR))
|
||||
{
|
||||
|
@ -560,9 +560,9 @@ static void GetAmmoTextLengths(player_t *CPlayer, int& ammocur, int& ammomax)
|
|||
{
|
||||
for (auto type : orderedammos)
|
||||
{
|
||||
AAmmo * ammoitem = static_cast<AAmmo*>(CPlayer->mo->FindInventory(type));
|
||||
AAmmo * inv = nullptr == ammoitem
|
||||
? static_cast<AAmmo*>(GetDefaultByType(type))
|
||||
auto ammoitem = CPlayer->mo->FindInventory(type);
|
||||
auto inv = nullptr == ammoitem
|
||||
? static_cast<AInventory*>(GetDefaultByType(type))
|
||||
: ammoitem;
|
||||
assert(nullptr != inv);
|
||||
|
||||
|
@ -646,15 +646,15 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
|
|||
for(i=orderedammos.Size()-1;i>=0;i--)
|
||||
{
|
||||
|
||||
PClassAmmo * type = orderedammos[i];
|
||||
AAmmo * ammoitem = (AAmmo*)CPlayer->mo->FindInventory(type);
|
||||
PClassInventory * type = orderedammos[i];
|
||||
auto ammoitem = CPlayer->mo->FindInventory(type);
|
||||
|
||||
AAmmo * inv = ammoitem? ammoitem : (AAmmo*)GetDefaultByType(orderedammos[i]);
|
||||
auto inv = ammoitem? ammoitem : (AInventory*)GetDefaultByType(orderedammos[i]);
|
||||
FTextureID AltIcon = GetHUDIcon(type);
|
||||
FTextureID icon = !AltIcon.isNull()? AltIcon : inv->Icon;
|
||||
if (!icon.isValid()) continue;
|
||||
|
||||
int trans= (wi && (type==wi->AmmoType1 || type==wi->AmmoType2)) ? 0xc000:0x6000;
|
||||
double trans= (wi && (type==wi->AmmoType1 || type==wi->AmmoType2)) ? 0.75 : 0.375;
|
||||
|
||||
int maxammo = inv->MaxAmount;
|
||||
int ammo = ammoitem? ammoitem->Amount : 0;
|
||||
|
@ -731,16 +731,16 @@ FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale=NULL
|
|||
|
||||
static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon)
|
||||
{
|
||||
int trans;
|
||||
double trans;
|
||||
|
||||
// Powered up weapons and inherited sister weapons are not displayed.
|
||||
if (weapon->WeaponFlags & WIF_POWERED_UP) return;
|
||||
if (weapon->SisterWeapon && weapon->IsKindOf(weapon->SisterWeapon->GetClass())) return;
|
||||
|
||||
trans=0x6666;
|
||||
trans=0.4;
|
||||
if (CPlayer->ReadyWeapon)
|
||||
{
|
||||
if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999;
|
||||
if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans = 0.85;
|
||||
}
|
||||
|
||||
FTextureID picnum = GetInventoryIcon(weapon, DI_ALTICONFIRST);
|
||||
|
@ -809,7 +809,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y)
|
|||
{
|
||||
screen->DrawTexture(invgems[!!(level.time&4)], x-10, y,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0x6666, TAG_DONE);
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.4, TAG_DONE);
|
||||
}
|
||||
|
||||
for(i=0;i<numitems && rover;rover=rover->NextInv())
|
||||
|
@ -820,7 +820,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y)
|
|||
|
||||
if (AltIcon.Exists() && (rover->Icon.isValid() || AltIcon.isValid()) )
|
||||
{
|
||||
int trans = rover==CPlayer->mo->InvSel ? 0x10000 : 0x6666;
|
||||
double trans = rover==CPlayer->mo->InvSel ? 1.0 : 0.4;
|
||||
|
||||
DrawImageToBox(TexMan[AltIcon.isValid()? AltIcon : rover->Icon], x, y, 19, 25, trans);
|
||||
if (rover->Amount>1)
|
||||
|
@ -845,7 +845,7 @@ static void DrawInventory(player_t * CPlayer, int x,int y)
|
|||
{
|
||||
screen->DrawTexture(invgems[2 + !!(level.time&4)], x-10, y,
|
||||
DTA_KeepRatio, true,
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0x6666, TAG_DONE);
|
||||
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, 0.4, TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1141,8 +1141,7 @@ void DrawHUD()
|
|||
DrawFrags(CPlayer, 5, hudheight-70);
|
||||
}
|
||||
DrawHealth(CPlayer, 5, hudheight-45);
|
||||
DrawArmor(CPlayer->mo->FindInventory<ABasicArmor>(),
|
||||
CPlayer->mo->FindInventory<AHexenArmor>(), 5, hudheight-20);
|
||||
DrawArmor(CPlayer->mo->FindInventory(NAME_BasicArmor), CPlayer->mo->FindInventory(NAME_HexenArmor), 5, hudheight-20);
|
||||
i=DrawKeys(CPlayer, hudwidth-4, hudheight-10);
|
||||
i=DrawAmmo(CPlayer, hudwidth-5, i);
|
||||
if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "v_font.h"
|
||||
#include "m_fixed.h"
|
||||
#include "gstrings.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
TArray<FSkillInfo> AllSkills;
|
||||
int DefaultSkill = -1;
|
||||
|
|
|
@ -294,7 +294,6 @@ int FindMugShotStateIndex(FName state);
|
|||
// Base Status Bar ----------------------------------------------------------
|
||||
|
||||
class FTexture;
|
||||
class AAmmo;
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -308,6 +307,7 @@ enum
|
|||
|
||||
class DBaseStatusBar : public DObject
|
||||
{
|
||||
friend class DSBarInfo;
|
||||
DECLARE_CLASS (DBaseStatusBar, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
@ -341,9 +341,7 @@ public:
|
|||
};
|
||||
|
||||
DBaseStatusBar (int reltop, int hres=320, int vres=200);
|
||||
void Destroy() override;
|
||||
|
||||
void SetScaled (bool scale, bool force=false);
|
||||
void OnDestroy() override;
|
||||
|
||||
void AttachMessage (DHUDMessage *msg, uint32 id=0, int layer=HUDMSGLayer_Default);
|
||||
DHUDMessage *DetachMessage (DHUDMessage *msg);
|
||||
|
@ -358,6 +356,7 @@ public:
|
|||
// do not make this a DObject Serialize function because it's not used like one!
|
||||
void SerializeMessages(FSerializer &arc);
|
||||
|
||||
virtual void SetScaled(bool scale, bool force = false);
|
||||
virtual void Tick ();
|
||||
virtual void Draw (EHudState state);
|
||||
void DrawBottomStuff (EHudState state);
|
||||
|
@ -376,26 +375,20 @@ public:
|
|||
virtual void SetMugShotState (const char *state_name, bool wait_till_done=false, bool reset=false);
|
||||
void DrawLog();
|
||||
|
||||
void GetCoords(int &x, int &y)
|
||||
{
|
||||
x = ST_X;
|
||||
y = ST_Y;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
void DrawPowerups ();
|
||||
|
||||
void UpdateRect (int x, int y, int width, int height) const;
|
||||
void DrawImage (FTexture *image, int x, int y, FRemapTable *translation=NULL) const;
|
||||
void DrawDimImage (FTexture *image, int x, int y, bool dimmed) const;
|
||||
void DrawPartialImage (FTexture *image, int wx, int ww) const;
|
||||
|
||||
void DrINumber (signed int val, int x, int y, int imgBase=imgINumbers) const;
|
||||
void DrBNumber (signed int val, int x, int y, int w=3) const;
|
||||
void DrSmallNumber (int val, int x, int y) const;
|
||||
|
||||
void DrINumberOuter (signed int val, int x, int y, bool center=false, int w=9) const;
|
||||
void DrBNumberOuter (signed int val, int x, int y, int w=3) const;
|
||||
void DrBNumberOuterFont (signed int val, int x, int y, int w=3) const;
|
||||
void DrSmallNumberOuter (int val, int x, int y, bool center) const;
|
||||
|
||||
|
||||
void RefreshBackground () const;
|
||||
|
||||
void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const;
|
||||
void GetCurrentAmmo (AInventory *&ammo1, AInventory *&ammo2, int &ammocount1, int &ammocount2) const;
|
||||
|
||||
public:
|
||||
AInventory *ValidateInvFirst (int numVisible) const;
|
||||
|
@ -403,7 +396,7 @@ public:
|
|||
|
||||
int ST_X, ST_Y;
|
||||
int RelTop;
|
||||
int HorizontalResolution, VirticalResolution;
|
||||
int HorizontalResolution, VerticalResolution;
|
||||
bool Scaled;
|
||||
bool Centering;
|
||||
bool FixedOrigin;
|
|
@ -45,21 +45,18 @@
|
|||
#include "st_stuff.h"
|
||||
#include "m_swap.h"
|
||||
#include "a_keys.h"
|
||||
#include "a_armor.h"
|
||||
#include "templates.h"
|
||||
#include "i_system.h"
|
||||
#include "sbarinfo.h"
|
||||
#include "gi.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "a_artifacts.h"
|
||||
#include "a_weaponpiece.h"
|
||||
#include "g_level.h"
|
||||
#include "v_palette.h"
|
||||
#include "p_acs.h"
|
||||
#include "gstrings.h"
|
||||
#include "version.h"
|
||||
#include "cmdlib.h"
|
||||
#include "a_ammo.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#define ARTIFLASH_OFFSET (statusBar->invBarOffset+6)
|
||||
enum
|
||||
|
@ -973,17 +970,16 @@ inline void adjustRelCenter(bool relX, bool relY, const double &x, const double
|
|||
outY = y;
|
||||
}
|
||||
|
||||
class DSBarInfo : public DBaseStatusBar
|
||||
class DSBarInfo
|
||||
{
|
||||
DECLARE_CLASS(DSBarInfo, DBaseStatusBar)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
DSBarInfo (SBarInfo *script=NULL) : DBaseStatusBar(script->height, script->resW, script->resH),
|
||||
DSBarInfo (DBaseStatusBar *wrapper, SBarInfo *script=NULL) :
|
||||
ammo1(NULL), ammo2(NULL), ammocount1(0), ammocount2(0), armor(NULL),
|
||||
pendingPopup(POP_None), currentPopup(POP_None), lastHud(-1),
|
||||
pendingPopup(DBaseStatusBar::POP_None), currentPopup(DBaseStatusBar::POP_None), lastHud(-1),
|
||||
scalingWasForced(false), lastInventoryBar(NULL), lastPopup(NULL)
|
||||
{
|
||||
this->script = script;
|
||||
this->wrapper = wrapper;
|
||||
|
||||
static const char *InventoryBarLumps[] =
|
||||
{
|
||||
|
@ -1004,8 +1000,6 @@ public:
|
|||
}
|
||||
invBarOffset = script->Images.Size();
|
||||
Images.Init(&patchnames[0], patchnames.Size());
|
||||
|
||||
CompleteBorder = script->completeBorder;
|
||||
}
|
||||
|
||||
~DSBarInfo ()
|
||||
|
@ -1013,9 +1007,18 @@ public:
|
|||
Images.Uninit();
|
||||
}
|
||||
|
||||
void ScreenSizeChanged()
|
||||
void _SetScaled(bool scaled)
|
||||
{
|
||||
Scaled = scaled;
|
||||
}
|
||||
|
||||
void _AttachToPlayer(player_t *player)
|
||||
{
|
||||
CPlayer = player;
|
||||
}
|
||||
|
||||
void _ScreenSizeChanged()
|
||||
{
|
||||
Super::ScreenSizeChanged();
|
||||
if (uiscale > 0)
|
||||
{
|
||||
script->cleanX = uiscale;
|
||||
|
@ -1027,13 +1030,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void Draw (EHudState state)
|
||||
void _Draw (EHudState state)
|
||||
{
|
||||
DBaseStatusBar::Draw(state);
|
||||
if (script->cleanX <= 0)
|
||||
{ // Calculate cleanX and cleanY
|
||||
ScreenSizeChanged();
|
||||
wrapper->ScreenSizeChanged();
|
||||
}
|
||||
wrapper->GetCoords(ST_X, ST_Y);
|
||||
int hud = STBAR_NORMAL;
|
||||
if(state == HUD_StatusBar)
|
||||
{
|
||||
|
@ -1062,14 +1065,14 @@ public:
|
|||
else if(!Scaled)
|
||||
{
|
||||
scalingWasForced = true;
|
||||
SetScaled(true, true);
|
||||
wrapper->SetScaled(true, true);
|
||||
setsizeneeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
//prepare ammo counts
|
||||
GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2);
|
||||
armor = CPlayer->mo->FindInventory<ABasicArmor>();
|
||||
wrapper->GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2);
|
||||
armor = CPlayer->mo->FindInventory(NAME_BasicArmor);
|
||||
|
||||
if(state != HUD_AltHud)
|
||||
{
|
||||
|
@ -1081,12 +1084,12 @@ public:
|
|||
if(scalingWasForced)
|
||||
{
|
||||
scalingWasForced = false;
|
||||
SetScaled(false);
|
||||
wrapper->SetScaled(false);
|
||||
setsizeneeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentPopup != POP_None && !script->huds[hud]->FullScreenOffsets())
|
||||
if(currentPopup != DBaseStatusBar::POP_None && !script->huds[hud]->FullScreenOffsets())
|
||||
script->huds[hud]->Draw(NULL, this, script->popups[currentPopup-1].getXDisplacement(), script->popups[currentPopup-1].getYDisplacement(), 1.);
|
||||
else
|
||||
script->huds[hud]->Draw(NULL, this, 0, 0, 1.);
|
||||
|
@ -1108,14 +1111,14 @@ public:
|
|||
}
|
||||
|
||||
// Handle popups
|
||||
if(currentPopup != POP_None)
|
||||
if(currentPopup != DBaseStatusBar::POP_None)
|
||||
{
|
||||
int popbar = 0;
|
||||
if(currentPopup == POP_Log)
|
||||
if(currentPopup == DBaseStatusBar::POP_Log)
|
||||
popbar = STBAR_POPUPLOG;
|
||||
else if(currentPopup == POP_Keys)
|
||||
else if(currentPopup == DBaseStatusBar::POP_Keys)
|
||||
popbar = STBAR_POPUPKEYS;
|
||||
else if(currentPopup == POP_Status)
|
||||
else if(currentPopup == DBaseStatusBar::POP_Status)
|
||||
popbar = STBAR_POPUPSTATUS;
|
||||
if(script->huds[popbar] != lastPopup)
|
||||
{
|
||||
|
@ -1132,40 +1135,33 @@ public:
|
|||
hud_scale = oldhud_scale;
|
||||
}
|
||||
|
||||
void NewGame ()
|
||||
void _NewGame ()
|
||||
{
|
||||
if (CPlayer != NULL)
|
||||
{
|
||||
AttachToPlayer (CPlayer);
|
||||
|
||||
// Reset the huds
|
||||
script->ResetHuds();
|
||||
lastHud = -1; // Reset
|
||||
}
|
||||
// Reset the huds
|
||||
script->ResetHuds();
|
||||
lastHud = -1; // Reset
|
||||
}
|
||||
|
||||
bool MustDrawLog (EHudState state)
|
||||
bool _MustDrawLog (EHudState state)
|
||||
{
|
||||
return script->huds[STBAR_POPUPLOG]->NumCommands() == 0;
|
||||
}
|
||||
|
||||
void SetMugShotState (const char *state_name, bool wait_till_done, bool reset)
|
||||
void _SetMugShotState (const char *state_name, bool wait_till_done, bool reset)
|
||||
{
|
||||
script->MugShot.SetState(state_name, wait_till_done, reset);
|
||||
}
|
||||
|
||||
void Tick ()
|
||||
void _Tick ()
|
||||
{
|
||||
DBaseStatusBar::Tick();
|
||||
|
||||
script->MugShot.Tick(CPlayer);
|
||||
if(currentPopup != POP_None)
|
||||
if(currentPopup != DBaseStatusBar::POP_None)
|
||||
{
|
||||
script->popups[currentPopup-1].tick();
|
||||
if(script->popups[currentPopup-1].opened == false && script->popups[currentPopup-1].isDoneMoving())
|
||||
{
|
||||
currentPopup = pendingPopup;
|
||||
if(currentPopup != POP_None)
|
||||
if(currentPopup != DBaseStatusBar::POP_None)
|
||||
script->popups[currentPopup-1].open();
|
||||
}
|
||||
|
||||
|
@ -1178,30 +1174,29 @@ public:
|
|||
lastInventoryBar->Tick(NULL, this, false);
|
||||
}
|
||||
|
||||
void ReceivedWeapon(AWeapon *weapon)
|
||||
void _ReceivedWeapon(AWeapon *weapon)
|
||||
{
|
||||
script->MugShot.Grin();
|
||||
}
|
||||
|
||||
// void DSBarInfo::FlashItem(const PClass *itemtype) - Is defined with CommandDrawSelectedInventory
|
||||
void FlashItem(const PClass *itemtype);
|
||||
void _FlashItem(const PClass *itemtype);
|
||||
|
||||
void ShowPop(int popnum)
|
||||
void _ShowPop(int popnum)
|
||||
{
|
||||
DBaseStatusBar::ShowPop(popnum);
|
||||
if(popnum != currentPopup)
|
||||
{
|
||||
pendingPopup = popnum;
|
||||
}
|
||||
else
|
||||
pendingPopup = POP_None;
|
||||
if(currentPopup != POP_None)
|
||||
pendingPopup = DBaseStatusBar::POP_None;
|
||||
if(currentPopup != DBaseStatusBar::POP_None)
|
||||
script->popups[currentPopup-1].close();
|
||||
else
|
||||
{
|
||||
currentPopup = pendingPopup;
|
||||
pendingPopup = POP_None;
|
||||
if(currentPopup != POP_None)
|
||||
pendingPopup = DBaseStatusBar::POP_None;
|
||||
if(currentPopup != DBaseStatusBar::POP_None)
|
||||
script->popups[currentPopup-1].open();
|
||||
}
|
||||
}
|
||||
|
@ -1272,10 +1267,10 @@ public:
|
|||
DTA_ClipTop, static_cast<int>(dcy),
|
||||
DTA_ClipRight, static_cast<int>(MIN<double>(INT_MAX, dcr)),
|
||||
DTA_ClipBottom, static_cast<int>(MIN<double>(INT_MAX, dcb)),
|
||||
DTA_Translation, translate ? GetTranslation() : 0,
|
||||
DTA_TranslationIndex, translate ? GetTranslation() : 0,
|
||||
DTA_ColorOverlay, dim ? DIM_OVERLAY : 0,
|
||||
DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_AlphaChannel, alphaMap,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
|
@ -1289,10 +1284,10 @@ public:
|
|||
DTA_ClipTop, static_cast<int>(dcy),
|
||||
DTA_ClipRight, static_cast<int>(MIN<double>(INT_MAX, dcr)),
|
||||
DTA_ClipBottom, static_cast<int>(MIN<double>(INT_MAX, dcb)),
|
||||
DTA_Translation, translate ? GetTranslation() : 0,
|
||||
DTA_TranslationIndex, translate ? GetTranslation() : 0,
|
||||
DTA_ColorOverlay, dim ? DIM_OVERLAY : 0,
|
||||
DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
@ -1349,10 +1344,10 @@ public:
|
|||
DTA_ClipTop, static_cast<int>(rcy),
|
||||
DTA_ClipRight, static_cast<int>(rcr),
|
||||
DTA_ClipBottom, static_cast<int>(rcb),
|
||||
DTA_Translation, translate ? GetTranslation() : 0,
|
||||
DTA_TranslationIndex, translate ? GetTranslation() : 0,
|
||||
DTA_ColorOverlay, dim ? DIM_OVERLAY : 0,
|
||||
DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
DTA_AlphaChannel, alphaMap,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
|
@ -1366,10 +1361,10 @@ public:
|
|||
DTA_ClipTop, static_cast<int>(rcy),
|
||||
DTA_ClipRight, static_cast<int>(rcr),
|
||||
DTA_ClipBottom, static_cast<int>(rcb),
|
||||
DTA_Translation, translate ? GetTranslation() : 0,
|
||||
DTA_TranslationIndex, translate ? GetTranslation() : 0,
|
||||
DTA_ColorOverlay, dim ? DIM_OVERLAY : 0,
|
||||
DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
@ -1387,7 +1382,7 @@ public:
|
|||
|
||||
const BYTE* str = (const BYTE*) cstring;
|
||||
const EColorRange boldTranslation = EColorRange(translation ? translation - 1 : NumTextColors - 1);
|
||||
FRemapTable *remap = font->GetColorTranslation(translation);
|
||||
int fontcolor = translation;
|
||||
|
||||
if(fullScreenOffsets)
|
||||
{
|
||||
|
@ -1413,7 +1408,7 @@ public:
|
|||
{
|
||||
EColorRange newColor = V_ParseFontColor(++str, translation, boldTranslation);
|
||||
if(newColor != CR_UNDEFINED)
|
||||
remap = font->GetColorTranslation(newColor);
|
||||
fontcolor = newColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1422,20 +1417,22 @@ public:
|
|||
width = font->GetCharWidth((unsigned char) *str);
|
||||
else
|
||||
width = font->GetCharWidth((unsigned char) script->spacingCharacter);
|
||||
FTexture* character = font->GetChar((unsigned char) *str, &width);
|
||||
if(character == NULL) //missing character.
|
||||
FTexture* c = font->GetChar((unsigned char) *str, &width);
|
||||
if(c == NULL) //missing character.
|
||||
{
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
int character = (unsigned char)*str;
|
||||
|
||||
if(script->spacingCharacter == '\0') //If we are monospaced lets use the offset
|
||||
ax += (character->LeftOffset+1); //ignore x offsets since we adapt to character size
|
||||
ax += (c->LeftOffset+1); //ignore x offsets since we adapt to character size
|
||||
|
||||
double rx, ry, rw, rh;
|
||||
rx = ax + xOffset;
|
||||
ry = ay + yOffset;
|
||||
rw = character->GetScaledWidthDouble();
|
||||
rh = character->GetScaledHeightDouble();
|
||||
rw = c->GetScaledWidthDouble();
|
||||
rh = c->GetScaledHeightDouble();
|
||||
|
||||
if(script->spacingCharacter != '\0')
|
||||
{
|
||||
|
@ -1489,39 +1486,42 @@ public:
|
|||
double salpha = (Alpha *HR_SHADOW);
|
||||
double srx = rx + (shadowX*xScale);
|
||||
double sry = ry + (shadowY*yScale);
|
||||
screen->DrawTexture(character, srx, sry,
|
||||
screen->DrawChar(font, CR_UNTRANSLATED, srx, sry, character,
|
||||
DTA_DestWidthF, rw,
|
||||
DTA_DestHeightF, rh,
|
||||
DTA_AlphaF, salpha,
|
||||
DTA_Alpha, salpha,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
}
|
||||
screen->DrawTexture(character, rx, ry,
|
||||
screen->DrawChar(font, fontcolor, rx, ry, character,
|
||||
DTA_DestWidthF, rw,
|
||||
DTA_DestHeightF, rh,
|
||||
DTA_Translation, remap,
|
||||
DTA_AlphaF, Alpha,
|
||||
DTA_Alpha, Alpha,
|
||||
TAG_DONE);
|
||||
if(script->spacingCharacter == '\0')
|
||||
ax += width + spacing - (character->LeftOffset+1);
|
||||
ax += width + spacing - (c->LeftOffset+1);
|
||||
else //width gets changed at the call to GetChar()
|
||||
ax += font->GetCharWidth((unsigned char) script->spacingCharacter) + spacing;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
FRemapTable* GetTranslation() const
|
||||
uint32_t GetTranslation() const
|
||||
{
|
||||
if(gameinfo.gametype & GAME_Raven)
|
||||
return translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)];
|
||||
return translationtables[TRANSLATION_Players][int(CPlayer - players)];
|
||||
return TRANSLATION(TRANSLATION_PlayersExtra, int(CPlayer - players));
|
||||
return TRANSLATION(TRANSLATION_Players, int(CPlayer - players));
|
||||
}
|
||||
|
||||
AAmmo *ammo1, *ammo2;
|
||||
AInventory *ammo1, *ammo2;
|
||||
int ammocount1, ammocount2;
|
||||
ABasicArmor *armor;
|
||||
AInventory *armor;
|
||||
FImageCollection Images;
|
||||
unsigned int invBarOffset;
|
||||
player_t *CPlayer = nullptr;
|
||||
DBaseStatusBar *wrapper;
|
||||
bool Scaled;
|
||||
int ST_X, ST_Y;
|
||||
|
||||
private:
|
||||
SBarInfo *script;
|
||||
|
@ -1533,20 +1533,6 @@ private:
|
|||
SBarInfoMainBlock *lastPopup;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DSBarInfo, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(DSBarInfo)
|
||||
IMPLEMENT_POINTER(ammo1)
|
||||
IMPLEMENT_POINTER(ammo2)
|
||||
IMPLEMENT_POINTER(armor)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
DBaseStatusBar *CreateCustomStatusBar (int script)
|
||||
{
|
||||
if(SBarInfoScript[script] == NULL)
|
||||
I_FatalError("Tried to create a status bar with no script!");
|
||||
return new DSBarInfo(SBarInfoScript[script]);
|
||||
}
|
||||
|
||||
void SBarInfoMainBlock::DrawAux(const SBarInfoMainBlock *block, DSBarInfo *statusBar, int xOffset, int yOffset, double alpha)
|
||||
{
|
||||
|
@ -1565,7 +1551,7 @@ void SBarInfoMainBlock::DrawAux(const SBarInfoMainBlock *block, DSBarInfo *statu
|
|||
else if(!statusBar->Scaled)
|
||||
{
|
||||
rescale = true;
|
||||
statusBar->SetScaled(true, true);
|
||||
statusBar->wrapper->SetScaled(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1576,8 +1562,111 @@ void SBarInfoMainBlock::DrawAux(const SBarInfoMainBlock *block, DSBarInfo *statu
|
|||
if(FullScreenOffsets())
|
||||
hud_scale = false;
|
||||
else
|
||||
statusBar->SetScaled(false);
|
||||
statusBar->wrapper->SetScaled(false);
|
||||
}
|
||||
}
|
||||
|
||||
#include "sbarinfo_commands.cpp"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SBarinfoWrapper
|
||||
//
|
||||
// This class abstracts SBARINFO from the rest of the engine.
|
||||
// The idea is, when status bars are moved to ZScript that only
|
||||
// this small wrapper class needs to be dealt with and the implementation
|
||||
// can be left alone.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
DSBarInfoWrapper::DSBarInfoWrapper(SBarInfo *script)
|
||||
: DBaseStatusBar(script->height, script->resW, script->resH)
|
||||
{
|
||||
core = new DSBarInfo(this, script);
|
||||
core->_SetScaled(Scaled);
|
||||
CompleteBorder = script->completeBorder;
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::OnDestroy()
|
||||
{
|
||||
if (core != nullptr) delete core;
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::SetScaled(bool scale, bool force)
|
||||
{
|
||||
Super::SetScaled(scale, force);
|
||||
core->_SetScaled(Scaled);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::AttachToPlayer(player_t *player)
|
||||
{
|
||||
Super::AttachToPlayer(player);
|
||||
core->_AttachToPlayer(player);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::ScreenSizeChanged()
|
||||
{
|
||||
Super::ScreenSizeChanged();
|
||||
core->_ScreenSizeChanged();
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::Draw(EHudState state)
|
||||
{
|
||||
Super::Draw(state);
|
||||
core->_Draw(state);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::NewGame()
|
||||
{
|
||||
Super::NewGame();
|
||||
if (CPlayer != NULL)
|
||||
{
|
||||
AttachToPlayer(CPlayer);
|
||||
core->_NewGame();
|
||||
}
|
||||
}
|
||||
|
||||
bool DSBarInfoWrapper::MustDrawLog(EHudState state)
|
||||
{
|
||||
return core->_MustDrawLog(state);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::SetMugShotState(const char *state_name, bool wait_till_done, bool reset)
|
||||
{
|
||||
core->_SetMugShotState(state_name, wait_till_done, reset);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::Tick()
|
||||
{
|
||||
DBaseStatusBar::Tick();
|
||||
core->_Tick();
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::ReceivedWeapon(AWeapon *weapon)
|
||||
{
|
||||
core->_ReceivedWeapon(weapon);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::FlashItem(const PClass *itemtype)
|
||||
{
|
||||
core->_FlashItem(itemtype);
|
||||
}
|
||||
|
||||
void DSBarInfoWrapper::ShowPop(int popnum)
|
||||
{
|
||||
DBaseStatusBar::ShowPop(popnum); //DBaseStatusBar supercall
|
||||
core->_ShowPop(popnum);
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(DSBarInfoWrapper, false, false)
|
||||
|
||||
DBaseStatusBar *CreateCustomStatusBar(int script)
|
||||
{
|
||||
if (SBarInfoScript[script] == NULL)
|
||||
I_FatalError("Tried to create a status bar with no script!");
|
||||
return new DSBarInfoWrapper(SBarInfoScript[script]);
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
#define NUMPOPUPS 3
|
||||
|
||||
class FScanner;
|
||||
|
||||
class DSBarInfo;
|
||||
class SBarInfoMainBlock;
|
||||
|
||||
//Popups!
|
||||
|
@ -129,4 +129,27 @@ struct SBarInfo
|
|||
#define SCRIPT_DEFAULT 1
|
||||
extern SBarInfo *SBarInfoScript[2];
|
||||
|
||||
class DSBarInfoWrapper : public DBaseStatusBar
|
||||
{
|
||||
DSBarInfo *core;
|
||||
DECLARE_CLASS(DSBarInfoWrapper, DBaseStatusBar)
|
||||
public:
|
||||
DSBarInfoWrapper() : DBaseStatusBar(10, 10, 10) { core = nullptr; }
|
||||
DSBarInfoWrapper(SBarInfo *script);
|
||||
void OnDestroy() override;
|
||||
void SetScaled(bool scale, bool force);
|
||||
void AttachToPlayer(player_t *player) override;
|
||||
|
||||
void ScreenSizeChanged() override;
|
||||
void Draw(EHudState state) override;
|
||||
void NewGame() override;
|
||||
bool MustDrawLog(EHudState state) override;
|
||||
void SetMugShotState(const char *state_name, bool wait_till_done, bool reset) override;
|
||||
void Tick() override;
|
||||
void ReceivedWeapon(AWeapon *weapon) override;
|
||||
void FlashItem(const PClass *itemtype) override;
|
||||
void ShowPop(int popnum) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //__SBarInfo_SBAR_H__
|
|
@ -244,31 +244,31 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
|
|||
texture = TexMan(statusBar->CPlayer->mo->ScoreIcon);
|
||||
else if(type == AMMO1)
|
||||
{
|
||||
AAmmo *ammo = statusBar->ammo1;
|
||||
auto ammo = statusBar->ammo1;
|
||||
if(ammo != NULL)
|
||||
GetIcon(ammo);
|
||||
}
|
||||
else if(type == AMMO2)
|
||||
{
|
||||
AAmmo *ammo = statusBar->ammo2;
|
||||
auto ammo = statusBar->ammo2;
|
||||
if(ammo != NULL)
|
||||
GetIcon(ammo);
|
||||
}
|
||||
else if(type == ARMOR)
|
||||
{
|
||||
ABasicArmor *armor = statusBar->armor;
|
||||
auto armor = statusBar->armor;
|
||||
if(armor != NULL && armor->Amount != 0)
|
||||
GetIcon(armor);
|
||||
}
|
||||
else if(type == WEAPONICON)
|
||||
{
|
||||
AWeapon *weapon = statusBar->CPlayer->ReadyWeapon;
|
||||
auto weapon = statusBar->CPlayer->ReadyWeapon;
|
||||
if(weapon != NULL)
|
||||
GetIcon(weapon);
|
||||
}
|
||||
else if(type == SIGIL)
|
||||
{
|
||||
AInventory *item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil));
|
||||
auto item = statusBar->CPlayer->mo->FindInventory(NAME_Sigil);
|
||||
if (item != NULL)
|
||||
texture = TexMan(item->Icon);
|
||||
}
|
||||
|
@ -276,13 +276,15 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
|
|||
{
|
||||
int armorType = type - HEXENARMOR_ARMOR;
|
||||
|
||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
||||
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||
if (harmor != NULL)
|
||||
{
|
||||
if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0)
|
||||
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||
double *SlotsIncrement = (double*)harmor->ScriptVar(NAME_SlotsIncrement, nullptr);
|
||||
if (Slots[armorType] > 0 && SlotsIncrement[armorType] > 0)
|
||||
{
|
||||
//combine the alpha values
|
||||
alpha *= MIN(1., harmor->Slots[armorType] / harmor->SlotsIncrement[armorType]);
|
||||
alpha *= MIN(1., Slots[armorType] / SlotsIncrement[armorType]);
|
||||
texture = statusBar->Images[image];
|
||||
}
|
||||
else
|
||||
|
@ -416,10 +418,10 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
PClassActor *cls = PClassActor::AllActorClasses[i];
|
||||
if (cls->IsDescendantOf(RUNTIME_CLASS(AKey)))
|
||||
if (cls->IsDescendantOf(PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
AKey *key = (AKey *)GetDefaultByType(cls);
|
||||
if (key->KeyNumber == keynum)
|
||||
auto key = GetDefaultByType(cls);
|
||||
if (key->special1 == keynum)
|
||||
return cls->TypeName;
|
||||
}
|
||||
}
|
||||
|
@ -554,9 +556,9 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
|
||||
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
||||
{
|
||||
if(item->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
if(item->IsKindOf(PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
int keynum = static_cast<AKey *>(item)->KeyNumber;
|
||||
int keynum = item->special1;
|
||||
if(keynum)
|
||||
{
|
||||
if(keynum == conditionalValue[0])
|
||||
|
@ -592,11 +594,11 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
}
|
||||
else if(condition == ARMORTYPE)
|
||||
{
|
||||
ABasicArmor *armor = (ABasicArmor *) statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor);
|
||||
auto armor = statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor);
|
||||
if(armor != NULL)
|
||||
{
|
||||
bool matches1 = armor->ArmorType.GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount);
|
||||
bool matches2 = armor->ArmorType.GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount);
|
||||
bool matches1 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount);
|
||||
bool matches2 = armor->NameVar(NAME_ArmorType).GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount);
|
||||
|
||||
drawAlt = 1;
|
||||
if(conditionAnd)
|
||||
|
@ -614,12 +616,12 @@ class CommandDrawSwitchableImage : public CommandDrawImage
|
|||
}
|
||||
else //check the inventory items and draw selected sprite
|
||||
{
|
||||
AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[0]));
|
||||
AInventory* item = statusBar->CPlayer->mo->FindInventory(inventoryItem[0]);
|
||||
if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount))
|
||||
drawAlt = 1;
|
||||
if(conditionAnd)
|
||||
{
|
||||
item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(inventoryItem[1]));
|
||||
item = statusBar->CPlayer->mo->FindInventory(inventoryItem[1]);
|
||||
bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount);
|
||||
if((item != NULL && secondCondition) && drawAlt == 0) //both
|
||||
{
|
||||
|
@ -1076,10 +1078,10 @@ class CommandDrawNumber : public CommandDrawString
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindActor(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -1092,10 +1094,10 @@ class CommandDrawNumber : public CommandDrawString
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindActor(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -1158,10 +1160,10 @@ class CommandDrawNumber : public CommandDrawString
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindActor(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -1409,16 +1411,16 @@ class CommandDrawNumber : public CommandDrawString
|
|||
case SAVEPERCENT:
|
||||
{
|
||||
double add = 0;
|
||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
||||
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||
if(harmor != NULL)
|
||||
{
|
||||
add = harmor->Slots[0] + harmor->Slots[1] +
|
||||
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
||||
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||
add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
}
|
||||
//Hexen counts basic armor also so we should too.
|
||||
if(statusBar->armor != NULL)
|
||||
{
|
||||
add += statusBar->armor->SavePercent * 100;
|
||||
add += statusBar->armor->FloatVar(NAME_SavePercent) * 100;
|
||||
}
|
||||
if(value == ARMORCLASS)
|
||||
add /= 5;
|
||||
|
@ -1433,11 +1435,14 @@ class CommandDrawNumber : public CommandDrawString
|
|||
break;
|
||||
case POWERUPTIME:
|
||||
{
|
||||
//Get the PowerupType and check to see if the player has any in inventory.
|
||||
PClassActor* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType;
|
||||
APowerup* powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType);
|
||||
if(powerup != NULL)
|
||||
num = powerup->EffectTics / TICRATE + 1;
|
||||
// num = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem) / TICRATE + 1;
|
||||
static VMFunction *func = nullptr;
|
||||
if (func == nullptr) PClass::FindFunction(&func, NAME_PlayerPawn, "GetEffectTicsForItem");
|
||||
VMValue params[] = { statusBar->CPlayer->mo, inventoryItem };
|
||||
int retv;
|
||||
VMReturn ret(&retv);
|
||||
GlobalVMStack.Call(func, params, 2, &ret, 1);
|
||||
num = retv / TICRATE + 1;
|
||||
break;
|
||||
}
|
||||
case INVENTORY:
|
||||
|
@ -1471,7 +1476,7 @@ class CommandDrawNumber : public CommandDrawString
|
|||
num = 0;
|
||||
for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory)
|
||||
{
|
||||
if(item->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
if(item->IsKindOf(PClass::FindActor(NAME_Key)))
|
||||
num++;
|
||||
}
|
||||
break;
|
||||
|
@ -1813,7 +1818,7 @@ class CommandDrawSelectedInventory : public CommandDrawImage, private CommandDra
|
|||
int CommandDrawSelectedInventory::artiflashTick = 0;
|
||||
double CommandDrawSelectedInventory::itemflashFade = 0.75;
|
||||
|
||||
void DSBarInfo::FlashItem(const PClass *itemtype)
|
||||
void DSBarInfo::_FlashItem(const PClass *itemtype)
|
||||
{
|
||||
CommandDrawSelectedInventory::Flash();
|
||||
}
|
||||
|
@ -2185,7 +2190,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand
|
|||
AInventory *item;
|
||||
unsigned int i = 0;
|
||||
// If the player has no artifacts, don't draw the bar
|
||||
statusBar->CPlayer->mo->InvFirst = statusBar->ValidateInvFirst(size);
|
||||
statusBar->CPlayer->mo->InvFirst = statusBar->wrapper->ValidateInvFirst(size);
|
||||
if(statusBar->CPlayer->mo->InvFirst != NULL || alwaysShow)
|
||||
{
|
||||
for(item = statusBar->CPlayer->mo->InvFirst, i = 0; item != NULL && i < size; item = item->NextInv(), ++i)
|
||||
|
@ -2426,7 +2431,7 @@ class CommandDrawKeyBar : public SBarInfoCommand
|
|||
int rowWidth = 0;
|
||||
for(unsigned int i = 0;i < number+keyOffset;i++)
|
||||
{
|
||||
while(!item->Icon.isValid() || !item->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
while(!item->Icon.isValid() || !item->IsKindOf(PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
item = item->Inventory;
|
||||
if(item == NULL)
|
||||
|
@ -2627,10 +2632,10 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
sc.MustGetToken(TK_Identifier);
|
||||
type = AMMO;
|
||||
data.inventoryItem = PClass::FindActor(sc.String);
|
||||
if(data.inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo
|
||||
if(data.inventoryItem == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
data.inventoryItem = RUNTIME_CLASS(AAmmo);
|
||||
data.inventoryItem = PClass::FindActor(NAME_Ammo);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -2655,10 +2660,10 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
data.inventoryItem = PClass::FindActor(sc.String);
|
||||
if(data.inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(data.inventoryItem))
|
||||
if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem))
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
data.inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
data.inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -2822,33 +2827,34 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
break;
|
||||
case POWERUPTIME:
|
||||
{
|
||||
//Get the PowerupType and check to see if the player has any in inventory.
|
||||
APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(data.inventoryItem);
|
||||
PClassActor *powerupType = powerupGiver->PowerupType;
|
||||
APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType);
|
||||
if(powerup != NULL && powerupType != NULL && powerupGiver != NULL)
|
||||
{
|
||||
value = powerup->EffectTics + 1;
|
||||
if(powerupGiver->EffectTics == 0) //if 0 we need to get the default from the powerup
|
||||
max = ((APowerup*) GetDefaultByType(powerupType))->EffectTics + 1;
|
||||
else
|
||||
max = powerupGiver->EffectTics + 1;
|
||||
}
|
||||
// [value, max] = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem);
|
||||
// value++; max++;
|
||||
static VMFunction *func = nullptr;
|
||||
if (func == nullptr) PClass::FindFunction(&func, NAME_PlayerPawn, "GetEffectTicsForItem");
|
||||
VMValue params[] = { statusBar->CPlayer->mo, data.inventoryItem };
|
||||
VMReturn ret[2];
|
||||
int ival;
|
||||
ret[0].IntAt(&ival);
|
||||
ret[1].IntAt(&max);
|
||||
GlobalVMStack.Call(func, params, 2, ret, 2);
|
||||
value = ival + 1;
|
||||
max++;
|
||||
break;
|
||||
}
|
||||
case SAVEPERCENT:
|
||||
{
|
||||
double add = 0;
|
||||
AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory<AHexenArmor>();
|
||||
if(harmor != NULL)
|
||||
auto harmor = statusBar->CPlayer->mo->FindInventory(NAME_HexenArmor);
|
||||
if (harmor != NULL)
|
||||
{
|
||||
add = harmor->Slots[0] + harmor->Slots[1] +
|
||||
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
||||
double *Slots = (double*)harmor->ScriptVar(NAME_Slots, nullptr);
|
||||
add = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];
|
||||
}
|
||||
|
||||
//Hexen counts basic armor also so we should too.
|
||||
if(statusBar->armor != NULL)
|
||||
{
|
||||
add += statusBar->armor->SavePercent * 100;
|
||||
add += statusBar->armor->FloatVar(NAME_SavePercent) * 100;
|
||||
}
|
||||
value = int(add);
|
||||
max = 100;
|
||||
|
@ -3142,12 +3148,12 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
|
|||
|
||||
for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory)
|
||||
{
|
||||
if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder)))
|
||||
auto hc = PClass::FindActor("WeaponHolder");
|
||||
if(inv->IsKindOf(hc))
|
||||
{
|
||||
AWeaponHolder *hold = static_cast<AWeaponHolder*>(inv);
|
||||
if(hold->PieceWeapon == weapon)
|
||||
if(inv->PointerVar<PClass>("PieceWeapon") == weapon)
|
||||
{
|
||||
SetTruth(0 != (hold->PieceMask & (1 << (piece-1))), block, statusBar);
|
||||
SetTruth(0 != (inv->IntVar("PieceMask") & (1 << (piece-1))), block, statusBar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3311,10 +3317,10 @@ class CommandWeaponAmmo : public SBarInfoNegatableFlowControl
|
|||
for(int i = 0;i < 2;i++)
|
||||
{
|
||||
ammo[i] = PClass::FindClass(sc.String);
|
||||
if(ammo[i] == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo[i])) //must be a kind of ammo
|
||||
if(ammo[i] == NULL || !PClass::FindActor(NAME_Ammo)->IsAncestorOf(ammo[i])) //must be a kind of ammo
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of ammo.", sc.String);
|
||||
ammo[i] = RUNTIME_CLASS(AAmmo);
|
||||
ammo[i] = PClass::FindActor(NAME_Ammo);
|
||||
}
|
||||
|
||||
if(sc.CheckToken(TK_OrOr))
|
||||
|
@ -3688,3 +3694,5 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
|||
sc.MustGetToken('}');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +55,8 @@
|
|||
#include "gstrings.h"
|
||||
#include "r_utility.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "virtual.h"
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
|
@ -84,7 +86,7 @@ DBaseStatusBar *StatusBar;
|
|||
|
||||
extern int setblocks;
|
||||
|
||||
int ST_X, ST_Y;
|
||||
int gST_X, gST_Y;
|
||||
int SB_state = 3;
|
||||
|
||||
FTexture *CrosshairImage;
|
||||
|
@ -246,7 +248,7 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres)
|
|||
CPlayer = NULL;
|
||||
ShowLog = false;
|
||||
HorizontalResolution = hres;
|
||||
VirticalResolution = vres;
|
||||
VerticalResolution = vres;
|
||||
|
||||
SetScaled (st_scale);
|
||||
}
|
||||
|
@ -257,7 +259,7 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::Destroy ()
|
||||
void DBaseStatusBar::OnDestroy ()
|
||||
{
|
||||
for (size_t i = 0; i < countof(Messages); ++i)
|
||||
{
|
||||
|
@ -270,7 +272,7 @@ void DBaseStatusBar::Destroy ()
|
|||
}
|
||||
Messages[i] = NULL;
|
||||
}
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -280,7 +282,7 @@ void DBaseStatusBar::Destroy ()
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
//[BL] Added force argument to have forcescaled mean forcescaled.
|
||||
// - Also, if the VirticalResolution is something other than the default (200)
|
||||
// - Also, if the VerticalResolution is something other than the default (200)
|
||||
// We should always obey the value of scale.
|
||||
void DBaseStatusBar::SetScaled (bool scale, bool force)
|
||||
{
|
||||
|
@ -290,10 +292,10 @@ void DBaseStatusBar::SetScaled (bool scale, bool force)
|
|||
{
|
||||
ST_X = (SCREENWIDTH - HorizontalResolution) / 2;
|
||||
ST_Y = SCREENHEIGHT - RelTop;
|
||||
::ST_Y = ST_Y;
|
||||
gST_Y = ST_Y;
|
||||
if (RelTop > 0)
|
||||
{
|
||||
Displacement = double((ST_Y * VirticalResolution / SCREENHEIGHT) - (VirticalResolution - RelTop))/RelTop;
|
||||
Displacement = double((ST_Y * VerticalResolution / SCREENHEIGHT) - (VerticalResolution - RelTop))/RelTop;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -303,20 +305,20 @@ void DBaseStatusBar::SetScaled (bool scale, bool force)
|
|||
else
|
||||
{
|
||||
ST_X = 0;
|
||||
ST_Y = VirticalResolution - RelTop;
|
||||
ST_Y = VerticalResolution - RelTop;
|
||||
float aspect = ActiveRatio(SCREENWIDTH, SCREENHEIGHT);
|
||||
if (!AspectTallerThanWide(aspect))
|
||||
{ // Normal resolution
|
||||
::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution);
|
||||
gST_Y = Scale (ST_Y, SCREENHEIGHT, VerticalResolution);
|
||||
}
|
||||
else
|
||||
{ // 5:4 resolution
|
||||
::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, AspectBaseHeight(aspect), 200)) + SCREENHEIGHT/2
|
||||
gST_Y = Scale(ST_Y - VerticalResolution/2, SCREENHEIGHT*3, Scale(VerticalResolution, AspectBaseHeight(aspect), 200)) + SCREENHEIGHT/2
|
||||
+ (SCREENHEIGHT - SCREENHEIGHT * AspectMultiplier(aspect) / 48) / 2;
|
||||
}
|
||||
Displacement = 0;
|
||||
}
|
||||
::ST_X = ST_X;
|
||||
gST_X = ST_X;
|
||||
ST_SetNeedRefresh();
|
||||
}
|
||||
|
||||
|
@ -533,506 +535,6 @@ void DBaseStatusBar::ShowPlayerName ()
|
|||
1.5f, 0.92f, 0, 0, color, 2.f, 0.35f), MAKE_ID('P','N','A','M'));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawImage
|
||||
//
|
||||
// Draws an image with the status bar's upper-left corner as the origin.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrawImage (FTexture *img,
|
||||
int x, int y, FRemapTable *translation) const
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
screen->DrawTexture (img, x + ST_X, y + ST_Y,
|
||||
DTA_Translation, translation,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawImage
|
||||
//
|
||||
// Draws an optionally dimmed image with the status bar's upper-left corner
|
||||
// as the origin.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrawDimImage (FTexture *img,
|
||||
int x, int y, bool dimmed) const
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
screen->DrawTexture (img, x + ST_X, y + ST_Y,
|
||||
DTA_ColorOverlay, dimmed ? DIM_OVERLAY : 0,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawPartialImage
|
||||
//
|
||||
// Draws a portion of an image with the status bar's upper-left corner as
|
||||
// the origin. The image should be the same size as the status bar.
|
||||
// Used for Doom's status bar.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrawPartialImage (FTexture *img, int wx, int ww) const
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
screen->DrawTexture (img, ST_X, ST_Y,
|
||||
DTA_WindowLeft, wx,
|
||||
DTA_WindowRight, wx + ww,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrINumber
|
||||
//
|
||||
// Draws a three digit number.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrINumber (signed int val, int x, int y, int imgBase) const
|
||||
{
|
||||
int oldval;
|
||||
|
||||
if (val > 999)
|
||||
val = 999;
|
||||
oldval = val;
|
||||
if (val < 0)
|
||||
{
|
||||
if (val < -9)
|
||||
{
|
||||
DrawImage (Images[imgLAME], x+1, y+1);
|
||||
return;
|
||||
}
|
||||
val = -val;
|
||||
DrawImage (Images[imgBase+val], x+18, y);
|
||||
DrawImage (Images[imgNEGATIVE], x+9, y);
|
||||
return;
|
||||
}
|
||||
if (val > 99)
|
||||
{
|
||||
DrawImage (Images[imgBase+val/100], x, y);
|
||||
}
|
||||
val = val % 100;
|
||||
if (val > 9 || oldval > 99)
|
||||
{
|
||||
DrawImage (Images[imgBase+val/10], x+9, y);
|
||||
}
|
||||
val = val % 10;
|
||||
DrawImage (Images[imgBase+val], x+18, y);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrBNumber
|
||||
//
|
||||
// Draws an x digit number using the big font.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrBNumber (signed int val, int x, int y, int size) const
|
||||
{
|
||||
bool neg;
|
||||
int i, w;
|
||||
int power;
|
||||
FTexture *pic;
|
||||
|
||||
pic = Images[imgBNumbers];
|
||||
w = (pic != NULL) ? pic->GetWidth() : 0;
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
if (pic != NULL)
|
||||
{
|
||||
DrawImage (pic, x - w, y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (neg = val < 0) )
|
||||
{
|
||||
val = -val;
|
||||
size--;
|
||||
}
|
||||
for (i = size-1, power = 10; i > 0; i--)
|
||||
{
|
||||
power *= 10;
|
||||
}
|
||||
if (val >= power)
|
||||
{
|
||||
val = power - 1;
|
||||
}
|
||||
while (val != 0 && size--)
|
||||
{
|
||||
x -= w;
|
||||
pic = Images[imgBNumbers + val % 10];
|
||||
val /= 10;
|
||||
if (pic != NULL)
|
||||
{
|
||||
DrawImage (pic, x, y);
|
||||
}
|
||||
}
|
||||
if (neg)
|
||||
{
|
||||
pic = Images[imgBNEGATIVE];
|
||||
if (pic != NULL)
|
||||
{
|
||||
DrawImage (pic, x - w, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrSmallNumber
|
||||
//
|
||||
// Draws a small three digit number.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrSmallNumber (int val, int x, int y) const
|
||||
{
|
||||
int digit = 0;
|
||||
|
||||
if (val > 999)
|
||||
{
|
||||
val = 999;
|
||||
}
|
||||
if (val > 99)
|
||||
{
|
||||
digit = val / 100;
|
||||
DrawImage (Images[imgSmNumbers + digit], x, y);
|
||||
val -= digit * 100;
|
||||
}
|
||||
if (val > 9 || digit)
|
||||
{
|
||||
digit = val / 10;
|
||||
DrawImage (Images[imgSmNumbers + digit], x+4, y);
|
||||
val -= digit * 10;
|
||||
}
|
||||
DrawImage (Images[imgSmNumbers + val], x+8, y);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrINumberOuter
|
||||
//
|
||||
// Draws a number outside the status bar, possibly scaled.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrINumberOuter (signed int val, int x, int y, bool center, int w) const
|
||||
{
|
||||
bool negative = false;
|
||||
|
||||
x += w*2;
|
||||
if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
val = -val;
|
||||
}
|
||||
else if (val == 0)
|
||||
{
|
||||
screen->DrawTexture (Images[imgINumbers], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
screen->DrawTexture (Images[imgINumbers], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
int oval = val;
|
||||
int ox = x;
|
||||
|
||||
// First the shadow
|
||||
while (val != 0)
|
||||
{
|
||||
screen->DrawTexture (Images[imgINumbers + val % 10], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
x -= w;
|
||||
val /= 10;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
screen->DrawTexture (Images[imgNEGATIVE], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
}
|
||||
|
||||
// Then the real deal
|
||||
val = oval;
|
||||
x = ox;
|
||||
while (val != 0)
|
||||
{
|
||||
screen->DrawTexture (Images[imgINumbers + val % 10], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
x -= w;
|
||||
val /= 10;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
screen->DrawTexture (Images[imgNEGATIVE], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrBNumberOuter
|
||||
//
|
||||
// Draws a three digit number using the big font outside the status bar.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrBNumberOuter (signed int val, int x, int y, int size) const
|
||||
{
|
||||
int xpos;
|
||||
int w;
|
||||
bool negative = false;
|
||||
FTexture *pic;
|
||||
|
||||
pic = Images[imgBNumbers+3];
|
||||
if (pic != NULL)
|
||||
{
|
||||
w = pic->GetWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
w = 0;
|
||||
}
|
||||
|
||||
xpos = x + w/2 + (size-1)*w;
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
pic = Images[imgBNumbers];
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
int oval = val;
|
||||
int oxpos = xpos;
|
||||
|
||||
// Draw shadow first
|
||||
while (val != 0)
|
||||
{
|
||||
pic = Images[val % 10 + imgBNumbers];
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
}
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = Images[imgBNEGATIVE];
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Then draw the real thing
|
||||
val = oval;
|
||||
xpos = oxpos;
|
||||
while (val != 0)
|
||||
{
|
||||
pic = Images[val % 10 + imgBNumbers];
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
}
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = Images[imgBNEGATIVE];
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrBNumberOuter
|
||||
//
|
||||
// Draws a three digit number using the real big font outside the status bar.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrBNumberOuterFont (signed int val, int x, int y, int size) const
|
||||
{
|
||||
int xpos;
|
||||
int w, v;
|
||||
bool negative = false;
|
||||
FTexture *pic;
|
||||
|
||||
w = 0;
|
||||
BigFont->GetChar ('0', &w);
|
||||
|
||||
if (w > 1)
|
||||
{
|
||||
w--;
|
||||
}
|
||||
xpos = x + w/2 + (size-1)*w;
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
pic = BigFont->GetChar ('0', &v);
|
||||
screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
screen->DrawTexture (pic, xpos - v/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
return;
|
||||
}
|
||||
else if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
int oval = val;
|
||||
int oxpos = xpos;
|
||||
|
||||
// First the shadow
|
||||
while (val != 0)
|
||||
{
|
||||
pic = BigFont->GetChar ('0' + val % 10, &v);
|
||||
screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = BigFont->GetChar ('-', &v);
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_AlphaF, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Then the foreground number
|
||||
val = oval;
|
||||
xpos = oxpos;
|
||||
while (val != 0)
|
||||
{
|
||||
pic = BigFont->GetChar ('0' + val % 10, &v);
|
||||
screen->DrawTexture (pic, xpos - v/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = BigFont->GetChar ('-', &v);
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawTexture (pic, xpos - v/2, y,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrSmallNumberOuter
|
||||
//
|
||||
// Draws a small three digit number outside the status bar.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::DrSmallNumberOuter (int val, int x, int y, bool center) const
|
||||
{
|
||||
int digit = 0;
|
||||
|
||||
if (val > 999)
|
||||
{
|
||||
val = 999;
|
||||
}
|
||||
if (val > 99)
|
||||
{
|
||||
digit = val / 100;
|
||||
screen->DrawTexture (Images[imgSmNumbers + digit], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
val -= digit * 100;
|
||||
}
|
||||
if (val > 9 || digit)
|
||||
{
|
||||
digit = val / 10;
|
||||
screen->DrawTexture (Images[imgSmNumbers + digit], x+4, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
val -= digit * 10;
|
||||
}
|
||||
screen->DrawTexture (Images[imgSmNumbers + val], x+8, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// RefreshBackground
|
||||
|
@ -1045,7 +547,7 @@ void DBaseStatusBar::RefreshBackground () const
|
|||
|
||||
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;
|
||||
y = x == ST_X && x > 0 ? ST_Y : gST_Y;
|
||||
|
||||
if(!CompleteBorder)
|
||||
{
|
||||
|
@ -1253,21 +755,21 @@ void DBaseStatusBar::Draw (EHudState state)
|
|||
vwidth = SCREENWIDTH;
|
||||
vheight = SCREENHEIGHT;
|
||||
xpos = vwidth - 80;
|
||||
y = ::ST_Y - height;
|
||||
y = gST_Y - height;
|
||||
}
|
||||
else if (active_con_scaletext() > 1)
|
||||
{
|
||||
vwidth = SCREENWIDTH / active_con_scaletext();
|
||||
vheight = SCREENHEIGHT / active_con_scaletext();
|
||||
xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
|
||||
y = ::ST_Y/4 - height;
|
||||
y = gST_Y/4 - height;
|
||||
}
|
||||
else
|
||||
{
|
||||
vwidth = SCREENWIDTH/2;
|
||||
vheight = SCREENHEIGHT/2;
|
||||
xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
|
||||
y = ::ST_Y/2 - height;
|
||||
y = gST_Y/2 - height;
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Strife)
|
||||
|
@ -1323,7 +825,7 @@ void DBaseStatusBar::Draw (EHudState state)
|
|||
}
|
||||
|
||||
// Draw map name
|
||||
y = ::ST_Y - height;
|
||||
y = gST_Y - height;
|
||||
if (gameinfo.gametype == GAME_Heretic && SCREENWIDTH > 320 && !Scaled)
|
||||
{
|
||||
y -= 8;
|
||||
|
@ -1474,7 +976,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b
|
|||
|
||||
void DBaseStatusBar::DrawBottomStuff (EHudState state)
|
||||
{
|
||||
DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
|
||||
DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? gST_Y : SCREENHEIGHT);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -1496,9 +998,9 @@ void DBaseStatusBar::DrawTopStuff (EHudState state)
|
|||
DrawPowerups ();
|
||||
if (automapactive && !viewactive)
|
||||
{
|
||||
DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
|
||||
DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? gST_Y : SCREENHEIGHT);
|
||||
}
|
||||
DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
|
||||
DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? gST_Y : SCREENHEIGHT);
|
||||
DrawConsistancy ();
|
||||
DrawWaiting ();
|
||||
if (ShowLog && MustDrawLog(state)) DrawLog ();
|
||||
|
@ -1528,13 +1030,22 @@ void DBaseStatusBar::DrawPowerups ()
|
|||
+ (ST_IsLatencyVisible() ? yshift : 0);
|
||||
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
||||
{
|
||||
if (item->DrawPowerup (x, y))
|
||||
IFVIRTUALPTR(item, AInventory, DrawPowerup)
|
||||
{
|
||||
x -= POWERUPICONSIZE;
|
||||
if (x < -POWERUPICONSIZE*5)
|
||||
VMValue params[3] = { item, x, y };
|
||||
VMReturn ret;
|
||||
int retv;
|
||||
|
||||
ret.IntAt(&retv);
|
||||
GlobalVMStack.Call(func, params, 3, &ret, 1);
|
||||
if (retv)
|
||||
{
|
||||
x = -20;
|
||||
y += POWERUPICONSIZE*2;
|
||||
x -= POWERUPICONSIZE;
|
||||
if (x < -POWERUPICONSIZE * 5)
|
||||
{
|
||||
x = -20;
|
||||
y += POWERUPICONSIZE * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1662,6 +1173,15 @@ void DBaseStatusBar::ReceivedWeapon (AWeapon *weapon)
|
|||
{
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_StatusBar, ReceivedWeapon)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_POINTER(w, AWeapon);
|
||||
StatusBar->ReceivedWeapon(w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void DBaseStatusBar::SerializeMessages(FSerializer &arc)
|
||||
{
|
||||
arc.Array("hudmessages", Messages, 3, true);
|
||||
|
@ -1783,7 +1303,7 @@ AInventory *DBaseStatusBar::ValidateInvFirst (int numVisible) const
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
void DBaseStatusBar::GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const
|
||||
void DBaseStatusBar::GetCurrentAmmo (AInventory *&ammo1, AInventory *&ammo2, int &ammocount1, int &ammocount2) const
|
||||
{
|
||||
if (CPlayer->ReadyWeapon != NULL)
|
||||
{
|
|
@ -12,13 +12,12 @@
|
|||
#include "m_swap.h"
|
||||
#include "templates.h"
|
||||
#include "a_keys.h"
|
||||
#include "a_armor.h"
|
||||
#include "a_ammo.h"
|
||||
#include "gi.h"
|
||||
#include "g_level.h"
|
||||
#include "colormatcher.h"
|
||||
#include "v_palette.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
// Number of tics to move the popscreen up and down.
|
||||
#define POP_TIME (TICRATE/8)
|
||||
|
@ -261,7 +260,7 @@ public:
|
|||
item != NULL;
|
||||
item = item->Inventory)
|
||||
{
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AKey)))
|
||||
if (item->IsKindOf (PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
if (i == KeyPopPos)
|
||||
{
|
||||
|
@ -408,7 +407,7 @@ private:
|
|||
DrawImage (&HealthBar, 49, 7);
|
||||
|
||||
// Armor
|
||||
item = CPlayer->mo->FindInventory<ABasicArmor>();
|
||||
item = CPlayer->mo->FindInventory(NAME_BasicArmor);
|
||||
if (item != NULL && item->Amount > 0)
|
||||
{
|
||||
DrawImage (TexMan(item->Icon), 2, 9);
|
||||
|
@ -416,7 +415,7 @@ private:
|
|||
}
|
||||
|
||||
// Ammo
|
||||
AAmmo *ammo1, *ammo2;
|
||||
AInventory *ammo1, *ammo2;
|
||||
int ammocount1, ammocount2;
|
||||
|
||||
GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2);
|
||||
|
@ -436,7 +435,7 @@ private:
|
|||
}
|
||||
|
||||
// Sigil
|
||||
item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil));
|
||||
item = CPlayer->mo->FindInventory(NAME_Sigil);
|
||||
if (item != NULL)
|
||||
{
|
||||
DrawImage (TexMan(item->Icon), 253, 7);
|
||||
|
@ -452,7 +451,7 @@ private:
|
|||
screen->DrawTexture (Images[CursorImage],
|
||||
42 + 35*i + ST_X, 12 + ST_Y,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
DTA_AlphaF, 1. - ItemFlash,
|
||||
DTA_Alpha, 1. - ItemFlash,
|
||||
TAG_DONE);
|
||||
}
|
||||
if (item->Icon.isValid())
|
||||
|
@ -473,7 +472,7 @@ private:
|
|||
TAG_DONE);
|
||||
|
||||
// Draw armor
|
||||
ABasicArmor *armor = CPlayer->mo->FindInventory<ABasicArmor>();
|
||||
auto armor = CPlayer->mo->FindInventory(NAME_BasicArmor);
|
||||
if (armor != NULL && armor->Amount != 0)
|
||||
{
|
||||
DrINumberOuter (armor->Amount, 35, -10, false, 7);
|
||||
|
@ -484,7 +483,7 @@ private:
|
|||
}
|
||||
|
||||
// Draw ammo
|
||||
AAmmo *ammo1, *ammo2;
|
||||
AInventory *ammo1, *ammo2;
|
||||
int ammocount1, ammocount2;
|
||||
|
||||
GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2);
|
||||
|
@ -524,7 +523,7 @@ private:
|
|||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_LeftOffset, cursor->GetWidth(),
|
||||
DTA_TopOffset, cursor->GetHeight(),
|
||||
DTA_AlphaF, ItemFlash,
|
||||
DTA_Alpha, ItemFlash,
|
||||
TAG_DONE);
|
||||
}
|
||||
DrINumberOuter (CPlayer->mo->InvSel->Amount, -51, -10, false, 7);
|
||||
|
@ -548,7 +547,7 @@ private:
|
|||
{
|
||||
screen->DrawTexture (Images[CursorImage], -100+i*35, -21,
|
||||
DTA_HUDRules, HUD_HorizCenter,
|
||||
DTA_Alpha, TRANSLUC75,
|
||||
DTA_Alpha, 0.75,
|
||||
TAG_DONE);
|
||||
}
|
||||
if (item->Icon.isValid())
|
||||
|
@ -581,7 +580,7 @@ private:
|
|||
left = screen->GetWidth()/2 - 160*CleanXfac;
|
||||
top = bottom + height * yscale;
|
||||
|
||||
screen->DrawTexture (Images[back], left, top, DTA_CleanNoMove, true, DTA_AlphaF, 0.75, TAG_DONE);
|
||||
screen->DrawTexture (Images[back], left, top, DTA_CleanNoMove, true, DTA_Alpha, 0.75, TAG_DONE);
|
||||
screen->DrawTexture (Images[bars], left, top, DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
|
||||
|
@ -633,7 +632,7 @@ private:
|
|||
i < endpos && item != NULL;
|
||||
item = item->Inventory)
|
||||
{
|
||||
if (!item->IsKindOf (RUNTIME_CLASS(AKey)))
|
||||
if (!item->IsKindOf (PClass::FindActor(NAME_Key)))
|
||||
continue;
|
||||
|
||||
if (i < pos)
|
||||
|
@ -678,7 +677,7 @@ private:
|
|||
item != NULL;
|
||||
item = item->Inventory)
|
||||
{
|
||||
if (item->IsKindOf (RUNTIME_CLASS(AKey)))
|
||||
if (item->IsKindOf (PClass::FindActor(NAME_Key)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
@ -846,8 +845,218 @@ private:
|
|||
int CurrentPop, PendingPop, PopHeight, PopHeightChange;
|
||||
int KeyPopPos, KeyPopScroll;
|
||||
double ItemFlash;
|
||||
|
||||
void DrINumberOuter(signed int val, int x, int y, bool center = false, int w = 9) const;
|
||||
void DrBNumberOuterFont(signed int val, int x, int y, int w = 3) const;
|
||||
void DrawDimImage(FTexture *image, int x, int y, bool dimmed) const;
|
||||
void DrawImage(FTexture *image, int x, int y/*, FRemapTable *translation = NULL*/) const;
|
||||
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrINumberOuter
|
||||
//
|
||||
// Draws a number outside the status bar, possibly scaled.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DStrifeStatusBar::DrINumberOuter(signed int val, int x, int y, bool center, int w) const
|
||||
{
|
||||
bool negative = false;
|
||||
|
||||
x += w * 2;
|
||||
if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
val = -val;
|
||||
}
|
||||
else if (val == 0)
|
||||
{
|
||||
screen->DrawTexture(Images[imgINumbers], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
screen->DrawTexture(Images[imgINumbers], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
int oval = val;
|
||||
int ox = x;
|
||||
|
||||
// First the shadow
|
||||
while (val != 0)
|
||||
{
|
||||
screen->DrawTexture(Images[imgINumbers + val % 10], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
x -= w;
|
||||
val /= 10;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
screen->DrawTexture(Images[imgNEGATIVE], x + 1, y + 1,
|
||||
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
}
|
||||
|
||||
// Then the real deal
|
||||
val = oval;
|
||||
x = ox;
|
||||
while (val != 0)
|
||||
{
|
||||
screen->DrawTexture(Images[imgINumbers + val % 10], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
x -= w;
|
||||
val /= 10;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
screen->DrawTexture(Images[imgNEGATIVE], x, y,
|
||||
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrBNumberOuter
|
||||
//
|
||||
// Draws a three digit number using the real big font outside the status bar.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DStrifeStatusBar::DrBNumberOuterFont(signed int val, int x, int y, int size) const
|
||||
{
|
||||
int xpos;
|
||||
int w, v;
|
||||
bool negative = false;
|
||||
FTexture *pic;
|
||||
|
||||
w = 0;
|
||||
BigFont->GetChar('0', &w);
|
||||
|
||||
if (w > 1)
|
||||
{
|
||||
w--;
|
||||
}
|
||||
xpos = x + w / 2 + (size - 1)*w;
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
pic = BigFont->GetChar('0', &v);
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, '0',
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Alpha, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2, y, '0',
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
return;
|
||||
}
|
||||
else if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
int oval = val;
|
||||
int oxpos = xpos;
|
||||
|
||||
// First the shadow
|
||||
while (val != 0)
|
||||
{
|
||||
pic = BigFont->GetChar('0' + val % 10, &v);
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2,
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Alpha, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = BigFont->GetChar('-', &v);
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, '-',
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
DTA_Alpha, HR_SHADOW,
|
||||
DTA_FillColor, 0,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Then the foreground number
|
||||
val = oval;
|
||||
xpos = oxpos;
|
||||
while (val != 0)
|
||||
{
|
||||
pic = BigFont->GetChar('0' + val % 10, &v);
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2, y, '0',
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
val /= 10;
|
||||
xpos -= w;
|
||||
}
|
||||
if (negative)
|
||||
{
|
||||
pic = BigFont->GetChar('-', &v);
|
||||
if (pic != NULL)
|
||||
{
|
||||
screen->DrawChar(BigFont, CR_UNTRANSLATED, xpos - v / 2, y, '-',
|
||||
DTA_HUDRules, HUD_Normal,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawImage
|
||||
//
|
||||
// Draws an image with the status bar's upper-left corner as the origin.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DStrifeStatusBar::DrawImage(FTexture *img,
|
||||
int x, int y) const
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
screen->DrawTexture(img, x + ST_X, y + ST_Y,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PROC DrawImage
|
||||
//
|
||||
// Draws an optionally dimmed image with the status bar's upper-left corner
|
||||
// as the origin.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DStrifeStatusBar::DrawDimImage(FTexture *img,
|
||||
int x, int y, bool dimmed) const
|
||||
{
|
||||
if (img != NULL)
|
||||
{
|
||||
screen->DrawTexture(img, x + ST_X, y + ST_Y,
|
||||
DTA_ColorOverlay, dimmed ? DIM_OVERLAY : 0,
|
||||
DTA_Bottom320x200, Scaled,
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_CLASS(DStrifeStatusBar, false, false);
|
||||
|
||||
DBaseStatusBar *CreateStrifeStatusBar ()
|
|
@ -45,6 +45,13 @@
|
|||
|
||||
gameinfo_t gameinfo;
|
||||
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype)
|
||||
|
||||
|
||||
const char *GameNames[17] =
|
||||
{
|
||||
NULL, "Doom", "Heretic", NULL, "Hexen", NULL, NULL, NULL, "Strife", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Chex"
|
||||
|
|
2
src/gi.h
2
src/gi.h
|
@ -148,7 +148,7 @@ struct gameinfo_t
|
|||
FString translator;
|
||||
DWORD defaultbloodcolor;
|
||||
DWORD defaultbloodparticlecolor;
|
||||
FString backpacktype;
|
||||
FName backpacktype;
|
||||
FString statusbar;
|
||||
FString intermissionMusic;
|
||||
int intermissionOrder;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "i_system.h"
|
||||
#include "v_text.h"
|
||||
#include "r_utility.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "gl/dynlights/gl_dynlight.h"
|
||||
#include "gl/utility/gl_geometric.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "g_level.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_player.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
|
@ -154,9 +155,9 @@ int LS_Sector_SetPlaneReflection (line_t *ln, AActor *it, bool backSide,
|
|||
|
||||
while ((secnum = itr.Next()) >= 0)
|
||||
{
|
||||
sector_t * s = §ors[secnum];
|
||||
sector_t * s = &level.sectors[secnum];
|
||||
if (!s->floorplane.isSlope()) s->reflect[sector_t::floor] = arg1/255.f;
|
||||
if (!s->ceilingplane.isSlope()) sectors[secnum].reflect[sector_t::ceiling] = arg2/255.f;
|
||||
if (!s->ceilingplane.isSlope()) level.sectors[secnum].reflect[sector_t::ceiling] = arg2/255.f;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -412,7 +413,7 @@ void InitGLRMapinfoData()
|
|||
|
||||
if (opt != NULL)
|
||||
{
|
||||
gl_SetFogParams(opt->fogdensity, level.info->outsidefog, opt->outsidefogdensity, opt->skyfog);
|
||||
gl_SetFogParams(clamp(opt->fogdensity, 0, 255), level.info->outsidefog, clamp(opt->outsidefogdensity, 0, 255), opt->skyfog);
|
||||
glset.map_lightmode = opt->lightmode;
|
||||
glset.map_lightadditivesurfaces = opt->lightadditivesurfaces;
|
||||
glset.map_attenuate = opt->attenuate;
|
||||
|
@ -482,7 +483,7 @@ FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, b
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// Recalculate all heights affectting this vertex.
|
||||
// Recalculate all heights affecting this vertex.
|
||||
//
|
||||
//==========================================================================
|
||||
void gl_RecalcVertexHeights(vertex_t * v)
|
||||
|
@ -532,14 +533,12 @@ void gl_InitData()
|
|||
|
||||
CCMD(dumpgeometry)
|
||||
{
|
||||
for(int i=0;i<numsectors;i++)
|
||||
for(auto §or : level.sectors)
|
||||
{
|
||||
sector_t * sector = §ors[i];
|
||||
|
||||
Printf(PRINT_LOG, "Sector %d\n",i);
|
||||
for(int j=0;j<sector->subsectorcount;j++)
|
||||
Printf(PRINT_LOG, "Sector %d\n", sector.sectornum);
|
||||
for(int j=0;j<sector.subsectorcount;j++)
|
||||
{
|
||||
subsector_t * sub = sector->subsectors[j];
|
||||
subsector_t * sub = sector.subsectors[j];
|
||||
|
||||
Printf(PRINT_LOG, " Subsector %d - real sector = %d - %s\n", int(sub-subsectors), sub->sector->sectornum, sub->hacked&1? "hacked":"");
|
||||
for(DWORD k=0;k<sub->numlines;k++)
|
||||
|
@ -549,7 +548,7 @@ CCMD(dumpgeometry)
|
|||
{
|
||||
Printf(PRINT_LOG, " (%4.4f, %4.4f), (%4.4f, %4.4f) - seg %d, linedef %d, side %d",
|
||||
seg->v1->fX(), seg->v1->fY(), seg->v2->fX(), seg->v2->fY(),
|
||||
int(seg-segs), int(seg->linedef-lines), seg->sidedef != seg->linedef->sidedef[0]);
|
||||
int(seg-segs), seg->linedef->Index(), seg->sidedef != seg->linedef->sidedef[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -563,7 +562,7 @@ CCMD(dumpgeometry)
|
|||
Printf(PRINT_LOG, ", back sector = %d, real back sector = %d", sub2->render_sector->sectornum, seg->PartnerSeg->frontsector->sectornum);
|
||||
}
|
||||
else if (seg->backsector)
|
||||
{
|
||||
{
|
||||
Printf(PRINT_LOG, ", back sector = %d (no partnerseg)", seg->backsector->sectornum);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ inline int getExtraLight()
|
|||
void gl_RecalcVertexHeights(vertex_t * v);
|
||||
FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror);
|
||||
|
||||
class AStackPoint;
|
||||
struct GLSectorStackPortal;
|
||||
|
||||
struct FPortal
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "gi.h"
|
||||
#include "g_level.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
|
@ -337,18 +338,17 @@ void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, c
|
|||
|
||||
static void CollectPortalSectors(FPortalMap &collection)
|
||||
{
|
||||
for (int i=0;i<numsectors;i++)
|
||||
for (auto &sec : level.sectors)
|
||||
{
|
||||
sector_t *sec = §ors[i];
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
int ptype = sec->GetPortalType(j);
|
||||
int ptype = sec.GetPortalType(j);
|
||||
if (ptype== PORTS_STACKEDSECTORTHING || ptype == PORTS_PORTAL || ptype == PORTS_LINKEDPORTAL) // only offset-displacing portal types
|
||||
{
|
||||
FPortalID id = { sec->GetPortalDisplacement(j) };
|
||||
FPortalID id = { sec.GetPortalDisplacement(j) };
|
||||
|
||||
FPortalSectors &sss = collection[id];
|
||||
FPortalSector ss = { sec, j };
|
||||
FPortalSector ss = { &sec, j };
|
||||
sss.Push(ss);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "gi.h"
|
||||
#include "p_setup.h"
|
||||
#include "g_level.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
|
@ -257,11 +258,11 @@ static void PrepareSectorData()
|
|||
ss->render_sector->subsectorcount++;
|
||||
}
|
||||
|
||||
for (i=0; i<numsectors; i++)
|
||||
for (auto &sec : level.sectors)
|
||||
{
|
||||
sectors[i].subsectors = subsectorbuffer;
|
||||
subsectorbuffer += sectors[i].subsectorcount;
|
||||
sectors[i].subsectorcount = 0;
|
||||
sec.subsectors = subsectorbuffer;
|
||||
subsectorbuffer += sec.subsectorcount;
|
||||
sec.subsectorcount = 0;
|
||||
}
|
||||
|
||||
for(i=0, ss = subsectors; i<numsubsectors; i++, ss++)
|
||||
|
@ -307,13 +308,6 @@ static void PrepareTransparentDoors(sector_t * sector)
|
|||
unsigned int selfref=0;
|
||||
sector_t * nextsec=NULL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (sector-sectors==34)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
P_Recalculate3DFloors(sector);
|
||||
if (sector->subsectorcount==0) return;
|
||||
|
||||
|
@ -388,7 +382,7 @@ static void PrepareTransparentDoors(sector_t * sector)
|
|||
|
||||
static void AddToVertex(const sector_t * sec, TArray<int> & list)
|
||||
{
|
||||
int secno = int(sec-sectors);
|
||||
int secno = sec->Index();
|
||||
|
||||
for(unsigned i=0;i<list.Size();i++)
|
||||
{
|
||||
|
@ -405,55 +399,49 @@ static void AddToVertex(const sector_t * sec, TArray<int> & list)
|
|||
|
||||
static void InitVertexData()
|
||||
{
|
||||
TArray<int> * vt_sectorlists;
|
||||
auto vt_sectorlists = new TArray<int>[level.vertexes.Size()];
|
||||
|
||||
int i,j,k;
|
||||
|
||||
vt_sectorlists = new TArray<int>[numvertexes];
|
||||
|
||||
|
||||
for(i=0;i<numlines;i++)
|
||||
for(auto &line : level.lines)
|
||||
{
|
||||
line_t * line = &lines[i];
|
||||
|
||||
for(j=0;j<2;j++)
|
||||
for(int j = 0; j < 2; ++j)
|
||||
{
|
||||
vertex_t * v = j==0? line->v1 : line->v2;
|
||||
vertex_t * v = j==0? line.v1 : line.v2;
|
||||
|
||||
for(k=0;k<2;k++)
|
||||
for(int k = 0; k < 2; ++k)
|
||||
{
|
||||
sector_t * sec = k==0? line->frontsector : line->backsector;
|
||||
sector_t * sec = k==0? line.frontsector : line.backsector;
|
||||
|
||||
if (sec)
|
||||
{
|
||||
extsector_t::xfloor &x = sec->e->XFloor;
|
||||
|
||||
AddToVertex(sec, vt_sectorlists[v-vertexes]);
|
||||
if (sec->heightsec) AddToVertex(sec->heightsec, vt_sectorlists[v-vertexes]);
|
||||
AddToVertex(sec, vt_sectorlists[v->Index()]);
|
||||
if (sec->heightsec) AddToVertex(sec->heightsec, vt_sectorlists[v->Index()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<numvertexes;i++)
|
||||
for(unsigned i = 0; i < level.vertexes.Size(); ++i)
|
||||
{
|
||||
auto vert = level.vertexes[i];
|
||||
int cnt = vt_sectorlists[i].Size();
|
||||
|
||||
vertexes[i].dirty = true;
|
||||
vertexes[i].numheights=0;
|
||||
vert.dirty = true;
|
||||
vert.numheights=0;
|
||||
if (cnt>1)
|
||||
{
|
||||
vertexes[i].numsectors= cnt;
|
||||
vertexes[i].sectors=new sector_t*[cnt];
|
||||
vertexes[i].heightlist = new float[cnt*2];
|
||||
vert.numsectors= cnt;
|
||||
vert.sectors=new sector_t*[cnt];
|
||||
vert.heightlist = new float[cnt*2];
|
||||
for(int j=0;j<cnt;j++)
|
||||
{
|
||||
vertexes[i].sectors[j] = §ors[vt_sectorlists[i][j]];
|
||||
vert.sectors[j] = &level.sectors[vt_sectorlists[i][j]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexes[i].numsectors=0;
|
||||
vert.numsectors=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,8 +456,8 @@ static void InitVertexData()
|
|||
|
||||
static void GetSideVertices(int sdnum, DVector2 *v1, DVector2 *v2)
|
||||
{
|
||||
line_t *ln = sides[sdnum].linedef;
|
||||
if (ln->sidedef[0] == &sides[sdnum])
|
||||
line_t *ln = level.sides[sdnum].linedef;
|
||||
if (ln->sidedef[0] == &level.sides[sdnum])
|
||||
{
|
||||
*v1 = ln->v1->fPos();
|
||||
*v2 = ln->v2->fPos();
|
||||
|
@ -496,54 +484,25 @@ static int segcmp(const void *a, const void *b)
|
|||
|
||||
static void PrepareSegs()
|
||||
{
|
||||
auto numsides = level.sides.Size();
|
||||
int *segcount = new int[numsides];
|
||||
int realsegs = 0;
|
||||
|
||||
// Get floatng point coordinates of vertices
|
||||
for(int i = 0; i < numvertexes; i++)
|
||||
for(auto &v : level.vertexes)
|
||||
{
|
||||
vertexes[i].dirty = true;
|
||||
v.dirty = true;
|
||||
}
|
||||
|
||||
// count the segs
|
||||
memset(segcount, 0, numsides * sizeof(int));
|
||||
|
||||
// set up the extra data in case the map was loaded with regular nodes that might pass as GL nodes.
|
||||
if (glsegextras == NULL)
|
||||
{
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
segs[i].PartnerSeg = NULL;
|
||||
}
|
||||
for (int i=0; i<numsubsectors; i++)
|
||||
{
|
||||
int seg = int(subsectors[i].firstline-segs);
|
||||
for(DWORD j=0;j<subsectors[i].numlines;j++)
|
||||
{
|
||||
segs[j+seg].Subsector = &subsectors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
seg_t *seg = &segs[i];
|
||||
|
||||
// Account for ZDoom space optimizations that cannot be done for GL
|
||||
unsigned int partner= glsegextras[i].PartnerSeg;
|
||||
if (partner < unsigned(numsegs)) seg->PartnerSeg = &segs[partner];
|
||||
else seg->PartnerSeg = NULL;
|
||||
seg->Subsector = glsegextras[i].Subsector;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
seg_t *seg = &segs[i];
|
||||
|
||||
if (seg->sidedef == NULL) continue; // miniseg
|
||||
int sidenum = int(seg->sidedef - sides);
|
||||
int sidenum = seg->sidedef->Index();
|
||||
|
||||
realsegs++;
|
||||
segcount[sidenum]++;
|
||||
|
@ -557,13 +516,13 @@ static void PrepareSegs()
|
|||
}
|
||||
|
||||
// allocate memory
|
||||
sides[0].segs = new seg_t*[realsegs];
|
||||
sides[0].numsegs = 0;
|
||||
level.sides[0].segs = new seg_t*[realsegs];
|
||||
level.sides[0].numsegs = 0;
|
||||
|
||||
for(int i = 1; i < numsides; i++)
|
||||
for(unsigned i = 1; i < numsides; i++)
|
||||
{
|
||||
sides[i].segs = sides[i-1].segs + segcount[i-1];
|
||||
sides[i].numsegs = 0;
|
||||
level.sides[i].segs = level.sides[i-1].segs + segcount[i-1];
|
||||
level.sides[i].numsegs = 0;
|
||||
}
|
||||
delete [] segcount;
|
||||
|
||||
|
@ -575,9 +534,9 @@ static void PrepareSegs()
|
|||
}
|
||||
|
||||
// sort the segs
|
||||
for(int i = 0; i < numsides; i++)
|
||||
for(unsigned i = 0; i < numsides; i++)
|
||||
{
|
||||
if (sides[i].numsegs > 1) qsort(sides[i].segs, sides[i].numsegs, sizeof(seg_t*), segcmp);
|
||||
if (level.sides[i].numsegs > 1) qsort(level.sides[i].segs, level.sides[i].numsegs, sizeof(seg_t*), segcmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,38 +549,36 @@ extern int restart;
|
|||
|
||||
void gl_PreprocessLevel()
|
||||
{
|
||||
int i;
|
||||
|
||||
PrepareSegs();
|
||||
PrepareSectorData();
|
||||
InitVertexData();
|
||||
int *checkmap = new int[numvertexes];
|
||||
memset(checkmap, -1, sizeof(int)*numvertexes);
|
||||
for(i=0;i<numsectors;i++)
|
||||
int *checkmap = new int[level.vertexes.Size()];
|
||||
memset(checkmap, -1, sizeof(int)*level.vertexes.Size());
|
||||
for(auto &sec : level.sectors)
|
||||
{
|
||||
sectors[i].sectornum = i;
|
||||
PrepareTransparentDoors(§ors[i]);
|
||||
int i = sec.sectornum;
|
||||
PrepareTransparentDoors(&sec);
|
||||
|
||||
// This ignores vertices only used for seg splitting because those aren't needed here
|
||||
for(auto l : sectors[i].Lines)
|
||||
for(auto l : sec.Lines)
|
||||
{
|
||||
if (l->sidedef[0]->Flags & WALLF_POLYOBJ) continue; // don't bother with polyobjects
|
||||
|
||||
int vtnum1 = int(l->v1 - vertexes);
|
||||
int vtnum2 = int(l->v2 - vertexes);
|
||||
int vtnum1 = l->v1->Index();
|
||||
int vtnum2 = l->v2->Index();
|
||||
|
||||
if (checkmap[vtnum1] < i)
|
||||
{
|
||||
checkmap[vtnum1] = i;
|
||||
sectors[i].e->vertices.Push(&vertexes[vtnum1]);
|
||||
vertexes[vtnum1].dirty = true;
|
||||
sec.e->vertices.Push(&level.vertexes[vtnum1]);
|
||||
level.vertexes[vtnum1].dirty = true;
|
||||
}
|
||||
|
||||
if (checkmap[vtnum2] < i)
|
||||
{
|
||||
checkmap[vtnum2] = i;
|
||||
sectors[i].e->vertices.Push(&vertexes[vtnum2]);
|
||||
vertexes[vtnum2].dirty = true;
|
||||
sec.e->vertices.Push(&level.vertexes[vtnum2]);
|
||||
level.vertexes[vtnum2].dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -661,32 +618,15 @@ void gl_CleanLevelData()
|
|||
mo=next;
|
||||
}
|
||||
|
||||
if (vertexes != NULL)
|
||||
if (level.sides.Size() > 0 && level.sides[0].segs)
|
||||
{
|
||||
for(int i = 0; i < numvertexes; i++) if (vertexes[i].numsectors > 0)
|
||||
{
|
||||
if (vertexes[i].sectors != NULL)
|
||||
{
|
||||
delete [] vertexes[i].sectors;
|
||||
vertexes[i].sectors = NULL;
|
||||
}
|
||||
if (vertexes[i].heightlist != NULL)
|
||||
{
|
||||
delete [] vertexes[i].heightlist;
|
||||
vertexes[i].heightlist = NULL;
|
||||
}
|
||||
}
|
||||
delete [] level.sides[0].segs;
|
||||
level.sides[0].segs = NULL;
|
||||
}
|
||||
|
||||
if (sides && sides[0].segs)
|
||||
if (level.sectors.Size() > 0 && level.sectors[0].subsectors)
|
||||
{
|
||||
delete [] sides[0].segs;
|
||||
sides[0].segs = NULL;
|
||||
}
|
||||
if (sectors && sectors[0].subsectors)
|
||||
{
|
||||
delete [] sectors[0].subsectors;
|
||||
sectors[0].subsectors = NULL;
|
||||
delete [] level.sectors[0].subsectors;
|
||||
level.sectors[0].subsectors = nullptr;
|
||||
}
|
||||
for (int i=0;i<numsubsectors;i++)
|
||||
{
|
||||
|
@ -721,7 +661,7 @@ CCMD(listmapsections)
|
|||
{
|
||||
if (subsectors[j].mapsection == i)
|
||||
{
|
||||
Printf("Mapsection %d, sector %d, line %d\n", i, subsectors[j].render_sector->sectornum, int(subsectors[j].firstline->linedef-lines));
|
||||
Printf("Mapsection %d, sector %d, line %d\n", i, subsectors[j].render_sector->Index(), subsectors[j].firstline->linedef->Index());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "r_state.h"
|
||||
#include "m_argv.h"
|
||||
#include "c_cvars.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
|
@ -394,27 +395,25 @@ void FFlatVertexBuffer::CreateFlatVBO()
|
|||
{
|
||||
for (int h = sector_t::floor; h <= sector_t::ceiling; h++)
|
||||
{
|
||||
for(int i=0; i<numsectors;i++)
|
||||
for(auto &sec : level.sectors)
|
||||
{
|
||||
CreateVertices(h, §ors[i], sectors[i].GetSecPlane(h), h == sector_t::floor);
|
||||
CreateVertices(h, &sec, sec.GetSecPlane(h), h == sector_t::floor);
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do a final check for Vavoom water and FF_FIX sectors.
|
||||
// No new vertices are needed here. The planes come from the actual sector
|
||||
for(int i=0; i<numsectors;i++)
|
||||
for (auto &sec : level.sectors)
|
||||
{
|
||||
for(unsigned j=0;j<sectors[i].e->XFloor.ffloors.Size(); j++)
|
||||
for(auto ff : sec.e->XFloor.ffloors)
|
||||
{
|
||||
F3DFloor *ff = sectors[i].e->XFloor.ffloors[j];
|
||||
|
||||
if (ff->top.model == §ors[i])
|
||||
if (ff->top.model == &sec)
|
||||
{
|
||||
ff->top.vindex = sectors[i].vboindex[ff->top.isceiling];
|
||||
ff->top.vindex = sec.vboindex[ff->top.isceiling];
|
||||
}
|
||||
if (ff->bottom.model == §ors[i])
|
||||
if (ff->bottom.model == &sec)
|
||||
{
|
||||
ff->bottom.vindex = sectors[i].vboindex[ff->top.isceiling];
|
||||
ff->bottom.vindex = sec.vboindex[ff->top.isceiling];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include "portal.h"
|
||||
#include "doomstat.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
|
@ -108,50 +109,7 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight)
|
|||
// which is controlled by flags
|
||||
//
|
||||
//==========================================================================
|
||||
IMPLEMENT_CLASS (ADynamicLight, false, false)
|
||||
IMPLEMENT_CLASS (AVavoomLight, false, false)
|
||||
IMPLEMENT_CLASS (AVavoomLightWhite, false, false)
|
||||
IMPLEMENT_CLASS (AVavoomLightColor, false, false)
|
||||
|
||||
void AVavoomLight::BeginPlay ()
|
||||
{
|
||||
// This must not call Super::BeginPlay!
|
||||
ChangeStatNum(STAT_DLIGHT);
|
||||
if (Sector) AddZ(-Sector->floorplane.ZatPoint(this), false);
|
||||
lighttype = PointLight;
|
||||
}
|
||||
|
||||
void AVavoomLightWhite::BeginPlay ()
|
||||
{
|
||||
m_Radius[0] = args[0] * 4;
|
||||
args[LIGHT_RED] = 128;
|
||||
args[LIGHT_GREEN] = 128;
|
||||
args[LIGHT_BLUE] = 128;
|
||||
|
||||
if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
|
||||
{
|
||||
m_Radius[0] = m_Radius[0] * 2 / 3;
|
||||
}
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void AVavoomLightColor::BeginPlay ()
|
||||
{
|
||||
int l_args[5];
|
||||
memcpy(l_args, args, sizeof(l_args));
|
||||
memset(args, 0, sizeof(args));
|
||||
m_Radius[0] = l_args[0] * 4;
|
||||
args[LIGHT_RED] = l_args[1] >> 1;
|
||||
args[LIGHT_GREEN] = l_args[2] >> 1;
|
||||
args[LIGHT_BLUE] = l_args[3] >> 1;
|
||||
|
||||
if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
|
||||
{
|
||||
m_Radius[0] = m_Radius[0] * 2 / 3;
|
||||
}
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
IMPLEMENT_CLASS(ADynamicLight, false, false)
|
||||
|
||||
static FRandom randLight;
|
||||
|
||||
|
@ -173,8 +131,7 @@ void ADynamicLight::Serialize(FSerializer &arc)
|
|||
arc("lightflags", lightflags, def->lightflags)
|
||||
("lighttype", lighttype, def->lighttype)
|
||||
("tickcount", m_tickCount, def->m_tickCount)
|
||||
("currentradius", m_currentRadius, def->m_currentRadius)
|
||||
.Array("lightradius", m_Radius, def->m_Radius, 2);
|
||||
("currentradius", m_currentRadius, def->m_currentRadius);
|
||||
|
||||
if (lighttype == PulseLight)
|
||||
arc("lastupdate", m_lastUpdate, def->m_lastUpdate)
|
||||
|
@ -201,15 +158,13 @@ void ADynamicLight::BeginPlay()
|
|||
//Super::BeginPlay();
|
||||
ChangeStatNum(STAT_DLIGHT);
|
||||
|
||||
m_Radius[0] = args[LIGHT_INTENSITY];
|
||||
m_Radius[1] = args[LIGHT_SECONDARY_INTENSITY];
|
||||
specialf1 = DAngle(double(SpawnAngle)).Normalized360().Degrees;
|
||||
visibletoplayer = true;
|
||||
|
||||
if (gl.legacyMode && (flags4 & MF4_ATTENUATE))
|
||||
{
|
||||
m_Radius[0] = m_Radius[0] * 2 / 3;
|
||||
m_Radius[1] = m_Radius[1] * 2 / 3;
|
||||
args[LIGHT_INTENSITY] = args[LIGHT_INTENSITY] * 2 / 3;
|
||||
args[LIGHT_SECONDARY_INTENSITY] = args[LIGHT_SECONDARY_INTENSITY] * 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +196,7 @@ void ADynamicLight::Activate(AActor *activator)
|
|||
//Super::Activate(activator);
|
||||
flags2&=~MF2_DORMANT;
|
||||
|
||||
m_currentRadius = float(m_Radius[0]);
|
||||
m_currentRadius = float(args[LIGHT_INTENSITY]);
|
||||
m_tickCount = 0;
|
||||
|
||||
if (lighttype == PulseLight)
|
||||
|
@ -249,11 +204,12 @@ void ADynamicLight::Activate(AActor *activator)
|
|||
float pulseTime = specialf1 / TICRATE;
|
||||
|
||||
m_lastUpdate = level.maptime;
|
||||
m_cycler.SetParams(float(m_Radius[1]), float(m_Radius[0]), pulseTime);
|
||||
m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime);
|
||||
m_cycler.ShouldCycle(true);
|
||||
m_cycler.SetCycleType(CYCLE_Sin);
|
||||
m_currentRadius = m_cycler.GetVal();
|
||||
}
|
||||
if (m_currentRadius <= 0) m_currentRadius = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,25 +266,25 @@ void ADynamicLight::Tick()
|
|||
|
||||
case FlickerLight:
|
||||
{
|
||||
BYTE rnd = randLight();
|
||||
int rnd = randLight();
|
||||
float pct = specialf1 / 360.f;
|
||||
|
||||
m_currentRadius = float(m_Radius[rnd >= pct * 255]);
|
||||
m_currentRadius = float(args[LIGHT_INTENSITY + (rnd >= pct * 255)]);
|
||||
break;
|
||||
}
|
||||
|
||||
case RandomFlickerLight:
|
||||
{
|
||||
int flickerRange = m_Radius[1] - m_Radius[0];
|
||||
int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY];
|
||||
float amt = randLight() / 255.f;
|
||||
|
||||
if (m_tickCount > specialf1)
|
||||
{
|
||||
m_tickCount = 0;
|
||||
}
|
||||
if (m_tickCount++ == 0 || m_currentRadius > m_Radius[1])
|
||||
if (m_tickCount++ == 0 || m_currentRadius > args[LIGHT_SECONDARY_INTENSITY])
|
||||
{
|
||||
m_currentRadius = float(m_Radius[0] + (amt * flickerRange));
|
||||
m_currentRadius = float(args[LIGHT_INTENSITY] + (amt * flickerRange));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -337,7 +293,7 @@ void ADynamicLight::Tick()
|
|||
// These need some more work elsewhere
|
||||
case ColorFlickerLight:
|
||||
{
|
||||
BYTE rnd = randLight();
|
||||
int rnd = randLight();
|
||||
float pct = specialf1/360.f;
|
||||
|
||||
m_currentRadius = m_Radius[rnd >= pct * 255];
|
||||
|
@ -346,14 +302,14 @@ void ADynamicLight::Tick()
|
|||
|
||||
case RandomColorFlickerLight:
|
||||
{
|
||||
int flickerRange = m_Radius[1] - m_Radius[0];
|
||||
int flickerRange = args[LIGHT_SECONDARY_INTENSITY] - args[LIGHT_INTENSITY];
|
||||
float amt = randLight() / 255.f;
|
||||
|
||||
m_tickCount++;
|
||||
|
||||
if (m_tickCount > specialf1)
|
||||
{
|
||||
m_currentRadius = m_Radius[0] + (amt * flickerRange);
|
||||
m_currentRadius = args[LIGHT_INTENSITY] + (amt * flickerRange);
|
||||
m_tickCount = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -375,9 +331,10 @@ void ADynamicLight::Tick()
|
|||
}
|
||||
|
||||
case PointLight:
|
||||
m_currentRadius = float(m_Radius[0]);
|
||||
m_currentRadius = float(args[LIGHT_INTENSITY]);
|
||||
break;
|
||||
}
|
||||
if (m_currentRadius <= 0) m_currentRadius = 1;
|
||||
UpdateLocation();
|
||||
}
|
||||
|
||||
|
@ -427,14 +384,14 @@ void ADynamicLight::UpdateLocation()
|
|||
|
||||
if (lighttype == FlickerLight || lighttype == RandomFlickerLight || lighttype == PulseLight)
|
||||
{
|
||||
intensity = float(MAX(m_Radius[0], m_Radius[1]));
|
||||
intensity = float(MAX(args[LIGHT_INTENSITY], args[LIGHT_SECONDARY_INTENSITY]));
|
||||
}
|
||||
else
|
||||
{
|
||||
intensity = m_currentRadius;
|
||||
}
|
||||
radius = intensity * 2.0f;
|
||||
assert(radius >= m_currentRadius * 2);
|
||||
if (radius < m_currentRadius * 2) radius = m_currentRadius * 2;
|
||||
|
||||
if (X() != oldx || Y() != oldy || radius != oldradius)
|
||||
{
|
||||
|
@ -804,10 +761,10 @@ void ADynamicLight::UnlinkLight ()
|
|||
while (touching_sector) touching_sector = DeleteLightNode(touching_sector);
|
||||
}
|
||||
|
||||
void ADynamicLight::Destroy()
|
||||
void ADynamicLight::OnDestroy()
|
||||
{
|
||||
UnlinkLight();
|
||||
Super::Destroy();
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue