# 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:
nashmuhandes 2017-02-05 20:13:39 +08:00
commit 032ad95b0f
363 changed files with 18221 additions and 17499 deletions

View file

@ -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

View file

@ -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
===============================================================================

View file

@ -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)

View file

@ -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 };

View file

@ -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]);

View file

@ -26,6 +26,8 @@ IMPLEMENT_POINTERS_START(DBot)
IMPLEMENT_POINTER(last_mate)
IMPLEMENT_POINTERS_END
DEFINE_FIELD(DBot, dest)
DBot::DBot ()
: DThinker(STAT_BOT)
{

View file

@ -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;

View file

@ -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];

View file

@ -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 ||

View file

@ -49,6 +49,7 @@
#include "d_player.h"
#include "g_level.h"
#include "doomstat.h"
#include "g_levellocals.h"
// MACROS ------------------------------------------------------------------

View file

@ -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;

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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
{

View file

@ -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 = &sectors[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)

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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:

View file

@ -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
//

View file

@ -49,6 +49,7 @@
#include "colormatcher.h"
#include "b_bot.h"
#include "serializer.h"
#include "g_levellocals.h"
FDecalLib DecalLibrary;

View file

@ -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;
}

View file

@ -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,

View file

@ -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 = &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;
}
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;

View file

@ -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);
}

View file

@ -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

View file

@ -30,6 +30,7 @@
#include "i_system.h"
#include "g_level.h"
#include "p_local.h"
#include "g_levellocals.h"
int SaveVersion;

View file

@ -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

View file

@ -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));
}

View file

@ -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

View file

@ -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)
{
}

View file

@ -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

View file

@ -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(&sectors[i], sectorrecord[i]);
ProcessEDSector(&level.sectors[i], sectorrecord[i]);
}
}
delete[] sectorrecord;

View file

@ -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

View file

@ -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 = &sectors[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(&sectors[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(&sectors[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 = &sectors[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(&sectors[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 = &sectors[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 = &sectors[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=&sectors[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 = &sectors[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));
}

View file

@ -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;
}
}

View file

@ -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 = &sectors[secnum];
sector_t *sec = &level.sectors[secnum];
if(sec->floordata || sec->ceilingdata || sec->lightingdata)
return false; // not finished
}

View file

@ -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);

View file

@ -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");
}

View file

@ -44,6 +44,7 @@
#include "gstrings.h"
#include "wi_stuff.h"
#include "serializer.h"
#include "g_levellocals.h"
//==========================================================================

View file

@ -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;
}
}
}
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -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

View file

@ -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__

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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__

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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)
//==========================================================================
//

View file

@ -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
View 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;
}

View file

@ -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 },

View file

@ -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)

View file

@ -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];
}

View file

@ -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)

View file

@ -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;
}
}
}
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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();

View file

@ -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)

View file

@ -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);
}

View file

@ -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__

View file

@ -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 ();
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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 ----------------------------------------------------------

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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]);
}

View file

@ -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__

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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 ()

View file

@ -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"

View file

@ -148,7 +148,7 @@ struct gameinfo_t
FString translator;
DWORD defaultbloodcolor;
DWORD defaultbloodparticlecolor;
FString backpacktype;
FName backpacktype;
FString statusbar;
FString intermissionMusic;
int intermissionOrder;

View file

@ -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"

View file

@ -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 = &sectors[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 &sector : level.sectors)
{
sector_t * sector = &sectors[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);
}

View file

@ -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

View file

@ -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 = &sectors[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);
}
}

View file

@ -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] = &sectors[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(&sectors[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;
}
}

View file

@ -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, &sectors[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 == &sectors[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 == &sectors[i])
if (ff->bottom.model == &sec)
{
ff->bottom.vindex = sectors[i].vboindex[ff->top.isceiling];
ff->bottom.vindex = sec.vboindex[ff->top.isceiling];
}
}
}

View file

@ -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