mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-31 13:50:48 +00:00
Merge remote-tracking branch 'origin/new_level_refactor' into HEAD
This commit is contained in:
commit
d96d0b43f8
795 changed files with 36646 additions and 12163 deletions
47
CMakeSettings.json
Normal file
47
CMakeSettings.json
Normal 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
21073
externs.txt
Normal file
File diff suppressed because it is too large
Load diff
BIN
externs.zip
Normal file
BIN
externs.zip
Normal file
Binary file not shown.
1073
p_destructible.cpp
Normal file
1073
p_destructible.cpp
Normal file
File diff suppressed because it is too large
Load diff
43
p_destructible.h
Normal file
43
p_destructible.h
Normal 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);
|
|
@ -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)
|
||||
|
|
165
src/actor.h
165
src/actor.h
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
@ -93,3 +87,94 @@ inline double AActor::AttackOffset(double 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;
|
||||
}
|
||||
|
||||
|
|
1449
src/am_map.cpp
1449
src/am_map.cpp
File diff suppressed because it is too large
Load diff
53
src/am_map.h
53
src/am_map.h
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
25
src/b_bot.h
25
src/b_bot.h
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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..
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,7 +392,6 @@ 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 ();
|
||||
|
||||
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]);
|
||||
}, 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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "i_system.h"
|
||||
|
||||
#include "d_protocol.h"
|
||||
#include "d_net.h"
|
||||
#include "doomstat.h"
|
||||
|
|
|
@ -489,6 +489,8 @@ void DObject::StaticPointerSubstitution (AActor *old, AActor *notOld)
|
|||
size_t changed = 0;
|
||||
int i;
|
||||
|
||||
if (old == nullptr) return;
|
||||
|
||||
// Go through all objects.
|
||||
i = 0;DObject *last=0;
|
||||
for (probe = GC::Root; probe != NULL; probe = probe->ObjNext)
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <type_traits>
|
||||
#include "doomtype.h"
|
||||
#include "i_system.h"
|
||||
|
||||
#include "vectors.h"
|
||||
|
||||
class PClass;
|
||||
|
|
121
src/dobjgc.cpp
121
src/dobjgc.cpp
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
372
src/events.cpp
372
src/events.cpp
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
196
src/events.h
196
src/events.h
|
@ -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;
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,25 +357,34 @@ 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)
|
||||
{
|
||||
InitFunctions();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::Construct()
|
||||
{
|
||||
RunningScripts = Create<DRunningScript>();
|
||||
GC::WriteBarrier(this, RunningScripts);
|
||||
LevelScript = Create<DFsScript>();
|
||||
LevelScript->parent = GlobalScript;
|
||||
LevelScript->parent = nullptr;
|
||||
GC::WriteBarrier(this, LevelScript);
|
||||
}
|
||||
InitFunctions();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,6 +374,12 @@ DFsVariable *DFsScript::FindVariable(const char *name)
|
|||
// check this script
|
||||
if ((var = current->VariableForName(name)))
|
||||
return var;
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
111
src/g_cvars.cpp
Normal file
111
src/g_cvars.cpp
Normal 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
9
src/g_cvars.h
Normal 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
351
src/g_dumpinfo.cpp
Normal 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");
|
||||
}
|
||||
|
202
src/g_game.cpp
202
src/g_game.cpp
|
@ -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
|
||||
|
@ -2099,8 +2103,11 @@ static void PutSavePic (FileWriter *file, int width, int height)
|
|||
M_CreateDummyPNG (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
|
36
src/g_game.h
36
src/g_game.h
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
899
src/g_level.cpp
899
src/g_level.cpp
File diff suppressed because it is too large
Load diff
574
src/g_level.h
574
src/g_level.h
|
@ -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__
|
||||
|
|
|
@ -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,17 +457,20 @@ 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
|
||||
|
@ -132,14 +491,74 @@ 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;
|
||||
|
||||
uint32_t flags;
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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(§ors[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(§ors[sec], CHAN_CEILING);
|
||||
sectors[sec].ceilingdata->Destroy();
|
||||
sectors[sec].ceilingdata = nullptr;
|
||||
}
|
||||
}
|
||||
return true;
|
81
src/g_shared/a_ceiling.h
Normal file
81
src/g_shared/a_ceiling.h
Normal 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
246
src/g_shared/a_decalfx.cpp
Normal 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
93
src/g_shared/a_decalfx.h
Normal 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;
|
||||
};
|
||||
|
|
@ -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,16 +841,20 @@ 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)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static void SpawnDecal(AActor *self)
|
||||
{
|
||||
const FDecalTemplate *tpl = nullptr;
|
||||
|
||||
if (self->args[0] < 0)
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = §ors[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 = §ors[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
87
src/g_shared/a_doors.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
|
@ -503,7 +484,7 @@ static FLightNode * DeleteLightNode(FLightNode * 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(§ors[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 = §ors[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(§ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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
173
src/g_shared/a_floor.h
Normal 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,
|
||||
};
|
||||
|
|
@ -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 §or : level.sectors)
|
||||
for (const sector_t §or : 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);
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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,177 +326,6 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -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>(§ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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
115
src/g_shared/a_lights.h
Normal 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);
|
||||
};
|
184
src/g_shared/a_lighttransfer.cpp
Normal file
184
src/g_shared/a_lighttransfer.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
src/g_shared/a_lighttransfer.h
Normal file
46
src/g_shared/a_lighttransfer.h
Normal 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;
|
||||
};
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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 = §ors[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
37
src/g_shared/a_pillar.h
Normal 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;
|
||||
};
|
||||
|
|
@ -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 = §ors[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
60
src/g_shared/a_plats.h
Normal 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;
|
||||
};
|
||||
|
|
@ -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)
|
||||
{
|
||||
AActor* thing;
|
||||
sector_t* sec;
|
||||
|
||||
sec = &level.sectors[s];
|
||||
thing = sec->thinglist;
|
||||
|
||||
while (thing &&
|
||||
thing->GetClass()->TypeName != NAME_PointPusher &&
|
||||
thing->GetClass()->TypeName != NAME_PointPuller)
|
||||
{
|
||||
thing = thing->snext;
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
//
|
||||
// Initialize the sectors where pushers are present
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void P_SpawnPushers ()
|
||||
void FLevelLocals::AdjustPusher(int tag, int magnitude, int angle, bool wind)
|
||||
{
|
||||
line_t *l = &level.lines[0];
|
||||
int s;
|
||||
struct FThinkerCollection
|
||||
{
|
||||
int RefNum;
|
||||
DThinker *Obj;
|
||||
};
|
||||
|
||||
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
46
src/g_shared/a_pusher.h
Normal 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);
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
42
src/g_shared/a_scroll.h
Normal 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];
|
||||
};
|
||||
|
|
@ -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__
|
||||
|
|
|
@ -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)
|
|
@ -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();
|
||||
}
|
|
@ -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,14 +25,13 @@ 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
|
@ -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__
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
Loading…
Reference in a new issue