Merge remote-tracking branch 'origin/new_level_refactor' into HEAD

This commit is contained in:
Rachael Alexanderson 2019-02-06 03:56:27 -05:00
commit d96d0b43f8
795 changed files with 36646 additions and 12163 deletions

47
CMakeSettings.json Normal file
View file

@ -0,0 +1,47 @@
{
"configurations": [
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "ZDOOM_GENERATE_ASM",
"value": "True",
"type": "BOOL"
},
{
"name": "ZDOOM_GENERATE_MAPFILE",
"value": "True",
"type": "BOOL"
},
{
"name": "ZDOOM_OUTPUT_OLDSTYLE",
"value": "True",
"type": "BOOL"
},
{
"name": "JPEG_INCLUDE_DIR",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\include\\",
"type": "PATH"
},
{
"name": "JPEG_LIBRARY_DEBUG",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\lib\\jpeg.lib",
"type": "FILEPATH"
},
{
"name": "JPEG_LIBRARY_RELEASE",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\lib\\jpeg.lib",
"type": "FILEPATH"
}
]
}
]
}

21073
externs.txt Normal file

File diff suppressed because it is too large Load diff

BIN
externs.zip Normal file

Binary file not shown.

1073
p_destructible.cpp Normal file

File diff suppressed because it is too large Load diff

43
p_destructible.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include "tarray.h"
#include "r_defs.h"
#include "p_trace.h"
// [ZZ] Destructible geometry related
struct FHealthGroup
{
TArray<sector_t*> sectors;
TArray<line_t*> lines;
int health;
int id;
};
// for P_DamageSector
enum
{
SECPART_Floor = 0,
SECPART_Ceiling = 1,
SECPART_3D = 2
};
void P_SetHealthGroupHealth(FHealthGroup* group, int health);
void P_SetHealthGroupHealth(FLevelLocals *Level, int group, int health);
void P_InitHealthGroups(FLevelLocals *Level);
FHealthGroup* P_GetHealthGroup(FLevelLocals *Level, int id);
FHealthGroup* P_GetHealthGroupOrNew(FLevelLocals *Level, int id, int startinghealth);
void P_DamageSector(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius, bool dogroups);
void P_DamageLinedef(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius, bool dogroups);
void P_GeometryLineAttack(FTraceResults& trace, AActor* thing, int damage, FName damageType);
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance);
bool P_ProjectileHitLinedef(AActor* projectile, line_t* line);
bool P_ProjectileHitPlane(AActor* projectile, int part);
bool P_CheckLinedefVulnerable(line_t* line, int side, int part = -1);
bool P_CheckSectorVulnerable(sector_t* sector, int part);
void P_SerializeHealthGroups(FSerializer& arc);

View file

@ -570,17 +570,17 @@ if( HAVE_MMX )
add_definitions( -DHAVE_MMX=1 )
set( SYSTEM_SOURCES ${SYSTEM_SOURCES}
textures/hires/hqnx_asm/hq2x_asm.cpp
textures/hires/hqnx_asm/hq3x_asm.cpp
textures/hires/hqnx_asm/hq4x_asm.cpp
textures/hires/hqnx_asm/hqnx_asm_Image.cpp)
gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp
gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp
gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp
gamedata/textures/hires/hqnx_asm/hqnx_asm_Image.cpp)
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set_source_files_properties(
textures/hires/hqnx_asm/hq2x_asm.cpp
textures/hires/hqnx_asm/hq3x_asm.cpp
textures/hires/hqnx_asm/hq4x_asm.cpp
textures/hires/gl_hqresize.cpp
gamedata/textures/hires/hqnx_asm/hq2x_asm.cpp
gamedata/textures/hires/hqnx_asm/hq3x_asm.cpp
gamedata/textures/hires/hqnx_asm/hq4x_asm.cpp
gamedata/textures/hires/gl_hqresize.cpp
PROPERTIES COMPILE_FLAGS "-mmmx" )
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
endif( HAVE_MMX )
@ -603,16 +603,16 @@ else()
endif()
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y )
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/gamedata/xlat/xlat_parser.y
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/gamedata/xlat/xlat_parser.y )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re
DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re )
COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re
DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re )
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
@ -653,7 +653,13 @@ file( GLOB HEADER_FILES
fragglescript/*.h
g_shared/*.h
g_statusbar/*.h
g_inventory/*.h
gamedata/*.h
gamedata/resourcefiles/*.h
gamedata/textures/*.h
gamedata/textures/hires/hqnx/*.h
gamedata/textures/hires/hqnx_asm/*.h
gamedata/textures/hires/xbr/*.h
gamedata/xlat/*.h
intermission/*.h
maploader/*.h
menu/*.h
@ -667,14 +673,11 @@ file( GLOB HEADER_FILES
win32/*.h
r_data/*.h
r_data/models/*.h
rapidjson/*.h
resourcefiles/*.h
sfmt/*.h
utility/rapidjson/*.h
utility/sfmt/*.h
utility/math./*h
utility/*.h
sound/*.h
textures/*.h
textures/hires/hqnx/*.h
textures/hires/hqnx_asm/*.h
textures/hires/xbr/*.h
scripting/*.h
scripting/backend/*.h
scripting/decorate/*.h
@ -687,106 +690,105 @@ file( GLOB HEADER_FILES
sound/timidity/*.h
sound/timiditypp/*.h
sound/wildmidi/*.h
xlat/*.h
swrenderer/*.h
swrenderer/textures/*.h
swrenderer/drawers/*.h
swrenderer/scene/*.h
swrenderer/segments/*.h
swrenderer/line/*.h
swrenderer/plane/*.h
swrenderer/things/*.h
swrenderer/viewport/*.h
polyrenderer/*.h
polyrenderer/math/*.h
polyrenderer/drawers/*.h
polyrenderer/scene/*.h
hwrenderer/data/*.h
hwrenderer/dynlights/*.h
hwrenderer/models/*.h
hwrenderer/postprocessing/*.h
hwrenderer/scene/*.h
hwrenderer/textures/*.h
hwrenderer/utility/*.h
gl/*.h
gl/models/*.h
gl/renderer/*.h
gl/scene/*.h
gl/shaders/*.h
gl/system/*.h
gl/textures/*.h
gl_load/*.h
rendering/swrenderer/*.h
rendering/swrenderer/textures/*.h
rendering/swrenderer/drawers/*.h
rendering/swrenderer/scene/*.h
rendering/swrenderer/segments/*.h
rendering/swrenderer/line/*.h
rendering/swrenderer/plane/*.h
rendering/swrenderer/things/*.h
rendering/swrenderer/viewport/*.h
rendering/polyrenderer/*.h
rendering/polyrenderer/math/*.h
rendering/polyrenderer/drawers/*.h
rendering/polyrenderer/scene/*.h
rendering/hwrenderer/data/*.h
rendering/hwrenderer/dynlights/*.h
rendering/hwrenderer/models/*.h
rendering/hwrenderer/postprocessing/*.h
rendering/hwrenderer/scene/*.h
rendering/hwrenderer/textures/*.h
rendering/hwrenderer/utility/*.h
rendering/gl/*.h
rendering/gl/models/*.h
rendering/gl/renderer/*.h
rendering/gl/scene/*.h
rendering/gl/shaders/*.h
rendering/gl/system/*.h
rendering/gl/textures/*.h
rendering/gl_load/*.h
*.h
)
set ( SWRENDER_SOURCES
swrenderer/r_swcolormaps.cpp
swrenderer/r_swrenderer.cpp
swrenderer/r_memory.cpp
swrenderer/r_renderthread.cpp
swrenderer/drawers/r_draw.cpp
swrenderer/drawers/r_draw_pal.cpp
swrenderer/drawers/r_draw_rgba.cpp
swrenderer/drawers/r_thread.cpp
swrenderer/scene/r_3dfloors.cpp
swrenderer/scene/r_light.cpp
swrenderer/scene/r_opaque_pass.cpp
swrenderer/scene/r_portal.cpp
swrenderer/scene/r_scene.cpp
swrenderer/scene/r_translucent_pass.cpp
swrenderer/viewport/r_drawerargs.cpp
swrenderer/viewport/r_skydrawer.cpp
swrenderer/viewport/r_spandrawer.cpp
swrenderer/viewport/r_spritedrawer.cpp
swrenderer/viewport/r_viewport.cpp
swrenderer/viewport/r_walldrawer.cpp
swrenderer/line/r_line.cpp
swrenderer/line/r_farclip_line.cpp
swrenderer/line/r_walldraw.cpp
swrenderer/line/r_wallsetup.cpp
swrenderer/line/r_fogboundary.cpp
swrenderer/line/r_renderdrawsegment.cpp
swrenderer/segments/r_clipsegment.cpp
swrenderer/segments/r_drawsegment.cpp
swrenderer/segments/r_portalsegment.cpp
swrenderer/things/r_visiblesprite.cpp
swrenderer/things/r_visiblespritelist.cpp
swrenderer/things/r_voxel.cpp
swrenderer/things/r_particle.cpp
swrenderer/things/r_playersprite.cpp
swrenderer/things/r_sprite.cpp
swrenderer/things/r_wallsprite.cpp
swrenderer/things/r_decal.cpp
swrenderer/things/r_model.cpp
swrenderer/plane/r_visibleplane.cpp
swrenderer/plane/r_visibleplanelist.cpp
swrenderer/plane/r_skyplane.cpp
swrenderer/plane/r_planerenderer.cpp
swrenderer/plane/r_flatplane.cpp
swrenderer/plane/r_slopeplane.cpp
rendering/swrenderer/r_swcolormaps.cpp
rendering/swrenderer/r_swrenderer.cpp
rendering/swrenderer/r_memory.cpp
rendering/swrenderer/r_renderthread.cpp
rendering/swrenderer/drawers/r_draw.cpp
rendering/swrenderer/drawers/r_draw_pal.cpp
rendering/swrenderer/drawers/r_draw_rgba.cpp
rendering/swrenderer/drawers/r_thread.cpp
rendering/swrenderer/scene/r_3dfloors.cpp
rendering/swrenderer/scene/r_light.cpp
rendering/swrenderer/scene/r_opaque_pass.cpp
rendering/swrenderer/scene/r_portal.cpp
rendering/swrenderer/scene/r_scene.cpp
rendering/swrenderer/scene/r_translucent_pass.cpp
rendering/swrenderer/viewport/r_drawerargs.cpp
rendering/swrenderer/viewport/r_skydrawer.cpp
rendering/swrenderer/viewport/r_spandrawer.cpp
rendering/swrenderer/viewport/r_spritedrawer.cpp
rendering/swrenderer/viewport/r_viewport.cpp
rendering/swrenderer/viewport/r_walldrawer.cpp
rendering/swrenderer/line/r_line.cpp
rendering/swrenderer/line/r_farclip_line.cpp
rendering/swrenderer/line/r_walldraw.cpp
rendering/swrenderer/line/r_wallsetup.cpp
rendering/swrenderer/line/r_fogboundary.cpp
rendering/swrenderer/line/r_renderdrawsegment.cpp
rendering/swrenderer/segments/r_clipsegment.cpp
rendering/swrenderer/segments/r_drawsegment.cpp
rendering/swrenderer/segments/r_portalsegment.cpp
rendering/swrenderer/things/r_visiblesprite.cpp
rendering/swrenderer/things/r_visiblespritelist.cpp
rendering/swrenderer/things/r_voxel.cpp
rendering/swrenderer/things/r_particle.cpp
rendering/swrenderer/things/r_playersprite.cpp
rendering/swrenderer/things/r_sprite.cpp
rendering/swrenderer/things/r_wallsprite.cpp
rendering/swrenderer/things/r_decal.cpp
rendering/swrenderer/things/r_model.cpp
rendering/swrenderer/plane/r_visibleplane.cpp
rendering/swrenderer/plane/r_visibleplanelist.cpp
rendering/swrenderer/plane/r_skyplane.cpp
rendering/swrenderer/plane/r_planerenderer.cpp
rendering/swrenderer/plane/r_flatplane.cpp
rendering/swrenderer/plane/r_slopeplane.cpp
)
set( POLYRENDER_SOURCES
polyrenderer/poly_renderer.cpp
polyrenderer/poly_renderthread.cpp
polyrenderer/scene/poly_scene.cpp
polyrenderer/scene/poly_portal.cpp
polyrenderer/scene/poly_cull.cpp
polyrenderer/scene/poly_decal.cpp
polyrenderer/scene/poly_particle.cpp
polyrenderer/scene/poly_plane.cpp
polyrenderer/scene/poly_playersprite.cpp
polyrenderer/scene/poly_wall.cpp
polyrenderer/scene/poly_wallsprite.cpp
polyrenderer/scene/poly_sprite.cpp
polyrenderer/scene/poly_model.cpp
polyrenderer/scene/poly_sky.cpp
polyrenderer/scene/poly_light.cpp
polyrenderer/drawers/poly_buffer.cpp
polyrenderer/drawers/poly_triangle.cpp
polyrenderer/drawers/poly_draw_args.cpp
polyrenderer/drawers/screen_triangle.cpp
polyrenderer/math/gpu_types.cpp
rendering/polyrenderer/poly_renderer.cpp
rendering/polyrenderer/poly_renderthread.cpp
rendering/polyrenderer/scene/poly_scene.cpp
rendering/polyrenderer/scene/poly_portal.cpp
rendering/polyrenderer/scene/poly_cull.cpp
rendering/polyrenderer/scene/poly_decal.cpp
rendering/polyrenderer/scene/poly_particle.cpp
rendering/polyrenderer/scene/poly_plane.cpp
rendering/polyrenderer/scene/poly_playersprite.cpp
rendering/polyrenderer/scene/poly_wall.cpp
rendering/polyrenderer/scene/poly_wallsprite.cpp
rendering/polyrenderer/scene/poly_sprite.cpp
rendering/polyrenderer/scene/poly_model.cpp
rendering/polyrenderer/scene/poly_sky.cpp
rendering/polyrenderer/scene/poly_light.cpp
rendering/polyrenderer/drawers/poly_buffer.cpp
rendering/polyrenderer/drawers/poly_triangle.cpp
rendering/polyrenderer/drawers/poly_draw_args.cpp
rendering/polyrenderer/drawers/screen_triangle.cpp
rendering/polyrenderer/math/gpu_types.cpp
)
# These files will be flagged as "headers" so that they appear in project files
@ -796,9 +798,9 @@ set( NOT_COMPILED_SOURCE_FILES
${SWRENDER_SOURCES}
${POLYRENDER_SOURCES}
sc_man_scanner.h
sc_man_scanner.re
utility/sc_man_scanner.re
g_statusbar/sbarinfo_commands.cpp
xlat/xlat_parser.y
gamedata/xlat/xlat_parser.y
xlat_parser.c
xlat_parser.h
scripting/zscript/zcc-parse.lemon
@ -823,9 +825,9 @@ set( VM_JIT_SOURCES
# Enable fast math for some sources
set( FASTMATH_SOURCES
swrenderer/r_all.cpp
swrenderer/r_swscene.cpp
polyrenderer/poly_all.cpp
rendering/swrenderer/r_all.cpp
rendering/swrenderer/r_swscene.cpp
rendering/polyrenderer/poly_all.cpp
sound/oplsynth/opl_mus_player.cpp
sound/mpg123_decoder.cpp
sound/music_midi_base.cpp
@ -833,32 +835,32 @@ set( FASTMATH_SOURCES
sound/sndfile_decoder.cpp
sound/timiditypp/fft4g.cpp
sound/timiditypp/reverb.cpp
textures/hires/hqnx/init.cpp
textures/hires/hqnx/hq2x.cpp
textures/hires/hqnx/hq3x.cpp
textures/hires/hqnx/hq4x.cpp
textures/hires/xbr/xbrz.cpp
textures/hires/xbr/xbrz_old.cpp
gl_load/gl_load.c
hwrenderer/postprocessing/hw_postprocess_cvars.cpp
hwrenderer/postprocessing/hw_postprocessshader.cpp
hwrenderer/dynlights/hw_dynlightdata.cpp
hwrenderer/scene/hw_bsp.cpp
hwrenderer/scene/hw_fakeflat.cpp
hwrenderer/scene/hw_decal.cpp
hwrenderer/scene/hw_drawinfo.cpp
hwrenderer/scene/hw_drawlist.cpp
hwrenderer/scene/hw_clipper.cpp
hwrenderer/scene/hw_flats.cpp
hwrenderer/scene/hw_portal.cpp
hwrenderer/scene/hw_renderhacks.cpp
hwrenderer/scene/hw_sky.cpp
hwrenderer/scene/hw_skyportal.cpp
hwrenderer/scene/hw_sprites.cpp
hwrenderer/scene/hw_spritelight.cpp
hwrenderer/scene/hw_walls.cpp
hwrenderer/scene/hw_walls_vertex.cpp
hwrenderer/scene/hw_weapon.cpp
gamedata/textures/hires/hqnx/init.cpp
gamedata/textures/hires/hqnx/hq2x.cpp
gamedata/textures/hires/hqnx/hq3x.cpp
gamedata/textures/hires/hqnx/hq4x.cpp
gamedata/textures/hires/xbr/xbrz.cpp
gamedata/textures/hires/xbr/xbrz_old.cpp
rendering/gl_load/gl_load.c
rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp
rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp
rendering/hwrenderer/dynlights/hw_dynlightdata.cpp
rendering/hwrenderer/scene/hw_bsp.cpp
rendering/hwrenderer/scene/hw_fakeflat.cpp
rendering/hwrenderer/scene/hw_decal.cpp
rendering/hwrenderer/scene/hw_drawinfo.cpp
rendering/hwrenderer/scene/hw_drawlist.cpp
rendering/hwrenderer/scene/hw_clipper.cpp
rendering/hwrenderer/scene/hw_flats.cpp
rendering/hwrenderer/scene/hw_portal.cpp
rendering/hwrenderer/scene/hw_renderhacks.cpp
rendering/hwrenderer/scene/hw_sky.cpp
rendering/hwrenderer/scene/hw_skyportal.cpp
rendering/hwrenderer/scene/hw_sprites.cpp
rendering/hwrenderer/scene/hw_spritelight.cpp
rendering/hwrenderer/scene/hw_walls.cpp
rendering/hwrenderer/scene/hw_walls_vertex.cpp
rendering/hwrenderer/scene/hw_weapon.cpp
r_data/models/models.cpp
r_data/matrix.cpp
sound/adlmidi/adldata.cpp
@ -890,7 +892,6 @@ set( FASTMATH_SOURCES
)
set (PCH_SOURCES
actorptrselect.cpp
am_map.cpp
b_bot.cpp
b_func.cpp
@ -906,124 +907,66 @@ set (PCH_SOURCES
c_dispatch.cpp
c_expr.cpp
c_functions.cpp
cmdlib.cpp
colormatcher.cpp
configfile.cpp
ct_chat.cpp
cycler.cpp
d_dehacked.cpp
d_iwad.cpp
d_main.cpp
d_anonstats.cpp
d_net.cpp
d_netinfo.cpp
d_protocol.cpp
decallib.cpp
dobject.cpp
dobjgc.cpp
dobjtype.cpp
doomstat.cpp
dsectoreffect.cpp
dthinker.cpp
f_wipe.cpp
files.cpp
files_decompress.cpp
g_doomedmap.cpp
g_cvars.cpp
g_dumpinfo.cpp
g_game.cpp
g_hub.cpp
g_level.cpp
g_mapinfo.cpp
g_skill.cpp
gameconfigfile.cpp
gi.cpp
gitinfo.cpp
hu_scores.cpp
i_module.cpp
i_net.cpp
i_time.cpp
info.cpp
keysections.cpp
m_alloc.cpp
m_argv.cpp
m_bbox.cpp
m_cheat.cpp
m_joy.cpp
m_misc.cpp
m_png.cpp
m_random.cpp
memarena.cpp
md5.cpp
name.cpp
nodebuild.cpp
nodebuild_classify_nosse2.cpp
nodebuild_events.cpp
nodebuild_extract.cpp
nodebuild_gl.cpp
nodebuild_utility.cpp
p_3dfloors.cpp
p_3dmidtex.cpp
p_acs.cpp
p_actionfunctions.cpp
p_ceiling.cpp
p_conversation.cpp
p_destructible.cpp
p_doors.cpp
p_effect.cpp
p_enemy.cpp
p_floor.cpp
p_interaction.cpp
p_lights.cpp
p_linkedsectors.cpp
p_lnspec.cpp
p_map.cpp
p_maputl.cpp
p_mobj.cpp
p_openmap.cpp
p_pillar.cpp
p_plats.cpp
p_pspr.cpp
p_pusher.cpp
p_saveg.cpp
p_scroll.cpp
p_secnodes.cpp
p_sectors.cpp
p_setup.cpp
p_sight.cpp
p_spec.cpp
p_states.cpp
p_switch.cpp
p_tags.cpp
p_teleport.cpp
p_terrain.cpp
p_things.cpp
p_tick.cpp
p_trace.cpp
p_usdf.cpp
p_user.cpp
p_xlat.cpp
parsecontext.cpp
po_man.cpp
portal.cpp
r_utility.cpp
r_sky.cpp
r_videoscale.cpp
s_advsound.cpp
s_environment.cpp
s_playlist.cpp
s_sndseq.cpp
s_sound.cpp
serializer.cpp
sc_man.cpp
scriptutil.cpp
st_stuff.cpp
statistics.cpp
stats.cpp
stringtable.cpp
teaminfo.cpp
umapinfo.cpp
v_2ddrawer.cpp
v_blend.cpp
v_collection.cpp
v_draw.cpp
v_font.cpp
v_framebuffer.cpp
@ -1031,66 +974,103 @@ set (PCH_SOURCES
v_pfx.cpp
v_text.cpp
v_video.cpp
w_wad.cpp
wi_stuff.cpp
zstrformat.cpp
g_inventory/a_keys.cpp
g_inventory/a_pickups.cpp
g_inventory/a_weapons.cpp
gamedata/a_keys.cpp
gamedata/a_weapons.cpp
gamedata/decallib.cpp
gamedata/g_mapinfo.cpp
gamedata/g_skill.cpp
gamedata/gi.cpp
gamedata/stringtable.cpp
gamedata/umapinfo.cpp
gamedata/w_wad.cpp
gamedata/d_dehacked.cpp
gamedata/g_doomedmap.cpp
gamedata/info.cpp
gamedata/keysections.cpp
gamedata/p_terrain.cpp
gamedata/teaminfo.cpp
g_shared/a_pickups.cpp
g_shared/a_action.cpp
g_shared/a_decals.cpp
g_shared/a_decalfx.cpp
g_shared/a_doors.cpp
g_shared/a_dynlight.cpp
g_shared/a_flashfader.cpp
g_shared/a_lightning.cpp
g_shared/a_morph.cpp
g_shared/a_quake.cpp
g_shared/a_specialspot.cpp
g_shared/hudmessages.cpp
g_shared/shared_hud.cpp
g_shared/a_ceiling.cpp
g_shared/a_floor.cpp
g_shared/a_lights.cpp
g_shared/a_lighttransfer.cpp
g_shared/a_pillar.cpp
g_shared/a_plats.cpp
g_shared/a_pusher.cpp
g_shared/a_scroll.cpp
g_shared/dsectoreffect.cpp
g_shared/p_secnodes.cpp
g_shared/p_sectors.cpp
g_shared/p_sight.cpp
g_shared/p_switch.cpp
g_shared/p_tags.cpp
g_shared/p_teleport.cpp
g_shared/actorptrselect.cpp
g_shared/dthinker.cpp
g_shared/p_3dfloors.cpp
g_shared/p_3dmidtex.cpp
g_shared/p_linkedsectors.cpp
g_shared/p_trace.cpp
g_shared/po_man.cpp
g_shared/portal.cpp
g_statusbar/hudmessages.cpp
g_statusbar/shared_hud.cpp
g_statusbar/sbarinfo.cpp
g_statusbar/sbar_mugshot.cpp
g_statusbar/shared_sbar.cpp
gl/renderer/gl_renderer.cpp
gl/renderer/gl_renderstate.cpp
gl/renderer/gl_renderbuffers.cpp
gl/renderer/gl_postprocess.cpp
gl/renderer/gl_postprocessstate.cpp
gl/renderer/gl_stereo3d.cpp
gl/renderer/gl_scene.cpp
gl/shaders/gl_shader.cpp
gl/shaders/gl_shaderprogram.cpp
gl/shaders/gl_postprocessshader.cpp
gl_load/gl_interface.cpp
gl/system/gl_framebuffer.cpp
gl/system/gl_debug.cpp
gl/system/gl_buffers.cpp
gl/textures/gl_hwtexture.cpp
gl/textures/gl_samplers.cpp
hwrenderer/data/hw_vertexbuilder.cpp
hwrenderer/data/flatvertices.cpp
hwrenderer/data/hw_viewpointbuffer.cpp
hwrenderer/dynlights/hw_aabbtree.cpp
hwrenderer/dynlights/hw_shadowmap.cpp
hwrenderer/dynlights/hw_lightbuffer.cpp
hwrenderer/models/hw_models.cpp
hwrenderer/scene/hw_skydome.cpp
hwrenderer/scene/hw_drawlistadd.cpp
hwrenderer/scene/hw_renderstate.cpp
hwrenderer/postprocessing/hw_postprocess.cpp
hwrenderer/postprocessing/hw_postprocess_cvars.cpp
hwrenderer/postprocessing/hw_postprocessshader.cpp
hwrenderer/postprocessing/hw_shadowmapshader.cpp
hwrenderer/postprocessing/hw_presentshader.cpp
hwrenderer/postprocessing/hw_present3dRowshader.cpp
hwrenderer/textures/hw_material.cpp
hwrenderer/textures/hw_precache.cpp
hwrenderer/utility/hw_clock.cpp
hwrenderer/utility/hw_cvars.cpp
hwrenderer/utility/hw_draw2d.cpp
hwrenderer/utility/hw_lighting.cpp
hwrenderer/utility/hw_shaderpatcher.cpp
hwrenderer/utility/hw_vrmodes.cpp
rendering/gl/renderer/gl_renderer.cpp
rendering/gl/renderer/gl_renderstate.cpp
rendering/gl/renderer/gl_renderbuffers.cpp
rendering/gl/renderer/gl_postprocess.cpp
rendering/gl/renderer/gl_postprocessstate.cpp
rendering/gl/renderer/gl_stereo3d.cpp
rendering/gl/renderer/gl_scene.cpp
rendering/gl/shaders/gl_shader.cpp
rendering/gl/shaders/gl_shaderprogram.cpp
rendering/gl/shaders/gl_postprocessshader.cpp
rendering/gl_load/gl_interface.cpp
rendering/gl/system/gl_framebuffer.cpp
rendering/gl/system/gl_debug.cpp
rendering/gl/system/gl_buffers.cpp
rendering/gl/textures/gl_hwtexture.cpp
rendering/gl/textures/gl_samplers.cpp
rendering/hwrenderer/data/hw_vertexbuilder.cpp
rendering/hwrenderer/data/flatvertices.cpp
rendering/hwrenderer/data/hw_viewpointbuffer.cpp
rendering/hwrenderer/dynlights/hw_aabbtree.cpp
rendering/hwrenderer/dynlights/hw_shadowmap.cpp
rendering/hwrenderer/dynlights/hw_lightbuffer.cpp
rendering/hwrenderer/models/hw_models.cpp
rendering/hwrenderer/scene/hw_skydome.cpp
rendering/hwrenderer/scene/hw_drawlistadd.cpp
rendering/hwrenderer/scene/hw_renderstate.cpp
rendering/hwrenderer/postprocessing/hw_postprocess.cpp
rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp
rendering/hwrenderer/postprocessing/hw_postprocessshader.cpp
rendering/hwrenderer/postprocessing/hw_shadowmapshader.cpp
rendering/hwrenderer/postprocessing/hw_presentshader.cpp
rendering/hwrenderer/postprocessing/hw_present3dRowshader.cpp
rendering/hwrenderer/textures/hw_material.cpp
rendering/hwrenderer/textures/hw_precache.cpp
rendering/hwrenderer/utility/hw_clock.cpp
rendering/hwrenderer/utility/hw_cvars.cpp
rendering/hwrenderer/utility/hw_draw2d.cpp
rendering/hwrenderer/utility/hw_lighting.cpp
rendering/hwrenderer/utility/hw_shaderpatcher.cpp
rendering/hwrenderer/utility/hw_vrmodes.cpp
maploader/edata.cpp
maploader/specials.cpp
maploader/maploader.cpp
maploader/slopes.cpp
maploader/glnodes.cpp
@ -1106,46 +1086,48 @@ set (PCH_SOURCES
menu/optionmenu.cpp
menu/playermenu.cpp
menu/resolutionmenu.cpp
resourcefiles/ancientzip.cpp
resourcefiles/file_7z.cpp
resourcefiles/file_grp.cpp
resourcefiles/file_lump.cpp
resourcefiles/file_rff.cpp
resourcefiles/file_wad.cpp
resourcefiles/file_zip.cpp
resourcefiles/file_pak.cpp
resourcefiles/file_directory.cpp
resourcefiles/resourcefile.cpp
textures/animations.cpp
textures/anim_switches.cpp
textures/bitmap.cpp
textures/texture.cpp
textures/image.cpp
textures/imagetexture.cpp
textures/texturemanager.cpp
textures/multipatchtexturebuilder.cpp
textures/skyboxtexture.cpp
textures/formats/automaptexture.cpp
textures/formats/brightmaptexture.cpp
textures/formats/buildtexture.cpp
textures/formats/canvastexture.cpp
textures/formats/ddstexture.cpp
textures/formats/flattexture.cpp
textures/formats/fontchars.cpp
textures/formats/imgztexture.cpp
textures/formats/jpegtexture.cpp
textures/formats/md5check.cpp
textures/formats/multipatchtexture.cpp
textures/formats/patchtexture.cpp
textures/formats/pcxtexture.cpp
textures/formats/pngtexture.cpp
textures/formats/rawpagetexture.cpp
textures/formats/emptytexture.cpp
textures/formats/shadertexture.cpp
textures/formats/tgatexture.cpp
textures/hires/hqresize.cpp
textures/hires/hirestex.cpp
xlat/parse_xlat.cpp
gamedata/resourcefiles/ancientzip.cpp
gamedata/resourcefiles/file_7z.cpp
gamedata/resourcefiles/file_grp.cpp
gamedata/resourcefiles/file_lump.cpp
gamedata/resourcefiles/file_rff.cpp
gamedata/resourcefiles/file_wad.cpp
gamedata/resourcefiles/file_zip.cpp
gamedata/resourcefiles/file_pak.cpp
gamedata/resourcefiles/file_directory.cpp
gamedata/resourcefiles/resourcefile.cpp
gamedata/textures/animations.cpp
gamedata/textures/anim_switches.cpp
gamedata/textures/bitmap.cpp
gamedata/textures/texture.cpp
gamedata/textures/image.cpp
gamedata/textures/imagetexture.cpp
gamedata/textures/texturemanager.cpp
gamedata/textures/multipatchtexturebuilder.cpp
gamedata/textures/skyboxtexture.cpp
gamedata/textures/formats/automaptexture.cpp
gamedata/textures/formats/brightmaptexture.cpp
gamedata/textures/formats/buildtexture.cpp
gamedata/textures/formats/canvastexture.cpp
gamedata/textures/formats/ddstexture.cpp
gamedata/textures/formats/flattexture.cpp
gamedata/textures/formats/fontchars.cpp
gamedata/textures/formats/imgztexture.cpp
gamedata/textures/formats/jpegtexture.cpp
gamedata/textures/formats/md5check.cpp
gamedata/textures/formats/multipatchtexture.cpp
gamedata/textures/formats/patchtexture.cpp
gamedata/textures/formats/pcxtexture.cpp
gamedata/textures/formats/pngtexture.cpp
gamedata/textures/formats/rawpagetexture.cpp
gamedata/textures/formats/emptytexture.cpp
gamedata/textures/formats/shadertexture.cpp
gamedata/textures/formats/tgatexture.cpp
gamedata/textures/hires/hqresize.cpp
gamedata/textures/hires/hirestex.cpp
gamedata/p_xlat.cpp
gamedata/xlat/parse_xlat.cpp
gamedata/xlat/parsecontext.cpp
fragglescript/t_func.cpp
fragglescript/t_load.cpp
fragglescript/t_oper.cpp
@ -1196,7 +1178,7 @@ set (PCH_SOURCES
scripting/zscript/ast.cpp
scripting/zscript/zcc_compile.cpp
scripting/zscript/zcc_parser.cpp
sfmt/SFMT.cpp
utility/sfmt/SFMT.cpp
sound/i_music.cpp
sound/i_sound.cpp
sound/i_soundfont.cpp
@ -1261,10 +1243,35 @@ set (PCH_SOURCES
sound/wildmidi/reverb.cpp
sound/wildmidi/wildmidi_lib.cpp
sound/wildmidi/wm_error.cpp
swrenderer/textures/r_swtexture.cpp
swrenderer/textures/warptexture.cpp
swrenderer/textures/swcanvastexture.cpp
rendering/swrenderer/textures/r_swtexture.cpp
rendering/swrenderer/textures/warptexture.cpp
rendering/swrenderer/textures/swcanvastexture.cpp
events.cpp
utility/files.cpp
utility/files_decompress.cpp
utility/m_png.cpp
utility/m_random.cpp
utility/memarena.cpp
utility/md5.cpp
utility/nodebuilder/nodebuild.cpp
utility/nodebuilder/nodebuild_classify_nosse2.cpp
utility/nodebuilder/nodebuild_events.cpp
utility/nodebuilder/nodebuild_extract.cpp
utility/nodebuilder/nodebuild_gl.cpp
utility/nodebuilder/nodebuild_utility.cpp
utility/sc_man.cpp
utility/cmdlib.cpp
utility/colormatcher.cpp
utility/configfile.cpp
utility/i_module.cpp
utility/i_time.cpp
utility/m_alloc.cpp
utility/m_argv.cpp
utility/m_bbox.cpp
utility/name.cpp
utility/s_playlist.cpp
utility/v_collection.cpp
utility/zstrformat.cpp
)
if( ${HAVE_VM_JIT} )
@ -1282,33 +1289,33 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
${SYSTEM_SOURCES}
${FASTMATH_SOURCES}
${PCH_SOURCES}
x86.cpp
strnatcmp.c
zstring.cpp
math/asin.c
math/atan.c
math/const.c
math/cosh.c
math/exp.c
math/isnan.c
math/log.c
math/log10.c
math/mtherr.c
math/polevl.c
math/pow.c
math/powi.c
math/sin.c
math/sinh.c
math/sqrt.c
math/tan.c
math/tanh.c
math/fastsin.cpp
utility/x86.cpp
utility/strnatcmp.c
utility/zstring.cpp
utility/math/asin.c
utility/math/atan.c
utility/math/const.c
utility/math/cosh.c
utility/math/exp.c
utility/math/isnan.c
utility/math/log.c
utility/math/log10.c
utility/math/mtherr.c
utility/math/polevl.c
utility/math/pow.c
utility/math/powi.c
utility/math/sin.c
utility/math/sinh.c
utility/math/sqrt.c
utility/math/tan.c
utility/math/tanh.c
utility/math/fastsin.cpp
zzautozend.cpp
)
set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} )
set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" )
set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" )
set_source_files_properties( utility/sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" )
set_source_files_properties( ${NOT_COMPILED_SOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE )
@ -1329,13 +1336,16 @@ target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
include_directories( .
g_statusbar
g_shared
g_inventory
gamedata
gamedata/textures
rendering
sound
textures
sound/oplsynth
sound/timidity
sound/wildmidi
xlat
utility
utility/nodebuilder
scripting
scripting/vm
../gdtoa
@ -1444,52 +1454,54 @@ 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("Game Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/.+")
source_group("Game Data\\Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gamedata/resourcefiles/.+")
source_group("Game Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/.+")
source_group("Game Data\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/.+")
source_group("Game Data\\Textures\\Hires\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/hqnx/.+")
source_group("Game Data\\Textures\\Hires\\HQ Resize MMX version" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/hqnx_asm/.+")
source_group("Game Data\\Textures\\Hires\\XBRZ" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/xbr/.+")
source_group("Game Data\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/formats/.+")
source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+")
source_group("Map Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/maploader/.+")
source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+")
source_group("Hardware Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
source_group("Hardware Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/data/.+")
source_group("Hardware Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/dynlights/.+")
source_group("Hardware Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/models/.+")
source_group("Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/postprocessing/.+")
source_group("Hardware Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/renderer/.+")
source_group("Hardware Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/scene/.+")
source_group("Hardware Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/shaders/.+")
source_group("Hardware Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/system/.+")
source_group("Hardware Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/textures/.+")
source_group("Hardware Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/utility/.+")
source_group("OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl_load/.+")
source_group("OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
source_group("OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/data/.+")
source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/dynlights/.+")
source_group("OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/renderer/.+")
source_group("OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/scene/.+")
source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/shaders/.+")
source_group("OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/system/.+")
source_group("OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/textures/.+")
source_group("OpenGL Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/utility/.+")
source_group("Software Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/.+")
source_group("Software Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/drawers/.+")
source_group("Software Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/scene/.+")
source_group("Software Renderer\\Segments" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/segments/.+")
source_group("Software Renderer\\Line" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/line/.+")
source_group("Software Renderer\\Plane" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/plane/.+")
source_group("Software Renderer\\Things" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/things/.+")
source_group("Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/viewport/.+")
source_group("Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/.+")
source_group("Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/math/.+")
source_group("Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/drawers/.+")
source_group("Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/scene/.+")
source_group("Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/.+")
source_group("Rendering\\Hardware Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
source_group("Rendering\\Hardware Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/data/.+")
source_group("Rendering\\Hardware Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/dynlights/.+")
source_group("Rendering\\Hardware Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/models/.+")
source_group("Rendering\\Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/postprocessing/.+")
source_group("Rendering\\Hardware Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/renderer/.+")
source_group("Rendering\\Hardware Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/scene/.+")
source_group("Rendering\\Hardware Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/shaders/.+")
source_group("Rendering\\Hardware Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/system/.+")
source_group("Rendering\\Hardware Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/textures/.+")
source_group("Rendering\\Hardware Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/hwrenderer/utility/.+")
source_group("Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl_load/.+")
source_group("Rendering\\OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/.+")
source_group("Rendering\\OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/data/.+")
source_group("Rendering\\OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/dynlights/.+")
source_group("Rendering\\OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/renderer/.+")
source_group("Rendering\\OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/scene/.+")
source_group("Rendering\\OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/shaders/.+")
source_group("Rendering\\OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/system/.+")
source_group("Rendering\\OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/textures/.+")
source_group("Rendering\\OpenGL Renderer\\Utilities" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/gl/utility/.+")
source_group("Rendering\\Software Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/.+")
source_group("Rendering\\Software Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/drawers/.+")
source_group("Rendering\\Software Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/scene/.+")
source_group("Rendering\\Software Renderer\\Segments" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/segments/.+")
source_group("Rendering\\Software Renderer\\Line" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/line/.+")
source_group("Rendering\\Software Renderer\\Plane" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/plane/.+")
source_group("Rendering\\Software Renderer\\Things" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/things/.+")
source_group("Rendering\\Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/swrenderer/viewport/.+")
source_group("Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/.+")
source_group("Rendering\\Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/math/.+")
source_group("Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/drawers/.+")
source_group("Rendering\\Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/scene/.+")
source_group("Render Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+")
source_group("Render Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/.+")
source_group("Render Data\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/.+")
source_group("Render Data\\Textures\\Hires\\HQ Resize" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/hqnx/.+")
source_group("Render Data\\Textures\\Hires\\HQ Resize MMX version" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/hqnx_asm/.+")
source_group("Render Data\\Textures\\Hires\\XBRZ" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/hires/xbr/.+")
source_group("Render Data\\Textures\\Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/formats/.+")
source_group("Render Data\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/models/.+")
source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h)
source_group("Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/resourcefiles/.+")
source_group("Platforms\\POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+")
source_group("Platforms\\Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+")
source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+")
@ -1501,8 +1513,13 @@ source_group("Scripting\\ZScript frontend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_
source_group("Scripting\\Compiler backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/backend/.+")
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
source_group("Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/.+")
source_group("Utility\\Node Builder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/nodebuilder/.+")
source_group("Utility\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/math/.+")
source_group("Utility\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/rapidjson/.+")
source_group("Utility\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/sfmt/.+")
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)
source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h utility/sc_man_scanner.re)

View file

@ -54,6 +54,8 @@ struct FPortalGroupArray;
struct visstyle_t;
class FLightDefaults;
struct FSection;
struct FLevelLocals;
struct FDynamicLight;
//
// NOTES: AActor
//
@ -89,8 +91,7 @@ struct FSection;
//
// Every actor is linked into a single sector
// based on its origin coordinates.
// The subsector_t is found with R_PointInSubsector(x,y),
// and the sector_t can be found with subsector->sector.
// The subsector_t is found with PointInSector(x,y).
// The sector links are only used by the rendering code,
// the play simulation does not care about them at all.
//
@ -451,6 +452,7 @@ enum ActorRenderFlag
RF_SPRITEFLIP = 0x08000000, // sprite flipped on x-axis
RF_ZDOOMTRANS = 0x10000000, // is not normally transparent in Vanilla Doom
RF_NOINTERPOLATEVIEW = 0x40000000, // don't interpolate the view next frame if this actor is a camera.
};
// This translucency value produces the closest match to Heretic's TINTTAB.
@ -637,8 +639,8 @@ class AActor : public DThinker
DECLARE_CLASS_WITH_META (AActor, DThinker, PClassActor)
HAS_OBJECT_POINTERS
public:
AActor () throw();
AActor (const AActor &other) throw();
AActor() = default;
AActor(const AActor &other) = delete; // Calling this would be disastrous.
AActor &operator= (const AActor &other);
~AActor ();
@ -648,7 +650,7 @@ public:
virtual void PostBeginPlay() override; // Called immediately before the actor's first tick
virtual void Tick() override;
static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
static AActor *StaticSpawn (FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
inline AActor *GetDefault () const
{
@ -752,7 +754,7 @@ public:
void ClearInventory();
// Returns true if this view is considered "local" for the player.
bool CheckLocalView (int playernum) const;
bool CheckLocalView() const;
// Finds the first item of a particular type.
AActor *FindInventory (PClassActor *type, bool subclass=false);
@ -899,74 +901,12 @@ public:
return other->PosRelative(this) - Pos();
}
DVector2 Vec2Offset(double dx, double dy, bool absolute = false)
{
if (absolute)
{
return { X() + dx, Y() + dy };
}
else
{
return P_GetOffsetPosition(X(), Y(), dx, dy);
}
}
DVector3 Vec2OffsetZ(double dx, double dy, double atz, bool absolute = false)
{
if (absolute)
{
return{ X() + dx, Y() + dy, atz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, atz);
}
}
DVector2 Vec2Angle(double length, DAngle angle, bool absolute = false)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin() };
}
else
{
return P_GetOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
}
}
DVector3 Vec3Offset(double dx, double dy, double dz, bool absolute = false)
{
if (absolute)
{
return { X() + dx, Y() + dy, Z() + dz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, Z() + dz);
}
}
DVector3 Vec3Offset(const DVector3 &ofs, bool absolute = false)
{
return Vec3Offset(ofs.X, ofs.Y, ofs.Z, absolute);
}
DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin(), Z() + dz };
}
else
{
DVector2 v = P_GetOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
return DVector3(v, Z() + dz);
}
}
DVector2 Vec2Offset(double dx, double dy, bool absolute = false);
DVector3 Vec2OffsetZ(double dx, double dy, double atz, bool absolute = false);
DVector2 Vec2Angle(double length, DAngle angle, bool absolute = false);
DVector3 Vec3Offset(double dx, double dy, double dz, bool absolute = false);
DVector3 Vec3Offset(const DVector3 &ofs, bool absolute = false);
DVector3 Vec3Angle(double length, DAngle angle, double dz, bool absolute = false);
void ClearInterpolation();
@ -1240,19 +1180,16 @@ public:
// ThingIDs
static void ClearTIDHashes ();
void AddToHash ();
void RemoveFromHash ();
private:
static AActor *TIDHash[128];
static inline int TIDHASH (int key) { return key & 127; }
public:
static FSharedStringArena mStringPropertyData;
private:
friend class FActorIterator;
friend bool P_IsTIDUsed(int tid);
bool FixMapthingPos();
@ -1487,27 +1424,28 @@ public:
int ApplyDamageFactor(FName damagetype, int damage) const;
int GetModifiedDamage(FName damagetype, int damage, bool passive);
void DeleteAttachedLights();
static void DeleteAllAttachedLights();
static void RecreateAllAttachedLights();
bool isFrozen();
bool hasmodel;
};
class FActorIterator
{
friend struct FLevelLocals;
protected:
FActorIterator (AActor **hash, int i) : TIDHash(hash), base (nullptr), id (i)
{
}
FActorIterator (AActor **hash, int i, AActor *start) : TIDHash(hash), base (start), id (i)
{
}
public:
FActorIterator (int i) : base (NULL), id (i)
{
}
FActorIterator (int i, AActor *start) : base (start), id (i)
{
}
AActor *Next ()
{
if (id == 0)
return NULL;
return nullptr;
if (!base)
base = AActor::TIDHash[id & 127];
base = TIDHash[id & 127];
else
base = base->inext;
@ -1522,37 +1460,23 @@ public:
}
private:
AActor **TIDHash;
AActor *base;
int id;
};
template<class T>
class TActorIterator : public FActorIterator
{
public:
TActorIterator (int id) : FActorIterator (id) {}
T *Next ()
{
AActor *actor;
do
{
actor = FActorIterator::Next ();
} while (actor && !actor->IsKindOf (RUNTIME_CLASS(T)));
return static_cast<T *>(actor);
}
};
class NActorIterator : public FActorIterator
{
friend struct FLevelLocals;
const PClass *type;
protected:
NActorIterator (AActor **hash, const PClass *cls, int id) : FActorIterator (hash, id) { type = cls; }
NActorIterator (AActor **hash, FName cls, int id) : FActorIterator (hash, id) { type = PClass::FindClass(cls); }
public:
NActorIterator (const PClass *cls, int id) : FActorIterator (id) { type = cls; }
NActorIterator (FName cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); }
NActorIterator (const char *cls, int id) : FActorIterator (id) { type = PClass::FindClass(cls); }
AActor *Next ()
{
AActor *actor;
if (type == NULL) return NULL;
if (type == nullptr) return nullptr;
do
{
actor = FActorIterator::Next ();
@ -1561,39 +1485,36 @@ public:
}
};
bool P_IsTIDUsed(int tid);
int P_FindUniqueTID(int start_tid, int limit);
PClassActor *ClassForSpawn(FName classname);
inline AActor *Spawn(PClassActor *type)
inline AActor *Spawn(FLevelLocals *Level, PClassActor *type)
{
return AActor::StaticSpawn(type, DVector3(0, 0, 0), NO_REPLACE);
return AActor::StaticSpawn(Level, type, DVector3(0, 0, 0), NO_REPLACE);
}
inline AActor *Spawn(PClassActor *type, const DVector3 &pos, replace_t allowreplacement)
inline AActor *Spawn(FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement)
{
return AActor::StaticSpawn(type, pos, allowreplacement);
return AActor::StaticSpawn(Level, type, pos, allowreplacement);
}
inline AActor *Spawn(FName type)
inline AActor *Spawn(FLevelLocals *Level, FName type)
{
return AActor::StaticSpawn(ClassForSpawn(type), DVector3(0, 0, 0), NO_REPLACE);
return AActor::StaticSpawn(Level, ClassForSpawn(type), DVector3(0, 0, 0), NO_REPLACE);
}
inline AActor *Spawn(FName type, const DVector3 &pos, replace_t allowreplacement)
inline AActor *Spawn(FLevelLocals *Level, FName type, const DVector3 &pos, replace_t allowreplacement)
{
return AActor::StaticSpawn(ClassForSpawn(type), pos, allowreplacement);
return AActor::StaticSpawn(Level, ClassForSpawn(type), pos, allowreplacement);
}
template<class T> inline T *Spawn(const DVector3 &pos, replace_t allowreplacement)
template<class T> inline T *Spawn(FLevelLocals *Level, const DVector3 &pos, replace_t allowreplacement)
{
return static_cast<T *>(AActor::StaticSpawn(RUNTIME_CLASS(T), pos, allowreplacement));
return static_cast<T *>(AActor::StaticSpawn(Level, RUNTIME_CLASS(T), pos, allowreplacement));
}
template<class T> inline T *Spawn() // for inventory items we do not need coordinates and replacement info.
template<class T> inline T *Spawn(FLevelLocals *Level) // for inventory items we do not need coordinates and replacement info.
{
return static_cast<T *>(AActor::StaticSpawn(RUNTIME_CLASS(T), DVector3(0, 0, 0), NO_REPLACE));
return static_cast<T *>(AActor::StaticSpawn(Level, RUNTIME_CLASS(T), DVector3(0, 0, 0), NO_REPLACE));
}
inline PClassActor *PClass::FindActor(FName name)

View file

@ -8,30 +8,24 @@
inline DVector3 AActor::PosRelative(int portalgroup) const
{
return Pos() + level.Displacements.getOffset(Sector->PortalGroup, portalgroup);
return Pos() + Level->Displacements.getOffset(Sector->PortalGroup, portalgroup);
}
inline DVector3 AActor::PosRelative(const AActor *other) const
{
return Pos() + level.Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
return Pos() + Level->Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
}
inline DVector3 AActor::PosRelative(sector_t *sec) const
{
return Pos() + level.Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
return Pos() + Level->Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
}
inline DVector3 AActor::PosRelative(const line_t *line) const
{
return Pos() + level.Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
return Pos() + Level->Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
}
inline DVector3 PosRelative(const DVector3 &pos, line_t *line, sector_t *refsec = NULL)
{
return pos + level.Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup);
}
inline void AActor::ClearInterpolation()
{
Prev = Pos();
@ -61,7 +55,7 @@ inline double AActor::GetBobOffset(double ticfrac) const
{
return 0;
}
return BobSin(FloatBobPhase + level.maptime + ticfrac) * FloatBobStrength;
return BobSin(FloatBobPhase + Level->maptime + ticfrac) * FloatBobStrength;
}
inline double AActor::GetCameraHeight() const
@ -78,7 +72,7 @@ inline FDropItem *AActor::GetDropItems() const
inline double AActor::GetGravity() const
{
if (flags & MF_NOGRAVITY) return 0;
return level.gravity * Sector->gravity * Gravity * 0.00125;
return Level->gravity * Sector->gravity * Gravity * 0.00125;
}
inline double AActor::AttackOffset(double offset)
@ -92,4 +86,95 @@ inline double AActor::AttackOffset(double offset)
return 8 + offset;
}
}
}
inline DVector2 AActor::Vec2Offset(double dx, double dy, bool absolute)
{
if (absolute)
{
return { X() + dx, Y() + dy };
}
else
{
return Level->GetPortalOffsetPosition(X(), Y(), dx, dy);
}
}
inline DVector3 AActor::Vec2OffsetZ(double dx, double dy, double atz, bool absolute)
{
if (absolute)
{
return{ X() + dx, Y() + dy, atz };
}
else
{
DVector2 v = Level->GetPortalOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, atz);
}
}
inline DVector2 AActor::Vec2Angle(double length, DAngle angle, bool absolute)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin() };
}
else
{
return Level->GetPortalOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
}
}
inline DVector3 AActor::Vec3Offset(double dx, double dy, double dz, bool absolute)
{
if (absolute)
{
return { X() + dx, Y() + dy, Z() + dz };
}
else
{
DVector2 v = Level->GetPortalOffsetPosition(X(), Y(), dx, dy);
return DVector3(v, Z() + dz);
}
}
inline DVector3 AActor::Vec3Offset(const DVector3 &ofs, bool absolute)
{
return Vec3Offset(ofs.X, ofs.Y, ofs.Z, absolute);
}
inline DVector3 AActor::Vec3Angle(double length, DAngle angle, double dz, bool absolute)
{
if (absolute)
{
return{ X() + length * angle.Cos(), Y() + length * angle.Sin(), Z() + dz };
}
else
{
DVector2 v = Level->GetPortalOffsetPosition(X(), Y(), length*angle.Cos(), length*angle.Sin());
return DVector3(v, Z() + dz);
}
}
inline bool AActor::isFrozen()
{
if (!(flags5 & MF5_NOTIMEFREEZE))
{
auto state = Level->isFrozen();
if (state)
{
if (player == nullptr || player->Bot != nullptr) return true;
// This is the only place in the entire game where the two freeze flags need different treatment.
// The time freezer flag also freezes other players, the global setting does not.
if ((state & 1) && player->timefreezer == 0)
{
return true;
}
}
}
return false;
}

File diff suppressed because it is too large Load diff

View file

@ -22,31 +22,44 @@
#ifndef __AMMAP_H__
#define __AMMAP_H__
#include "dobject.h"
struct event_t;
class FSerializer;
struct FLevelLocals;
class DAutomapBase : public DObject
{
DECLARE_ABSTRACT_CLASS(DAutomapBase, DObject);
public:
FLevelLocals *Level; // temporary location so that it can be set from the outside.
// Called by main loop.
virtual bool Responder(event_t* ev, bool last) = 0;
// Called by main loop.
virtual void Ticker(void) = 0;
// Called by main loop,
// called instead of view drawer if automap active.
virtual void Drawer(int bottom) = 0;
virtual void NewResolution() = 0;
virtual void LevelInit() = 0;
virtual void UpdateShowAllLines() = 0;
virtual void GoBig() = 0;
virtual void ResetFollowLocation() = 0;
virtual int addMark() = 0;
virtual bool clearMarks() = 0;
virtual DVector2 GetPosition() = 0;
virtual void startDisplay() = 0;
};
void AM_StaticInit();
void AM_ClearColorsets(); // reset data for a restart.
// Called by main loop.
bool AM_Responder (event_t* ev, bool last);
// Called by main loop.
void AM_Ticker (void);
// Called by main loop,
// called instead of view drawer if automap active.
void AM_Drawer (int bottom);
// Called to force the automap to quit
// if the level is completed while it is up.
void AM_Stop (void);
void AM_NewResolution ();
void AM_ToggleMap ();
void AM_LevelInit ();
void AM_SerializeMarkers(FSerializer &arc);
DAutomapBase *AM_Create(FLevelLocals *Level);
void AM_Stop();
void AM_ToggleMap();
#endif

View file

@ -40,7 +40,7 @@
#include "c_cvars.h"
#include "c_dispatch.h"
#include "b_bot.h"
#include "doomstat.h"
#include "g_game.h"
#include "p_local.h"
#include "cmdlib.h"
#include "teaminfo.h"
@ -49,6 +49,7 @@
#include "d_player.h"
#include "w_wad.h"
#include "vm.h"
#include "g_levellocals.h"
IMPLEMENT_CLASS(DBot, false, true)
@ -63,8 +64,7 @@ IMPLEMENT_POINTERS_END
DEFINE_FIELD(DBot, dest)
DBot::DBot ()
: DThinker(STAT_BOT)
void DBot::Construct()
{
Clear ();
}
@ -138,20 +138,19 @@ void DBot::Tick ()
{
Super::Tick ();
if (player->mo == nullptr || bglobal.freeze)
if (player->mo == nullptr || Level->isFrozen())
{
return;
}
BotThinkCycles.Clock();
bglobal.m_Thinking = true;
Level->BotInfo.m_Thinking = true;
Think ();
bglobal.m_Thinking = false;
Level->BotInfo.m_Thinking = false;
BotThinkCycles.Unclock();
}
CVAR (Int, bot_next_color, 11, 0)
CVAR (Bool, bot_observer, false, 0)
CCMD (addbot)
{
@ -174,9 +173,9 @@ CCMD (addbot)
}
if (argv.argc() > 1)
bglobal.SpawnBot (argv[1]);
primaryLevel->BotInfo.SpawnBot (argv[1]);
else
bglobal.SpawnBot (nullptr);
primaryLevel->BotInfo.SpawnBot (nullptr);
}
void FCajunMaster::ClearPlayer (int i, bool keepTeam)
@ -233,7 +232,7 @@ CCMD (freeze)
CCMD (listbots)
{
botinfo_t *thebot = bglobal.botinfo;
botinfo_t *thebot = primaryLevel->BotInfo.botinfo;
int count = 0;
while (thebot)

View file

@ -116,12 +116,12 @@ public:
void ClearPlayer (int playernum, bool keepTeam);
//(b_game.cpp)
void Main ();
void Main (FLevelLocals *Level);
void Init ();
void End();
bool SpawnBot (const char *name, int color = NOCOLOR);
void TryAddBot (uint8_t **stream, int player);
void RemoveAllBots (bool fromlist);
void TryAddBot (FLevelLocals *Level, uint8_t **stream, int player);
void RemoveAllBots (FLevelLocals *Level, bool fromlist);
bool LoadBots ();
void ForgetBots ();
@ -129,7 +129,7 @@ public:
void StartTravel ();
void FinishTravel ();
bool IsLeader (player_t *player);
void SetBodyAt (const DVector3 &pos, int hostnum);
void SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum);
double FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
bool SafeCheckPosition (AActor *actor, double x, double y, FCheckPosition &tm);
void BotTick(AActor *mo);
@ -139,8 +139,9 @@ public:
bool IsDangerous (sector_t *sec);
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
uint8_t freeze; //Game in freeze mode.
uint8_t changefreeze; //Game wants to change freeze mode.
//uint8_t freeze; //Game in freeze mode.
//uint8_t changefreeze; //Game wants to change freeze mode.
int botnum;
botinfo_t *botinfo;
int spawn_tries;
@ -153,12 +154,11 @@ public:
private:
//(b_game.cpp)
bool DoAddBot (uint8_t *info, botskill_t skill);
bool DoAddBot (FLevelLocals *Level, uint8_t *info, botskill_t skill);
protected:
bool ctf;
int t_join;
bool observer; //Consoleplayer is observer.
};
class DBot : public DThinker
@ -166,7 +166,8 @@ class DBot : public DThinker
DECLARE_CLASS(DBot,DThinker)
HAS_OBJECT_POINTERS
public:
DBot ();
static const int DEFAULT_STAT = STAT_BOT;
void Construct ();
void Clear ();
void Serialize(FSerializer &arc);
@ -236,15 +237,9 @@ private:
//Externs
extern FCajunMaster bglobal;
extern cycle_t BotThinkCycles, BotSupportCycles;
EXTERN_CVAR (Float, bot_flag_return_time)
EXTERN_CVAR (Int, bot_next_color)
EXTERN_CVAR (Bool, bot_allow_duds)
EXTERN_CVAR (Int, bot_maxcorpses)
EXTERN_CVAR (Bool, bot_observer)
EXTERN_CVAR (Bool, bot_watersplash)
EXTERN_CVAR (Bool, bot_chat)
#endif // __B_BOT_H__

View file

@ -73,7 +73,7 @@ bool DBot::Reachable (AActor *rtarget)
double estimated_dist = player->mo->Distance2D(rtarget);
bool reachable = true;
FPathTraverse it(player->mo->X()+player->mo->Vel.X, player->mo->Y()+player->mo->Vel.Y, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS);
FPathTraverse it(Level, player->mo->X()+player->mo->Vel.X, player->mo->Y()+player->mo->Vel.Y, rtarget->X(), rtarget->Y(), PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in;
while ((in = it.Next()))
{
@ -105,7 +105,7 @@ bool DBot::Reachable (AActor *rtarget)
double ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
double floorheight = s->floorplane.ZatPoint (hitx, hity);
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
if (!Level->BotInfo.IsDangerous (s) && //Any nukage/lava?
(floorheight <= (last_z+MAXMOVEHEIGHT)
&& ((ceilingheight == floorheight && line->special)
|| (ceilingheight - floorheight) >= player->mo->Height))) //Does it fit?
@ -235,8 +235,8 @@ void DBot::Dofire (ticcmd_t *cmd)
// prediction aiming
Dist = player->mo->Distance2D(enemy);
fm = Dist / GetDefaultByType (GetBotInfo(player->ReadyWeapon).projectileType)->Speed;
bglobal.SetBodyAt(enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);
Angle = player->mo->AngleTo(bglobal.body1);
Level->BotInfo.SetBodyAt(Level, enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);
Angle = player->mo->AngleTo(Level->BotInfo.body1);
if (Check_LOS (enemy, SHOOTFOV))
no_fire = false;
}
@ -300,7 +300,7 @@ extern int BotWTG;
void FCajunMaster::BotTick(AActor *mo)
{
BotSupportCycles.Clock();
bglobal.m_Thinking = true;
m_Thinking = true;
for (int i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].Bot == NULL)
@ -333,7 +333,7 @@ void FCajunMaster::BotTick(AActor *mo)
}
}
}
bglobal.m_Thinking = false;
m_Thinking = false;
BotSupportCycles.Unclock();
}
@ -345,7 +345,6 @@ AActor *DBot::Choose_Mate ()
int count;
double closest_dist, test;
AActor *target;
AActor *observer;
//is mate alive?
if (mate)
@ -365,10 +364,6 @@ AActor *DBot::Choose_Mate ()
target = NULL;
closest_dist = FLT_MAX;
if (bot_observer)
observer = players[consoleplayer].mo;
else
observer = NULL;
//Check for player friends
for (count = 0; count < MAXPLAYERS; count++)
@ -380,9 +375,8 @@ AActor *DBot::Choose_Mate ()
&& player->mo != client->mo
&& (player->mo->IsTeammate (client->mo) || !deathmatch)
&& client->mo->health > 0
&& client->mo != observer
&& ((player->mo->health/2) <= client->mo->health || !deathmatch)
&& !bglobal.IsLeader(client)) //taken?
&& !Level->BotInfo.IsLeader(client)) //taken?
{
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
{
@ -401,7 +395,7 @@ AActor *DBot::Choose_Mate ()
//Make a introducing to mate.
if(target && target!=last_mate)
{
if((P_Random()%(200*bglobal.botnum))<3)
if((P_Random()%(200*Level->BotInfo.botnum))<3)
{
chat = c_teamup;
if(target->bot)
@ -423,7 +417,6 @@ AActor *DBot::Find_enemy ()
double closest_dist, temp; //To target.
AActor *target;
DAngle vangle;
AActor *observer;
if (!deathmatch)
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
@ -439,17 +432,12 @@ AActor *DBot::Find_enemy ()
target = NULL;
closest_dist = FLT_MAX;
if (bot_observer)
observer = players[consoleplayer].mo;
else
observer = NULL;
for (count = 0; count < MAXPLAYERS; count++)
{
player_t *client = &players[count];
if (playeringame[count]
&& !player->mo->IsTeammate (client->mo)
&& client->mo != observer
&& client->mo->health > 0
&& player->mo != client->mo)
{
@ -479,7 +467,7 @@ AActor *DBot::Find_enemy ()
//Creates a temporary mobj (invisible) at the given location.
void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
void FCajunMaster::SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum)
{
if (hostnum == 1)
{
@ -489,7 +477,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
}
else
{
body1 = Spawn ("CajunBodyNode", pos, NO_REPLACE);
body1 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
}
}
else if (hostnum == 2)
@ -500,7 +488,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
}
else
{
body2 = Spawn ("CajunBodyNode", pos, NO_REPLACE);
body2 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
}
}
}
@ -517,7 +505,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
//Emulates missile travel. Returns distance travelled.
double FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
{
AActor *th = Spawn ("CajunTrace", source->PosPlusZ(4*8.), NO_REPLACE);
AActor *th = Spawn (source->Level, "CajunTrace", source->PosPlusZ(4*8.), NO_REPLACE);
th->target = source; // where it came from
@ -543,9 +531,9 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
AActor *actor;
double m;
bglobal.SetBodyAt(player->mo->PosPlusZ(player->mo->Height / 2) + player->mo->Vel.XY() * 5, 2);
Level->BotInfo.SetBodyAt(Level, player->mo->PosPlusZ(player->mo->Height / 2) + player->mo->Vel.XY() * 5, 2);
actor = bglobal.body2;
actor = Level->BotInfo.body2;
dist = actor->Distance2D (enemy);
if (dist < SAFE_SELF_MISDIST)
@ -553,24 +541,24 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
//Predict.
m = ((dist+1) / GetDefaultByName("Rocket")->Speed);
bglobal.SetBodyAt(DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1);
Level->BotInfo.SetBodyAt(Level, DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1);
//try the predicted location
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
if (P_CheckSight (actor, Level->BotInfo.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
{
FCheckPosition tm;
if (bglobal.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm))
if (Level->BotInfo.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm))
{
if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
if (Level->BotInfo.FakeFire (actor, Level->BotInfo.body1, cmd) >= SAFE_SELF_MISDIST)
{
return actor->AngleTo(bglobal.body1);
return actor->AngleTo(Level->BotInfo.body1);
}
}
}
//Try fire straight.
if (P_CheckSight (actor, enemy, 0))
{
if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
if (Level->BotInfo.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
{
return player->mo->AngleTo(enemy);
}

View file

@ -96,9 +96,6 @@ Everything that is changed is marked (maybe commented) with "Added by MC"
static FRandom pr_botspawn ("BotSpawn");
//Externs
FCajunMaster bglobal;
cycle_t BotThinkCycles, BotSupportCycles;
int BotWTG;
@ -129,7 +126,7 @@ FCajunMaster::~FCajunMaster()
}
//This function is called every tick (from g_game.c).
void FCajunMaster::Main ()
void FCajunMaster::Main(FLevelLocals *Level)
{
BotThinkCycles.Reset();
@ -137,7 +134,7 @@ void FCajunMaster::Main ()
return;
//Add new bots?
if (wanted_botnum > botnum && !freeze)
if (wanted_botnum > botnum && !Level->isFrozen())
{
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
{
@ -151,24 +148,6 @@ void FCajunMaster::Main ()
//Check if player should go observer. Or un observe
FLinkContext ctx;
if (bot_observer && !observer && !netgame)
{
Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
observer = true;
players[consoleplayer].mo->UnlinkFromWorld (&ctx);
players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
players[consoleplayer].mo->flags2 |= MF2_FLY;
players[consoleplayer].mo->LinkToWorld (&ctx);
}
else if (!bot_observer && observer && !netgame) //Go back
{
Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
observer = false;
players[consoleplayer].mo->UnlinkFromWorld (&ctx);
players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
players[consoleplayer].mo->flags2 &= ~MF2_FLY;
players[consoleplayer].mo->LinkToWorld (&ctx);
}
}
void FCajunMaster::Init ()
@ -176,8 +155,6 @@ void FCajunMaster::Init ()
botnum = 0;
firstthing = nullptr;
spawn_tries = 0;
freeze = false;
observer = false;
body1 = nullptr;
body2 = nullptr;
@ -340,7 +317,7 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
return true;
}
void FCajunMaster::TryAddBot (uint8_t **stream, int player)
void FCajunMaster::TryAddBot (FLevelLocals *Level, uint8_t **stream, int player)
{
int botshift = ReadByte (stream);
char *info = ReadString (stream);
@ -363,7 +340,7 @@ void FCajunMaster::TryAddBot (uint8_t **stream, int player)
}
}
if (DoAddBot ((uint8_t *)info, skill))
if (DoAddBot (Level,(uint8_t *)info, skill))
{
//Increment this.
botnum++;
@ -384,7 +361,7 @@ void FCajunMaster::TryAddBot (uint8_t **stream, int player)
delete[] info;
}
bool FCajunMaster::DoAddBot (uint8_t *info, botskill_t skill)
bool FCajunMaster::DoAddBot (FLevelLocals *Level, uint8_t *info, botskill_t skill)
{
int bnum;
@ -405,7 +382,7 @@ bool FCajunMaster::DoAddBot (uint8_t *info, botskill_t skill)
D_ReadUserInfoStrings (bnum, &info, false);
multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
players[bnum].Bot = Create<DBot>();
players[bnum].Bot = Level->CreateThinker<DBot>();
players[bnum].Bot->player = &players[bnum];
players[bnum].Bot->skill = skill;
playeringame[bnum] = true;
@ -417,38 +394,37 @@ bool FCajunMaster::DoAddBot (uint8_t *info, botskill_t skill)
else
Printf ("%s joined the game\n", players[bnum].userinfo.GetName());
G_DoReborn (bnum, true);
Level->DoReborn (bnum, true);
return true;
}
void FCajunMaster::RemoveAllBots (bool fromlist)
void FCajunMaster::RemoveAllBots (FLevelLocals *Level, bool fromlist)
{
int i, j;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (players[i].Bot != NULL)
if (Level->Players[i]->Bot != nullptr)
{
// If a player is looking through this bot's eyes, make him
// look through his own eyes instead.
for (j = 0; j < MAXPLAYERS; ++j)
{
if (i != j && playeringame[j] && players[j].Bot == NULL)
if (i != j && Level->PlayerInGame(j) && Level->Players[j]->Bot == nullptr)
{
if (players[j].camera == players[i].mo)
if (Level->Players[j]->camera == Level->Players[i]->mo)
{
players[j].camera = players[j].mo;
if (j == consoleplayer)
Level->Players[j]->camera = Level->Players[j]->mo;
if (Level->isConsolePlayer(Level->Players[j]->mo))
{
StatusBar->AttachToPlayer (players + j);
StatusBar->AttachToPlayer (Level->Players[j]);
}
}
}
}
// [ZZ] run event hook
E_PlayerDisconnected(i);
//
level.Behaviors.StartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true);
Level->localEventManager->PlayerDisconnected(i);
Level->Behaviors.StartTypedScripts (SCRIPT_Disconnect, Level->Players[i]->mo, true, i, true);
ClearPlayer (i, !fromlist);
}
}
@ -521,7 +497,7 @@ bool FCajunMaster::LoadBots ()
bool gotteam = false;
int loaded_bots = 0;
bglobal.ForgetBots ();
ForgetBots ();
tmp = M_GetCajunPath(BOTFILENAME);
if (tmp.IsEmpty())
{
@ -637,9 +613,9 @@ bool FCajunMaster::LoadBots ()
appendinfo (newinfo->info, "team");
appendinfo (newinfo->info, "255");
}
newinfo->next = bglobal.botinfo;
newinfo->next = botinfo;
newinfo->lastteam = TEAM_NONE;
bglobal.botinfo = newinfo;
botinfo = newinfo;
loaded_bots++;
}
Printf ("%d bots read from %s\n", loaded_bots, BOTFILENAME);
@ -654,11 +630,3 @@ ADD_STAT (bots)
BotWTG);
return out;
}
DEFINE_ACTION_FUNCTION(FLevelLocals, RemoveAllBots)
{
PARAM_PROLOGUE;
PARAM_BOOL(fromlist);
bglobal.RemoveAllBots(fromlist);
return 0;
}

View file

@ -104,7 +104,7 @@ bool DBot::Move (ticcmd_t *cmd)
tryx = player->mo->X() + 8*xspeed[player->mo->movedir];
tryy = player->mo->Y() + 8*yspeed[player->mo->movedir];
try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd);
try_ok = Level->BotInfo.CleanAhead (player->mo, tryx, tryy, cmd);
if (!try_ok) //Anything blocking that could be opened etc..
{

View file

@ -289,7 +289,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
r = pr_botmove();
if (r < 128)
{
TThinkerIterator<AActor> it (NAME_Inventory, MAX_STATNUM+1, bglobal.firstthing);
auto it = player->mo->Level->GetThinkerIterator<AActor>(NAME_Inventory, MAX_STATNUM+1, Level->BotInfo.firstthing);
auto item = it.Next();
if (item != NULL || (item = it.Next()) != NULL)
@ -304,7 +304,7 @@ void DBot::ThinkForMove (ticcmd_t *cmd)
{
item = it.Next();
}
bglobal.firstthing = item;
Level->BotInfo.firstthing = item;
dest = item;
}
}
@ -356,9 +356,6 @@ void DBot::WhatToGet (AActor *item)
}
int weapgiveammo = (alwaysapplydmflags || deathmatch) && !(dmflags & DF_WEAPONS_STAY);
//if(pos && !bglobal.thingvis[pos->id][item->id]) continue;
// if (item->IsKindOf (RUNTIME_CLASS(AArtifact)))
// return; // don't know how to use artifacts
if (item->IsKindOf(NAME_Weapon))
{
// FIXME

View file

@ -182,9 +182,9 @@ static FRandom pr_bbannounce ("BBAnnounce");
void DoVoiceAnnounce (const char *sound)
{
// Don't play announcements too close together
if (LastAnnounceTime == 0 || LastAnnounceTime <= level.time-5)
if (LastAnnounceTime == 0 || LastAnnounceTime <= primaryLevel->time-5)
{
LastAnnounceTime = level.time;
LastAnnounceTime = primaryLevel->time;
S_Sound (CHAN_VOICE, sound, 1, ATTN_NONE);
}
}
@ -224,7 +224,7 @@ bool AnnounceKill (AActor *killer, AActor *killee)
if (cl_bbannounce && deathmatch)
{
bool playSound = killee->CheckLocalView (consoleplayer);
bool playSound = killee->CheckLocalView();
if (killer == NULL)
{ // The world killed the player
@ -258,7 +258,7 @@ bool AnnounceKill (AActor *killer, AActor *killee)
// Blood only plays the announcement sound on the killer's
// computer. I think it sounds neater to also hear it on
// the killee's machine.
playSound |= killer->CheckLocalView (consoleplayer);
playSound |= killer->CheckLocalView();
}
message = GStrings(choice->Message);
@ -302,8 +302,8 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee)
killee->player->userinfo.GetName(), killer->player->userinfo.GetName());
Printf (PRINT_MEDIUM, "%s\n", assembled);
}
if (killee->CheckLocalView (consoleplayer) ||
killer->CheckLocalView (consoleplayer))
if (killee->CheckLocalView() ||
killer->CheckLocalView())
{
DoVoiceAnnounce (TelefragSounds[rannum % 7]);
}
@ -337,7 +337,7 @@ bool AnnounceSpreeLoss (AActor *who)
{
if (cl_bbannounce)
{
if (who->CheckLocalView (consoleplayer))
if (who->CheckLocalView())
{
DoVoiceAnnounce (TooBadSounds[M_Random() % 3]);
}
@ -357,7 +357,7 @@ bool AnnounceMultikill (AActor *who)
{
if (cl_bbannounce)
{
if (who->CheckLocalView (consoleplayer))
if (who->CheckLocalView())
{
DoVoiceAnnounce (GoodJobSounds[M_Random() % 3]);
}

View file

@ -753,7 +753,6 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
dclickmask = 1 << (ev->data1 & 7);
dclick = false;
// This used level.time which didn't work outside a level.
nowtime = (unsigned)I_msTime();
if (doublebinds != NULL && int(DClickTime[ev->data1] - nowtime) > 0 && ev->type == EV_KeyDown)
{

View file

@ -47,7 +47,6 @@
#include "c_dispatch.h"
#include "i_system.h"
#include "doomerrors.h"
#include "doomstat.h"
#include "gstrings.h"
@ -68,6 +67,7 @@
#include "r_utility.h"
#include "c_functions.h"
#include "g_levellocals.h"
#include "v_video.h"
extern FILE *Logfile;
extern bool insave;
@ -366,7 +366,7 @@ CCMD (changemap)
if (argv.argc() > 1)
{
const char *mapname = argv[1];
if (!strcmp(mapname, "*")) mapname = level.MapName.GetChars();
if (!strcmp(mapname, "*")) mapname = primaryLevel->MapName.GetChars();
try
{
@ -945,7 +945,8 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha
}
}
}
TThinkerIterator<AActor> it;
// This only works on the primary level.
auto it = primaryLevel->GetThinkerIterator<AActor>();
while ( (mo = it.Next()) )
{
@ -1055,20 +1056,21 @@ CCMD(changesky)
if (netgame || argv.argc()<2) return;
// This only alters the primary level's sky setting. For testing out a sky that is sufficient.
sky1name = argv[1];
if (sky1name[0] != 0)
{
FTextureID newsky = TexMan.GetTextureID(sky1name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst);
if (newsky.Exists())
{
sky1texture = level.skytexture1 = newsky;
primaryLevel->skytexture1 = newsky;
}
else
{
Printf("changesky: Texture '%s' not found\n", sky1name);
}
}
R_InitSkyMap ();
InitSkyMap (primaryLevel);
}
//-----------------------------------------------------------------------------
@ -1099,9 +1101,9 @@ CCMD(nextmap)
return;
}
if (level.NextMap.Len() > 0 && level.NextMap.Compare("enDSeQ", 6))
if (primaryLevel->NextMap.Len() > 0 && primaryLevel->NextMap.Compare("enDSeQ", 6))
{
G_DeferedInitNew(level.NextMap);
G_DeferedInitNew(primaryLevel->NextMap);
}
else
{
@ -1123,9 +1125,9 @@ CCMD(nextsecret)
return;
}
if (level.NextSecretMap.Len() > 0 && level.NextSecretMap.Compare("enDSeQ", 6))
if (primaryLevel->NextSecretMap.Len() > 0 && primaryLevel->NextSecretMap.Compare("enDSeQ", 6))
{
G_DeferedInitNew(level.NextSecretMap);
G_DeferedInitNew(primaryLevel->NextSecretMap);
}
else
{
@ -1170,10 +1172,10 @@ static void PrintSecretString(const char *string, bool thislevel)
{
auto secnum = (unsigned)strtoull(string+2, (char**)&string, 10);
if (*string == ';') string++;
if (thislevel && secnum < level.sectors.Size())
if (thislevel && secnum < primaryLevel->sectors.Size())
{
if (level.sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
else if (level.sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
if (primaryLevel->sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
else if (primaryLevel->sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
else colstr = TEXTCOLOR_ORANGE;
}
}
@ -1181,7 +1183,7 @@ static void PrintSecretString(const char *string, bool thislevel)
{
long tid = (long)strtoll(string+2, (char**)&string, 10);
if (*string == ';') string++;
FActorIterator it(tid);
auto it = primaryLevel->GetActorIterator(tid);
AActor *actor;
bool foundone = false;
if (thislevel)
@ -1214,8 +1216,8 @@ static void PrintSecretString(const char *string, bool thislevel)
CCMD(secret)
{
const char *mapname = argv.argc() < 2? level.MapName.GetChars() : argv[1];
bool thislevel = !stricmp(mapname, level.MapName);
const char *mapname = argv.argc() < 2? primaryLevel->MapName.GetChars() : argv[1];
bool thislevel = !stricmp(mapname, primaryLevel->MapName);
bool foundsome = false;
int lumpno=Wads.CheckNumForName("SECRETS");

View file

@ -34,7 +34,7 @@
#include "templates.h"
#include "p_setup.h"
#include "i_system.h"
#include "version.h"
#include "g_game.h"
#include "c_bind.h"
@ -1243,7 +1243,7 @@ void C_FullConsole ()
if (gamestate != GS_STARTUP)
{
gamestate = GS_FULLCONSOLE;
level.Music = "";
primaryLevel->Music = "";
S_Start ();
P_FreeLevelData ();
V_SetBlend (0,0,0,0);

View file

@ -51,7 +51,6 @@ constate_e;
extern int PrintColors[PRINTLEVELS + 2];
extern constate_e ConsoleState;
extern int ConBottom;
// Initialize the console
void C_InitConsole (int width, int height, bool ingame);
@ -65,6 +64,7 @@ void C_Ticker (void);
void AddToConsole (int printlevel, const char *string);
int PrintString (int printlevel, const char *string);
int PrintStringHigh (const char *string);
int VPrintf (int printlevel, const char *format, va_list parms) GCCFORMAT(2);
void C_DrawConsole ();

View file

@ -40,9 +40,9 @@
#include "c_console.h"
#include "c_dispatch.h"
#include "doomstat.h"
#include "g_game.h"
#include "d_player.h"
#include "v_video.h"
#include "d_netinf.h"
#include "menu/menu.h"

View file

@ -45,7 +45,7 @@
#include "c_console.h"
#include "c_dispatch.h"
#include "m_argv.h"
#include "doomstat.h"
#include "g_game.h"
#include "d_player.h"
#include "configfile.h"
#include "v_text.h"
@ -54,6 +54,7 @@
#include "serializer.h"
#include "menu/menu.h"
#include "vm.h"
#include "g_levellocals.h"
// MACROS ------------------------------------------------------------------

View file

@ -27,7 +27,7 @@
#include "m_swap.h"
#include "hu_stuff.h"
#include "s_sound.h"
#include "doomstat.h"
#include "g_game.h"
#include "st_stuff.h"
#include "c_console.h"
#include "c_dispatch.h"
@ -38,6 +38,7 @@
#include "d_net.h"
#include "d_event.h"
#include "sbar.h"
#include "v_video.h"
#define QUEUESIZE 128
#define MESSAGESIZE 128

View file

@ -25,6 +25,7 @@
#include "basictypes.h"
#include <functional>
//
@ -58,7 +59,7 @@ struct event_t
enum gameaction_t : int
{
ga_nothing,
ga_loadlevel,
ga_loadlevel, // not used.
ga_newgame,
ga_newgame2,
ga_recordgame,
@ -119,6 +120,7 @@ typedef enum
// Called by IO functions when input is detected.
void D_PostEvent (const event_t* ev);
void D_RemoveNextCharEvent();
void D_Render(std::function<void()> action, bool interpolate);
//
@ -127,8 +129,6 @@ void D_RemoveNextCharEvent();
#define MAXEVENTS 128
extern event_t events[MAXEVENTS];
extern int eventhead;
extern int eventtail;
extern gameaction_t gameaction;

View file

@ -99,6 +99,8 @@
#include "events.h"
#include "vm.h"
#include "types.h"
#include "i_system.h"
#include "g_cvars.h"
#include "r_data/r_vanillatrans.h"
EXTERN_CVAR(Bool, hud_althud)
@ -170,7 +172,7 @@ CUSTOM_CVAR (Int, fraglimit, 0, CVAR_SERVERINFO)
if (playeringame[i] && self <= D_GetFragCount(&players[i]))
{
Printf ("%s\n", GStrings("TXT_FRAGLIMIT"));
G_ExitLevel (0, false);
primaryLevel->ExitLevel (0, false);
break;
}
}
@ -271,7 +273,7 @@ void D_ProcessEvents (void)
if (M_Responder (ev))
continue; // menu ate the event
// check events
if (ev->type != EV_Mouse && E_Responder(ev)) // [ZZ] ZScript ate the event // update 07.03.17: mouse events are handled directly
if (ev->type != EV_Mouse && primaryLevel->localEventManager->Responder(ev)) // [ZZ] ZScript ate the event // update 07.03.17: mouse events are handled directly
continue;
G_Responder (ev);
}
@ -293,7 +295,7 @@ void D_PostEvent (const event_t *ev)
return;
}
events[eventhead] = *ev;
if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !E_Responder(ev) && !paused)
if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !primaryLevel->localEventManager->Responder(ev) && !paused)
{
if (Button_Mlook.bDown || freelook)
{
@ -351,6 +353,35 @@ void D_RemoveNextCharEvent()
}
}
//==========================================================================
//
// Render wrapper.
// This function contains all the needed setup and cleanup for starting a render job.
//
//==========================================================================
void D_Render(std::function<void()> action, bool interpolate)
{
for (auto Level : AllLevels())
{
// Check for the presence of dynamic lights at the start of the frame once.
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4))
{
Level->HasDynamicLights = !!Level->lights;
}
else Level->HasDynamicLights = false; // lights are off so effectively we have none.
if (interpolate) Level->interpolator.DoInterpolations(I_GetTimeFrac());
P_FindParticleSubsectors(Level);
PO_LinkToSubsectors(Level);
}
action();
if (interpolate) for (auto Level : AllLevels())
{
Level->interpolator.RestoreInterpolations();
}
}
//==========================================================================
//
// CVAR dmflags
@ -361,8 +392,7 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO)
{
// In case DF_NO_FREELOOK was changed, reinitialize the sky
// map. (If no freelook, then no need to stretch the sky.)
if (sky1texture.isValid())
R_InitSkyMap ();
R_InitSkyMap ();
if (self & DF_NO_FREELOOK)
{
@ -502,36 +532,40 @@ CVAR (Flag, sv_respawnsuper, dmflags2, DF2_RESPAWN_SUPER);
//
//==========================================================================
int i_compatflags, i_compatflags2; // internal compatflags composed from the compatflags CVAR and MAPINFO settings
int ii_compatflags, ii_compatflags2, ib_compatflags;
EXTERN_CVAR(Int, compatmode)
static int GetCompatibility(int mask)
static int GetCompatibility(FLevelLocals *Level, int mask)
{
if (level.info == NULL) return mask;
else return (mask & ~level.info->compatmask) | (level.info->compatflags & level.info->compatmask);
if (Level->info == nullptr) return mask;
else return (mask & ~Level->info->compatmask) | (Level->info->compatflags & Level->info->compatmask);
}
static int GetCompatibility2(int mask)
static int GetCompatibility2(FLevelLocals *Level, int mask)
{
return (level.info == NULL) ? mask
: (mask & ~level.info->compatmask2) | (level.info->compatflags2 & level.info->compatmask2);
return (Level->info == nullptr) ? mask
: (mask & ~Level->info->compatmask2) | (Level->info->compatflags2 & Level->info->compatmask2);
}
CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
int old = i_compatflags;
i_compatflags = GetCompatibility(self) | ii_compatflags;
if ((old ^ i_compatflags) & COMPATF_POLYOBJ)
for (auto Level : AllLevels())
{
FPolyObj::ClearAllSubsectorLinks();
int old = Level->i_compatflags;
Level->i_compatflags = GetCompatibility(Level, self) | Level->ii_compatflags;
if ((old ^ Level->i_compatflags) & COMPATF_POLYOBJ)
{
Level->ClearAllSubsectorLinks();
}
}
}
CUSTOM_CVAR (Int, compatflags2, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
i_compatflags2 = GetCompatibility2(self) | ii_compatflags2;
for (auto Level : AllLevels())
{
Level->i_compatflags2 = GetCompatibility2(Level, self) | Level->ii_compatflags2;
Level->SetCompatLineOnSide(true);
}
}
CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
@ -746,19 +780,16 @@ void D_Display ()
//E_RenderFrame();
//
// Check for the presence of dynamic lights at the start of the frame once.
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4))
D_Render([&]()
{
level.HasDynamicLights = !!level.lights;
}
else level.HasDynamicLights = false; // lights are off so effectively we have none.
viewsec = screen->RenderView(&players[consoleplayer]);
viewsec = screen->RenderView(&players[consoleplayer]);
}, true);
screen->Begin2D();
screen->DrawBlend(viewsec);
if (automapactive)
{
AM_Drawer (hud_althud? viewheight : StatusBar->GetTopOfStatusbar());
primaryLevel->automap->Drawer (hud_althud? viewheight : StatusBar->GetTopOfStatusbar());
}
// for timing the statusbar code.
@ -928,7 +959,7 @@ void D_Display ()
void D_ErrorCleanup ()
{
savegamerestore = false;
bglobal.RemoveAllBots (true);
primaryLevel->BotInfo.RemoveAllBots (primaryLevel, true);
D_QuitNetGame ();
if (demorecording || demoplayback)
G_CheckDemoStatus ();
@ -2524,14 +2555,14 @@ void D_DoomMain (void)
PClassActor::StaticSetActorNums();
//Added by MC:
bglobal.getspawned.Clear();
primaryLevel->BotInfo.getspawned.Clear();
argcount = Args->CheckParmList("-bots", &args);
for (p = 0; p < argcount; ++p)
{
bglobal.getspawned.Push(args[p]);
primaryLevel->BotInfo.getspawned.Push(args[p]);
}
bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size();
primaryLevel->BotInfo.spawn_tries = 0;
primaryLevel->BotInfo.wanted_botnum = primaryLevel->BotInfo.getspawned.Size();
if (!batchrun) Printf ("P_Init: Init Playloop state.\n");
StartScreen->LoadingStatus ("Init game engine", 0x3f);
@ -2695,8 +2726,11 @@ void D_DoomMain (void)
// clean up game state
ST_Clear();
D_ErrorCleanup ();
DThinker::DestroyThinkersInList(STAT_STATIC);
E_Shutdown(false);
for (auto Level : AllLevels())
{
Level->Thinkers.DestroyThinkersInList(STAT_STATIC);
}
staticEventManager.Shutdown();
P_FreeLevelData();
M_SaveDefaults(NULL); // save config before the restart

View file

@ -61,8 +61,10 @@
#include "a_keys.h"
#include "intermission/intermission.h"
#include "g_levellocals.h"
#include "actorinlines.h"
#include "events.h"
#include "i_time.h"
#include "i_system.h"
#include "vm.h"
EXTERN_CVAR (Int, disableautosave)
@ -2079,17 +2081,12 @@ uint8_t *FDynamicBuffer::GetData (int *len)
}
static int KillAll(PClassActor *cls)
{
return P_Massacre(false, cls);
}
static int RemoveClass(const PClass *cls)
static int RemoveClass(FLevelLocals *Level, const PClass *cls)
{
AActor *actor;
int removecount = 0;
bool player = false;
TThinkerIterator<AActor> iterator(cls);
auto iterator = Level->GetThinkerIterator<AActor>(cls->TypeName);
while ((actor = iterator.Next()))
{
if (actor->IsA(cls))
@ -2225,8 +2222,8 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
s = ReadString (stream);
// Using LEVEL_NOINTERMISSION tends to throw the game out of sync.
// That was a long time ago. Maybe it works now?
level.flags |= LEVEL_CHANGEMAPCHEAT;
G_ChangeLevel(s, pos, 0);
primaryLevel->flags |= LEVEL_CHANGEMAPCHEAT;
primaryLevel->ChangeLevel(s, pos, 0);
break;
case DEM_SUICIDE:
@ -2234,11 +2231,11 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
break;
case DEM_ADDBOT:
bglobal.TryAddBot (stream, player);
primaryLevel->BotInfo.TryAddBot (primaryLevel, stream, player);
break;
case DEM_KILLBOTS:
bglobal.RemoveAllBots (true);
primaryLevel->BotInfo.RemoveAllBots (primaryLevel, true);
Printf ("Removed all bots\n");
break;
@ -2333,14 +2330,14 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
const AActor *def = GetDefaultByType (typeinfo);
DVector3 spawnpos = source->Vec3Angle(def->radius * 2 + source->radius, source->Angles.Yaw, 8.);
AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE);
AActor *spawned = Spawn (primaryLevel, typeinfo, spawnpos, ALLOW_REPLACE);
if (spawned != NULL)
{
if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF)
{
if (spawned->CountsAsKill())
{
level.total_monsters--;
primaryLevel->total_monsters--;
}
spawned->FriendPlayer = player + 1;
spawned->flags |= MF_FRIENDLY;
@ -2510,7 +2507,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
}
if (!CheckCheatmode(player == consoleplayer))
{
P_ExecuteSpecial(snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
P_ExecuteSpecial(primaryLevel, snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
}
}
break;
@ -2563,11 +2560,11 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
if (cls != NULL)
{
killcount = KillAll(cls);
PClassActor *cls_rep = cls->GetReplacement();
killcount = primaryLevel->Massacre(false, cls->TypeName);
PClassActor *cls_rep = cls->GetReplacement(primaryLevel);
if (cls != cls_rep)
{
killcount += KillAll(cls_rep);
killcount += primaryLevel->Massacre(false, cls_rep->TypeName);
}
Printf ("Killed %d monsters of type %s.\n",killcount, s);
}
@ -2585,11 +2582,11 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
PClassActor *cls = PClass::FindActor(s);
if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AActor)))
{
removecount = RemoveClass(cls);
const PClass *cls_rep = cls->GetReplacement();
removecount = RemoveClass(primaryLevel, cls);
const PClass *cls_rep = cls->GetReplacement(primaryLevel);
if (cls != cls_rep)
{
removecount += RemoveClass(cls_rep);
removecount += RemoveClass(primaryLevel, cls_rep);
}
Printf("Removed %d actors of type %s.\n", removecount, s);
}
@ -2663,7 +2660,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
case DEM_FINISHGAME:
// Simulate an end-of-game action
G_ChangeLevel(NULL, 0, 0);
primaryLevel->ChangeLevel(NULL, 0, 0);
break;
case DEM_NETEVENT:
@ -2674,7 +2671,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
for (int i = 0; i < 3; i++)
arg[i] = ReadLong(stream);
bool manual = !!ReadByte(stream);
E_Console(player, s, arg[0], arg[1], arg[2], manual);
primaryLevel->localEventManager->Console(player, s, arg[0], arg[1], arg[2], manual);
}
break;
@ -2701,7 +2698,7 @@ static void RunScript(uint8_t **stream, AActor *pawn, int snum, int argn, int al
arg[i] = argval;
}
}
P_StartScript(pawn, NULL, snum, level.MapName, arg, MIN<int>(countof(arg), argn), ACS_NET | always);
P_StartScript(pawn->Level, pawn, NULL, snum, primaryLevel->MapName, arg, MIN<int>(countof(arg), argn), ACS_NET | always);
}
void Net_SkipCommand (int type, uint8_t **stream)

View file

@ -32,7 +32,7 @@
**
*/
#include "i_system.h"
#include "d_protocol.h"
#include "d_net.h"
#include "doomstat.h"

View file

@ -488,6 +488,8 @@ void DObject::StaticPointerSubstitution (AActor *old, AActor *notOld)
DObject *probe;
size_t changed = 0;
int i;
if (old == nullptr) return;
// Go through all objects.
i = 0;DObject *last=0;
@ -515,8 +517,8 @@ void DObject::StaticPointerSubstitution (AActor *old, AActor *notOld)
}
}
// Go through sectors.
for (auto &sec : level.sectors)
// Go through sectors. Only the level this actor belongs to is relevant.
for (auto &sec : old->Level->sectors)
{
if (sec.SoundTarget == old) sec.SoundTarget = notOld;
}

View file

@ -37,7 +37,7 @@
#include <stdlib.h>
#include <type_traits>
#include "doomtype.h"
#include "i_system.h"
#include "vectors.h"
class PClass;

View file

@ -96,9 +96,6 @@
#define DEFAULT_GCMUL 400 // GC runs 'quadruple the speed' of memory allocation
// Number of sectors to mark for each step.
#define SECTORSTEPSIZE 32
#define POLYSTEPSIZE 120
#define SIDEDEFSTEPSIZE 240
#define GCSTEPSIZE 1024u
#define GCSWEEPMAX 40
@ -107,22 +104,6 @@
// TYPES -------------------------------------------------------------------
// This object is responsible for marking sectors during the propagate
// stage. In case there are many, many sectors, it lets us break them
// up instead of marking them all at once.
class DSectorMarker : public DObject
{
DECLARE_CLASS(DSectorMarker, DObject)
public:
DSectorMarker() : SecNum(0),PolyNum(0),SideNum(0) {}
size_t PropagateMark();
int SecNum;
int PolyNum;
int SideNum;
};
IMPLEMENT_CLASS(DSectorMarker, false, false)
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -154,8 +135,6 @@ bool FinalGC;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static DSectorMarker *SectorMarker;
// CODE --------------------------------------------------------------------
//==========================================================================
@ -303,10 +282,10 @@ static void MarkRoot()
Mark(StatusBar);
M_MarkMenus();
Mark(DIntermissionController::CurrentIntermission);
DThinker::MarkRoots();
Mark(E_FirstEventHandler);
Mark(E_LastEventHandler);
level.Mark();
Mark(staticEventManager.FirstEventHandler);
Mark(staticEventManager.LastEventHandler);
for (auto Level : AllLevels())
Level->Mark();
// Mark players.
for (i = 0; i < MAXPLAYERS; i++)
@ -314,27 +293,12 @@ static void MarkRoot()
if (playeringame[i])
players[i].PropagateMark();
}
// Mark sound sequences.
DSeqNode::StaticMarkHead();
// Mark sectors.
if (SectorMarker == nullptr && level.sectors.Size() > 0)
for (auto Level : AllLevels())
{
SectorMarker = Create<DSectorMarker>();
Level->Mark();
}
else if (level.sectors.Size() == 0)
{
SectorMarker = nullptr;
}
else
{
SectorMarker->SecNum = 0;
}
Mark(SectorMarker);
Mark(interpolator.Head);
// Mark bot stuff.
Mark(bglobal.firstthing);
Mark(bglobal.body1);
Mark(bglobal.body2);
// NextToThink must not be freed while thinkers are ticking.
Mark(NextToThink);
// Mark soft roots.
@ -617,77 +581,6 @@ void DelSoftRoot(DObject *obj)
}
//==========================================================================
//
// DSectorMarker :: PropagateMark
//
// Propagates marks across a few sectors and reinserts itself into the
// gray list if it didn't do them all.
//
//==========================================================================
size_t DSectorMarker::PropagateMark()
{
int i;
int marked = 0;
bool moretodo = false;
int numsectors = level.sectors.Size();
for (i = 0; i < SECTORSTEPSIZE && SecNum + i < numsectors; ++i)
{
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 && level.Polyobjects.Size() > 0)
{
for (i = 0; i < POLYSTEPSIZE && PolyNum + i < (int)level.Polyobjects.Size(); ++i)
{
GC::Mark(level.Polyobjects[PolyNum + i].interpolation);
}
marked += i * sizeof(FPolyObj);
if (PolyNum + i < (int)level.Polyobjects.Size())
{
PolyNum += i;
moretodo = true;
}
}
if (!moretodo && level.sides.Size() > 0)
{
for (i = 0; i < SIDEDEFSTEPSIZE && SideNum + i < (int)level.sides.Size(); ++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 < (int)level.sides.Size())
{
SideNum += i;
moretodo = true;
}
}
// If there are more sectors to mark, put ourself back into the gray
// list.
if (moretodo)
{
Black2Gray();
GCNext = GC::Gray;
GC::Gray = this;
}
return marked;
}
//==========================================================================
//
// STAT gc

View file

@ -49,6 +49,7 @@
#include "vm.h"
#include "types.h"
#include "scriptutil.h"
#include "i_system.h"
// MACROS ------------------------------------------------------------------
@ -562,12 +563,7 @@ void PClass::InitializeDefaults()
assert(Defaults == nullptr);
Defaults = (uint8_t *)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;

View file

@ -151,7 +151,9 @@ enum ELineFlags : unsigned
ML_MAPPED = 0x00000100, // set if already drawn in automap
ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable
// 0x400, 0x800 and 0x1000 are ML_SPAC_MASK, they can be used for internal things but not for real map flags.
ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally)
ML_COMPATSIDE = 0x00000800, // for compatible PointOnLineSide checks. Using the global compatibility check would be a bit expensive for this check.
// Extended flags
ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line

View file

@ -71,33 +71,6 @@ enum
};
// The current state of the game: whether we are
// playing, gazing at the intermission screen,
// the game final animation, or a demo.
enum gamestate_t : int
{
GS_LEVEL,
GS_INTERMISSION,
GS_FINALE,
GS_DEMOSCREEN,
GS_FULLCONSOLE, // [RH] Fullscreen console
GS_HIDECONSOLE, // [RH] The menu just did something that should hide fs console
GS_STARTUP, // [RH] Console is fullscreen, and game is just starting
GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN
GS_FORCEWIPE = -1,
GS_FORCEWIPEFADE = -2,
GS_FORCEWIPEBURN = -3,
GS_FORCEWIPEMELT = -4
};
extern gamestate_t gamestate;
// wipegamestate can be set to -1
// to force a wipe on the next draw
extern gamestate_t wipegamestate;
typedef float skill_t;
/*

View file

@ -39,6 +39,7 @@
#include <stdio.h>
#include <exception>
#include <stdexcept>
#include "doomtype.h"
#define MAX_ERRORTEXT 1024
@ -103,4 +104,7 @@ public:
CFatalError(const char *message) : CDoomError(message) {}
};
void I_Error (const char *error, ...) GCCPRINTF(1,2);
void I_FatalError (const char *error, ...) GCCPRINTF(1,2);
#endif //__ERRORS_H__

View file

@ -50,14 +50,21 @@ CVAR (Bool, alwaysapplydmflags, false, CVAR_SERVERINFO);
CUSTOM_CVAR (Float, teamdamage, 0.f, CVAR_SERVERINFO)
{
level.teamdamage = self;
for (auto Level : AllLevels())
{
Level->teamdamage = self;
}
}
CUSTOM_CVAR (String, language, "auto", CVAR_ARCHIVE)
{
SetLanguageIDs ();
GStrings.LoadStrings (false);
if (level.info != NULL) level.LevelName = level.info->LookupLevelName();
for (auto Level : AllLevels())
{
// does this even make sense on secondary levels...?
if (Level->info != nullptr) Level->LevelName = Level->info->LookupLevelName();
}
}
// [RH] Network arbitrator

View file

@ -248,7 +248,6 @@ EXTERN_CVAR (Int, dmflags2); // [BC]
EXTERN_CVAR (Int, compatflags);
EXTERN_CVAR (Int, compatflags2);
extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags;
// Filters from AddAutoloadFiles(). Used to filter files from archives.
extern FString LumpFilterIWAD;

View file

View file

@ -39,24 +39,27 @@
#include "actor.h"
#include "c_dispatch.h"
#include "d_net.h"
#include "g_game.h"
#include "info.h"
DStaticEventHandler* E_FirstEventHandler = nullptr;
DStaticEventHandler* E_LastEventHandler = nullptr;
EventManager staticEventManager;
EventManager eventManager;
bool E_RegisterHandler(DStaticEventHandler* handler)
bool EventManager::RegisterHandler(DStaticEventHandler* handler)
{
if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe)
return false;
if (E_CheckHandler(handler))
if (CheckHandler(handler))
return false;
handler->OnRegister();
handler->owner = this;
// link into normal list
// update: link at specific position based on order.
DStaticEventHandler* before = nullptr;
for (DStaticEventHandler* existinghandler = E_FirstEventHandler; existinghandler; existinghandler = existinghandler->next)
for (DStaticEventHandler* existinghandler = FirstEventHandler; existinghandler; existinghandler = existinghandler->next)
{
if (existinghandler->Order > handler->Order)
{
@ -65,11 +68,6 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
}
}
// 1. MyHandler2->1:
// E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler2
// 2. MyHandler3->2:
// E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler3
// (Yes, all those write barriers here are really needed!)
if (before != nullptr)
{
@ -86,9 +84,9 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
GC::WriteBarrier(handler, before->prev);
before->prev = handler;
GC::WriteBarrier(before, handler);
if (before == E_FirstEventHandler)
if (before == FirstEventHandler)
{
E_FirstEventHandler = handler;
FirstEventHandler = handler;
GC::WriteBarrier(handler);
}
}
@ -96,11 +94,11 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
{
// so if before is null, it means add last.
// it can also mean that we have no handlers at all yet.
handler->prev = E_LastEventHandler;
GC::WriteBarrier(handler, E_LastEventHandler);
handler->prev = LastEventHandler;
GC::WriteBarrier(handler, LastEventHandler);
handler->next = nullptr;
if (E_FirstEventHandler == nullptr) E_FirstEventHandler = handler;
E_LastEventHandler = handler;
if (FirstEventHandler == nullptr) FirstEventHandler = handler;
LastEventHandler = handler;
GC::WriteBarrier(handler);
if (handler->prev != nullptr)
{
@ -117,11 +115,11 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
return true;
}
bool E_UnregisterHandler(DStaticEventHandler* handler)
bool EventManager::UnregisterHandler(DStaticEventHandler* handler)
{
if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe)
return false;
if (!E_CheckHandler(handler))
if (!CheckHandler(handler))
return false;
handler->OnUnregister();
@ -137,14 +135,14 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
handler->next->prev = handler->prev;
GC::WriteBarrier(handler->next, handler->prev);
}
if (handler == E_FirstEventHandler)
if (handler == FirstEventHandler)
{
E_FirstEventHandler = handler->next;
FirstEventHandler = handler->next;
GC::WriteBarrier(handler->next);
}
if (handler == E_LastEventHandler)
if (handler == LastEventHandler)
{
E_LastEventHandler = handler->prev;
LastEventHandler = handler->prev;
GC::WriteBarrier(handler->prev);
}
if (handler->IsStatic())
@ -155,7 +153,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
return true;
}
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual)
bool EventManager::SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual)
{
if (gamestate != GS_LEVEL)
return false;
@ -171,73 +169,21 @@ bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual)
return true;
}
bool E_CheckHandler(DStaticEventHandler* handler)
bool EventManager::CheckHandler(DStaticEventHandler* handler)
{
for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next)
for (DStaticEventHandler* lhandler = FirstEventHandler; lhandler; lhandler = lhandler->next)
if (handler == lhandler) return true;
return false;
}
bool E_IsStaticType(PClass* type)
bool EventManager::IsStaticType(PClass* type)
{
assert(type != nullptr);
assert(type->IsDescendantOf(RUNTIME_CLASS(DStaticEventHandler)));
return !type->IsDescendantOf(RUNTIME_CLASS(DEventHandler));
}
void E_SerializeEvents(FSerializer& arc)
{
// todo : stuff
if (arc.BeginArray("eventhandlers"))
{
int numlocalhandlers = 0;
TArray<DStaticEventHandler*> handlers;
if (arc.isReading())
{
numlocalhandlers = arc.ArraySize();
// delete all current local handlers, if any
for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next)
if (!lhandler->IsStatic()) lhandler->Destroy();
}
else
{
for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next)
{
if (lhandler->IsStatic()) continue;
numlocalhandlers++;
handlers.Push(lhandler);
}
}
for (int i = 0; i < numlocalhandlers; i++)
{
// serialize the object properly.
if (arc.isReading())
{
// get object and put it into the array
DStaticEventHandler* lhandler;
arc(nullptr, lhandler);
if (lhandler != nullptr)
handlers.Push(lhandler);
}
else
{
::Serialize<DStaticEventHandler>(arc, nullptr, handlers[i], nullptr);
}
}
if (arc.isReading())
{
// add all newly deserialized handlers into the list
for (int i = 0; i < numlocalhandlers; i++)
E_RegisterHandler(handlers[i]);
}
arc.EndArray();
}
}
static PClass* E_GetHandlerClass(const FString& typeName)
static PClass* GetHandlerClass(const FString& typeName)
{
PClass* type = PClass::FindClass(typeName);
@ -253,11 +199,11 @@ static PClass* E_GetHandlerClass(const FString& typeName)
return type;
}
static void E_InitHandler(PClass* type)
void EventManager::InitHandler(PClass* type)
{
// check if type already exists, don't add twice.
bool typeExists = false;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
{
if (handler->IsA(type))
{
@ -268,27 +214,27 @@ static void E_InitHandler(PClass* type)
if (typeExists) return;
DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew();
E_RegisterHandler(handler);
RegisterHandler(handler);
}
void E_InitStaticHandlers(bool map)
void EventManager::InitStaticHandlers(bool map)
{
// don't initialize map handlers if restoring from savegame.
if (savegamerestore)
return;
// just make sure
E_Shutdown(map);
Shutdown();
// initialize event handlers from gameinfo
for (const FString& typeName : gameinfo.EventHandlers)
{
PClass* type = E_GetHandlerClass(typeName);
PClass* type = GetHandlerClass(typeName);
// don't init the really global stuff here on startup initialization.
// don't init map-local global stuff here on level setup.
if (map == E_IsStaticType(type))
if (map == IsStaticType(type))
continue;
E_InitHandler(type);
InitHandler(type);
}
if (!map)
@ -297,107 +243,105 @@ void E_InitStaticHandlers(bool map)
// initialize event handlers from mapinfo
for (const FString& typeName : level.info->EventHandlers)
{
PClass* type = E_GetHandlerClass(typeName);
if (E_IsStaticType(type))
PClass* type = GetHandlerClass(typeName);
if (IsStaticType(type))
I_Error("Fatal: invalid event handler class %s in MAPINFO!\nMap-specific event handlers cannot be static.\n", typeName.GetChars());
E_InitHandler(type);
InitHandler(type);
}
}
void E_Shutdown(bool map)
void EventManager::Shutdown()
{
// delete handlers.
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
{
if (handler->IsStatic() == !map)
handler->Destroy();
handler->Destroy();
}
}
#define DEFINE_EVENT_LOOPER(name) void E_##name() \
#define DEFINE_EVENT_LOOPER(name, play) void EventManager::name() \
{ \
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) \
if (ShouldCallStatic(play)) staticEventManager.name(); \
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) \
handler->name(); \
}
// note for the functions below.
// *Unsafe is executed on EVERY map load/close, including savegame loading, etc.
// There is no point in allowing non-static handlers to receive unsafe event separately, as there is no point in having static handlers receive safe event.
// Because the main point of safe WorldLoaded/Unloading is that it will be preserved in savegames.
void E_WorldLoaded()
void EventManager::WorldLoaded()
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
{
if (handler->IsStatic()) continue;
if (savegamerestore) continue; // don't execute WorldLoaded for handlers loaded from the savegame.
handler->WorldLoaded();
}
}
void E_WorldUnloaded()
void EventManager::WorldUnloaded()
{
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
{
if (handler->IsStatic()) continue;
handler->WorldUnloaded();
}
}
void E_WorldLoadedUnsafe()
bool EventManager::ShouldCallStatic(bool forplay)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
{
if (!handler->IsStatic()) continue;
handler->WorldLoaded();
}
return this != &staticEventManager && Level == primaryLevel;
}
void E_WorldUnloadedUnsafe()
{
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
{
if (!handler->IsStatic()) continue;
handler->WorldUnloaded();
}
}
void E_WorldThingSpawned(AActor* actor)
void EventManager::WorldThingSpawned(AActor* actor)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldThingSpawned(actor);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldThingSpawned(actor);
}
void E_WorldThingDied(AActor* actor, AActor* inflictor)
void EventManager::WorldThingDied(AActor* actor, AActor* inflictor)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldThingDied(actor, inflictor);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldThingDied(actor, inflictor);
}
void E_WorldThingRevived(AActor* actor)
void EventManager::WorldThingRevived(AActor* actor)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldThingRevived(actor);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldThingRevived(actor);
}
void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle)
void EventManager::WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldThingDamaged(actor, inflictor, source, damage, mod, flags, angle);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldThingDamaged(actor, inflictor, source, damage, mod, flags, angle);
}
void E_WorldThingDestroyed(AActor* actor)
void EventManager::WorldThingDestroyed(AActor* actor)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
@ -406,73 +350,92 @@ void E_WorldThingDestroyed(AActor* actor)
// this is because Destroyed should be reverse of Spawned. we don't want to catch random inventory give failures.
if (!(actor->ObjectFlags & OF_Spawned))
return;
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
handler->WorldThingDestroyed(actor);
if (ShouldCallStatic(true)) staticEventManager.WorldThingDestroyed(actor);
}
void E_WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate)
void EventManager::WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldLinePreActivated(line, actor, activationType, shouldactivate);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldLinePreActivated(line, actor, activationType, shouldactivate);
}
void E_WorldLineActivated(line_t* line, AActor* actor, int activationType)
void EventManager::WorldLineActivated(line_t* line, AActor* actor, int activationType)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldLineActivated(line, actor, activationType);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldLineActivated(line, actor, activationType);
}
int E_WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius)
int EventManager::WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldSectorDamaged(sector, source, damage, damagetype, part, position, isradius);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
damage = handler->WorldSectorDamaged(sector, source, damage, damagetype, part, position, isradius);
return damage;
}
int E_WorldLineDamaged(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius)
int EventManager::WorldLineDamaged(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.WorldLineDamaged(line, source, damage, damagetype, side, position, isradius);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
damage = handler->WorldLineDamaged(line, source, damage, damagetype, side, position, isradius);
return damage;
}
void E_PlayerEntered(int num, bool fromhub)
void EventManager::PlayerEntered(int num, bool fromhub)
{
// this event can happen during savegamerestore. make sure that local handlers don't receive it.
// actually, global handlers don't want it too.
if (savegamerestore && !fromhub)
return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.PlayerEntered(num, fromhub);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->PlayerEntered(num, fromhub);
}
void E_PlayerRespawned(int num)
void EventManager::PlayerRespawned(int num)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.PlayerRespawned(num);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->PlayerRespawned(num);
}
void E_PlayerDied(int num)
void EventManager::PlayerDied(int num)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(true)) staticEventManager.PlayerDied(num);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->PlayerDied(num);
}
void E_PlayerDisconnected(int num)
void EventManager::PlayerDisconnected(int num)
{
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
handler->PlayerDisconnected(num);
if (ShouldCallStatic(true)) staticEventManager.PlayerDisconnected(num);
}
bool E_Responder(const event_t* ev)
bool EventManager::Responder(const event_t* ev)
{
bool uiProcessorsFound = false;
if (ev->type == EV_GUI_Event)
{
// iterate handlers back to front by order, and give them this event.
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
{
if (handler->IsUiProcessor)
{
@ -485,7 +448,7 @@ bool E_Responder(const event_t* ev)
else
{
// not sure if we want to handle device changes, but whatevs.
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
for (DStaticEventHandler* handler = LastEventHandler; handler; handler = handler->prev)
{
if (handler->IsUiProcessor)
uiProcessorsFound = true;
@ -493,77 +456,92 @@ bool E_Responder(const event_t* ev)
return true; // event was processed
}
}
if (ShouldCallStatic(false)) uiProcessorsFound = staticEventManager.Responder(ev);
return (uiProcessorsFound && (ev->type == EV_Mouse)); // mouse events are eaten by the event system if there are any uiprocessors.
}
void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual)
void EventManager::Console(int player, FString name, int arg1, int arg2, int arg3, bool manual)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(false)) staticEventManager.Console(player, name, arg1, arg2, arg3, manual);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->ConsoleProcess(player, name, arg1, arg2, arg3, manual);
}
void E_RenderOverlay(EHudState state)
void EventManager::RenderOverlay(EHudState state)
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(false)) staticEventManager.RenderOverlay(state);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->RenderOverlay(state);
}
bool E_CheckUiProcessors()
bool EventManager::CheckUiProcessors()
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(false))
{
if (staticEventManager.CheckUiProcessors()) return true;
}
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
if (handler->IsUiProcessor)
return true;
return false;
}
bool E_CheckRequireMouse()
bool EventManager::CheckRequireMouse()
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(false))
{
if (staticEventManager.CheckRequireMouse()) return true;
}
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
if (handler->IsUiProcessor && handler->RequireMouse)
return true;
return false;
}
bool E_CheckReplacement( PClassActor *replacee, PClassActor **replacement )
bool EventManager::CheckReplacement( PClassActor *replacee, PClassActor **replacement )
{
bool final = false;
for (DStaticEventHandler *handler = E_FirstEventHandler; handler; handler = handler->next)
// This is play scope but unlike in-game events needs to be handled like UI by static handlers.
if (ShouldCallStatic(false)) final = staticEventManager.CheckReplacement(replacee, replacement);
for (DStaticEventHandler *handler = FirstEventHandler; handler; handler = handler->next)
handler->CheckReplacement(replacee,replacement,&final);
return final;
}
bool E_CheckReplacee(PClassActor **replacee, PClassActor *replacement)
bool EventManager::CheckReplacee(PClassActor **replacee, PClassActor *replacement)
{
bool final = false;
for (DStaticEventHandler *handler = E_FirstEventHandler; handler; handler = handler->next)
if (ShouldCallStatic(false)) final = staticEventManager.CheckReplacee(replacee, replacement);
for (DStaticEventHandler *handler = FirstEventHandler; handler; handler = handler->next)
handler->CheckReplacee(replacee, replacement, &final);
return final;
}
void E_NewGame(EventHandlerType handlerType)
void EventManager::NewGame()
{
bool isStatic = handlerType == EventHandlerType::Global;
// Shut down all per-map event handlers before static NewGame events.
if (isStatic)
E_Shutdown(true);
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
//This is called separately for static and local handlers, so no forwarding here.
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
{
if (handler->IsStatic() == isStatic)
handler->NewGame();
handler->NewGame();
}
}
// normal event loopers (non-special, argument-less)
DEFINE_EVENT_LOOPER(RenderFrame)
DEFINE_EVENT_LOOPER(WorldLightning)
DEFINE_EVENT_LOOPER(WorldTick)
DEFINE_EVENT_LOOPER(UiTick)
DEFINE_EVENT_LOOPER(PostUiTick)
DEFINE_EVENT_LOOPER(RenderFrame, false)
DEFINE_EVENT_LOOPER(WorldLightning, true)
DEFINE_EVENT_LOOPER(WorldTick, true)
DEFINE_EVENT_LOOPER(UiTick, false)
DEFINE_EVENT_LOOPER(PostUiTick, false)
// declarations
IMPLEMENT_CLASS(DStaticEventHandler, false, true);
@ -643,8 +621,10 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder)
PARAM_SELF_PROLOGUE(DStaticEventHandler);
PARAM_INT(order);
if (E_CheckHandler(self))
/* not really needed - this is never checked again. To re-add, the handlers need a pointer to their manager but that's not worth it just for this check.
if (eventManager.CheckHandler(self))
return 0;
*/
self->Order = order;
return 0;
@ -659,14 +639,14 @@ DEFINE_ACTION_FUNCTION(DEventHandler, SendNetworkEvent)
PARAM_INT(arg3);
//
ACTION_RETURN_BOOL(E_SendNetworkEvent(name, arg1, arg2, arg3, false));
ACTION_RETURN_BOOL(currentVMLevel->localEventManager->SendNetworkEvent(name, arg1, arg2, arg3, false));
}
DEFINE_ACTION_FUNCTION(DEventHandler, Find)
{
PARAM_PROLOGUE;
PARAM_CLASS(t, DStaticEventHandler);
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
for (DStaticEventHandler* handler = currentVMLevel->localEventManager->FirstEventHandler; handler; handler = handler->next)
if (handler->GetClass() == t) // check precise class
ACTION_RETURN_OBJECT(handler);
ACTION_RETURN_OBJECT(nullptr);
@ -677,7 +657,7 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Find)
{
PARAM_PROLOGUE;
PARAM_CLASS(t, DStaticEventHandler);
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
for (DStaticEventHandler* handler = staticEventManager.FirstEventHandler; handler; handler = handler->next)
if (handler->GetClass() == t) // check precise class
ACTION_RETURN_OBJECT(handler);
ACTION_RETURN_OBJECT(nullptr);
@ -725,11 +705,11 @@ void DStaticEventHandler::OnUnregister()
}
}
static FWorldEvent E_SetupWorldEvent()
FWorldEvent EventManager::SetupWorldEvent()
{
FWorldEvent e;
e.IsSaveGame = savegamerestore;
e.IsReopen = level.FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1.
e.IsReopen = Level->FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1.
e.DamageAngle = 0.0;
return e;
}
@ -740,7 +720,7 @@ void DStaticEventHandler::WorldLoaded()
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
@ -752,7 +732,7 @@ void DStaticEventHandler::WorldUnloaded()
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
@ -764,7 +744,7 @@ void DStaticEventHandler::WorldThingSpawned(AActor* actor)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
@ -777,7 +757,7 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.Inflictor = inflictor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
@ -791,7 +771,7 @@ void DStaticEventHandler::WorldThingRevived(AActor* actor)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
@ -804,7 +784,7 @@ void DStaticEventHandler::WorldThingDamaged(AActor* actor, AActor* inflictor, AA
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.Inflictor = inflictor;
e.Damage = damage;
@ -823,7 +803,7 @@ void DStaticEventHandler::WorldThingDestroyed(AActor* actor)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
@ -836,7 +816,7 @@ void DStaticEventHandler::WorldLinePreActivated(line_t* line, AActor* actor, int
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.ActivatedLine = line;
e.ActivationType = activationType;
@ -853,7 +833,7 @@ void DStaticEventHandler::WorldLineActivated(line_t* line, AActor* actor, int ac
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.ActivatedLine = line;
e.ActivationType = activationType;
@ -868,7 +848,7 @@ int DStaticEventHandler::WorldSectorDamaged(sector_t* sector, AActor* source, in
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return damage;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.DamageSource = source;
e.DamageSector = sector;
e.NewDamage = e.Damage = damage;
@ -891,7 +871,7 @@ int DStaticEventHandler::WorldLineDamaged(line_t* line, AActor* source, int dama
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return damage;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
e.DamageSource = source;
e.DamageLine = line;
e.NewDamage = e.Damage = damage;
@ -914,7 +894,7 @@ void DStaticEventHandler::WorldLightning()
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = E_SetupWorldEvent();
FWorldEvent e = owner->SetupWorldEvent();
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
@ -931,7 +911,7 @@ void DStaticEventHandler::WorldTick()
}
}
static FRenderEvent E_SetupRenderEvent()
FRenderEvent EventManager::SetupRenderEvent()
{
FRenderEvent e;
auto &vp = r_viewpoint;
@ -951,7 +931,7 @@ void DStaticEventHandler::RenderFrame()
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FRenderEvent e = E_SetupRenderEvent();
FRenderEvent e = owner->SetupRenderEvent;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
@ -964,7 +944,7 @@ void DStaticEventHandler::RenderOverlay(EHudState state)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FRenderEvent e = E_SetupRenderEvent();
FRenderEvent e = owner->SetupRenderEvent();
e.HudState = int(state);
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
@ -1189,7 +1169,7 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int
}
}
void DStaticEventHandler::CheckReplacement( PClassActor *replacee, PClassActor **replacement, bool *final )
void DStaticEventHandler::CheckReplacement(PClassActor *replacee, PClassActor **replacement, bool *final )
{
IFVIRTUAL(DStaticEventHandler, CheckReplacement)
{
@ -1233,7 +1213,7 @@ void DStaticEventHandler::NewGame()
//
void DStaticEventHandler::OnDestroy()
{
E_UnregisterHandler(this);
eventManager.UnregisterHandler(this);
Super::OnDestroy();
}
@ -1254,7 +1234,7 @@ CCMD(event)
for (int i = 0; i < argn; i++)
arg[i] = atoi(argv[2 + i]);
// call locally
E_Console(-1, argv[1], arg[0], arg[1], arg[2], true);
primaryLevel->localEventManager->Console(-1, argv[1], arg[0], arg[1], arg[2], true);
}
}
@ -1279,6 +1259,6 @@ CCMD(netevent)
for (int i = 0; i < argn; i++)
arg[i] = atoi(argv[2 + i]);
// call networked
E_SendNetworkEvent(argv[1], arg[0], arg[1], arg[2], true);
primaryLevel->localEventManager->SendNetworkEvent(argv[1], arg[0], arg[1], arg[2], true);
}
}

View file

@ -1,5 +1,4 @@
#ifndef EVENTS_H
#define EVENTS_H
#pragma once
#include "dobject.h"
#include "serializer.h"
@ -8,6 +7,7 @@
#include "sbar.h"
class DStaticEventHandler;
struct EventManager;
enum class EventHandlerType
{
@ -15,89 +15,6 @@ enum class EventHandlerType
PerMap
};
// register
bool E_RegisterHandler(DStaticEventHandler* handler);
// unregister
bool E_UnregisterHandler(DStaticEventHandler* handler);
// find
bool E_CheckHandler(DStaticEventHandler* handler);
// check type
bool E_IsStaticType(PClass* type);
// init static handlers
void E_InitStaticHandlers(bool map);
// shutdown handlers
void E_Shutdown(bool map);
// called right after the map has loaded (approximately same time as OPEN ACS scripts)
void E_WorldLoaded();
// called when the map is about to unload (approximately same time as UNLOADING ACS scripts)
void E_WorldUnloaded();
// called right after the map has loaded (every time, UNSAFE VERSION)
void E_WorldLoadedUnsafe();
// called right before the map is unloaded (every time, UNSAFE VERSION)
void E_WorldUnloadedUnsafe();
// called around PostBeginPlay of each actor.
void E_WorldThingSpawned(AActor* actor);
// called after AActor::Die of each actor.
void E_WorldThingDied(AActor* actor, AActor* inflictor);
// called after AActor::Revive.
void E_WorldThingRevived(AActor* actor);
// called before P_DamageMobj and before AActor::DamageMobj virtuals.
void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle);
// called before AActor::Destroy of each actor.
void E_WorldThingDestroyed(AActor* actor);
// called in P_ActivateLine before executing special, set shouldactivate to false to prevent activation.
void E_WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate);
// called in P_ActivateLine after successful special execution.
void E_WorldLineActivated(line_t* line, AActor* actor, int activationType);
// called in P_DamageSector and P_DamageLinedef before receiving damage to the sector. returns actual damage
int E_WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius);
// called in P_DamageLinedef before receiving damage to the linedef. returns actual damage
int E_WorldLineDamaged(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius);
// same as ACS SCRIPT_Lightning
void E_WorldLightning();
// this executes on every tick, before everything, only when in valid level and not paused
void E_WorldTick();
// this executes on every tick on UI side, always
void E_UiTick();
// this executes on every tick on UI side, always AND immediately after everything else
void E_PostUiTick();
// called on each render frame once.
void E_RenderFrame();
// called after everything's been rendered, but before console/menus
void E_RenderOverlay(EHudState state);
// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN
void E_PlayerEntered(int num, bool fromhub);
// this executes when a player respawns. includes resurrect cheat.
void E_PlayerRespawned(int num);
// this executes when a player dies (partially duplicating worldthingdied, but whatever)
void E_PlayerDied(int num);
// this executes when a player leaves the game
void E_PlayerDisconnected(int num);
// this executes on events.
bool E_Responder(const event_t* ev); // splits events into InputProcess and UiProcess
// this executes on console/net events.
void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual);
// called when looking up the replacement for an actor class
bool E_CheckReplacement(PClassActor* replacee, PClassActor** replacement);
// called when looking up the replaced for an actor class
bool E_CheckReplacee(PClassActor** replacee, PClassActor* replacement);
// called on new game
void E_NewGame(EventHandlerType handlerType);
// send networked event. unified function.
bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual);
// check if there is anything that should receive GUI events
bool E_CheckUiProcessors();
// check if we need native mouse due to UiProcessors
bool E_CheckRequireMouse();
// serialization stuff
void E_SerializeEvents(FSerializer& arc);
// ==============================================
//
// EventHandler - base class
@ -117,6 +34,7 @@ public:
IsUiProcessor = false;
}
EventManager *owner;
DStaticEventHandler* prev;
DStaticEventHandler* next;
virtual bool IsStatic() { return true; }
@ -141,6 +59,8 @@ public:
}
*/
arc("next", next);
arc("prev", prev);
arc("Order", Order);
arc("IsUiProcessor", IsUiProcessor);
arc("RequireMouse", RequireMouse);
@ -200,8 +120,6 @@ class DEventHandler : public DStaticEventHandler
public:
bool IsStatic() override { return false; }
};
extern DStaticEventHandler* E_FirstEventHandler;
extern DStaticEventHandler* E_LastEventHandler;
struct FRenderEvent
{
@ -311,4 +229,106 @@ struct FReplacedEvent
bool IsFinal;
};
#endif
struct EventManager
{
FLevelLocals *Level = nullptr;
DStaticEventHandler* FirstEventHandler = nullptr;
DStaticEventHandler* LastEventHandler = nullptr;
EventManager() = default;
EventManager(FLevelLocals *l) { Level = l; }
~EventManager() { Shutdown(); }
bool ShouldCallStatic(bool forplay);
// register
bool RegisterHandler(DStaticEventHandler* handler);
// unregister
bool UnregisterHandler(DStaticEventHandler* handler);
// find
bool CheckHandler(DStaticEventHandler* handler);
// check type
bool IsStaticType(PClass* type);
// init static handlers
void InitStaticHandlers(bool map);
// shutdown handlers
void Shutdown();
// called right after the map has loaded (approximately same time as OPEN ACS scripts)
void WorldLoaded();
// called when the map is about to unload (approximately same time as UNLOADING ACS scripts)
void WorldUnloaded();
// called around PostBeginPlay of each actor.
void WorldThingSpawned(AActor* actor);
// called after AActor::Die of each actor.
void WorldThingDied(AActor* actor, AActor* inflictor);
// called after AActor::Revive.
void WorldThingRevived(AActor* actor);
// called before P_DamageMobj and before AActor::DamageMobj virtuals.
void WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle);
// called before AActor::Destroy of each actor.
void WorldThingDestroyed(AActor* actor);
// called in P_ActivateLine before executing special, set shouldactivate to false to prevent activation.
void WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate);
// called in P_ActivateLine after successful special execution.
void WorldLineActivated(line_t* line, AActor* actor, int activationType);
// called in P_DamageSector and P_DamageLinedef before receiving damage to the sector. returns actual damage
int WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius);
// called in P_DamageLinedef before receiving damage to the linedef. returns actual damage
int WorldLineDamaged(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius);
// same as ACS SCRIPT_Lightning
void WorldLightning();
// this executes on every tick, before everything, only when in valid level and not paused
void WorldTick();
// this executes on every tick on UI side, always
void UiTick();
// this executes on every tick on UI side, always AND immediately after everything else
void PostUiTick();
// called on each render frame once.
void RenderFrame();
// called after everything's been rendered, but before console/menus
void RenderOverlay(EHudState state);
// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN
void PlayerEntered(int num, bool fromhub);
// this executes when a player respawns. includes resurrect cheat.
void PlayerRespawned(int num);
// this executes when a player dies (partially duplicating worldthingdied, but whatever)
void PlayerDied(int num);
// this executes when a player leaves the game
void PlayerDisconnected(int num);
// this executes on events.
bool Responder(const event_t* ev); // splits events into InputProcess and UiProcess
// this executes on console/net events.
void Console(int player, FString name, int arg1, int arg2, int arg3, bool manual);
// called when looking up the replacement for an actor class
bool CheckReplacement(PClassActor* replacee, PClassActor** replacement);
// called when looking up the replaced for an actor class
bool CheckReplacee(PClassActor** replacee, PClassActor* replacement);
// called on new game
void NewGame();
// send networked event. unified function.
bool SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual);
// check if there is anything that should receive GUI events
bool CheckUiProcessors();
// check if we need native mouse due to UiProcessors
bool CheckRequireMouse();
void InitHandler(PClass* type);
FWorldEvent SetupWorldEvent();
FRenderEvent SetupRenderEvent();
void SetOwnerForHandlers()
{
for (DStaticEventHandler* existinghandler = FirstEventHandler; existinghandler; existinghandler = existinghandler->next)
{
existinghandler->owner = this;
}
}
};
extern EventManager eventManager;
extern EventManager staticEventManager;

View file

@ -77,7 +77,7 @@ static void FS_Gimme(const char * what)
//
//==========================================================================
void FS_MapCmd(FScanner &sc)
void FS_MapCmd(FLevelLocals *Level, FScanner &sc)
{
char nextmap[9];
int NextSkill = -1;
@ -108,7 +108,7 @@ void FS_MapCmd(FScanner &sc)
flags &= ~(CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH);
}
}
G_ChangeLevel(nextmap, 0, flags, NextSkill);
Level->ChangeLevel(nextmap, 0, flags, NextSkill);
}
//==========================================================================
@ -154,12 +154,12 @@ void FS_EmulateCmd(FLevelLocals *Level, char * string)
{
sc.MustGetFloat();
double playerviewheight = sc.Float;
for(int i=0;i<MAXPLAYERS;i++)
for (auto p : Level->Players)
{
// No, this is not correct. But this is the way Legacy WADs expect it to be handled!
if (players[i].mo != NULL) players[i].mo->FloatVar(NAME_ViewHeight) = playerviewheight;
players[i].viewheight = playerviewheight;
players[i].Uncrouch();
if (p->mo != nullptr) p->mo->FloatVar(NAME_ViewHeight) = playerviewheight;
p->viewheight = playerviewheight;
p->Uncrouch();
}
while (sc.GetString())
{
@ -168,7 +168,7 @@ void FS_EmulateCmd(FLevelLocals *Level, char * string)
}
else if (sc.Compare("map"))
{
FS_MapCmd(sc);
FS_MapCmd(Level, sc);
}
else if (sc.Compare("gr_fogdensity"))
{

View file

@ -50,6 +50,7 @@
#include "actorinlines.h"
#include "scriptutil.h"
#include "vm.h"
#include "a_lights.h"
static FRandom pr_script("FScript");
@ -269,7 +270,7 @@ int FParser::T_GetPlayerNum(const svalue_t &arg)
//script_error("mobj not a player!\n");
return -1;
}
playernum = int(arg.value.mobj->player - players);
playernum = Level->PlayerNum(arg.value.mobj->player);
}
else
playernum = intvalue(arg);
@ -278,7 +279,7 @@ int FParser::T_GetPlayerNum(const svalue_t &arg)
{
return -1;
}
if(!playeringame[playernum]) // no error, just return -1
if(!Level->PlayerInGame(playernum)) // no error, just return -1
{
return -1;
}
@ -288,7 +289,7 @@ int FParser::T_GetPlayerNum(const svalue_t &arg)
AActor *FParser::T_GetPlayerActor(const svalue_t &arg)
{
int num = T_GetPlayerNum(arg);
return num == -1 ? nullptr : players[num].mo;
return num == -1 ? nullptr : Level->Players[num]->mo;
}
PClassActor *T_ClassType(const svalue_t &arg)
@ -296,33 +297,6 @@ PClassActor *T_ClassType(const svalue_t &arg)
return PClass::FindActor(stringvalue(arg));
}
//==========================================================================
//
// Finds a sector from a tag. This has been extended to allow looking for
// sectors directly by passing a negative value
//
//==========================================================================
class FSSectorTagIterator : public FSectorTagIterator
{
public:
FSSectorTagIterator(int tag)
: FSectorTagIterator(tag)
{
if (tag < 0)
{
searchtag = INT_MIN;
start = tag == -32768? 0 : -tag < (int)level.sectors.Size()? -tag : -1;
}
}
};
inline int T_FindFirstSectorFromTag(int tagnum)
{
FSSectorTagIterator it(tagnum);
return it.Next();
}
//==========================================================================
//
// Get an ammo type
@ -587,7 +561,7 @@ void FParser::SF_Include(void)
else
mysnprintf(tempstr, countof(tempstr), "%i", (int)t_argv[0].value.i);
Script->ParseInclude(tempstr);
Script->ParseInclude(Level, tempstr);
}
}
@ -635,7 +609,7 @@ void FParser::SF_Clock(void)
void FParser::SF_ExitLevel(void)
{
G_ExitLevel(0, false);
Level->ExitLevel(0, false);
}
//==========================================================================
@ -647,7 +621,7 @@ void FParser::SF_ExitLevel(void)
void FParser::SF_Tip(void)
{
if (t_argc>0 && Script->trigger &&
Script->trigger->CheckLocalView(consoleplayer))
Script->trigger->CheckLocalView())
{
C_MidPrint(SmallFont, GetFormatString(0).GetChars());
}
@ -686,7 +660,7 @@ void FParser::SF_PlayerTip(void)
if (CheckArgs(1))
{
int plnum = T_GetPlayerNum(t_argv[0]);
if (plnum!=-1 && players[plnum].mo->CheckLocalView(consoleplayer))
if (plnum!=-1 && Level->Players[plnum]->mo->CheckLocalView())
{
C_MidPrint(SmallFont, GetFormatString(1).GetChars());
}
@ -702,7 +676,7 @@ void FParser::SF_PlayerTip(void)
void FParser::SF_Message(void)
{
if (t_argc>0 && Script->trigger &&
Script->trigger->CheckLocalView(consoleplayer))
Script->trigger->CheckLocalView())
{
Printf(PRINT_HIGH, "%s\n", GetFormatString(0).GetChars());
}
@ -719,7 +693,7 @@ void FParser::SF_PlayerMsg(void)
if (CheckArgs(1))
{
int plnum = T_GetPlayerNum(t_argv[0]);
if (plnum!=-1 && players[plnum].mo->CheckLocalView(consoleplayer))
if (plnum!=-1 && Level->Players[plnum]->mo->CheckLocalView())
{
Printf(PRINT_HIGH, "%s\n", GetFormatString(1).GetChars());
}
@ -741,7 +715,7 @@ void FParser::SF_PlayerInGame(void)
if (plnum!=-1)
{
t_return.type = svt_int;
t_return.value.i = playeringame[plnum];
t_return.value.i = Level->PlayerInGame(plnum);
}
}
}
@ -760,7 +734,7 @@ void FParser::SF_PlayerName(void)
{
player_t *pl=NULL;
if (Script->trigger) pl = Script->trigger->player;
if(pl) plnum = int(pl - players);
if(pl) plnum = Level->PlayerNum(pl);
else plnum=-1;
}
else
@ -769,7 +743,7 @@ void FParser::SF_PlayerName(void)
if(plnum !=-1)
{
t_return.type = svt_string;
t_return.string = players[plnum].userinfo.GetName();
t_return.string = Level->Players[plnum]->userinfo.GetName();
}
else
{
@ -791,7 +765,7 @@ void FParser::SF_PlayerObj(void)
{
player_t *pl=NULL;
if (Script->trigger) pl = Script->trigger->player;
if(pl) plnum = int(pl - players);
if(pl) plnum = Level->PlayerNum(pl);
else plnum=-1;
}
else
@ -800,7 +774,7 @@ void FParser::SF_PlayerObj(void)
if(plnum !=-1)
{
t_return.type = svt_mobj;
t_return.value.mobj = players[plnum].mo;
t_return.value.mobj = Level->Players[plnum]->mo;
}
else
{
@ -831,7 +805,7 @@ void FParser::SF_Player(void)
if(mo && mo->player) // haleyjd: added mo->player
{
t_return.value.i = (int)(mo->player - players);
t_return.value.i = Level->PlayerNum(mo->player);
}
else
{
@ -866,7 +840,7 @@ void FParser::SF_Spawn(void)
// [Graf Zahl] added option of spawning with a relative z coordinate
if(t_argc > 5)
{
if (intvalue(t_argv[5])) pos.Z += P_PointInSector(pos)->floorplane.ZatPoint(pos);
if (intvalue(t_argv[5])) pos.Z += Level->PointInSector(pos)->floorplane.ZatPoint(pos);
}
}
else
@ -881,7 +855,7 @@ void FParser::SF_Spawn(void)
}
t_return.type = svt_mobj;
t_return.value.mobj = Spawn(pclass, pos, ALLOW_REPLACE);
t_return.value.mobj = Spawn(Level, pclass, pos, ALLOW_REPLACE);
if (t_return.value.mobj)
{
@ -1067,7 +1041,7 @@ void FParser::SF_Teleport(void)
}
if(mo)
EV_Teleport(0, tag, NULL, 0, mo, TELF_DESTFOG | TELF_SOURCEFOG);
Level->EV_Teleport(0, tag, NULL, 0, mo, TELF_DESTFOG | TELF_SOURCEFOG);
}
}
@ -1096,7 +1070,7 @@ void FParser::SF_SilentTeleport(void)
}
if(mo)
EV_Teleport(0, tag, NULL, 0, mo, TELF_KEEPORIENTATION);
Level->EV_Teleport(0, tag, NULL, 0, mo, TELF_KEEPORIENTATION);
}
}
@ -1150,7 +1124,7 @@ void FParser::SF_ObjSector(void)
}
t_return.type = svt_int;
t_return.value.i = mo ? tagManager.GetFirstSectorTag(mo->Sector) : 0; // nullptr check
t_return.value.i = mo ? Level->GetFirstSectorTag(mo->Sector) : 0; // nullptr check
}
//==========================================================================
@ -1429,8 +1403,8 @@ void FParser::SF_SetCamera(void)
if (CheckArgs(1))
{
player=Script->trigger->player;
if (!player) player=&players[0];
player = Script->trigger->player;
if (!player) player = Level->Players[0];
newcamera = actorvalue(t_argv[0]);
if(!newcamera)
@ -1449,7 +1423,7 @@ void FParser::SF_SetCamera(void)
if (t_argc < 4) newcamera->Angles.Pitch = 0.;
else newcamera->Angles.Pitch = clamp(floatvalue(t_argv[3]), -50., 50.) * (20. / 32.);
player->camera=newcamera;
R_ResetViewInterpolation();
newcamera->renderflags |= RF_NOINTERPOLATEVIEW;
}
}
@ -1462,8 +1436,8 @@ void FParser::SF_SetCamera(void)
void FParser::SF_ClearCamera(void)
{
player_t * player;
player=Script->trigger->player;
if (!player) player=&players[0];
player = Script->trigger->player;
if (!player) player = Level->Players[0];
AActor * cam=player->camera;
if (cam)
@ -1518,7 +1492,7 @@ void FParser::SF_StartSectorSound(void)
tagnum = intvalue(t_argv[0]);
int i=-1;
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
sector = &Level->sectors[i];
@ -1555,7 +1529,7 @@ void FParser::SF_FloorHeight(void)
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
auto &sec = Level->sectors[i];
@ -1574,7 +1548,7 @@ void FParser::SF_FloorHeight(void)
}
else
{
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{
script_error("sector not found with tagnum %i\n", tagnum);
@ -1610,10 +1584,10 @@ void FParser::SF_MoveFloor(void)
// move all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((secnum = itr.Next()) >= 0)
{
P_CreateFloor(&Level->sectors[secnum], DFloor::floorMoveToValue, NULL, platspeed, destheight, crush, 0, false, false);
Level->CreateFloor(&Level->sectors[secnum], DFloor::floorMoveToValue, NULL, platspeed, destheight, crush, 0, false, false);
}
}
}
@ -1645,7 +1619,7 @@ void FParser::SF_CeilingHeight(void)
dest = floatvalue(t_argv[1]);
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
auto &sec = Level->sectors[i];
@ -1664,7 +1638,7 @@ void FParser::SF_CeilingHeight(void)
}
else
{
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{
script_error("sector not found with tagnum %i\n", tagnum);
@ -1702,10 +1676,10 @@ void FParser::SF_MoveCeiling(void)
silent=t_argc>4 ? intvalue(t_argv[4]):1;
// move all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((secnum = itr.Next()) >= 0)
{
P_CreateCeiling(&Level->sectors[secnum], DCeiling::ceilMoveToValue, NULL, tagnum, platspeed, platspeed, destheight, crush, silent | 4, 0, DCeiling::ECrushMode::crushDoom);
Level->CreateCeiling(&Level->sectors[secnum], DCeiling::ceilMoveToValue, NULL, tagnum, platspeed, platspeed, destheight, crush, silent | 4, 0, DCeiling::ECrushMode::crushDoom);
}
}
}
@ -1727,7 +1701,7 @@ void FParser::SF_LightLevel(void)
tagnum = intvalue(t_argv[0]);
// argv is sector tag
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{
@ -1741,7 +1715,7 @@ void FParser::SF_LightLevel(void)
int i = -1;
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
Level->sectors[i].SetLightLevel(intvalue(t_argv[1]));
@ -1768,11 +1742,9 @@ class DLightLevel : public DLighting
unsigned char destlevel;
unsigned char speed;
DLightLevel() = default;
public:
DLightLevel(sector_t * s,int destlevel,int speed);
void Construct(sector_t * s,int destlevel,int speed);
void Serialize(FSerializer &arc);
void Tick ();
void OnDestroy() { Super::OnDestroy(); m_Sector->lightingdata = nullptr; }
@ -1833,8 +1805,9 @@ void DLightLevel::Tick()
//==========================================================================
//
//==========================================================================
DLightLevel::DLightLevel(sector_t * s,int _destlevel,int _speed) : DLighting(s)
void DLightLevel::Construct(sector_t * s,int _destlevel,int _speed)
{
Super::Construct(s);
destlevel=_destlevel;
speed=_speed;
s->lightingdata=this;
@ -1859,10 +1832,10 @@ void FParser::SF_FadeLight(void)
destlevel = intvalue(t_argv[1]);
speed = t_argc>2 ? intvalue(t_argv[2]) : 1;
FSectorTagIterator it(sectag);
auto it = Level->GetSectorTagIterator(sectag);
while ((i = it.Next()) >= 0)
{
if (!Level->sectors[i].lightingdata) Create<DLightLevel>(&Level->sectors[i],destlevel,speed);
if (!Level->sectors[i].lightingdata) Level->CreateThinker<DLightLevel>(&Level->sectors[i],destlevel,speed);
}
}
}
@ -1882,7 +1855,7 @@ void FParser::SF_FloorTexture(void)
tagnum = intvalue(t_argv[0]);
// argv is sector tag
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -1895,7 +1868,7 @@ void FParser::SF_FloorTexture(void)
FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable);
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
Level->sectors[i].SetTexture(sector_t::floor, picnum);
@ -1934,7 +1907,7 @@ void FParser::SF_SectorColormap(void)
tagnum = intvalue(t_argv[0]);
// argv is sector tag
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -1945,7 +1918,7 @@ void FParser::SF_SectorColormap(void)
{
uint32_t cm = R_ColormapNumForName(t_argv[1].value.s);
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
sectors[i].midmap=cm;
@ -1972,7 +1945,7 @@ void FParser::SF_CeilingTexture(void)
tagnum = intvalue(t_argv[0]);
// argv is sector tag
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
@ -1985,7 +1958,7 @@ void FParser::SF_CeilingTexture(void)
FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable);
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
Level->sectors[i].SetTexture(sector_t::ceiling, picnum);
@ -2042,7 +2015,7 @@ void FParser::SF_OpenDoor(void)
if(t_argc > 2) speed = intvalue(t_argv[2]);
else speed = 1; // 1= normal speed
EV_DoDoor(wait_time ? DDoor::doorRaise : DDoor::doorOpen, NULL, NULL, sectag, 2. * clamp(speed, 1, 127), wait_time, 0, 0);
Level->EV_DoDoor(wait_time ? DDoor::doorRaise : DDoor::doorOpen, NULL, NULL, sectag, 2. * clamp(speed, 1, 127), wait_time, 0, 0);
}
}
@ -2067,7 +2040,7 @@ void FParser::SF_CloseDoor(void)
if(t_argc > 1) speed = intvalue(t_argv[1]);
else speed = 1; // 1= normal speed
EV_DoDoor(DDoor::doorClose, NULL, NULL, sectag, 2.*clamp(speed, 1, 127), 0, 0, 0);
Level->EV_DoDoor(DDoor::doorClose, NULL, NULL, sectag, 2.*clamp(speed, 1, 127), 0, 0, 0);
}
}
@ -2097,8 +2070,8 @@ void FParser::SF_LineTrigger()
maplinedef_t mld;
mld.special=intvalue(t_argv[0]);
mld.tag=t_argc > 1 ? intvalue(t_argv[1]) : 0;
P_TranslateLineDef(&line, &mld);
P_ExecuteSpecial(line.special, NULL, Script->trigger, false,
Level->TranslateLineDef(&line, &mld);
P_ExecuteSpecial(Level, line.special, NULL, Script->trigger, false,
line.args[0],line.args[1],line.args[2],line.args[3],line.args[4]);
}
}
@ -2157,7 +2130,7 @@ void FParser::SF_SetLineBlocking(void)
{
blocking=blocks[blocking];
int tag=intvalue(t_argv[0]);
FLineIdIterator itr(tag);
auto itr = Level->GetLineIdIterator(tag);
int i;
while ((i = itr.Next()) >= 0)
{
@ -2180,7 +2153,7 @@ void FParser::SF_SetLineMonsterBlocking(void)
int blocking = intvalue(t_argv[1]) ? (int)ML_BLOCKMONSTERS : 0;
int tag=intvalue(t_argv[0]);
FLineIdIterator itr(tag);
auto itr = Level->GetLineIdIterator(tag);
int i;
while ((i = itr.Next()) >= 0)
{
@ -2237,7 +2210,7 @@ void FParser::SF_SetLineTexture(void)
texture = stringvalue(t_argv[3]);
texturenum = TexMan.GetTextureID(texture, ETextureType::Wall, FTextureManager::TEXMAN_Overridable);
FLineIdIterator itr(tag);
auto itr = Level->GetLineIdIterator(tag);
while ((i = itr.Next()) >= 0)
{
// bad sidedef, Hexen just SEGV'd here!
@ -2257,7 +2230,7 @@ void FParser::SF_SetLineTexture(void)
int sections = intvalue(t_argv[3]);
// set all sectors with tag
FLineIdIterator itr(tag);
auto itr = Level->GetLineIdIterator(tag);
while ((i = itr.Next()) >= 0)
{
side_t *sided = Level->lines[i].sidedef[side];
@ -2447,13 +2420,13 @@ void FParser::SF_PlayerKeys(void)
if(t_argc == 2)
{
t_return.type = svt_int;
t_return.value.i = CheckInventory(players[playernum].mo, keyname);
t_return.value.i = CheckInventory(Level->Players[playernum]->mo, keyname);
return;
}
else
{
givetake = intvalue(t_argv[2]);
ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, keyname.GetIndex(), ScriptUtil::Int, 1, ScriptUtil::End);
ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, keyname.GetIndex(), ScriptUtil::Int, 1, ScriptUtil::End);
t_return.type = svt_int;
t_return.value.i = 0;
}
@ -2532,14 +2505,14 @@ void FParser::SF_PlayerWeapon()
if (t_argc == 2)
{
AActor * wp = players[playernum].mo->FindInventory(ti);
AActor * wp = Level->Players[playernum]->mo->FindInventory(ti);
t_return.type = svt_int;
t_return.value.i = wp!=NULL;
return;
}
else
{
AActor * wp = players[playernum].mo->FindInventory(ti);
AActor * wp = Level->Players[playernum]->mo->FindInventory(ti);
newweapon = !!intvalue(t_argv[2]);
if (!newweapon)
@ -2548,14 +2521,14 @@ void FParser::SF_PlayerWeapon()
{
wp->Destroy();
// If the weapon is active pick a replacement. Legacy didn't do this!
if (players[playernum].PendingWeapon==wp) players[playernum].PendingWeapon=WP_NOCHANGE;
if (players[playernum].ReadyWeapon==wp)
if (Level->Players[playernum]->PendingWeapon==wp) Level->Players[playernum]->PendingWeapon=WP_NOCHANGE;
if (Level->Players[playernum]->ReadyWeapon==wp)
{
players[playernum].ReadyWeapon=nullptr;
Level->Players[playernum]->ReadyWeapon=nullptr;
IFVM(PlayerPawn, PickNewWeapon)
{
VMValue param[] = { players[playernum].mo, (void*)nullptr };
VMValue param[] = { Level->Players[playernum]->mo, (void*)nullptr };
VMCall(func, param, 2, nullptr, 0);
}
}
@ -2565,9 +2538,9 @@ void FParser::SF_PlayerWeapon()
{
if (!wp)
{
auto pw=players[playernum].PendingWeapon;
players[playernum].mo->GiveInventoryType(ti);
players[playernum].PendingWeapon=pw;
auto pw=Level->Players[playernum]->PendingWeapon;
Level->Players[playernum]->mo->GiveInventoryType(ti);
Level->Players[playernum]->PendingWeapon=pw;
}
}
@ -2616,13 +2589,13 @@ void FParser::SF_PlayerSelectedWeapon()
return;
}
players[playernum].PendingWeapon = players[playernum].mo->FindInventory(ti);
Level->Players[playernum]->PendingWeapon = Level->Players[playernum]->mo->FindInventory(ti);
}
t_return.type = svt_int;
for(int i=0;i<9;i++)
{
if (players[playernum].ReadyWeapon->GetClass ()->TypeName == FName(WeaponNames[i]))
if (Level->Players[playernum]->ReadyWeapon->GetClass ()->TypeName == FName(WeaponNames[i]))
{
t_return.value.i=i;
break;
@ -2648,7 +2621,7 @@ void FParser::SF_GiveInventory(void)
if(t_argc == 2) count=1;
else count=intvalue(t_argv[2]);
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
t_return.type = svt_int;
t_return.value.i = 0;
}
@ -2671,7 +2644,7 @@ void FParser::SF_TakeInventory(void)
if(t_argc == 2) count=32767;
else count=intvalue(t_argv[2]);
ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, Level->Players[playernum]->mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End);
t_return.type = svt_int;
t_return.value.i = 0;
}
@ -2696,7 +2669,7 @@ void FParser::SF_CheckInventory(void)
return;
}
t_return.type = svt_int;
t_return.value.i = CheckInventory(players[playernum].mo, stringvalue(t_argv[1]));
t_return.value.i = CheckInventory(Level->Players[playernum]->mo, stringvalue(t_argv[1]));
}
}
@ -2853,7 +2826,7 @@ void FParser::SF_AmbientSound(void)
void FParser::SF_ExitSecret(void)
{
G_SecretExitLevel(0);
Level->SecretExitLevel(0);
}
@ -2928,9 +2901,9 @@ void FParser::SF_SpawnExplosion()
if(t_argc > 3)
pos.Z = floatvalue(t_argv[3]);
else
pos.Z = P_PointInSector(pos)->floorplane.ZatPoint(pos);
pos.Z = Level->PointInSector(pos)->floorplane.ZatPoint(pos);
spawn = Spawn (pclass, pos, ALLOW_REPLACE);
spawn = Spawn (Level, pclass, pos, ALLOW_REPLACE);
t_return.type = svt_int;
t_return.value.i=0;
if (spawn)
@ -3249,10 +3222,10 @@ void FParser::SF_PlayerAddFrag()
{
playernum1 = T_GetPlayerNum(t_argv[0]);
players[playernum1].fragcount++;
Level->Players[playernum1]->fragcount++;
t_return.type = svt_int;
t_return.value.f = players[playernum1].fragcount;
t_return.value.f = Level->Players[playernum1]->fragcount;
}
else
@ -3260,10 +3233,10 @@ void FParser::SF_PlayerAddFrag()
playernum1 = T_GetPlayerNum(t_argv[0]);
playernum2 = T_GetPlayerNum(t_argv[1]);
players[playernum1].frags[playernum2]++;
Level->Players[playernum1]->frags[playernum2]++;
t_return.type = svt_int;
t_return.value.f = players[playernum1].frags[playernum2];
t_return.value.f = Level->Players[playernum1]->frags[playernum2];
}
}
}
@ -3642,10 +3615,10 @@ void FParser::SF_ThingCount(void)
pClass=T_GetMobjType(t_argv[0]);
if (!pClass) return;
// If we want to count map items we must consider actor replacement
pClass = pClass->GetReplacement();
pClass = pClass->GetReplacement(Level);
again:
TThinkerIterator<AActor> it;
again:
auto it = Level->GetThinkerIterator<AActor>();
if (t_argc<2 || intvalue(t_argv[1])==0 || pClass->IsDescendantOf(NAME_Inventory))
{
@ -3671,7 +3644,7 @@ again:
{
// Again, with decorate replacements
replacemented = true;
PClassActor *newkind = pClass->GetReplacement();
PClassActor *newkind = pClass->GetReplacement(Level);
if (newkind != pClass)
{
pClass = newkind;
@ -3700,7 +3673,7 @@ void FParser::SF_SetColor(void)
{
tagnum = intvalue(t_argv[0]);
secnum = T_FindFirstSectorFromTag(tagnum);
secnum = Level->FindFirstSectorFromTag(tagnum);
if(secnum < 0)
{
@ -3721,7 +3694,7 @@ void FParser::SF_SetColor(void)
else return;
// set all sectors with tag
FSSectorTagIterator itr(tagnum);
auto itr = Level->GetSectorTagIterator(tagnum);
while ((i = itr.Next()) >= 0)
{
Level->sectors[i].SetColor(color, 0);
@ -3761,7 +3734,7 @@ void FParser::SF_SpawnShot2(void)
t_return.type = svt_mobj;
AActor *mo = Spawn(pclass, source->PosPlusZ(z), ALLOW_REPLACE);
AActor *mo = Spawn(Level, pclass, source->PosPlusZ(z), ALLOW_REPLACE);
if (mo)
{
S_Sound(mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM);
@ -3786,13 +3759,13 @@ void FParser::SF_KillInSector()
{
if (CheckArgs(1))
{
TThinkerIterator<AActor> it;
auto it = Level->GetThinkerIterator<AActor>();
AActor * mo;
int tag=intvalue(t_argv[0]);
while ((mo=it.Next()))
{
if (mo->flags3&MF3_ISMONSTER && tagManager.SectorHasTag(mo->Sector, tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
if (mo->flags3&MF3_ISMONSTER && Level->SectorHasTag(mo->Sector, tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
}
}
}
@ -3814,7 +3787,7 @@ void FParser::SF_SetLineTrigger()
id=intvalue(t_argv[0]);
spec=intvalue(t_argv[1]);
if (t_argc>2) tag=intvalue(t_argv[2]);
FLineIdIterator itr(id);
auto itr = Level->GetLineIdIterator(id);
while ((i = itr.Next()) >= 0)
{
maplinedef_t mld;
@ -3822,7 +3795,7 @@ void FParser::SF_SetLineTrigger()
mld.tag = tag;
mld.flags = 0;
int f = Level->lines[i].flags;
P_TranslateLineDef(&Level->lines[i], &mld);
Level->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));
@ -3848,7 +3821,7 @@ void FParser::RunLineSpecial(const FLineSpecial *spec)
if (t_argc>i) args[i]=intvalue(t_argv[i]);
else args[i] = 0;
}
t_return.value.i = P_ExecuteSpecial(spec->number, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
t_return.value.i = P_ExecuteSpecial(Level, spec->number, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
}
}

View file

@ -143,8 +143,8 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
sc.MustGetStringName("=");
sc.MustGetString();
sky2texture = sky1texture = Level->skytexture1 = Level->skytexture2 = TexMan.GetTextureID (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst);
R_InitSkyMap ();
Level->skytexture1 = Level->skytexture2 = TexMan.GetTextureID (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst);
InitSkyMap (Level);
}
else if (sc.Compare("interpic"))
{
@ -262,7 +262,7 @@ bool FScriptLoader::ParseInfo(MapData * map)
I_Error("Only one FraggleThinker is allowed to exist at a time.\nCheck your code.");
}
auto th = Create<DFraggleThinker>();
auto th = Level->CreateThinker<DFraggleThinker>();
th->LevelScript->data = copystring(scriptsrc.GetChars());
Level->FraggleScriptThinker = th;
@ -294,9 +294,9 @@ void T_LoadScripts(FLevelLocals *Level, MapData *map)
// the default translator is being used.
// Custom translators will not be patched.
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && Level->info->Translator.IsEmpty() &&
Level->maptype == MAPTYPE_DOOM && SimpleLineTranslations.Size() > 272 && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
Level->maptype == MAPTYPE_DOOM && Level->Translator->SimpleLineTranslations.Size() > 272 && Level->Translator->SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
{
std::swap(SimpleLineTranslations[270], SimpleLineTranslations[272]);
std::swap(Level->Translator->SimpleLineTranslations[270], Level->Translator->SimpleLineTranslations[272]);
}
}

View file

@ -31,6 +31,7 @@
/* includes ************************/
#include "t_script.h"
#include "g_levellocals.h"
#define evaluate_leftnright(a, b, c) {\
@ -84,7 +85,7 @@ void FParser::OPequals(svalue_t &result, int start, int n, int stop)
{
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
var = Script->FindVariable(Tokens[start], Level->FraggleScriptThinker->GlobalScript);
if(var)
{
@ -478,7 +479,7 @@ void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
{
DFsVariable *var;
var = Script->FindVariable(Tokens[stop]);
var = Script->FindVariable(Tokens[stop], Level->FraggleScriptThinker->GlobalScript);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[stop]);
@ -503,7 +504,7 @@ void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
svalue_t newvalue;
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
var = Script->FindVariable(Tokens[start], Level->FraggleScriptThinker->GlobalScript);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[start]);
@ -541,7 +542,7 @@ void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
{
DFsVariable *var;
var = Script->FindVariable(Tokens[stop]);
var = Script->FindVariable(Tokens[stop], Level->FraggleScriptThinker->GlobalScript);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[stop]);
@ -567,7 +568,7 @@ void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
svalue_t newvalue;
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
var = Script->FindVariable(Tokens[start], Level->FraggleScriptThinker->GlobalScript);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[start]);

View file

@ -34,7 +34,7 @@
#include <stdarg.h>
#include "t_script.h"
#include "v_text.h"
#include "g_levellocals.h"
CVAR(Bool, script_debug, false, 0)
@ -561,7 +561,7 @@ void FParser::SimpleEvaluate(svalue_t &returnvar, int n)
break;
case name_:
var = Script->FindVariable(Tokens[n]);
var = Script->FindVariable(Tokens[n], Level->FraggleScriptThinker->GlobalScript);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[n]);

View file

@ -333,13 +333,13 @@ char *DFsScript::ProcessFindChar(char *datap, char find)
//
//==========================================================================
void DFsScript::DryRunScript()
void DFsScript::DryRunScript(FLevelLocals *Level)
{
char *end = data + len;
char *rover = data;
// allocate space for the tokens
FParser parse(&level, this);
FParser parse(Level, this);
try
{
while(rover < end && *rover)
@ -387,11 +387,11 @@ void DFsScript::DryRunScript()
//
//==========================================================================
void DFsScript::Preprocess()
void DFsScript::Preprocess(FLevelLocals *Level)
{
len = (int)strlen(data);
ProcessFindChar(data, 0); // fill in everything
DryRunScript();
DryRunScript(Level);
}
//==========================================================================
@ -406,7 +406,7 @@ void DFsScript::Preprocess()
//
//==========================================================================
void DFsScript::ParseInclude(char *lumpname)
void DFsScript::ParseInclude(FLevelLocals *Level, char *lumpname)
{
int lumpnum;
char *lump;
@ -429,7 +429,7 @@ void DFsScript::ParseInclude(char *lumpname)
ProcessFindChar(lump, 0);
// now parse the lump
FParser parse(&level, this);
FParser parse(Level, this);
parse.Run(lump, lump, lump+lumplen);
// free the lump

View file

@ -176,8 +176,6 @@ void DFsScript::OnDestroy()
void DFsScript::Serialize(FSerializer &arc)
{
Super::Serialize(arc);
// don't save a reference to the global script, which contains unserializable data.
if (parent == level.FraggleScriptThinker->GlobalScript) parent = nullptr;
arc("data", data)
("scriptnum", scriptnum)
@ -188,8 +186,6 @@ void DFsScript::Serialize(FSerializer &arc)
.Array("sections", sections, SECTIONSLOTS)
.Array("variables", variables, VARIABLESLOTS)
.Array("children", children, MAXSCRIPTS);
if (parent == nullptr) parent = level.FraggleScriptThinker->GlobalScript;
}
//==========================================================================
@ -200,7 +196,7 @@ void DFsScript::Serialize(FSerializer &arc)
//
//==========================================================================
void DFsScript::ParseScript(char *position)
void DFsScript::ParseScript(char *position, DFraggleThinker *th)
{
if (position == nullptr)
{
@ -215,11 +211,11 @@ void DFsScript::ParseScript(char *position)
return;
}
level.FraggleScriptThinker->trigger_obj = trigger; // set trigger
th->trigger_obj = trigger; // set trigger variable.
try
{
FParser parse(&level, this);
FParser parse(th->Level, this);
parse.Run(position, data, data + len);
}
catch (CFraggleScriptError &err)
@ -361,24 +357,18 @@ IMPLEMENT_POINTERS_END
//==========================================================================
//
// This thinker is a little unusual from all the rest, because it
// needs to construct some non-serializable data.
//
// This cannot be done in Construct, but requires an actual constructor,
// so that even a deserialized ionstance is fully set up.
//
//==========================================================================
DFraggleThinker::DFraggleThinker()
: DThinker(STAT_SCRIPTS)
{
GlobalScript = Create<DFsScript>();
GC::WriteBarrier(this, GlobalScript);
// do not create resources which will be filled in by the serializer if being called from there.
if (!bSerialOverride)
{
RunningScripts = Create<DRunningScript>();
GC::WriteBarrier(this, RunningScripts);
LevelScript = Create<DFsScript>();
LevelScript->parent = GlobalScript;
GC::WriteBarrier(this, LevelScript);
}
InitFunctions();
}
@ -388,6 +378,21 @@ DFraggleThinker::DFraggleThinker()
//
//==========================================================================
void DFraggleThinker::Construct()
{
RunningScripts = Create<DRunningScript>();
GC::WriteBarrier(this, RunningScripts);
LevelScript = Create<DFsScript>();
LevelScript->parent = nullptr;
GC::WriteBarrier(this, LevelScript);
}
//==========================================================================
//
//
//
//==========================================================================
void DFraggleThinker::OnDestroy()
{
DRunningScript *p = RunningScripts;
@ -456,10 +461,10 @@ bool DFraggleThinker::wait_finished(DRunningScript *script)
case wt_tagwait:
{
int secnum;
FSectorTagIterator itr(script->wait_data);
auto itr = Level->GetSectorTagIterator(script->wait_data);
while ((secnum = itr.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
sector_t *sec = &Level->sectors[secnum];
if(sec->floordata || sec->ceilingdata || sec->lightingdata)
return false; // not finished
}
@ -523,7 +528,7 @@ void DFraggleThinker::Tick()
next = current->next; // save before freeing
// continue the script
current->script->ParseScript (current->script->data + current->save_point);
current->script->ParseScript (current->script->data + current->save_point, this);
// free
current->Destroy();
@ -611,10 +616,10 @@ void T_PreprocessScripts(FLevelLocals *Level)
// get the other scripts
// levelscript started by player 0 'superplayer'
th->LevelScript->trigger = players[0].mo;
th->LevelScript->trigger = Level->Players[0]->mo;
th->LevelScript->Preprocess();
th->LevelScript->ParseScript();
th->LevelScript->Preprocess(Level);
th->LevelScript->ParseScript(nullptr, th);
}
}
@ -662,6 +667,6 @@ CCMD(fpuke)
}
else
{
T_RunScript(&level, atoi(argv[1]), players[consoleplayer].mo);
T_RunScript(players[consoleplayer].mo->Level, atoi(argv[1]), players[consoleplayer].mo);
}
}

View file

@ -35,6 +35,8 @@
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class DFraggleThinker;
class CFraggleScriptError : public CDoomError
{
@ -341,7 +343,7 @@ public:
void NewFunction(const char *name, void (FParser::*handler)());
DFsVariable *VariableForName(const char *name);
DFsVariable *FindVariable(const char *name);
DFsVariable *FindVariable(const char *name, DFsScript *global);
void ClearVariables(bool complete= false);
DFsVariable *NewLabel(char *labelptr);
char *LabelValue(const svalue_t &v);
@ -360,10 +362,10 @@ public:
DFsSection *FindSectionStart(const char *brace);
DFsSection *FindSectionEnd(const char *brace);
char *ProcessFindChar(char *data, char find);
void DryRunScript();
void Preprocess();
void ParseInclude(char *lumpname);
void ParseScript(char *rover = NULL);
void DryRunScript(FLevelLocals *Level);
void Preprocess(FLevelLocals *Level);
void ParseInclude(FLevelLocals *Level, char *lumpname);
void ParseScript(char *rover, DFraggleThinker *th);
void ParseData(char *rover, char *data, char *end);
};
@ -688,7 +690,7 @@ class DFraggleThinker : public DThinker
DECLARE_CLASS(DFraggleThinker, DThinker)
HAS_OBJECT_POINTERS
public:
static const int DEFAULT_STAT = STAT_SCRIPTS;
int zoom = 1;
AActor *trigger_obj; // this is a transient pointer not being subjected to GC.
TObjPtr<DFsScript*> GlobalScript;
@ -696,7 +698,8 @@ public:
TObjPtr<DRunningScript*> RunningScripts;
TArray<TObjPtr<AActor*> > SpawnedThings;
DFraggleThinker();
DFraggleThinker(); // This class needs a real constructor because it has non-serializable content.
void Construct();
void OnDestroy() override;

View file

@ -429,7 +429,7 @@ void FParser::spec_script()
newscript->parent = Script; // remember parent
// preprocess the newscript now
newscript->Preprocess();
newscript->Preprocess(Level);
// we dont want to run the newscript, only add it
// jump past the newscript in parsing

View file

@ -364,7 +364,7 @@ DFsVariable *DFsScript::VariableForName(const char *name)
//
//==========================================================================
DFsVariable *DFsScript::FindVariable(const char *name)
DFsVariable *DFsScript::FindVariable(const char *name, DFsScript *GlobalScript)
{
DFsVariable *var;
DFsScript *current = this;
@ -374,7 +374,13 @@ DFsVariable *DFsScript::FindVariable(const char *name)
// check this script
if ((var = current->VariableForName(name)))
return var;
current = current->parent; // try the parent of this one
// Since the global script cannot be serialized, we cannot store a pointer to it, because this cannot be safely restored during deserialization.
// To compensate we need to check the relationship explicitly here.
if (current->parent == nullptr && current != GlobalScript)
current = GlobalScript;
else
current = current->parent; // try the parent of this one
}
return NULL; // no variable

111
src/g_cvars.cpp Normal file
View file

@ -0,0 +1,111 @@
/*
** g_cvars.cpp
** collects all the CVARs that were scattered all across the code before
**
**---------------------------------------------------------------------------
** Copyright 1998-2016 Randy Heit
** Copyright 2003-2018 Christoph 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_cvars.h"
#include "g_levellocals.h"
#include "g_game.h"
CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE)
CVAR(Bool, var_pushers, true, CVAR_SERVERINFO);
CVAR(Bool, gl_cachenodes, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Float, gl_cachetime, 0.6f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Bool, gl_lights, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
for (auto Level : AllLevels())
{
if (self) Level->RecreateAllAttachedLights();
else Level->DeleteAllAttachedLights();
}
}
CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
if (self > 0)
{
for (auto Level : AllLevels())
{
auto &corpsequeue = Level->CorpseQueue;
while (corpsequeue.Size() > (unsigned)self)
{
AActor *corpse = corpsequeue[0];
if (corpse) corpse->Destroy();
corpsequeue.Delete(0);
}
}
}
}
CUSTOM_CVAR (Int, cl_maxdecals, 1024, CVAR_ARCHIVE)
{
if (self < 0)
{
self = 0;
}
else for (auto Level : AllLevels())
{
while (Level->ImpactDecalCount > self)
{
DThinker *thinker = Level->FirstThinker(STAT_AUTODECAL);
if (thinker != NULL)
{
thinker->Destroy();
}
}
}
}
// [BC] Allow the maximum number of particles to be specified by a cvar (so people
// with lots of nice hardware can have lots of particles!).
CUSTOM_CVAR(Int, r_maxparticles, 4000, CVAR_ARCHIVE)
{
if (self == 0)
self = 4000;
else if (self > 65535)
self = 65535;
else if (self < 100)
self = 100;
if (gamestate != GS_STARTUP)
{
for (auto Level : AllLevels())
{
P_InitParticles(Level);
}
}
}

9
src/g_cvars.h Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#include "c_cvars.h"
EXTERN_CVAR(Bool, r_dynlights)
EXTERN_CVAR(Bool, gl_lights)

351
src/g_dumpinfo.cpp Normal file
View file

@ -0,0 +1,351 @@
/*
** g_dumpinfo.cpp
** diagnostic CCMDs that output info about the current game
**
**---------------------------------------------------------------------------
** Copyright 1998-2016 Randy Heit
** Copyright 2003-2018 Christoph 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 "g_levellocals.h"
#include "a_dynlight.h"
#include "a_sharedglobal.h"
#include "d_net.h"
#include "p_setup.h"
#include "w_wad.h"
#include "v_text.h"
#include "c_functions.h"
//==========================================================================
//
// CCMDs
//
//==========================================================================
CCMD(listlights)
{
int walls, sectors;
int allwalls=0, allsectors=0, allsubsecs = 0;
int i=0, shadowcount = 0;
FDynamicLight * dl;
for (auto Level : AllLevels())
{
Printf("Lights for %s\n", Level->MapName.GetChars());
for (dl = Level->lights; dl; dl = dl->next)
{
walls=0;
sectors=0;
Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s %s",
dl->target->GetClass()->TypeName.GetChars(),
dl->X(), dl->Y(), dl->Z(), dl->GetRed(), dl->GetGreen(), dl->GetBlue(),
dl->radius, dl->IsAttenuated()? "attenuated" : "", dl->shadowmapped? "shadowmapped" : "");
i++;
shadowcount += dl->shadowmapped;
if (dl->target)
{
FTextureID spr = sprites[dl->target->sprite].GetSpriteFrame(dl->target->frame, 0, 0., nullptr);
Printf(", frame = %s ", TexMan.GetTexture(spr)->GetName().GetChars());
}
FLightNode * node;
node=dl->touching_sides;
while (node)
{
walls++;
allwalls++;
node = node->nextTarget;
}
node = dl->touching_sector;
while (node)
{
allsectors++;
sectors++;
node = node->nextTarget;
}
Printf("- %d walls, %d sectors\n", walls, sectors);
}
Printf("%i dynamic lights, %d shadowmapped, %d walls, %d sectors\n\n\n", i, shadowcount, allwalls, allsectors);
}
}
CCMD (countdecals)
{
for (auto Level : AllLevels())
{
auto iterator = Level->GetThinkerIterator<DImpactDecal>(NAME_None, STAT_AUTODECAL);
int count = 0;
while (iterator.Next())
count++;
Printf("%s: Counted %d impact decals\n", Level->MapName.GetChars(), count);
}
}
CCMD (spray)
{
if (who == NULL || argv.argc() < 2)
{
Printf ("Usage: spray <decal>\n");
return;
}
Net_WriteByte (DEM_SPRAY);
Net_WriteString (argv[1]);
}
//==========================================================================
//
// CCMD mapchecksum
//
//==========================================================================
CCMD (mapchecksum)
{
MapData *map;
uint8_t cksum[16];
if (argv.argc() < 2)
{
Printf("Usage: mapchecksum <map> ...\n");
}
for (int i = 1; i < argv.argc(); ++i)
{
map = P_OpenMapData(argv[i], true);
if (map == NULL)
{
Printf("Cannot load %s as a map\n", argv[i]);
}
else
{
map->GetChecksum(cksum);
const char *wadname = Wads.GetWadName(Wads.GetLumpFile(map->lumpnum));
delete map;
for (size_t j = 0; j < sizeof(cksum); ++j)
{
Printf("%02X", cksum[j]);
}
Printf(" // %s %s\n", wadname, argv[i]);
}
}
}
//==========================================================================
//
// CCMD hiddencompatflags
//
//==========================================================================
CCMD (hiddencompatflags)
{
for(auto Level : AllLevels())
{
Printf("%s: %08x %08x %08x\n", Level->MapName.GetChars(), Level->ii_compatflags, Level->ii_compatflags2, Level->ib_compatflags);
}
}
CCMD(dumpportals)
{
for (auto Level : AllLevels())
{
Printf("Portal groups for %s\n", Level->MapName.GetChars());
for (unsigned i = 0; i < Level->portalGroups.Size(); i++)
{
auto p = Level->portalGroups[i];
double xdisp = p->mDisplacement.X;
double ydisp = p->mDisplacement.Y;
Printf(PRINT_LOG, "Portal #%d, %s, displacement = (%f,%f)\n", i, p->plane == 0 ? "floor" : "ceiling",
xdisp, ydisp);
Printf(PRINT_LOG, "Coverage:\n");
for (auto &sub : Level->subsectors)
{
auto port = sub.render_sector->GetPortalGroup(p->plane);
if (port == p)
{
Printf(PRINT_LOG, "\tSubsector %d (%d):\n\t\t", sub.Index(), sub.render_sector->sectornum);
for (unsigned k = 0; k < sub.numlines; k++)
{
Printf(PRINT_LOG, "(%.3f,%.3f), ", sub.firstline[k].v1->fX() + xdisp, sub.firstline[k].v1->fY() + ydisp);
}
Printf(PRINT_LOG, "\n\t\tCovered by subsectors:\n");
FPortalCoverage *cov = &sub.portalcoverage[p->plane];
for (int l = 0; l < cov->sscount; l++)
{
subsector_t *csub = &Level->subsectors[cov->subsectors[l]];
Printf(PRINT_LOG, "\t\t\t%5d (%4d): ", cov->subsectors[l], csub->render_sector->sectornum);
for (unsigned m = 0; m < csub->numlines; m++)
{
Printf(PRINT_LOG, "(%.3f,%.3f), ", csub->firstline[m].v1->fX(), csub->firstline[m].v1->fY());
}
Printf(PRINT_LOG, "\n");
}
}
}
}
}
}
ADD_STAT (interpolations)
{
FString out;
for (auto Level : AllLevels())
{
if (out.Len() > 0) out << '\n';
out.AppendFormat("%s: %d interpolations", Level->MapName.GetChars(), Level->interpolator.CountInterpolations ());
}
return out;
}
CCMD(printsections)
{
void PrintSections(FLevelLocals *Level);
for (auto Level : AllLevels())
{
PrintSections(Level);
}
}
CCMD(dumptags)
{
for (auto Level : AllLevels())
{
Level->tagManager.DumpTags();
}
}
CCMD(dump3df)
{
if (argv.argc() > 1)
{
// Print 3D floor info for a single sector.
// This only checks the primary level.
int sec = (int)strtoll(argv[1], NULL, 10);
if ((unsigned)sec >= primaryLevel->sectors.Size())
{
Printf("Sector %d does not exist.\n", sec);
return;
}
sector_t *sector = &primaryLevel->sectors[sec];
TArray<F3DFloor*> & ffloors = sector->e->XFloor.ffloors;
for (unsigned int i = 0; i < ffloors.Size(); i++)
{
double height = ffloors[i]->top.plane->ZatPoint(sector->centerspot);
double bheight = ffloors[i]->bottom.plane->ZatPoint(sector->centerspot);
IGNORE_FORMAT_PRE
Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n",
i, height, ffloors[i]->top.model->sectornum,
bheight, ffloors[i]->bottom.model->sectornum,
ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS) ? "Exists" : "", (ffloors[i]->flags&FF_DYNAMIC) ? "Dynamic" : "");
IGNORE_FORMAT_POST
}
}
}
//============================================================================
//
// print the group link table to the console
//
//============================================================================
CCMD(dumplinktable)
{
for (auto Level : AllLevels())
{
Printf("Portal displacements for %s:\n", Level->MapName.GetChars());
for (int x = 1; x < Level->Displacements.size; x++)
{
for (int y = 1; y < Level->Displacements.size; y++)
{
FDisplacement &disp = Level->Displacements(x, y);
Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, int(disp.pos.X), int(disp.pos.Y));
}
Printf("\n");
}
}
}
//===========================================================================
//
// CCMD printinv
//
// Prints the console player's current inventory.
//
//===========================================================================
CCMD(printinv)
{
int pnum = consoleplayer;
#ifdef _DEBUG
// Only allow peeking on other players' inventory in debug builds.
if (argv.argc() > 1)
{
pnum = atoi(argv[1]);
if (pnum < 0 || pnum >= MAXPLAYERS)
{
return;
}
}
#endif
C_PrintInv(players[pnum].mo);
}
CCMD(targetinv)
{
FTranslatedLineTarget t;
if (CheckCheatmode() || players[consoleplayer].mo == NULL)
return;
C_AimLine(&t, true);
if (t.linetarget)
{
C_PrintInv(t.linetarget);
}
else Printf("No target found. Targetinv cannot find actors that have "
"the NOBLOCKMAP flag or have height/radius of 0.\n");
}

View file

@ -72,6 +72,8 @@
#include "vm.h"
#include "dobjgc.h"
#include "gi.h"
#include "a_dynlight.h"
#include "i_system.h"
#include "g_hub.h"
#include "g_levellocals.h"
@ -218,6 +220,8 @@ bool SendLand;
const AActor *SendItemUse, *SendItemDrop;
int SendItemDropAmount;
extern uint8_t globalfreeze;
EXTERN_CVAR (Int, team)
CVAR (Bool, teamplay, false, CVAR_SERVERINFO)
@ -769,7 +773,7 @@ void G_AddViewPitch (int look, bool mouse)
return;
}
look = LookAdjust(look);
if (!level.IsFreelookAllowed())
if (!primaryLevel->IsFreelookAllowed())
{
LocalViewPitch = 0;
}
@ -955,7 +959,7 @@ bool G_Responder (event_t *ev)
{
if (ST_Responder (ev))
return true; // status window ate it
if (!viewactive && AM_Responder (ev, false))
if (!viewactive && primaryLevel->automap->Responder (ev, false))
return true; // automap ate it
}
else if (gamestate == GS_FINALE)
@ -986,7 +990,7 @@ bool G_Responder (event_t *ev)
// the events *last* so that any bound keys get precedence.
if (gamestate == GS_LEVEL && viewactive)
return AM_Responder (ev, true);
return primaryLevel->automap->Responder (ev, true);
return (ev->type == EV_KeyDown ||
ev->type == EV_Mouse);
@ -1014,7 +1018,7 @@ void G_Ticker ()
}
if (players[i].playerstate == PST_REBORN || players[i].playerstate == PST_ENTER)
{
G_DoReborn(i, false);
primaryLevel->DoReborn(i, false);
}
}
}
@ -1036,9 +1040,6 @@ void G_Ticker ()
}
switch (gameaction)
{
case ga_loadlevel:
G_DoLoadLevel (-1, false, false);
break;
case ga_recordgame:
G_CheckDemoStatus();
G_RecordDemo(newdemoname);
@ -1090,6 +1091,7 @@ void G_Ticker ()
AM_ToggleMap ();
gameaction = ga_nothing;
break;
default:
case ga_nothing:
break;
}
@ -1112,7 +1114,7 @@ void G_Ticker ()
uint32_t rngsum = FRandom::StaticSumSeeds ();
//Added by MC: For some of that bot stuff. The main bot function.
bglobal.Main ();
primaryLevel->BotInfo.Main (primaryLevel);
for (i = 0; i < MAXPLAYERS; i++)
{
@ -1171,7 +1173,7 @@ void G_Ticker ()
}
// [ZZ] also tick the UI part of the events
E_UiTick();
primaryLevel->localEventManager->UiTick();
C_RunDelayedCommands();
// do main actions
@ -1179,7 +1181,7 @@ void G_Ticker ()
{
case GS_LEVEL:
P_Ticker ();
AM_Ticker ();
primaryLevel->automap->Ticker ();
break;
case GS_TITLELEVEL:
@ -1211,7 +1213,7 @@ void G_Ticker ()
}
// [MK] Additional ticker for UI events right after all others
E_PostUiTick();
primaryLevel->localEventManager->PostUiTick();
}
@ -1241,7 +1243,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags)
// Called after a player dies
// almost everything is cleared and initialized
//
void G_PlayerReborn (int player)
void FLevelLocals::PlayerReborn (int player)
{
player_t* p;
int frags[MAXPLAYERS];
@ -1325,7 +1327,7 @@ void G_PlayerReborn (int player)
// because something is occupying it
//
bool G_CheckSpot (int playernum, FPlayerStart *mthing)
bool FLevelLocals::CheckSpot (int playernum, FPlayerStart *mthing)
{
DVector3 spot;
double oldz;
@ -1335,11 +1337,11 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing)
spot = mthing->pos;
if (!(level.flags & LEVEL_USEPLAYERSTARTZ))
if (!(flags & LEVEL_USEPLAYERSTARTZ))
{
spot.Z = 0;
}
spot.Z += P_PointInSector (spot)->floorplane.ZatPoint (spot);
spot.Z += PointInSector (spot)->floorplane.ZatPoint (spot);
if (!players[playernum].mo)
{ // first spawn of level, before corpses
@ -1377,7 +1379,7 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing)
//
// [RH] Returns the distance of the closest player to the given mapthing
static double PlayersRangeFromSpot (FPlayerStart *spot)
double FLevelLocals::PlayersRangeFromSpot (FPlayerStart *spot)
{
double closest = INT_MAX;
double distance;
@ -1398,7 +1400,7 @@ static double PlayersRangeFromSpot (FPlayerStart *spot)
}
// [RH] Select the deathmatch spawn spot farthest from everyone.
static FPlayerStart *SelectFarthestDeathmatchSpot (size_t selections)
FPlayerStart *FLevelLocals::SelectFarthestDeathmatchSpot (size_t selections)
{
double bestdistance = 0;
FPlayerStart *bestspot = NULL;
@ -1406,12 +1408,12 @@ static FPlayerStart *SelectFarthestDeathmatchSpot (size_t selections)
for (i = 0; i < selections; i++)
{
double distance = PlayersRangeFromSpot (&level.deathmatchstarts[i]);
double distance = PlayersRangeFromSpot (&deathmatchstarts[i]);
if (distance > bestdistance)
{
bestdistance = distance;
bestspot = &level.deathmatchstarts[i];
bestspot = &deathmatchstarts[i];
}
}
@ -1419,27 +1421,27 @@ static FPlayerStart *SelectFarthestDeathmatchSpot (size_t selections)
}
// [RH] Select a deathmatch spawn spot at random (original mechanism)
static FPlayerStart *SelectRandomDeathmatchSpot (int playernum, unsigned int selections)
FPlayerStart *FLevelLocals::SelectRandomDeathmatchSpot (int playernum, unsigned int selections)
{
unsigned int i, j;
for (j = 0; j < 20; j++)
{
i = pr_dmspawn() % selections;
if (G_CheckSpot (playernum, &level.deathmatchstarts[i]) )
if (CheckSpot (playernum, &deathmatchstarts[i]) )
{
return &level.deathmatchstarts[i];
return &deathmatchstarts[i];
}
}
// [RH] return a spot anyway, since we allow telefragging when a player spawns
return &level.deathmatchstarts[i];
return &deathmatchstarts[i];
}
DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart)
DEFINE_ACTION_FUNCTION(FLevelLocals, PickDeathmatchStart)
{
PARAM_PROLOGUE;
unsigned int selections = level.deathmatchstarts.Size();
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
unsigned int selections = self->deathmatchstarts.Size();
DVector3 pos;
int angle;
if (selections == 0)
@ -1450,8 +1452,8 @@ DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart)
else
{
unsigned int i = pr_dmspawn() % selections;
angle = level.deathmatchstarts[i].angle;
pos = level.deathmatchstarts[i].pos;
angle = self->deathmatchstarts[i].angle;
pos = self->deathmatchstarts[i].pos;
}
if (numret > 1)
@ -1466,12 +1468,12 @@ DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart)
return numret;
}
void G_DeathMatchSpawnPlayer (int playernum)
void FLevelLocals::DeathMatchSpawnPlayer (int playernum)
{
unsigned int selections;
FPlayerStart *spot;
selections = level.deathmatchstarts.Size ();
selections = deathmatchstarts.Size ();
// [RH] We can get by with just 1 deathmatch start
if (selections < 1)
I_Error ("No deathmatch starts");
@ -1488,22 +1490,22 @@ void G_DeathMatchSpawnPlayer (int playernum)
{ // No good spot, so the player will probably get stuck.
// We were probably using select farthest above, and all
// the spots were taken.
spot = G_PickPlayerStart(playernum, PPS_FORCERANDOM);
if (!G_CheckSpot(playernum, spot))
spot = PickPlayerStart(playernum, PPS_FORCERANDOM);
if (!CheckSpot(playernum, spot))
{ // This map doesn't have enough coop spots for this player
// to use one.
spot = SelectRandomDeathmatchSpot(playernum, selections);
if (spot == NULL)
{ // We have a player 1 start, right?
spot = &level.playerstarts[0];
spot = &playerstarts[0];
if (spot->type == 0)
{ // Fine, whatever.
spot = &level.deathmatchstarts[0];
spot = &deathmatchstarts[0];
}
}
}
}
AActor *mo = P_SpawnPlayer(spot, playernum);
AActor *mo = SpawnPlayer(spot, playernum);
if (mo != NULL) P_PlayerStartStomp(mo);
}
@ -1511,15 +1513,15 @@ void G_DeathMatchSpawnPlayer (int playernum)
//
// G_PickPlayerStart
//
FPlayerStart *G_PickPlayerStart(int playernum, int flags)
FPlayerStart *FLevelLocals::PickPlayerStart(int playernum, int flags)
{
if (level.AllPlayerStarts.Size() == 0) // No starts to pick
if (AllPlayerStarts.Size() == 0) // No starts to pick
{
return NULL;
}
if ((level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) || (flags & PPS_FORCERANDOM) ||
level.playerstarts[playernum].type == 0)
if ((flags2 & LEVEL2_RANDOMPLAYERSTARTS) || (flags & PPS_FORCERANDOM) ||
playerstarts[playernum].type == 0)
{
if (!(flags & PPS_NOBLOCKINGCHECK))
{
@ -1527,11 +1529,11 @@ FPlayerStart *G_PickPlayerStart(int playernum, int flags)
unsigned int i;
// Find all unblocked player starts.
for (i = 0; i < level.AllPlayerStarts.Size(); ++i)
for (i = 0; i < AllPlayerStarts.Size(); ++i)
{
if (G_CheckSpot(playernum, &level.AllPlayerStarts[i]))
if (CheckSpot(playernum, &AllPlayerStarts[i]))
{
good_starts.Push(&level.AllPlayerStarts[i]);
good_starts.Push(&AllPlayerStarts[i]);
}
}
if (good_starts.Size() > 0)
@ -1540,17 +1542,17 @@ FPlayerStart *G_PickPlayerStart(int playernum, int flags)
}
}
// Pick a spot at random, whether it's open or not.
return &level.AllPlayerStarts[pr_pspawn(level.AllPlayerStarts.Size())];
return &AllPlayerStarts[pr_pspawn(AllPlayerStarts.Size())];
}
return &level.playerstarts[playernum];
return &playerstarts[playernum];
}
DEFINE_ACTION_FUNCTION(DObject, G_PickPlayerStart)
DEFINE_ACTION_FUNCTION(FLevelLocals, PickPlayerStart)
{
PARAM_PROLOGUE;
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_INT(playernum);
PARAM_INT(flags);
auto ps = G_PickPlayerStart(playernum, flags);
auto ps = self->PickPlayerStart(playernum, flags);
if (numret > 1)
{
ret[1].SetInt(ps? ps->angle : 0);
@ -1566,23 +1568,24 @@ DEFINE_ACTION_FUNCTION(DObject, G_PickPlayerStart)
//
// G_QueueBody
//
static void G_QueueBody (AActor *body)
void FLevelLocals::QueueBody (AActor *body)
{
// flush an old corpse if needed
int modslot = level.bodyqueslot%level.BODYQUESIZE;
level.bodyqueslot = modslot + 1;
int modslot = bodyqueslot % BODYQUESIZE;
bodyqueslot = modslot + 1;
if (level.bodyqueslot >= level.BODYQUESIZE && level.bodyque[modslot] != NULL)
if (bodyqueslot >= BODYQUESIZE && bodyque[modslot] != NULL)
{
level.bodyque[modslot]->Destroy ();
bodyque[modslot]->Destroy ();
}
level.bodyque[modslot] = body;
bodyque[modslot] = body;
// Copy the player's translation, so that if they change their color later, only
// their current body will change and not all their old corpses.
if (GetTranslationType(body->Translation) == TRANSLATION_Players ||
GetTranslationType(body->Translation) == TRANSLATION_PlayersExtra)
{
// This needs to be able to handle multiple levels, in case a level with dead players is used as a secondary one later.
*translationtables[TRANSLATION_PlayerCorpses][modslot] = *TranslationToTable(body->Translation);
body->Translation = TRANSLATION(TRANSLATION_PlayerCorpses,modslot);
translationtables[TRANSLATION_PlayerCorpses][modslot]->UpdateNative();
@ -1606,9 +1609,9 @@ static void G_QueueBody (AActor *body)
// G_DoReborn
//
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
void G_DoReborn (int playernum, bool freshbot)
void FLevelLocals::DoReborn (int playernum, bool freshbot)
{
if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN) && !sv_singleplayerrespawn &&
if (!multiplayer && !(flags2 & LEVEL2_ALLOWRESPAWN) && !sv_singleplayerrespawn &&
!G_SkillProperty(SKILLP_PlayerRespawn))
{
if (BackupSaveName.Len() > 0 && FileExists (BackupSaveName.GetChars()))
@ -1620,9 +1623,8 @@ void G_DoReborn (int playernum, bool freshbot)
{ // Reload the level from scratch
bool indemo = demoplayback;
BackupSaveName = "";
G_InitNew (level.MapName, false);
G_InitNew (MapName, false);
demoplayback = indemo;
// gameaction = ga_loadlevel;
}
}
else
@ -1633,28 +1635,28 @@ void G_DoReborn (int playernum, bool freshbot)
// first disassociate the corpse
if (players[playernum].mo)
{
G_QueueBody (players[playernum].mo);
QueueBody (players[playernum].mo);
players[playernum].mo->player = NULL;
}
// spawn at random spot if in deathmatch
if ((deathmatch || isUnfriendly) && (level.deathmatchstarts.Size () > 0))
if ((deathmatch || isUnfriendly) && (deathmatchstarts.Size () > 0))
{
G_DeathMatchSpawnPlayer (playernum);
DeathMatchSpawnPlayer (playernum);
return;
}
if (!(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) &&
level.playerstarts[playernum].type != 0 &&
G_CheckSpot (playernum, &level.playerstarts[playernum]))
if (!(flags2 & LEVEL2_RANDOMPLAYERSTARTS) &&
playerstarts[playernum].type != 0 &&
CheckSpot (playernum, &playerstarts[playernum]))
{
AActor *mo = P_SpawnPlayer(&level.playerstarts[playernum], playernum);
AActor *mo = SpawnPlayer(&playerstarts[playernum], playernum);
if (mo != NULL) P_PlayerStartStomp(mo, true);
}
else
{ // try to spawn at any random player's spot
FPlayerStart *start = G_PickPlayerStart(playernum, PPS_FORCERANDOM);
AActor *mo = P_SpawnPlayer(start, playernum);
FPlayerStart *start = PickPlayerStart(playernum, PPS_FORCERANDOM);
AActor *mo = SpawnPlayer(start, playernum);
if (mo != NULL) P_PlayerStartStomp(mo, true);
}
}
@ -1692,22 +1694,23 @@ void G_DoPlayerPop(int playernum)
}
// [RH] Make the player disappear
level.Behaviors.StopMyScripts(players[playernum].mo);
auto mo = players[playernum].mo;
mo->Level->Behaviors.StopMyScripts(mo);
// [ZZ] fire player disconnect hook
E_PlayerDisconnected(playernum);
mo->Level->localEventManager->PlayerDisconnected(playernum);
// [RH] Let the scripts know the player left
level.Behaviors.StartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true);
if (players[playernum].mo != NULL)
mo->Level->Behaviors.StartTypedScripts(SCRIPT_Disconnect, mo, true, playernum, true);
if (mo != NULL)
{
P_DisconnectEffect(players[playernum].mo);
players[playernum].mo->player = NULL;
players[playernum].mo->Destroy();
P_DisconnectEffect(mo);
mo->player = NULL;
mo->Destroy();
if (!(players[playernum].mo->ObjectFlags & OF_EuthanizeMe))
{ // We just destroyed a morphed player, so now the original player
// has taken their place. Destroy that one too.
players[playernum].mo->Destroy();
}
players[playernum].mo = NULL;
players[playernum].mo = nullptr;
players[playernum].camera = nullptr;
}
@ -1811,7 +1814,7 @@ void G_DoLoadGame ()
SaveVersion = 0;
void *data = info->CacheLump();
FSerializer arc;
FSerializer arc(nullptr);
if (!arc.OpenReader((const char *)data, info->LumpSize))
{
Printf("Failed to access savegame info\n");
@ -1894,7 +1897,7 @@ void G_DoLoadGame ()
// Read intermission data for hubs
G_SerializeHub(arc);
bglobal.RemoveAllBots(true);
primaryLevel->BotInfo.RemoveAllBots(primaryLevel, true);
FString cvar;
arc("importantcvars", cvar);
@ -1907,7 +1910,8 @@ void G_DoLoadGame ()
uint32_t time[2] = { 1,0 };
arc("ticrate", time[0])
("leveltime", time[1]);
("leveltime", time[1])
("globalfreeze", globalfreeze);
// dearchive all the modifications
level.time = Scale(time[1], TICRATE, time[0]);
@ -2034,14 +2038,15 @@ void G_DoAutoSave ()
file = G_BuildSaveName ("auto", nextautosave);
if (!(level.flags2 & LEVEL2_NOAUTOSAVEHINT))
// The hint flag is only relevant on the primary level.
if (!(primaryLevel->flags2 & LEVEL2_NOAUTOSAVEHINT))
{
nextautosave = (nextautosave + 1) % count;
}
else
{
// This flag can only be used once per level
level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
primaryLevel->flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
}
readableTime = myasctime ();
@ -2059,9 +2064,9 @@ static void PutSaveWads (FSerializer &arc)
arc.AddString("Game WAD", name);
// Name of wad the map resides in
if (Wads.GetLumpFile (level.lumpnum) > Wads.GetIwadNum())
if (Wads.GetLumpFile (primaryLevel->lumpnum) > Wads.GetIwadNum())
{
name = Wads.GetWadName (Wads.GetLumpFile (level.lumpnum));
name = Wads.GetWadName (Wads.GetLumpFile (primaryLevel->lumpnum));
arc.AddString("Map WAD", name);
}
}
@ -2080,12 +2085,11 @@ static void PutSaveComment (FSerializer &arc)
arc.AddString("Creation Time", comment);
// Get level name
//strcpy (comment, level.level_name);
comment.Format("%s - %s\n", level.MapName.GetChars(), level.LevelName.GetChars());
comment.Format("%s - %s\n", primaryLevel->MapName.GetChars(), primaryLevel->LevelName.GetChars());
// Append elapsed time
const char *const time = GStrings("SAVECOMMENT_TIME");
levelTime = level.time / TICRATE;
levelTime = primaryLevel->time / TICRATE;
comment.AppendFormat("%s: %02d:%02d:%02d", time, levelTime/3600, (levelTime%3600)/60, levelTime%60);
// Write out the comment
@ -2100,7 +2104,10 @@ static void PutSavePic (FileWriter *file, int width, int height)
}
else
{
screen->WriteSavePic(&players[consoleplayer], file, width, height);
D_Render([&]()
{
screen->WriteSavePic(&players[consoleplayer], file, width, height);
}, false);
}
}
@ -2113,7 +2120,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 (level.lines.Size() == 0 || level.sectors.Size() == 0 || gamestate != GS_LEVEL)
if (primaryLevel->lines.Size() == 0 || primaryLevel->sectors.Size() == 0 || gamestate != GS_LEVEL)
{
return;
}
@ -2129,7 +2136,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
insave = true;
try
{
G_SnapshotLevel();
level.SnapshotLevel();
}
catch(CRecoverableError &err)
{
@ -2152,8 +2159,8 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
BufferWriter savepic;
FSerializer savegameinfo; // this is for displayable info about the savegame
FSerializer savegameglobals; // and this for non-level related info that must be saved.
FSerializer savegameinfo(nullptr); // this is for displayable info about the savegame
FSerializer savegameglobals(nullptr); // and this for non-level related info that must be saved.
savegameinfo.OpenWriter(true);
savegameglobals.OpenWriter(save_formatted);
@ -2164,7 +2171,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
// put some basic info into the PNG so that this isn't lost when the image gets extracted.
M_AppendPNGText(&savepic, "Software", buf);
M_AppendPNGText(&savepic, "Title", description);
M_AppendPNGText(&savepic, "Current Map", level.MapName);
M_AppendPNGText(&savepic, "Current Map", primaryLevel->MapName);
M_FinishPNG(&savepic);
int ver = SAVEVER;
@ -2172,7 +2179,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
.AddString("Engine", GAMESIG)
("Save Version", ver)
.AddString("Title", description)
.AddString("Current Map", level.MapName);
.AddString("Current Map", primaryLevel->MapName);
PutSaveWads (savegameinfo);
@ -2382,7 +2389,7 @@ void G_BeginRecording (const char *startmap)
if (startmap == NULL)
{
startmap = level.MapName;
startmap = primaryLevel->MapName;
}
demo_p = demobuffer;
@ -2707,7 +2714,7 @@ void G_DoPlayDemo (void)
{
G_InitNew (mapname, false);
}
else if (level.sectors.Size() == 0)
else if (primaryLevel->sectors.Size() == 0)
{
I_Error("Cannot play demo without its savegame\n");
}
@ -2857,17 +2864,17 @@ bool G_CheckDemoStatus (void)
return false;
}
void G_StartSlideshow(FName whichone)
void G_StartSlideshow(FLevelLocals *Level, FName whichone)
{
gameaction = ga_slideshow;
SelectedSlideshow = whichone == NAME_None ? level.info->slideshow : whichone;
SelectedSlideshow = whichone == NAME_None ? Level->info->slideshow : whichone;
}
DEFINE_ACTION_FUNCTION(FLevelLocals, StartSlideshow)
{
PARAM_PROLOGUE;
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_NAME(whichone);
G_StartSlideshow(whichone);
G_StartSlideshow(self, whichone);
return 0;
}
@ -2878,12 +2885,13 @@ DEFINE_GLOBAL_NAMED(Skins, PlayerSkins)
DEFINE_GLOBAL(consoleplayer)
DEFINE_GLOBAL_NAMED(PClass::AllClasses, AllClasses)
DEFINE_GLOBAL_NAMED(PClassActor::AllActorClasses, AllActorClasses)
DEFINE_GLOBAL_NAMED(primaryLevel, Level)
DEFINE_GLOBAL(validcount)
DEFINE_GLOBAL(multiplayer)
DEFINE_GLOBAL(gameaction)
DEFINE_GLOBAL(gamestate)
DEFINE_GLOBAL(skyflatnum)
DEFINE_GLOBAL_NAMED(bglobal.freeze, globalfreeze)
DEFINE_GLOBAL(globalfreeze)
DEFINE_GLOBAL(gametic)
DEFINE_GLOBAL(demoplayback)
DEFINE_GLOBAL(automapactive);

View file

@ -32,15 +32,40 @@ struct event_t;
#include "dobjgc.h"
// The current state of the game: whether we are
// playing, gazing at the intermission screen,
// the game final animation, or a demo.
enum gamestate_t : int
{
GS_LEVEL,
GS_INTERMISSION,
GS_FINALE,
GS_DEMOSCREEN,
GS_FULLCONSOLE, // [RH] Fullscreen console
GS_HIDECONSOLE, // [RH] The menu just did something that should hide fs console
GS_STARTUP, // [RH] Console is fullscreen, and game is just starting
GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN
GS_FORCEWIPE = -1,
GS_FORCEWIPEFADE = -2,
GS_FORCEWIPEBURN = -3,
GS_FORCEWIPEMELT = -4
};
extern gamestate_t gamestate;
// wipegamestate can be set to -1
// to force a wipe on the next draw
extern gamestate_t wipegamestate;
class AActor;
struct FLevelLocals;
//
// GAME
//
void G_DeathMatchSpawnPlayer (int playernum);
struct FPlayerStart *G_PickPlayerStart (int playernum, int flags = 0);
enum
{
PPS_FORCERANDOM = 1,
@ -67,13 +92,11 @@ void G_PlayDemo (char* name);
void G_TimeDemo (const char* name);
bool G_CheckDemoStatus (void);
void G_WorldDone (void);
void G_Ticker (void);
bool G_Responder (event_t* ev);
void G_ScreenShot (char *filename);
void G_StartSlideshow(FName whichone);
void G_StartSlideshow(FLevelLocals *Level, FName whichone);
FString G_BuildSaveName (const char *prefix, int slot);
@ -89,7 +112,6 @@ enum EFinishLevelType
void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags);
void G_DoReborn (int playernum, bool freshbot);
void G_DoPlayerPop(int playernum);
// Adds pitch to consoleplayer's viewpitch and clamps it

View file

@ -76,7 +76,7 @@ struct FHubInfo
static TArray<FHubInfo> hubdata;
void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
void G_LeavingHub(FLevelLocals *Level, int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
unsigned int i, j;
@ -84,7 +84,7 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
for (i = 0; i < hubdata.Size(); i++)
{
if (hubdata[i].levelnum == level.levelnum)
if (hubdata[i].levelnum == Level->levelnum)
{
hubdata[i] = *wbs;
break;
@ -95,13 +95,13 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
hubdata[hubdata.Reserve(1)] = *wbs;
}
hubdata[i].levelnum = level.levelnum;
hubdata[i].levelnum = Level->levelnum;
if (!multiplayer && !deathmatch)
{
// The player counters don't work in hubs
hubdata[i].plyr[0].skills = level.killed_monsters;
hubdata[i].plyr[0].sitems = level.found_items;
hubdata[i].plyr[0].ssecret = level.found_secrets;
hubdata[i].plyr[0].skills = Level->killed_monsters;
hubdata[i].plyr[0].sitems = Level->found_items;
hubdata[i].plyr[0].ssecret = Level->found_secrets;
}
@ -129,11 +129,11 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
if (cluster->flags & CLUSTER_LOOKUPNAME)
{
level.LevelName = GStrings(cluster->ClusterName);
Level->LevelName = GStrings(cluster->ClusterName);
}
else
{
level.LevelName = cluster->ClusterName;
Level->LevelName = cluster->ClusterName;
}
}
}
@ -185,4 +185,4 @@ void G_SerializeHub(FSerializer &arc)
void G_ClearHubInfo()
{
hubdata.Clear();
}
}

View file

@ -4,9 +4,10 @@
struct cluster_info_t;
struct wbstartstruct_t;
class FSerializer;
struct FLevelLocals;
void G_SerializeHub (FSerializer &file);
void G_LeavingHub(int mode, cluster_info_t * cluster, struct wbstartstruct_t * wbs);
void G_LeavingHub(FLevelLocals *Level, int mode, cluster_info_t * cluster, struct wbstartstruct_t * wbs);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,450 +1,14 @@
/*
** g_level.h
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
#ifndef __G_LEVEL_H__
#define __G_LEVEL_H__
#pragma once
#include "doomtype.h"
#include "vectors.h"
#include "sc_man.h"
#include "resourcefiles/file_zip.h"
#include "g_mapinfo.h"
struct level_info_t;
struct cluster_info_t;
class FSerializer;
#if defined(_MSC_VER)
#pragma section(".yreg$u",read)
#define MSVC_YSEG __declspec(allocate(".yreg$u"))
#define GCC_YSEG
#else
#define MSVC_YSEG
#define GCC_YSEG __attribute__((section(SECTION_YREG))) __attribute__((used))
#endif
// The structure used to control scripts between maps
struct acsdefered_t
{
enum EType
{
defexecute,
defexealways,
defsuspend,
defterminate
} type;
int script;
int args[3];
int playernum;
};
FSerializer &Serialize(FSerializer &arc, const char *key, acsdefered_t &defer, acsdefered_t *def);
struct FIntermissionDescriptor;
struct FIntermissionAction;
struct FMapInfoParser
{
enum EFormatType
{
FMT_Unknown,
FMT_Old,
FMT_New
};
FScanner sc;
int format_type;
bool HexenHack;
FMapInfoParser(int format = FMT_Unknown)
{
format_type = format;
HexenHack = false;
}
bool ParseLookupName(FString &dest);
void ParseMusic(FString &name, int &order);
//void ParseLumpOrTextureName(char *name);
void ParseLumpOrTextureName(FString &name);
void ParseExitText(FName formap, level_info_t *info);
void ParseExitMusic(FName formap, level_info_t *info);
void ParseExitBackdrop(FName formap, level_info_t *info, bool ispic);
void ParseCluster();
void ParseNextMap(FString &mapname);
level_info_t *ParseMapHeader(level_info_t &defaultinfo);
void ParseMapDefinition(level_info_t &leveldef);
void ParseGameInfo();
void ParseEpisodeInfo ();
void ParseSkill ();
void ParseMapInfo (int lump, level_info_t &gamedefaults, level_info_t &defaultinfo);
void ParseOpenBrace();
bool ParseCloseBrace();
bool CheckAssign();
void ParseAssign();
void MustParseAssign();
void ParseComma();
bool CheckNumber();
bool CheckFloat();
void SkipToNext();
void CheckEndOfFile(const char *block);
void ParseIntermissionAction(FIntermissionDescriptor *Desc);
void ParseIntermission();
void ParseDoomEdNums();
void ParseSpawnNums();
void ParseConversationIDs();
void ParseAMColors(bool);
FName CheckEndSequence();
FName ParseEndGame();
void ParseDamageDefinition();
};
#define DEFINE_MAP_OPTION(name, old) \
static void MapOptHandler_##name(FMapInfoParser &parse, level_info_t *info); \
static FMapOptInfo MapOpt_##name = \
{ #name, MapOptHandler_##name, old }; \
MSVC_YSEG FMapOptInfo *mapopt_##name GCC_YSEG = &MapOpt_##name; \
static void MapOptHandler_##name(FMapInfoParser &parse, level_info_t *info)
struct FMapOptInfo
{
const char *name;
void (*handler) (FMapInfoParser &parse, level_info_t *levelinfo);
bool old;
};
enum ELevelFlags : unsigned int
{
LEVEL_NOINTERMISSION = 0x00000001,
LEVEL_NOINVENTORYBAR = 0x00000002, // This effects Doom only, since it's the only one without a standard inventory bar.
LEVEL_DOUBLESKY = 0x00000004,
LEVEL_HASFADETABLE = 0x00000008, // Level uses Hexen's fadetable mapinfo to get fog
LEVEL_MAP07SPECIAL = 0x00000010,
LEVEL_BRUISERSPECIAL = 0x00000020,
LEVEL_CYBORGSPECIAL = 0x00000040,
LEVEL_SPIDERSPECIAL = 0x00000080,
LEVEL_SPECLOWERFLOOR = 0x00000100,
LEVEL_SPECOPENDOOR = 0x00000200,
LEVEL_SPECLOWERFLOORTOHIGHEST=0x00000300,
LEVEL_SPECACTIONSMASK = 0x00000300,
LEVEL_MONSTERSTELEFRAG = 0x00000400,
LEVEL_ACTOWNSPECIAL = 0x00000800,
LEVEL_SNDSEQTOTALCTRL = 0x00001000,
LEVEL_FORCETILEDSKY = 0x00002000,
LEVEL_CROUCH_NO = 0x00004000,
LEVEL_JUMP_NO = 0x00008000,
LEVEL_FREELOOK_NO = 0x00010000,
LEVEL_FREELOOK_YES = 0x00020000,
// The absence of both of the following bits means that this level does not
// use falling damage (though damage can be forced with dmflags,.
LEVEL_FALLDMG_ZD = 0x00040000, // Level uses ZDoom's falling damage
LEVEL_FALLDMG_HX = 0x00080000, // Level uses Hexen's falling damage
LEVEL_HEADSPECIAL = 0x00100000, // Heretic episode 1/4
LEVEL_MINOTAURSPECIAL = 0x00200000, // Heretic episode 2/5
LEVEL_SORCERER2SPECIAL = 0x00400000, // Heretic episode 3
LEVEL_SPECKILLMONSTERS = 0x00800000,
LEVEL_STARTLIGHTNING = 0x01000000, // Automatically start lightning
LEVEL_FILTERSTARTS = 0x02000000, // Apply mapthing filtering to player starts
LEVEL_LOOKUPLEVELNAME = 0x04000000, // Level name is the name of a language string
LEVEL_USEPLAYERSTARTZ = 0x08000000, // Use the Z position of player starts
LEVEL_SWAPSKIES = 0x10000000, // Used by lightning
LEVEL_NOALLIES = 0x20000000, // i.e. Inside Strife's front base
LEVEL_CHANGEMAPCHEAT = 0x40000000, // Don't display cluster messages
LEVEL_VISITED = 0x80000000, // Used for intermission map
// The flags uint64_t is now split into 2 DWORDs
LEVEL2_RANDOMPLAYERSTARTS = 0x00000001, // Select single player starts randomnly (no voodoo dolls)
LEVEL2_ALLMAP = 0x00000002, // The player picked up a map on this level
LEVEL2_LAXMONSTERACTIVATION = 0x00000004, // Monsters can open doors depending on the door speed
LEVEL2_LAXACTIVATIONMAPINFO = 0x00000008, // LEVEL_LAXMONSTERACTIVATION is not a default.
LEVEL2_MISSILESACTIVATEIMPACT=0x00000010, // Missiles are the activators of SPAC_IMPACT events, not their shooters
LEVEL2_FROZEN = 0x00000020, // Game is frozen by a TimeFreezer
LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1
LEVEL2_PRERAISEWEAPON = 0x00000080, // players should spawn with their weapons fully raised (but not when respawning it multiplayer)
LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100,
LEVEL2_CLIPMIDTEX = 0x00000200,
LEVEL2_WRAPMIDTEX = 0x00000400,
LEVEL2_CHECKSWITCHRANGE = 0x00000800,
LEVEL2_PAUSE_MUSIC_IN_MENUS = 0x00001000,
LEVEL2_TOTALINFIGHTING = 0x00002000,
LEVEL2_NOINFIGHTING = 0x00004000,
LEVEL2_NOMONSTERS = 0x00008000,
LEVEL2_INFINITE_FLIGHT = 0x00010000,
LEVEL2_ALLOWRESPAWN = 0x00020000,
LEVEL2_FORCETEAMPLAYON = 0x00040000,
LEVEL2_FORCETEAMPLAYOFF = 0x00080000,
LEVEL2_CONV_SINGLE_UNFREEZE = 0x00100000,
LEVEL2_RAILINGHACK = 0x00200000, // but UDMF requires them to be separate to have more control
LEVEL2_DUMMYSWITCHES = 0x00400000,
LEVEL2_HEXENHACK = 0x00800000, // Level was defined in a Hexen style MAPINFO
LEVEL2_SMOOTHLIGHTING = 0x01000000, // Level uses the smooth lighting feature.
LEVEL2_POLYGRIND = 0x02000000, // Polyobjects grind corpses to gibs.
LEVEL2_RESETINVENTORY = 0x04000000, // Resets player inventory when starting this level (unless in a hub)
LEVEL2_RESETHEALTH = 0x08000000, // Resets player health when starting this level (unless in a hub)
LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected
LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit.
LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept
LEVEL2_FORGETSTATE = 0x80000000, // forget this map's state in a hub
// More flags!
LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled
LEVEL3_REMOVEITEMS = 0x00000002, // kills all INVBAR items on map change.
LEVEL3_ATTENUATE = 0x00000004, // attenuate lights?
LEVEL3_NOLIGHTFADE = 0x00000008, // no light fading to black.
LEVEL3_NOCOLOREDSPRITELIGHTING = 0x00000010, // draw sprites only with color-less light
LEVEL3_EXITNORMALUSED = 0x00000020,
LEVEL3_EXITSECRETUSED = 0x00000040,
LEVEL3_FORCEWORLDPANNING = 0x00000080, // Forces the world panning flag for all textures, even those without it explicitly set.
};
struct FSpecialAction
{
FName Type; // this is initialized before the actors...
uint8_t Action;
int Args[5];
};
class DScroller;
class FScanner;
struct level_info_t;
typedef TMap<int, FName> FMusicMap;
enum EMapType : int
{
MAPTYPE_UNKNOWN = 0,
MAPTYPE_DOOM,
MAPTYPE_HEXEN,
MAPTYPE_BUILD,
MAPTYPE_UDMF // This does not distinguish between namespaces.
};
struct FExitText
{
enum EDefined
{
DEF_TEXT = 1,
DEF_MUSIC = 2,
DEF_BACKDROP = 4,
DEF_LOOKUP = 8,
DEF_PIC = 16
};
int16_t mDefined = 0;
int16_t mOrder = -1;
FString mText;
FString mMusic;
FString mBackdrop;
FExitText(int def = 0, int order = -1, const FString &text = "", const FString &backdrop = "", const FString &music = "")
: mDefined(int16_t(def)), mOrder(int16_t(order)), mText(text), mMusic(music), mBackdrop(backdrop)
{
}
};
struct level_info_t
{
int levelnum;
FString MapName;
FString NextMap;
FString NextSecretMap;
FString PName;
FString SkyPic1;
FString SkyPic2;
FString FadeTable;
FString F1Pic;
FString BorderTexture;
FString MapBackground;
TMap<FName, FExitText> ExitMapTexts;
int cluster;
int partime;
int sucktime;
int32_t flags;
uint32_t flags2;
uint32_t flags3;
FString Music;
FString LevelName;
int8_t WallVertLight, WallHorizLight;
int musicorder;
FCompressedBuffer Snapshot;
TArray<acsdefered_t> deferred;
float skyspeed1;
float skyspeed2;
uint32_t fadeto;
uint32_t outsidefog;
int cdtrack;
unsigned int cdid;
double gravity;
double aircontrol;
int WarpTrans;
int airsupply;
uint32_t compatflags, compatflags2;
uint32_t compatmask, compatmask2;
FString Translator; // for converting Doom-format linedef and sector types.
int DefaultEnvironment; // Default sound environment for the map.
FName Intermission;
FName deathsequence;
FName slideshow;
uint32_t hazardcolor;
uint32_t hazardflash;
int fogdensity;
int outsidefogdensity;
int skyfog;
float pixelstretch;
// Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one.
FName RedirectType;
FString RedirectMapName;
FString EnterPic;
FString ExitPic;
FString InterMusic;
int intermusicorder;
TMap <FName, std::pair<FString, int> > MapInterMusic;
FString SoundInfo;
FString SndSeq;
double teamdamage;
FMusicMap MusicMap;
TArray<FSpecialAction> specialactions;
TArray<int> PrecacheSounds;
TArray<FString> PrecacheTextures;
TArray<FName> PrecacheClasses;
TArray<FString> EventHandlers;
ELightMode lightmode;
int8_t brightfog;
int8_t lightadditivesurfaces;
int8_t notexturefill;
FVector3 skyrotatevector;
FVector3 skyrotatevector2;
FString EDName;
FString acsName;
bool fs_nocheckposition;
level_info_t()
{
Reset();
}
~level_info_t()
{
Snapshot.Clean();
ClearDefered();
}
void Reset();
bool isValid();
FString LookupLevelName ();
void ClearDefered()
{
deferred.Clear();
}
level_info_t *CheckLevelRedirect ();
};
struct cluster_info_t
{
int cluster;
FString FinaleFlat;
FString ExitText;
FString EnterText;
FString MessageMusic;
int musicorder;
int flags;
int cdtrack;
FString ClusterName;
unsigned int cdid;
void Reset();
};
// Cluster flags
#define CLUSTER_HUB 0x00000001 // Cluster uses hub behavior
#define CLUSTER_EXITTEXTINLUMP 0x00000002 // Exit text is the name of a lump
#define CLUSTER_ENTERTEXTINLUMP 0x00000004 // Enter text is the name of a lump
#define CLUSTER_FINALEPIC 0x00000008 // Finale "flat" is actually a full-sized image
#define CLUSTER_LOOKUPEXITTEXT 0x00000010 // Exit text is the name of a language string
#define CLUSTER_LOOKUPENTERTEXT 0x00000020 // Enter text is the name of a language string
#define CLUSTER_LOOKUPNAME 0x00000040 // Name is the name of a language string
#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 TArray<level_info_t> wadlevelinfos;
extern TArray<cluster_info_t> wadclusterinfos;
extern bool savegamerestore;
// mapname will be changed if it is a valid warptrans
bool CheckWarpTransMap (FString &mapname, bool substitute);
void G_InitNew (const char *mapname, bool bTitleLevel);
// Can be called by the startup code or M_Responder.
@ -454,11 +18,6 @@ void G_DeferedInitNew (const char *mapname, int skill = -1);
struct FGameStartup;
void G_DeferedInitNew (FGameStartup *gs);
void G_ExitLevel (int position, bool keepFacing);
void G_SecretExitLevel (int position);
const char *G_GetExitMap();
const char *G_GetSecretExitMap();
enum
{
CHANGELEVEL_KEEPFACING = 1,
@ -470,140 +29,13 @@ enum
CHANGELEVEL_PRERAISEWEAPON = 64,
};
void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1);
void G_StartTravel ();
int G_FinishTravel ();
void G_DoLoadLevel (int position, bool autosave, bool newGame);
void G_InitLevelLocals (void);
void G_AirControlChanged ();
cluster_info_t *FindClusterInfo (int cluster);
level_info_t *FindLevelInfo (const char *mapname, bool allowdefault=true);
level_info_t *FindLevelByNum (int num);
level_info_t *CheckLevelRedirect (level_info_t *info);
FString CalcMapName (int episode, int level);
void G_ParseMapInfo (FString basemapinfo);
void G_DoLoadLevel (const FString &MapName, int position, bool autosave, bool newGame);
void G_ClearSnapshots (void);
void P_RemoveDefereds ();
void G_SnapshotLevel (void);
void G_UnSnapshotLevel (bool keepPlayers);
void G_ReadSnapshots (FResourceFile *);
void G_WriteSnapshots (TArray<FString> &, TArray<FCompressedBuffer> &);
void G_WriteVisited(FSerializer &arc);
void G_ReadVisited(FSerializer &arc);
void G_ClearHubInfo();
enum ESkillProperty
{
SKILLP_FastMonsters,
SKILLP_Respawn,
SKILLP_RespawnLimit,
SKILLP_DisableCheats,
SKILLP_AutoUseHealth,
SKILLP_SpawnFilter,
SKILLP_EasyBossBrain,
SKILLP_ACSReturn,
SKILLP_NoPain,
SKILLP_EasyKey,
SKILLP_SlowMonsters,
SKILLP_Infight,
SKILLP_PlayerRespawn,
};
enum EFSkillProperty // floating point properties
{
SKILLP_AmmoFactor,
SKILLP_DropAmmoFactor,
SKILLP_ArmorFactor,
SKILLP_HealthFactor,
SKILLP_DamageFactor,
SKILLP_Aggressiveness,
SKILLP_MonsterHealth,
SKILLP_FriendlyHealth,
SKILLP_KickbackFactor,
};
int G_SkillProperty(ESkillProperty prop);
double G_SkillProperty(EFSkillProperty prop);
const char * G_SkillName();
typedef TMap<FName, FString> SkillMenuNames;
typedef TMap<FName, FName> SkillActorReplacement;
struct FSkillInfo
{
FName Name = NAME_None;
double AmmoFactor, DoubleAmmoFactor, DropAmmoFactor;
double DamageFactor;
double ArmorFactor;
double HealthFactor;
double KickbackFactor;
bool FastMonsters;
bool SlowMonsters;
bool DisableCheats;
bool AutoUseHealth;
bool EasyBossBrain;
bool EasyKey;
bool NoMenu;
int RespawnCounter;
int RespawnLimit;
double Aggressiveness;
int SpawnFilter;
int ACSReturn;
FString MenuName;
FString PicName;
SkillMenuNames MenuNamesForPlayerClass;
bool MustConfirm;
FString MustConfirmText;
char Shortcut;
FString TextColor;
SkillActorReplacement Replace;
SkillActorReplacement Replaced;
double MonsterHealth;
double FriendlyHealth;
bool NoPain;
int Infighting;
bool PlayerRespawn;
FSkillInfo() {}
FSkillInfo(const FSkillInfo &other)
{
operator=(other);
}
FSkillInfo &operator=(const FSkillInfo &other);
int GetTextColor() const;
void SetReplacement(FName a, FName b);
FName GetReplacement(FName a);
void SetReplacedBy(FName b, FName a);
FName GetReplacedBy(FName b);
};
extern TArray<FSkillInfo> AllSkills;
extern int DefaultSkill;
struct FEpisode
{
FString mEpisodeName;
FString mEpisodeMap;
FString mPicName;
char mShortcut;
bool mNoSkill;
};
extern TArray<FEpisode> AllEpisodes;
int ParseUMapInfo(int lumpnum);
void CommitUMapinfo(level_info_t *defaultinfo);
#endif //__G_LEVEL_H__

View file

@ -44,16 +44,370 @@
#include "p_local.h"
#include "po_man.h"
#include "p_acs.h"
#include "p_tags.h"
#include "p_spec.h"
#include "actor.h"
#include "b_bot.h"
#include "p_effect.h"
#include "d_player.h"
#include "p_destructible.h"
#include "r_data/r_sections.h"
#include "r_data/r_canvastexture.h"
#include "r_data/r_interpolate.h"
//============================================================================
//
// This is used to mark processed portals for some collection functions.
//
//============================================================================
struct FPortalBits
{
TArray<uint32_t> data;
void setSize(int num)
{
data.Resize((num + 31) / 32);
clear();
}
void clear()
{
memset(&data[0], 0, data.Size() * sizeof(uint32_t));
}
void setBit(int group)
{
data[group >> 5] |= (1 << (group & 31));
}
int getBit(int group)
{
return data[group >> 5] & (1 << (group & 31));
}
};
class DACSThinker;
class DFraggleThinker;
class DSpotState;
class DSeqNode;
struct FStrifeDialogueNode;
class DAutomapBase;
struct wbstartstruct_t;
class DSectorMarker;
struct FTranslator;
struct EventManager;
struct FLevelData
typedef TMap<int, int> FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS)
typedef TMap<FName, int> FDialogueMap; // maps actor class names to dialogue array index
typedef TMap<int, FUDMFKeys> FUDMFKeyMap;
struct FLevelLocals
{
void *level;
void *Level; // bug catchers.
FLevelLocals();
~FLevelLocals();
friend class MapLoader;
void Tick();
void Mark();
void AddScroller(int secnum);
void SetInterMusic(const char *nextmap);
void SetMusicVolume(float v);
void ClearLevelData();
void ClearPortals();
bool CheckIfExitIsGood(AActor *self, level_info_t *newmap);
void FormatMapName(FString &mapname, const char *mapnamecolor);
void ClearAllSubsectorLinks();
void TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1);
int TranslateSectorSpecial(int special);
bool IsTIDUsed(int tid);
int FindUniqueTID(int start_tid, int limit);
int GetConversation(int conv_id);
int GetConversation(FName classname);
void SetConversation(int convid, PClassActor *Class, int dlgindex);
int FindNode (const FStrifeDialogueNode *node);
int GetInfighting();
void SetCompatLineOnSide(bool state);
void Init();
private:
line_t *FindPortalDestination(line_t *src, int tag);
void BuildPortalBlockmap();
void UpdatePortal(FLinePortal *port);
void CollectLinkedPortals();
void CreateLinkedPortals();
bool ChangePortalLine(line_t *line, int destid);
void AddDisplacementForPortal(FSectorPortal *portal);
void AddDisplacementForPortal(FLinePortal *portal);
bool ConnectPortalGroups();
public:
void SnapshotLevel();
void UnSnapshotLevel(bool hubLoad);
void FinalizePortals();
bool ChangePortal(line_t *ln, int thisid, int destid);
unsigned GetSkyboxPortal(AActor *actor);
unsigned GetPortal(int type, int plane, sector_t *orgsec, sector_t *destsec, const DVector2 &displacement);
unsigned GetStackPortal(AActor *point, int plane);
DVector2 GetPortalOffsetPosition(double x, double y, double dx, double dy);
bool CollectConnectedGroups(int startgroup, const DVector3 &position, double upperz, double checkradius, FPortalGroupArray &out);
void ActivateInStasisPlat(int tag);
bool CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush);
void ActivateInStasisCeiling(int tag);
bool CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, double speed, double height, int crush, int change, bool hexencrush, bool hereticlower);
void DoDeferedScripts();
void AdjustPusher(int tag, int magnitude, int angle, bool wind);
int Massacre(bool baddies = false, FName cls = NAME_None);
AActor *SpawnMapThing(FMapThing *mthing, int position);
AActor *SpawnMapThing(int index, FMapThing *mt, int position);
AActor *SpawnPlayer(FPlayerStart *mthing, int playernum, int flags = 0);
void StartLightning();
void ForceLightning(int mode);
void ClearDynamic3DFloorData();
void WorldDone(void);
void AirControlChanged();
AActor *SelectTeleDest(int tid, int tag, bool norandom);
bool AlignFlat(int linenum, int side, int fc);
void ReplaceTextures(const char *fromname, const char *toname, int flags);
bool EV_Thing_Spawn(int tid, AActor *source, int type, DAngle angle, bool fog, int newtid);
bool EV_Thing_Move(int tid, AActor *source, int mapspot, bool fog);
bool EV_Thing_Projectile(int tid, AActor *source, int type, const char *type_name, DAngle angle,
double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid, bool leadTarget);
int EV_Thing_Damage(int tid, AActor *whofor0, int amount, FName type);
bool EV_DoPlat(int tag, line_t *line, DPlat::EPlatType type, double height, double speed, int delay, int lip, int change);
void EV_StopPlat(int tag, bool remove);
bool EV_DoPillar(DPillar::EPillar type, line_t *line, int tag, double speed, double height, double height2, int crush, bool hexencrush);
bool EV_DoDoor(DDoor::EVlDoor type, line_t *line, AActor *thing, int tag, double speed, int delay, int lock, int lightTag, bool boomgen = false, int topcountdown = 0);
bool EV_SlidingDoor(line_t *line, AActor *thing, int tag, int speed, int delay, DAnimatedDoor::EADType type);
bool EV_DoCeiling(DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom);
bool EV_CeilingCrushStop(int tag, bool remove);
bool EV_StopCeiling(int tag, line_t *line);
bool EV_BuildStairs(int tag, DFloor::EStair type, line_t *line, double stairsize, double speed, int delay, int reset, int igntxt, int usespecials);
bool EV_DoFloor(DFloor::EFloor floortype, line_t *line, int tag, double speed, double height, int crush, int change, bool hexencrush, bool hereticlower = false);
bool EV_FloorCrushStop(int tag, line_t *line);
bool EV_StopFloor(int tag, line_t *line);
bool EV_DoDonut(int tag, line_t *line, double pillarspeed, double slimespeed);
bool EV_DoElevator(line_t *line, DElevator::EElevator type, double speed, double height, int tag);
bool EV_StartWaggle(int tag, line_t *line, int height, int speed, int offset, int timer, bool ceiling);
bool EV_DoChange(line_t *line, EChange changetype, int tag);
void EV_StartLightFlickering(int tag, int upper, int lower);
void EV_StartLightStrobing(int tag, int upper, int lower, int utics, int ltics);
void EV_StartLightStrobing(int tag, int utics, int ltics);
void EV_TurnTagLightsOff(int tag);
void EV_LightTurnOn(int tag, int bright);
void EV_LightTurnOnPartway(int tag, double frac);
void EV_LightChange(int tag, int value);
void EV_StartLightGlowing(int tag, int upper, int lower, int tics);
void EV_StartLightFading(int tag, int value, int tics);
void EV_StopLightEffect(int tag);
bool EV_Teleport(int tid, int tag, line_t *line, int side, AActor *thing, int flags);
bool EV_SilentLineTeleport(line_t *line, int side, AActor *thing, int id, INTBOOL reverse);
bool EV_TeleportOther(int other_tid, int dest_tid, bool fog);
bool EV_TeleportGroup(int group_tid, AActor *victim, int source_tid, int dest_tid, bool moveSource, bool fog);
bool EV_TeleportSector(int tag, int source_tid, int dest_tid, bool fog, int group_tid);
void RecalculateDrawnSubsectors();
FSerializer &SerializeSubsectors(FSerializer &arc, const char *key);
void SpawnExtraPlayers();
void Serialize(FSerializer &arc, bool hubload);
DThinker *FirstThinker (int statnum);
// g_Game
void PlayerReborn (int player);
bool CheckSpot (int playernum, FPlayerStart *mthing);
void DoReborn (int playernum, bool freshbot);
void QueueBody (AActor *body);
double PlayersRangeFromSpot (FPlayerStart *spot);
FPlayerStart *SelectFarthestDeathmatchSpot (size_t selections);
FPlayerStart *SelectRandomDeathmatchSpot (int playernum, unsigned int selections);
void DeathMatchSpawnPlayer (int playernum);
FPlayerStart *PickPlayerStart(int playernum, int flags = 0);
bool DoCompleted(FString nextlevel, wbstartstruct_t &wminfo);
void StartTravel();
int FinishTravel();
void ChangeLevel(const char *levelname, int position, int flags, int nextSkill = -1);
const char *GetSecretExitMap();
void ExitLevel(int position, bool keepFacing);
void SecretExitLevel(int position);
void DoLoadLevel(const FString &nextmapname, int position, bool autosave, bool newGame);
void DeleteAllAttachedLights();
void RecreateAllAttachedLights();
private:
// Work data for CollectConnectedGroups.
FPortalBits processMask;
TArray<FLinePortal*> foundPortals;
TArray<int> groupsToCheck;
public:
FSectorTagIterator GetSectorTagIterator(int tag)
{
return FSectorTagIterator(tagManager, tag);
}
FSectorTagIterator GetSectorTagIterator(int tag, line_t *line)
{
return FSectorTagIterator(tagManager, tag, line);
}
FLineIdIterator GetLineIdIterator(int tag)
{
return FLineIdIterator(tagManager, tag);
}
template<class T> TThinkerIterator<T> GetThinkerIterator(FName subtype = NAME_None, int statnum = MAX_STATNUM+1)
{
if (subtype == NAME_None) return TThinkerIterator<T>(this, statnum);
else return TThinkerIterator<T>(this, subtype, statnum);
}
template<class T> TThinkerIterator<T> GetThinkerIterator(FName subtype, int statnum, AActor *prev)
{
return TThinkerIterator<T>(this, subtype, statnum, prev);
}
FActorIterator GetActorIterator(int tid)
{
return FActorIterator(TIDHash, tid);
}
FActorIterator GetActorIterator(int tid, AActor *start)
{
return FActorIterator(TIDHash, tid, start);
}
NActorIterator GetActorIterator(FName type, int tid)
{
return NActorIterator(TIDHash, type, tid);
}
AActor *SingleActorFromTID(int tid, AActor *defactor)
{
return tid == 0 ? defactor : GetActorIterator(tid).Next();
}
bool SectorHasTags(sector_t *sector)
{
return tagManager.SectorHasTags(sector);
}
bool SectorHasTag(sector_t *sector, int tag)
{
return tagManager.SectorHasTag(sector, tag);
}
bool SectorHasTag(int sector, int tag)
{
return tagManager.SectorHasTag(sector, tag);
}
int GetFirstSectorTag(const sector_t *sect) const
{
return tagManager.GetFirstSectorTag(sect);
}
int GetFirstSectorTag(int i) const
{
return tagManager.GetFirstSectorTag(i);
}
int GetFirstLineId(const line_t *sect) const
{
return tagManager.GetFirstLineID(sect);
}
bool LineHasId(int line, int tag)
{
return tagManager.LineHasID(line, tag);
}
bool LineHasId(line_t *line, int tag)
{
return tagManager.LineHasID(line, tag);
}
int FindFirstSectorFromTag(int tag)
{
auto it = GetSectorTagIterator(tag);
return it.Next();
}
int FindFirstLineFromID(int tag)
{
auto it = GetLineIdIterator(tag);
return it.Next();
}
int isFrozen()
{
return frozenstate;
}
private: // The engine should never ever access subsectors of the game nodes. This is only needed for actually implementing PointInSector.
subsector_t *PointInSubsector(double x, double y);
public:
sector_t *PointInSectorBuggy(double x, double y);
subsector_t *PointInRenderSubsector (fixed_t x, fixed_t y);
sector_t *PointInSector(const DVector2 &pos)
{
return PointInSubsector(pos.X, pos.Y)->sector;
}
sector_t *PointInSector(double x, double y)
{
return PointInSubsector(x, y)->sector;
}
subsector_t *PointInRenderSubsector (const DVector2 &pos)
{
return PointInRenderSubsector(FloatToFixed(pos.X), FloatToFixed(pos.Y));
}
FPolyObj *GetPolyobj (int polyNum)
{
auto index = Polyobjects.FindEx([=](const auto &poly) { return poly.tag == polyNum; });
return index == Polyobjects.Size()? nullptr : &Polyobjects[index];
}
void ClearTIDHashes ()
{
memset(TIDHash, 0, sizeof(TIDHash));
}
bool CheckReject(sector_t *s1, sector_t *s2)
{
if (rejectmatrix.Size() > 0)
{
int pnum = int(s1->Index()) * sectors.Size() + int(s2->Index());
return !(rejectmatrix[pnum >> 3] & (1 << (pnum & 7)));
}
return true;
}
DThinker *CreateThinker(PClass *cls, int statnum = STAT_DEFAULT)
{
DThinker *thinker = static_cast<DThinker*>(cls->CreateNew());
assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker)));
thinker->ObjectFlags |= OF_JustSpawned;
Thinkers.Link(thinker, statnum);
thinker->Level = this;
return thinker;
}
template<typename T, typename... Args>
T* CreateThinker(Args&&... args)
{
auto thinker = static_cast<T*>(CreateThinker(RUNTIME_CLASS(T), T::DEFAULT_STAT));
thinker->Construct(std::forward<Args>(args)...);
return thinker;
}
void SetMusic()
{
if (cdtrack == 0 || !S_ChangeCDMusic(cdtrack, cdid))
S_ChangeMusic(Music, musicorder);
}
TArray<vertex_t> vertexes;
TArray<sector_t> sectors;
TArray<line_t*> linebuffer; // contains the line lists for the sectors.
@ -82,12 +436,14 @@ struct FLevelData
TArray<FLinePortalSpan> linePortalSpans;
FSectionContainer sections;
FCanvasTextureInfo canvasTextureInfo;
EventManager *localEventManager = nullptr;
// [ZZ] Destructible geometry information
TMap<int, FHealthGroup> healthGroups;
FBlockmap blockmap;
TArray<polyblock_t *> PolyBlockMap;
FUDMFKeyMap UDMFKeys[4];
// These are copies of the loaded map data that get used by the savegame code to skip unaltered fields
// Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered.
@ -101,21 +457,24 @@ struct FLevelData
TArray<FPlayerStart> AllPlayerStarts;
FBehaviorContainer Behaviors;
};
AActor *TIDHash[128];
struct FLevelLocals : public FLevelData
{
void Tick();
void Mark();
void AddScroller(int secnum);
void SetInterMusic(const char *nextmap);
void SetMusicVolume(float v);
void ClearLevelData();
void ClearPortals();
TArray<FStrifeDialogueNode *> StrifeDialogues;
FDialogueIDMap DialogueRoots;
FDialogueMap ClassRoots;
FCajunMaster BotInfo;
int ii_compatflags = 0;
int ii_compatflags2 = 0;
int ib_compatflags = 0;
int i_compatflags = 0;
int i_compatflags2 = 0;
DSectorMarker *SectorMarker;
uint8_t 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 maptime; // time in the map
int totaltime; // time in the game
int starttime;
int partime;
@ -132,13 +491,73 @@ struct FLevelLocals : public FLevelData
FString NextMap; // go here when using the regular exit
FString NextSecretMap; // map to go to when used secret exit
FString F1Pic;
FTranslator *Translator;
EMapType maptype;
FTagManager tagManager;
FInterpolator interpolator;
uint64_t ShaderStartTime = 0; // tell the shader system when we started the level (forces a timer restart)
static const int BODYQUESIZE = 32;
TObjPtr<AActor*> bodyque[BODYQUESIZE];
TObjPtr<DAutomapBase*> automap = nullptr;
int bodyqueslot;
// For now this merely points to the global player array, but with this in place, access to this array can be moved over to the level.
// As things progress each level needs to be able to point to different players, even if they are just null if the second level is merely a skybox or camera target.
// But even if it got a real player, the level will not own it - the player merely links to the level.
// This should also be made a real object eventually.
player_t *Players[MAXPLAYERS];
// This is to allow refactoring without refactoring the data right away.
bool PlayerInGame(int pnum)
{
return playeringame[pnum];
}
// This needs to be done better, but for now it should be good enough.
bool PlayerInGame(player_t *player)
{
for (int i = 0; i < MAXPLAYERS; i++)
{
if (player == Players[i]) return PlayerInGame(i);
}
return false;
}
int PlayerNum(player_t *player)
{
for (int i = 0; i < MAXPLAYERS; i++)
{
if (player == Players[i]) return i;
}
return -1;
}
bool isPrimaryLevel() const
{
return true;
}
// Gets the console player without having the calling code be aware of the level's state.
player_t *GetConsolePlayer() const
{
return isPrimaryLevel()? Players[consoleplayer] : nullptr;
}
bool isConsolePlayer(AActor *mo) const
{
auto p = GetConsolePlayer();
if (!p) return false;
return p->mo == mo;
}
bool isCamera(AActor *mo) const
{
auto p = GetConsolePlayer();
if (!p) return false;
return p->camera == mo;
}
int NumMapSections;
@ -162,6 +581,10 @@ struct FLevelLocals : public FLevelData
float skyspeed1; // Scrolling speed of sky textures, in pixels per ms
float skyspeed2;
double sky1pos, sky2pos;
float hw_sky1pos, hw_sky2pos;
bool skystretch;
int total_secrets;
int found_secrets;
@ -177,6 +600,16 @@ struct FLevelLocals : public FLevelData
int airsupply;
int DefaultEnvironment; // Default sound environment.
int ActiveSequences;
DSeqNode *SequenceListHead;
// [RH] particle globals
uint32_t ActiveParticles;
uint32_t InactiveParticles;
TArray<particle_t> Particles;
TArray<uint16_t> ParticlesInSubsec;
FThinkerCollection Thinkers;
TArray<DVector2> Scrolls; // NULL if no DScrollers in this level
int8_t WallVertLight; // Light diffs for vert/horiz walls
@ -185,6 +618,7 @@ struct FLevelLocals : public FLevelData
bool FromSnapshot; // The current map was restored from a snapshot
bool HasHeightSecs; // true if some Transfer_Heights effects are present in the map. If this is false, some checks in the renderer can be shortcut.
bool HasDynamicLights; // Another render optimization for maps with no lights at all.
uint8_t frozenstate;
double teamdamage;
@ -234,38 +668,40 @@ struct FLevelLocals : public FLevelData
}
};
#ifndef NO_DEFINE_LEVEL
extern FLevelLocals level;
extern FLevelLocals *primaryLevel; // level for which to display the user interface. This will always be the one the current consoleplayer is in.
extern FLevelLocals *currentVMLevel;
inline FSectorPortal *line_t::GetTransferredPortal()
{
return portaltransferred >= level.sectorPortals.Size() ? (FSectorPortal*)nullptr : &level.sectorPortals[portaltransferred];
auto Level = GetLevel();
return portaltransferred >= Level->sectorPortals.Size() ? (FSectorPortal*)nullptr : &Level->sectorPortals[portaltransferred];
}
inline FSectorPortal *sector_t::GetPortal(int plane)
{
return &level.sectorPortals[Portals[plane]];
return &Level->sectorPortals[Portals[plane]];
}
inline double sector_t::GetPortalPlaneZ(int plane)
{
return level.sectorPortals[Portals[plane]].mPlaneZ;
return Level->sectorPortals[Portals[plane]].mPlaneZ;
}
inline DVector2 sector_t::GetPortalDisplacement(int plane)
{
return level.sectorPortals[Portals[plane]].mDisplacement;
return Level->sectorPortals[Portals[plane]].mDisplacement;
}
inline int sector_t::GetPortalType(int plane)
{
return level.sectorPortals[Portals[plane]].mType;
return Level->sectorPortals[Portals[plane]].mType;
}
inline int sector_t::GetOppositePortalGroup(int plane)
{
return level.sectorPortals[Portals[plane]].mDestination->PortalGroup;
return Level->sectorPortals[Portals[plane]].mDestination->PortalGroup;
}
inline bool sector_t::PortalBlocksView(int plane)
@ -294,31 +730,35 @@ inline bool sector_t::PortalIsLinked(int plane)
return (GetPortalType(plane) == PORTS_LINKEDPORTAL);
}
inline FLevelLocals *line_t::GetLevel() const
{
return frontsector->Level;
}
inline FLinePortal *line_t::getPortal() const
{
return portalindex >= level.linePortals.Size() ? (FLinePortal*)NULL : &level.linePortals[portalindex];
return portalindex >= GetLevel()->linePortals.Size() ? (FLinePortal*)nullptr : &GetLevel()->linePortals[portalindex];
}
// returns true if the portal is crossable by actors
inline bool line_t::isLinePortal() const
{
return portalindex >= level.linePortals.Size() ? false : !!(level.linePortals[portalindex].mFlags & PORTF_PASSABLE);
return portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_PASSABLE);
}
// returns true if the portal needs to be handled by the renderer
inline bool line_t::isVisualPortal() const
{
return portalindex >= level.linePortals.Size() ? false : !!(level.linePortals[portalindex].mFlags & PORTF_VISIBLE);
return portalindex >= GetLevel()->linePortals.Size() ? false : !!(GetLevel()->linePortals[portalindex].mFlags & PORTF_VISIBLE);
}
inline line_t *line_t::getPortalDestination() const
{
return portalindex >= level.linePortals.Size() ? (line_t*)NULL : level.linePortals[portalindex].mDestination;
return portalindex >= GetLevel()->linePortals.Size() ? (line_t*)nullptr : GetLevel()->linePortals[portalindex].mDestination;
}
inline int line_t::getPortalAlignment() const
{
return portalindex >= level.linePortals.Size() ? 0 : level.linePortals[portalindex].mAlign;
return portalindex >= GetLevel()->linePortals.Size() ? 0 : GetLevel()->linePortals[portalindex].mAlign;
}
inline bool line_t::hitSkyWall(AActor* mo) const
@ -327,4 +767,10 @@ inline bool line_t::hitSkyWall(AActor* mo) const
backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this));
}
#endif
// This must later be extended to return an array with all levels.
// It is meant for code that needs to iterate over all levels to make some global changes, e.g. configuation CCMDs.
inline TArrayView<FLevelLocals *> AllLevels()
{
return TArrayView<FLevelLocals *>(&primaryLevel, 1);
}

View file

@ -32,6 +32,8 @@
#include "vm.h"
#include "actorinlines.h"
EXTERN_CVAR(Int, sv_corpsequeuesize)
//----------------------------------------------------------------------------
//
// PROC A_NoBlocking
@ -88,22 +90,6 @@ void A_Unblock(AActor *self, bool drop)
//
//----------------------------------------------------------------------------
CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
if (self > 0)
{
auto &corpsequeue = level.CorpseQueue;
while (corpsequeue.Size() > (unsigned)self)
{
AActor *corpse = corpsequeue[0];
if (corpse) corpse->Destroy();
corpsequeue.Delete(0);
}
}
}
// throw another corpse on the queue
DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
{
@ -111,7 +97,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
if (sv_corpsequeuesize > 0)
{
auto &corpsequeue = level.CorpseQueue;
auto &corpsequeue = self->Level->CorpseQueue;
while (corpsequeue.Size() >= (unsigned)sv_corpsequeuesize)
{
AActor *corpse = corpsequeue[0];
@ -128,7 +114,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse)
{
PARAM_SELF_PROLOGUE(AActor);
auto &corpsequeue = level.CorpseQueue;
auto &corpsequeue = self->Level->CorpseQueue;
auto index = corpsequeue.FindEx([=](auto &element) { return element == self; });
if (index < corpsequeue.Size())
{

View file

@ -47,10 +47,6 @@
IMPLEMENT_CLASS(DCeiling, false, false)
DCeiling::DCeiling ()
{
}
//============================================================================
//
//
@ -208,14 +204,14 @@ void DCeiling::Tick ()
//
//============================================================================
DCeiling::DCeiling (sector_t *sec)
: DMovingCeiling (sec)
void DCeiling::Construct(sector_t *sec)
{
Super::Construct(sec);
}
DCeiling::DCeiling (sector_t *sec, double speed1, double speed2, int silent)
: DMovingCeiling (sec)
void DCeiling::Construct(sector_t *sec, double speed1, double speed2, int silent)
{
Super::Construct(sec);
m_Crush = -1;
m_CrushMode = ECrushMode::crushDoom;
m_Speed = m_Speed1 = speed1;
@ -235,7 +231,7 @@ DCeiling::DCeiling (sector_t *sec, double speed1, double speed2, int silent)
//
//============================================================================
bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag,
bool FLevelLocals::CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag,
double speed, double speed2, double height,
int crush, int silent, int change, DCeiling::ECrushMode hexencrush)
{
@ -248,7 +244,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
}
// new door thinker
DCeiling *ceiling = Create<DCeiling> (sec, speed, speed2, silent & ~4);
DCeiling *ceiling = CreateThinker<DCeiling> (sec, speed, speed2, silent & ~4);
vertex_t *spot = sec->Lines[0]->v1;
switch (type)
@ -465,9 +461,9 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
return ceiling != NULL;
}
DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling)
DEFINE_ACTION_FUNCTION(FLevelLocals, CreateCeiling)
{
PARAM_PROLOGUE;
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_POINTER_NOT_NULL(sec, sector_t);
PARAM_INT(type);
PARAM_POINTER(ln, line_t);
@ -478,7 +474,7 @@ DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling)
PARAM_INT(silent);
PARAM_INT(change);
PARAM_INT(crushmode);
ACTION_RETURN_BOOL(P_CreateCeiling(sec, (DCeiling::ECeiling)type, ln, 0, speed, speed2, height, crush, silent, change, (DCeiling::ECrushMode)crushmode));
ACTION_RETURN_BOOL(self->CreateCeiling(sec, (DCeiling::ECeiling)type, ln, 0, speed, speed2, height, crush, silent, change, (DCeiling::ECrushMode)crushmode));
}
//============================================================================
@ -490,7 +486,7 @@ DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling)
//
//============================================================================
bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
bool FLevelLocals::EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
int tag, double speed, double speed2, double height,
int crush, int silent, int change, DCeiling::ECrushMode hexencrush)
{
@ -508,22 +504,22 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
secnum = sec->sectornum;
// [RH] Hack to let manual crushers be retriggerable, too
tag ^= secnum | 0x1000000;
P_ActivateInStasisCeiling (tag);
return P_CreateCeiling(sec, type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
ActivateInStasisCeiling (tag);
return CreateCeiling(sec, type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
}
// Reactivate in-stasis ceilings...for certain types.
// This restarts a crusher after it has been stopped
if (type == DCeiling::ceilCrushAndRaise)
{
P_ActivateInStasisCeiling (tag);
ActivateInStasisCeiling (tag);
}
// affects all sectors with the same tag as the linedef
FSectorTagIterator it(tag);
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
rtn |= P_CreateCeiling(&level.sectors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
rtn |= CreateCeiling(&sectors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush);
}
return rtn;
}
@ -536,10 +532,10 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line,
//
//============================================================================
void P_ActivateInStasisCeiling (int tag)
void FLevelLocals::ActivateInStasisCeiling (int tag)
{
DCeiling *scan;
TThinkerIterator<DCeiling> iterator;
auto iterator = GetThinkerIterator<DCeiling>();
while ( (scan = iterator.Next ()) )
{
@ -559,13 +555,12 @@ void P_ActivateInStasisCeiling (int tag)
//
//============================================================================
bool EV_CeilingCrushStop (int tag, bool remove)
bool FLevelLocals::EV_CeilingCrushStop (int tag, bool remove)
{
bool rtn = false;
DCeiling *scan;
TThinkerIterator<DCeiling> iterator;
auto iterator = GetThinkerIterator<DCeiling>();
scan = iterator.Next();
auto scan = iterator.Next();
while (scan != nullptr)
{
DCeiling *next = iterator.Next();
@ -589,17 +584,17 @@ bool EV_CeilingCrushStop (int tag, bool remove)
return rtn;
}
bool EV_StopCeiling(int tag, line_t *line)
bool FLevelLocals::EV_StopCeiling(int tag, line_t *line)
{
int sec;
FSectorTagIterator it(tag, line);
auto it = GetSectorTagIterator(tag, line);
while ((sec = it.Next()) >= 0)
{
if (level.sectors[sec].ceilingdata)
if (sectors[sec].ceilingdata)
{
SN_StopSequence(&level.sectors[sec], CHAN_CEILING);
level.sectors[sec].ceilingdata->Destroy();
level.sectors[sec].ceilingdata = nullptr;
SN_StopSequence(&sectors[sec], CHAN_CEILING);
sectors[sec].ceilingdata->Destroy();
sectors[sec].ceilingdata = nullptr;
}
}
return true;

81
src/g_shared/a_ceiling.h Normal file
View file

@ -0,0 +1,81 @@
#pragma once
//
// P_CEILING
//
// [RH] Changed these
class DCeiling : public DMovingCeiling
{
DECLARE_CLASS (DCeiling, DMovingCeiling)
public:
enum ECeiling
{
ceilLowerByValue,
ceilRaiseByValue,
ceilMoveToValue,
ceilLowerToHighestFloor,
ceilLowerInstant,
ceilRaiseInstant,
ceilCrushAndRaise,
ceilLowerAndCrush,
ceil_placeholder,
ceilCrushRaiseAndStay,
ceilRaiseToNearest,
ceilLowerToLowest,
ceilLowerToFloor,
// The following are only used by Generic_Ceiling
ceilRaiseToHighest,
ceilLowerToHighest,
ceilRaiseToLowest,
ceilLowerToNearest,
ceilRaiseToHighestFloor,
ceilRaiseToFloor,
ceilRaiseByTexture,
ceilLowerByTexture,
genCeilingChg0,
genCeilingChgT,
genCeilingChg
};
enum class ECrushMode
{
crushDoom = 0,
crushHexen = 1,
crushSlowdown = 2
};
void Construct(sector_t *sec);
void Construct(sector_t *sec, double speed1, double speed2, int silent);
void Serialize(FSerializer &arc);
void Tick ();
protected:
ECeiling m_Type;
double m_BottomHeight;
double m_TopHeight;
double m_Speed;
double m_Speed1; // [RH] dnspeed of crushers
double m_Speed2; // [RH] upspeed of crushers
int m_Crush;
ECrushMode m_CrushMode;
int m_Silent;
int m_Direction; // 1 = up, 0 = waiting, -1 = down
// [RH] Need these for BOOM-ish transferring ceilings
FTextureID m_Texture;
secspecial_t m_NewSpecial{};
// ID
int m_Tag;
int m_OldDirection;
void PlayCeilingSound ();
friend struct FLevelLocals;
};

246
src/g_shared/a_decalfx.cpp Normal file
View file

@ -0,0 +1,246 @@
/*
** a_decalfx.h
** Decal animation thinkers
**
**---------------------------------------------------------------------------
** 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 "decallib.h"
#include "a_decalfx.h"
#include "serializer.h"
#include "a_sharedglobal.h"
#include "g_levellocals.h"
#include "m_fixed.h"
IMPLEMENT_CLASS(DDecalThinker, false, true)
IMPLEMENT_POINTERS_START(DDecalThinker)
IMPLEMENT_POINTER(TheDecal)
IMPLEMENT_POINTERS_END
void DDecalThinker::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("thedecal", TheDecal);
}
IMPLEMENT_CLASS(DDecalFader, false, false)
void DDecalFader::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("starttime", TimeToStartDecay)
("endtime", TimeToEndDecay)
("starttrans", StartTrans);
}
void DDecalFader::Tick ()
{
if (TheDecal == nullptr)
{
Destroy ();
}
else
{
if (Level->maptime < TimeToStartDecay || Level->isFrozen())
{
return;
}
else if (Level->maptime >= TimeToEndDecay)
{
TheDecal->Destroy (); // remove the decal
Destroy (); // remove myself
return;
}
if (StartTrans == -1)
{
StartTrans = TheDecal->Alpha;
}
int distanceToEnd = TimeToEndDecay - Level->maptime;
int fadeDistance = TimeToEndDecay - TimeToStartDecay;
TheDecal->Alpha = StartTrans * distanceToEnd / fadeDistance;
}
}
IMPLEMENT_CLASS(DDecalStretcher, false, false)
void DDecalStretcher::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("starttime", TimeToStart)
("endtime", TimeToStop)
("goalx", GoalX)
("startx", StartX)
("stretchx", bStretchX)
("goaly", GoalY)
("starty", StartY)
("stretchy", bStretchY)
("started", bStarted);
}
void DDecalStretcher::Tick ()
{
if (TheDecal == nullptr)
{
Destroy ();
return;
}
if (Level->maptime < TimeToStart || Level->isFrozen())
{
return;
}
if (Level->maptime >= TimeToStop)
{
if (bStretchX)
{
TheDecal->ScaleX = GoalX;
}
if (bStretchY)
{
TheDecal->ScaleY = GoalY;
}
Destroy ();
return;
}
if (!bStarted)
{
bStarted = true;
StartX = TheDecal->ScaleX;
StartY = TheDecal->ScaleY;
}
int distance = Level->maptime - TimeToStart;
int maxDistance = TimeToStop - TimeToStart;
if (bStretchX)
{
TheDecal->ScaleX = StartX + (GoalX - StartX) * distance / maxDistance;
}
if (bStretchY)
{
TheDecal->ScaleY = StartY + (GoalY - StartY) * distance / maxDistance;
}
}
IMPLEMENT_CLASS(DDecalSlider, false, false)
void DDecalSlider::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("starttime", TimeToStart)
("endtime", TimeToStop)
("disty", DistY)
("starty", StartY)
("started", bStarted);
}
void DDecalSlider::Tick ()
{
if (TheDecal == nullptr)
{
Destroy ();
return;
}
if (Level->maptime < TimeToStart || Level->isFrozen())
{
return;
}
if (!bStarted)
{
bStarted = true;
/*StartX = TheDecal->LeftDistance;*/
StartY = TheDecal->Z;
}
if (Level->maptime >= TimeToStop)
{
/*TheDecal->LeftDistance = StartX + DistX;*/
TheDecal->Z = StartY + DistY;
Destroy ();
return;
}
int distance = Level->maptime - TimeToStart;
int maxDistance = TimeToStop - TimeToStart;
/*TheDecal->LeftDistance = StartX + DistX * distance / maxDistance);*/
TheDecal->Z = StartY + DistY * distance / maxDistance;
}
IMPLEMENT_CLASS(DDecalColorer, false, false)
void DDecalColorer::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("starttime", TimeToStartDecay)
("endtime", TimeToEndDecay)
("startcolor", StartColor)
("goalcolor", GoalColor);
}
void DDecalColorer::Tick ()
{
if (TheDecal == nullptr || !(TheDecal->RenderStyle.Flags & STYLEF_ColorIsFixed))
{
Destroy ();
}
else
{
if (Level->maptime < TimeToStartDecay || Level->isFrozen())
{
return;
}
else if (Level->maptime >= TimeToEndDecay)
{
TheDecal->SetShade (GoalColor);
Destroy (); // remove myself
}
if (StartColor.a == 255)
{
StartColor = TheDecal->AlphaColor & 0xffffff;
if (StartColor == GoalColor)
{
Destroy ();
return;
}
}
if (Level->maptime & 0)
{ // Changing the shade can be expensive, so don't do it too often.
return;
}
int distance = Level->maptime - TimeToStartDecay;
int maxDistance = TimeToEndDecay - TimeToStartDecay;
int r = StartColor.r + Scale (GoalColor.r - StartColor.r, distance, maxDistance);
int g = StartColor.g + Scale (GoalColor.g - StartColor.g, distance, maxDistance);
int b = StartColor.b + Scale (GoalColor.b - StartColor.b, distance, maxDistance);
TheDecal->SetShade (r, g, b);
}
}

93
src/g_shared/a_decalfx.h Normal file
View file

@ -0,0 +1,93 @@
#pragma once
#include "dthinker.h"
struct DDecalThinker : public DThinker
{
DECLARE_CLASS (DDecalThinker, DThinker)
HAS_OBJECT_POINTERS
public:
static const int DEFAULT_STAT = STAT_DECALTHINKER;
void Construct(DBaseDecal *decal)
{
TheDecal = decal;
}
void Serialize(FSerializer &arc);
TObjPtr<DBaseDecal*> TheDecal;
};
class DDecalFader : public DDecalThinker
{
DECLARE_CLASS (DDecalFader, DDecalThinker)
public:
void Construct(DBaseDecal *decal)
{
Super::Construct(decal);
}
void Serialize(FSerializer &arc);
void Tick ();
int TimeToStartDecay;
int TimeToEndDecay;
double StartTrans;
};
class DDecalColorer : public DDecalThinker
{
DECLARE_CLASS (DDecalColorer, DDecalThinker)
public:
void Construct(DBaseDecal *decal)
{
Super::Construct(decal);
}
void Serialize(FSerializer &arc);
void Tick ();
int TimeToStartDecay;
int TimeToEndDecay;
PalEntry StartColor;
PalEntry GoalColor;
};
class DDecalStretcher : public DDecalThinker
{
DECLARE_CLASS (DDecalStretcher, DDecalThinker)
public:
void Construct(DBaseDecal *decal)
{
Super::Construct(decal);
}
void Serialize(FSerializer &arc);
void Tick ();
int TimeToStart;
int TimeToStop;
double GoalX;
double StartX;
double GoalY;
double StartY;
bool bStretchX;
bool bStretchY;
bool bStarted;
};
class DDecalSlider : public DDecalThinker
{
DECLARE_CLASS (DDecalSlider, DDecalThinker)
public:
void Construct(DBaseDecal *decal)
{
Super::Construct(decal);
}
void Serialize(FSerializer &arc);
void Tick ();
int TimeToStart;
int TimeToStop;
/* double DistX; */
double DistY;
double StartX;
double StartY;
bool bStarted;
};

View file

@ -45,6 +45,16 @@
#include "g_levellocals.h"
#include "vm.h"
EXTERN_CVAR (Bool, cl_spreaddecals)
EXTERN_CVAR (Int, cl_maxdecals)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
struct SpreadInfo
{
double DecalWidth, DecalLeft, DecalRight;
@ -54,9 +64,12 @@ struct SpreadInfo
TArray<side_t *> SpreadStack;
};
static int ImpactCount;
CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
IMPLEMENT_CLASS(DBaseDecal, false, true)
@ -67,48 +80,64 @@ IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(DImpactDecal, false, false)
DBaseDecal::DBaseDecal ()
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), LeftDistance(0), Z(0), ScaleX(1.), ScaleY(1.), Alpha(1.),
AlphaColor(0), Translation(0), RenderFlags(0)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Construct(double z)
{
Z = z;
RenderStyle = STYLE_None;
PicNum.SetInvalid();
}
DBaseDecal::DBaseDecal (double z)
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), LeftDistance(0), Z(z), ScaleX(1.), ScaleY(1.), Alpha(1.),
AlphaColor(0), Translation(0), RenderFlags(0), Side(nullptr), Sector(nullptr)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Construct(const AActor *basis)
{
RenderStyle = STYLE_None;
PicNum.SetInvalid();
Z = basis->Z();
ScaleX = basis->Scale.X;
ScaleY = basis->Scale.Y;
Alpha = basis->Alpha;
AlphaColor = basis->fillcolor;
Translation = basis->Translation;
PicNum = basis->picnum;
RenderFlags = basis->renderflags;
RenderStyle = basis->RenderStyle;
}
DBaseDecal::DBaseDecal (int statnum, double z)
: DThinker(statnum),
WallNext(nullptr), WallPrev(nullptr), LeftDistance(0), Z(z), ScaleX(1.), ScaleY(1.), Alpha(1.),
AlphaColor(0), Translation(0), RenderFlags(0), Side(nullptr), Sector(nullptr)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Construct(const DBaseDecal *basis)
{
RenderStyle = STYLE_None;
PicNum.SetInvalid();
LeftDistance = basis->LeftDistance;
Z = basis->Z;
ScaleX = basis->ScaleX;
ScaleY = basis->ScaleY;
Alpha = basis->Alpha;
AlphaColor = basis->AlphaColor;
Translation = basis->Translation;
PicNum = basis->PicNum;
RenderFlags = basis->RenderFlags;
RenderStyle = basis->RenderStyle;
}
DBaseDecal::DBaseDecal (const AActor *basis)
: DThinker(STAT_DECAL),
WallNext(nullptr), WallPrev(nullptr), LeftDistance(0), Z(basis->Z()), ScaleX(basis->Scale.X), ScaleY(basis->Scale.Y),
Alpha(basis->Alpha), AlphaColor(basis->fillcolor), Translation(basis->Translation), PicNum(basis->picnum),
RenderFlags(basis->renderflags), RenderStyle(basis->RenderStyle), Side(nullptr), Sector(nullptr)
{
}
DBaseDecal::DBaseDecal (const DBaseDecal *basis)
: DThinker(STAT_DECAL),
WallNext(nullptr), WallPrev(nullptr), LeftDistance(basis->LeftDistance), Z(basis->Z), ScaleX(basis->ScaleX),
ScaleY(basis->ScaleY), Alpha(basis->Alpha), AlphaColor(basis->AlphaColor), Translation(basis->Translation),
PicNum(basis->PicNum), RenderFlags(basis->RenderFlags), RenderStyle(basis->RenderStyle), Side(nullptr), Sector(nullptr)
{
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::OnDestroy ()
{
@ -116,6 +145,12 @@ void DBaseDecal::OnDestroy ()
Super::OnDestroy();
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Remove ()
{
if (WallPrev == nullptr)
@ -130,6 +165,12 @@ void DBaseDecal::Remove ()
WallNext = nullptr;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -149,6 +190,12 @@ void DBaseDecal::Serialize(FSerializer &arc)
("sector", Sector);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::GetXY (side_t *wall, double &ox, double &oy) const
{
line_t *line = wall->linedef;
@ -172,18 +219,35 @@ void DBaseDecal::GetXY (side_t *wall, double &ox, double &oy) const
oy = v1->fY() + LeftDistance * dy;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::SetShade (uint32_t rgb)
{
PalEntry *entry = (PalEntry *)&rgb;
AlphaColor = rgb | (ColorMatcher.Pick (entry->r, entry->g, entry->b) << 24);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::SetShade (int r, int g, int b)
{
AlphaColor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b);
}
//----------------------------------------------------------------------------
//
// Returns the texture the decal stuck to.
//
//----------------------------------------------------------------------------
FTextureID DBaseDecal::StickToWall (side_t *wall, double x, double y, F3DFloor *ffloor)
{
Side = wall;
@ -275,6 +339,12 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, double x, double y, F3DFloor *
return tex;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
double DBaseDecal::GetRealZ (const side_t *wall) const
{
const line_t *line = wall->linedef;
@ -329,6 +399,12 @@ double DBaseDecal::GetRealZ (const side_t *wall) const
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::CalcFracPos (side_t *wall, double x, double y)
{
line_t *line = wall->linedef;
@ -362,6 +438,12 @@ void DBaseDecal::CalcFracPos (side_t *wall, double x, double y)
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static void GetWallStuff (side_t *wall, vertex_t *&v1, double &ldx, double &ldy)
{
line_t *line = wall->linedef;
@ -379,11 +461,23 @@ static void GetWallStuff (side_t *wall, vertex_t *&v1, double &ldx, double &ldy)
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static double Length (double dx, double dy)
{
return DVector2(dx, dy).Length();
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static side_t *NextWall (const side_t *wall)
{
line_t *line = wall->linedef;
@ -402,6 +496,12 @@ static side_t *NextWall (const side_t *wall)
return NULL;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::SpreadLeft (double r, vertex_t *v1, side_t *feelwall, F3DFloor *ffloor, SpreadInfo *spread)
{
double ldx, ldy;
@ -415,7 +515,7 @@ void DBaseDecal::SpreadLeft (double r, vertex_t *v1, side_t *feelwall, F3DFloor
double x = v1->fX();
double y = v1->fY();
feelwall = &level.sides[feelwall->LeftSide];
feelwall = &feelwall->GetLevel()->sides[feelwall->LeftSide];
GetWallStuff (feelwall, v1, ldx, ldy);
double wallsize = Length (ldx, ldy);
r += spread->DecalLeft;
@ -446,6 +546,12 @@ void DBaseDecal::SpreadLeft (double r, vertex_t *v1, side_t *feelwall, F3DFloor
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::SpreadRight (double r, side_t *feelwall, double wallsize, F3DFloor *ffloor, SpreadInfo *spread)
{
vertex_t *v1;
@ -455,7 +561,7 @@ void DBaseDecal::SpreadRight (double r, side_t *feelwall, double wallsize, F3DFl
while (r > wallsize && feelwall->RightSide != NO_SIDE)
{
feelwall = &level.sides[feelwall->RightSide];
feelwall = &feelwall->GetLevel()->sides[feelwall->RightSide];
side_t *nextwall = NextWall (feelwall);
if (nextwall != NULL && nextwall->LeftSide != NO_SIDE)
@ -486,6 +592,12 @@ void DBaseDecal::SpreadRight (double r, side_t *feelwall, double wallsize, F3DFl
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor)
{
SpreadInfo spread;
@ -519,9 +631,15 @@ void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, double x, doub
Length (wall->linedef->Delta().X, wall->linedef->Delta().Y), ffloor, &spread);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, double ix, double iy, double iz, side_t *wall, F3DFloor * ffloor) const
{
DBaseDecal *decal = Create<DBaseDecal>(iz);
DBaseDecal *decal = Level->CreateThinker<DBaseDecal>(iz);
if (decal != NULL)
{
if (decal->StickToWall (wall, ix, iy, ffloor).isValid())
@ -540,49 +658,32 @@ DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, double ix, double
return decal;
}
CUSTOM_CVAR (Int, cl_maxdecals, 1024, CVAR_ARCHIVE)
{
if (self < 0)
{
self = 0;
}
else
{
while (level.ImpactDecalCount > self)
{
DThinker *thinker = DThinker::FirstThinker(STAT_AUTODECAL);
if (thinker != NULL)
{
thinker->Destroy();
}
}
}
}
DImpactDecal::DImpactDecal ()
: DBaseDecal (STAT_AUTODECAL, 0.)
{
}
DImpactDecal::DImpactDecal (double z)
: DBaseDecal (STAT_AUTODECAL, z)
{
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DImpactDecal::CheckMax ()
{
if (++level.ImpactDecalCount >= cl_maxdecals)
if (++Level->ImpactDecalCount >= cl_maxdecals)
{
DThinker *thinker = DThinker::FirstThinker (STAT_AUTODECAL);
DThinker *thinker = Level->FirstThinker (STAT_AUTODECAL);
if (thinker != NULL)
{
thinker->Destroy();
level.ImpactDecalCount--;
Level->ImpactDecalCount--;
}
}
}
DImpactDecal *DImpactDecal::StaticCreate (const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
{
if (cl_maxdecals > 0)
{
@ -590,13 +691,19 @@ DImpactDecal *DImpactDecal::StaticCreate (const char *name, const DVector3 &pos,
if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL)
{
return StaticCreate (tpl, pos, wall, ffloor, color);
return StaticCreate (Level, tpl, pos, wall, ffloor, color);
}
}
return NULL;
}
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
{
DImpactDecal *decal = NULL;
if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS))
@ -610,9 +717,9 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVect
// apply the custom color as well.
if (tpl->ShadeColor != tpl_low->ShadeColor) lowercolor=0;
else lowercolor = color;
StaticCreate (tpl_low, pos, wall, ffloor, lowercolor);
StaticCreate (Level, tpl_low, pos, wall, ffloor, lowercolor);
}
decal = Create<DImpactDecal>(pos.Z);
decal = Level->CreateThinker<DImpactDecal>(pos.Z);
if (decal == NULL)
{
return NULL;
@ -641,6 +748,12 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVect
return decal;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, double iy, double iz, side_t *wall, F3DFloor * ffloor) const
{
if (wall->Flags & WALLF_NOAUTODECALS)
@ -648,7 +761,7 @@ DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, doubl
return NULL;
}
DImpactDecal *decal = Create<DImpactDecal>(iz);
DImpactDecal *decal = Level->CreateThinker<DImpactDecal>(iz);
if (decal != NULL)
{
if (decal->StickToWall (wall, ix, iy, ffloor).isValid())
@ -668,33 +781,11 @@ DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, doubl
return decal;
}
CCMD (countdecals)
{
Printf ("%d impact decals\n", ImpactCount);
}
CCMD (countdecalsreal)
{
TThinkerIterator<DImpactDecal> iterator (STAT_AUTODECAL);
int count = 0;
while (iterator.Next())
count++;
Printf ("Counted %d impact decals\n", count);
}
CCMD (spray)
{
if (who == NULL || argv.argc() < 2)
{
Printf ("Usage: spray <decal>\n");
return;
}
Net_WriteByte (DEM_SPRAY);
Net_WriteString (argv[1]);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void SprayDecal(AActor *shooter, const char *name, double distance)
{
@ -709,12 +800,18 @@ void SprayDecal(AActor *shooter, const char *name, double distance)
{
if (trace.HitType == TRACE_HitWall)
{
DImpactDecal::StaticCreate(name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
DImpactDecal::StaticCreate(shooter->Level, name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
}
}
}
DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DBaseDecal *ShootDecal(FLevelLocals *Level, const FDecalTemplate *tpl, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent)
{
if (tpl == NULL || (tpl = tpl->GetDecal()) == NULL)
{
@ -731,7 +828,7 @@ DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *
{
if (permanent)
{
decal = Create<DBaseDecal>(trace.HitPos.Z);
decal = Level->CreateThinker<DBaseDecal>(trace.HitPos.Z);
wall = trace.Line->sidedef[trace.Side];
decal->StickToWall(wall, trace.HitPos.X, trace.HitPos.Y, trace.ffloor);
tpl->ApplyToDecal(decal, wall);
@ -744,18 +841,22 @@ DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *
}
else
{
return DImpactDecal::StaticCreate(tpl, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
return DImpactDecal::StaticCreate(Level, tpl, trace.HitPos, trace.Line->sidedef[trace.Side], NULL);
}
}
return NULL;
}
DEFINE_ACTION_FUNCTION(ADecal, SpawnDecal)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static void SpawnDecal(AActor *self)
{
PARAM_SELF_PROLOGUE(AActor);
const FDecalTemplate *tpl = nullptr;
if (self->args[0] < 0)
{
FName name = ENamedName(-self->args[0]);
@ -766,7 +867,7 @@ DEFINE_ACTION_FUNCTION(ADecal, SpawnDecal)
int decalid = self->args[0] + (self->args[1] << 8); // [KS] High byte for decals.
tpl = DecalLibrary.GetDecalByNum(decalid);
}
// If no decal is specified, don't try to create one.
if (tpl != nullptr)
{
@ -779,7 +880,7 @@ DEFINE_ACTION_FUNCTION(ADecal, SpawnDecal)
// Look for a wall within 64 units behind the actor. If none can be
// found, then no decal is created, and this actor is destroyed
// without effectively doing anything.
if (NULL == ShootDecal(tpl, self, self->Sector, self->X(), self->Y(), self->Z(), self->Angles.Yaw + 180, 64., true))
if (!ShootDecal(self->Level, tpl, self->Sector, self->X(), self->Y(), self->Z(), self->Angles.Yaw + 180, 64., true))
{
DPrintf (DMSG_WARNING, "Could not find a wall to stick decal to at (%f,%f)\n", self->X(), self->Y());
}
@ -789,5 +890,11 @@ DEFINE_ACTION_FUNCTION(ADecal, SpawnDecal)
{
DPrintf (DMSG_ERROR, "Decal actor at (%f,%f) does not have a good template\n", self->X(), self->Y());
}
}
DEFINE_ACTION_FUNCTION_NATIVE(ADecal, SpawnDecal, SpawnDecal)
{
PARAM_SELF_PROLOGUE(AActor);
SpawnDecal(self);
return 0;
}

View file

@ -47,10 +47,6 @@
IMPLEMENT_CLASS(DDoor, false, false)
DDoor::DDoor ()
{
}
void DDoor::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -136,7 +132,7 @@ void DDoor::Tick ()
// killough 10/98: implement gradual lighting effects
if (m_LightTag != 0 && m_TopDist != -m_Sector->floorplane.fD())
{
EV_LightTurnOnPartway (m_LightTag,
Level->EV_LightTurnOnPartway (m_LightTag,
(m_Sector->ceilingplane.fD() + m_Sector->floorplane.fD()) / (m_TopDist + m_Sector->floorplane.fD()));
}
@ -182,7 +178,7 @@ void DDoor::Tick ()
// killough 10/98: implement gradual lighting effects
if (m_LightTag != 0 && m_TopDist != -m_Sector->floorplane.fD())
{
EV_LightTurnOnPartway (m_LightTag,
Level->EV_LightTurnOnPartway (m_LightTag,
(m_Sector->ceilingplane.fD() + m_Sector->floorplane.fD()) / (m_TopDist + m_Sector->floorplane.fD()));
}
@ -332,9 +328,9 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const
}
}
DDoor::DDoor (sector_t *sector)
: DMovingCeiling (sector)
void DDoor::Construct(sector_t *sector)
{
Super::Construct(sector);
}
//============================================================================
@ -343,14 +339,20 @@ DDoor::DDoor (sector_t *sector)
//
//============================================================================
DDoor::DDoor (sector_t *sec, EVlDoor type, double speed, int delay, int lightTag, int topcountdown)
: DMovingCeiling (sec),
m_Type (type), m_Speed (speed), m_TopWait (delay), m_TopCountdown(topcountdown), m_LightTag (lightTag)
void DDoor::Construct(sector_t *sec, EVlDoor type, double speed, int delay, int lightTag, int topcountdown)
{
vertex_t *spot;
double height;
if (i_compatflags & COMPATF_NODOORLIGHT)
Super::Construct(sec);
m_Type = type;
m_Speed = speed;
m_TopWait = delay;
m_TopCountdown = topcountdown;
m_LightTag = lightTag;
if (Level->i_compatflags & COMPATF_NODOORLIGHT)
{
m_LightTag = 0;
}
@ -417,7 +419,7 @@ DDoor::DDoor (sector_t *sec, EVlDoor type, double speed, int delay, int lightTag
//
//============================================================================
bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
bool FLevelLocals::EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
int tag, double speed, int delay, int lock, int lightTag, bool boomgen, int topcountdown)
{
bool rtn = false;
@ -484,21 +486,21 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
}
return false;
}
if (Create<DDoor> (sec, type, speed, delay, lightTag, topcountdown))
if (CreateThinker<DDoor> (sec, type, speed, delay, lightTag, topcountdown))
rtn = true;
}
else
{ // [RH] Remote door
FSectorTagIterator it(tag);
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
// if the ceiling is already moving, don't start the door action
if (sec->PlaneMoving(sector_t::ceiling))
continue;
if (Create<DDoor>(sec, type, speed, delay, lightTag, topcountdown))
if (CreateThinker<DDoor>(sec, type, speed, delay, lightTag, topcountdown))
rtn = true;
}
@ -514,13 +516,9 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
IMPLEMENT_CLASS(DAnimatedDoor, false, false)
DAnimatedDoor::DAnimatedDoor ()
{
}
DAnimatedDoor::DAnimatedDoor (sector_t *sec)
: DMovingCeiling (sec, false)
void DAnimatedDoor::Construct(sector_t *sec)
{
Super::Construct(sec, false);
}
void DAnimatedDoor::Serialize(FSerializer &arc)
@ -683,12 +681,13 @@ void DAnimatedDoor::Tick ()
//
//============================================================================
DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim, DAnimatedDoor::EADType type)
: DMovingCeiling (sec, false)
void DAnimatedDoor::Construct(sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim, DAnimatedDoor::EADType type)
{
double topdist;
FTextureID picnum;
Super::Construct(sec, false);
m_DoorAnim = anim;
m_Line1 = line;
@ -748,7 +747,7 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay,
//
//============================================================================
bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay, DAnimatedDoor::EADType type)
bool FLevelLocals::EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay, DAnimatedDoor::EADType type)
{
sector_t *sec;
int secnum;
@ -781,16 +780,16 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay,
FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top));
if (anim != NULL)
{
Create<DAnimatedDoor>(sec, line, speed, delay, anim, type);
CreateThinker<DAnimatedDoor>(sec, line, speed, delay, anim, type);
return true;
}
return false;
}
FSectorTagIterator it(tag);
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
if (sec->ceilingdata != NULL)
{
continue;
@ -806,7 +805,7 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay,
if (anim != NULL)
{
rtn = true;
Create<DAnimatedDoor>(sec, line, speed, delay, anim, type);
CreateThinker<DAnimatedDoor>(sec, line, speed, delay, anim, type);
break;
}
}

87
src/g_shared/a_doors.h Normal file
View file

@ -0,0 +1,87 @@
#pragma once
//
// P_DOORS
//
class DDoor : public DMovingCeiling
{
DECLARE_CLASS (DDoor, DMovingCeiling)
public:
enum EVlDoor
{
doorClose,
doorOpen,
doorRaise,
doorWaitRaise,
doorCloseWaitOpen,
doorWaitClose,
};
void Construct(sector_t *sector);
void Construct(sector_t *sec, EVlDoor type, double speed, int delay, int lightTag, int topcountdown);
void Serialize(FSerializer &arc);
void Tick ();
protected:
EVlDoor m_Type;
double m_TopDist;
double m_BotDist, m_OldFloorDist;
vertex_t *m_BotSpot;
double m_Speed;
// 1 = up, 0 = waiting at top, -1 = down
int m_Direction;
// tics to wait at the top
int m_TopWait;
// (keep in case a door going down is reset)
// when it reaches 0, start going down
int m_TopCountdown;
int m_LightTag;
void DoorSound (bool raise, class DSeqNode *curseq=NULL) const;
private:
friend struct FLevelLocals;
};
class DAnimatedDoor : public DMovingCeiling
{
DECLARE_CLASS (DAnimatedDoor, DMovingCeiling)
public:
enum EADType
{
adOpenClose,
adClose
};
void Construct(sector_t *sector);
void Construct(sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim, EADType type);
void Serialize(FSerializer &arc);
void Tick ();
bool StartClosing ();
protected:
line_t *m_Line1, *m_Line2;
int m_Frame;
FDoorAnimation *m_DoorAnim;
int m_Timer;
double m_BotDist;
int m_Status;
int m_Type;
enum
{
Opening,
Waiting,
Closing,
Dead
};
int m_Speed;
int m_Delay;
bool m_SetBlocking1, m_SetBlocking2;
friend struct FLevelLocals;
};

View file

@ -69,28 +69,8 @@ static FMemArena DynLightArena(sizeof(FDynamicLight) * 200);
static TArray<FDynamicLight*> FreeList;
static FRandom randLight;
CUSTOM_CVAR (Bool, gl_lights, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (self) AActor::RecreateAllAttachedLights();
else AActor::DeleteAllAttachedLights();
}
extern TArray<FLightDefaults *> StateLights;
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(type, S, DynamicLight)
{
PROP_STRING_PARM(str, 0);
static const char * ltype_names[]={
"Point","Pulse","Flicker","Sector","RandomFlicker", "ColorPulse", "ColorFlicker", "RandomColorFlicker", nullptr};
static const int ltype_values[]={
PointLight, PulseLight, FlickerLight, SectorLight, RandomFlickerLight, ColorPulseLight, ColorFlickerLight, RandomColorFlickerLight };
int style = MatchString(str, ltype_names);
if (style < 0) I_Error("Unknown light type '%s'", str);
defaults->IntVar(NAME_lighttype) = ltype_values[style];
}
//==========================================================================
//
@ -98,7 +78,7 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight)
//
//==========================================================================
static FDynamicLight *GetLight()
static FDynamicLight *GetLight(FLevelLocals *Level)
{
FDynamicLight *ret;
if (FreeList.Size())
@ -107,11 +87,12 @@ static FDynamicLight *GetLight()
}
else ret = (FDynamicLight*)DynLightArena.Alloc(sizeof(FDynamicLight));
memset(ret, 0, sizeof(*ret));
ret->next = level.lights;
level.lights = ret;
ret->next = Level->lights;
Level->lights = ret;
if (ret->next) ret->next->prev = ret;
ret->visibletoplayer = true;
ret->mShadowmapIndex = 1024;
ret->Level = Level;
ret->Pos.X = -10000000; // not a valid coordinate.
return ret;
}
@ -126,7 +107,7 @@ static FDynamicLight *GetLight()
void AttachLight(AActor *self)
{
auto light = GetLight();
auto light = GetLight(self->Level);
light->pSpotInnerAngle = &self->AngleVar(NAME_SpotInnerAngle);
light->pSpotOuterAngle = &self->AngleVar(NAME_SpotOuterAngle);
@ -219,9 +200,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(ADynamicLight, SetOffset, SetOffset)
void FDynamicLight::ReleaseLight()
{
assert(prev != nullptr || this == level.lights);
assert(prev != nullptr || this == Level->lights);
if (prev != nullptr) prev->next = next;
else level.lights = next;
else Level->lights = next;
if (next != nullptr) next->prev = prev;
next = prev = nullptr;
FreeList.Push(this);
@ -243,7 +224,7 @@ void FDynamicLight::Activate()
{
float pulseTime = float(specialf1 / TICRATE);
m_lastUpdate = level.maptime;
m_lastUpdate = Level->maptime;
if (!swapped) m_cycler.SetParams(float(GetSecondaryIntensity()), float(GetIntensity()), pulseTime);
else m_cycler.SetParams(float(GetIntensity()), float(GetSecondaryIntensity()), pulseTime);
m_cycler.ShouldCycle(true);
@ -292,9 +273,9 @@ void FDynamicLight::Tick()
{
case PulseLight:
{
float diff = (level.maptime - m_lastUpdate) / (float)TICRATE;
float diff = (Level->maptime - m_lastUpdate) / (float)TICRATE;
m_lastUpdate = level.maptime;
m_lastUpdate = Level->maptime;
m_cycler.Update(diff);
m_currentRadius = float(m_cycler.GetVal());
break;
@ -501,9 +482,9 @@ static FLightNode * DeleteLightNode(FLightNode * node)
tn=node->nextTarget;
delete node;
return(tn);
}
}
return(nullptr);
} // phares 3/13/98
}
@ -588,7 +569,7 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section,
line_t *other = port->mDestination;
if (other->validcount != ::validcount)
{
subsector_t *othersub = R_PointInSubsector(other->v1->fPos() + other->Delta() / 2);
subsector_t *othersub = Level->PointInRenderSubsector(other->v1->fPos() + other->Delta() / 2);
FSection *othersect = othersub->section;
if (othersect->validcount != ::validcount)
{
@ -639,7 +620,7 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section,
if (sec->GetPortalPlaneZ(sector_t::ceiling) < Z() + radius)
{
DVector2 refpos = other->v1->fPos() + other->Delta() / 2 + sec->GetPortalDisplacement(sector_t::ceiling);
subsector_t *othersub = R_PointInSubsector(refpos);
subsector_t *othersub = Level->PointInRenderSubsector(refpos);
FSection *othersect = othersub->section;
if (othersect->validcount != dl_validcount)
{
@ -654,7 +635,7 @@ void FDynamicLight::CollectWithinRadius(const DVector3 &opos, FSection *section,
if (sec->GetPortalPlaneZ(sector_t::floor) > Z() - radius)
{
DVector2 refpos = other->v1->fPos() + other->Delta() / 2 + sec->GetPortalDisplacement(sector_t::floor);
subsector_t *othersub = R_PointInSubsector(refpos);
subsector_t *othersub = Level->PointInRenderSubsector(refpos);
FSection *othersect = othersub->section;
if (othersect->validcount != dl_validcount)
{
@ -694,7 +675,7 @@ void FDynamicLight::LinkLight()
if (radius>0)
{
// passing in radius*radius allows us to do a distance check without any calls to sqrt
FSection *sect = R_PointInSubsector(Pos)->section;
FSection *sect = Level->PointInRenderSubsector(Pos)->section;
dl_validcount++;
::validcount++;
@ -758,7 +739,7 @@ void AActor::AttachLight(unsigned int count, const FLightDefaults *lightdef)
}
else
{
light = GetLight();
light = GetLight(Level);
light->SetActor(this, true);
AttachedLights.Push(light);
}
@ -770,7 +751,6 @@ void AActor::AttachLight(unsigned int count, const FLightDefaults *lightdef)
// per-state light adjustment
//
//==========================================================================
extern TArray<FLightDefaults *> StateLights;
void AActor::SetDynamicLights()
{
@ -830,9 +810,9 @@ void AActor::DeleteAttachedLights()
//
//==========================================================================
void AActor::DeleteAllAttachedLights()
void FLevelLocals::DeleteAllAttachedLights()
{
TThinkerIterator<AActor> it;
auto it = GetThinkerIterator<AActor>();
AActor * a;
while ((a=it.Next()))
@ -847,9 +827,9 @@ void AActor::DeleteAllAttachedLights()
//
//==========================================================================
void AActor::RecreateAllAttachedLights()
void FLevelLocals::RecreateAllAttachedLights()
{
TThinkerIterator<AActor> it;
auto it = GetThinkerIterator<AActor>();
AActor * a;
while ((a=it.Next()))
@ -869,60 +849,3 @@ void AActor::RecreateAllAttachedLights()
}
}
//==========================================================================
//
// CCMDs
//
//==========================================================================
CCMD(listlights)
{
int walls, sectors;
int allwalls=0, allsectors=0, allsubsecs = 0;
int i=0, shadowcount = 0;
FDynamicLight * dl;
for (dl = level.lights; dl; dl = dl->next)
{
walls=0;
sectors=0;
Printf("%s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f %s %s",
dl->target->GetClass()->TypeName.GetChars(),
dl->X(), dl->Y(), dl->Z(), dl->GetRed(), dl->GetGreen(), dl->GetBlue(),
dl->radius, dl->IsAttenuated()? "attenuated" : "", dl->shadowmapped? "shadowmapped" : "");
i++;
shadowcount += dl->shadowmapped;
if (dl->target)
{
FTextureID spr = sprites[dl->target->sprite].GetSpriteFrame(dl->target->frame, 0, 0., nullptr);
Printf(", frame = %s ", TexMan.GetTexture(spr)->GetName().GetChars());
}
FLightNode * node;
node=dl->touching_sides;
while (node)
{
walls++;
allwalls++;
node = node->nextTarget;
}
node = dl->touching_sector;
while (node)
{
allsectors++;
sectors++;
node = node->nextTarget;
}
Printf("- %d walls, %d sectors\n", walls, sectors);
}
Printf("%i dynamic lights, %d shadowmapped, %d walls, %d sectors\n\n\n", i, shadowcount, allwalls, allsectors);
}

View file

@ -4,9 +4,6 @@
#include "cycler.h"
#include "g_levellocals.h"
EXTERN_CVAR(Bool, r_dynlights)
EXTERN_CVAR(Bool, gl_lights)
struct side_t;
struct seg_t;
@ -75,7 +72,7 @@ public:
void SetSpot(bool spot) { if (spot) m_lightFlags |= LF_SPOT; else m_lightFlags &= ~LF_SPOT; }
void SetSpotInnerAngle(double angle) { m_spotInnerAngle = angle; }
void SetSpotOuterAngle(double angle) { m_spotOuterAngle = angle; }
static void SetAttenuationForLevel();
static void SetAttenuationForLevel(bool);
void OrderIntensities()
{
@ -169,7 +166,7 @@ struct FDynamicLight
inline DVector3 PosRelative(int portalgroup) const
{
return Pos + level.Displacements.getOffset(Sector->PortalGroup, portalgroup);
return Pos + Level->Displacements.getOffset(Sector->PortalGroup, portalgroup);
}
bool ShouldLightActor(AActor *check)
@ -232,6 +229,7 @@ public:
double specialf1;
FDynamicLight *next, *prev;
sector_t *Sector;
FLevelLocals *Level;
TObjPtr<AActor *> target;
FLightNode * touching_sides;
FLightNode * touching_sector;

View file

@ -43,16 +43,30 @@ IMPLEMENT_POINTERS_START(DFlashFader)
IMPLEMENT_POINTER(ForWho)
IMPLEMENT_POINTERS_END
DFlashFader::DFlashFader (float r1, float g1, float b1, float a1,
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::Construct (float r1, float g1, float b1, float a1,
float r2, float g2, float b2, float a2,
float time, AActor *who, bool terminate)
: TotalTics ((int)(time*TICRATE)), RemainingTics(TotalTics), ForWho (who)
{
TotalTics = (int)(time*TICRATE);
RemainingTics = TotalTics;
ForWho = who;
Blends[0][0]=r1; Blends[0][1]=g1; Blends[0][2]=b1; Blends[0][3]=a1;
Blends[1][0]=r2; Blends[1][1]=g2; Blends[1][2]=b2; Blends[1][3]=a2;
Terminate = terminate;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::OnDestroy ()
{
if (Terminate) Blends[1][3] = 0.f; // Needed in order to cancel out the secondary fade.
@ -60,6 +74,12 @@ void DFlashFader::OnDestroy ()
Super::OnDestroy();
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -69,6 +89,12 @@ void DFlashFader::Serialize(FSerializer &arc)
.Array("blends", Blends[0], 8);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::Tick ()
{
if (ForWho == NULL || ForWho->player == NULL)
@ -85,6 +111,12 @@ void DFlashFader::Tick ()
SetBlend (1.f - (float)RemainingTics / (float)TotalTics);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::SetBlend (float time)
{
if (ForWho == NULL || ForWho->player == NULL)
@ -99,6 +131,12 @@ void DFlashFader::SetBlend (float time)
player->BlendA = Blends[0][3]*iT + Blends[1][3]*time;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DFlashFader::Cancel ()
{
RemainingTics = 0;

View file

@ -73,10 +73,6 @@ static void StartFloorSound (sector_t *sec)
IMPLEMENT_CLASS(DFloor, false, false)
DFloor::DFloor ()
{
}
void DFloor::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -192,19 +188,19 @@ void DFloor::Tick ()
sector_t *sec = m_Sector;
sec->stairlock = -1; // thinker done, promote lock to -1
while (sec->prevsec != -1 && level.sectors[sec->prevsec].stairlock != -2)
sec = &level.sectors[sec->prevsec]; // search for a non-done thinker
while (sec->prevsec != -1 && Level->sectors[sec->prevsec].stairlock != -2)
sec = &Level->sectors[sec->prevsec]; // search for a non-done thinker
if (sec->prevsec == -1) // if all thinkers previous are done
{
sec = m_Sector; // search forward
while (sec->nextsec != -1 && level.sectors[sec->nextsec].stairlock != -2)
sec = &level.sectors[sec->nextsec];
while (sec->nextsec != -1 && Level->sectors[sec->nextsec].stairlock != -2)
sec = &Level->sectors[sec->nextsec];
if (sec->nextsec == -1) // if all thinkers ahead are done too
{
while (sec->prevsec != -1) // clear all locks
{
sec->stairlock = 0;
sec = &level.sectors[sec->prevsec];
sec = &Level->sectors[sec->prevsec];
}
sec->stairlock = 0;
}
@ -259,9 +255,9 @@ void DFloor::StartFloorSound ()
//
//==========================================================================
DFloor::DFloor (sector_t *sec)
: DMovingFloor (sec)
void DFloor::Construct(sector_t *sec)
{
Super::Construct(sec);
}
//==========================================================================
@ -270,7 +266,7 @@ DFloor::DFloor (sector_t *sec)
//
//==========================================================================
bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
bool FLevelLocals::CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
double speed, double height, int crush, int change, bool hexencrush, bool hereticlower)
{
bool rtn;
@ -287,7 +283,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
// new floor thinker
rtn = true;
floor = Create<DFloor>(sec);
floor = CreateThinker<DFloor>(sec);
floor->m_Type = floortype;
floor->m_Crush = crush;
floor->m_Hexencrush = hexencrush;
@ -465,7 +461,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
// [Graf Zahl]
// Don't make sounds for instant movement hacks but make an exception for
// switches that activate their own back side.
if (!(i_compatflags & COMPATF_SILENT_INSTANT_FLOORS))
if (!(sec->Level->i_compatflags & COMPATF_SILENT_INSTANT_FLOORS))
{
if (!line || !(line->activation & (SPAC_Use | SPAC_Push)) || line->backsector != sec)
silent = true;
@ -502,9 +498,9 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
return true;
}
DEFINE_ACTION_FUNCTION(DFloor, CreateFloor)
DEFINE_ACTION_FUNCTION(FLevelLocals, CreateFloor)
{
PARAM_PROLOGUE;
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_POINTER_NOT_NULL(sec, sector_t);
PARAM_INT(floortype);
PARAM_POINTER(ln, line_t);
@ -514,7 +510,7 @@ DEFINE_ACTION_FUNCTION(DFloor, CreateFloor)
PARAM_INT(change);
PARAM_BOOL(hereticlower);
PARAM_BOOL(hexencrush);
ACTION_RETURN_BOOL(P_CreateFloor(sec, (DFloor::EFloor)floortype, ln, speed, height, crush, change, hexencrush, hereticlower));
ACTION_RETURN_BOOL(self->CreateFloor(sec, (DFloor::EFloor)floortype, ln, speed, height, crush, change, hexencrush, hereticlower));
}
//==========================================================================
@ -525,17 +521,17 @@ DEFINE_ACTION_FUNCTION(DFloor, CreateFloor)
//
//==========================================================================
bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
bool FLevelLocals::EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
double speed, double height, int crush, int change, bool hexencrush, bool hereticlower)
{
int secnum;
bool rtn = false;
// check if a manual trigger; if so do just the sector on the backside
FSectorTagIterator it(tag, line);
auto it = GetSectorTagIterator(tag, line);
while ((secnum = it.Next()) >= 0)
{
rtn |= P_CreateFloor(&level.sectors[secnum], floortype, line, speed, height, crush, change, hexencrush, hereticlower);
rtn |= CreateFloor(&sectors[secnum], floortype, line, speed, height, crush, change, hexencrush, hereticlower);
}
return rtn;
}
@ -548,13 +544,13 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
//
//==========================================================================
bool EV_FloorCrushStop (int tag, line_t *line)
bool FLevelLocals::EV_FloorCrushStop (int tag, line_t *line)
{
int secnum;
FSectorTagIterator it(tag, line);
auto it = GetSectorTagIterator(tag, line);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
sector_t *sec = &sectors[secnum];
if (sec->floordata && sec->floordata->IsKindOf (RUNTIME_CLASS(DFloor)) &&
barrier_cast<DFloor *>(sec->floordata)->m_Type == DFloor::floorRaiseAndCrush)
@ -568,17 +564,17 @@ bool EV_FloorCrushStop (int tag, line_t *line)
}
// same as above but stops any floor mover that was active on the given sector.
bool EV_StopFloor(int tag, line_t *line)
bool FLevelLocals::EV_StopFloor(int tag, line_t *line)
{
int sec;
FSectorTagIterator it(tag, line);
auto it = GetSectorTagIterator(tag, line);
while ((sec = it.Next()) >= 0)
{
if (level.sectors[sec].floordata)
if (sectors[sec].floordata)
{
SN_StopSequence(&level.sectors[sec], CHAN_FLOOR);
level.sectors[sec].floordata->Destroy();
level.sectors[sec].floordata = nullptr;
SN_StopSequence(&sectors[sec], CHAN_FLOOR);
sectors[sec].floordata->Destroy();
sectors[sec].floordata = nullptr;
}
}
return true;
@ -593,9 +589,7 @@ bool EV_StopFloor(int tag, line_t *line)
//
//==========================================================================
bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
double stairsize, double speed, int delay, int reset, int igntxt,
int usespecials)
bool FLevelLocals::EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, double stairsize, double speed, int delay, int reset, int igntxt, int usespecials)
{
int secnum = -1;
int osecnum; //jff 3/4/98 save old loop index
@ -619,13 +613,13 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
persteptime = int(stairsize / speed);
// check if a manual trigger, if so do just the sector on the backside
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
// The compatibility mode doesn't work with a hashing algorithm.
// It needs the original linear search method. This was broken in Boom.
bool compatible = tag != 0 && (i_compatflags & COMPATF_STAIRINDEX);
while ((secnum = itr.NextCompat(compatible, secnum)) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
//jff 2/26/98 add special lockout condition to wait for entire
@ -637,7 +631,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
// new floor thinker
rtn = true;
floor = Create<DFloor> (sec);
floor = CreateThinker<DFloor> (sec);
floor->m_Direction = (type == DFloor::buildUp) ? 1 : -1;
stairstep = stairsize * floor->m_Direction;
floor->m_Type = DFloor::buildStair; //jff 3/31/98 do not leave uninited
@ -740,7 +734,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
secnum = newsecnum;
// create and initialize a thinker for the next step
floor = Create<DFloor> (sec);
floor = CreateThinker<DFloor> (sec);
floor->StartFloorSound ();
floor->m_Direction = (type == DFloor::buildUp) ? 1 : -1;
floor->m_FloorDestDist = sec->floorplane.PointToDist (DVector2(0, 0), height);
@ -770,7 +764,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
} while (ok);
// [RH] make sure the first sector doesn't point to a previous one, otherwise
// it can infinite loop when the first sector stops moving.
level.sectors[osecnum].prevsec = -1;
sectors[osecnum].prevsec = -1;
}
return rtn;
}
@ -781,7 +775,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
//
//==========================================================================
bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
bool FLevelLocals::EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
{
sector_t* s1;
sector_t* s2;
@ -794,10 +788,10 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
rtn = false;
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
while ((secnum = itr.Next()) >= 0)
{
s1 = &level.sectors[secnum]; // s1 is pillar's sector
s1 = &sectors[secnum]; // s1 is pillar's sector
// ALREADY MOVING? IF SO, KEEP GOING...
if (s1->PlaneMoving(sector_t::floor))
@ -819,7 +813,7 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
s3 = ln->backsector;
// Spawn rising slime
floor = Create<DFloor> (s2);
floor = CreateThinker<DFloor> (s2);
floor->m_Type = DFloor::donutRaise;
floor->m_Crush = -1;
floor->m_Hexencrush = false;
@ -834,7 +828,7 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed)
floor->StartFloorSound ();
// Spawn lowering donut-hole
floor = Create<DFloor> (s1);
floor = CreateThinker<DFloor> (s1);
floor->m_Type = DFloor::floorLowerToNearest;
floor->m_Crush = -1;
floor->m_Hexencrush = false;
@ -864,13 +858,9 @@ IMPLEMENT_POINTERS_START(DElevator)
IMPLEMENT_POINTER(m_Interp_Ceiling)
IMPLEMENT_POINTERS_END
DElevator::DElevator ()
{
}
DElevator::DElevator (sector_t *sec)
: Super (sec)
void DElevator::Construct(sector_t *sec)
{
Super::Construct(sec);
sec->floordata = this;
sec->ceilingdata = this;
m_Interp_Floor = sec->SetInterpolation(sector_t::FloorMove, true);
@ -994,7 +984,7 @@ void DElevator::StartFloorSound ()
//
//==========================================================================
bool EV_DoElevator (line_t *line, DElevator::EElevator elevtype,
bool FLevelLocals::EV_DoElevator (line_t *line, DElevator::EElevator elevtype,
double speed, double height, int tag)
{
int secnum;
@ -1011,19 +1001,19 @@ bool EV_DoElevator (line_t *line, DElevator::EElevator elevtype,
secnum = -1;
rtn = false;
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
// act on all sectors with the same tag as the triggering linedef
while ((secnum = itr.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
// If either floor or ceiling is already activated, skip it
if (sec->PlaneMoving(sector_t::floor) || sec->ceilingdata) //jff 2/22/98
continue; // the loop used to break at the end if tag were 0, but would miss that step if "continue" occured [FDARI]
// create and initialize new elevator thinker
rtn = true;
elevator = Create<DElevator> (sec);
elevator = CreateThinker<DElevator> (sec);
elevator->m_Type = elevtype;
elevator->m_Speed = speed;
elevator->StartFloorSound ();
@ -1097,7 +1087,7 @@ bool EV_DoElevator (line_t *line, DElevator::EElevator elevtype,
//
//==========================================================================
bool EV_DoChange (line_t *line, EChange changetype, int tag)
bool FLevelLocals::EV_DoChange (line_t *line, EChange changetype, int tag)
{
int secnum;
bool rtn;
@ -1106,10 +1096,10 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
rtn = false;
// change all sectors with the same tag as the linedef
FSectorTagIterator it(tag);
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
rtn = true;
@ -1151,10 +1141,6 @@ IMPLEMENT_CLASS(DWaggleBase, false, false)
IMPLEMENT_CLASS(DFloorWaggle, false, false)
IMPLEMENT_CLASS(DCeilingWaggle, false, false)
DWaggleBase::DWaggleBase ()
{
}
void DWaggleBase::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -1178,9 +1164,9 @@ void DWaggleBase::Serialize(FSerializer &arc)
#define WGLSTATE_STABLE 2
#define WGLSTATE_REDUCE 3
DWaggleBase::DWaggleBase (sector_t *sec)
: Super (sec)
void DWaggleBase::Construct(sector_t *sec)
{
Super::Construct(sec);
}
//==========================================================================
@ -1266,13 +1252,9 @@ void DWaggleBase::DoWaggle (bool ceiling)
//
//==========================================================================
DFloorWaggle::DFloorWaggle ()
{
}
DFloorWaggle::DFloorWaggle (sector_t *sec)
: Super (sec)
void DFloorWaggle::Construct(sector_t *sec)
{
Super::Construct(sec);
sec->floordata = this;
interpolation = sec->SetInterpolation(sector_t::FloorMove, true);
}
@ -1288,13 +1270,9 @@ void DFloorWaggle::Tick ()
//
//==========================================================================
DCeilingWaggle::DCeilingWaggle ()
{
}
DCeilingWaggle::DCeilingWaggle (sector_t *sec)
: Super (sec)
void DCeilingWaggle::Construct(sector_t *sec)
{
Super::Construct(sec);
sec->ceilingdata = this;
interpolation = sec->SetInterpolation(sector_t::CeilingMove, true);
}
@ -1310,8 +1288,7 @@ void DCeilingWaggle::Tick ()
//
//==========================================================================
bool EV_StartWaggle (int tag, line_t *line, int height, int speed, int offset,
int timer, bool ceiling)
bool FLevelLocals::EV_StartWaggle (int tag, line_t *line, int height, int speed, int offset, int timer, bool ceiling)
{
int sectorIndex;
sector_t *sector;
@ -1320,11 +1297,11 @@ bool EV_StartWaggle (int tag, line_t *line, int height, int speed, int offset,
retCode = false;
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
while ((sectorIndex = itr.Next()) >= 0)
{
sector = &level.sectors[sectorIndex];
sector = &sectors[sectorIndex];
if ((!ceiling && sector->PlaneMoving(sector_t::floor)) ||
(ceiling && sector->PlaneMoving(sector_t::ceiling)))
{ // Already busy with another thinker
@ -1333,12 +1310,12 @@ bool EV_StartWaggle (int tag, line_t *line, int height, int speed, int offset,
retCode = true;
if (ceiling)
{
waggle = Create<DCeilingWaggle> (sector);
waggle = CreateThinker<DCeilingWaggle> (sector);
waggle->m_OriginalDist = sector->ceilingplane.fD();
}
else
{
waggle = Create<DFloorWaggle> (sector);
waggle = CreateThinker<DFloorWaggle> (sector);
waggle->m_OriginalDist = sector->floorplane.fD();
}
waggle->m_Accumulator = offset;

173
src/g_shared/a_floor.h Normal file
View file

@ -0,0 +1,173 @@
#pragma once
//
// P_FLOOR
//
class DFloor : public DMovingFloor
{
DECLARE_CLASS (DFloor, DMovingFloor)
public:
enum EFloor
{
floorLowerToLowest,
floorLowerToNearest,
floorLowerToHighest,
floorLowerByValue,
floorRaiseByValue,
floorRaiseToHighest,
floorRaiseToNearest,
floorRaiseAndCrush,
floorRaiseAndCrushDoom,
floorCrushStop,
floorLowerInstant,
floorRaiseInstant,
floorMoveToValue,
floorRaiseToLowestCeiling,
floorRaiseByTexture,
floorLowerAndChange,
floorRaiseAndChange,
floorRaiseToLowest,
floorRaiseToCeiling,
floorLowerToLowestCeiling,
floorLowerByTexture,
floorLowerToCeiling,
donutRaise,
buildStair,
waitStair,
resetStair,
// Not to be used as parameters to EV_DoFloor()
genFloorChg0,
genFloorChgT,
genFloorChg
};
// [RH] Changed to use Hexen-ish specials
enum EStair
{
buildUp,
buildDown
};
enum EStairType
{
stairUseSpecials = 1,
stairSync = 2,
stairCrush = 4,
};
void Construct(sector_t *sec);
void Serialize(FSerializer &arc);
void Tick ();
//protected:
EFloor m_Type;
int m_Crush;
bool m_Hexencrush;
bool m_Instant;
int m_Direction;
secspecial_t m_NewSpecial{};
FTextureID m_Texture;
double m_FloorDestDist;
double m_Speed;
// [RH] New parameters used to reset and delay stairs
double m_OrgDist;
int m_ResetCount;
int m_Delay;
int m_PauseTime;
int m_StepTime;
int m_PerStepTime;
void StartFloorSound ();
void SetFloorChangeType (sector_t *sec, int change);
friend struct FLevelLocals;
};
class DElevator : public DMover
{
DECLARE_CLASS (DElevator, DMover)
HAS_OBJECT_POINTERS
public:
enum EElevator
{
elevateUp,
elevateDown,
elevateCurrent,
// [RH] For FloorAndCeiling_Raise/Lower
elevateRaise,
elevateLower
};
void Construct(sector_t *sec);
void OnDestroy() override;
void Serialize(FSerializer &arc);
void Tick ();
protected:
EElevator m_Type;
int m_Direction;
double m_FloorDestDist;
double m_CeilingDestDist;
double m_Speed;
TObjPtr<DInterpolation*> m_Interp_Ceiling;
TObjPtr<DInterpolation*> m_Interp_Floor;
void StartFloorSound ();
friend struct FLevelLocals;
};
class DWaggleBase : public DMover
{
DECLARE_CLASS (DWaggleBase, DMover)
HAS_OBJECT_POINTERS
public:
void Construct(sector_t *sec);
void Serialize(FSerializer &arc);
protected:
double m_OriginalDist;
double m_Accumulator;
double m_AccDelta;
double m_TargetScale;
double m_Scale;
double m_ScaleDelta;
int m_Ticker;
int m_State;
friend struct FLevelLocals;
void DoWaggle (bool ceiling);
};
class DFloorWaggle : public DWaggleBase
{
DECLARE_CLASS (DFloorWaggle, DWaggleBase)
public:
void Construct(sector_t *sec);
void Tick ();
};
class DCeilingWaggle : public DWaggleBase
{
DECLARE_CLASS (DCeilingWaggle, DWaggleBase)
public:
void Construct(sector_t *sec);
void Tick ();
};
//jff 3/15/98 pure texture/type change for better generalized support
enum EChange
{
trigChangeOnly,
numChangeOnly,
};

View file

@ -41,14 +41,19 @@ static FRandom pr_lightning ("Lightning");
IMPLEMENT_CLASS(DLightningThinker, false, false)
DLightningThinker::DLightningThinker ()
: DThinker (STAT_LIGHTNING)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DLightningThinker::Construct()
{
Stopped = false;
LightningFlashCount = 0;
NextLightningFlash = ((pr_lightning()&15)+5)*35; // don't flash at level start
LightningLightLevels.Resize(level.sectors.Size());
LightningLightLevels.Resize(Level->sectors.Size());
fillshort(&LightningLightLevels[0], LightningLightLevels.Size(), SHRT_MAX);
}
@ -56,6 +61,12 @@ DLightningThinker::~DLightningThinker ()
{
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DLightningThinker::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -65,6 +76,12 @@ void DLightningThinker::Serialize(FSerializer &arc)
("levels", LightningLightLevels);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DLightningThinker::Tick ()
{
if (!NextLightningFlash || LightningFlashCount)
@ -78,6 +95,12 @@ void DLightningThinker::Tick ()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DLightningThinker::LightningFlash ()
{
int i, j;
@ -89,8 +112,8 @@ void DLightningThinker::LightningFlash ()
LightningFlashCount--;
if (LightningFlashCount)
{ // reduce the brightness of the flash
tempSec = &level.sectors[0];
for (i = level.sectors.Size(), 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,
@ -105,24 +128,24 @@ void DLightningThinker::LightningFlash ()
}
else
{ // remove the alternate lightning flash special
tempSec = &level.sectors[0];
for (i = level.sectors.Size(), 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], level.sectors.Size(), SHRT_MAX);
level.flags &= ~LEVEL_SWAPSKIES;
fillshort(&LightningLightLevels[0], Level->sectors.Size(), SHRT_MAX);
Level->flags &= ~LEVEL_SWAPSKIES;
}
return;
}
LightningFlashCount = (pr_lightning()&7)+8;
flashLight = 200+(pr_lightning()&31);
tempSec = &level.sectors[0];
for (i = level.sectors.Size(), j = 0; i > 0; ++j, --i, ++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;
@ -152,12 +175,12 @@ void DLightningThinker::LightningFlash ()
}
}
level.flags |= LEVEL_SWAPSKIES; // set alternate sky
Level->flags |= LEVEL_SWAPSKIES; // set alternate sky
S_Sound (CHAN_AUTO, "world/thunder", 1.0, ATTN_NONE);
// [ZZ] just in case
E_WorldLightning();
Level->localEventManager->WorldLightning();
// start LIGHTNING scripts
level.Behaviors.StartTypedScripts (SCRIPT_Lightning, NULL, false); // [RH] Run lightning scripts
Level->Behaviors.StartTypedScripts (SCRIPT_Lightning, NULL, false); // [RH] Run lightning scripts
// Calculate the next lighting flash
if (!NextLightningFlash)
@ -168,7 +191,7 @@ void DLightningThinker::LightningFlash ()
}
else
{
if (pr_lightning() < 128 && !(level.time&32))
if (pr_lightning() < 128 && !(Level->time&32))
{
NextLightningFlash = ((pr_lightning()&7)+2)*35;
}
@ -180,6 +203,12 @@ void DLightningThinker::LightningFlash ()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void DLightningThinker::ForceLightning (int mode)
{
switch (mode)
@ -197,22 +226,34 @@ void DLightningThinker::ForceLightning (int mode)
}
}
static DLightningThinker *LocateLightning ()
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static DLightningThinker *LocateLightning (FLevelLocals *Level)
{
TThinkerIterator<DLightningThinker> iterator (STAT_LIGHTNING);
auto iterator = Level->GetThinkerIterator<DLightningThinker>(NAME_None, STAT_LIGHTNING);
return iterator.Next ();
}
void P_StartLightning ()
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FLevelLocals::StartLightning ()
{
const bool isOriginalHexen = (gameinfo.gametype == GAME_Hexen)
&& (level.flags2 & LEVEL2_HEXENHACK);
&& (flags2 & LEVEL2_HEXENHACK);
if (isOriginalHexen)
{
bool hasLightning = false;
for (const sector_t &sector : level.sectors)
for (const sector_t &sector : sectors)
{
hasLightning = sector.GetTexture(sector_t::ceiling) == skyflatnum
|| sector.special == Light_IndoorLightning1
@ -226,26 +267,32 @@ void P_StartLightning ()
if (!hasLightning)
{
level.flags &= ~LEVEL_STARTLIGHTNING;
flags &= ~LEVEL_STARTLIGHTNING;
return;
}
}
DLightningThinker *lightning = LocateLightning ();
if (lightning == NULL)
DLightningThinker *lightning = LocateLightning (this);
if (lightning == nullptr)
{
Create<DLightningThinker>();
CreateThinker<DLightningThinker>();
}
}
void P_ForceLightning (int mode)
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FLevelLocals::ForceLightning (int mode)
{
DLightningThinker *lightning = LocateLightning ();
if (lightning == NULL)
DLightningThinker *lightning = LocateLightning (this);
if (lightning == nullptr)
{
lightning = Create<DLightningThinker>();
lightning = CreateThinker<DLightningThinker>();
}
if (lightning != NULL)
if (lightning != nullptr)
{
lightning->ForceLightning (mode);
}

View file

@ -11,7 +11,8 @@ class DLightningThinker : public DThinker
{
DECLARE_CLASS (DLightningThinker, DThinker);
public:
DLightningThinker ();
static const int DEFAULT_STAT = STAT_LIGHTNING;
void Construct();
~DLightningThinker ();
void Serialize(FSerializer &arc);
void Tick ();
@ -27,7 +28,5 @@ protected:
TArray<short> LightningLightLevels;
};
void P_StartLightning ();
void P_ForceLightning (int mode);
#endif //__A_LIGHTNING_H__

View file

@ -37,6 +37,8 @@
#include "doomstat.h"
#include "p_maputl.h"
#include "g_levellocals.h"
#include "maploader/maploader.h"
#include "p_spec_thinkers.h"
// State.
#include "serializer.h"
@ -47,132 +49,6 @@ static FRandom pr_strobeflash ("StrobeFlash");
static FRandom pr_fireflicker ("FireFlicker");
class DFireFlicker : public DLighting
{
DECLARE_CLASS(DFireFlicker, DLighting)
public:
DFireFlicker(sector_t *sector);
DFireFlicker(sector_t *sector, int upper, int lower);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
private:
DFireFlicker();
};
class DFlicker : public DLighting
{
DECLARE_CLASS(DFlicker, DLighting)
public:
DFlicker(sector_t *sector, int upper, int lower);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
private:
DFlicker();
};
class DLightFlash : public DLighting
{
DECLARE_CLASS(DLightFlash, DLighting)
public:
DLightFlash(sector_t *sector);
DLightFlash(sector_t *sector, int min, int max);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
int m_MaxTime;
int m_MinTime;
private:
DLightFlash();
};
class DStrobe : public DLighting
{
DECLARE_CLASS(DStrobe, DLighting)
public:
DStrobe(sector_t *sector, int utics, int ltics, bool inSync);
DStrobe(sector_t *sector, int upper, int lower, int utics, int ltics);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MinLight;
int m_MaxLight;
int m_DarkTime;
int m_BrightTime;
private:
DStrobe();
};
class DGlow : public DLighting
{
DECLARE_CLASS(DGlow, DLighting)
public:
DGlow(sector_t *sector);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_MinLight;
int m_MaxLight;
int m_Direction;
private:
DGlow();
};
// [RH] Glow from Light_Glow and Light_Fade specials
class DGlow2 : public DLighting
{
DECLARE_CLASS(DGlow2, DLighting)
public:
DGlow2(sector_t *sector, int start, int end, int tics, bool oneshot);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Start;
int m_End;
int m_MaxTics;
int m_Tics;
bool m_OneShot;
private:
DGlow2();
};
// [RH] Phased light thinker
class DPhased : public DLighting
{
DECLARE_CLASS(DPhased, DLighting)
public:
DPhased(sector_t *sector);
DPhased(sector_t *sector, int baselevel, int phase);
// These are for internal use only but the Create template needs access to them.
DPhased();
DPhased(sector_t *sector, int baselevel);
void Serialize(FSerializer &arc);
void Tick();
protected:
uint8_t m_BaseLevel;
uint8_t m_Phase;
private:
int PhaseHelper(sector_t *sector, int index, int light, sector_t *prev);
};
#define GLOWSPEED 8
#define STROBEBRIGHT 5
#define FASTDARK 15
#define SLOWDARK TICRATE
//-----------------------------------------------------------------------------
//
//
@ -181,16 +57,6 @@ private:
IMPLEMENT_CLASS(DLighting, false, false)
DLighting::DLighting ()
{
}
DLighting::DLighting (sector_t *sector)
: DSectorEffect (sector)
{
ChangeStatNum (STAT_LIGHT);
}
//-----------------------------------------------------------------------------
//
// FIRELIGHT FLICKER
@ -199,10 +65,6 @@ DLighting::DLighting (sector_t *sector)
IMPLEMENT_CLASS(DFireFlicker, false, false)
DFireFlicker::DFireFlicker ()
{
}
void DFireFlicker::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -242,17 +104,17 @@ void DFireFlicker::Tick ()
//
//-----------------------------------------------------------------------------
DFireFlicker::DFireFlicker (sector_t *sector)
: DLighting (sector)
void DFireFlicker::Construct(sector_t *sector)
{
Super::Construct(sector);
m_MaxLight = sector->lightlevel;
m_MinLight = sector_t::ClampLight(FindMinSurroundingLight(sector, sector->lightlevel) + 16);
m_Count = 4;
}
DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower)
: DLighting (sector)
void DFireFlicker::Construct(sector_t *sector, int upper, int lower)
{
Super::Construct(sector);
m_MaxLight = sector_t::ClampLight(upper);
m_MinLight = sector_t::ClampLight(lower);
m_Count = 4;
@ -266,10 +128,6 @@ DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower)
IMPLEMENT_CLASS(DFlicker, false, false)
DFlicker::DFlicker ()
{
}
void DFlicker::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -308,32 +166,15 @@ void DFlicker::Tick ()
//
//-----------------------------------------------------------------------------
DFlicker::DFlicker (sector_t *sector, int upper, int lower)
: DLighting (sector)
void DFlicker::Construct(sector_t *sector, int upper, int lower)
{
Super::Construct(sector);
m_MaxLight = sector_t::ClampLight(upper);
m_MinLight = sector_t::ClampLight(lower);
sector->lightlevel = m_MaxLight;
m_Count = (pr_flicker()&64)+1;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void EV_StartLightFlickering (int tag, int upper, int lower)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
Create<DFlicker> (&level.sectors[secnum], upper, lower);
}
}
//-----------------------------------------------------------------------------
//
// BROKEN LIGHT FLASHING
@ -342,10 +183,6 @@ void EV_StartLightFlickering (int tag, int upper, int lower)
IMPLEMENT_CLASS(DLightFlash, false, false)
DLightFlash::DLightFlash ()
{
}
void DLightFlash::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -386,9 +223,9 @@ void DLightFlash::Tick ()
//
//-----------------------------------------------------------------------------
DLightFlash::DLightFlash (sector_t *sector)
: DLighting (sector)
void DLightFlash::Construct(sector_t *sector)
{
Super::Construct(sector);
// Find light levels like Doom.
m_MaxLight = sector->lightlevel;
m_MinLight = FindMinSurroundingLight (sector, sector->lightlevel);
@ -397,9 +234,9 @@ DLightFlash::DLightFlash (sector_t *sector)
m_Count = (pr_lightflash() & m_MaxTime) + 1;
}
DLightFlash::DLightFlash (sector_t *sector, int min, int max)
: DLighting (sector)
void DLightFlash::Construct (sector_t *sector, int min, int max)
{
Super::Construct(sector);
// Use specified light levels.
m_MaxLight = sector_t::ClampLight(max);
m_MinLight = sector_t::ClampLight(min);
@ -417,10 +254,6 @@ DLightFlash::DLightFlash (sector_t *sector, int min, int max)
IMPLEMENT_CLASS(DStrobe, false, false)
DStrobe::DStrobe ()
{
}
void DStrobe::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -460,9 +293,9 @@ void DStrobe::Tick ()
//
//-----------------------------------------------------------------------------
DStrobe::DStrobe (sector_t *sector, int upper, int lower, int utics, int ltics)
: DLighting (sector)
void DStrobe::Construct(sector_t *sector, int upper, int lower, int utics, int ltics)
{
Super::Construct(sector);
m_DarkTime = ltics;
m_BrightTime = utics;
m_MaxLight = sector_t::ClampLight(upper);
@ -476,9 +309,9 @@ DStrobe::DStrobe (sector_t *sector, int upper, int lower, int utics, int ltics)
//
//-----------------------------------------------------------------------------
DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync)
: DLighting (sector)
void DStrobe::Construct(sector_t *sector, int utics, int ltics, bool inSync)
{
Super::Construct(sector);
m_DarkTime = ltics;
m_BrightTime = utics;
@ -493,178 +326,7 @@ DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync)
//-----------------------------------------------------------------------------
//
// Start strobing lights (usually from a trigger)
// [RH] Made it more configurable.
//
//-----------------------------------------------------------------------------
void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
if (sec->lightingdata)
continue;
Create<DStrobe> (sec, upper, lower, utics, ltics);
}
}
void EV_StartLightStrobing (int tag, int utics, int ltics)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
if (sec->lightingdata)
continue;
Create<DStrobe> (sec, utics, ltics, false);
}
}
//-----------------------------------------------------------------------------
//
// TURN LINE'S TAG LIGHTS OFF
// [RH] Takes a tag instead of a line
//
//-----------------------------------------------------------------------------
void EV_TurnTagLightsOff (int tag)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sector = &level.sectors[secnum];
int min = sector->lightlevel;
for (auto ln : sector->Lines)
{
sector_t *tsec = getNextSector (ln, sector);
if (!tsec)
continue;
if (tsec->lightlevel < min)
min = tsec->lightlevel;
}
sector->SetLightLevel(min);
}
}
//-----------------------------------------------------------------------------
//
// TURN LINE'S TAG LIGHTS ON
// [RH] Takes a tag instead of a line
//
//-----------------------------------------------------------------------------
void EV_LightTurnOn (int tag, int bright)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sector = &level.sectors[secnum];
int tbright = bright; //jff 5/17/98 search for maximum PER sector
// bright = -1 means to search ([RH] Not 0)
// for highest light level
// surrounding sector
if (bright < 0)
{
for (auto ln : sector->Lines)
{
sector_t *temp = getNextSector(ln, sector);
if (!temp)
continue;
if (temp->lightlevel > tbright)
tbright = temp->lightlevel;
}
}
sector->SetLightLevel(tbright);
//jff 5/17/98 unless compatibility optioned
//then maximum near ANY tagged sector
if (i_compatflags & COMPATF_LIGHT)
{
bright = tbright;
}
}
}
//-----------------------------------------------------------------------------
//
// killough 10/98
//
// EV_LightTurnOnPartway
//
// Turn sectors tagged to line lights on to specified or max neighbor level
//
// Passed the tag of sector(s) to light and a light level fraction between 0 and 1.
// Sets the light to min on 0, max on 1, and interpolates in-between.
// Used for doors with gradual lighting effects.
//
//-----------------------------------------------------------------------------
void EV_LightTurnOnPartway (int tag, double frac)
{
frac = clamp(frac, 0., 1.);
// Search all sectors for ones with same tag as activating line
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *temp, *sector = &level.sectors[secnum];
int bright = 0, min = sector->lightlevel;
for (auto ln : sector->Lines)
{
if ((temp = getNextSector (ln, sector)) != nullptr)
{
if (temp->lightlevel > bright)
{
bright = temp->lightlevel;
}
if (temp->lightlevel < min)
{
min = temp->lightlevel;
}
}
}
sector->SetLightLevel(int(frac * bright + (1 - frac) * min));
}
}
//-----------------------------------------------------------------------------
//
// [RH] New function to adjust tagged sectors' light levels
// by a relative amount. Light levels are clipped to
// be within range for sector_t::lightlevel.
//
//-----------------------------------------------------------------------------
void EV_LightChange (int tag, int value)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
level.sectors[secnum].SetLightLevel(level.sectors[secnum].lightlevel + value);
}
}
//-----------------------------------------------------------------------------
//
// Spawn glowing light
@ -673,10 +335,6 @@ void EV_LightChange (int tag, int value)
IMPLEMENT_CLASS(DGlow, false, false)
DGlow::DGlow ()
{
}
void DGlow::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -693,6 +351,7 @@ void DGlow::Serialize(FSerializer &arc)
void DGlow::Tick ()
{
const int GLOWSPEED = 8;
int newlight = m_Sector->lightlevel;
switch (m_Direction)
@ -726,9 +385,9 @@ void DGlow::Tick ()
//
//-----------------------------------------------------------------------------
DGlow::DGlow (sector_t *sector)
: DLighting (sector)
void DGlow::Construct(sector_t *sector)
{
Super::Construct(sector);
m_MinLight = FindMinSurroundingLight (sector, sector->lightlevel);
m_MaxLight = sector->lightlevel;
m_Direction = -1;
@ -742,10 +401,6 @@ DGlow::DGlow (sector_t *sector)
IMPLEMENT_CLASS(DGlow2, false, false)
DGlow2::DGlow2 ()
{
}
void DGlow2::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -790,9 +445,9 @@ void DGlow2::Tick ()
//
//-----------------------------------------------------------------------------
DGlow2::DGlow2 (sector_t *sector, int start, int end, int tics, bool oneshot)
: DLighting (sector)
void DGlow2::Construct(sector_t *sector, int start, int end, int tics, bool oneshot)
{
Super::Construct(sector);
m_Start = sector_t::ClampLight(start);
m_End = sector_t::ClampLight(end);
m_MaxTics = tics;
@ -800,72 +455,6 @@ DGlow2::DGlow2 (sector_t *sector, int start, int end, int tics, bool oneshot)
m_OneShot = oneshot;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void EV_StartLightGlowing (int tag, int upper, int lower, int tics)
{
int secnum;
// If tics is non-positive, then we can't really do anything.
if (tics <= 0)
{
return;
}
if (upper < lower)
{
int temp = upper;
upper = lower;
lower = temp;
}
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
if (sec->lightingdata)
continue;
Create<DGlow2> (sec, upper, lower, tics, false);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void EV_StartLightFading (int tag, int value, int tics)
{
int secnum;
FSectorTagIterator it(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &level.sectors[secnum];
if (sec->lightingdata)
continue;
if (tics <= 0)
{
sec->SetLightLevel(value);
}
else
{
// No need to fade if lightlevel is already at desired value.
if (sec->lightlevel == value)
continue;
Create<DGlow2> (sec, sec->lightlevel, value, tics, true);
}
}
}
//-----------------------------------------------------------------------------
//
// [RH] Phased lighting ala Hexen, but implemented without the help of the Hexen source
@ -875,10 +464,6 @@ void EV_StartLightFading (int tag, int value, int tics)
IMPLEMENT_CLASS(DPhased, false, false)
DPhased::DPhased ()
{
}
void DPhased::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -934,7 +519,7 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev
m_BaseLevel = baselevel;
}
else
l = Create<DPhased> (sector, baselevel);
l = Level->CreateThinker<DPhased> (sector, baselevel);
int numsteps = PhaseHelper (sector->NextSpecialSector (
sector->special == LightSequenceSpecial1 ?
@ -954,26 +539,273 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev
//
//-----------------------------------------------------------------------------
DPhased::DPhased (sector_t *sector, int baselevel)
: DLighting (sector)
{
m_BaseLevel = baselevel;
}
DPhased::DPhased (sector_t *sector)
: DLighting (sector)
void DPhased::Propagate()
{
validcount++;
PhaseHelper (sector, 0, 0, NULL);
PhaseHelper (m_Sector, 0, 0, nullptr);
}
DPhased::DPhased (sector_t *sector, int baselevel, int phase)
: DLighting (sector)
void DPhased::Construct (sector_t *sector, int baselevel, int phase)
{
Super::Construct(sector);
m_BaseLevel = baselevel;
m_Phase = phase;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_StartLightFlickering(int tag, int upper, int lower)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
CreateThinker<DFlicker>(&sectors[secnum], upper, lower);
}
}
//-----------------------------------------------------------------------------
//
// Start strobing lights (usually from a trigger)
// [RH] Made it more configurable.
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_StartLightStrobing(int tag, int upper, int lower, int utics, int ltics)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &sectors[secnum];
if (sec->lightingdata)
continue;
CreateThinker<DStrobe>(sec, upper, lower, utics, ltics);
}
}
void FLevelLocals::EV_StartLightStrobing(int tag, int utics, int ltics)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &sectors[secnum];
if (sec->lightingdata)
continue;
CreateThinker<DStrobe>(sec, utics, ltics, false);
}
}
//-----------------------------------------------------------------------------
//
// TURN LINE'S TAG LIGHTS OFF
// [RH] Takes a tag instead of a line
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_TurnTagLightsOff(int tag)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sector = &sectors[secnum];
int min = sector->lightlevel;
for (auto ln : sector->Lines)
{
sector_t *tsec = getNextSector(ln, sector);
if (!tsec)
continue;
if (tsec->lightlevel < min)
min = tsec->lightlevel;
}
sector->SetLightLevel(min);
}
}
//-----------------------------------------------------------------------------
//
// TURN LINE'S TAG LIGHTS ON
// [RH] Takes a tag instead of a line
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_LightTurnOn(int tag, int bright)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sector = &sectors[secnum];
int tbright = bright; //jff 5/17/98 search for maximum PER sector
// bright = -1 means to search ([RH] Not 0)
// for highest light level
// surrounding sector
if (bright < 0)
{
for (auto ln : sector->Lines)
{
sector_t *temp = getNextSector(ln, sector);
if (!temp)
continue;
if (temp->lightlevel > tbright)
tbright = temp->lightlevel;
}
}
sector->SetLightLevel(tbright);
//jff 5/17/98 unless compatibility optioned
//then maximum near ANY tagged sector
if (i_compatflags & COMPATF_LIGHT)
{
bright = tbright;
}
}
}
//-----------------------------------------------------------------------------
//
// killough 10/98
//
// EV_LightTurnOnPartway
//
// Turn sectors tagged to line lights on to specified or max neighbor level
//
// Passed the tag of sector(s) to light and a light level fraction between 0 and 1.
// Sets the light to min on 0, max on 1, and interpolates in-between.
// Used for doors with gradual lighting effects.
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_LightTurnOnPartway(int tag, double frac)
{
frac = clamp(frac, 0., 1.);
// Search all sectors for ones with same tag as activating line
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *temp, *sector = &sectors[secnum];
int bright = 0, min = sector->lightlevel;
for (auto ln : sector->Lines)
{
if ((temp = getNextSector(ln, sector)) != nullptr)
{
if (temp->lightlevel > bright)
{
bright = temp->lightlevel;
}
if (temp->lightlevel < min)
{
min = temp->lightlevel;
}
}
}
sector->SetLightLevel(int(frac * bright + (1 - frac) * min));
}
}
//-----------------------------------------------------------------------------
//
// [RH] New function to adjust tagged sectors' light levels
// by a relative amount. Light levels are clipped to
// be within range for sector_t::light
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_LightChange(int tag, int value)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sectors[secnum].SetLightLevel(sectors[secnum].lightlevel + value);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_StartLightGlowing(int tag, int upper, int lower, int tics)
{
int secnum;
// If tics is non-positive, then we can't really do anything.
if (tics <= 0)
{
return;
}
if (upper < lower)
{
int temp = upper;
upper = lower;
lower = temp;
}
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &sectors[secnum];
if (sec->lightingdata)
continue;
CreateThinker<DGlow2>(sec, upper, lower, tics, false);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FLevelLocals::EV_StartLightFading(int tag, int value, int tics)
{
int secnum;
auto it = GetSectorTagIterator(tag);
while ((secnum = it.Next()) >= 0)
{
sector_t *sec = &sectors[secnum];
if (sec->lightingdata)
continue;
if (tics <= 0)
{
sec->SetLightLevel(value);
}
else
{
// No need to fade if lightlevel is already at desired value.
if (sec->lightlevel == value)
continue;
CreateThinker<DGlow2>(sec, sec->lightlevel, value, tics, true);
}
}
}
//============================================================================
//
// EV_StopLightEffect
@ -982,14 +814,14 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase)
//
//============================================================================
void EV_StopLightEffect (int tag)
void FLevelLocals::EV_StopLightEffect (int tag)
{
TThinkerIterator<DLighting> iterator;
auto iterator = GetThinkerIterator<DLighting>(NAME_None, STAT_LIGHTNING);
DLighting *effect;
while ((effect = iterator.Next()) != NULL)
while ((effect = iterator.Next()) != nullptr)
{
if (tagManager.SectorHasTag(effect->GetSector(), tag))
if (SectorHasTag(effect->GetSector(), tag))
{
effect->Destroy();
}
@ -997,61 +829,3 @@ void EV_StopLightEffect (int tag)
}
void P_SpawnLights(sector_t *sector)
{
switch (sector->special)
{
case Light_Phased:
Create<DPhased>(sector, 48, 63 - (sector->lightlevel & 63));
break;
// [RH] Hexen-like phased lighting
case LightSequenceStart:
Create<DPhased>(sector);
break;
case dLight_Flicker:
Create<DLightFlash>(sector);
break;
case dLight_StrobeFast:
Create<DStrobe>(sector, STROBEBRIGHT, FASTDARK, false);
break;
case dLight_StrobeSlow:
Create<DStrobe>(sector, STROBEBRIGHT, SLOWDARK, false);
break;
case dLight_Strobe_Hurt:
Create<DStrobe>(sector, STROBEBRIGHT, FASTDARK, false);
break;
case dLight_Glow:
Create<DGlow>(sector);
break;
case dLight_StrobeSlowSync:
Create<DStrobe>(sector, STROBEBRIGHT, SLOWDARK, true);
break;
case dLight_StrobeFastSync:
Create<DStrobe>(sector, STROBEBRIGHT, FASTDARK, true);
break;
case dLight_FireFlicker:
Create<DFireFlicker>(sector);
break;
case dScroll_EastLavaDamage:
Create<DStrobe>(sector, STROBEBRIGHT, FASTDARK, false);
break;
case sLight_Strobe_Hurt:
Create<DStrobe>(sector, STROBEBRIGHT, FASTDARK, false);
break;
default:
break;
}
}

115
src/g_shared/a_lights.h Normal file
View file

@ -0,0 +1,115 @@
#pragma once
class DLighting : public DSectorEffect
{
DECLARE_CLASS(DLighting, DSectorEffect)
public:
static const int DEFAULT_STAT = STAT_LIGHT;
};
class DFireFlicker : public DLighting
{
DECLARE_CLASS(DFireFlicker, DLighting)
public:
void Construct(sector_t *sector);
void Construct(sector_t *sector, int upper, int lower);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
};
class DFlicker : public DLighting
{
DECLARE_CLASS(DFlicker, DLighting)
public:
void Construct(sector_t *sector, int upper, int lower);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
};
class DLightFlash : public DLighting
{
DECLARE_CLASS(DLightFlash, DLighting)
public:
void Construct(sector_t *sector);
void Construct(sector_t *sector, int min, int max);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MaxLight;
int m_MinLight;
int m_MaxTime;
int m_MinTime;
};
class DStrobe : public DLighting
{
DECLARE_CLASS(DStrobe, DLighting)
public:
void Construct(sector_t *sector, int utics, int ltics, bool inSync);
void Construct(sector_t *sector, int upper, int lower, int utics, int ltics);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Count;
int m_MinLight;
int m_MaxLight;
int m_DarkTime;
int m_BrightTime;
};
class DGlow : public DLighting
{
DECLARE_CLASS(DGlow, DLighting)
public:
void Construct(sector_t *sector);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_MinLight;
int m_MaxLight;
int m_Direction;
};
// [RH] Glow from Light_Glow and Light_Fade specials
class DGlow2 : public DLighting
{
DECLARE_CLASS(DGlow2, DLighting)
public:
void Construct(sector_t *sector, int start, int end, int tics, bool oneshot);
void Serialize(FSerializer &arc);
void Tick();
protected:
int m_Start;
int m_End;
int m_MaxTics;
int m_Tics;
bool m_OneShot;
};
// [RH] Phased light thinker
class DPhased : public DLighting
{
DECLARE_CLASS(DPhased, DLighting)
public:
void Construct(sector_t *sector, int baselevel = 0, int phase = 0);
// These are for internal use only but the Create template needs access to them.
void Construct();
void Propagate();
void Serialize(FSerializer &arc);
void Tick();
protected:
uint8_t m_BaseLevel;
uint8_t m_Phase;
private:
int PhaseHelper(sector_t *sector, int index, int light, sector_t *prev);
};

View file

@ -0,0 +1,184 @@
/*
** a_lighttransfer.cpp
**
**---------------------------------------------------------------------------
** Copyright 1998-2016 Randy Heit
** Copyright 2003-2018 Christoph 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 "p_spec.h"
#include "a_lighttransfer.h"
#include "serializer.h"
#include "g_levellocals.h"
//
// SPECIAL SPAWNING
//
IMPLEMENT_CLASS(DLightTransfer, false, false)
void DLightTransfer::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("lastlight", LastLight)
("source", Source)
("targettag", TargetTag)
("copyfloor", CopyFloor);
}
void DLightTransfer::Construct(sector_t *srcSec, int target, bool copyFloor)
{
int secnum;
Source = srcSec;
TargetTag = target;
CopyFloor = copyFloor;
DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor);
if (copyFloor)
{
auto itr = Level->GetSectorTagIterator(target);
while ((secnum = itr.Next()) >= 0)
Level->sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
}
else
{
auto itr = Level->GetSectorTagIterator(target);
while ((secnum = itr.Next()) >= 0)
Level->sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
}
}
void DLightTransfer::Tick ()
{
int light = Source->lightlevel;
if (light != LastLight)
{
LastLight = light;
DoTransfer (light, TargetTag, CopyFloor);
}
}
void DLightTransfer::DoTransfer (int llevel, int target, bool floor)
{
int secnum;
if (floor)
{
auto itr = Level->GetSectorTagIterator(target);
while ((secnum = itr.Next()) >= 0)
Level->sectors[secnum].SetPlaneLight(sector_t::floor, llevel);
}
else
{
auto itr = Level->GetSectorTagIterator(target);
while ((secnum = itr.Next()) >= 0)
Level->sectors[secnum].SetPlaneLight(sector_t::ceiling, llevel);
}
}
IMPLEMENT_CLASS(DWallLightTransfer, false, false)
void DWallLightTransfer::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("lastlight", LastLight)
("source", Source)
("targetid", TargetID)
("flags", Flags);
}
void DWallLightTransfer::Construct(sector_t *srcSec, int target, uint8_t flags)
{
int linenum;
int wallflags;
Source = srcSec;
TargetID = target;
Flags = flags;
DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags);
if (!(flags & WLF_NOFAKECONTRAST))
{
wallflags = WALLF_ABSLIGHTING;
}
else
{
wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST;
}
auto itr = Level->GetLineIdIterator(target);
while ((linenum = itr.Next()) >= 0)
{
if (flags & WLF_SIDE1 && Level->lines[linenum].sidedef[0] != NULL)
{
Level->lines[linenum].sidedef[0]->Flags |= wallflags;
}
if (flags & WLF_SIDE2 && Level->lines[linenum].sidedef[1] != NULL)
{
Level->lines[linenum].sidedef[1]->Flags |= wallflags;
}
}
}
void DWallLightTransfer::Tick ()
{
short light = sector_t::ClampLight(Source->lightlevel);
if (light != LastLight)
{
LastLight = light;
DoTransfer (light, TargetID, Flags);
}
}
void DWallLightTransfer::DoTransfer (short lightlevel, int target, uint8_t flags)
{
int linenum;
auto itr = Level->GetLineIdIterator(target);
while ((linenum = itr.Next()) >= 0)
{
line_t *line = &Level->lines[linenum];
if (flags & WLF_SIDE1 && line->sidedef[0] != NULL)
{
line->sidedef[0]->SetLight(lightlevel);
}
if (flags & WLF_SIDE2 && line->sidedef[1] != NULL)
{
line->sidedef[1]->SetLight(lightlevel);
}
}
}

View file

@ -0,0 +1,46 @@
#pragma once
class DLightTransfer : public DThinker
{
DECLARE_CLASS (DLightTransfer, DThinker)
public:
static const int DEFAULT_STAT = STAT_LIGHTTRANSFER;
void Construct(sector_t *srcSec, int target, bool copyFloor);
void Serialize(FSerializer &arc);
void Tick ();
protected:
void DoTransfer (int level, int target, bool floor);
sector_t *Source;
int TargetTag;
bool CopyFloor;
short LastLight;
};
class DWallLightTransfer : public DThinker
{
enum
{
WLF_SIDE1=1,
WLF_SIDE2=2,
WLF_NOFAKECONTRAST=4
};
DECLARE_CLASS (DWallLightTransfer, DThinker)
public:
static const int DEFAULT_STAT = STAT_LIGHTTRANSFER;
void Construct(sector_t *srcSec, int target, uint8_t flags);
void Serialize(FSerializer &arc);
void Tick ();
protected:
void DoTransfer (short level, int target, uint8_t flags);
sector_t *Source;
int TargetID;
short LastLight;
uint8_t Flags;
};

View file

@ -35,21 +35,11 @@
#include <assert.h>
#include "info.h"
#include "p_local.h"
#include "p_lnspec.h"
#include "sbar.h"
#include "statnums.h"
#include "c_dispatch.h"
#include "gstrings.h"
#include "a_morph.h"
#include "a_specialspot.h"
#include "g_game.h"
#include "sbar.h"
#include "doomstat.h"
#include "d_player.h"
#include "serializer.h"
#include "vm.h"
#include "c_functions.h"
#include "g_levellocals.h"
EXTERN_CVAR(Bool, sv_unlimited_pickup)
@ -115,46 +105,3 @@ bool CallTryPickup(AActor *item, AActor *toucher, AActor **toucher_return)
return !!res;
}
//===========================================================================
//
// CCMD printinv
//
// Prints the console player's current inventory.
//
//===========================================================================
CCMD (printinv)
{
int pnum = consoleplayer;
#ifdef _DEBUG
// Only allow peeking on other players' inventory in debug builds.
if (argv.argc() > 1)
{
pnum = atoi (argv[1]);
if (pnum < 0 || pnum >= MAXPLAYERS)
{
return;
}
}
#endif
C_PrintInv(players[pnum].mo);
}
CCMD (targetinv)
{
FTranslatedLineTarget t;
if (CheckCheatmode () || players[consoleplayer].mo == NULL)
return;
C_AimLine(&t, true);
if (t.linetarget)
{
C_PrintInv(t.linetarget);
}
else Printf("No target found. Targetinv cannot find actors that have "
"the NOBLOCKMAP flag or have height/radius of 0.\n");
}

View file

@ -48,9 +48,11 @@ IMPLEMENT_POINTERS_START(DPillar)
IMPLEMENT_POINTER(m_Interp_Ceiling)
IMPLEMENT_POINTERS_END
DPillar::DPillar ()
{
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPillar::OnDestroy()
{
@ -67,6 +69,12 @@ void DPillar::OnDestroy()
Super::OnDestroy();
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPillar::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
@ -81,6 +89,12 @@ void DPillar::Serialize(FSerializer &arc)
("interp_ceiling", m_Interp_Ceiling);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPillar::Tick ()
{
EMoveResult r, s;
@ -118,10 +132,15 @@ void DPillar::Tick ()
}
}
DPillar::DPillar (sector_t *sector, EPillar type, double speed,
double floordist, double ceilingdist, int crush, bool hexencrush)
: DMover (sector)
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPillar::Construct(sector_t *sector, EPillar type, double speed, double floordist, double ceilingdist, int crush, bool hexencrush)
{
Super::Construct(sector);
double newheight;
vertex_t *spot;
@ -210,7 +229,13 @@ DPillar::DPillar (sector_t *sector, EPillar type, double speed,
}
}
bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FLevelLocals::EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
double speed, double height, double height2, int crush, bool hexencrush)
{
int secnum;
@ -218,10 +243,10 @@ bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
bool rtn = false;
// check if a manual trigger; if so do just the sector on the backside
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
while ((secnum = itr.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
if (sec->PlaneMoving(sector_t::floor) || sec->PlaneMoving(sector_t::ceiling))
continue;
@ -238,7 +263,7 @@ bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag,
continue;
rtn = true;
Create<DPillar> (sec, type, speed, height, height2, crush, hexencrush);
CreateThinker<DPillar> (sec, type, speed, height, height2, crush, hexencrush);
}
return rtn;
}

37
src/g_shared/a_pillar.h Normal file
View file

@ -0,0 +1,37 @@
#pragma once
//
// [RH]
// P_PILLAR
//
class DPillar : public DMover
{
DECLARE_CLASS (DPillar, DMover)
HAS_OBJECT_POINTERS
public:
enum EPillar
{
pillarBuild,
pillarOpen
};
void Construct (sector_t *sector, EPillar type, double speed, double height, double height2, int crush, bool hexencrush);
void Serialize(FSerializer &arc);
void Tick ();
void OnDestroy() override;
protected:
EPillar m_Type;
double m_FloorSpeed;
double m_CeilingSpeed;
double m_FloorTarget;
double m_CeilingTarget;
int m_Crush;
bool m_Hexencrush;
TObjPtr<DInterpolation*> m_Interp_Ceiling;
TObjPtr<DInterpolation*> m_Interp_Floor;
};

View file

@ -41,9 +41,11 @@ static FRandom pr_doplat ("DoPlat");
IMPLEMENT_CLASS(DPlat, false, false)
DPlat::DPlat ()
{
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPlat::Serialize(FSerializer &arc)
{
@ -60,6 +62,12 @@ void DPlat::Serialize(FSerializer &arc)
("tag", m_Tag);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPlat::PlayPlatSound (const char *sound)
{
if (m_Sector->Flags & SECF_SILENTMOVE) return;
@ -78,9 +86,12 @@ void DPlat::PlayPlatSound (const char *sound)
}
}
//-----------------------------------------------------------------------------
//
// Move a plat up and down
//
//-----------------------------------------------------------------------------
void DPlat::Tick ()
{
EMoveResult res;
@ -204,18 +215,52 @@ void DPlat::Tick ()
}
}
DPlat::DPlat (sector_t *sector)
: DMovingFloor (sector)
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPlat::Reactivate()
{
if (m_Type == platToggle) //jff 3/14/98 reactivate toggle type
m_Status = m_OldStatus == up ? down : up;
else
m_Status = m_OldStatus;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPlat::Stop()
{
m_OldStatus = m_Status;
m_Status = in_stasis;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPlat::Construct (sector_t *sector)
{
Super::Construct(sector);
}
//-----------------------------------------------------------------------------
//
// Do Platforms
// [RH] Changed amount to height and added delay,
// lip, change, tag, and speed parameters.
//
bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height,
double speed, int delay, int lip, int change)
//-----------------------------------------------------------------------------
bool FLevelLocals::EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height, double speed, int delay, int lip, int change)
{
DPlat *plat;
int secnum;
@ -233,7 +278,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height,
case DPlat::platToggle:
rtn = true;
case DPlat::platPerpetualRaise:
P_ActivateInStasis (tag);
ActivateInStasisPlat (tag);
break;
default:
@ -244,10 +289,10 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height,
// [RH] If tag is zero, use the sector on the back side
// of the activating line (if any).
FSectorTagIterator itr(tag, line);
auto itr = GetSectorTagIterator(tag, line);
while ((secnum = itr.Next()) >= 0)
{
sec = &level.sectors[secnum];
sec = &sectors[secnum];
if (sec->PlaneMoving(sector_t::floor))
{
@ -256,7 +301,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height,
// Find lowest & highest floors around sector
rtn = true;
plat = Create<DPlat> (sec);
plat = CreateThinker<DPlat> (sec);
plat->m_Type = type;
plat->m_Crush = -1;
@ -392,18 +437,16 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height,
return rtn;
}
void DPlat::Reactivate ()
{
if (m_Type == platToggle) //jff 3/14/98 reactivate toggle type
m_Status = m_OldStatus == up ? down : up;
else
m_Status = m_OldStatus;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void P_ActivateInStasis (int tag)
void FLevelLocals::ActivateInStasisPlat (int tag)
{
DPlat *scan;
TThinkerIterator<DPlat> iterator;
auto iterator = GetThinkerIterator<DPlat>();
while ( (scan = iterator.Next ()) )
{
@ -412,16 +455,16 @@ void P_ActivateInStasis (int tag)
}
}
void DPlat::Stop ()
{
m_OldStatus = m_Status;
m_Status = in_stasis;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void EV_StopPlat (int tag, bool remove)
void FLevelLocals::EV_StopPlat (int tag, bool remove)
{
DPlat *scan;
TThinkerIterator<DPlat> iterator;
auto iterator = GetThinkerIterator<DPlat>();
scan = iterator.Next();
while (scan != nullptr)

60
src/g_shared/a_plats.h Normal file
View file

@ -0,0 +1,60 @@
#pragma once
//
// P_PLATS
//
class DPlat : public DMovingFloor
{
DECLARE_CLASS (DPlat, DMovingFloor)
public:
enum EPlatState
{
up,
down,
waiting,
in_stasis
};
enum EPlatType
{
platPerpetualRaise,
platDownWaitUpStay,
platDownWaitUpStayStone,
platUpWaitDownStay,
platUpNearestWaitDownStay,
platDownByValue,
platUpByValue,
platUpByValueStay,
platRaiseAndStay,
platToggle,
platDownToNearestFloor,
platDownToLowestCeiling,
platRaiseAndStayLockout,
};
void Serialize(FSerializer &arc);
void Tick ();
bool IsLift() const { return m_Type == platDownWaitUpStay || m_Type == platDownWaitUpStayStone; }
void Construct(sector_t *sector);
protected:
double m_Speed;
double m_Low;
double m_High;
int m_Wait;
int m_Count;
EPlatState m_Status;
EPlatState m_OldStatus;
int m_Crush;
int m_Tag;
EPlatType m_Type;
void PlayPlatSound (const char *sound);
void Reactivate ();
void Stop ();
friend struct FLevelLocals;
};

View file

@ -36,47 +36,10 @@
#include "d_player.h"
#include "g_levellocals.h"
#include "actorinlines.h"
#include "p_spec_thinkers.h"
#include "maploader/maploader.h"
CVAR(Bool, var_pushers, true, CVAR_SERVERINFO);
// phares 3/20/98: added new model of Pushers for push/pull effects
class DPusher : public DThinker
{
DECLARE_CLASS (DPusher, DThinker)
HAS_OBJECT_POINTERS
public:
enum EPusher
{
p_push,
p_pull,
p_wind,
p_current
};
DPusher ();
DPusher (EPusher type, line_t *l, int magnitude, int angle, AActor *source, int affectee);
void Serialize(FSerializer &arc);
int CheckForSectorMatch (EPusher type, int tag);
void ChangeValues (int magnitude, int angle)
{
DAngle ang = angle * (360. / 256.);
m_PushVec = ang.ToVector(magnitude);
m_Magnitude = magnitude;
}
void Tick ();
protected:
EPusher m_Type;
TObjPtr<AActor*> m_Source;// Point source if point pusher
DVector2 m_PushVec;
double m_Magnitude; // Vector strength for point pusher
double m_Radius; // Effective radius for point pusher
int m_Affectee; // Number of affected sector
friend bool PIT_PushThing (AActor *thing);
};
EXTERN_CVAR(Bool, var_pushers);
IMPLEMENT_CLASS(DPusher, false, true)
@ -84,9 +47,11 @@ IMPLEMENT_POINTERS_START(DPusher)
IMPLEMENT_POINTER(m_Source)
IMPLEMENT_POINTERS_END
DPusher::DPusher ()
{
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DPusher::Serialize(FSerializer &arc)
{
@ -100,7 +65,7 @@ void DPusher::Serialize(FSerializer &arc)
}
////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// PUSH/PULL EFFECT
//
@ -143,15 +108,16 @@ void DPusher::Serialize(FSerializer &arc)
// to have the PUSH_MASK bit set. If this bit is turned off by a switch
// at run-time, the effect will not occur. The controlling sector for
// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
//
//-----------------------------------------------------------------------------
#define PUSH_FACTOR 128
/////////////////////////////
//-----------------------------------------------------------------------------
//
// Add a push thinker to the thinker list
//
//-----------------------------------------------------------------------------
DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
void DPusher::Construct (DPusher::EPusher type, line_t *l, int magnitude, int angle,
AActor *source, int affectee)
{
m_Source = source;
@ -174,18 +140,20 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
int DPusher::CheckForSectorMatch (EPusher type, int tag)
{
if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
if (m_Type == type && Level->SectorHasTag(m_Affectee, tag))
return m_Affectee;
else
return -1;
}
/////////////////////////////
//-----------------------------------------------------------------------------
//
// T_Pusher looks for all objects that are inside the radius of
// the effect.
//
//-----------------------------------------------------------------------------
void DPusher::Tick ()
{
sector_t *sec;
@ -196,7 +164,7 @@ void DPusher::Tick ()
if (!var_pushers)
return;
sec = &level.sectors[m_Affectee];
sec = &Level->sectors[m_Affectee];
// Be sure the special sector type is still turned on. If so, proceed.
// Else, bail out; the sector type has been changed on us.
@ -240,7 +208,7 @@ void DPusher::Tick ()
bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
// MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't.
if (compatflags & COMPATF_MBFMONSTERMOVE)
if (Level->i_compatflags & COMPATF_MBFMONSTERMOVE)
{
pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here
&& (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here
@ -333,117 +301,43 @@ void DPusher::Tick ()
}
}
/////////////////////////////
//-----------------------------------------------------------------------------
//
// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
// NULL otherwise.
//
//
//-----------------------------------------------------------------------------
AActor *P_GetPushThing (int s)
void FLevelLocals::AdjustPusher(int tag, int magnitude, int angle, bool wind)
{
AActor* thing;
sector_t* sec;
sec = &level.sectors[s];
thing = sec->thinglist;
while (thing &&
thing->GetClass()->TypeName != NAME_PointPusher &&
thing->GetClass()->TypeName != NAME_PointPuller)
struct FThinkerCollection
{
thing = thing->snext;
}
return thing;
}
int RefNum;
DThinker *Obj;
};
/////////////////////////////
//
// Initialize the sectors where pushers are present
//
void P_SpawnPushers ()
{
line_t *l = &level.lines[0];
int s;
for (unsigned i = 0; i < level.lines.Size(); i++, l++)
{
switch (l->special)
{
case Sector_SetWind: // wind
{
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
Create<DPusher>(DPusher::p_wind, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, s);
l->special = 0;
break;
}
case Sector_SetCurrent: // current
{
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
Create<DPusher>(DPusher::p_current, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, s);
l->special = 0;
break;
}
case PointPush_SetForce: // push/pull
if (l->args[0]) { // [RH] Find thing by sector
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
AActor *thing = P_GetPushThing (s);
if (thing) { // No MT_P* means no effect
// [RH] Allow narrowing it down by tid
if (!l->args[1] || l->args[1] == thing->tid)
Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2],
0, thing, s);
}
}
} else { // [RH] Find thing by tid
AActor *thing;
FActorIterator iterator (l->args[1]);
while ( (thing = iterator.Next ()) )
{
if (thing->GetClass()->TypeName == NAME_PointPusher ||
thing->GetClass()->TypeName == NAME_PointPuller)
{
Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], 0, thing, thing->Sector->Index());
}
}
}
l->special = 0;
break;
}
}
}
void AdjustPusher (int tag, int magnitude, int angle, bool wind)
{
DPusher::EPusher type = wind? DPusher::p_wind : DPusher::p_current;
// Find pushers already attached to the sector, and change their parameters.
TArray<FThinkerCollection> Collection;
{
TThinkerIterator<DPusher> iterator;
auto iterator = GetThinkerIterator<DPusher>();
FThinkerCollection collect;
while ( (collect.Obj = iterator.Next ()) )
while ((collect.Obj = iterator.Next()))
{
if ((collect.RefNum = ((DPusher *)collect.Obj)->CheckForSectorMatch (type, tag)) >= 0)
if ((collect.RefNum = ((DPusher *)collect.Obj)->CheckForSectorMatch(type, tag)) >= 0)
{
((DPusher *)collect.Obj)->ChangeValues (magnitude, angle);
Collection.Push (collect);
((DPusher *)collect.Obj)->ChangeValues(magnitude, angle);
Collection.Push(collect);
}
}
}
size_t numcollected = Collection.Size ();
size_t numcollected = Collection.Size();
int secnum;
// Now create pushers for any sectors that don't already have them.
FSectorTagIterator itr(tag);
auto itr = GetSectorTagIterator(tag);
while ((secnum = itr.Next()) >= 0)
{
unsigned int i;
@ -454,7 +348,7 @@ void AdjustPusher (int tag, int magnitude, int angle, bool wind)
}
if (i == numcollected)
{
Create<DPusher> (type, nullptr, magnitude, angle, nullptr, secnum);
CreateThinker<DPusher>(type, nullptr, magnitude, angle, nullptr, secnum);
}
}
}

46
src/g_shared/a_pusher.h Normal file
View file

@ -0,0 +1,46 @@
#pragma once
// phares 3/20/98: added new model of Pushers for push/pull effects
class DPusher : public DThinker
{
DECLARE_CLASS (DPusher, DThinker)
HAS_OBJECT_POINTERS
enum
{
PUSH_FACTOR = 128
};
public:
enum EPusher
{
p_push,
p_pull,
p_wind,
p_current
};
void Construct(EPusher type, line_t *l, int magnitude, int angle, AActor *source, int affectee);
void Serialize(FSerializer &arc);
int CheckForSectorMatch (EPusher type, int tag);
void ChangeValues (int magnitude, int angle)
{
DAngle ang = angle * (360. / 256.);
m_PushVec = ang.ToVector(magnitude);
m_Magnitude = magnitude;
}
void Tick ();
protected:
EPusher m_Type;
TObjPtr<AActor*> m_Source;// Point source if point pusher
DVector2 m_PushVec;
double m_Magnitude; // Vector strength for point pusher
double m_Radius; // Effective radius for point pusher
int m_Affectee; // Number of affected sector
friend bool PIT_PushThing (AActor *thing);
};

View file

@ -31,6 +31,7 @@
#include "serializer.h"
#include "d_player.h"
#include "r_utility.h"
#include "g_levellocals.h"
static FRandom pr_quake ("Quake");
@ -40,28 +41,16 @@ IMPLEMENT_POINTERS_START(DEarthquake)
IMPLEMENT_POINTER(m_Spot)
IMPLEMENT_POINTERS_END
//==========================================================================
//
// DEarthquake :: DEarthquake private constructor
//
//==========================================================================
DEarthquake::DEarthquake()
: DThinker(STAT_EARTHQUAKE)
{
}
//==========================================================================
//
// DEarthquake :: DEarthquake public constructor
//
//==========================================================================
DEarthquake::DEarthquake(AActor *center, int intensityX, int intensityY, int intensityZ, int duration,
void DEarthquake::Construct(AActor *center, int intensityX, int intensityY, int intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesound, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint,
double rollIntensity, double rollWave)
: DThinker(STAT_EARTHQUAKE)
{
m_QuakeSFX = quakesound;
m_Spot = center;
@ -133,9 +122,9 @@ void DEarthquake::Tick ()
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !(players[i].cheats & CF_NOCLIP))
if (Level->PlayerInGame(i) && !(Level->Players[i]->cheats & CF_NOCLIP))
{
AActor *victim = players[i].mo;
AActor *victim = Level->Players[i]->mo;
double dist;
dist = m_Spot->Distance2D(victim, true);
@ -299,7 +288,7 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak
return 0;
}
TThinkerIterator<DEarthquake> iterator(STAT_EARTHQUAKE);
auto iterator = victim->Level->GetThinkerIterator<DEarthquake>(NAME_None, STAT_EARTHQUAKE);
DEarthquake *quake;
int count = 0;
@ -378,7 +367,7 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak
//
//==========================================================================
bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration,
bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, int intensityX, int intensityY, int intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint,
double rollIntensity, double rollWave)
@ -394,18 +383,18 @@ bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY,
{
if (activator != NULL)
{
Create<DEarthquake>(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad,
Level->CreateThinker<DEarthquake>(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad,
quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave);
return true;
}
}
else
{
FActorIterator iterator (tid);
auto iterator = Level->GetActorIterator(tid);
while ( (center = iterator.Next ()) )
{
res = true;
Create<DEarthquake>(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad,
Level->CreateThinker<DEarthquake>(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad,
quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave);
}
}
@ -413,7 +402,7 @@ bool P_StartQuakeXYZ(AActor *activator, int tid, int intensityX, int intensityY,
return res;
}
bool P_StartQuake(AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx)
bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, int intensity, int duration, int damrad, int tremrad, FSoundID quakesfx)
{ //Maintains original behavior by passing 0 to intensityZ, flags, and everything else after QSFX.
return P_StartQuakeXYZ(activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0);
return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0);
}

View file

@ -62,50 +62,8 @@
#include "p_lnspec.h"
#include "r_data/r_interpolate.h"
#include "g_levellocals.h"
//-----------------------------------------------------------------------------
//
// killough 3/7/98: Add generalized scroll effects
//
//-----------------------------------------------------------------------------
class DScroller : public DThinker
{
DECLARE_CLASS (DScroller, DThinker)
HAS_OBJECT_POINTERS
public:
DScroller(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
DScroller (double dx, double dy, const line_t *l, sector_t *control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void OnDestroy() override;
void Serialize(FSerializer &arc);
void Tick ();
bool AffectsWall (side_t * wall) const { return m_Side == wall; }
side_t *GetWall () const { return m_Side; }
sector_t *GetSector() const { return m_Sector; }
void SetRate (double dx, double dy) { m_dx = dx; m_dy = dy; }
bool IsType (EScroll type) const { return type == m_Type; }
EScrollPos GetScrollParts() const { return m_Parts; }
protected:
EScroll m_Type; // Type of scroll effect
double m_dx, m_dy; // (dx,dy) scroll speeds
sector_t *m_Sector; // Affected sector
side_t *m_Side; // ... or side
sector_t *m_Controller; // Control sector (nullptr if none) used to control scrolling
double m_LastHeight; // Last known height of control sector
double m_vdx, m_vdy; // Accumulated velocity if accelerative
int m_Accel; // Whether it's accelerative
EScrollPos m_Parts; // Which parts of a sidedef are being scrolled?
TObjPtr<DInterpolation*> m_Interpolations[3];
private:
DScroller ()
{
}
};
#include "maploader/maploader.h"
#include "p_spec_thinkers.h"
IMPLEMENT_CLASS(DScroller, false, true)
@ -255,7 +213,7 @@ void DScroller::Tick ()
// [RH] Don't actually carry anything here. That happens later.
case EScroll::sc_carry:
level.Scrolls[m_Sector->Index()] += { dx, dy };
Level->Scrolls[m_Sector->Index()] += { dx, dy };
// mark all potentially affected things here so that the very expensive calculation loop in AActor::Tick does not need to run for actors which do not touch a scrolling sector.
for (auto n = m_Sector->touching_thinglist; n; n = n->m_snext)
{
@ -288,8 +246,7 @@ void DScroller::Tick ()
//
//-----------------------------------------------------------------------------
DScroller::DScroller (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos)
{
m_Type = type;
m_dx = dx;
@ -310,7 +267,7 @@ DScroller::DScroller (EScroll type, double dx, double dy, sector_t *ctrl, secto
{
case EScroll::sc_carry:
assert(sec != nullptr);
level.AddScroller (sec->Index());
Level->AddScroller (sec->Index());
break;
case EScroll::sc_side:
@ -370,8 +327,7 @@ void DScroller::OnDestroy ()
//
//-----------------------------------------------------------------------------
DScroller::DScroller (double dx, double dy, const line_t *l, sector_t * control, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
void DScroller::Construct(double dx, double dy, const line_t *l, sector_t * control, int accel, EScrollPos scrollpos)
{
double x = fabs(l->Delta().X), y = fabs(l->Delta().Y), d;
if (y > x) d = x, x = y, y = d;
@ -411,221 +367,6 @@ DScroller::DScroller (double dx, double dy, const line_t *l, sector_t * control,
}
}
// Amount (dx,dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5
#define SCROLLTYPE(i) EScrollPos(((i) <= 0) || ((i) & ~7) ? 7 : (i))
//-----------------------------------------------------------------------------
//
// Initialize the scrollers
//
//-----------------------------------------------------------------------------
void P_SpawnScrollers(FLevelLocals *Level)
{
line_t *l = &Level->lines[0];
side_t *side;
TArray<int> copyscrollers;
for (auto &line : Level->lines)
{
if (line.special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (!tagManager.SectorHasTag(line.frontsector, line.args[0]))
{
copyscrollers.Push(line.Index());
}
line.special = 0;
}
}
for (unsigned i = 0; i < Level->lines.Size(); i++, l++)
{
double dx; // direction and speed of scrolling
double dy;
sector_t *control = nullptr;
int accel = 0; // no control sector or acceleration
int special = l->special;
// Check for undefined parameters that are non-zero and output messages for them.
// We don't report for specials we don't understand.
FLineSpecial *spec = P_GetLineSpecialInfo(special);
if (spec != nullptr)
{
int max = spec->map_args;
for (unsigned arg = max; arg < countof(l->args); ++arg)
{
if (l->args[arg] != 0)
{
Printf("Line %d (type %d:%s), arg %u is %d (should be 0)\n",
i, special, spec->name, arg+1, l->args[arg]);
}
}
}
// killough 3/7/98: Types 245-249 are same as 250-254 except that the
// first side's sector's heights cause scrolling when they change, and
// this linedef controls the direction and speed of the scrolling. The
// most complicated linedef since donuts, but powerful :)
//
// killough 3/15/98: Add acceleration. Types 214-218 are the same but
// are accelerative.
// [RH] Assume that it's a scroller and zero the line's special.
l->special = 0;
dx = dy = 0; // Shut up, GCC
if (special == Scroll_Ceiling ||
special == Scroll_Floor ||
special == Scroll_Texture_Model)
{
if (l->args[1] & 3)
{
// if 1, then displacement
// if 2, then accelerative (also if 3)
control = l->sidedef[0]->sector;
if (l->args[1] & 2)
accel = 1;
}
if (special == Scroll_Texture_Model || l->args[1] & 4)
{
// The line housing the special controls the
// direction and speed of scrolling.
dx = l->Delta().X / 32.;
dy = l->Delta().Y / 32.;
}
else
{
// The speed and direction are parameters to the special.
dx = (l->args[3] - 128) / 32.;
dy = (l->args[4] - 128) / 32.;
}
}
switch (special)
{
int s;
case Scroll_Ceiling:
{
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
Create<DScroller>(EScroll::sc_ceiling, -dx, dy, control, &Level->sectors[s], nullptr, accel);
}
for (unsigned j = 0; j < copyscrollers.Size(); j++)
{
line_t *line = &Level->lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 1))
{
Create<DScroller>(EScroll::sc_ceiling, -dx, dy, control, line->frontsector, nullptr, accel);
}
}
break;
}
case Scroll_Floor:
if (l->args[2] != 1)
{ // scroll the floor texture
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
Create<DScroller> (EScroll::sc_floor, -dx, dy, control, &Level->sectors[s], nullptr, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &Level->lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 2))
{
Create<DScroller>(EScroll::sc_floor, -dx, dy, control, line->frontsector, nullptr, accel);
}
}
}
if (l->args[2] > 0)
{ // carry objects on the floor
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
Create<DScroller> (EScroll::sc_carry, dx, dy, control, &Level->sectors[s], nullptr, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &Level->lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 4))
{
Create<DScroller> (EScroll::sc_carry, dx, dy, control, line->frontsector, nullptr, accel);
}
}
}
break;
// killough 3/1/98: scroll wall according to linedef
// (same direction and speed as scrolling floors)
case Scroll_Texture_Model:
{
FLineIdIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
if (s != (int)i)
Create<DScroller>(dx, dy, &Level->lines[s], control, accel);
}
break;
}
case Scroll_Texture_Offsets:
// killough 3/2/98: scroll according to sidedef offsets
side = Level->lines[i].sidedef[0];
Create<DScroller> (EScroll::sc_side, -side->GetTextureXOffset(side_t::mid),
side->GetTextureYOffset(side_t::mid), nullptr, nullptr, side, accel, SCROLLTYPE(l->args[0]));
break;
case Scroll_Texture_Left:
l->special = special; // Restore the special, for compat_useblocking's benefit.
side = Level->lines[i].sidedef[0];
Create<DScroller> (EScroll::sc_side, l->args[0] / 64., 0, nullptr, nullptr, side, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Right:
l->special = special;
side = Level->lines[i].sidedef[0];
Create<DScroller> (EScroll::sc_side, -l->args[0] / 64., 0, nullptr, nullptr, side, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Up:
l->special = special;
side = Level->lines[i].sidedef[0];
Create<DScroller> (EScroll::sc_side, 0, l->args[0] / 64., nullptr, nullptr, side, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Down:
l->special = special;
side = Level->lines[i].sidedef[0];
Create<DScroller> (EScroll::sc_side, 0, -l->args[0] / 64., nullptr, nullptr, side, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Both:
side = Level->lines[i].sidedef[0];
if (l->args[0] == 0) {
dx = (l->args[1] - l->args[2]) / 64.;
dy = (l->args[4] - l->args[3]) / 64.;
Create<DScroller> (EScroll::sc_side, dx, dy, nullptr, nullptr, side, accel);
}
break;
default:
// [RH] It wasn't a scroller after all, so restore the special.
l->special = special;
break;
}
}
}
//-----------------------------------------------------------------------------
//
// Modify a wall scroller
@ -640,14 +381,14 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
if (dx == 0 && dy == 0)
{
// Special case: Remove the scroller, because the deltas are both 0.
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
auto iterator = Level->GetThinkerIterator<DScroller>(NAME_None, STAT_SCROLLER);
DScroller *scroller;
while ( (scroller = iterator.Next ()) )
{
auto wall = scroller->GetWall ();
if (wall != nullptr && tagManager.LineHasID(wall->linedef, id) && wall->linedef->sidedef[sidechoice] == wall && Where == scroller->GetScrollParts())
if (wall != nullptr && Level->LineHasId(wall->linedef, id) && wall->linedef->sidedef[sidechoice] == wall && Where == scroller->GetScrollParts())
{
scroller->Destroy ();
}
@ -659,7 +400,7 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
// their rates.
TArray<DScroller *> Collection;
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
auto iterator = Level->GetThinkerIterator<DScroller>(NAME_None, STAT_SCROLLER);
DScroller *scroll;
while ( (scroll = iterator.Next ()) )
@ -668,7 +409,7 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
if (wall != nullptr)
{
auto line = wall->linedef;
if (tagManager.LineHasID(line, id) && line->sidedef[sidechoice] == wall && Where == scroll->GetScrollParts())
if (Level->LineHasId(line, id) && line->sidedef[sidechoice] == wall && Where == scroll->GetScrollParts())
{
scroll->SetRate(dx, dy);
Collection.Push(scroll);
@ -681,7 +422,7 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
int linenum;
// Now create scrollers for any walls that don't already have them.
FLineIdIterator itr(id);
auto itr = Level->GetLineIdIterator(id);
while ((linenum = itr.Next()) >= 0)
{
side_t *side = Level->lines[linenum].sidedef[sidechoice];
@ -689,7 +430,7 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
{
if (Collection.FindEx([=](const DScroller *element) { return element->GetWall() == side; }) == Collection.Size())
{
Create<DScroller> (EScroll::sc_side, dx, dy, nullptr, nullptr, side, 0, Where);
Level->CreateThinker<DScroller> (EScroll::sc_side, dx, dy, nullptr, nullptr, side, 0, Where);
}
}
}
@ -698,7 +439,7 @@ void SetWallScroller (FLevelLocals *Level, int id, int sidechoice, double dx, do
void SetScroller (FLevelLocals *Level, int tag, EScroll type, double dx, double dy)
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
auto iterator = Level->GetThinkerIterator<DScroller>(NAME_None, STAT_SCROLLER);
DScroller *scroller;
int i;
@ -712,7 +453,7 @@ void SetScroller (FLevelLocals *Level, int tag, EScroll type, double dx, double
{
if (scroller->IsType (type))
{
if (tagManager.SectorHasTag(scroller->GetSector(), tag))
if (Level->SectorHasTag(scroller->GetSector(), tag))
{
i++;
scroller->SetRate (dx, dy);
@ -726,14 +467,9 @@ void SetScroller (FLevelLocals *Level, int tag, EScroll type, double dx, double
}
// Need to create scrollers for the sector(s)
FSectorTagIterator itr(tag);
auto itr = Level->GetSectorTagIterator(tag);
while ((i = itr.Next()) >= 0)
{
Create<DScroller> (type, dx, dy, nullptr, &Level->sectors[i], nullptr, 0);
Level->CreateThinker<DScroller> (type, dx, dy, nullptr, &Level->sectors[i], nullptr, 0);
}
}
void P_CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos)
{
Create<DScroller>(type, dx, dy, nullptr, affectee, nullptr, accel, scrollpos);
}

42
src/g_shared/a_scroll.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
//-----------------------------------------------------------------------------
//
// killough 3/7/98: Add generalized scroll effects
//
//-----------------------------------------------------------------------------
class DScroller : public DThinker
{
DECLARE_CLASS (DScroller, DThinker)
HAS_OBJECT_POINTERS
public:
static const int DEFAULT_STAT = STAT_SCROLLER;
void Construct(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void Construct(double dx, double dy, const line_t *l, sector_t *control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void OnDestroy() override;
void Serialize(FSerializer &arc);
void Tick ();
bool AffectsWall (side_t * wall) const { return m_Side == wall; }
side_t *GetWall () const { return m_Side; }
sector_t *GetSector() const { return m_Sector; }
void SetRate (double dx, double dy) { m_dx = dx; m_dy = dy; }
bool IsType (EScroll type) const { return type == m_Type; }
EScrollPos GetScrollParts() const { return m_Parts; }
protected:
EScroll m_Type; // Type of scroll effect
double m_dx, m_dy; // (dx,dy) scroll speeds
sector_t *m_Sector; // Affected sector
side_t *m_Side; // ... or side
sector_t *m_Controller; // Control sector (nullptr if none) used to control scrolling
double m_LastHeight; // Last known height of control sector
double m_vdx, m_vdy; // Accumulated velocity if accelerative
int m_Accel; // Whether it's accelerative
EScrollPos m_Parts; // Which parts of a sidedef are being scrolled?
TObjPtr<DInterpolation*> m_Interpolations[3];
};

View file

@ -11,7 +11,7 @@ struct F3DFloor;
class DBaseDecal;
struct SpreadInfo;
class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent);
DBaseDecal *ShootDecal(FLevelLocals *Level, const FDecalTemplate *tpl, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent);
void SprayDecal(AActor *shooter, const char *name,double distance = 172.);
class DBaseDecal : public DThinker
@ -19,11 +19,10 @@ class DBaseDecal : public DThinker
DECLARE_CLASS (DBaseDecal, DThinker)
HAS_OBJECT_POINTERS
public:
DBaseDecal ();
DBaseDecal(double z);
DBaseDecal(int statnum, double z);
DBaseDecal (const AActor *actor);
DBaseDecal (const DBaseDecal *basis);
static const int DEFAULT_STAT = STAT_DECAL;
void Construct(double z = 0);
void Construct(const AActor *actor);
void Construct(const DBaseDecal *basis);
void Serialize(FSerializer &arc);
void OnDestroy() override;
@ -34,19 +33,19 @@ public:
void Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor);
void GetXY (side_t *side, double &x, double &y) const;
DBaseDecal *WallNext, *WallPrev;
DBaseDecal *WallNext = nullptr, *WallPrev = nullptr;
double LeftDistance;
double LeftDistance = 0;
double Z;
double ScaleX, ScaleY;
double Alpha;
uint32_t AlphaColor;
int Translation;
double ScaleX = 1, ScaleY = 1;
double Alpha = 1;
uint32_t AlphaColor = 0;
int Translation = 0;
FTextureID PicNum;
uint32_t RenderFlags;
uint32_t RenderFlags = 0;
FRenderStyle RenderStyle;
side_t *Side;
sector_t *Sector;
side_t *Side = nullptr;
sector_t *Sector = nullptr;
protected:
virtual DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const;
@ -61,20 +60,21 @@ class DImpactDecal : public DBaseDecal
{
DECLARE_CLASS (DImpactDecal, DBaseDecal)
public:
DImpactDecal(double z);
DImpactDecal (side_t *wall, const FDecalTemplate *templ);
static const int DEFAULT_STAT = STAT_AUTODECAL;
void Construct(double z = 0)
{
Super::Construct(z);
}
void Construct(side_t *wall, const FDecalTemplate *templ);
static DImpactDecal *StaticCreate(const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
static DImpactDecal *StaticCreate(FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
static DImpactDecal *StaticCreate(FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
void BeginPlay ();
protected:
DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const;
void CheckMax ();
private:
DImpactDecal();
};
class DFlashFader : public DThinker
@ -82,7 +82,7 @@ class DFlashFader : public DThinker
DECLARE_CLASS (DFlashFader, DThinker)
HAS_OBJECT_POINTERS
public:
DFlashFader (float r1, float g1, float b1, float a1,
void Construct(float r1, float g1, float b1, float a1,
float r2, float g2, float b2, float a2,
float time, AActor *who, bool terminate = false);
void OnDestroy() override;
@ -99,7 +99,6 @@ protected:
TObjPtr<AActor*> ForWho;
bool Terminate;
void SetBlend (float time);
DFlashFader() = default;
};
enum
@ -126,7 +125,8 @@ class DEarthquake : public DThinker
DECLARE_CLASS (DEarthquake, DThinker)
HAS_OBJECT_POINTERS
public:
DEarthquake(AActor *center, int intensityX, int intensityY, int intensityZ, int duration,
static const int DEFAULT_STAT = STAT_EARTHQUAKE;
void Construct(AActor *center, int intensityX, int intensityY, int intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave);
@ -149,9 +149,6 @@ public:
double GetFalloff(double dist) const;
static int StaticGetQuakeIntensities(double ticFrac, AActor *viewer, FQuakeJiggers &jiggers);
private:
DEarthquake ();
};
#endif //__A_SHAREDGLOBAL_H__

View file

@ -35,6 +35,7 @@
#include "actor.h"
#include "d_player.h"
#include "p_local.h"
#include "g_levellocals.h"
//==========================================================================
//
@ -61,14 +62,18 @@
Only one selector of each type can be used.
*/
#define AAPTR_RESOLVE_PLAYERNUM(playernum) (playeringame[playernum] ? players[playernum].mo : NULL)
AActor *COPY_AAPTR(AActor *origin, int selector)
{
if (selector == AAPTR_DEFAULT) return origin;
FTranslatedLineTarget t;
auto Level = origin->Level;
auto AAPTR_RESOLVE_PLAYERNUM = [=](int playernum) -> AActor*
{
return (Level->PlayerInGame(playernum) ? Level->Players[playernum]->mo : nullptr);
};
if (origin)
{
if (origin->player)
@ -97,7 +102,7 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
return t.linetarget;
}
}
switch (selector & AAPTR_STATIC_SELECTORS)
{
case AAPTR_PLAYER1: return AAPTR_RESOLVE_PLAYERNUM(0);

View file

@ -36,12 +36,6 @@
IMPLEMENT_CLASS(DSectorEffect, false, false)
DSectorEffect::DSectorEffect ()
: DThinker(STAT_SECTOREFFECT)
{
m_Sector = nullptr;
}
void DSectorEffect::OnDestroy()
{
if (m_Sector)
@ -62,8 +56,7 @@ void DSectorEffect::OnDestroy()
Super::OnDestroy();
}
DSectorEffect::DSectorEffect (sector_t *sector)
: DThinker(STAT_SECTOREFFECT)
void DSectorEffect::Construct(sector_t *sector)
{
m_Sector = sector;
}
@ -88,9 +81,9 @@ IMPLEMENT_POINTERS_START(DMover)
IMPLEMENT_POINTER(interpolation)
IMPLEMENT_POINTERS_END
DMover::DMover (sector_t *sector)
: DSectorEffect (sector)
void DMover::Construct (sector_t *sector)
{
Super::Construct(sector);
interpolation = nullptr;
}
@ -118,9 +111,9 @@ void DMover::StopInterpolation(bool force)
IMPLEMENT_CLASS(DMovingFloor, true, false)
DMovingFloor::DMovingFloor (sector_t *sector)
: DMover (sector)
void DMovingFloor::Construct(sector_t *sector)
{
Super::Construct(sector);
sector->floordata = this;
interpolation = sector->SetInterpolation(sector_t::FloorMove, true);
}
@ -128,9 +121,9 @@ DMovingFloor::DMovingFloor (sector_t *sector)
IMPLEMENT_CLASS(DMovingCeiling, true, false)
DMovingCeiling::DMovingCeiling (sector_t *sector, bool interpolate)
: DMover (sector)
void DMovingCeiling::Construct(sector_t *sector, bool interpolate)
{
Super::Construct(sector);
sector->ceilingdata = this;
if (interpolate) interpolation = sector->SetInterpolation(sector_t::CeilingMove, true);
}
@ -221,7 +214,7 @@ EMoveResult sector_t::MoveFloor(double speed, double dest, int crush, int direct
//destheight = (dest < ceilingheight) ? dest : ceilingheight;
if (!ceilingplane.isSlope() && !floorplane.isSlope() &&
!PortalIsLinked(sector_t::ceiling) &&
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && -dest > ceilingplane.fD()))
(!(Level->i_compatflags2 & COMPATF2_FLOORMOVE) && -dest > ceilingplane.fD()))
{
dest = -ceilingplane.fD();
}
@ -311,7 +304,7 @@ EMoveResult sector_t::MoveCeiling(double speed, double dest, int crush, int dire
//destheight = (dest > floorheight) ? dest : floorheight;
if (!ceilingplane.isSlope() && !floorplane.isSlope() &&
!PortalIsLinked(sector_t::floor) &&
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && dest < -floorplane.fD()))
(!(Level->i_compatflags2 & COMPATF2_FLOORMOVE) && dest < -floorplane.fD()))
{
dest = -floorplane.fD();
}

View file

@ -8,7 +8,8 @@ class DSectorEffect : public DThinker
{
DECLARE_CLASS (DSectorEffect, DThinker)
public:
DSectorEffect (sector_t *sector);
static const int DEFAULT_STAT = STAT_SECTOREFFECT;
void Construct(sector_t *sector);
void Serialize(FSerializer &arc);
@ -17,10 +18,6 @@ public:
sector_t *GetSector() const { return m_Sector; }
sector_t *m_Sector;
protected:
DSectorEffect();
};
class DMover : public DSectorEffect
@ -28,15 +25,14 @@ class DMover : public DSectorEffect
DECLARE_ABSTRACT_CLASS (DMover, DSectorEffect)
HAS_OBJECT_POINTERS
protected:
DMover (sector_t *sector);
void Construct(sector_t *sector);
TObjPtr<DInterpolation*> interpolation;
public:
void StopInterpolation(bool force = false);
protected:
DMover () {}
void Serialize(FSerializer &arc);
void OnDestroy() override;
};
@ -45,16 +41,14 @@ class DMovingFloor : public DMover
{
DECLARE_ABSTRACT_CLASS (DMovingFloor, DMover)
protected:
DMovingFloor (sector_t *sector);
DMovingFloor() {}
void Construct(sector_t *sector);
};
class DMovingCeiling : public DMover
{
DECLARE_ABSTRACT_CLASS (DMovingCeiling, DMover)
protected:
DMovingCeiling (sector_t *sector, bool interpolate = true);
DMovingCeiling () {}
void Construct(sector_t *sector, bool interpolate = true);
};
#endif //__DSECTOREFFECT_H__

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,7 @@ struct pspdef_s;
struct FState;
class DThinker;
class FSerializer;
struct FLevelLocals;
class FThinkerIterator;
@ -52,20 +53,50 @@ enum { MAX_STATNUM = 127 };
// Doubly linked ring list of thinkers
struct FThinkerList
{
FThinkerList() : Sentinel(0) {}
// No destructor. If this list goes away it's the GC's task to clean the orphaned thinkers. Otherwise this may clash with engine shutdown.
void AddTail(DThinker *thinker);
DThinker *GetHead() const;
DThinker *GetTail() const;
bool IsEmpty() const;
void DestroyThinkers();
bool DoDestroyThinkers();
int TickThinkers(FThinkerList *dest); // Returns: # of thinkers ticked
int ProfileThinkers(FThinkerList *dest);
void SaveList(FSerializer &arc);
DThinker *Sentinel;
private:
DThinker *Sentinel = nullptr;
friend struct FThinkerCollection;
};
struct FThinkerCollection
{
void DestroyThinkersInList(int statnum)
{
Thinkers[statnum].DestroyThinkers();
FreshThinkers[statnum].DestroyThinkers();
}
void RunThinkers(FLevelLocals *Level); // The level is needed to tick the lights
void DestroyAllThinkers();
void SerializeThinkers(FSerializer &arc, bool keepPlayers);
void MarkRoots();
DThinker *FirstThinker(int statnum);
void Link(DThinker *thinker, int statnum);
private:
FThinkerList Thinkers[MAX_STATNUM + 2];
FThinkerList FreshThinkers[MAX_STATNUM + 1];
friend class FThinkerIterator;
};
class DThinker : public DObject
{
DECLARE_CLASS (DThinker, DObject)
public:
DThinker (int statnum = STAT_DEFAULT) throw();
static const int DEFAULT_STAT = STAT_DEFAULT;
void OnDestroy () override;
virtual ~DThinker ();
virtual void Tick ();
@ -73,44 +104,26 @@ public:
virtual void PostBeginPlay (); // Called just before the first tick
virtual void CallPostBeginPlay(); // different in actor.
virtual void PostSerialize();
void Serialize(FSerializer &arc) override;
size_t PropagateMark();
void ChangeStatNum (int statnum);
static void RunThinkers ();
static void RunThinkers (int statnum);
static void DestroyAllThinkers ();
static void DestroyThinkersInList(int statnum)
{
DestroyThinkersInList(Thinkers[statnum]);
DestroyThinkersInList(FreshThinkers[statnum]);
}
static void SerializeThinkers(FSerializer &arc, bool keepPlayers);
static void MarkRoots();
static DThinker *FirstThinker (int statnum);
static bool bSerialOverride;
// only used internally but Create needs access.
enum no_link_type { NO_LINK };
DThinker(no_link_type) throw();
private:
static void DestroyThinkersInList (FThinkerList &list);
static bool DoDestroyThinkersInList(FThinkerList &list);
static int TickThinkers (FThinkerList *list, FThinkerList *dest); // Returns: # of thinkers ticked
static int ProfileThinkers(FThinkerList *list, FThinkerList *dest);
static void SaveList(FSerializer &arc, DThinker *node);
void Remove();
static FThinkerList Thinkers[MAX_STATNUM+2]; // Current thinkers
static FThinkerList FreshThinkers[MAX_STATNUM+1]; // Newly created thinkers
friend struct FThinkerList;
friend struct FThinkerCollection;
friend class FThinkerIterator;
friend class DObject;
friend class FSerializer;
DThinker *NextThinker, *PrevThinker;
DThinker *NextThinker = nullptr, *PrevThinker = nullptr;
public:
FLevelLocals *Level;
friend struct FLevelLocals; // Needs access to FreshThinkers until the thinker storage gets refactored.
};
class FThinkerIterator
@ -118,14 +131,15 @@ class FThinkerIterator
protected:
const PClass *m_ParentType;
private:
FLevelLocals *Level;
DThinker *m_CurrThinker;
uint8_t m_Stat;
bool m_SearchStats;
bool m_SearchingFresh;
public:
FThinkerIterator (const PClass *type, int statnum=MAX_STATNUM+1);
FThinkerIterator (const PClass *type, int statnum, DThinker *prev);
FThinkerIterator (FLevelLocals *Level, const PClass *type, int statnum=MAX_STATNUM+1);
FThinkerIterator (FLevelLocals *Level, const PClass *type, int statnum, DThinker *prev);
DThinker *Next (bool exact = false);
void Reinit ();
@ -136,28 +150,19 @@ protected:
template <class T> class TThinkerIterator : public FThinkerIterator
{
public:
TThinkerIterator (int statnum=MAX_STATNUM+1) : FThinkerIterator (RUNTIME_CLASS(T), statnum)
TThinkerIterator (FLevelLocals *Level, int statnum=MAX_STATNUM+1) : FThinkerIterator (Level, RUNTIME_CLASS(T), statnum)
{
}
TThinkerIterator (int statnum, DThinker *prev) : FThinkerIterator (RUNTIME_CLASS(T), statnum, prev)
TThinkerIterator (FLevelLocals *Level, int statnum, DThinker *prev) : FThinkerIterator (Level, RUNTIME_CLASS(T), statnum, prev)
{
}
TThinkerIterator (const PClass *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(subclass, statnum)
TThinkerIterator (FLevelLocals *Level, const PClass *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(Level, subclass, statnum)
{
}
TThinkerIterator (FName subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(PClass::FindClass(subclass), statnum)
TThinkerIterator (FLevelLocals *Level, FName subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(Level, PClass::FindClass(subclass), statnum)
{
}
TThinkerIterator (ENamedName subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(PClass::FindClass(subclass), statnum)
{
}
TThinkerIterator (FName subclass, int statnum, DThinker *prev) : FThinkerIterator(PClass::FindClass(subclass), statnum, prev)
{
}
TThinkerIterator (ENamedName subclass, int statnum, DThinker *prev) : FThinkerIterator(PClass::FindClass(subclass), statnum, prev)
{
}
TThinkerIterator (const char *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(PClass::FindClass(subclass), statnum)
TThinkerIterator (FLevelLocals *Level, FName subclass, int statnum, DThinker *prev) : FThinkerIterator(Level, PClass::FindClass(subclass), statnum, prev)
{
}
T *Next (bool exact = false)
@ -166,4 +171,5 @@ public:
}
};
#endif //__DTHINKER_H__

View file

@ -105,7 +105,7 @@ void F3DFloor::UpdateColormap(FColormap &map)
// Add one 3D floor to the sector
//
//==========================================================================
static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int alpha)
void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int alpha)
{
F3DFloor* ffloor;
unsigned i;
@ -200,105 +200,6 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
}
}
//==========================================================================
//
// Creates all 3D floors defined by one linedef
//
//==========================================================================
static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
{
int s;
int flags;
int tag = line->args[0];
sector_t * sec = line->frontsector, *ss;
FSectorTagIterator itr(tag);
while ((s = itr.Next()) >= 0)
{
ss = &level.sectors[s];
if (param == 0)
{
flags = FF_EXISTS | FF_RENDERALL | FF_SOLID | FF_INVERTSECTOR;
alpha = 255;
for (auto l: sec->Lines)
{
if (l->special == Sector_SetContents && l->frontsector == sec)
{
alpha = clamp<int>(l->args[1], 0, 100);
if (l->args[2] & 1) flags &= ~FF_SOLID;
if (l->args[2] & 2) flags |= FF_SEETHROUGH;
if (l->args[2] & 4) flags |= FF_SHOOTTHROUGH;
if (l->args[2] & 8) flags |= FF_ADDITIVETRANS;
if (alpha != 100) flags |= FF_TRANSLUCENT;//|FF_BOTHPLANES|FF_ALLSIDES;
if (l->args[0])
{
// Yes, Vavoom's 3D-floor definitions suck!
// The content list changed in r1783 of Vavoom to be unified
// among all its supported games, so it has now ten different
// values instead of just five.
static uint32_t vavoomcolors[] = { VC_EMPTY,
VC_WATER, VC_LAVA, VC_NUKAGE, VC_SLIME, VC_HELLSLIME,
VC_BLOOD, VC_SLUDGE, VC_HAZARD, VC_BOOMWATER };
flags |= FF_SWIMMABLE | FF_BOTHPLANES | FF_ALLSIDES | FF_FLOOD;
l->frontsector->Colormap.FadeColor = vavoomcolors[l->args[0]] & VC_COLORMASK;
l->frontsector->Colormap.FogDensity = 0;
}
alpha = (alpha * 255) / 100;
break;
}
}
}
else if (param == 4)
{
flags = FF_EXISTS | FF_RENDERPLANES | FF_INVERTPLANES | FF_NOSHADE | FF_FIX;
if (param2 & 1) flags |= FF_SEETHROUGH; // marker for allowing missing texture checks
alpha = 255;
}
else
{
static const int defflags[] = { 0,
FF_SOLID,
FF_SWIMMABLE | FF_BOTHPLANES | FF_ALLSIDES | FF_SHOOTTHROUGH | FF_SEETHROUGH,
FF_SHOOTTHROUGH | FF_SEETHROUGH,
};
flags = defflags[param & 3] | FF_EXISTS | FF_RENDERALL;
if (param & 4) flags |= FF_ALLSIDES | FF_BOTHPLANES;
if (param & 16) flags ^= FF_SEETHROUGH;
if (param & 32) flags ^= FF_SHOOTTHROUGH;
if (param2 & 1) flags |= FF_NOSHADE;
if (param2 & 2) flags |= FF_DOUBLESHADOW;
if (param2 & 4) flags |= FF_FOG;
if (param2 & 8) flags |= FF_THINFLOOR;
if (param2 & 16) flags |= FF_UPPERTEXTURE;
if (param2 & 32) flags |= FF_LOWERTEXTURE;
if (param2 & 64) flags |= FF_ADDITIVETRANS | FF_TRANSLUCENT;
// if flooding is used the floor must be non-solid and is automatically made shootthrough and seethrough
if ((param2 & 128) && !(flags & FF_SOLID)) flags |= FF_FLOOD | FF_SEETHROUGH | FF_SHOOTTHROUGH;
if (param2 & 512) flags |= FF_FADEWALLS;
if (param2&1024) flags |= FF_RESET;
FTextureID tex = line->sidedef[0]->GetTexture(side_t::top);
if (!tex.Exists() && alpha < 255)
{
alpha = -tex.GetIndex();
}
alpha = clamp(alpha, 0, 255);
if (alpha == 0) flags &= ~(FF_RENDERALL | FF_BOTHPLANES | FF_ALLSIDES);
else if (alpha != 255) flags |= FF_TRANSLUCENT;
}
P_Add3DFloor(ss, sec, line, flags, alpha);
}
// To be 100% safe this should be done even if the alpha by texture value isn't used.
if (!line->sidedef[0]->GetTexture(side_t::top).isValid())
line->sidedef[0]->SetTexture(side_t::top, FNullTextureID());
return 1;
}
//==========================================================================
//
// P_PlayerOnSpecial3DFloor
@ -332,8 +233,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
P_PlayerInSpecialSector(player, rover->model);
// Apply flat specials (using the ceiling!)
P_PlayerOnSpecialFlat(
player, rover->model->GetTerrain(rover->top.isceiling));
P_PlayerOnSpecialFlat(player, rover->model->GetTerrain(rover->top.isceiling));
break;
}
@ -657,9 +557,9 @@ void P_Recalculate3DFloors(sector_t * sector)
//
//==========================================================================
void P_ClearDynamic3DFloorData()
void FLevelLocals::ClearDynamic3DFloorData()
{
for (auto &sec : level.sectors)
for (auto &sec : sectors)
{
TArray<F3DFloor*> & ffloors = sec.e->XFloor.ffloors;
@ -878,58 +778,6 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
}
//==========================================================================
//
// Spawns 3D floors
//
//==========================================================================
void P_Spawn3DFloors (void)
{
static int flagvals[] = {512, 2+512, 512+1024};
for (auto &line : level.lines)
{
switch(line.special)
{
case ExtraFloor_LightOnly:
if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0;
if (line.args[0] != 0)
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
break;
case Sector_Set3DFloor:
// The flag high-byte/line id is only needed in Hexen format.
// UDMF can set both of these parameters without any restriction of the usable values.
// In Doom format the translators can take full integers for the tag and the line ID always is the same as the tag.
if (level.maptype == MAPTYPE_HEXEN)
{
if (line.args[1]&8)
{
tagManager.AddLineID(line.Index(), line.args[4]);
}
else
{
line.args[0]+=256*line.args[4];
line.args[4]=0;
}
}
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
break;
default:
continue;
}
line.special=0;
line.args[0] = line.args[1] = line.args[2] = line.args[3] = line.args[4] = 0;
}
for (auto &sec : level.sectors)
{
P_Recalculate3DFloors(&sec);
}
}
//==========================================================================
//
// Returns a 3D floorplane appropriate for the given coordinates
@ -965,9 +813,8 @@ secplane_t P_FindFloorPlane(sector_t * sector, const DVector3 &pos)
int P_Find3DFloor(sector_t * sec, const DVector3 &pos, bool above, bool floor, double &cmpz)
{
// If no sector given, find the one appropriate
if (sec == NULL)
sec = P_PointInSector(pos);
// sector must be given
if (sec == nullptr) return -1;
// Above normal ceiling
cmpz = sec->ceilingplane.ZatPoint(pos);
@ -1011,33 +858,3 @@ int P_Find3DFloor(sector_t * sec, const DVector3 &pos, bool above, bool floor, d
return -1;
}
#include "c_dispatch.h"
CCMD (dump3df)
{
if (argv.argc() > 1)
{
int sec = (int)strtoll(argv[1], NULL, 10);
if ((unsigned)sec >= level.sectors.Size())
{
Printf("Sector %d does not exist.\n", sec);
return;
}
sector_t *sector = &level.sectors[sec];
TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors;
for (unsigned int i = 0; i < ffloors.Size(); i++)
{
double height=ffloors[i]->top.plane->ZatPoint(sector->centerspot);
double bheight=ffloors[i]->bottom.plane->ZatPoint(sector->centerspot);
IGNORE_FORMAT_PRE
Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n",
i, height, ffloors[i]->top.model->sectornum,
bheight, ffloors[i]->bottom.model->sectornum,
ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS)? "Exists":"", (ffloors[i]->flags&FF_DYNAMIC)? "Dynamic":"");
IGNORE_FORMAT_POST
}
}
}

View file

@ -123,7 +123,6 @@ void P_Recalculate3DFloors(sector_t *);
void P_RecalculateAttached3DFloors(sector_t * sec);
void P_RecalculateLights(sector_t *sector);
void P_RecalculateAttachedLights(sector_t *sector);
void P_ClearDynamic3DFloorData();
lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside);
void P_Spawn3DFloors( void );
@ -136,4 +135,6 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
secplane_t P_FindFloorPlane(sector_t * sector, const DVector3 &pos);
int P_Find3DFloor(sector_t * sec, const DVector3 &pos, bool above, bool floor, double &cmpz);
void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int alpha);
#endif

View file

@ -119,15 +119,16 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
// invalid set of parameters
return;
}
auto Level = sector->Level;
extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
// Bit arrays that mark whether a line or sector is to be attached.
uint8_t *found_lines = new uint8_t[(level.lines.Size()+7)/8];
uint8_t *found_sectors = new uint8_t[(level.sectors.Size()+7)/8];
uint8_t *found_lines = new uint8_t[(Level->lines.Size()+7)/8];
uint8_t *found_sectors = new uint8_t[(Level->sectors.Size()+7)/8];
memset(found_lines, 0, sizeof (uint8_t) * ((level.lines.Size()+7)/8));
memset(found_sectors, 0, sizeof (uint8_t) * ((level.sectors.Size()+7)/8));
memset(found_lines, 0, sizeof (uint8_t) * ((Level->lines.Size()+7)/8));
memset(found_sectors, 0, sizeof (uint8_t) * ((Level->sectors.Size()+7)/8));
// mark all lines and sectors that are already attached to this one
// and clear the arrays. The old data will be re-added automatically
@ -149,11 +150,11 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
if (tag == 0)
{
FLineIdIterator itr(lineid);
auto itr = Level->GetLineIdIterator(lineid);
int line;
while ((line = itr.Next()) >= 0)
{
line_t *ln = &level.lines[line];
line_t *ln = &Level->lines[line];
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
{
@ -165,13 +166,13 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
}
else
{
FSectorTagIterator it(tag);
auto it = Level->GetSectorTagIterator(tag);
int sec;
while ((sec = it.Next()) >= 0)
{
for (auto ln : level.sectors[sec].Lines)
for (auto ln : Level->sectors[sec].Lines)
{
if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
if (lineid != 0 && !Level->LineHasId(ln, lineid)) continue;
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
{
@ -185,28 +186,28 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
}
for(unsigned i=0; i < level.lines.Size(); i++)
for(unsigned i=0; i < Level->lines.Size(); i++)
{
if (found_lines[i>>3] & (1 << (i&7)))
{
auto &line = level.lines[i];
auto &line = Level->lines[i];
scrollplane.AttachedLines.Push(&line);
v = line.frontsector->Index();
assert(v < (int)level.sectors.Size());
assert(v < (int)Level->sectors.Size());
found_sectors[v>>3] |= 1 << (v&7);
v = line.backsector->Index();
assert(v < (int)level.sectors.Size());
assert(v < (int)Level->sectors.Size());
found_sectors[v>>3] |= 1 << (v&7);
}
}
for (unsigned i=0; i < level.sectors.Size(); i++)
for (unsigned i=0; i < Level->sectors.Size(); i++)
{
if (found_sectors[i>>3] & (1 << (i&7)))
{
scrollplane.AttachedSectors.Push(&level.sectors[i]);
scrollplane.AttachedSectors.Push(&Level->sectors[i]);
}
}
@ -235,7 +236,7 @@ bool P_GetMidTexturePosition(const line_t *line, int sideno, double *ptextop, do
FTexCoordInfo tci;
// We only need the vertical positioning info here.
tci.GetFromTexture(tex, 1., (float)side->GetTextureYScale(side_t::mid));
tci.GetFromTexture(tex, 1., (float)side->GetTextureYScale(side_t::mid), !!(line->GetLevel()->flags3 & LEVEL3_FORCEWORLDPANNING));
double y_offset = tci.RowOffset((float)side->GetTextureYOffset(side_t::mid));
double textureheight = tci.mRenderHeight;

Some files were not shown because too many files have changed in this diff Show more