- updated OpenAL branch.

SVN r3269 (openal)
This commit is contained in:
Christoph Oelckers 2011-07-08 22:00:23 +00:00
commit f84368677a
485 changed files with 41338 additions and 17437 deletions

View file

@ -1,7 +1,7 @@
cmake_minimum_required( VERSION 2.4 )
if( CMAKE_COMPILER_IS_GNUC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fomit-frame-pointer" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
endif( CMAKE_COMPILER_IS_GNUC )
add_definitions( -DBZ_NO_STDIO )

View file

@ -7,7 +7,7 @@ if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
endif( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
if( CMAKE_COMPILER_IS_GNUCXX )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
if( NOT PROFILE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" )
endif( NOT PROFILE )

View file

@ -18,8 +18,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000 };
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 300 };
Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000, 0, 0, 0, 0, 0, 0, 0, 0 };
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 300, 0, 0, 0, 0, 0, 0, 0, 0 };
Gbs_Emu::Gbs_Emu()
{
@ -39,7 +39,7 @@ Gbs_Emu::Gbs_Emu()
set_max_initial_silence( 21 );
set_gain( 1.2 );
static equalizer_t const eq = { -1.0, 120 };
static equalizer_t const eq = { -1.0, 120, 0, 0, 0, 0, 0, 0, 0, 0 };
set_equalizer( eq );
}

View file

@ -24,7 +24,7 @@ int const silence_threshold = 0x10;
long const fade_block_size = 512;
int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
Music_Emu::equalizer_t const Music_Emu::tv_eq = { -8.0, 180 };
Music_Emu::equalizer_t const Music_Emu::tv_eq = { -8.0, 180, 0, 0, 0, 0, 0, 0, 0, 0 };
void Music_Emu::clear_track_vars()
{

View file

@ -31,8 +31,8 @@ int const fme7_flag = 0x20;
long const clock_divisor = 12;
Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = { -1.0, 80 };
Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq = { -15.0, 80 };
Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = { -1.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 };
Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq = { -15.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 };
int Nsf_Emu::pcm_read( void* emu, nes_addr_t addr )
{

View file

@ -36,7 +36,7 @@ Vgm_Emu::Vgm_Emu()
set_silence_lookahead( 1 ); // tracks should already be trimmed
static equalizer_t const eq = { -14.0, 80 };
static equalizer_t const eq = { -14.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 };
set_equalizer( eq );
}

View file

@ -337,7 +337,7 @@ void GMEAPI gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
void GMEAPI gme_equalizer( Music_Emu const* me, gme_equalizer_t* out )
{
gme_equalizer_t e = { };
gme_equalizer_t e = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
e.treble = me->equalizer().treble;
e.bass = me->equalizer().bass;
*out = e;

View file

@ -8,8 +8,8 @@ if( MSVC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102" )
endif( MSVC )
if( CMAKE_COMPILER_IS_GNUCXX )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
if( CMAKE_COMPILER_IS_GNUCXX )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
endif( CMAKE_COMPILER_IS_GNUCXX )
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )

View file

@ -1,7 +1,7 @@
cmake_minimum_required( VERSION 2.4 )
if( CMAKE_COMPILER_IS_GNUC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fomit-frame-pointer" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
endif( CMAKE_COMPILER_IS_GNUC )
add_library( jpeg

View file

@ -1,7 +1,7 @@
cmake_minimum_required( VERSION 2.4 )
if( CMAKE_COMPILER_IS_GNUC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fomit-frame-pointer" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
endif( CMAKE_COMPILER_IS_GNUC )
set( LZMA_FILES

View file

@ -1,5 +1,5 @@
===============================================================================
Universal Doom Map Format ZDoom extensions v1.10 - 25.04.2010
Universal Doom Map Format ZDoom extensions v1.15 - 14.12.2010
Copyright (c) 2008 Christoph Oelckers.
@ -84,6 +84,12 @@ field to 'strifeally', even for the 'Doom' namespace.
In addition to the standard fields, ZDoom defines the following:
Note: All <bool> fields default to false unless mentioned otherwise.
vertex
{
zfloor = <float>; // Floor height at this vertex. Only applies to triangular sectors
zceiling = <float>; // Ceiling height at this vertex. Only applies to triangular sectors
}
linedef
{
alpha = <float>; // Translucency of this line, default is 1.0
@ -106,6 +112,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
checkswitchrange = <bool>;// Switches can only be activated when vertically reachable.
blockprojectiles = <bool>;// Line blocks all projectiles
blockuse = <bool>; // Line blocks all use actions
blocksight = <bool>; // Line blocks monster line of sight
}
@ -153,9 +160,15 @@ Note: All <bool> fields default to false unless mentioned otherwise.
// relative to the owning sector's light level.
lightceilingabsolute = <bool>; // true = 'lightceiling' is an absolute value. Default is
// relative to the owning sector's light level.
alphafloor = <float>; // translucency of floor plane (only has meaning with Sector_SetPortal) Default is 1.0.
alphaceiling = <float>; // translucency of ceiling plane (only has meaning with Sector_SetPortal) Default is 1.0.
renderstylefloor = <string>; // floor plane renderstyle (only has meaning with Sector_SetPortal); not implemented yet in software renderer
// can be "translucent" or "add", default is "translucent".
renderstyleceiling = <string>; // ceiling plane renderstyle (only has meaning with Sector_SetPortal); not implemented yet in software renderer
// can be "translucent" or "add", default is "translucent".
gravity = <float>; // Sector's gravity. Default is 1.0.
lightcolor = <integer>; // Sector'S light color as RRGGBB value, default = 0xffffff.
fadecolor = <integer>; // Sector'S fog color as RRGGBB value, default = 0x000000.
lightcolor = <integer>; // Sector's light color as RRGGBB value, default = 0xffffff.
fadecolor = <integer>; // Sector's fog color as RRGGBB value, default = 0x000000.
desaturation = <float>; // Color desaturation factor. 0 = none, 1 = full, default = 0.
silent = <bool>; // Actors in this sector make no sound,
nofallingdamage = <bool>; // Falling damage is disabled in this sector
@ -167,7 +180,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
* Note about dropactors
The spec requires this to be false by default. Currently, however ZDoom assumes this to be true
The spec requires this to be false by default. Currently, however, ZDoom assumes this to be true
for Doom format maps so any map converter converting to the ZDoomTranslated namespace should
set this flag for each tagged sector.
@ -175,14 +188,11 @@ Note: All <bool> fields default to false unless mentioned otherwise.
thing
{
skill# = <bool> // Unlike the base spec, # can range from 1-8.
// 8 is the maximum amount of skills the skill
// menu can display.
class# = <bool> // Unlike the base spec, # can range from 1-8.
// 8 is the maximum amount of classes the class
// menu can display.
skill# = <bool> // Unlike the base spec, # can range from 1-16.
class# = <bool> // Unlike the base spec, # can range from 1-16.
conversation = <int> // Assigns a conversation dialogue to this thing.
// Parameter is the conversation ID, 0 meaning none.
countsecret = <bool>; // Picking up this actor counts as a secret.
}
@ -202,6 +212,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
181: Plane_Align, arg2
215: Teleport_Line, arg0
222: Scroll_Texture_Model, arg0 (arg0 must be preserved)
160: Sector_3DFloor, arg4 (both uses as high-byte of tag and line ID are not supported in UDMF and must be remapped)
Some specials also allow setting the extended flags. These must also be
converted to explicitly setting the flags through the defined map fields.
@ -269,7 +280,7 @@ Changed node specifications to deprecate compression of node lump.
Added 'playeruseback' line trigger flag.
1.11 07.08.2010
Added 'soundsequnce' sector property.
Added 'soundsequence' sector property.
1.12 22.08.2010
Added 'conversation' thing property.
@ -277,6 +288,21 @@ Added 'conversation' thing property.
1.13 29.08.2010
Added 'hidden' sector property.
1.14 19.09.2010
Added 'countsecret' actor property.
1.15 14.12.2010
Added vertex floor and ceiling height properties
1.16 23.01.2011
Added alphaceiling and alphafloor sector properties
Added blocksight linedef flag
Removed remarks of 8 being the maximum number of player classes/skill levels the menu can handle so the spec now properly lists 16 as limit.
1.17 12.02.2011
Added renderstyleceiling and renderstylefloor sector properties
Added Sector_Set3DFloor to list of specials that need to be handled for line ID remapping
===============================================================================
EOF
===============================================================================

View file

@ -298,6 +298,19 @@ else( WIN32 )
set( WITH_GSTREAMER ON )
endif( GSTREAMER_FOUND )
endif( NOT OPENAL_FOUND )
# Check for Xcursor library and header files
find_library( XCURSOR_LIB Xcursor )
if( XCURSOR_LIB )
find_file( XCURSOR_HEADER "X11/Xcursor/Xcursor.h" )
if( XCURSOR_HEADER )
add_definitions( -DUSE_XCURSOR=1 )
message( STATUS "Found Xcursor at ${XCURSOR_LIB}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${XCURSOR_LIB} )
else( XCURSOR_HEADER )
unset( XCURSOR_LIB )
endif( XCURSOR_HEADER )
endif( XCURSOR_LIB )
endif( APPLE )
set( NASM_NAMES nasm )
@ -524,8 +537,7 @@ endif( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX )
if( PROFILE )
set( CMAKE_C_FLinclude( FindFluidSynth.cmake )
AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
@ -539,7 +551,7 @@ AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_CXX_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_CXX_FLAGS}" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused -Wextra -Wno-missing-field-initializers" )
# Remove extra warnings when using the official DirectX headers.
# Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid,
@ -682,6 +694,7 @@ else( WIN32 )
sdl/hardware.cpp
sdl/i_cd.cpp
sdl/i_input.cpp
sdl/i_joystick.cpp
sdl/i_main.cpp
sdl/i_movie.cpp
sdl/i_system.cpp
@ -747,6 +760,7 @@ add_executable( zdoom WIN32
${SYSTEM_SOURCES}
${X86_SOURCES}
x86.cpp
actorptrselect.cpp
am_map.cpp
b_bot.cpp
b_func.cpp
@ -779,7 +793,6 @@ add_executable( zdoom WIN32
doomstat.cpp
dsectoreffect.cpp
dthinker.cpp
f_finale.cpp
f_wipe.cpp
farchive.cpp
files.cpp
@ -803,6 +816,7 @@ add_executable( zdoom WIN32
m_misc.cpp
m_png.cpp
m_random.cpp
memarena.cpp
md5.cpp
name.cpp
nodebuild.cpp
@ -852,19 +866,18 @@ add_executable( zdoom WIN32
p_xlat.cpp
parsecontext.cpp
po_man.cpp
r_anim.cpp
r_swrenderer.cpp
r_utility.cpp
r_3dfloors.cpp
r_bsp.cpp
r_data.cpp
r_draw.cpp
r_drawt.cpp
r_interpolate.cpp
r_main.cpp
r_plane.cpp
r_polymost.cpp
r_segs.cpp
r_sky.cpp
r_things.cpp
r_translate.cpp
s_advsound.cpp
s_environment.cpp
s_playlist.cpp
@ -872,8 +885,10 @@ add_executable( zdoom WIN32
s_sound.cpp
sc_man.cpp
st_stuff.cpp
statistics.cpp
stats.cpp
stringtable.cpp
strnatcmp.c
tables.cpp
teaminfo.cpp
tempfiles.cpp
@ -931,6 +946,8 @@ add_executable( zdoom WIN32
g_shared/sbar_mugshot.cpp
g_shared/shared_hud.cpp
g_shared/shared_sbar.cpp
intermission/intermission.cpp
intermission/intermission_parse.cpp
menu/colorpickermenu.cpp
menu/joystickmenu.cpp
menu/listmenu.cpp
@ -970,6 +987,7 @@ add_executable( zdoom WIN32
sound/music_mus_midiout.cpp
sound/music_smf_midiout.cpp
sound/music_hmi_midiout.cpp
sound/music_xmi_midiout.cpp
sound/music_midistream.cpp
sound/music_midi_base.cpp
sound/music_midi_timidity.cpp
@ -980,6 +998,9 @@ add_executable( zdoom WIN32
sound/music_timidity_mididevice.cpp
sound/music_win_mididevice.cpp
sound/oalsound.cpp
sound/music_pseudo_mididevice.cpp
textures/animations.cpp
textures/anim_switches.cpp
textures/automaptexture.cpp
textures/bitmap.cpp
textures/buildtexture.cpp
@ -1017,7 +1038,24 @@ add_executable( zdoom WIN32
timidity/resample.cpp
timidity/timidity.cpp
xlat/parse_xlat.cpp
autozend.cpp )
fragglescript/t_fspic.cpp
fragglescript/t_func.cpp
fragglescript/t_load.cpp
fragglescript/t_oper.cpp
fragglescript/t_parse.cpp
fragglescript/t_prepro.cpp
fragglescript/t_script.cpp
fragglescript/t_spec.cpp
fragglescript/t_variable.cpp
fragglescript/t_cmd.cpp
r_data/colormaps.cpp
r_data/sprites.cpp
r_data/voxels.cpp
r_data/renderstyle.cpp
r_data/r_interpolate.cpp
r_data/r_translate.cpp
autozend.cpp
)
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" )

View file

@ -95,6 +95,8 @@ DEFINE_SPECIAL(Polyobj_OR_MoveTimes8, 93, 4, 4, 4)
DEFINE_SPECIAL(Pillar_BuildAndCrush, 94, 4, 5, 5)
DEFINE_SPECIAL(FloorAndCeiling_LowerByValue, 95, 3, 3, 3)
DEFINE_SPECIAL(FloorAndCeiling_RaiseByValue, 96, 3, 3, 3)
DEFINE_SPECIAL(Ceiling_LowerAndCrushDist, 97, 3, 5, 5)
DEFINE_SPECIAL(Sector_SetTranslucent, 98, 3, 4, 4)
DEFINE_SPECIAL(Scroll_Texture_Left, 100, -1, -1, 2)
DEFINE_SPECIAL(Scroll_Texture_Right, 101, -1, -1, 2)
@ -123,7 +125,7 @@ DEFINE_SPECIAL(UsePuzzleItem, 129, 2, 5, 5)
DEFINE_SPECIAL(Thing_Activate, 130, 1, 1, 1)
DEFINE_SPECIAL(Thing_Deactivate, 131, 1, 1, 1)
DEFINE_SPECIAL(Thing_Remove, 132, 1, 1, 1)
DEFINE_SPECIAL(Thing_Destroy, 133, 1, 2, 2)
DEFINE_SPECIAL(Thing_Destroy, 133, 1, 3, 3)
DEFINE_SPECIAL(Thing_Projectile, 134, 5, 5, 5)
DEFINE_SPECIAL(Thing_Spawn, 135, 3, 4, 4)
DEFINE_SPECIAL(Thing_ProjectileGravity, 136, 5, 5, 5)
@ -226,7 +228,7 @@ DEFINE_SPECIAL(Elevator_LowerToNearest, 247, 2, 2, 2)
DEFINE_SPECIAL(HealThing, 248, 1, 2, 2)
DEFINE_SPECIAL(Door_CloseWaitOpen, 249, 3, 4, 4)
DEFINE_SPECIAL(Floor_Donut, 250, 3, 3, 3)
DEFINE_SPECIAL(FloorAndCeiling_LowerRaise, 251, 3, 3, 3)
DEFINE_SPECIAL(FloorAndCeiling_LowerRaise, 251, 3, 3, 4)
DEFINE_SPECIAL(Ceiling_RaiseToNearest, 252, 2, 2, 2)
DEFINE_SPECIAL(Ceiling_LowerToLowest, 253, 2, 2, 2)
DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 2, 2)

View file

@ -37,8 +37,9 @@
#include "doomdef.h"
#include "textures/textures.h"
#include "r_blend.h"
#include "r_data/renderstyle.h"
#include "s_sound.h"
#include "memarena.h"
struct subsector_t;
//
@ -269,7 +270,7 @@ enum
MF5_FASTMELEE = 0x00000002, // has a faster melee attack when DF_FAST_MONSTERS or nightmare is on.
MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances.
/* = 0x00000008, */
/* = 0x00000010, */
MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret
MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs
MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage
MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set.
@ -289,7 +290,7 @@ enum
MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks
MF5_NOTIMEFREEZE = 0x00400000, // Actor is not affected by time freezer
MF5_PUFFGETSOWNER = 0x00800000, // [BB] Sets the owner of the puff to the player who fired it
MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to removr
MF5_SPECIALFIREDAMAGE=0x01000000, // Special treatment of PhoenixFX1 turned into a flag to remove
// dependence of main engine code of specific actor types.
MF5_SUMMONEDMONSTER = 0x02000000, // To mark the friendly Minotaur. Hopefully to be generalized later.
MF5_NOVERTICALMELEERANGE=0x04000000,// Does not check vertical distance for melee range
@ -323,6 +324,12 @@ enum
MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself
MF6_ADDITIVEPOISONDAMAGE = 0x00100000,
MF6_ADDITIVEPOISONDURATION = 0x00200000,
MF6_NOMENU = 0x00400000, // Player class should not appear in the class selection menu.
MF6_BOSSCUBE = 0x00800000, // Actor spawned by A_BrainSpit, flagged for timefreeze reasons.
MF6_SEEINVISIBLE = 0x01000000, // Monsters can see invisible player.
MF6_DONTCORPSE = 0x02000000, // [RC] Don't autoset MF_CORPSE upon death and don't force Crash state change.
MF6_POISONALWAYS = 0x04000000, // Always apply poison, even when target can't take the damage.
MF6_DOHARMSPECIES = 0x08000000, // Do hurt one's own species with projectiles.
// --- mobj.renderflags ---
@ -528,7 +535,12 @@ struct FDropItem
class FDropItemPtrArray : public TArray<FDropItem *>
{
public:
~FDropItemPtrArray();
~FDropItemPtrArray()
{
Clear();
}
void Clear();
};
extern FDropItemPtrArray DropItemList;
@ -675,7 +687,7 @@ public:
void ConversationAnimation (int animnum);
// Make this actor hate the same things as another actor
void CopyFriendliness (AActor *other, bool changeTarget);
void CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth=true);
// Moves the other actor's inventory to this one
void ObtainInventory (AActor *other);
@ -703,6 +715,12 @@ public:
// Return starting health adjusted by skill level
int SpawnHealth();
int GibHealth();
inline bool isMissile(bool precise=true)
{
return (flags&MF_MISSILE) || (precise && GetDefault()->flags&MF_MISSILE);
}
// Check for monsters that count as kill but excludes all friendlies.
bool CountsAsKill() const
@ -753,6 +771,7 @@ public:
fixed_t GetGravity() const;
bool IsSentient() const;
const char *GetTag(const char *def = NULL) const;
void SetTag(const char *def);
// info for drawing
@ -788,6 +807,7 @@ public:
SDWORD tics; // state tic counter
FState *state;
SDWORD Damage; // For missiles and monster railgun
int projectileKickback;
DWORD flags;
DWORD flags2; // Heretic flags
DWORD flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable
@ -832,7 +852,7 @@ public:
BYTE MinMissileChance;// [RH] If a random # is > than this, then missile attack.
SBYTE LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0)
WORD BounceFlags; // which bouncing type?
WORD SpawnFlags;
DWORD SpawnFlags; // Increased to DWORD because of Doom 64
fixed_t meleerange; // specifies how far a melee attack reaches.
fixed_t meleethreshold; // Distance below which a monster doesn't try to shoot missiles anynore
// but instead tries to come closer for a melee attack.
@ -848,16 +868,19 @@ public:
int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL
int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL
int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything.
FNameNoInit Tag; // Strife's tag name. FIXME: should be case sensitive!
FString * Tag; // Strife's tag name.
int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players.
AActor *BlockingMobj; // Actor that blocked the last move
line_t *BlockingLine; // Line that blocked the last move
int PoisonDamage; // Damage received per tic from poison.
FNameNoInit PoisonDamageType; // Damage type dealt by poison.
int PoisonDuration; // Duration left for receiving poison damage.
int PoisonPeriod; // How often poison damage is applied. (Every X tics.)
int PoisonDamageReceived; // Damage received per tic from poison.
FNameNoInit PoisonDamageTypeReceived; // Damage type received by poison.
int PoisonDurationReceived; // Duration left for receiving poison damage.
int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.)
TObjPtr<AActor> Poisoner; // Last source of received poison damage.
@ -894,8 +917,12 @@ public:
SWORD PainChance;
int PainThreshold;
FNameNoInit DamageType;
FNameNoInit DamageTypeReceived;
fixed_t DamageFactor;
FNameNoInit PainType;
FNameNoInit DeathType;
FState *SpawnState;
FState *SeeState;
FState *MeleeState;
@ -920,6 +947,7 @@ public:
private:
static AActor *TIDHash[128];
static inline int TIDHASH (int key) { return key & 127; }
static FSharedStringArena mStringPropertyData;
friend class FActorIterator;
@ -937,6 +965,7 @@ public:
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
bool isFast();
void SetIdle();
void ClearCounters();
FState *FindState (FName label) const
{
@ -1029,6 +1058,7 @@ inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)
return static_cast<T *>(AActor::StaticSpawn (RUNTIME_CLASS(T), x, y, z, allowreplacement));
}
void PrintMiscActorInfo(AActor * query);
#define S_FREETARGMOBJ 1

179
src/actorptrselect.cpp Normal file
View file

@ -0,0 +1,179 @@
#include "actorptrselect.h"
#include "actor.h"
#include "d_player.h"
#include "p_pspr.h"
//==========================================================================
//
// Standard pointer acquisition functions
//
// Possible effective results at run-time
// assigntovariable = NULL (or a RETURN statement is issued)
// P_BulletSlope(pointer_owner, &temporary), assigntovariable = temporary
// assigntovariable = pointer_owner->target or ...->master or ...->tracer
//
//==========================================================================
/*
COPY_AAPTR
Result overview in order of priority:
1. Caller is player and a player specific selector is specified: Player specific selector is used.
2. Caller is non-null and a general actor selector is specified: General actor selector is used.
3. A static actor selector is specified: Static actor selector is used.
4. The origin actor is used.
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 (origin)
{
if (origin->player)
{
switch (selector & AAPTR_PLAYER_SELECTORS)
{
case AAPTR_PLAYER_GETTARGET:
{
AActor *gettarget = NULL;
P_BulletSlope(origin, &gettarget);
return gettarget;
}
case AAPTR_PLAYER_GETCONVERSATION:
return origin->player->ConversationNPC;
}
}
switch (selector & AAPTR_GENERAL_SELECTORS)
{
case AAPTR_TARGET: return origin->target;
case AAPTR_MASTER: return origin->master;
case AAPTR_TRACER: return origin->tracer;
case AAPTR_FRIENDPLAYER:
return origin->FriendPlayer ? AAPTR_RESOLVE_PLAYERNUM(origin->FriendPlayer - 1) : NULL;
}
}
switch (selector & AAPTR_STATIC_SELECTORS)
{
case AAPTR_PLAYER1: return AAPTR_RESOLVE_PLAYERNUM(0);
case AAPTR_PLAYER2: return AAPTR_RESOLVE_PLAYERNUM(1);
case AAPTR_PLAYER3: return AAPTR_RESOLVE_PLAYERNUM(2);
case AAPTR_PLAYER4: return AAPTR_RESOLVE_PLAYERNUM(3);
case AAPTR_PLAYER5: return AAPTR_RESOLVE_PLAYERNUM(4);
case AAPTR_PLAYER6: return AAPTR_RESOLVE_PLAYERNUM(5);
case AAPTR_PLAYER7: return AAPTR_RESOLVE_PLAYERNUM(6);
case AAPTR_PLAYER8: return AAPTR_RESOLVE_PLAYERNUM(7);
case AAPTR_NULL: return NULL;
}
return origin;
}
// [FDARI] Exported logic for guarding against loops in Target (for missiles) and Master (for all) chains.
// It is called from multiple locations.
// The code may be in need of optimisation.
//==========================================================================
//
// Checks whether this actor is a missile
// Unfortunately this was buggy in older versions of the code and many
// released DECORATE monsters rely on this bug so it can only be fixed
// with an optional flag
//
//==========================================================================
void VerifyTargetChain(AActor *self, bool preciseMissileCheck)
{
if (!self || !self->isMissile(preciseMissileCheck)) return;
AActor *origin = self;
AActor *next = origin->target;
// origin: the most recent actor that has been verified as appearing only once
// next: the next actor to be verified; will be "origin" in the next iteration
while (next && next->isMissile(preciseMissileCheck)) // we only care when there are missiles involved
{
AActor *compare = self;
// every new actor must prove not to be the first actor in the chain, or any subsequent actor
// any actor up to and including "origin" has only appeared once
for (;;)
{
if (compare == next)
{
// if any of the actors from self to (inclusive) origin match the next actor,
// self has reached/created a loop
self->target = NULL;
return;
}
if (compare == origin) break; // when "compare" = origin, we know that the next actor is, and should be "next"
compare = compare->target;
}
origin = next;
next = next->target;
}
}
void VerifyMasterChain(AActor *self)
{
// See VerifyTargetChain for detailed comments.
if (!self) return;
AActor *origin = self;
AActor *next = origin->master;
while (next) // We always care (See "VerifyTargetChain")
{
AActor *compare = self;
for (;;)
{
if (compare == next)
{
self->master = NULL;
return;
}
if (compare == origin) break;
compare = compare->master;
}
origin = next;
next = next->master;
}
}
//==========================================================================
//
// Checks whether this actor is a missile
// Unfortunately this was buggy in older versions of the code and many
// released DECORATE monsters rely on this bug so it can only be fixed
// with an optional flag
//
//==========================================================================
void ASSIGN_AAPTR(AActor *toActor, int toSlot, AActor *ptr, int flags)
{
switch (toSlot)
{
case AAPTR_TARGET:
toActor->target = ptr;
if (!(PTROP_UNSAFETARGET & (flags))) VerifyTargetChain(toActor);
break;
case AAPTR_MASTER:
toActor->master = ptr;
if (!(PTROP_UNSAFEMASTER & (flags))) VerifyMasterChain(toActor);
break;
case AAPTR_TRACER:
toActor->tracer = ptr;
break;
}
}

98
src/actorptrselect.h Normal file
View file

@ -0,0 +1,98 @@
#pragma once
//==========================================================================
//
// Standard pointer acquisition functions
//
// Possible effective results at run-time
// assigntovariable = NULL (or a RETURN statement is issued)
// P_BulletSlope(pointer_owner, &temporary), assigntovariable = temporary
// assigntovariable = pointer_owner->target or ...->master or ...->tracer
//
//==========================================================================
class AActor;
// Pointer selectors (enum)
enum AAPTR
{
AAPTR_DEFAULT = 0,
AAPTR_NULL = 0x1,
AAPTR_TARGET = 0x2,
AAPTR_MASTER = 0x4,
AAPTR_TRACER = 0x8,
AAPTR_PLAYER_GETTARGET = 0x10,
AAPTR_PLAYER_GETCONVERSATION = 0x20,
AAPTR_PLAYER1 = 0x40,
AAPTR_PLAYER2 = 0x80,
AAPTR_PLAYER3 = 0x100,
AAPTR_PLAYER4 = 0x200,
AAPTR_PLAYER5 = 0x400,
AAPTR_PLAYER6 = 0x800,
AAPTR_PLAYER7 = 0x1000,
AAPTR_PLAYER8 = 0x2000,
AAPTR_FRIENDPLAYER = 0x4000,
AAPTR_PLAYER_SELECTORS =
AAPTR_PLAYER_GETTARGET|AAPTR_PLAYER_GETCONVERSATION,
AAPTR_GENERAL_SELECTORS =
AAPTR_TARGET|AAPTR_MASTER|AAPTR_TRACER|AAPTR_FRIENDPLAYER,
AAPTR_STATIC_SELECTORS =
AAPTR_PLAYER1|AAPTR_PLAYER2|AAPTR_PLAYER3|AAPTR_PLAYER4|
AAPTR_PLAYER5|AAPTR_PLAYER6|AAPTR_PLAYER7|AAPTR_PLAYER8|
AAPTR_NULL
};
/*
COPY_AAPTR
Result overview in order of priority:
1. Caller is player and a player specific selector is specified: Player specific selector is used.
2. Caller is non-null and a general actor selector is specified: General actor selector is used.
3. A static actor selector is specified: Static actor selector is used.
4. The origin actor is used.
Only one selector of each type can be used.
*/
AActor *COPY_AAPTR(AActor *origin, int selector);
// Use COPY_AAPTR_NOT_NULL to return from a function if the pointer is NULL
#define COPY_AAPTR_NOT_NULL(source, destination, selector) { destination = COPY_AAPTR(source, selector); if (!destination) return; }
enum PTROP
{
PTROP_UNSAFETARGET = 1,
PTROP_UNSAFEMASTER = 2,
PTROP_NOSAFEGUARDS = PTROP_UNSAFETARGET|PTROP_UNSAFEMASTER
};
// [FDARI] Exported logic for guarding against loops in Target (for missiles) and Master (for all) chains.
// It is called from multiple locations.
// The code may be in need of optimisation.
//==========================================================================
//
// Checks whether this actor is a missile
// Unfortunately this was buggy in older versions of the code and many
// released DECORATE monsters rely on this bug so it can only be fixed
// with an optional flag
//
//==========================================================================
void VerifyTargetChain(AActor *self, bool preciseMissileCheck=true);
void VerifyMasterChain(AActor *self);
void ASSIGN_AAPTR(AActor *toActor, int toSlot, AActor *ptr, int flags) ;

View file

@ -33,12 +33,13 @@
#include "w_wad.h"
#include "a_sharedglobal.h"
#include "statnums.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "d_event.h"
#include "gi.h"
#include "r_bsp.h"
#include "p_setup.h"
#include "c_bind.h"
#include "farchive.h"
#include "r_renderer.h"
#include "m_cheat.h"
#include "i_system.h"
@ -63,6 +64,13 @@
#include "a_artifacts.h"
#include "po_man.h"
#include "a_keys.h"
#include "r_data/colormaps.h"
//=============================================================================
//
// Automap colors
//
//=============================================================================
struct AMColor
{
@ -83,9 +91,9 @@ struct AMColor
};
static AMColor Background, YourColor, WallColor, TSWallColor,
FDWallColor, CDWallColor, ThingColor,
FDWallColor, CDWallColor, EFWallColor, ThingColor,
ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend,
SecretWallColor, GridColor, XHairColor,
SpecialWallColor, SecretWallColor, GridColor, XHairColor,
NotSeenColor,
LockedColor,
AlmostBackground,
@ -119,6 +127,12 @@ static BYTE RavenPaletteVals[11*3] =
0, 0, 0, 0, 0, 0,
};
//=============================================================================
//
// globals
//
//=============================================================================
#define MAPBITS 12
#define MapDiv SafeDivScale12
#define MapMul MulScale12
@ -155,9 +169,11 @@ CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE);
CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE);
CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE);
CVAR (Color, am_secretwallcolor, 0x000000, CVAR_ARCHIVE);
CVAR (Color, am_specialwallcolor, 0xffffff, CVAR_ARCHIVE);
CVAR (Color, am_tswallcolor, 0x888888, CVAR_ARCHIVE);
CVAR (Color, am_fdwallcolor, 0x887058, CVAR_ARCHIVE);
CVAR (Color, am_cdwallcolor, 0x4c3820, CVAR_ARCHIVE);
CVAR (Color, am_efwallcolor, 0x665555, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor, 0xfcfcfc, CVAR_ARCHIVE);
CVAR (Color, am_gridcolor, 0x8b5a2b, CVAR_ARCHIVE);
CVAR (Color, am_xhaircolor, 0x808080, CVAR_ARCHIVE);
@ -165,6 +181,7 @@ CVAR (Color, am_notseencolor, 0x6c6c6c, CVAR_ARCHIVE);
CVAR (Color, am_lockedcolor, 0x007800, CVAR_ARCHIVE);
CVAR (Color, am_ovyourcolor, 0xfce8d8, CVAR_ARCHIVE);
CVAR (Color, am_ovwallcolor, 0x00ff00, CVAR_ARCHIVE);
CVAR (Color, am_ovspecialwallcolor, 0xffffff, CVAR_ARCHIVE);
CVAR (Color, am_ovthingcolor, 0xe88800, CVAR_ARCHIVE);
CVAR (Color, am_ovotherwallscolor, 0x008844, CVAR_ARCHIVE);
CVAR (Color, am_ovunseencolor, 0x00226e, CVAR_ARCHIVE);
@ -176,6 +193,7 @@ CVAR (Color, am_ovsecretsectorcolor,0x00ffff, CVAR_ARCHIVE);
CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE);
CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE);
CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE);
CVAR (Bool, am_showtriggerlines, false, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE);
@ -287,72 +305,28 @@ struct islope_t
// A line drawing of the player pointing right,
// starting from the middle.
//
#define R ((8*PLAYERRADIUS)/7)
mline_t player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/4 } }, // ----->
{ { R, 0 }, { R-R/2, -R/4 } },
{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
};
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
mline_t player_arrow_raven[] = {
{ { -R+R/4, 0 }, { 0, 0} }, // center line.
{ { -R+R/4, R/8 }, { R, 0} }, // blade
{ { -R+R/4, -R/8 }, { R, 0 } },
{ { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
{ { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
{ { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors
{ { -R+R/8, R/4 }, { -R+R/4, R/4} },
{ { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel
{ { -R-R/4, R/8 }, { -R+R/8, R/8 } },
{ { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
};
#define NUMPLYRLINES_RAVEN (sizeof(player_arrow_raven)/sizeof(mline_t))
mline_t cheat_player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/6 } }, // ----->
{ { R, 0 }, { R-R/2, -R/6 } },
{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
{ { -R/6, -R/6 }, { 0, -R/6 } },
{ { 0, -R/6 }, { 0, R/4 } },
{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
};
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
#undef R
static TArray<mline_t> MapArrow;
static TArray<mline_t> CheatMapArrow;
static TArray<mline_t> CheatKey;
#define R (MAPUNIT)
// [RH] Avoid lots of warnings without compiler-specific #pragmas
#define L(a,b,c,d) { {(fixed_t)((a)*R),(fixed_t)((b)*R)}, {(fixed_t)((c)*R),(fixed_t)((d)*R)} }
mline_t triangle_guy[] = {
static mline_t triangle_guy[] = {
L (-.867,-.5, .867,-.5),
L (.867,-.5, 0,1),
L (0,1, -.867,-.5)
};
#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
mline_t thintriangle_guy[] = {
static mline_t thintriangle_guy[] = {
L (-.5,-.7, 1,0),
L (1,0, -.5,.7),
L (-.5,.7, -.5,-.7)
};
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
mline_t square_guy[] = {
static mline_t square_guy[] = {
L (0,1,1,0),
L (1,0,0,-1),
L (0,-1,-1,0),
@ -361,26 +335,6 @@ mline_t square_guy[] = {
#define NUMSQUAREGUYLINES (sizeof(square_guy)/sizeof(mline_t))
#undef R
#define R (MAPUNIT)
mline_t key_guy[] = {
L (-2, 0, -1.7, -0.5),
L (-1.7, -0.5, -1.5, -0.7),
L (-1.5, -0.7, -0.8, -0.5),
L (-0.8, -0.5, -0.6, 0),
L (-0.6, 0, -0.8, 0.5),
L (-1.5, 0.7, -0.8, 0.5),
L (-1.7, 0.5, -1.5, 0.7),
L (-2, 0, -1.7, 0.5),
L (-0.6, 0, 2, 0),
L (1.7, 0, 1.7, -1),
L (1.5, 0, 1.5, -1),
L (1.3, 0, 1.3, -1)
};
#define NUMKEYGUYLINES (sizeof(key_guy)/sizeof(mline_t))
#undef L
#undef R
@ -396,8 +350,6 @@ CUSTOM_CVAR (Int, am_cheat, 0, 0)
static int grid = 0;
static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
bool automapactive = false;
// location of window on screen
@ -449,8 +401,6 @@ static FTextureID marknums[10]; // numbers used for marking by the automap
static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
static int markpointnum = 0; // next point to be assigned
static int followplayer = 1; // specifies whether to follow the player around
static FTextureID mapback; // the automap background
static fixed_t mapystart=0; // y-value for the start of the map bitmap...used in the parallax stuff.
static fixed_t mapxstart=0; //x-value for the bitmap.
@ -476,11 +426,14 @@ void AM_restoreScaleAndLoc ();
void AM_minOutWindowScale ();
CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE)
CCMD(am_togglefollow)
{
followplayer = !followplayer;
am_followplayer = !am_followplayer;
f_oldloc.x = FIXED_MAX;
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
Printf ("%s\n", GStrings(am_followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
}
CCMD(am_togglegrid)
@ -545,6 +498,76 @@ void AM_getIslope (mline_t *ml, islope_t *is)
}
*/
void AM_ParseArrow(TArray<mline_t> &Arrow, const char *lumpname)
{
const int R = ((8*PLAYERRADIUS)/7);
FScanner sc;
int lump = Wads.CheckNumForFullName(lumpname, true);
if (lump >= 0)
{
sc.OpenLumpNum(lump);
sc.SetCMode(true);
while (sc.GetToken())
{
mline_t line;
sc.TokenMustBe('(');
sc.MustGetFloat();
line.a.x = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(',');
sc.MustGetFloat();
line.a.y = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(')');
sc.MustGetToken(',');
sc.MustGetToken('(');
sc.MustGetFloat();
line.b.x = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(',');
sc.MustGetFloat();
line.b.y = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(')');
Arrow.Push(line);
}
}
}
void AM_StaticInit()
{
MapArrow.Clear();
CheatMapArrow.Clear();
CheatKey.Clear();
if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow);
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
AM_ParseArrow(CheatKey, "maparrows/key.txt");
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
char namebuf[9];
for (int i = 0; i < 10; i++)
{
mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i);
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
}
markpointnum = 0;
mapback.SetInvalid();
static DWORD *lastpal = NULL;
//static int lastback = -1;
DWORD *palette;
palette = (DWORD *)GPalette.BaseColors;
int i, j;
for (i = j = 0; i < 11; i++, j += 3)
{
DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]);
StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]);
RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]);
}
}
//=============================================================================
//
// called by the coordinate drawer
@ -599,7 +622,7 @@ void AM_restoreScaleAndLoc ()
{
m_w = old_m_w;
m_h = old_m_h;
if (!followplayer)
if (!am_followplayer)
{
m_x = old_m_x;
m_y = old_m_y;
@ -796,7 +819,7 @@ void AM_changeWindowLoc ()
{
if (0 != (m_paninc.x | m_paninc.y))
{
followplayer = 0;
am_followplayer = false;
f_oldloc.x = FIXED_MAX;
}
@ -868,18 +891,6 @@ void AM_initVariables ()
old_m_h = m_h;
}
/*
static void GetComponents (int color, DWORD *palette, float &r, float &g, float &b)
{
if (palette)
color = palette[color];
r = (float)RPART(color);
g = (float)GPART(color);
b = (float)BPART(color);
}
*/
//=============================================================================
//
//
@ -888,28 +899,11 @@ static void GetComponents (int color, DWORD *palette, float &r, float &g, float
static void AM_initColors (bool overlayed)
{
static DWORD *lastpal = NULL;
//static int lastback = -1;
DWORD *palette;
palette = (DWORD *)GPalette.BaseColors;
if (lastpal != palette)
{
int i, j;
for (i = j = 0; i < 11; i++, j += 3)
{
DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]);
StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]);
RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]);
}
}
if (overlayed)
{
YourColor.FromCVar (am_ovyourcolor);
WallColor.FromCVar (am_ovwallcolor);
SpecialWallColor.FromCVar(am_ovspecialwallcolor);
SecretWallColor = WallColor;
SecretSectorColor.FromCVar (am_ovsecretsectorcolor);
ThingColor_Item.FromCVar (am_ovthingcolor_item);
@ -918,7 +912,7 @@ static void AM_initColors (bool overlayed)
ThingColor_Monster.FromCVar (am_ovthingcolor_monster);
ThingColor.FromCVar (am_ovthingcolor);
LockedColor.FromCVar (am_ovotherwallscolor);
FDWallColor = CDWallColor = LockedColor;
EFWallColor = FDWallColor = CDWallColor = LockedColor;
TSWallColor.FromCVar (am_ovunseencolor);
NotSeenColor = TSWallColor;
InterTeleportColor.FromCVar (am_ovtelecolor);
@ -932,10 +926,12 @@ static void AM_initColors (bool overlayed)
Background.FromCVar (am_backcolor);
YourColor.FromCVar (am_yourcolor);
SecretWallColor.FromCVar (am_secretwallcolor);
SpecialWallColor.FromCVar (am_specialwallcolor);
WallColor.FromCVar (am_wallcolor);
TSWallColor.FromCVar (am_tswallcolor);
FDWallColor.FromCVar (am_fdwallcolor);
CDWallColor.FromCVar (am_cdwallcolor);
EFWallColor.FromCVar (am_efwallcolor);
ThingColor_Item.FromCVar (am_thingcolor_item);
ThingColor_CountItem.FromCVar (am_thingcolor_citem);
ThingColor_Friend.FromCVar (am_thingcolor_friend);
@ -973,9 +969,10 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = DoomColors[3];
TSWallColor = DoomColors[4];
FDWallColor = DoomColors[5];
EFWallColor = FDWallColor = DoomColors[5];
LockedColor =
CDWallColor = DoomColors[6];
ThingColor_Item =
@ -994,9 +991,10 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = StrifeColors[3];
TSWallColor = StrifeColors[4];
FDWallColor = StrifeColors[5];
EFWallColor = FDWallColor = StrifeColors[5];
LockedColor =
CDWallColor = StrifeColors[6];
ThingColor_Item = StrifeColors[10];
@ -1015,9 +1013,10 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = RavenColors[3];
TSWallColor = RavenColors[4];
FDWallColor = RavenColors[5];
EFWallColor = FDWallColor = RavenColors[5];
LockedColor =
CDWallColor = RavenColors[6];
ThingColor =
@ -1030,30 +1029,6 @@ static void AM_initColors (bool overlayed)
break;
}
lastpal = palette;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_loadPics ()
{
int i;
char namebuf[9];
for (i = 0; i < 10; i++)
{
mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i);
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
}
const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0];
mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch);
}
//=============================================================================
@ -1078,7 +1053,8 @@ bool AM_clearMarks ()
void AM_LevelInit ()
{
leveljuststarted = 0;
const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0];
mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch);
AM_clearMarks();
@ -1116,7 +1092,6 @@ void AM_Start ()
if (!stopped) AM_Stop();
stopped = false;
AM_initVariables();
AM_loadPics();
}
@ -1228,7 +1203,7 @@ bool AM_Responder (event_t *ev, bool last)
{
if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
{
if (followplayer)
if (am_followplayer)
{
// check for am_pan* and ignore in follow mode
const char *defbind = AutomapBindings.GetBind(ev->data1);
@ -1275,6 +1250,10 @@ void AM_changeWindowScale ()
{
mtof_zoommul = int(M_ZOOMOUT);
}
else
{
mtof_zoommul = MAPUNIT;
}
am_zoomdir = 0;
// Change the scaling multipliers
@ -1341,7 +1320,7 @@ void AM_Ticker ()
amclock++;
if (followplayer)
if (am_followplayer)
{
AM_doFollowPlayer();
}
@ -1484,28 +1463,28 @@ bool AM_clipMline (mline_t *ml, fline_t *fl)
{
dy = fl->a.y - fl->b.y;
dx = fl->b.x - fl->a.x;
tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
tmp.x = fl->a.x + Scale(dx, fl->a.y, dy);
tmp.y = 0;
}
else if (outside & BOTTOM)
{
dy = fl->a.y - fl->b.y;
dx = fl->b.x - fl->a.x;
tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
tmp.x = fl->a.x + Scale(dx, fl->a.y - f_h, dy);
tmp.y = f_h-1;
}
else if (outside & RIGHT)
{
dy = fl->b.y - fl->a.y;
dx = fl->b.x - fl->a.x;
tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
tmp.y = fl->a.y + Scale(dy, f_w-1 - fl->a.x, dx);
tmp.x = f_w-1;
}
else if (outside & LEFT)
{
dy = fl->b.y - fl->a.y;
dx = fl->b.x - fl->a.x;
tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
tmp.y = fl->a.y + Scale(dy, -fl->a.x, dx);
tmp.x = 0;
}
@ -1561,7 +1540,7 @@ void AM_drawGrid (const AMColor &color)
// [RH] Calculate a minimum for how long the grid lines should be so that
// they cover the screen at any rotation.
minlen = (fixed_t)sqrtf ((float)m_w*(float)m_w + (float)m_h*(float)m_h);
minlen = (fixed_t)sqrt ((double)m_w*(double)m_w + (double)m_h*(double)m_h);
extx = (minlen - m_w) / 2;
exty = (minlen - m_h) / 2;
@ -1655,8 +1634,7 @@ void AM_drawSubsectors()
points[j].Y = f_y + (f_h - (pt.y - m_y) * scale / float(1 << 24));
}
// For lighting and texture determination
sector_t *sec = R_FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight,
&ceilinglight, false);
sector_t *sec = Renderer->FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight, &ceilinglight, false);
// Find texture origin.
mpoint_t originpt = { -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS,
sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS };
@ -1676,6 +1654,56 @@ void AM_drawSubsectors()
originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24));
// Coloring for the polygon
colormap = sec->ColorMap;
FTextureID maptex = sec->GetTexture(sector_t::floor);
#ifdef _3DFLOORS
if (sec->e->XFloor.ffloors.Size())
{
secplane_t *floorplane = &sec->floorplane;
// Look for the highest floor below the camera viewpoint.
// Check the center of the subsector's sector. Do not check each
// subsector separately because that might result in different planes for
// different subsectors of the same sector which is not wanted here.
// (Make the comparison in floating point to avoid overflows and improve performance.)
double secx;
double secy;
double cmpz = FIXED2DBL(viewz);
if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector)
{
// For the actual camera sector use the current viewpoint as reference.
secx = FIXED2DBL(viewx);
secy = FIXED2DBL(viewy);
}
else
{
secx = FIXED2DBL(sec->soundorg[0]);
secy = FIXED2DBL(sec->soundorg[1]);
}
for (unsigned int i = 0; i < sec->e->XFloor.ffloors.Size(); ++i)
{
F3DFloor *rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & FF_FOG) continue;
if (rover->alpha == 0) continue;
if (rover->top.plane->ZatPoint(secx, secy) < cmpz)
{
maptex = *(rover->top.texture);
floorplane = rover->top.plane;
break;
}
}
lightlist_t *light = P_GetPlaneLight(sec, floorplane, false);
floorlight = *light->p_lightlevel;
colormap = light->extra_colormap;
}
#endif
// If this subsector has not actually been seen yet (because you are cheating
// to see it on the map), tint and desaturate it.
if (!(subsectors[i].flags & SSECF_DRAWN))
@ -1691,8 +1719,7 @@ void AM_drawSubsectors()
}
// Draw the polygon.
screen->FillSimplePoly(
TexMan(sec->GetTexture(sector_t::floor)),
screen->FillSimplePoly(TexMan(maptex),
&points[0], points.Size(),
originx, originy,
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
@ -1806,6 +1833,69 @@ void AM_showSS()
}
}
#ifdef _3DFLOORS
//=============================================================================
//
// Determines if a 3D floor boundary should be drawn
//
//=============================================================================
bool AM_Check3DFloors(line_t *line)
{
TArray<F3DFloor*> &ff_front = line->frontsector->e->XFloor.ffloors;
TArray<F3DFloor*> &ff_back = line->backsector->e->XFloor.ffloors;
// No 3D floors so there's no boundary
if (ff_back.Size() == 0 && ff_front.Size() == 0) return false;
int realfrontcount = 0;
int realbackcount = 0;
for(unsigned i=0;i<ff_front.Size();i++)
{
F3DFloor *rover = ff_front[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->alpha == 0) continue;
realfrontcount++;
}
for(unsigned i=0;i<ff_back.Size();i++)
{
F3DFloor *rover = ff_back[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->alpha == 0) continue;
realbackcount++;
}
// if the amount of 3D floors does not match there is a boundary
if (realfrontcount != realbackcount) return true;
for(unsigned i=0;i<ff_front.Size();i++)
{
F3DFloor *rover = ff_front[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->alpha == 0) continue;
bool found = false;
for(unsigned j=0;j<ff_back.Size();j++)
{
F3DFloor *rover2 = ff_back[j];
if (!(rover2->flags & FF_EXISTS)) continue;
if (rover2->alpha == 0) continue;
if (rover->model == rover2->model && rover->flags == rover2->flags)
{
found = true;
break;
}
}
// At least one 3D floor in the front sector didn't have a match in the back sector so there is a boundary.
if (!found) return true;
}
// All 3D floors could be matched so let's not draw a boundary.
return false;
}
#endif
//=============================================================================
//
// Determines visible lines, draws them.
@ -1873,14 +1963,16 @@ void AM_drawWalls (bool allmap)
else if (lines[i].special == Door_LockedRaise ||
lines[i].special == ACS_LockedExecute ||
lines[i].special == ACS_LockedExecuteDoor ||
(lines[i].special == Generic_Door && lines[i].args[4] !=0 ))
(lines[i].special == Door_Animated && lines[i].args[3] != 0) ||
(lines[i].special == Generic_Door && lines[i].args[4] != 0))
{
if (am_colorset == 0 || am_colorset == 3) // Raven games show door colors
{
int P_GetMapColorForLock(int lock);
int lock;
if (lines[i].special==Door_LockedRaise) lock=lines[i].args[3];
if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated)
lock=lines[i].args[3];
else lock=lines[i].args[4];
int color = P_GetMapColorForLock(lock);
@ -1897,6 +1989,17 @@ void AM_drawWalls (bool allmap)
AM_drawMline (&l, LockedColor); // locked special
}
}
else if (am_showtriggerlines && am_colorset == 0 && lines[i].special != 0
&& lines[i].special != Door_Open
&& lines[i].special != Door_Close
&& lines[i].special != Door_CloseWaitOpen
&& lines[i].special != Door_Raise
&& lines[i].special != Door_Animated
&& lines[i].special != Generic_Door
&& (lines[i].activation & SPAC_PlayerActivate))
{
AM_drawMline(&l, SpecialWallColor); // wall with special non-door action the player can do
}
else if (lines[i].backsector == NULL)
{
AM_drawMline(&l, WallColor); // one-sided wall
@ -1911,6 +2014,12 @@ void AM_drawWalls (bool allmap)
{
AM_drawMline(&l, CDWallColor); // ceiling level change
}
#ifdef _3DFLOORS
else if (AM_Check3DFloors(&lines[i]))
{
AM_drawMline(&l, EFWallColor); // Extra floor border
}
#endif
else if (am_cheat != 0)
{
AM_drawMline(&l, TSWallColor);
@ -2059,20 +2168,15 @@ void AM_drawPlayers ()
angle = players[consoleplayer].camera->angle;
}
if (gameinfo.gametype & GAME_Raven)
if (am_cheat != 0 && CheatMapArrow.Size() > 0)
{
arrow = player_arrow_raven;
numarrowlines = NUMPLYRLINES_RAVEN;
}
else if (am_cheat != 0)
{
arrow = cheat_player_arrow;
numarrowlines = NUMCHEATPLYRLINES;
arrow = &CheatMapArrow[0];
numarrowlines = CheatMapArrow.Size();
}
else
{
arrow = player_arrow;
numarrowlines = NUMPLYRLINES;
arrow = &MapArrow[0];
numarrowlines = MapArrow.Size();
}
AM_drawLineCharacter(arrow, numarrowlines, 0, angle, YourColor, pt.x, pt.y);
return;
@ -2125,9 +2229,7 @@ void AM_drawPlayers ()
angle -= players[consoleplayer].camera->angle - ANG90;
}
AM_drawLineCharacter
(player_arrow, NUMPLYRLINES, 0, angle,
color, pt.x, pt.y);
AM_drawLineCharacter(&MapArrow[0], MapArrow.Size(), 0, angle, color, pt.x, pt.y);
}
}
}
@ -2183,7 +2285,7 @@ void AM_drawThings ()
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
else color = ThingColor_CountItem;
AM_drawLineCharacter(key_guy, NUMKEYGUYLINES, 16<<MAPBITS, 0, color, p.x, p.y);
AM_drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, 0, color, p.x, p.y);
color.Index = -1;
}
else

View file

@ -25,6 +25,9 @@
struct event_t;
class FArchive;
void AM_StaticInit();
// Called by main loop.
bool AM_Responder (event_t* ev, bool last);

View file

@ -28,6 +28,9 @@
%define setupmvlineasm _setupmvlineasm
%define mvlineasm1 _mvlineasm1
%define mvlineasm4 _mvlineasm4
%define R_SetupDrawSlabA _R_SetupDrawSlabA
%define R_DrawSlabA _R_DrawSlabA
%endif
EXTERN ylookup ; near
@ -44,9 +47,6 @@ EXTERN dc_dest
EXTERN dc_source
EXTERN dc_texturefrac
mvlineasm4_counter:
dd 0
SECTION .text
ALIGN 16
@ -59,8 +59,45 @@ setvlinebpl_:
mov [fixchain2ma+2], eax
mov [fixchain2mb+2], eax
selfmod fixchain1a, fixchain2mb+6
setdrawslabbpl:
mov dword [voxbpl1+2], eax
mov dword [voxbpl2+2], eax
mov dword [voxbpl3+2], eax
mov dword [voxbpl4+2], eax
mov dword [voxbpl5+2], eax
mov dword [voxbpl6+2], eax
mov dword [voxbpl7+2], eax
mov dword [voxbpl8+2], eax
selfmod voxbpl1, voxpl8+6
ret
SECTION .data
lastslabcolormap:
dd 4
SECTION .text
GLOBAL R_SetupDrawSlabA
GLOBAL @R_SetupDrawSlabA@4
R_SetupDrawSlabA:
mov ecx, [esp+4]
@R_SetupDrawSlabA@4:
cmp [lastslabcolormap], ecx
je .done
mov [lastslabcolormap], ecx
mov dword [voxpal1+2], ecx
mov dword [voxpal2+2], ecx
mov dword [voxpal3+2], ecx
mov dword [voxpal4+2], ecx
mov dword [voxpal5+2], ecx
mov dword [voxpal6+2], ecx
mov dword [voxpal7+2], ecx
mov dword [voxpal8+2], ecx
.done ret
; pass it log2(texheight)
ALIGN 16
@ -549,6 +586,226 @@ mvcase0: jmp beginmvlineasm4
align 16
;*************************************************************************
;***************************** Voxel Slabs *******************************
;*************************************************************************
GLOBAL R_DrawSlabA
R_DrawSlabA:
push ebx
push ebp
push esi
push edi
mov eax, [esp+5*4+0]
mov ebx, [esp+5*4+4]
mov ecx, [esp+5*4+8]
mov edx, [esp+5*4+12]
mov esi, [esp+5*4+16]
mov edi, [esp+5*4+20]
cmp eax, 2
je voxbegdraw2
ja voxskip2
xor eax, eax
voxbegdraw1:
mov ebp, ebx
shr ebp, 16
add ebx, edx
dec ecx
mov al, byte [esi+ebp]
voxpal1: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl1: lea edi, [edi+88888888h]
jnz voxbegdraw1
jmp voxskipslab5
voxbegdraw2:
mov ebp, ebx
shr ebp, 16
add ebx, edx
xor eax, eax
dec ecx
mov al, byte [esi+ebp]
voxpal2: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl2: lea edi, [edi+88888888h]
jnz voxbegdraw2
jmp voxskipslab5
voxskip2:
cmp eax, 4
jne voxskip4
xor eax, eax
voxbegdraw4:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal3: mov al, byte [eax+88888888h]
mov ah, al
shl eax, 8
mov al, ah
shl eax, 8
mov al, ah
mov dword [edi], eax
voxbpl3: add edi, 88888888h
dec ecx
jnz voxbegdraw4
jmp voxskipslab5
voxskip4:
add eax, edi
test edi, 1
jz voxskipslab1
cmp edi, eax
je voxskipslab1
push eax
push ebx
push ecx
push edi
voxbegslab1:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal4: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl4: add edi, 88888888h
dec ecx
jnz voxbegslab1
pop edi
pop ecx
pop ebx
pop eax
inc edi
voxskipslab1:
push eax
test edi, 2
jz voxskipslab2
dec eax
cmp edi, eax
jge voxskipslab2
push ebx
push ecx
push edi
voxbegslab2:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal5: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl5: add edi, 88888888h
dec ecx
jnz voxbegslab2
pop edi
pop ecx
pop ebx
add edi, 2
voxskipslab2:
mov eax, [esp]
sub eax, 3
cmp edi, eax
jge voxskipslab3
voxprebegslab3:
push ebx
push ecx
push edi
voxbegslab3:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal6: mov al, byte [eax+88888888h]
mov ah, al
shl eax, 8
mov al, ah
shl eax, 8
mov al, ah
mov dword [edi], eax
voxbpl6: add edi, 88888888h
dec ecx
jnz voxbegslab3
pop edi
pop ecx
pop ebx
add edi, 4
mov eax, [esp]
sub eax, 3
cmp edi, eax
jl voxprebegslab3
voxskipslab3:
mov eax, [esp]
dec eax
cmp edi, eax
jge voxskipslab4
push ebx
push ecx
push edi
voxbegslab4:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal7: mov al, byte [eax+88888888h]
mov ah, al
mov word [edi], ax
voxbpl7: add edi, 88888888h
dec ecx
jnz voxbegslab4
pop edi
pop ecx
pop ebx
add edi, 2
voxskipslab4:
pop eax
cmp edi, eax
je voxskipslab5
voxbegslab5:
mov ebp, ebx
add ebx, edx
shr ebp, 16
xor eax, eax
mov al, byte [esi+ebp]
voxpal8: mov al, byte [eax+88888888h]
mov byte [edi], al
voxbpl8: add edi, 88888888h
dec ecx
jnz voxbegslab5
voxskipslab5:
pop edi
pop esi
pop ebp
pop ebx
ret
align 16
%ifdef M_TARGET_MACHO
GLOBAL _rtext_a_end
_rtext_a_end:

View file

@ -342,13 +342,13 @@ dsy3: shr ebp,26
mov edx,[ds_ystep]
mov ecx,[ds_xfrac]
dsy4: shr ecx,26
dsm8: and edx,0xffffffc0
dsm8: and edx,strict dword 0xffffffc0
or ebp,edx
mov [esp+4],ebp
mov ebp,[ds_yfrac]
mov edx,[ds_xfrac]
dsy2: shl edx,6
dsm9: and ebp,0xffffffc0
dsm9: and ebp,strict dword 0xffffffc0
or ecx,ebp
shr esi,1
jnc dseven1
@ -485,13 +485,13 @@ dmsy3: shr ebp,26
mov edx,[ds_ystep]
mov ecx,[ds_xfrac]
dmsy4: shr ecx,26
dmsm8: and edx,0xffffffc0
dmsm8: and edx,strict dword 0xffffffc0
or ebp,edx
mov [esp+4],ebp
mov ebp,[ds_yfrac]
mov edx,[ds_xfrac]
dmsy2: shl edx,6
dmsm9: and ebp,0xffffffc0
dmsm9: and ebp,strict dword 0xffffffc0
or ecx,ebp
shr esi,1
jnc dmseven1
@ -850,8 +850,8 @@ GLOBAL R_DrawColumnHorizP_ASM
align 16
@R_DrawColumnHorizP_ASM@0:
R_DrawColumnHorizP_ASM:
_R_DrawColumnHorizP_ASM:
R_DrawColumnHorizP_ASM:
; count = dc_yh - dc_yl;
@ -870,8 +870,10 @@ _R_DrawColumnHorizP_ASM:
inc eax ; make 0 count mean 0 pixels
and edx,3
push eax
mov esi,[dc_ctspan+edx*4]
lea eax,[dc_temp+ecx*4+edx] ; eax = top of column in buffer
mov eax,[dc_temp]
mov esi,[dc_ctspan+edx*4]
add eax,edx
lea eax,[eax+ecx*4] ; eax = top of column in buffer
mov ebp,[dc_yh]
mov [esi],ecx
mov [esi+4],ebp
@ -1102,8 +1104,9 @@ _rt_copy1col_asm:
lea esi,[eax*4]
inc ebx ; ebx = count
mov eax,edx
lea ecx,[dc_temp+ecx+esi] ; ecx = source
add ecx,esi
mov edi,[ylookup+esi]
add ecx,[dc_temp] ; ecx = source
mov esi,[dc_pitch] ; esi = pitch
add eax,edi ; eax = dest
add eax,[dc_destorg]
@ -1169,10 +1172,11 @@ _rt_copy4cols_asm:
inc ebx ; ebx = count
mov eax,ecx
mov esi,[ylookup+edx*4]
lea ecx,[dc_temp+edx*4] ; ecx = source
mov edx,[dc_pitch] ; edx = pitch
mov ecx,[dc_temp]
add eax,esi ; eax = dest
add eax,[dc_destorg]
lea ecx,[ecx+edx*4] ; ecx = source
mov edx,[dc_pitch] ; edx = pitch
shr ebx,1
jnc .even
@ -1241,7 +1245,8 @@ _rt_map1col_asm:
mov esi,[dc_colormap] ; esi = colormap
inc ebx ; ebx = count
mov eax,edx
lea ebp,[dc_temp+ecx+edi] ; ebp = source
lea ebp,[ecx+edi] ; ebp = source
add ebp,[dc_temp]
mov ecx,[ylookup+edi]
mov edi,[dc_pitch] ; edi = pitch
add eax,ecx ; eax = dest
@ -1320,7 +1325,8 @@ _rt_map4cols_asm1:
mov eax,ecx
inc ebx ; ebx = count
mov edi,[ylookup+edx]
lea ebp,[dc_temp+edx] ; ebp = source
mov ebp,[dc_temp]
add ebp,edx ; ebp = source
add eax,edi ; eax = dest
mov edi,[dc_pitch] ; edi = pitch
add eax,[dc_destorg]
@ -1414,7 +1420,8 @@ _rt_map4cols_asm2:
mov eax,ecx
inc ebx ; ebx = count
mov edi,[ylookup+edx]
lea ebp,[dc_temp+edx] ; ebp = source
mov ebp,[dc_temp]
add ebp,edx ; ebp = source
add eax,edi ; eax = dest
mov edi,[dc_pitch] ; edi = pitch
add eax,[dc_destorg]
@ -1493,10 +1500,11 @@ _rt_shaded4cols_asm:
add eax,[dc_destorg] ; eax = destination
push ebx
push esi
mov esi,[dc_temp]
inc ebp ; ebp = count
add eax,[esp+16]
push edi
lea esi,[dc_temp+ecx*4] ; esi = source
lea esi,[esi+ecx*4] ; esi = source
align 16
@ -1580,10 +1588,11 @@ _rt_add4cols_asm:
add eax,[dc_destorg]
push ebx
push esi
mov esi,[dc_temp]
push ebp
inc edi
add eax,[esp+20]
lea esi,[dc_temp+ecx*4]
lea esi,[esi+ecx*4]
align 16
a4loop:
@ -1659,10 +1668,11 @@ _rt_addclamp4cols_asm:
add eax,[dc_destorg]
push ebx
push esi
mov esi,[dc_temp]
push ebp
inc edi
add eax,[esp+20]
lea esi,[dc_temp+ecx*4]
lea esi,[esi+ecx*4]
push edi
align 16

View file

@ -12,6 +12,7 @@
#include "cmdlib.h"
#include "teaminfo.h"
#include "d_net.h"
#include "farchive.h"
CVAR (Int, bot_next_color, 11, 0)
CVAR (Bool, bot_observer, false, 0)
@ -105,11 +106,6 @@ FArchive &operator<< (FArchive &arc, botskill_t &skill)
// This is intentionally not in the weapon definition anymore.
void InitBotStuff()
{
static bool done = false;
if (done) return;
done = true;
static struct BotInit
{
const char *type;

View file

@ -15,7 +15,6 @@
#include "g_game.h"
#include "m_random.h"
#include "r_sky.h"
#include "r_main.h"
#include "st_stuff.h"
#include "stats.h"
#include "i_system.h"

View file

@ -48,7 +48,6 @@ Everything that is changed is marked (maybe commented) with "Added by MC"
#include "b_bot.h"
#include "g_game.h"
#include "m_random.h"
#include "r_things.h"
#include "doomstat.h"
#include "cmdlib.h"
#include "sc_man.h"
@ -63,8 +62,6 @@ Everything that is changed is marked (maybe commented) with "Added by MC"
static FRandom pr_botspawn ("BotSpawn");
void InitBotStuff();
//Externs
FCajunMaster bglobal;
@ -321,7 +318,6 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
waitingforspawn[playernumber] = true;
InitBotStuff();
Net_WriteByte (DEM_ADDBOT);
Net_WriteByte (playernumber);
{

View file

@ -12,7 +12,6 @@
#include "g_game.h"
#include "d_ticcmd.h"
#include "m_random.h"
#include "r_main.h"
#include "i_system.h"
#include "p_lnspec.h"
#include "gi.h"

View file

@ -14,7 +14,6 @@
#include "b_bot.h"
#include "g_game.h"
#include "m_random.h"
#include "r_main.h"
#include "stats.h"
#include "a_pickups.h"
#include "statnums.h"

View file

@ -124,7 +124,7 @@ static const FBinding DefBindings[] =
{ "pad_start", "pause" },
{ "pad_back", "menu_main" },
{ "lthumb", "crouch" },
{ NULL }
{ NULL, NULL }
};
static const FBinding DefRavenBindings[] =
@ -135,13 +135,13 @@ static const FBinding DefRavenBindings[] =
{ "pgdn", "+lookup" },
{ "del", "+lookdown" },
{ "end", "centerview" },
{ NULL }
{ NULL, NULL }
};
static const FBinding DefHereticBindings[] =
{
{ "backspace", "use ArtiTomeOfPower" },
{ NULL }
{ NULL, NULL }
};
static const FBinding DefHexenBindings[] =
@ -156,7 +156,7 @@ static const FBinding DefHexenBindings[] =
{ "6", "use ArtiPork" },
{ "5", "use ArtiInvulnerability2" },
{ "scroll", "+showscores" },
{ NULL }
{ NULL, NULL }
};
static const FBinding DefStrifeBindings[] =
@ -167,7 +167,7 @@ static const FBinding DefStrifeBindings[] =
{ "z", "showpop 3" },
{ "k", "showpop 2" },
{ "q", "invquery" },
{ NULL }
{ NULL, NULL }
// not done
// h - use health
};
@ -190,7 +190,7 @@ static const FBinding DefAutomapBindings[] =
{ "kp+", "+am_zoomin" },
{ "mwheelup", "am_zoom 1.2" },
{ "mwheeldown", "am_zoom -1.2" },
{ NULL }
{ NULL, NULL }
};

View file

@ -61,13 +61,15 @@
#include "gi.h"
#include "r_defs.h"
#include "d_player.h"
#include "r_main.h"
#include "templates.h"
#include "p_local.h"
#include "r_sky.h"
#include "p_setup.h"
#include "cmdlib.h"
#include "d_net.h"
#include "v_text.h"
#include "p_lnspec.h"
#include "v_video.h"
extern FILE *Logfile;
extern bool insave;
@ -451,7 +453,7 @@ CCMD (puke)
if (argc < 2 || argc > 5)
{
Printf (" puke <script> [arg1] [arg2] [arg3]\n");
Printf ("Usage: puke <script> [arg1] [arg2] [arg3]\n");
}
else
{
@ -487,6 +489,52 @@ CCMD (puke)
}
}
CCMD (special)
{
int argc = argv.argc();
if (argc < 2 || argc > 7)
{
Printf("Usage: special <special-name> [arg1] [arg2] [arg3] [arg4] [arg5]\n");
}
else
{
int specnum;
if (argv[1][0] >= '0' && argv[1][0] <= '9')
{
specnum = atoi(argv[1]);
if (specnum < 0 || specnum > 255)
{
Printf("Bad special number\n");
return;
}
}
else
{
int min_args;
specnum = P_FindLineSpecial(argv[1], &min_args);
if (specnum == 0 || min_args < 0)
{
Printf("Unknown special\n");
return;
}
if (argc < 2 + min_args)
{
Printf("%s needs at least %d argument%s\n", argv[1], min_args, min_args == 1 ? "" : "s");
return;
}
}
Net_WriteByte(DEM_RUNSPECIAL);
Net_WriteByte(specnum);
Net_WriteByte(argc - 2);
for (int i = 2; i < argc; ++i)
{
Net_WriteLong(atoi(argv[i]));
}
}
}
CCMD (error)
{
if (argv.argc() > 1)
@ -614,32 +662,6 @@ CCMD (fov)
Net_WriteByte (clamp (atoi (argv[1]), 5, 179));
}
//==========================================================================
//
// CCMD r_visibility
//
// Controls how quickly light ramps across a 1/z range. Set this, and it
// sets all the r_*Visibility variables (except r_SkyVisibilily, which is
// currently unused).
//
//==========================================================================
CCMD (r_visibility)
{
if (argv.argc() < 2)
{
Printf ("Visibility is %g\n", R_GetVisibility());
}
else if (!netgame)
{
R_SetVisibility ((float)atof (argv[1]));
}
else
{
Printf ("Visibility cannot be changed in net games.\n");
}
}
//==========================================================================
//
// CCMD warp
@ -929,6 +951,7 @@ CCMD(nextsecret)
//
//
//-----------------------------------------------------------------------------
CCMD(currentpos)
{
AActor *mo = players[consoleplayer].mo;
@ -936,4 +959,121 @@ CCMD(currentpos)
FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
}
//-----------------------------------------------------------------------------
//
// Print secret info (submitted by Karl Murks)
//
//-----------------------------------------------------------------------------
static void PrintSecretString(const char *string, bool thislevel)
{
const char *colstr = thislevel? TEXTCOLOR_YELLOW : TEXTCOLOR_CYAN;
if (string != NULL)
{
if (*string == '$')
{
if (string[1] == 'S' || string[1] == 's')
{
long secnum = strtol(string+2, (char**)&string, 10);
if (*string == ';') string++;
if (thislevel && secnum >= 0 && secnum < numsectors)
{
if (sectors[secnum].secretsector)
{
if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED;
else colstr = TEXTCOLOR_GREEN;
}
else colstr = TEXTCOLOR_ORANGE;
}
}
else if (string[1] == 'T' || string[1] == 't')
{
long tid = strtol(string+2, (char**)&string, 10);
if (*string == ';') string++;
FActorIterator it(tid);
AActor *actor;
bool foundone = false;
if (thislevel)
{
while ((actor = it.Next()))
{
if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue;
foundone = true;
break;
}
}
if (foundone) colstr = TEXTCOLOR_RED;
else colstr = TEXTCOLOR_GREEN;
}
}
FBrokenLines *brok = V_BreakLines(ConFont, screen->GetWidth()*95/100, string);
for (int k = 0; brok[k].Width >= 0; k++)
{
Printf("%s%s\n", colstr, brok[k].Text.GetChars());
}
V_FreeBrokenLines(brok);
}
}
//============================================================================
//
// Print secret hints
//
//============================================================================
CCMD(secret)
{
const char *mapname = argv.argc() < 2? level.mapname : argv[1];
bool thislevel = !stricmp(mapname, level.mapname);
bool foundsome = false;
int lumpno=Wads.CheckNumForName("SECRETS");
if (lumpno < 0) return;
FWadLump lump = Wads.OpenLumpNum(lumpno);
FString maphdr;
maphdr.Format("[%s]", mapname);
FString linebuild;
char readbuffer[1024];
bool inlevel = false;
while (lump.Gets(readbuffer, 1024))
{
if (!inlevel)
{
if (readbuffer[0] == '[')
{
inlevel = !strnicmp(readbuffer, maphdr, maphdr.Len());
if (!foundsome)
{
FString levelname;
level_info_t *info = FindLevelInfo(mapname);
levelname.Format("%s - %s\n", mapname, info->LevelName.GetChars());
size_t llen = levelname.Len() - 1;
for(size_t ii=0; ii<llen; ii++) levelname += '-';
Printf(TEXTCOLOR_YELLOW"%s\n", levelname.GetChars());
foundsome = true;
}
}
continue;
}
else
{
if (readbuffer[0] != '[')
{
linebuild += readbuffer;
if (linebuild.Len() < 1023 || linebuild[1022] == '\n')
{
// line complete so print it.
linebuild.Substitute("\r", "");
linebuild.StripRight(" \t\n");
PrintSecretString(linebuild, thislevel);
linebuild = "";
}
}
else inlevel = false;
}
}
}

View file

@ -53,8 +53,6 @@
#include "v_video.h"
#include "v_text.h"
#include "w_wad.h"
#include "r_main.h"
#include "r_draw.h"
#include "sbar.h"
#include "s_sound.h"
#include "s_sndseq.h"
@ -65,6 +63,7 @@
#include "d_net.h"
#include "g_level.h"
#include "d_event.h"
#include "d_player.h"
#include "gi.h"
@ -94,7 +93,7 @@ extern FBaseCVar *CVars;
extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE];
int ConCols, PhysRows;
bool vidactive = false, gotconback = false;
bool vidactive = false;
bool cursoron = false;
int ConBottom, ConScroll, RowAdjust;
int CursorTicker;
@ -232,7 +231,7 @@ CUSTOM_CVAR (Int, msgmidcolor2, 4, CVAR_ARCHIVE)
static void maybedrawnow (bool tick, bool force)
{
// FIXME: Does not work right with hw2d
if (ConsoleDrawing || !gotconback || screen == NULL || screen->IsLocked () || screen->Accel2D)
if (ConsoleDrawing || screen == NULL || screen->IsLocked () || screen->Accel2D || ConFont == NULL)
{
return;
}
@ -297,32 +296,28 @@ void DequeueConsoleText ()
EnqueuedTextTail = &EnqueuedText;
}
void C_InitConback()
{
conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch);
if (!conback.isValid())
{
conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch);
conshade = MAKEARGB(175,0,0,0);
conline = true;
}
else
{
conshade = 0;
conline = false;
}
}
void C_InitConsole (int width, int height, bool ingame)
{
if ( (vidactive = ingame) )
{
if (!gotconback)
{
conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch);
if (!conback.isValid())
{
conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch);
conshade = MAKEARGB(175,0,0,0);
conline = true;
}
else
{
conshade = 0;
conline = false;
}
gotconback = true;
}
}
int cwidth, cheight;
vidactive = ingame;
if (ConFont != NULL)
{
cwidth = ConFont->GetCharWidth ('M');

View file

@ -53,6 +53,7 @@ extern int ConBottom;
// Initialize the console
void C_InitConsole (int width, int height, bool ingame);
void C_DeinitConsole ();
void C_InitConback();
// Adjust the console for a new screen mode
void C_NewModeAdjust (void);

View file

@ -221,7 +221,16 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
#else
case CVAR_Float: res = (int)value.Float; break;
#endif
case CVAR_String: res = strtol (value.String, NULL, 0); break;
case CVAR_String:
{
if (stricmp (value.String, "true") == 0)
res = 1;
else if (stricmp (value.String, "false") == 0)
res = 0;
else
res = strtol (value.String, NULL, 0);
break;
}
case CVAR_GUID: res = 0; break;
default: res = 0; break;
}
@ -444,7 +453,12 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
break;
case CVAR_Int:
ret.Int = strtol (value, NULL, 0);
if (stricmp (value, "true") == 0)
ret.Int = 1;
else if (stricmp (value, "false") == 0)
ret.Int = 0;
else
ret.Int = strtol (value, NULL, 0);
break;
case CVAR_Float:
@ -600,6 +614,11 @@ void FBaseCVar::EnableCallbacks ()
}
}
void FBaseCVar::DisableCallbacks ()
{
m_UseCallback = false;
}
//
// Boolean cvar implementation
//

View file

@ -117,6 +117,7 @@ public:
static void EnableNoSet (); // enable the honoring of CVAR_NOSET
static void EnableCallbacks ();
static void DisableCallbacks ();
static void ResetColors (); // recalc color cvars' indices after screen change
static void ListVars (const char *filter, bool plain);

View file

@ -53,6 +53,7 @@
#include "v_text.h"
#include "d_net.h"
#include "d_main.h"
#include "farchive.h"
// MACROS ------------------------------------------------------------------
@ -1211,6 +1212,30 @@ void C_ArchiveAliases (FConfigFile *f)
}
}
void C_ClearAliases ()
{
int bucket;
FConsoleCommand *alias;
for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++)
{
alias = Commands[bucket];
while (alias)
{
FConsoleCommand *next = alias->m_Next;
if (alias->IsAlias())
static_cast<FConsoleAlias *>(alias)->SafeDelete();
alias = next;
}
}
}
CCMD(clearaliases)
{
C_ClearAliases();
}
// This is called only by the ini parser.
void C_SetAlias (const char *name, const char *cmd)
{

View file

@ -58,6 +58,7 @@ int C_ExecFile (const char *cmd, bool usePullin);
void C_ArchiveAliases (FConfigFile *f);
void C_SetAlias (const char *name, const char *cmd);
void C_ClearAliases ();
// build a single string out of multiple strings
FString BuildString (int argc, char **argv);
@ -165,5 +166,6 @@ void ResetButtonStates (); // Same as above, but also clear bDown
extern unsigned int MakeKey (const char *s);
extern unsigned int MakeKey (const char *s, size_t len);
extern unsigned int SuperFastHash (const char *data, size_t len);
#endif //__C_DISPATCH_H__

View file

@ -1004,7 +1004,8 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
{
const char **argv[] = {dirpath, NULL };
char * const argv[] = {new char[strlen(dirpath)+1], NULL };
memcpy(argv[0], dirpath, strlen(dirpath)+1);
FTS *fts;
FTSENT *ent;
@ -1012,6 +1013,7 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
if (fts == NULL)
{
I_Error("Failed to start directory traversal: %s\n", strerror(errno));
delete[] argv[0];
return;
}
while ((ent = fts_read(fts)) != NULL)
@ -1037,5 +1039,6 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
}
}
fts_close(fts);
delete[] argv[0];
}
#endif

View file

@ -89,6 +89,7 @@ static FCompatOption Options[] =
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
{ "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS },
// list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, 0 },
@ -119,6 +120,7 @@ static FCompatOption Options[] =
{ "hitscan", COMPATF_HITSCAN, 0 },
{ "lightlevel", COMPATF_LIGHT, 0 },
{ "polyobj", COMPATF_POLYOBJ, 0 },
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, 0 },
{ NULL, 0, 0 }
};
@ -141,6 +143,9 @@ void ParseCompatibility()
int i, x;
unsigned int j;
BCompatMap.Clear();
CompatParams.Clear();
// The contents of this file are not cumulative, as it should not
// be present in user-distributed maps.
FScanner sc(Wads.GetNumForFullName("compatibility.txt"));
@ -260,7 +265,7 @@ void CheckCompatibility(MapData *map)
// When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT.
// I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt.
// TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD.
if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && !(level.flags & LEVEL_HEXENFORMAT))
if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM)
{
ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT;
if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX;
@ -279,7 +284,6 @@ void CheckCompatibility(MapData *map)
ib_compatflags = 0;
ii_compatparams = -1;
}
else
{
map->GetChecksum(md5.Bytes);

View file

@ -252,7 +252,7 @@ void CT_Drawer (void)
}
// draw the prompt, text, and cursor
ChatQueue[len] = gameinfo.gametype & GAME_DoomChex ? '_' : '[';
ChatQueue[len] = SmallFont->GetCursor();
ChatQueue[len+1] = '\0';
if (con_scaletext < 2)
{

View file

@ -60,18 +60,18 @@
#include "gi.h"
#include "c_dispatch.h"
#include "decallib.h"
#include "r_draw.h"
#include "v_palette.h"
#include "a_sharedglobal.h"
#include "thingdef/thingdef.h"
#include "thingdef/thingdef_exp.h"
#include "vectors.h"
#include "dobject.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "sc_man.h"
#include "i_system.h"
#include "doomerrors.h"
#include "p_effect.h"
#include "farchive.h"
// [SO] Just the way Randy said to do it :)
// [RH] Made this CVAR_SERVERINFO
@ -309,7 +309,7 @@ static const struct {
{ "[PARS]", PatchPars },
{ "[CODEPTR]", PatchCodePtrs },
{ "[MUSIC]", PatchMusic },
{ NULL, },
{ NULL, NULL },
};
static int HandleMode (const char *mode, int num);
@ -1712,7 +1712,7 @@ static int PatchMisc (int dummy)
{ "IDKFA Armor", myoffsetof(struct DehInfo,KFAArmor) },
{ "IDKFA Armor Class", myoffsetof(struct DehInfo,KFAAC) },
{ "No Autofreeze", myoffsetof(struct DehInfo,NoAutofreeze) },
{ NULL, }
{ NULL, 0 }
};
int result;
@ -1866,8 +1866,8 @@ static int PatchMisc (int dummy)
player->health = deh.StartHealth;
// Hm... I'm not sure that this is the right way to change this info...
unsigned int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1;
if (index >= 0 && index < DropItemList.Size())
int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1;
if (index >= 0 && index < (signed)DropItemList.Size())
{
FDropItem * di = DropItemList[index];
while (di != NULL)
@ -2880,6 +2880,8 @@ void FinishDehPatch ()
// Now that all Dehacked patches have been processed, it's okay to free StateMap.
StateMap.Clear();
StateMap.ShrinkToFit();
TouchedActors.Clear();
TouchedActors.ShrinkToFit();
}
void ModifyDropAmount(AInventory *inv, int dropamount);
@ -2895,11 +2897,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher)
if (RealPickup != NULL)
{
// The internally spawned item should never count towards statistics.
if (RealPickup->flags & MF_COUNTITEM)
{
RealPickup->flags &= ~MF_COUNTITEM;
level.total_items--;
}
RealPickup->ClearCounters();
if (!(flags & MF_DROPPED))
{
RealPickup->flags &= ~MF_DROPPED;

View file

@ -62,6 +62,7 @@ typedef enum
ga_newgame,
ga_newgame2,
ga_loadgame,
ga_loadgamehidecon,
ga_autoloadgame,
ga_savegame,
ga_autosave,

View file

@ -43,6 +43,8 @@
#include "m_argv.h"
#include "m_misc.h"
#include "c_cvars.h"
#include "sc_man.h"
#include "v_video.h"
#include "gameconfigfile.h"
#include "resourcefiles/resourcefile.h"
@ -50,96 +52,229 @@
CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (String, defaultiwad, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
EIWADType gameiwad;
//==========================================================================
//
// Clear check list
//
//==========================================================================
// If autoname is NULL, that's either because that game doesn't allow
// loading of external wads or because it's already caught by the
// general game-specific wads section.
const IWADInfo IWADInfos[NUM_IWAD_TYPES] =
void FIWadManager::ClearChecks()
{
// banner text, autoname, fg color, bg color
{ "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX | GI_COMPATSTAIRS },
{ "Final Doom: Plutonia Experiment", "Plutonia", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/plutonia.txt", GI_MAPxx | GI_COMPATSHORTTEX },
{ "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 },
{ "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 | GI_COMPATPOLY2 },
{ "Hexen: Demo Version", "HexenDemo",MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_SHAREWARE },
{ "DOOM 2: Hell on Earth", "Doom2", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx | GI_COMPATSHORTTEX },
{ "Heretic Shareware", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/hereticsw.txt",GI_SHAREWARE },
{ "Heretic: Shadow of the Serpent Riders", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/heretic.txt", GI_MENUHACK_EXTENDED },
{ "Heretic", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/heretic.txt" },
{ "DOOM Shareware", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom1.txt", GI_SHAREWARE | GI_COMPATSHORTTEX },
{ "The Ultimate DOOM", "Doom1", MAKERGB(84,84,84), MAKERGB(168,168,168), GAME_Doom, "mapinfo/ultdoom.txt", GI_COMPATSHORTTEX },
{ "DOOM Registered", "Doom1", MAKERGB(84,84,84), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom1.txt", GI_COMPATSHORTTEX },
{ "Strife: Quest for the Sigil", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx },
{ "Strife: Teaser (Old Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE },
{ "Strife: Teaser (New Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE | GI_TEASER2 },
{ "Freedoom", "Freedoom", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
{ "Ultimate Freedoom", "Freedoom1",MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" },
{ "Freedoom \"Demo\"", NULL, MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" },
{ "FreeDM", "FreeDM", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
{ "Blasphemer", "Blasphemer",MAKERGB(115,0,0), MAKERGB(0,0,0), GAME_Heretic, "mapinfo/heretic.txt" },
{ "Chex(R) Quest", "Chex1", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex.txt" },
{ "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt", GI_NOTEXTCOLOR },
{ "Action Doom 2: Urban Brawl", "UrbanBrawl",MAKERGB(168,168,0), MAKERGB(168,0,0), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
{ "Harmony", "Harmony", MAKERGB(110,180,230), MAKERGB(69,79,126), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx },
//{ "ZDoom Engine", NULL, MAKERGB(168,0,0), MAKERGB(168,168,168) },
};
mLumpsFound.Resize(mIWads.Size());
for(unsigned i=0;i<mLumpsFound.Size(); i++)
{
mLumpsFound[i] = 0;
}
}
static const char *IWADNames[] =
//==========================================================================
//
// Check one lump
//
//==========================================================================
void FIWadManager::CheckLumpName(const char *name)
{
NULL,
"doom2f.wad",
"doom2.wad",
"plutonia.wad",
"tnt.wad",
"doomu.wad", // Hack from original Linux version. Not necessary, but I threw it in anyway.
"doom.wad",
"doom1.wad",
"heretic.wad",
"heretic1.wad",
"hexen.wad",
"hexdd.wad",
"hexendemo.wad",
"hexdemo.wad",
"strife1.wad",
"strife0.wad",
"freedoom.wad", // Freedoom.wad is distributed as Doom2.wad, but this allows to have both in the same directory.
"freedoom1.wad",
"freedoomu.wad",
"freedm.wad",
"blasphem.wad",
"blasphemer.wad",
"chex.wad",
"chex3.wad",
"action2.wad",
"harm1.wad",
#ifdef unix
"DOOM2.WAD", // Also look for all-uppercase names
"PLUTONIA.WAD",
"TNT.WAD",
"DOOM.WAD",
"DOOM1.WAD",
"HERETIC.WAD",
"HERETIC1.WAD",
"HEXEN.WAD",
"HEXDD.WAD",
"HEXENDEMO.WAD",
"HEXDEMO.WAD",
"STRIFE1.WAD",
"STRIFE0.WAD",
"FREEDOOM.WAD",
"FREEDOOM1.WAD",
"FREEDOOMU.WAD",
"FREEDM.WAD",
"BLASPHEM.WAD",
"BLASPHEMER.WAD",
"CHEX.WAD",
"CHEX3.WAD",
"ACTION2.WAD",
"HARM1.WAD",
for(unsigned i=0; i< mIWads.Size(); i++)
{
for(unsigned j=0; j < mIWads[i].Lumps.Size(); j++)
{
if (!mIWads[i].Lumps[j].CompareNoCase(name))
{
mLumpsFound[i] |= (1<<j);
}
}
}
}
//==========================================================================
//
// Returns check result
//
//==========================================================================
int FIWadManager::GetIWadInfo()
{
for(unsigned i=0; i< mIWads.Size(); i++)
{
if (mLumpsFound[i] == (1 << mIWads[i].Lumps.Size()) - 1)
{
return i;
}
}
return -1;
}
//==========================================================================
//
// Parses IWAD definitions
//
//==========================================================================
void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
{
FScanner sc;
sc.OpenMem("IWADINFO", data, datasize);
while (sc.GetString())
{
if (sc.Compare("IWAD"))
{
FIWADInfo *iwad = &mIWads[mIWads.Reserve(1)];
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("Name"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->Name = sc.String;
}
else if (sc.Compare("Autoname"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->Autoname = sc.String;
}
else if (sc.Compare("Config"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->Configname = sc.String;
}
else if (sc.Compare("Game"))
{
sc.MustGetStringName("=");
sc.MustGetString();
if (sc.Compare("Doom")) iwad->gametype = GAME_Doom;
else if (sc.Compare("Heretic")) iwad->gametype = GAME_Heretic;
else if (sc.Compare("Hexen")) iwad->gametype = GAME_Hexen;
else if (sc.Compare("Strife")) iwad->gametype = GAME_Strife;
else if (sc.Compare("Chex")) iwad->gametype = GAME_Chex;
else sc.ScriptError(NULL);
}
else if (sc.Compare("Mapinfo"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->MapInfo = sc.String;
}
else if (sc.Compare("Compatibility"))
{
sc.MustGetStringName("=");
do
{
sc.MustGetString();
if(sc.Compare("NoTextcolor")) iwad->flags |= GI_NOTEXTCOLOR;
else if(sc.Compare("Poly1")) iwad->flags |= GI_COMPATPOLY1;
else if(sc.Compare("Poly2")) iwad->flags |= GI_COMPATPOLY2;
else if(sc.Compare("Shareware")) iwad->flags |= GI_SHAREWARE;
else if(sc.Compare("Teaser2")) iwad->flags |= GI_TEASER2;
else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED;
else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX;
else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS;
else sc.ScriptError(NULL);
}
while (sc.CheckString(","));
}
else if (sc.Compare("MustContain"))
{
sc.MustGetStringName("=");
do
{
sc.MustGetString();
iwad->Lumps.Push(FString(sc.String));
}
while (sc.CheckString(","));
}
else if (sc.Compare("BannerColors"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->FgColor = V_GetColor(NULL, sc.String);
sc.MustGetStringName(",");
sc.MustGetString();
iwad->BkColor = V_GetColor(NULL, sc.String);
}
else if (sc.Compare("Load"))
{
sc.MustGetStringName("=");
do
{
sc.MustGetString();
iwad->Load.Push(FString(sc.String));
}
while (sc.CheckString(","));
}
else if (sc.Compare("Required"))
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->Required = sc.String;
}
else
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
}
}
}
else if (sc.Compare("NAMES"))
{
sc.MustGetStringName("{");
mIWadNames.Push(FString());
while (!sc.CheckString("}"))
{
sc.MustGetString();
FString wadname = sc.String;
#if defined(_WIN32) || defined(__APPLE__) // Turns out Mac OS X is case insensitive.
mIWadNames.Push(wadname);
#else
// check for lowercase, uppercased first letter and full uppercase on Linux etc.
wadname.ToLower();
mIWadNames.Push(wadname);
wadname.LockBuffer()[0] = toupper(wadname[0]);
wadname.UnlockBuffer();
mIWadNames.Push(wadname);
wadname.ToUpper();
mIWadNames.Push(wadname);
#endif
NULL
};
}
}
}
}
//==========================================================================
//
// Lool for IWAD definition lump
//
//==========================================================================
void FIWadManager::ParseIWadInfos(const char *fn)
{
FResourceFile *resfile = FResourceFile::OpenResourceFile(fn, NULL, true);
if (resfile != NULL)
{
DWORD cnt = resfile->LumpCount();
for(int i=cnt-1; i>=0; i--)
{
FResourceLump *lmp = resfile->GetLump(i);
if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO"))
{
// Found one!
ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize);
break;
}
}
delete resfile;
}
if (mIWadNames.Size() == 0 || mIWads.Size() == 0)
{
I_FatalError("No IWAD definitions found");
}
}
//==========================================================================
//
@ -148,273 +283,30 @@ static const char *IWADNames[] =
// Scan the contents of an IWAD to determine which one it is
//==========================================================================
static EIWADType ScanIWAD (const char *iwad)
int FIWadManager::ScanIWAD (const char *iwad)
{
static const char checklumps[][8] =
{
"AD2LIB",
"E1M1",
"E4M2",
"MAP01",
"MAP40",
"MAP60",
"TITLE",
"REDTNT2",
"CAMO1",
{ 'E','X','T','E','N','D','E','D'},
"ENDSTRF",
"MAP33",
"INVCURS",
{ 'F','R','E','E','D','O','O','M' },
{ 'B','L','A','S','P','H','E','M' },
"W94_1",
{ 'P','O','S','S','H','0','M','0' },
"CYCLA1",
"FLMBA1",
"MAPINFO",
"0HAWK01",
"0CARA3",
"0NOSE1",
{ 'G','A','M','E','I','N','F','O' },
"E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9",
"E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9",
"DPHOOF","BFGGA0","HEADA1","CYBRA1",
{ 'S','P','I','D','A','1','D','1' },
};
#define NUM_CHECKLUMPS (countof(checklumps))
enum
{
Check_ad2lib,
Check_e1m1,
Check_e4m1,
Check_map01,
Check_map40,
Check_map60,
Check_title,
Check_redtnt2,
Check_cam01,
Check_Extended,
Check_endstrf,
Check_map33,
Check_invcurs,
Check_FreeDoom,
Check_Blasphem,
Check_W94_1,
Check_POSSH0M0,
Check_Cycla1,
Check_Flmba1,
Check_Mapinfo,
Check_Hawk,
Check_Car,
Check_Nose,
Check_Gameinfo,
Check_e2m1
};
bool lumpsfound[NUM_CHECKLUMPS];
size_t i;
memset (lumpsfound, 0, sizeof(lumpsfound));
FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true);
if (iwadfile != NULL)
{
ClearChecks();
for(DWORD ii = 0; ii < iwadfile->LumpCount(); ii++)
{
FResourceLump *lump = iwadfile->GetLump(ii);
size_t j;
for (j = 0; j < NUM_CHECKLUMPS; j++)
CheckLumpName(lump->Name);
if (lump->FullName != NULL)
{
if (!lumpsfound[j])
if (strnicmp(lump->FullName, "maps/", 5) == 0)
{
if (strnicmp (lump->Name, checklumps[j], 8) == 0)
{
lumpsfound[j] = true;
break;
}
// Check for maps inside zips, too.
else if (lump->FullName != NULL)
{
if (checklumps[j][0] == 'E' && checklumps[j][2] == 'M' && checklumps[j][4] == '\0')
{
if (strnicmp(lump->FullName, "maps/", 5) == 0 &&
strnicmp(lump->FullName + 5, checklumps[j], 4) == 0 &&
stricmp(lump->FullName + 9, ".wad") == 0)
{
lumpsfound[j] = true;
break;
}
}
else if (checklumps[j][0] == 'M' && checklumps[j][1] == 'A' && checklumps[j][2] == 'P' &&
checklumps[j][5] == '\0')
{
if (strnicmp(lump->FullName, "maps/", 5) == 0 &&
strnicmp(lump->FullName + 5, checklumps[j], 5) == 0 &&
stricmp(lump->FullName + 10, ".wad") == 0)
{
lumpsfound[j] = true;
break;
}
}
}
FString mapname(lump->FullName+5, strcspn(lump->FullName+5, "."));
CheckLumpName(mapname);
}
}
}
delete iwadfile;
}
// Always check for custom iwads first.
#if 0
if (lumpsfound[Check_Gameinfo])
{
return IWAD_Custom;
}
#endif
if (lumpsfound[Check_title] && lumpsfound[Check_map60])
{
return IWAD_HexenDK;
}
else if (lumpsfound[Check_map33] && lumpsfound[Check_endstrf])
{
if (lumpsfound[Check_map01])
{
return IWAD_Strife;
}
else if (lumpsfound[Check_invcurs])
{
return IWAD_StrifeTeaser2; // Strife0.wad from 14 Mar 1996
}
else
{
return IWAD_StrifeTeaser; // Strife0.wad from 22 Feb 1996
}
}
else if (lumpsfound[Check_map01])
{
if (lumpsfound[Check_ad2lib])
{
return IWAD_ActionDoom2;
}
else if (lumpsfound[Check_Hawk] && lumpsfound[Check_Car] && lumpsfound[Check_Nose])
{
return IWAD_Harmony;
}
else if (lumpsfound[Check_FreeDoom])
{
// Is there a 100% reliable way to tell FreeDoom and FreeDM
// apart based solely on the lump names?
if (strstr(iwad, "freedm.wad") || strstr(iwad, "FREEDM.WAD"))
{
return IWAD_FreeDM;
}
else
{
return IWAD_FreeDoom;
}
}
else if (lumpsfound[Check_redtnt2])
{
return IWAD_Doom2TNT;
}
else if (lumpsfound[Check_cam01])
{
return IWAD_Doom2Plutonia;
}
else
{
if (lumpsfound[Check_title])
{
if (lumpsfound[Check_map40])
{
return IWAD_Hexen;
}
else
{
return IWAD_HexenDemo;
}
}
else
{
return IWAD_Doom2;
}
}
}
else if (lumpsfound[Check_e1m1])
{
if (lumpsfound[Check_title])
{
if (!lumpsfound[Check_e2m1])
{
return IWAD_HereticShareware;
}
else
{
if (lumpsfound[Check_Blasphem])
{
return IWAD_Blasphemer;
}
else if (lumpsfound[Check_Extended])
{
return IWAD_HereticExtended;
}
else
{
return IWAD_Heretic;
}
}
}
else if (lumpsfound[Check_Cycla1] && lumpsfound[Check_Flmba1])
{
if (!lumpsfound[Check_Mapinfo])
{
// The original release won't work without its hacked custom EXE.
//I_FatalError("Found an incompatible version of Chex Quest 3");
return NUM_IWAD_TYPES; // Can't use it.
}
return IWAD_ChexQuest3;
}
else
{
if (lumpsfound[Check_FreeDoom])
{
if (!lumpsfound[Check_e2m1])
{
return IWAD_FreeDoom1;
}
else
{
return IWAD_FreeDoomU;
}
}
for (i = Check_e2m1; i < NUM_CHECKLUMPS; i++)
{
if (!lumpsfound[i])
{
return IWAD_DoomShareware;
}
}
if (i == NUM_CHECKLUMPS)
{
if (lumpsfound[Check_e4m1])
{
if (lumpsfound[Check_W94_1] && lumpsfound[Check_POSSH0M0])
{
return IWAD_ChexQuest;
}
else
{
return IWAD_UltimateDoom;
}
}
else
{
return IWAD_DoomRegistered;
}
}
}
}
return NUM_IWAD_TYPES; // Don't know
return GetIWadInfo();
}
//==========================================================================
@ -428,10 +320,9 @@ static EIWADType ScanIWAD (const char *iwad)
//
//==========================================================================
static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads)
{
const char *slash;
int i;
int numfound;
numfound = 0;
@ -439,20 +330,21 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
slash = (doomwaddir[0] && doomwaddir[strlen (doomwaddir)-1] != '/') ? "/" : "";
// Search for a pre-defined IWAD
for (i = IWADNames[0] ? 0 : 1; IWADNames[i]; i++)
for (unsigned i=0; i< mIWadNames.Size(); i++)
{
if (wads[i].Path.IsEmpty())
if (mIWadNames[i].IsNotEmpty() && wads[i].Path.IsEmpty())
{
FString iwad;
iwad.Format ("%s%s%s", doomwaddir, slash, IWADNames[i]);
iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars());
FixPathSeperator (iwad);
if (FileExists (iwad))
{
wads[i].Type = ScanIWAD (iwad);
if (wads[i].Type != NUM_IWAD_TYPES)
if (wads[i].Type != -1)
{
wads[i].Path = iwad;
wads[i].Name = mIWads[wads[i].Type].Name;
numfound++;
}
}
@ -483,10 +375,10 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
//
//==========================================================================
static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad)
int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad)
{
WadStuff wads[countof(IWADNames)];
size_t foundwads[NUM_IWAD_TYPES] = { 0 };
TArray<WadStuff> wads;
TArray<size_t> foundwads;
const char *iwadparm = Args->CheckValue ("-iwad");
size_t numwads;
int pickwad;
@ -494,6 +386,11 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
bool iwadparmfound = false;
FString custwad;
ParseIWadInfos(zdoom_wad);
wads.Resize(mIWadNames.Size());
foundwads.Resize(mIWads.Size());
memset(&foundwads[0], 0, foundwads.Size() * sizeof(foundwads[0]));
if (iwadparm == NULL && iwad != NULL && *iwad != 0)
{
iwadparm = iwad;
@ -503,7 +400,7 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
{
custwad = iwadparm;
FixPathSeperator (custwad);
if (CheckIWAD (custwad, wads))
if (CheckIWAD (custwad, &wads[0]))
{ // -iwad parameter was a directory
iwadparm = NULL;
}
@ -511,8 +408,8 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
{
DefaultExtension (custwad, ".wad");
iwadparm = custwad;
IWADNames[0] = iwadparm;
CheckIWAD ("", wads);
mIWadNames[0] = custwad;
CheckIWAD ("", &wads[0]);
}
}
@ -529,7 +426,7 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
{
FString nice = NicePath(value);
FixPathSeperator(nice);
CheckIWAD(nice, wads);
CheckIWAD(nice, &wads[0]);
}
}
}
@ -549,7 +446,7 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
steam_path += "/SteamApps/common/";
for (i = 0; i < countof(steam_dirs); ++i)
{
CheckIWAD (steam_path + steam_dirs[i], wads);
CheckIWAD (steam_path + steam_dirs[i], &wads[0]);
}
}
#endif
@ -560,7 +457,7 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
iwadparmfound = true;
}
for (i = numwads = 0; i < countof(IWADNames); i++)
for (i = numwads = 0; i < mIWadNames.Size(); i++)
{
if (!wads[i].Path.IsEmpty())
{
@ -573,20 +470,42 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
}
}
if (foundwads[IWAD_HexenDK] && !foundwads[IWAD_Hexen])
{ // Cannot play Hexen DK without Hexen
size_t kill = foundwads[IWAD_HexenDK];
for (i = kill; i < numwads; ++i)
for (unsigned i=0; i<mIWads.Size(); i++)
{
if (mIWads[i].Required.IsNotEmpty() && foundwads[i])
{
wads[i - 1] = wads[i];
}
numwads--;
foundwads[IWAD_HexenDK] = 0;
for (i = 0; i < NUM_IWAD_TYPES; ++i)
{
if (foundwads[i] > kill)
bool found = false;
// needs to be loaded with another IWAD (HexenDK)
for (unsigned j=0; j<mIWads.Size(); j++)
{
foundwads[i]--;
if (!mIWads[i].Required.Compare(mIWads[j].Name))
{
if (foundwads[j])
{
found = true;
mIWads[i].preload = j;
}
break;
}
}
// The required WAD is not there so this one can't be used and must be deleted from the list
if (!found)
{
size_t kill = foundwads[i];
for (size_t j = kill; j < numwads; ++j)
{
wads[j - 1] = wads[j];
}
numwads--;
foundwads[i] = 0;
for (unsigned j = 0; j < foundwads.Size(); ++j)
{
if (foundwads[j] > kill)
{
foundwads[j]--;
}
}
}
}
}
@ -620,7 +539,7 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
}
}
}
pickwad = I_PickIWad (wads, (int)numwads, queryiwad, defiwad);
pickwad = I_PickIWad (&wads[0], (int)numwads, queryiwad, defiwad);
if (pickwad >= 0)
{
// The newly selected IWAD becomes the new default
@ -633,17 +552,17 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
exit (0);
// zdoom.pk3 must always be the first file loaded and the IWAD second.
wadfiles.Clear();
D_AddFile (wadfiles, zdoom_wad);
if (wads[pickwad].Type == IWAD_HexenDK)
{ // load hexen.wad before loading hexdd.wad
D_AddFile (wadfiles, wads[foundwads[IWAD_Hexen]-1].Path);
if (mIWads[wads[pickwad].Type].preload >= 0)
{
D_AddFile (wadfiles, wads[foundwads[mIWads[wads[pickwad].Type].preload]-1].Path);
}
D_AddFile (wadfiles, wads[pickwad].Path);
if (wads[pickwad].Type == IWAD_Strife)
{ // Try to load voices.wad along with strife1.wad
for (unsigned i=0; i < mIWads[wads[pickwad].Type].Load.Size(); i++)
{
long lastslash = wads[pickwad].Path.LastIndexOf ('/');
FString path;
@ -655,19 +574,31 @@ static EIWADType IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, c
{
path = FString (wads[pickwad].Path.GetChars(), lastslash + 1);
}
path += "voices.wad";
path += mIWads[wads[pickwad].Type].Load[i];
D_AddFile (wadfiles, path);
}
}
return wads[pickwad].Type;
}
const IWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad)
//==========================================================================
//
// Find an IWAD to use for this game
//
//==========================================================================
const FIWADInfo *FIWadManager::FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad)
{
EIWADType iwadType = IdentifyVersion(wadfiles, iwad, basewad);
gameiwad = iwadType;
const IWADInfo *iwad_info = &IWADInfos[iwadType];
I_SetIWADInfo(iwad_info);
int iwadType = IdentifyVersion(wadfiles, iwad, basewad);
//gameiwad = iwadType;
const FIWADInfo *iwad_info = &mIWads[iwadType];
if (DoomStartupInfo.Name.IsEmpty()) DoomStartupInfo.Name = iwad_info->Name;
if (DoomStartupInfo.BkColor == 0 && DoomStartupInfo.FgColor == 0)
{
DoomStartupInfo.BkColor = iwad_info->BkColor;
DoomStartupInfo.FgColor = iwad_info->FgColor;
}
I_SetIWADInfo();
return iwad_info;
}

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,12 @@ struct event_t;
// calls all startup code, parses command line options.
// If not overrided by user input, calls N_AdvanceDemo.
//
struct CRestartException
{
char dummy;
};
void D_DoomMain (void);
@ -56,57 +62,66 @@ bool D_AddFile (TArray<FString> &wadfiles, const char *file, bool check = true,
extern const char *D_DrawIcon;
enum EIWADType
{
IWAD_Doom2TNT,
IWAD_Doom2Plutonia,
IWAD_Hexen,
IWAD_HexenDK,
IWAD_HexenDemo,
IWAD_Doom2,
IWAD_HereticShareware,
IWAD_HereticExtended,
IWAD_Heretic,
IWAD_DoomShareware,
IWAD_UltimateDoom,
IWAD_DoomRegistered,
IWAD_Strife,
IWAD_StrifeTeaser,
IWAD_StrifeTeaser2,
IWAD_FreeDoom,
IWAD_FreeDoomU,
IWAD_FreeDoom1,
IWAD_FreeDM,
IWAD_Blasphemer,
IWAD_ChexQuest,
IWAD_ChexQuest3,
IWAD_ActionDoom2,
IWAD_Harmony,
IWAD_Custom,
NUM_IWAD_TYPES
};
struct WadStuff
{
WadStuff() : Type(IWAD_Doom2TNT) {}
WadStuff() : Type(0) {}
FString Path;
EIWADType Type;
FString Name;
int Type;
};
struct IWADInfo
struct FIWADInfo
{
const char *Name; // Title banner text for this IWAD
const char *Autoname; // Name of autoload ini section for this IWAD
FString Name; // Title banner text for this IWAD
FString Autoname; // Name of autoload ini section for this IWAD
FString Configname; // Name of config section for this IWAD
FString Required; // Requires another IWAD
DWORD FgColor; // Foreground color for title banner
DWORD BkColor; // Background color for title banner
EGameType gametype; // which game are we playing?
const char *MapInfo; // Base mapinfo to load
FString MapInfo; // Base mapinfo to load
TArray<FString> Load; // Wads to be loaded with this one.
TArray<FString> Lumps; // Lump names for identification
int flags;
int preload;
FIWADInfo() { flags = 0; preload = -1; FgColor = 0; BkColor= 0xc0c0c0; gametype = GAME_Doom; }
};
struct FStartupInfo
{
FString Name;
DWORD FgColor; // Foreground color for title banner
DWORD BkColor; // Background color for title banner
};
extern FStartupInfo DoomStartupInfo;
//==========================================================================
//
// IWAD identifier class
//
//==========================================================================
struct FIWadManager
{
private:
TArray<FIWADInfo> mIWads;
TArray<FString> mIWadNames;
TArray<int> mLumpsFound;
void ParseIWadInfo(const char *fn, const char *data, int datasize);
void ParseIWadInfos(const char *fn);
void ClearChecks();
void CheckLumpName(const char *name);
int GetIWadInfo();
int ScanIWAD (const char *iwad);
int CheckIWAD (const char *doomwaddir, WadStuff *wads);
int IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad);
public:
const FIWADInfo *FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
};
extern const IWADInfo IWADInfos[NUM_IWAD_TYPES];
extern EIWADType gameiwad;
#endif

View file

@ -57,6 +57,8 @@
#include "g_level.h"
#include "d_event.h"
#include "m_argv.h"
#include "p_lnspec.h"
#include "v_video.h"
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
@ -1538,7 +1540,6 @@ static void SendSetup (DWORD playersdetected[MAXNETNODES], BYTE gotsetup[MAXNETN
// D_CheckNetGame
// Works out player numbers among the net participants
//
extern int viewangleoffset;
void D_CheckNetGame (void)
{
@ -2316,13 +2317,38 @@ void Net_DoCommand (int type, BYTE **stream, int player)
for (i = 0; i < argn; ++i)
{
arg[i] = ReadLong (stream);
int argval = ReadLong(stream);
if ((unsigned)i < countof(arg))
{
arg[i] = argval;
}
}
P_StartScript (players[player].mo, NULL, snum, level.mapname, false,
arg[0], arg[1], arg[2], type == DEM_RUNSCRIPT2, false, true);
}
break;
case DEM_RUNSPECIAL:
{
int snum = ReadByte(stream);
int argn = ReadByte(stream);
int arg[5] = { 0, 0, 0, 0, 0 };
for (i = 0; i < argn; ++i)
{
int argval = ReadLong(stream);
if ((unsigned)i < countof(arg))
{
arg[i] = argval;
}
}
if (!CheckCheatmode(player == consoleplayer))
{
P_ExecuteSpecial(snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
}
}
break;
case DEM_CROUCH:
if (gamestate == GS_LEVEL && players[player].mo != NULL &&
players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP))
@ -2400,7 +2426,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
{
players[player].weapons.Slots[slot].Clear();
}
for(int i = 0; i < count; ++i)
for(i = 0; i < count; ++i)
{
const PClass *wpn = Net_ReadWeapon(stream);
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
@ -2521,6 +2547,10 @@ void Net_SkipCommand (int type, BYTE **stream)
skip = 3 + *(*stream + 2) * 4;
break;
case DEM_RUNSPECIAL:
skip = 2 + *(*stream + 1) * 4;
break;
case DEM_CONVREPLY:
skip = 3;
break;

View file

@ -43,19 +43,20 @@
#include "d_netinf.h"
#include "d_net.h"
#include "d_protocol.h"
#include "d_player.h"
#include "c_dispatch.h"
#include "v_palette.h"
#include "v_video.h"
#include "i_system.h"
#include "r_draw.h"
#include "r_state.h"
#include "sbar.h"
#include "gi.h"
#include "m_random.h"
#include "teaminfo.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "templates.h"
#include "cmdlib.h"
#include "farchive.h"
static FRandom pr_pickteam ("PickRandomTeam");
@ -835,11 +836,9 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info)
{
arc.Read (&info.netname, sizeof(info.netname));
}
arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch;
if (SaveVersion >= 2193)
{
arc << info.colorset;
}
arc << info.team << info.aimdist << info.color
<< info.skin << info.gender << info.neverswitch
<< info.colorset;
return arc;
}

View file

@ -74,6 +74,7 @@ enum
FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum);
void P_EnumPlayerColorSets(FName classname, TArray<int> *out);
const char *GetPrintableDisplayName(const PClass *cls);
class player_t;
@ -136,6 +137,7 @@ public:
int SpawnMask;
FNameNoInit MorphWeapon;
fixed_t AttackZOffset; // attack height, relative to player center
const PClass *FlechetteType;
// [CW] Fades for when you are being damaged.
PalEntry DamageFade;
@ -411,10 +413,7 @@ public:
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
inline FArchive &operator<< (FArchive &arc, player_t *&p)
{
return arc.SerializePointer (players, (BYTE **)&p, sizeof(*players));
}
FArchive &operator<< (FArchive &arc, player_t *&p);
void P_CheckPlayerSprites();

View file

@ -158,6 +158,7 @@ enum EDemoCommand
DEM_CONVREPLY, // 59 Word: Dialogue node, Byte: Reply number
DEM_CONVCLOSE, // 60
DEM_CONVNULL, // 61
DEM_RUNSPECIAL, // 62 Byte: Special number, Byte: Arg count, Ints: Args
};
// The following are implemented by cht_DoCheat in m_cheat.cpp

View file

@ -42,12 +42,13 @@
#include "weightedlist.h"
#include "statnums.h"
#include "templates.h"
#include "r_draw.h"
#include "a_sharedglobal.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "gi.h"
#include "g_level.h"
#include "colormatcher.h"
#include "b_bot.h"
#include "farchive.h"
FDecalLib DecalLibrary;
@ -347,6 +348,16 @@ void FDecalLib::ReadAllDecals ()
int lump, lastlump = 0;
unsigned int i;
for(unsigned i=0;i<Animators.Size(); i++)
{
delete Animators[i];
}
Animators.Clear();
FDecalCombinerAnim::AnimatorList.Clear();
DecalTranslations.Clear();
DecalLibrary.Clear();
while ((lump = Wads.FindLump ("DECALDEF", &lastlump)) != -1)
{
FScanner sc(lump);

View file

@ -37,7 +37,7 @@
#include <string.h>
#include "doomtype.h"
#include "r_blend.h"
#include "r_data/renderstyle.h"
#include "textures/textures.h"
class FScanner;

View file

@ -47,6 +47,7 @@
#include "stats.h"
#include "a_sharedglobal.h"
#include "dsectoreffect.h"
#include "farchive.h"
PClass DObject::_StaticType;
ClassReg DObject::RegistrationInfo =
@ -538,12 +539,7 @@ void DObject::SerializeUserVars(FArchive &arc)
PSymbolTable *symt;
FName varname;
DWORD count, j;
int *varloc;
if (SaveVersion < 1933)
{
return;
}
int *varloc = NULL;
symt = &GetClass()->Symbols;

View file

@ -314,6 +314,9 @@ namespace GC
// is NULLed instead.
void Mark(DObject **obj);
// For cleanup
void DelSoftRootHead();
// Soft-roots an object.
void AddSoftRoot(DObject *obj);

View file

@ -61,18 +61,19 @@
#include "b_bot.h"
#include "p_local.h"
#include "g_game.h"
#include "r_data.h"
#include "a_sharedglobal.h"
#include "sbar.h"
#include "stats.h"
#include "c_dispatch.h"
#include "p_acs.h"
#include "s_sndseq.h"
#include "r_interpolate.h"
#include "r_data/r_interpolate.h"
#include "doomstat.h"
#include "m_argv.h"
#include "po_man.h"
#include "v_video.h"
#include "menu/menu.h"
#include "intermission/intermission.h"
// MACROS ------------------------------------------------------------------
@ -300,6 +301,7 @@ static void MarkRoot()
Mark(screen);
Mark(StatusBar);
Mark(DMenu::CurrentMenu);
Mark(DIntermissionController::CurrentIntermission);
DThinker::MarkRoots();
FCanvasTextureInfo::Mark();
Mark(DACSThinker::ActiveThinker);
@ -527,6 +529,12 @@ void Barrier(DObject *pointing, DObject *pointed)
}
}
void DelSoftRootHead()
{
if (SoftRoots != NULL) delete SoftRoots;
SoftRoots = NULL;
}
//==========================================================================
//
// AddSoftRoot

View file

@ -80,6 +80,24 @@ void PClass::StaticInit ()
}
}
void PClass::ClearRuntimeData ()
{
StaticShutdown();
m_RuntimeActors.Clear();
m_Types.Clear();
memset(TypeHash, 0, sizeof(TypeHash));
bShutdown = false;
// Immediately reinitialize the internal classes
FAutoSegIterator probe(CRegHead, CRegTail);
while (*++probe != NULL)
{
((ClassReg *)*probe)->RegisterClass ();
}
}
void PClass::StaticShutdown ()
{
TArray<size_t *> uniqueFPs(64);
@ -105,6 +123,8 @@ void PClass::StaticShutdown ()
uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers));
}
}
type->FlatPointers = NULL;
// For runtime classes, this call will also delete the PClass.
PClass::StaticFreeData (type);
}
@ -222,7 +242,7 @@ const PClass *PClass::FindClass (FName zaname)
}
else if (lexx == 0)
{
return cls->Size<0? NULL : cls;
return cls;
}
else
{
@ -316,6 +336,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
info->StateList = NULL;
info->DamageFactors = NULL;
info->PainChances = NULL;
info->PainFlashes = NULL;
info->ColorSets = NULL;
m_RuntimeActors.Push (type);
}
@ -410,6 +431,7 @@ void PClass::InitializeActorInfo ()
info->StateList = NULL;
info->DamageFactors = NULL;
info->PainChances = NULL;
info->PainFlashes = NULL;
info->ColorSets = NULL;
m_RuntimeActors.Push (this);
}

View file

@ -125,6 +125,7 @@ struct PClass
static void StaticInit ();
static void StaticShutdown ();
static void StaticFreeData (PClass *type);
static void ClearRuntimeData();
// Per-class information -------------------------------------
FName TypeName; // this class's name

View file

@ -152,6 +152,7 @@ enum ELineFlags
ML_FIRSTSIDEONLY = 0x00800000, // activated only when crossed from front side
ML_BLOCKPROJECTILE = 0x01000000,
ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line
ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight
};
@ -380,6 +381,8 @@ enum EMapThingFlags
MTF_STANDSTILL = 0x4000,
MTF_STRIFESOMETHING = 0x8000,
MTF_SECRET = 0x080000, // Secret pickup
MTF_NOINFIGHTING = 0x100000,
// BOOM and DOOM compatible versions of some of the above
BTF_NOTSINGLE = 0x0010, // (TF_COOPERATIVE|TF_DEATHMATCH)

View file

@ -76,7 +76,9 @@ typedef enum
GS_TITLELEVEL, // [RH] A combination of GS_LEVEL and GS_DEMOSCREEN
GS_FORCEWIPE = -1,
GS_FORCEWIPEFADE = -2
GS_FORCEWIPEFADE = -2,
GS_FORCEWIPEBURN = -3,
GS_FORCEWIPEMELT = -4
} gamestate_t;
extern gamestate_t gamestate;
@ -294,6 +296,7 @@ enum
DF2_NOAUTOAIM = 1 << 23, // Players cannot use autoaim.
DF2_DONTCHECKAMMO = 1 << 24, // Don't Check ammo when switching weapons.
DF2_KILLBOSSMONST = 1 << 25, // Kills all monsters spawned by a boss cube when the boss dies
DF2_NOCOUNTENDMONST = 1 << 26, // Do not count monsters in 'end level when dying' sectors towards kill count
};
// [RH] Compatibility flags.
@ -330,6 +333,7 @@ enum
COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code.
COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom
COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way
COMPATF_MASKEDMIDTEX = 1 << 31, // Ignore compositing when drawing masked midtextures
};
// Emulate old bugs for select maps. These are not exposed by a cvar
@ -339,6 +343,8 @@ enum
BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow
BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps
BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected.
BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials
BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior
};
// phares 3/20/98:

View file

@ -67,3 +67,5 @@ int NextSkill = -1;
int SinglePlayerClass[MAXPLAYERS];
bool ToggleFullscreen;
int BorderTopRefresh;

View file

@ -124,10 +124,6 @@ extern "C" int halfviewwidth; // [RH] Half view width, for plane drawing
// This one is related to the 3-screen display mode.
// ANG90 = left side, ANG270 = right
extern int viewangleoffset;
// Player taking events. i.e. The local player.
extern int consoleplayer;

View file

@ -26,8 +26,9 @@
#include "gi.h"
#include "p_local.h"
#include "p_3dmidtex.h"
#include "r_interpolate.h"
#include "r_data/r_interpolate.h"
#include "statnums.h"
#include "farchive.h"
IMPLEMENT_CLASS (DSectorEffect)

View file

@ -38,6 +38,7 @@
#include "statnums.h"
#include "i_system.h"
#include "doomerrors.h"
#include "farchive.h"
static cycle_t ThinkCycles;

File diff suppressed because it is too large Load diff

View file

@ -1,53 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#ifndef __F_FINALE__
#define __F_FINALE__
#include "basictypes.h"
struct event_t;
//
// FINALE
//
// Called by main loop.
bool F_Responder (event_t* ev);
// Called by main loop.
void F_Ticker ();
// Called by main loop.
void F_Drawer ();
void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat,
const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText,
bool ending, int endsequence = 0);
void F_StartSlideshow ();
void F_EndFinale ();
#endif

View file

@ -55,7 +55,6 @@
#include "c_dispatch.h"
#include "d_player.h"
#include "dobject.h"
#include "r_local.h"
// These are special tokens found in the data stream of an archive.
// Whenever a new object is encountered, it gets created using new and
@ -1539,3 +1538,28 @@ FArchive &operator<< (FArchive &arc, const PClass * &info)
}
return arc;
}
FArchive &operator<< (FArchive &arc, sector_t *&sec)
{
return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
}
FArchive &operator<< (FArchive &arc, const sector_t *&sec)
{
return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
}
FArchive &operator<< (FArchive &arc, line_t *&line)
{
return arc.SerializePointer (lines, (BYTE **)&line, sizeof(*lines));
}
FArchive &operator<< (FArchive &arc, vertex_t *&vert)
{
return arc.SerializePointer (vertexes, (BYTE **)&vert, sizeof(*vertexes));
}
FArchive &operator<< (FArchive &arc, side_t *&side)
{
return arc.SerializePointer (sides, (BYTE **)&side, sizeof(*sides));
}

View file

@ -36,6 +36,7 @@
#include <stdio.h>
#include "dobject.h"
#include "r_state.h"
class FFile
{
@ -291,7 +292,11 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
}
struct FStrifeDialogueNode;
struct FSwitchDef;
struct FDoorAnimation;
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
@ -314,4 +319,17 @@ inline FArchive &operator<< (FArchive &arc, TArray<T,TT> &self)
return arc;
}
struct sector_t;
struct line_t;
struct vertex_t;
struct side_t;
FArchive &operator<< (FArchive &arc, sector_t *&sec);
FArchive &operator<< (FArchive &arc, const sector_t *&sec);
FArchive &operator<< (FArchive &arc, line_t *&line);
FArchive &operator<< (FArchive &arc, vertex_t *&vert);
FArchive &operator<< (FArchive &arc, side_t *&side);
#endif //__FARCHIVE_H__

204
src/fragglescript/t_cmd.cpp Normal file
View file

@ -0,0 +1,204 @@
/*
** t_cmd.cpp
** Emulation for selected Legacy console commands
** Unfortunately Legacy allows full access of FS to the console
** so everything that gets used by some map has to be emulated...
**
**---------------------------------------------------------------------------
** Copyright 2005 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 <string.h>
#include <stdio.h>
#include "p_local.h"
#include "doomdef.h"
#include "doomstat.h"
#include "c_dispatch.h"
#include "sc_man.h"
#include "g_level.h"
#include "r_renderer.h"
//==========================================================================
//
//
//
//==========================================================================
static void FS_Gimme(const char * what)
{
char buffer[80];
// This is intentionally limited to the few items
// it can handle in Legacy.
if (!strnicmp(what, "health", 6)) what="health";
else if (!strnicmp(what, "ammo", 4)) what="ammo";
else if (!strnicmp(what, "armor", 5)) what="greenarmor";
else if (!strnicmp(what, "keys", 4)) what="keys";
else if (!strnicmp(what, "weapons", 7)) what="weapons";
else if (!strnicmp(what, "chainsaw", 8)) what="chainsaw";
else if (!strnicmp(what, "shotgun", 7)) what="shotgun";
else if (!strnicmp(what, "supershotgun", 12)) what="supershotgun";
else if (!strnicmp(what, "rocket", 6)) what="rocketlauncher";
else if (!strnicmp(what, "plasma", 6)) what="plasmarifle";
else if (!strnicmp(what, "bfg", 3)) what="BFG9000";
else if (!strnicmp(what, "chaingun", 8)) what="chaingun";
else if (!strnicmp(what, "berserk", 7)) what="Berserk";
else if (!strnicmp(what, "map", 3)) what="Allmap";
else if (!strnicmp(what, "fullmap", 7)) what="Allmap";
else return;
mysnprintf(buffer, countof(buffer), "give %.72s", what);
AddCommandString(buffer);
}
//==========================================================================
//
//
//
//==========================================================================
void FS_MapCmd(FScanner &sc)
{
char nextmap[9];
int NextSkill = -1;
int flags = CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH;
if (dmflags & DF_NO_MONSTERS)
flags |= CHANGELEVEL_NOMONSTERS;
sc.MustGetString();
strncpy (nextmap, sc.String, 8);
nextmap[8]=0;
while (sc.GetString())
{
if (sc.Compare("-skill"))
{
sc.MustGetNumber();
NextSkill = clamp<int>(sc.Number-1, 0, AllSkills.Size()-1);
}
else if (sc.Compare("-monsters"))
{
sc.MustGetNumber();
if (sc.Number)
flags &= ~CHANGELEVEL_NOMONSTERS;
else
flags |= CHANGELEVEL_NOMONSTERS;
}
else if (sc.Compare("-noresetplayers"))
{
flags &= ~(CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH);
}
}
G_ChangeLevel(nextmap, 0, flags, NextSkill);
}
//==========================================================================
//
//
//
//==========================================================================
void FS_EmulateCmd(char * string)
{
FScanner sc;
sc.OpenMem("RUNCMD", string, (int)strlen(string));
while (sc.GetString())
{
if (sc.Compare("GIMME"))
{
while (sc.GetString())
{
if (!sc.Compare(";")) FS_Gimme(sc.String);
else break;
}
}
else if (sc.Compare("ALLOWJUMP"))
{
sc.MustGetNumber();
if (sc.Number) dmflags = dmflags & ~DF_NO_JUMP;
else dmflags=dmflags | DF_NO_JUMP;
while (sc.GetString())
{
if (sc.Compare(";")) break;
}
}
else if (sc.Compare("gravity"))
{
sc.MustGetFloat();
level.gravity=(float)(sc.Float*800);
while (sc.GetString())
{
if (sc.Compare(";")) break;
}
}
else if (sc.Compare("viewheight"))
{
sc.MustGetFloat();
fixed_t playerviewheight = (fixed_t)(sc.Float*FRACUNIT);
for(int i=0;i<MAXPLAYERS;i++)
{
// 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->ViewHeight = playerviewheight;
players[i].Uncrouch();
}
while (sc.GetString())
{
if (sc.Compare(";")) break;
}
}
else if (sc.Compare("map"))
{
FS_MapCmd(sc);
}
else if (sc.Compare("gr_fogdensity"))
{
sc.MustGetNumber();
// Using this disables most MAPINFO fog options!
Renderer->SetFogParams(sc.Number*70/400, 0xff000000, 0, 0);
}
else if (sc.Compare("gr_fogcolor"))
{
sc.MustGetString();
level.fadeto = strtol(sc.String, NULL, 16);
}
else
{
// Skip unhandled commands
while (sc.GetString())
{
if (sc.Compare(";")) break;
}
}
}
}

14
src/fragglescript/t_fs.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef T_FS_H
#define T_FS_H
// global FS interface
struct MapData;
class AActor;
void T_PreprocessScripts();
void T_LoadScripts(MapData * map);
void T_AddSpawnedThing(AActor * );
#endif

View file

@ -0,0 +1,203 @@
/*
** t_fspic.cpp
** Fragglescript HUD pics (incomplete and untested!)
**
**---------------------------------------------------------------------------
** Copyright 2005 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 "t_script.h"
#include "doomtype.h"
#include "p_local.h"
#include "farchive.h"
#include "sbar.h"
#include "v_video.h"
struct FHudPic
{
FTextureID texturenum;
int xpos;
int ypos;
bool draw;
void Serialize(FArchive & arc)
{
arc << xpos << ypos << draw << texturenum;
}
};
//======================================================================
//
//======================================================================
class DHUDPicManager : public DHUDMessage
{
// This is no real hudmessage but this way I don't need any external code to handle this
// because the hudmessage and thinker code handles everything automatically
DECLARE_CLASS(DHUDPicManager, DHUDMessage)
float basetrans;
public:
TArray<FHudPic> piclist;
DHUDPicManager();
~DHUDPicManager() {}
void Serialize(FArchive & ar);
virtual void DoDraw (int linenum, int x, int y, int hudheight, float translucent);
} ;
IMPLEMENT_CLASS(DHUDPicManager)
//======================================================================
//
//======================================================================
DHUDPicManager::DHUDPicManager()
{
HUDWidth=HUDHeight=0;
basetrans=0.8f;
//SetID(0xffffffff);
NumLines=1;
HoldTics=0; // stay forever!
//logtoconsole=false;
}
//======================================================================
//
//======================================================================
void DHUDPicManager::Serialize(FArchive & ar)
{
Super::Serialize(ar);
short count=piclist.Size();
ar << count << basetrans;
if (ar.IsLoading()) piclist.Resize(count);
for(int i=0;i<count;i++) piclist[i].Serialize(ar);
}
//======================================================================
//
//======================================================================
void DHUDPicManager::DoDraw (int linenum, int x, int y, int hudheight, float translucent)
{
for(unsigned int i=0; i<piclist.Size();i++) if (piclist[i].texturenum.isValid() && piclist[i].draw)
{
FTexture * tex = TexMan[piclist[i].texturenum];
if (tex) screen->DrawTexture(tex, piclist[i].xpos, piclist[i].ypos, DTA_320x200, true,
DTA_Alpha, (fixed_t)(translucent*basetrans*FRACUNIT), TAG_DONE);
}
}
//======================================================================
//
//======================================================================
static TArray<FHudPic> & GetPicList()
{
//TThinkerIterator<DHUDPicManager> it;
DHUDPicManager * pm=NULL;//it.Next();
if (!pm) pm=new DHUDPicManager;
return pm->piclist;
}
//======================================================================
//
// External interface
//
//======================================================================
//======================================================================
//
//======================================================================
int HU_GetFSPic(FTextureID texturenum, int xpos, int ypos)
{
TArray<FHudPic> &piclist=GetPicList();
unsigned int i;
for(i=0;i<piclist.Size();i++) if (piclist[i].texturenum.isValid()) continue;
if (i==piclist.Size()) i=piclist.Reserve(1);
FHudPic * pic=&piclist[i];
piclist[i].texturenum = texturenum;
piclist[i].xpos = xpos;
piclist[i].ypos = ypos;
piclist[i].draw = false;
return i;
}
//======================================================================
//
//======================================================================
int HU_DeleteFSPic(unsigned handle)
{
TArray<FHudPic> &piclist=GetPicList();
if(handle >= piclist.Size()) return -1;
piclist[handle].texturenum.SetInvalid();
return 0;
}
//======================================================================
//
//======================================================================
int HU_ModifyFSPic(unsigned handle, FTextureID texturenum, int xpos, int ypos)
{
TArray<FHudPic> &piclist=GetPicList();
if(handle >= piclist.Size()) return -1;
if(!piclist[handle].texturenum.isValid()) return -1;
piclist[handle].texturenum = texturenum;
piclist[handle].xpos = xpos;
piclist[handle].ypos = ypos;
return 0;
}
//======================================================================
//
//======================================================================
int HU_FSDisplay(unsigned handle, bool newval)
{
TArray<FHudPic> &piclist=GetPicList();
if(handle >= piclist.Size()) return -1;
if(!piclist[handle].texturenum.isValid()) return -1;
piclist[handle].draw = newval;
return 0;
}

4845
src/fragglescript/t_func.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,367 @@
/*
** t_load.cpp
** FraggleScript loader
**
**---------------------------------------------------------------------------
** Copyright 2002-2005 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 "w_wad.h"
#include "tarray.h"
#include "g_level.h"
#include "sc_man.h"
#include "s_sound.h"
#include "r_sky.h"
#include "t_script.h"
#include "cmdlib.h"
#include "p_lnspec.h"
#include "gi.h"
#include "xlat/xlat.h"
void T_Init();
class FScriptLoader
{
enum
{
RT_SCRIPT,
RT_INFO,
RT_OTHER,
} readtype;
int drownflag;
bool HasScripts;
bool IgnoreInfo;
void ParseInfoCmd(char *line, FString &scriptsrc);
public:
bool ParseInfo(MapData * map);
};
struct FFsOptions : public FOptionalMapinfoData
{
FFsOptions()
{
identifier = "fragglescript";
nocheckposition = false;
}
virtual FOptionalMapinfoData *Clone() const
{
FFsOptions *newopt = new FFsOptions;
newopt->identifier = identifier;
newopt->nocheckposition = nocheckposition;
return newopt;
}
bool nocheckposition;
};
DEFINE_MAP_OPTION(fs_nocheckposition, false)
{
FFsOptions *opt = info->GetOptData<FFsOptions>("fragglescript");
parse.ParseAssign();
if (parse.CheckAssign())
{
parse.sc.MustGetNumber();
opt->nocheckposition = !!parse.sc.Number;
}
else
{
opt->nocheckposition = true;
}
}
//-----------------------------------------------------------------------------
//
// Process the lump to strip all unneeded information from it
//
//-----------------------------------------------------------------------------
void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
{
char *temp;
// clear any control chars
for(temp=line; *temp; temp++) if (*temp<32) *temp=32;
if(readtype != RT_SCRIPT) // not for scripts
{
temp = line+strlen(line)-1;
// strip spaces at the beginning and end of the line
while(*temp == ' ') *temp-- = 0;
while(*line == ' ') line++;
if(!*line) return;
if((line[0] == '/' && line[1] == '/') || // comment
line[0] == '#' || line[0] == ';') return;
}
if(*line == '[') // a new section seperator
{
line++;
if(!strnicmp(line, "scripts", 7))
{
readtype = RT_SCRIPT;
HasScripts = true; // has scripts
}
else if (!strnicmp(line, "level info", 10))
{
readtype = RT_INFO;
}
return;
}
if (readtype==RT_SCRIPT)
{
scriptsrc << line << '\n';
}
else if (readtype==RT_INFO)
{
// Read the usable parts of the level info header
// and ignore the rest.
FScanner sc;
sc.OpenMem("LEVELINFO", line, (int)strlen(line));
sc.SetCMode(true);
sc.MustGetString();
if (sc.Compare("levelname"))
{
char * beg = strchr(line, '=')+1;
while (*beg<=' ') beg++;
char * comm = strstr(beg, "//");
if (comm) *comm=0;
level.LevelName = beg;
}
else if (sc.Compare("partime"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
level.partime=sc.Number;
}
else if (sc.Compare("music"))
{
bool FS_ChangeMusic(const char * string);
sc.MustGetStringName("=");
sc.MustGetString();
if (!FS_ChangeMusic(sc.String))
{
S_ChangeMusic(level.Music, level.musicorder);
}
}
else if (sc.Compare("skyname"))
{
sc.MustGetStringName("=");
sc.MustGetString();
strncpy(level.skypic1, sc.String, 8);
strncpy(level.skypic2, sc.String, 8);
level.skypic1[8]=level.skypic2[8]=0;
sky2texture = sky1texture = TexMan.GetTexture (sc.String, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
R_InitSkyMap ();
}
else if (sc.Compare("interpic"))
{
sc.MustGetStringName("=");
sc.MustGetString();
level.info->ExitPic = sc.String;
}
else if (sc.Compare("gravity"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
level.gravity=sc.Number*8.f;
}
else if (sc.Compare("nextlevel"))
{
sc.MustGetStringName("=");
sc.MustGetString();
strncpy(level.nextmap, sc.String, 8);
level.nextmap[8]=0;
}
else if (sc.Compare("nextsecret"))
{
sc.MustGetStringName("=");
sc.MustGetString();
strncpy(level.secretmap, sc.String, 8);
level.secretmap[8]=0;
}
else if (sc.Compare("drown"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
drownflag=!!sc.Number;
}
else if (sc.Compare("consolecmd"))
{
char * beg = strchr(line, '=')+1;
while (*beg<' ') beg++;
char * comm = strstr(beg, "//");
if (comm) *comm=0;
FS_EmulateCmd(beg);
}
else if (sc.Compare("ignore"))
{
sc.MustGetStringName("=");
sc.MustGetNumber();
IgnoreInfo=!!sc.Number;
}
// Ignore anything unknows
sc.Close();
}
}
//-----------------------------------------------------------------------------
//
// Loads the scripts for the current map
// Initializes all FS data
//
//-----------------------------------------------------------------------------
bool FScriptLoader::ParseInfo(MapData * map)
{
char *lump;
char *rover;
char *startofline;
int lumpsize;
bool fsglobal=false;
FString scriptsrc;
// Global initializazion if not done yet.
static bool done=false;
// Load the script lump
IgnoreInfo = false;
lumpsize = map->Size(0);
if (lumpsize==0)
{
// Try a global FS lump
int lumpnum=Wads.CheckNumForName("FSGLOBAL");
if (lumpnum<0) return false;
lumpsize=Wads.LumpLength(lumpnum);
if (lumpsize==0) return false;
fsglobal=true;
lump=new char[lumpsize+3];
Wads.ReadLump(lumpnum,lump);
}
else
{
lump=new char[lumpsize+3];
map->Read(0, lump);
}
// Append a new line. The parser likes to crash when the last character is a valid token.
lump[lumpsize]='\n';
lump[lumpsize+1]='\r';
lump[lumpsize+2]=0;
lumpsize+=2;
rover = startofline = lump;
HasScripts=false;
drownflag=-1;
readtype = RT_OTHER;
while(rover < lump+lumpsize)
{
if(*rover == '\n') // end of line
{
*rover = 0; // make it an end of string (0)
if (!IgnoreInfo) ParseInfoCmd(startofline, scriptsrc);
startofline = rover+1; // next line
*rover = '\n'; // back to end of line
}
rover++;
}
if (HasScripts)
{
new DFraggleThinker;
DFraggleThinker::ActiveThinker->LevelScript->data = copystring(scriptsrc.GetChars());
if (drownflag==-1) drownflag = (level.maptype != MAPTYPE_DOOM || fsglobal);
if (!drownflag) level.airsupply=0; // Legacy doesn't to water damage so we need to check if it has to be disabled here.
FFsOptions *opt = level.info->GetOptData<FFsOptions>("fragglescript", false);
if (opt != NULL)
{
DFraggleThinker::ActiveThinker->nocheckposition = opt->nocheckposition;
}
}
delete lump;
return HasScripts;
}
//-----------------------------------------------------------------------------
//
// Starts the level info parser
// and patches the global linedef translation table
//
//-----------------------------------------------------------------------------
void T_LoadScripts(MapData *map)
{
FScriptLoader parser;
T_Init();
bool HasScripts = parser.ParseInfo(map);
// Hack for Legacy compatibility: Since 272 is normally an MBF sky transfer we have to patch it.
// It could be done with an additional translator but that would be sub-optimal for the user.
// To handle this the default translator defines the proper Legacy type at index 270.
// This code then then swaps 270 and 272 - but only if this is either Doom or Heretic and
// 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[272 - 2*HasScripts].special == FS_Execute)
{
FLineTrans t = SimpleLineTranslations[270];
SimpleLineTranslations[270] = SimpleLineTranslations[272];
SimpleLineTranslations[272] = t;
}
}
//-----------------------------------------------------------------------------
//
// Adds an actor to the list of spawned things
//
//-----------------------------------------------------------------------------
void T_AddSpawnedThing(AActor * ac)
{
if (DFraggleThinker::ActiveThinker)
{
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
SpawnedThings.Push(GC::ReadBarrier(ac));
}
}

View file

@ -0,0 +1,653 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// Operators
//
// Handler code for all the operators. The 'other half'
// of the parsing.
//
// By Simon Howard
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
/* includes ************************/
#include "t_script.h"
#define evaluate_leftnright(a, b, c) {\
EvaluateExpression(left, (a), (b)-1); \
EvaluateExpression(right, (b)+1, (c)); }\
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
FParser::operator_t FParser::operators[]=
{
{"=", &FParser::OPequals, backward},
{"||", &FParser::OPor, forward},
{"&&", &FParser::OPand, forward},
{"|", &FParser::OPor_bin, forward},
{"&", &FParser::OPand_bin, forward},
{"==", &FParser::OPcmp, forward},
{"!=", &FParser::OPnotcmp, forward},
{"<", &FParser::OPlessthan, forward},
{">", &FParser::OPgreaterthan, forward},
{"<=", &FParser::OPlessthanorequal, forward},
{">=", &FParser::OPgreaterthanorequal, forward},
{"+", &FParser::OPplus, forward},
{"-", &FParser::OPminus, forward},
{"*", &FParser::OPmultiply, forward},
{"/", &FParser::OPdivide, forward},
{"%", &FParser::OPremainder, forward},
{"~", &FParser::OPnot_bin, forward}, // haleyjd
{"!", &FParser::OPnot, forward},
{"++", &FParser::OPincrement, forward},
{"--", &FParser::OPdecrement, forward},
{".", &FParser::OPstructure, forward},
};
int FParser::num_operators = sizeof(FParser::operators) / sizeof(FParser::operator_t);
/***************** logic *********************/
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPequals(svalue_t &result, int start, int n, int stop)
{
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
if(var)
{
EvaluateExpression(result, n+1, stop);
var->SetValue (result);
}
else
{
script_error("unknown variable '%s'\n", Tokens[start]);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPor(svalue_t &result, int start, int n, int stop)
{
int exprtrue = false;
// if first is true, do not evaluate the second
EvaluateExpression(result, start, n-1);
if(intvalue(result))
exprtrue = true;
else
{
EvaluateExpression(result, n+1, stop);
exprtrue = !!intvalue(result);
}
result.type = svt_int;
result.value.i = exprtrue;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPand(svalue_t &result, int start, int n, int stop)
{
int exprtrue = true;
// if first is false, do not eval second
EvaluateExpression(result, start, n-1);
if(!intvalue(result) )
exprtrue = false;
else
{
EvaluateExpression(result, n+1, stop);
exprtrue = !!intvalue(result);
}
result.type = svt_int;
result.value.i = exprtrue;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPcmp(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int; // always an int returned
if(left.type == svt_string && right.type == svt_string)
{
result.value.i = !strcmp(left.string, right.string);
return;
}
// haleyjd: direct mobj comparison when both are mobj
if(left.type == svt_mobj && right.type == svt_mobj)
{
// we can safely assume reference equivalency for
// AActor's in all cases since they are static for the
// duration of a level
result.value.i = (left.value.mobj == right.value.mobj);
return;
}
if(left.type == svt_fixed || right.type == svt_fixed)
{
result.value.i = (fixedvalue(left) == fixedvalue(right));
return;
}
result.value.i = (intvalue(left) == intvalue(right));
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPnotcmp(svalue_t &result, int start, int n, int stop)
{
OPcmp(result, start, n, stop);
result.type = svt_int;
result.value.i = !result.value.i;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPlessthan(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int;
// haleyjd: 8-17
if(left.type == svt_fixed || right.type == svt_fixed)
result.value.i = (fixedvalue(left) < fixedvalue(right));
else
result.value.i = (intvalue(left) < intvalue(right));
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPgreaterthan(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
// haleyjd: 8-17
result.type = svt_int;
if(left.type == svt_fixed || right.type == svt_fixed)
result.value.i = (fixedvalue(left) > fixedvalue(right));
else
result.value.i = (intvalue(left) > intvalue(right));
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPnot(svalue_t &result, int start, int n, int stop)
{
EvaluateExpression(result, n+1, stop);
result.value.i = !intvalue(result);
result.type = svt_int;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPplus(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
if (left.type == svt_string)
{
if (right.type == svt_string)
{
result.string.Format("%s%s", left.string.GetChars(), right.string.GetChars());
}
else if (right.type == svt_fixed)
{
result.string.Format("%s%4.4f", left.string.GetChars(), floatvalue(right));
}
else
{
result.string.Format("%s%i", left.string.GetChars(), intvalue(right));
}
result.type = svt_string;
}
// haleyjd: 8-17
else if(left.type == svt_fixed || right.type == svt_fixed)
{
result.type = svt_fixed;
result.value.f = fixedvalue(left) + fixedvalue(right);
}
else
{
result.type = svt_int;
result.value.i = intvalue(left) + intvalue(right);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPminus(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
// do they mean minus as in '-1' rather than '2-1'?
if(start == n)
{
// kinda hack, hehe
EvaluateExpression(right, n+1, stop);
}
else
{
evaluate_leftnright(start, n, stop);
}
// haleyjd: 8-17
if(left.type == svt_fixed || right.type == svt_fixed)
{
result.type = svt_fixed;
result.value.f = fixedvalue(left) - fixedvalue(right);
}
else
{
result.type = svt_int;
result.value.i = intvalue(left) - intvalue(right);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPmultiply(svalue_t &result,int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
// haleyjd: 8-17
if(left.type == svt_fixed || right.type == svt_fixed)
{
result.type = svt_fixed;
result.value.f = FixedMul(fixedvalue(left), fixedvalue(right));
}
else
{
result.type = svt_int;
result.value.i = intvalue(left) * intvalue(right);
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPdivide(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
// haleyjd: 8-17
if(left.type == svt_fixed || right.type == svt_fixed)
{
fixed_t fr;
if((fr = fixedvalue(right)) == 0)
script_error("divide by zero\n");
else
{
result.type = svt_fixed;
result.value.f = FixedDiv(fixedvalue(left), fr);
}
}
else
{
int ir;
if(!(ir = intvalue(right)))
script_error("divide by zero\n");
else
{
result.type = svt_int;
result.value.i = intvalue(left) / ir;
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPremainder(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
int ir;
evaluate_leftnright(start, n, stop);
if(!(ir = intvalue(right)))
script_error("divide by zero\n");
else
{
result.type = svt_int;
result.value.i = intvalue(left) % ir;
}
}
/********** binary operators **************/
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPor_bin(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int;
result.value.i = intvalue(left) | intvalue(right);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPand_bin(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int;
result.value.i = intvalue(left) & intvalue(right);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPnot_bin(svalue_t &result, int start, int n, int stop)
{
EvaluateExpression(result, n+1, stop);
result.value.i = ~intvalue(result);
result.type = svt_int;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
{
if(start == n) // ++n
{
DFsVariable *var;
var = Script->FindVariable(Tokens[stop]);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[stop]);
}
var->GetValue(result);
// haleyjd
if(var->type != svt_fixed)
{
result.value.i = intvalue(result) + 1;
result.type = svt_int;
var->SetValue (result);
}
else
{
result.value.f = fixedvalue(result) + FRACUNIT;
result.type = svt_fixed;
var->SetValue (result);
}
}
else if(stop == n) // n++
{
svalue_t newvalue;
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[start]);
}
var->GetValue(result);
// haleyjd
if(var->type != svt_fixed)
{
newvalue.type = svt_int;
newvalue.value.i = intvalue(result) + 1;
var->SetValue (newvalue);
}
else
{
newvalue.type = svt_fixed;
newvalue.value.f = fixedvalue(result) + FRACUNIT;
var->SetValue (newvalue);
}
}
else
{
script_error("incorrect arguments to ++ operator\n");
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
{
if(start == n) // ++n
{
DFsVariable *var;
var = Script->FindVariable(Tokens[stop]);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[stop]);
}
var->GetValue(result);
// haleyjd
if(var->type != svt_fixed)
{
result.value.i = intvalue(result) - 1;
result.type = svt_int;
var->SetValue (result);
}
else
{
result.value.f = fixedvalue(result) - FRACUNIT;
result.type = svt_fixed;
var->SetValue (result);
}
}
else if(stop == n) // n++
{
svalue_t newvalue;
DFsVariable *var;
var = Script->FindVariable(Tokens[start]);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[start]);
}
var->GetValue(result);
// haleyjd
if(var->type != svt_fixed)
{
newvalue.type = svt_int;
newvalue.value.i = intvalue(result) - 1;
var->SetValue (newvalue);
}
else
{
newvalue.type = svt_fixed;
newvalue.value.f = fixedvalue(result) - FRACUNIT;
var->SetValue (newvalue);
}
}
else
{
script_error("incorrect arguments to ++ operator\n");
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPlessthanorequal(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int;
if(left.type == svt_fixed || right.type == svt_fixed)
result.value.i = (fixedvalue(left) <= fixedvalue(right));
else
result.value.i = (intvalue(left) <= intvalue(right));
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FParser::OPgreaterthanorequal(svalue_t &result, int start, int n, int stop)
{
svalue_t left, right;
evaluate_leftnright(start, n, stop);
result.type = svt_int;
if(left.type == svt_fixed || right.type == svt_fixed)
result.value.i = (fixedvalue(left) >= fixedvalue(right));
else
result.value.i = (intvalue(left) >= intvalue(right));
}

View file

@ -0,0 +1,746 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
// Copyright(C) 2002-2008 Christoph Oelckers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// Parsing.
//
// Takes lines of code, or groups of lines and runs them.
// The main core of FraggleScript
//
// By Simon Howard
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
/* includes ************************/
#include <stdarg.h>
#include "t_script.h"
#include "s_sound.h"
#include "v_text.h"
#include "c_cvars.h"
#include "i_system.h"
CVAR(Bool, script_debug, false, 0)
/************ Divide into tokens **************/
#define isnum(c) ( ((c)>='0' && (c)<='9') || (c)=='.')
//==========================================================================
//
// NextToken: end this token, go onto the next
//
//==========================================================================
void FParser::NextToken()
{
if(Tokens[NumTokens-1][0] || TokenType[NumTokens-1]==string_)
{
NumTokens++;
Tokens[NumTokens-1] = Tokens[NumTokens-2] + strlen(Tokens[NumTokens-2]) + 1;
Tokens[NumTokens-1][0] = 0;
}
// get to the next token, ignoring spaces, newlines,
// useless chars, comments etc
while(1)
{
// empty whitespace
if(*Rover && (*Rover==' ' || *Rover<32))
{
while((*Rover==' ' || *Rover<32) && *Rover) Rover++;
}
// end-of-script?
if(!*Rover)
{
if(Tokens[0][0])
{
// line contains text, but no semicolon: an error
script_error("missing ';'\n");
}
// empty line, end of command-list
return;
}
break; // otherwise
}
if(NumTokens>1 && *Rover == '(' && TokenType[NumTokens-2] == name_)
TokenType[NumTokens-2] = function;
if(*Rover == '{' || *Rover == '}')
{
if(*Rover == '{')
{
BraceType = bracket_open;
Section = Script->FindSectionStart(Rover);
}
else // closing brace
{
BraceType = bracket_close;
Section = Script->FindSectionEnd(Rover);
}
if(!Section)
{
I_Error("section not found!\n");
return;
}
}
else if(*Rover == ':') // label
{
// ignore the label : reset
NumTokens = 1;
Tokens[0][0] = 0; TokenType[NumTokens-1] = name_;
Rover++; // ignore
}
else if(*Rover == '\"')
{
TokenType[NumTokens-1] = string_;
if(TokenType[NumTokens-2] == string_) NumTokens--; // join strings
Rover++;
}
else
{
TokenType[NumTokens-1] = isop(*Rover) ? operator_ : isnum(*Rover) ? number : name_;
}
}
//==========================================================================
//
// return an escape sequence (prefixed by a '\')
// do not use all C escape sequences
//
//==========================================================================
static char escape_sequence(char c)
{
if(c == 'n') return '\n';
if(c == '\\') return '\\';
if(c == '"') return '"';
if(c == '?') return '?';
if(c == 'a') return '\a'; // alert beep
if(c == 't') return '\t'; //tab
return c;
}
//==========================================================================
//
// add_char: add one character to the current token
//
//==========================================================================
static void add_char(char *tokn, char c)
{
char *out = tokn + strlen(tokn);
out[0] = c;
out[1] = 0;
}
//==========================================================================
//
// get_tokens.
// Take a string, break it into tokens.
//
// individual tokens are stored inside the tokens[] array
// tokentype is also used to hold the type for each token:
//
// name: a piece of text which starts with an alphabet letter.
// probably a variable name. Some are converted into
// function types later on in find_brackets
// number: a number. like '12' or '1337'
// operator: an operator such as '&&' or '+'. All FraggleScript
// operators are either one character, or two character
// (if 2 character, 2 of the same char or ending in '=')
// string: a text string that was enclosed in quote "" marks in
// the original text
// unset: shouldn't ever end up being set really.
// function: a function name (found in second stage parsing)
//
//==========================================================================
char *FParser::GetTokens(char *s)
{
char *tokn = NULL;
Rover = s;
NumTokens = 1;
Tokens[0][0] = 0; TokenType[NumTokens-1] = name_;
Section = NULL; // default to no section found
NextToken();
LineStart = Rover; // save the start
if(*Rover)
{
while(1)
{
tokn = Tokens[NumTokens-1];
if(Section)
{
// a { or } section brace has been found
break; // stop parsing now
}
else if(TokenType[NumTokens-1] != string_)
{
if(*Rover == ';') break; // check for end of command ';'
}
switch(TokenType[NumTokens-1])
{
case unset:
case string_:
while(*Rover != '\"') // dedicated loop for speed
{
if(*Rover == '\\') // escape sequences
{
Rover++;
if (*Rover>='0' && *Rover<='9')
{
add_char(tokn, TEXTCOLOR_ESCAPE);
add_char(tokn, *Rover+'A'-'0');
}
else add_char(tokn, escape_sequence(*Rover));
}
else
add_char(tokn, *Rover);
Rover++;
}
Rover++;
NextToken(); // end of this token
continue;
case operator_:
// all 2-character operators either end in '=' or
// are 2 of the same character
// do not allow 2-characters for brackets '(' ')'
// which are still being considered as operators
// operators are only 2-char max, do not need
// a seperate loop
if((*tokn && *Rover != '=' && *Rover!=*tokn) ||
*tokn == '(' || *tokn == ')')
{
// end of operator
NextToken();
continue;
}
add_char(tokn, *Rover);
break;
case number:
// haleyjd: 8-17
// add while number chars are read
while(isnum(*Rover)) // dedicated loop
add_char(tokn, *Rover++);
NextToken();
continue;
case name_:
// add the chars
while(!isop(*Rover)) // dedicated loop
add_char(tokn, *Rover++);
NextToken();
continue;
default:
break;
}
Rover++;
}
}
// check for empty last token
if(!tokn || !tokn[0])
{
NumTokens = NumTokens - 1;
}
Rover++;
return Rover;
}
//==========================================================================
//
// PrintTokens: add one character to the current token
//
//==========================================================================
void FParser::PrintTokens() // DEBUG
{
int i;
for (i = 0; i < NumTokens; i++)
{
Printf("\n'%s' \t\t --", Tokens[i]);
switch (TokenType[i])
{
case string_:
Printf("string");
break;
case operator_:
Printf("operator");
break;
case name_:
Printf("name");
break;
case number:
Printf("number");
break;
case unset:
Printf("duh");
break;
case function:
Printf("function name");
break;
}
}
Printf("\n");
if (Section)
Printf("current section: offset %i\n", Section->start_index);
}
//==========================================================================
//
// Parses a block of script code
//
//==========================================================================
void FParser::Run(char *rover, char *data, char *end)
{
Rover = rover;
try
{
PrevSection = NULL; // clear it
while(*Rover) // go through the script executing each statement
{
// past end of script?
if(Rover > end)
break;
PrevSection = Section; // store from prev. statement
// get the line and tokens
GetTokens(Rover);
if(!NumTokens)
{
if(Section) // no tokens but a brace
{
// possible } at end of loop:
// refer to spec.c
spec_brace();
}
continue; // continue to next statement
}
if(script_debug) PrintTokens(); // debug
RunStatement(); // run the statement
}
}
catch (const CFsError &err)
{
ErrorMessage(err.msg);
}
catch (const CFsTerminator &)
{
// The script has signalled that it wants to be terminated in an orderly fashion.
}
}
//==========================================================================
//
// decide what to do with it
//
// NB this stuff is a bit hardcoded:
// it could be nicer really but i'm
// aiming for speed
//
// if() and while() will be mistaken for functions
// during token processing
//
//==========================================================================
void FParser::RunStatement()
{
if(TokenType[0] == function)
{
if(!strcmp(Tokens[0], "if"))
{
Script->lastiftrue = spec_if();
return;
}
else if(!strcmp(Tokens[0], "elseif"))
{
if(!PrevSection ||
(PrevSection->type != st_if &&
PrevSection->type != st_elseif))
{
script_error("elseif statement without if\n");
return;
}
Script->lastiftrue = spec_elseif(Script->lastiftrue);
return;
}
else if(!strcmp(Tokens[0], "else"))
{
if(!PrevSection ||
(PrevSection->type != st_if &&
PrevSection->type != st_elseif))
{
script_error("else statement without if\n");
return;
}
spec_else(Script->lastiftrue);
Script->lastiftrue = true;
return;
}
else if(!strcmp(Tokens[0], "while"))
{
spec_while();
return;
}
else if(!strcmp(Tokens[0], "for"))
{
spec_for();
return;
}
}
else if(TokenType[0] == name_)
{
// NB: goto is a function so is not here
// Allow else without '()'
if (!strcmp(Tokens[0], "else"))
{
if(!PrevSection ||
(PrevSection->type != st_if &&
PrevSection->type != st_elseif))
{
script_error("else statement without if\n");
return;
}
spec_else(Script->lastiftrue);
Script->lastiftrue = true;
return;
}
// if a variable declaration, return now
if(spec_variable()) return;
}
// just a plain expression
svalue_t scratch;
EvaluateExpression(scratch,0, NumTokens-1);
}
/***************** Evaluating Expressions ************************/
//==========================================================================
//
// find a token, ignoring things in brackets
//
//==========================================================================
int FParser::FindOperator(int start, int stop, const char *value)
{
int i;
int bracketlevel = 0;
for(i=start; i<=stop; i++)
{
// only interested in operators
if(TokenType[i] != operator_) continue;
// use bracketlevel to check the number of brackets
// which we are inside
bracketlevel += Tokens[i][0]=='(' ? 1 :
Tokens[i][0]==')' ? -1 : 0;
// only check when we are not in brackets
if(!bracketlevel && !strcmp(value, Tokens[i]))
return i;
}
return -1;
}
//==========================================================================
//
// go through tokens the same as find_operator, but backwards
//
//==========================================================================
int FParser::FindOperatorBackwards(int start, int stop, const char *value)
{
int i;
int bracketlevel = 0;
for(i=stop; i>=start; i--) // check backwards
{
// operators only
if(TokenType[i] != operator_) continue;
// use bracketlevel to check the number of brackets
// which we are inside
bracketlevel += Tokens[i][0]=='(' ? -1 :
Tokens[i][0]==')' ? 1 : 0;
// only check when we are not in brackets
// if we find what we want, return it
if(!bracketlevel && !strcmp(value, Tokens[i]))
return i;
}
return -1;
}
//==========================================================================
//
// simple_evaluate is used once evalute_expression gets to the level
// where it is evaluating just one token
//
// converts number tokens into svalue_ts and returns
// the same with string tokens
// name tokens are considered to be variables and
// attempts are made to find the value of that variable
// command tokens are executed (does not return a svalue_t)
//
//==========================================================================
void FParser::SimpleEvaluate(svalue_t &returnvar, int n)
{
DFsVariable *var;
switch(TokenType[n])
{
case string_:
returnvar.type = svt_string;
returnvar.string = Tokens[n];
break;
case number:
if(strchr(Tokens[n], '.'))
{
returnvar.type = svt_fixed;
returnvar.value.f = (fixed_t)(atof(Tokens[n]) * FRACUNIT);
}
else
{
returnvar.type = svt_int;
returnvar.value.i = atoi(Tokens[n]);
}
break;
case name_:
var = Script->FindVariable(Tokens[n]);
if(!var)
{
script_error("unknown variable '%s'\n", Tokens[n]);
}
else var->GetValue(returnvar);
default:
break;
}
}
//==========================================================================
//
// pointless_brackets checks to see if there are brackets surrounding
// an expression. eg. "(2+4)" is the same as just "2+4"
//
// because of the recursive nature of evaluate_expression, this function is
// neccesary as evaluating expressions such as "2*(2+4)" will inevitably
// lead to evaluating "(2+4)"
//
//==========================================================================
void FParser::PointlessBrackets(int *start, int *stop)
{
int bracket_level, i;
// check that the start and end are brackets
while(Tokens[*start][0] == '(' && Tokens[*stop][0] == ')')
{
bracket_level = 0;
// confirm there are pointless brackets..
// if they are, bracket_level will only get to 0
// at the last token
// check up to <*stop rather than <=*stop to ignore
// the last token
for(i = *start; i<*stop; i++)
{
if(TokenType[i] != operator_) continue; // ops only
bracket_level += (Tokens[i][0] == '(');
bracket_level -= (Tokens[i][0] == ')');
if(bracket_level == 0) return; // stop if braces stop before end
}
// move both brackets in
*start = *start + 1;
*stop = *stop - 1;
}
}
//==========================================================================
//
// evaluate_expresion is the basic function used to evaluate
// a FraggleScript expression.
// start and stop denote the tokens which are to be evaluated.
//
// works by recursion: it finds operators in the expression
// (checking for each in turn), then splits the expression into
// 2 parts, left and right of the operator found.
// The handler function for that particular operator is then
// called, which in turn calls evaluate_expression again to
// evaluate each side. When it reaches the level of being asked
// to evaluate just 1 token, it calls simple_evaluate
//
//==========================================================================
void FParser::EvaluateExpression(svalue_t &result, int start, int stop)
{
int i, n;
// possible pointless brackets
if(TokenType[start] == operator_ && TokenType[stop] == operator_)
PointlessBrackets(&start, &stop);
if(start == stop) // only 1 thing to evaluate
{
SimpleEvaluate(result, start);
return;
}
// go through each operator in order of precedence
for(i=0; i<num_operators; i++)
{
// check backwards for the token. it has to be
// done backwards for left-to-right reading: eg so
// 5-3-2 is (5-3)-2 not 5-(3-2)
if (operators[i].direction==forward)
{
n = FindOperatorBackwards(start, stop, operators[i].string);
}
else
{
n = FindOperator(start, stop, operators[i].string);
}
if( n != -1)
{
// call the operator function and evaluate this chunk of tokens
(this->*operators[i].handler)(result, start, n, stop);
return;
}
}
if(TokenType[start] == function)
{
EvaluateFunction(result, start, stop);
return;
}
// error ?
{
FString tempstr;
for(i=start; i<=stop; i++) tempstr << Tokens[i] << ' ';
script_error("couldnt evaluate expression: %s\n",tempstr.GetChars());
}
}
//==========================================================================
//
// intercepts an error message and inserts script/line information
//
//==========================================================================
void FParser::ErrorMessage(FString msg)
{
int linenum = 0;
// find the line number
if(Rover >= Script->data && Rover <= Script->data+Script->len)
{
char *temp;
for(temp = Script->data; temp<LineStart; temp++)
if(*temp == '\n') linenum++; // count EOLs
}
//lineinfo.Format("Script %d, line %d: ", Script->scriptnum, linenum);
I_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
}
//==========================================================================
//
// throws an error message
//
//==========================================================================
void script_error(const char *s, ...)
{
FString composed;
va_list args;
va_start(args, s);
composed.VFormat(s, args);
throw CFsError(composed);
}
// EOF

View file

@ -0,0 +1,445 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// Preprocessor.
//
// The preprocessor must be called when the script is first loaded.
// It performs 2 functions:
// 1: blank out comments (which could be misinterpreted)
// 2: makes a list of all the sections held within {} braces
// 3: 'dry' runs the script: goes thru each statement and
// sets the types of all the DFsSection's in the script
// 4: Saves locations of all goto() labels
//
// the system of DFsSection's is pretty horrible really, but it works
// and its probably the only way i can think of of saving scripts
// half-way thru running
//
// By Simon Howard
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
/* includes ************************/
#include "t_script.h"
#include "i_system.h"
#include "w_wad.h"
#include "farchive.h"
//==========================================================================
//
// {} sections
//
// during preprocessing all of the {} sections
// are found. these are stored in a hash table
// according to their offset in the script.
// functions here deal with creating new sections
// and finding them from a given offset.
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsSection)
DECLARE_POINTER(next)
END_POINTERS
//==========================================================================
//
//
//
//==========================================================================
void DFsSection::Serialize(FArchive &ar)
{
Super::Serialize(ar);
ar << type << start_index << end_index << loop_index << next;
}
//==========================================================================
//
//
//
//==========================================================================
char *DFsScript::SectionStart(const DFsSection *sec)
{
return data + sec->start_index;
}
//==========================================================================
//
//
//
//==========================================================================
char *DFsScript::SectionEnd(const DFsSection *sec)
{
return data + sec->end_index;
}
//==========================================================================
//
//
//
//==========================================================================
char *DFsScript::SectionLoop(const DFsSection *sec)
{
return data + sec->loop_index;
}
//==========================================================================
//
//
//
//==========================================================================
void DFsScript::ClearSections()
{
for(int i=0;i<SECTIONSLOTS;i++)
{
DFsSection * var = sections[i];
while(var)
{
DFsSection *next = var->next;
var->Destroy();
var = next;
}
sections[i] = NULL;
}
}
//==========================================================================
//
// create section
//
//==========================================================================
DFsSection *DFsScript::NewSection(const char *brace)
{
int n = section_hash(brace);
DFsSection *newsec = new DFsSection;
newsec->start_index = MakeIndex(brace);
newsec->next = sections[n];
sections[n] = newsec;
GC::WriteBarrier(this, newsec);
return newsec;
}
//==========================================================================
//
// find a Section from the location of the starting { brace
//
//==========================================================================
DFsSection *DFsScript::FindSectionStart(const char *brace)
{
int n = section_hash(brace);
DFsSection *current = sections[n];
// use the hash table: check the appropriate hash chain
while(current)
{
if(SectionStart(current) == brace) return current;
current = current->next;
}
return NULL; // not found
}
//==========================================================================
//
// find a Section from the location of the closing } brace
//
//==========================================================================
DFsSection *DFsScript::FindSectionEnd(const char *brace)
{
int n;
// hash table is no use, they are hashed according to
// the offset of the starting brace
// we have to go through every entry to find from the
// ending brace
for(n=0; n<SECTIONSLOTS; n++) // check all sections in all chains
{
DFsSection *current = sections[n];
while(current)
{
if(SectionEnd(current) == brace) return current; // found it
current = current->next;
}
}
return NULL; // not found
}
//==========================================================================
//
// preproocessor main loop
//
// This works by recursion. when a { opening
// brace is found, another instance of the
// function is called for the data inside
// the {} section.
// At the same time, the sections are noted
// down and hashed. Goto() labels are noted
// down, and comments are blanked out
//
//==========================================================================
char *DFsScript::ProcessFindChar(char *datap, char find)
{
while(*datap)
{
if(*datap==find) return datap;
if(*datap=='\"') // found a quote: ignore stuff in it
{
datap++;
while(*datap && *datap != '\"')
{
// escape sequence ?
if(*datap=='\\') datap++;
datap++;
}
// error: end of script in a constant
if(!*datap) return NULL;
}
// comments: blank out
if(*datap=='/' && *(datap+1)=='*') // /* -- */ comment
{
while(*datap && (*datap != '*' || *(datap+1) != '/') )
{
*datap=' '; datap++;
}
if(*datap)
*datap = *(datap+1) = ' '; // blank the last bit
else
{
// script terminated in comment
script_error("script terminated inside comment\n");
}
}
if(*datap=='/' && *(datap+1)=='/') // // -- comment
{
while(*datap != '\n')
{
*datap=' '; datap++; // blank out
}
}
/********** labels ****************/
// labels are also found during the
// preprocessing. these are of the form
//
// label_name:
//
// and are used for the goto function.
// goto labels are stored as variables.
if(*datap==':' && scriptnum != -1) // not in global scripts
{
char *labelptr = datap-1;
while(!isop(*labelptr)) labelptr--;
FString labelname(labelptr+1, strcspn(labelptr+1, ":"));
if (labelname.Len() == 0)
{
Printf(PRINT_BOLD,"Script %d: ':' encountrered in incorrect position!\n",scriptnum);
}
DFsVariable *newlabel = NewVariable(labelname, svt_label);
newlabel->value.i = MakeIndex(labelptr);
}
if(*datap=='{') // { -- } sections: add 'em
{
DFsSection *newsec = NewSection(datap);
newsec->type = st_empty;
// find the ending } and save
char * theend = ProcessFindChar(datap+1, '}');
if(!theend)
{ // brace not found
// This is fatal because it will cause a crash later
// if the game isn't terminated.
I_Error("Script %d: section error: no ending brace\n", scriptnum);
}
newsec->end_index = MakeIndex(theend);
// continue from the end of the section
datap = theend;
}
datap++;
}
return NULL;
}
//==========================================================================
//
// second stage parsing
//
// second stage preprocessing considers the script
// in terms of tokens rather than as plain data.
//
// we 'dry' run the script: go thru each statement and
// collect types for Sections
//
// this is an important thing to do, it cannot be done
// at runtime for 2 reasons:
// 1. gotos() jumping inside loops will pass thru
// the end of the loop
// 2. savegames. loading a script saved inside a
// loop will let it pass thru the loop
//
// this is basically a cut-down version of the normal
// parsing loop.
//
//==========================================================================
void DFsScript::DryRunScript()
{
char *end = data + len;
char *rover = data;
// allocate space for the tokens
FParser parse(this);
try
{
while(rover < end && *rover)
{
rover = parse.GetTokens(rover);
if(!parse.NumTokens) continue;
if(parse.Section && parse.TokenType[0] == function)
{
if(!strcmp(parse.Tokens[0], "if"))
{
parse.Section->type = st_if;
continue;
}
else if(!strcmp(parse.Tokens[0], "elseif")) // haleyjd: SoM's else code
{
parse.Section->type = st_elseif;
continue;
}
else if(!strcmp(parse.Tokens[0], "else"))
{
parse.Section->type = st_else;
continue;
}
else if(!strcmp(parse.Tokens[0], "while") ||
!strcmp(parse.Tokens[0], "for"))
{
parse.Section->type = st_loop;
parse.Section->loop_index = MakeIndex(parse.LineStart);
continue;
}
}
}
}
catch (CFsError err)
{
parse.ErrorMessage(err.msg);
}
}
//==========================================================================
//
// main preprocess function
//
//==========================================================================
void DFsScript::Preprocess()
{
len = (int)strlen(data);
ProcessFindChar(data, 0); // fill in everything
DryRunScript();
}
//==========================================================================
//
// FraggleScript allows 'including' of other lumps.
// we divert input from the current script (normally
// levelscript) to a seperate lump. This of course
// first needs to be preprocessed to remove comments
// etc.
//
// parse an 'include' lump
//
//==========================================================================
void DFsScript::ParseInclude(char *lumpname)
{
int lumpnum;
char *lump;
if((lumpnum = Wads.CheckNumForName(lumpname)) == -1)
{
I_Error("include lump '%s' not found!\n", lumpname);
return;
}
int lumplen=Wads.LumpLength(lumpnum);
lump=new char[lumplen+10];
Wads.ReadLump(lumpnum,lump);
lump[lumplen]=0;
// preprocess the include
// we assume that it does not include sections or labels or
// other nasty things
ProcessFindChar(lump, 0);
// now parse the lump
FParser parse(this);
parse.Run(lump, lump, lump+lumplen);
// free the lump
delete[] lump;
}

View file

@ -0,0 +1,725 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
// Copyright(C) 2005-2008 Christoph Oelckers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// scripting.
//
// delayed scripts, running scripts, console cmds etc in here
// the interface between FraggleScript and the rest of the game
//
// By Simon Howard
//
// (completely redone and cleaned up in 2008 by Christoph Oelckers)
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
#include "t_script.h"
#include "p_lnspec.h"
#include "a_keys.h"
#include "d_player.h"
#include "p_spec.h"
#include "c_dispatch.h"
#include "i_system.h"
#include "doomerrors.h"
#include "doomstat.h"
#include "farchive.h"
//==========================================================================
//
// global variables
// These two are the last remaining ones:
// - The global script contains static data so it must be global
// - The trigger is referenced by a global variable. However, it is set
// each time a script is started so that's not a problem.
//
//==========================================================================
DFsScript *global_script;
AActor *trigger_obj;
//==========================================================================
//
//
//
//==========================================================================
#define DECLARE_16_POINTERS(v, i) \
DECLARE_POINTER(v[i]) \
DECLARE_POINTER(v[i+1]) \
DECLARE_POINTER(v[i+2]) \
DECLARE_POINTER(v[i+3]) \
DECLARE_POINTER(v[i+4]) \
DECLARE_POINTER(v[i+5]) \
DECLARE_POINTER(v[i+6]) \
DECLARE_POINTER(v[i+7]) \
DECLARE_POINTER(v[i+8]) \
DECLARE_POINTER(v[i+9]) \
DECLARE_POINTER(v[i+10]) \
DECLARE_POINTER(v[i+11]) \
DECLARE_POINTER(v[i+12]) \
DECLARE_POINTER(v[i+13]) \
DECLARE_POINTER(v[i+14]) \
DECLARE_POINTER(v[i+15]) \
//==========================================================================
//
//
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsScript)
DECLARE_POINTER(parent)
DECLARE_POINTER(trigger)
DECLARE_16_POINTERS(sections, 0)
DECLARE_POINTER(sections[16])
DECLARE_16_POINTERS(variables, 0)
DECLARE_16_POINTERS(children, 0)
DECLARE_16_POINTERS(children, 16)
DECLARE_16_POINTERS(children, 32)
DECLARE_16_POINTERS(children, 48)
DECLARE_16_POINTERS(children, 64)
DECLARE_16_POINTERS(children, 80)
DECLARE_16_POINTERS(children, 96)
DECLARE_16_POINTERS(children, 112)
DECLARE_16_POINTERS(children, 128)
DECLARE_16_POINTERS(children, 144)
DECLARE_16_POINTERS(children, 160)
DECLARE_16_POINTERS(children, 176)
DECLARE_16_POINTERS(children, 192)
DECLARE_16_POINTERS(children, 208)
DECLARE_16_POINTERS(children, 224)
DECLARE_16_POINTERS(children, 240)
DECLARE_POINTER(children[256])
END_POINTERS
//==========================================================================
//
//
//
//==========================================================================
void DFsScript::ClearChildren()
{
int j;
for(j=0;j<MAXSCRIPTS;j++) if (children[j])
{
children[j]->Destroy();
children[j]=NULL;
}
}
//==========================================================================
//
//
//
//==========================================================================
DFsScript::DFsScript()
{
int i;
for(i=0; i<SECTIONSLOTS; i++) sections[i] = NULL;
for(i=0; i<VARIABLESLOTS; i++) variables[i] = NULL;
for(i=0; i<MAXSCRIPTS; i++) children[i] = NULL;
data = NULL;
scriptnum = -1;
len = 0;
parent = NULL;
trigger = NULL;
lastiftrue = false;
}
//==========================================================================
//
//
//
//==========================================================================
void DFsScript::Destroy()
{
ClearVariables(true);
ClearSections();
ClearChildren();
parent = NULL;
if (data != NULL) delete [] data;
data = NULL;
parent = NULL;
trigger = NULL;
Super::Destroy();
}
//==========================================================================
//
//
//
//==========================================================================
void DFsScript::Serialize(FArchive &arc)
{
Super::Serialize(arc);
// don't save a reference to the global script
if (parent == global_script) parent = NULL;
arc << data << scriptnum << len << parent << trigger << lastiftrue;
for(int i=0; i< SECTIONSLOTS; i++) arc << sections[i];
for(int i=0; i< VARIABLESLOTS; i++) arc << variables[i];
for(int i=0; i< MAXSCRIPTS; i++) arc << children[i];
if (parent == NULL) parent = global_script;
}
//==========================================================================
//
// run_script
//
// the function called by t_script.c
//
//==========================================================================
void DFsScript::ParseScript(char *position)
{
if (position == NULL)
{
lastiftrue = false;
position = data;
}
// check for valid position
if(position < data || position > data+len)
{
Printf("script %d: trying to continue from point outside script!\n", scriptnum);
return;
}
trigger_obj = trigger; // set trigger
try
{
FParser parse(this);
parse.Run(position, data, data + len);
}
catch (CRecoverableError &err)
{
Printf ("%s\n", err.GetMessage());
}
// dont clear global vars!
if(scriptnum != -1) ClearVariables(); // free variables
// haleyjd
lastiftrue = false;
}
//==========================================================================
//
// Running Scripts
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DRunningScript)
DECLARE_POINTER(prev)
DECLARE_POINTER(next)
DECLARE_POINTER(trigger)
DECLARE_16_POINTERS(variables, 0)
END_POINTERS
//==========================================================================
//
//
//
//==========================================================================
DRunningScript::DRunningScript(AActor *trigger, DFsScript *owner, int index)
{
prev = next = NULL;
script = owner;
GC::WriteBarrier(this, script);
save_point = index;
wait_type = wt_none;
wait_data = 0;
this->trigger = trigger;
if (owner == NULL)
{
for(int i=0; i< VARIABLESLOTS; i++) variables[i] = NULL;
}
else
{
// save the script variables
for(int i=0; i<VARIABLESLOTS; i++)
{
variables[i] = owner->variables[i];
if (index == 0) // we are starting another Script:
{
// remove all the variables from the script variable list
// we only start with the basic labels
while(variables[i] && variables[i]->type != svt_label)
variables[i] = variables[i]->next;
}
else // a script is being halted
{
// remove all the variables from the script variable list
// to prevent them being removed when the script stops
while(owner->variables[i] && owner->variables[i]->type != svt_label)
owner->variables[i] = owner->variables[i]->next;
GC::WriteBarrier(owner, owner->variables[i]);
}
GC::WriteBarrier(this, variables[i]);
}
}
}
//==========================================================================
//
//
//
//==========================================================================
void DRunningScript::Destroy()
{
int i;
DFsVariable *current, *next;
for(i=0; i<VARIABLESLOTS; i++)
{
current = variables[i];
// go thru this chain
while(current)
{
next = current->next; // save for after freeing
current->Destroy();
current = next; // go to next in chain
}
variables[i] = NULL;
}
Super::Destroy();
}
//==========================================================================
//
//
//
//==========================================================================
void DRunningScript::Serialize(FArchive &arc)
{
Super::Serialize(arc);
arc << script << save_point << wait_type << wait_data << prev << next << trigger;
for(int i=0; i< VARIABLESLOTS; i++) arc << variables[i];
}
//==========================================================================
//
// The main thinker
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFraggleThinker)
DECLARE_POINTER(RunningScripts)
DECLARE_POINTER(LevelScript)
END_POINTERS
TObjPtr<DFraggleThinker> DFraggleThinker::ActiveThinker;
//==========================================================================
//
//
//
//==========================================================================
DFraggleThinker::DFraggleThinker()
: DThinker(STAT_SCRIPTS)
{
if (ActiveThinker)
{
I_Error ("Only one FraggleThinker is allowed to exist at a time.\nCheck your code.");
}
else
{
ActiveThinker = this;
RunningScripts = new DRunningScript;
LevelScript = new DFsScript;
LevelScript->parent = global_script;
GC::WriteBarrier(this, RunningScripts);
GC::WriteBarrier(this, LevelScript);
nocheckposition = false;
}
}
//==========================================================================
//
//
//
//==========================================================================
void DFraggleThinker::Destroy()
{
DRunningScript *p = RunningScripts;
while (p)
{
DRunningScript *q = p;
p = p->next;
q->prev = q->next = NULL;
q->Destroy();
}
RunningScripts = NULL;
LevelScript->Destroy();
LevelScript = NULL;
SpawnedThings.Clear();
ActiveThinker = NULL;
Super::Destroy();
}
//==========================================================================
//
//
//
//==========================================================================
void DFraggleThinker::Serialize(FArchive &arc)
{
Super::Serialize(arc);
arc << LevelScript << RunningScripts << SpawnedThings << nocheckposition;
}
//==========================================================================
//
// PAUSING SCRIPTS
//
//==========================================================================
bool DFraggleThinker::wait_finished(DRunningScript *script)
{
switch(script->wait_type)
{
case wt_none: return true; // uh? hehe
case wt_scriptwait: // waiting for script to finish
{
DRunningScript *current;
for(current = RunningScripts->next; current; current = current->next)
{
if(current == script) continue; // ignore this script
if(current->script->scriptnum == script->wait_data)
return false; // script still running
}
return true; // can continue now
}
case wt_delay: // just count down
{
return --script->wait_data <= 0;
}
case wt_tagwait:
{
int secnum = -1;
while ((secnum = P_FindSectorFromTag(script->wait_data, secnum)) >= 0)
{
sector_t *sec = &sectors[secnum];
if(sec->floordata || sec->ceilingdata || sec->lightingdata)
return false; // not finished
}
return true;
}
case wt_scriptwaitpre: // haleyjd - wait for script to start
{
DRunningScript *current;
for(current = RunningScripts->next; current; current=current->next)
{
if(current == script) continue; // ignore this script
if(current->script->scriptnum == script->wait_data)
return true; // script is now running
}
return false; // no running instances found
}
default: return true;
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
void DFraggleThinker::Tick()
{
DRunningScript *current, *next;
int i;
current = RunningScripts->next;
while(current)
{
if(wait_finished(current))
{
// copy out the script variables from the
// runningscript
for(i=0; i<VARIABLESLOTS; i++)
{
current->script->variables[i] = current->variables[i];
GC::WriteBarrier(current->script, current->variables[i]);
current->variables[i] = NULL;
}
current->script->trigger = current->trigger; // copy trigger
// unhook from chain
current->prev->next = current->next;
GC::WriteBarrier(current->prev, current->next);
if(current->next)
{
current->next->prev = current->prev;
GC::WriteBarrier(current->next, current->prev);
}
next = current->next; // save before freeing
// continue the script
current->script->ParseScript (current->script->data + current->save_point);
// free
current->Destroy();
}
else
next = current->next;
current = next; // continue to next in chain
}
}
//==========================================================================
//
// We have to mark the SpawnedThings array manually because it's not
// in the list of declared pointers.
//
//==========================================================================
size_t DFraggleThinker::PropagateMark()
{
for(unsigned i=0;i<SpawnedThings.Size();i++)
{
GC::Mark(SpawnedThings[i]);
}
return Super::PropagateMark();
}
//==========================================================================
//
// Again we have to handle the SpawnedThings array manually because
// it's not in the list of declared pointers.
//
//==========================================================================
size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld)
{
size_t changed = Super::PointerSubstitution(old, notOld);
for(unsigned i=0;i<SpawnedThings.Size();i++)
{
if (SpawnedThings[i] == static_cast<AActor*>(old))
{
SpawnedThings[i] = static_cast<AActor*>(notOld);
changed++;
}
}
return changed;
}
//==========================================================================
//
// Adds a running script to the list of running scripts
//
//==========================================================================
void DFraggleThinker::AddRunningScript(DRunningScript *runscr)
{
runscr->next = RunningScripts->next;
GC::WriteBarrier(runscr, RunningScripts->next);
runscr->prev = RunningScripts;
GC::WriteBarrier(runscr, RunningScripts);
runscr->prev->next = runscr;
GC::WriteBarrier(runscr->prev, runscr);
if(runscr->next)
{
runscr->next->prev = runscr;
GC::WriteBarrier(runscr->next, runscr);
}
}
//==========================================================================
//
//
//
//==========================================================================
void T_PreprocessScripts()
{
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
if (th)
{
// run the levelscript first
// get the other scripts
// levelscript started by player 0 'superplayer'
th->LevelScript->trigger = players[0].mo;
th->LevelScript->Preprocess();
th->LevelScript->ParseScript();
}
}
//==========================================================================
//
//
//
//==========================================================================
static bool RunScript(int snum, AActor * t_trigger)
{
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
if (th)
{
// [CO] It is far too dangerous to start the script right away.
// Better queue it for execution for the next time
// the runningscripts are checked.
if(snum < 0 || snum >= MAXSCRIPTS) return false;
DFsScript *script = th->LevelScript->children[snum];
if(!script) return false;
DRunningScript *runscr = new DRunningScript(t_trigger, script, 0);
// hook into chain at start
th->AddRunningScript(runscr);
return true;
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
static int LS_FS_Execute (line_t *ln, AActor *it, bool backSide,
int arg0, int arg1, int arg2, int arg3, int arg4)
// FS_Execute(script#,firstsideonly,lock,msgtype)
{
if (arg1 && ln && backSide) return false;
if (arg2!=0 && !P_CheckKeys(it, arg2, !!arg3)) return false;
return RunScript(arg0,it);
}
//==========================================================================
//
//
//
//==========================================================================
void FS_Close()
{
int i;
DFsVariable *current, *next;
// we have to actually delete the global variables if we don't want
// to get them reported as memory leaks.
for(i=0; i<VARIABLESLOTS; i++)
{
current = global_script->variables[i];
while(current)
{
next = current->next; // save for after freeing
current->ObjectFlags |= OF_YesReallyDelete;
delete current;
current = next; // go to next in chain
}
}
GC::DelSoftRoot(global_script);
global_script->ObjectFlags |= OF_YesReallyDelete;
delete global_script;
}
void T_Init()
{
void init_functions();
if (global_script == NULL)
{
// I'd rather link the special here than make another source file depend on FS!
LineSpecials[FS_Execute]=LS_FS_Execute;
global_script = new DFsScript;
GC::AddSoftRoot(global_script);
init_functions();
atterm(FS_Close);
}
}
//==========================================================================
//
//
//
//==========================================================================
CCMD(fpuke)
{
int argc = argv.argc();
if (argc < 2)
{
Printf (" fpuke <script>\n");
}
else
{
RunScript(atoi(argv[1]), players[consoleplayer].mo);
}
}

View file

@ -0,0 +1,698 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
// Copyright(C) 2002-2008 Christoph Oelckers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
#ifndef __T_SCRIPT_H__
#define __T_SCRIPT_H__
#include "p_setup.h"
#include "p_lnspec.h"
#include "m_fixed.h"
#include "actor.h"
#ifdef _MSC_VER
// This pragma saves 8kb of wasted code.
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class DRunningScript;
inline bool isop(int c)
{
return !( ( (c)<='Z' && (c)>='A') || ( (c)<='z' && (c)>='a') ||
( (c)<='9' && (c)>='0') || ( (c)=='_') );
}
//==========================================================================
//
//
//
//==========================================================================
enum
{
svt_string,
svt_int,
svt_mobj, // a map object
svt_function, // functions are stored as variables
svt_label, // labels for goto calls are variables
svt_const, // const
svt_fixed, // haleyjd: fixed-point int - 8-17 std
svt_pInt, // pointer to game int
svt_pMobj, // pointer to game mobj
svt_linespec, // line special (can be used as both function and constant)
};
//==========================================================================
//
//
//
//==========================================================================
struct svalue_t
{
int type;
FString string;
union
{
int i;
fixed_t f; // haleyjd: 8-17
AActor *mobj;
} value;
svalue_t()
{
type = svt_int;
value.i = 0;
}
svalue_t(const svalue_t & other)
{
type = other.type;
string = other.string;
value = other.value;
}
};
int intvalue(const svalue_t & v);
fixed_t fixedvalue(const svalue_t & v);
float floatvalue(const svalue_t & v);
const char *stringvalue(const svalue_t & v);
AActor *actorvalue(const svalue_t &svalue);
//==========================================================================
//
// varoius defines collected in a nicer manner
//
//==========================================================================
enum
{
VARIABLESLOTS = 16,
SECTIONSLOTS = 17,
T_MAXTOKENS = 256,
TOKENLENGTH = 128,
MAXARGS = 128,
MAXSCRIPTS = 257,
};
//==========================================================================
//
// One variable
//
//==========================================================================
struct FParser;
struct DFsVariable : public DObject
{
DECLARE_CLASS(DFsVariable, DObject)
HAS_OBJECT_POINTERS
public:
FString Name;
TObjPtr<DFsVariable> next; // for hashing
int type; // svt_string or svt_int: same as in svalue_t
FString string;
TObjPtr<AActor> actor;
union value_t
{
SDWORD i;
fixed_t fixed; // haleyjd: fixed-point
// the following are only used in the global script so we don't need to bother with them
// when serializing variables.
int *pI; // pointer to game int
AActor **pMobj; // pointer to game obj
void (FParser::*handler)(); // for functions
const FLineSpecial *ls;
} value;
public:
DFsVariable(const char *_name = "");
void GetValue(svalue_t &result);
void SetValue(const svalue_t &newvalue);
void Serialize(FArchive &ar);
};
//==========================================================================
//
// hash the variables for speed: this is the hashkey
//
//==========================================================================
inline int variable_hash(const char *n)
{
return
(n[0]? ( ( n[0] + n[1] +
(n[1] ? n[2] +
(n[2] ? n[3] : 0) : 0) ) % VARIABLESLOTS ) :0);
}
//==========================================================================
//
// Sections
//
//==========================================================================
enum // section types
{
st_empty, // empty {} braces
st_if,
st_elseif,
st_else,
st_loop,
};
struct DFsSection : public DObject
{
DECLARE_CLASS(DFsSection, DObject)
HAS_OBJECT_POINTERS
public:
int type;
int start_index;
int end_index;
int loop_index;
TObjPtr<DFsSection> next; // for hashing
DFsSection()
{
next = NULL;
}
void Serialize(FArchive &ar);
};
//==========================================================================
//
// Tokens
//
//==========================================================================
enum tokentype_t
{
name_, // a name, eg 'count1' or 'frag'
number,
operator_,
string_,
unset,
function // function name
};
enum // brace types: where current_section is a { or }
{
bracket_open,
bracket_close
};
//==========================================================================
//
// Errors
//
//==========================================================================
class CFsError
{
public:
// trying to throw strings crashes VC++ badly so we have to use a static buffer. :(
char msg[2048];
CFsError(const FString &in)
{
strncpy(msg, in, 2047);
msg[2047]=0;
}
};
// throw this object to regularly terminate a script's execution.
class CFsTerminator
{
int fill;
};
//==========================================================================
//
// Scripts
//
//==========================================================================
class DFsScript : public DObject
{
DECLARE_CLASS(DFsScript, DObject)
HAS_OBJECT_POINTERS
public:
// script data
char *data;
int scriptnum; // this script's number
int len;
// {} sections
TObjPtr<DFsSection> sections[SECTIONSLOTS];
// variables:
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
// ptr to the parent script
// the parent script is the script above this level
// eg. individual linetrigger scripts are children
// of the levelscript, which is a child of the
// global_script
TObjPtr<DFsScript> parent;
// haleyjd: 8-17
// child scripts.
// levelscript holds ptrs to all of the level's scripts
// here.
TObjPtr<DFsScript> children[MAXSCRIPTS];
TObjPtr<AActor> trigger; // object which triggered this script
bool lastiftrue; // haleyjd: whether last "if" statement was
// true or false
DFsScript();
void Destroy();
void Serialize(FArchive &ar);
DFsVariable *NewVariable(const char *name, int vtype);
void NewFunction(const char *name, void (FParser::*handler)());
DFsVariable *VariableForName(const char *name);
DFsVariable *FindVariable(const char *name);
void ClearVariables(bool complete= false);
DFsVariable *NewLabel(char *labelptr);
char *LabelValue(const svalue_t &v);
char *SectionStart(const DFsSection *sec);
char *SectionEnd(const DFsSection *sec);
char *SectionLoop(const DFsSection *sec);
void ClearSections();
void ClearChildren();
int MakeIndex(const char *p) { return int(p-data); }
// preprocessor
int section_hash(const char *b) { return MakeIndex(b) % SECTIONSLOTS; }
DFsSection *NewSection(const char *brace);
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 ParseData(char *rover, char *data, char *end);
};
//==========================================================================
//
// The script parser
//
//==========================================================================
struct FParser
{
struct operator_t
{
const char *string;
void (FParser::*handler)(svalue_t &, int, int, int); // left, mid, right
int direction;
};
enum
{
forward,
backward
};
static operator_t operators[];
static int num_operators;
char *LineStart;
char *Rover;
char *Tokens[T_MAXTOKENS];
tokentype_t TokenType[T_MAXTOKENS];
int NumTokens;
DFsScript *Script; // the current script
DFsSection *Section;
DFsSection *PrevSection;
int BraceType;
int t_argc; // number of arguments
svalue_t *t_argv; // arguments
svalue_t t_return; // returned value
FString t_func; // name of current function
FParser(DFsScript *scr)
{
LineStart = NULL;
Rover = NULL;
Tokens[0] = new char[scr->len+32]; // 32 for safety. FS seems to need a few bytes more than the script's actual length.
NumTokens = 0;
Script = scr;
Section = PrevSection = NULL;
BraceType = 0;
}
~FParser()
{
if (Tokens[0]) delete [] Tokens[0];
}
void NextToken();
char *GetTokens(char *s);
void PrintTokens();
void ErrorMessage(FString msg);
void Run(char *rover, char *data, char *end);
void RunStatement();
int FindOperator(int start, int stop, const char *value);
int FindOperatorBackwards(int start, int stop, const char *value);
void SimpleEvaluate(svalue_t &, int n);
void PointlessBrackets(int *start, int *stop);
void EvaluateExpression(svalue_t &, int start, int stop);
void EvaluateFunction(svalue_t &, int start, int stop);
void OPequals(svalue_t &, int, int, int); // =
void OPplus(svalue_t &, int, int, int); // +
void OPminus(svalue_t &, int, int, int); // -
void OPmultiply(svalue_t &, int, int, int); // *
void OPdivide(svalue_t &, int, int, int); // /
void OPremainder(svalue_t &, int, int, int); // %
void OPor(svalue_t &, int, int, int); // ||
void OPand(svalue_t &, int, int, int); // &&
void OPnot(svalue_t &, int, int, int); // !
void OPor_bin(svalue_t &, int, int, int); // |
void OPand_bin(svalue_t &, int, int, int); // &
void OPnot_bin(svalue_t &, int, int, int); // ~
void OPcmp(svalue_t &, int, int, int); // ==
void OPnotcmp(svalue_t &, int, int, int); // !=
void OPlessthan(svalue_t &, int, int, int); // <
void OPgreaterthan(svalue_t &, int, int, int); // >
void OPincrement(svalue_t &, int, int, int); // ++
void OPdecrement(svalue_t &, int, int, int); // --
void OPstructure(svalue_t &, int, int, int); // in t_vari.c
void OPlessthanorequal(svalue_t &, int, int, int); // <=
void OPgreaterthanorequal(svalue_t &, int, int, int); // >=
void spec_brace();
bool spec_if();
bool spec_elseif(bool lastif);
void spec_else(bool lastif);
void spec_for();
void spec_while();
void CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop);
void ParseVarLine(int newvar_type, DFsScript *newvar_script, int start);
bool spec_variable();
void spec_script();
DFsSection *looping_section();
FString GetFormatString(int startarg);
bool CheckArgs(int cnt);
void SF_Print();
void SF_Rnd();
void SF_Continue();
void SF_Break();
void SF_Goto();
void SF_Return();
void SF_Include();
void SF_Input();
void SF_Beep();
void SF_Clock();
void SF_ExitLevel();
void SF_Tip();
void SF_TimedTip();
void SF_PlayerTip();
void SF_Message();
void SF_PlayerMsg();
void SF_PlayerInGame();
void SF_PlayerName();
void SF_PlayerObj();
void SF_StartScript(); // FPUKE needs to access this
void SF_ScriptRunning();
void SF_Wait();
void SF_TagWait();
void SF_ScriptWait();
void SF_ScriptWaitPre(); // haleyjd: new wait types
void SF_Player();
void SF_Spawn();
void SF_RemoveObj();
void SF_KillObj();
void SF_ObjX();
void SF_ObjY();
void SF_ObjZ();
void SF_ObjAngle();
void SF_Teleport();
void SF_SilentTeleport();
void SF_DamageObj();
void SF_ObjSector();
void SF_ObjHealth();
void SF_ObjFlag();
void SF_PushThing();
void SF_ReactionTime();
void SF_MobjTarget();
void SF_MobjMomx();
void SF_MobjMomy();
void SF_MobjMomz();
void SF_PointToAngle();
void SF_PointToDist();
void SF_SetCamera();
void SF_ClearCamera();
void SF_StartSound();
void SF_StartSectorSound();
void SF_FloorHeight();
void SF_MoveFloor();
void SF_CeilingHeight();
void SF_MoveCeiling();
void SF_LightLevel();
void SF_FadeLight();
void SF_FloorTexture();
void SF_SectorColormap();
void SF_CeilingTexture();
void SF_ChangeHubLevel();
void SF_StartSkill();
void SF_OpenDoor();
void SF_CloseDoor();
void SF_RunCommand();
void SF_LineTrigger();
void SF_ChangeMusic();
void SF_SetLineBlocking();
void SF_SetLineMonsterBlocking();
void SF_SetLineTexture();
void SF_Max();
void SF_Min();
void SF_Abs();
void SF_Gameskill();
void SF_Gamemode();
void SF_IsPlayerObj();
void SF_PlayerKeys();
void SF_PlayerAmmo();
void SF_MaxPlayerAmmo();
void SF_PlayerWeapon();
void SF_PlayerSelectedWeapon();
void SF_GiveInventory();
void SF_TakeInventory();
void SF_CheckInventory();
void SF_SetWeapon();
void SF_MoveCamera();
void SF_ObjAwaken();
void SF_AmbientSound();
void SF_ExitSecret();
void SF_MobjValue();
void SF_StringValue();
void SF_IntValue();
void SF_FixedValue();
void SF_SpawnExplosion();
void SF_RadiusAttack();
void SF_SetObjPosition();
void SF_TestLocation();
void SF_HealObj(); //no pain sound
void SF_ObjDead();
void SF_SpawnMissile();
void SF_MapThingNumExist();
void SF_MapThings();
void SF_ObjState();
void SF_LineFlag();
void SF_PlayerAddFrag();
void SF_SkinColor();
void SF_PlayDemo();
void SF_CheckCVar();
void SF_Resurrect();
void SF_LineAttack();
void SF_ObjType();
void SF_Sin();
void SF_ASin();
void SF_Cos();
void SF_ACos();
void SF_Tan();
void SF_ATan();
void SF_Exp();
void SF_Log();
void SF_Sqrt();
void SF_Floor();
void SF_Pow();
void SF_NewHUPic();
void SF_DeleteHUPic();
void SF_ModifyHUPic();
void SF_SetHUPicDisplay();
void SF_SetCorona();
void SF_Ls();
void SF_LevelNum();
void SF_MobjRadius();
void SF_MobjHeight();
void SF_ThingCount();
void SF_SetColor();
void SF_SpawnShot2();
void SF_KillInSector();
void SF_SectorType();
void SF_SetLineTrigger();
void SF_ChangeTag();
void SF_WallGlow();
void RunLineSpecial(const FLineSpecial *);
DRunningScript *SaveCurrentScript();
};
//==========================================================================
//
// Running scripts
//
//==========================================================================
enum waittype_e
{
wt_none, // not waiting
wt_delay, // wait for a set amount of time
wt_tagwait, // wait for sector to stop moving
wt_scriptwait, // wait for script to finish
wt_scriptwaitpre, // haleyjd - wait for script to start
};
class DRunningScript : public DObject
{
DECLARE_CLASS(DRunningScript, DObject)
HAS_OBJECT_POINTERS
public:
DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
void Destroy();
void Serialize(FArchive &arc);
TObjPtr<DFsScript> script;
// where we are
int save_point;
int wait_type;
int wait_data; // data for wait: tagnum, counter, script number etc
// saved variables
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
TObjPtr<DRunningScript> prev, next; // for chain
TObjPtr<AActor> trigger;
};
//-----------------------------------------------------------------------------
//
// This thinker eliminates the need to call the Fragglescript functions from the main code
//
//-----------------------------------------------------------------------------
class DFraggleThinker : public DThinker
{
DECLARE_CLASS(DFraggleThinker, DThinker)
HAS_OBJECT_POINTERS
public:
TObjPtr<DFsScript> LevelScript;
TObjPtr<DRunningScript> RunningScripts;
TArray<TObjPtr<AActor> > SpawnedThings;
bool nocheckposition;
DFraggleThinker();
void Destroy();
void Serialize(FArchive & arc);
void Tick();
size_t PropagateMark();
size_t PointerSubstitution (DObject *old, DObject *notOld);
bool wait_finished(DRunningScript *script);
void AddRunningScript(DRunningScript *runscr);
static TObjPtr<DFraggleThinker> ActiveThinker;
};
//-----------------------------------------------------------------------------
//
// Global stuff
//
//-----------------------------------------------------------------------------
#include "t_fs.h"
void script_error(const char *s, ...);
void FS_EmulateCmd(char * string);
extern AActor *trigger_obj;
extern DFsScript *global_script;
#endif

View file

@ -0,0 +1,628 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// 'Special' stuff
//
// if(), int statements, etc.
//
// By Simon Howard
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
#include "t_script.h"
//==========================================================================
//
// ending brace found in parsing
//
//==========================================================================
void FParser::spec_brace()
{
if(BraceType != bracket_close) // only deal with closing } braces
return;
// if() requires nothing to be done
if(Section->type == st_if || Section->type == st_else)
return;
// if a loop, jump back to the start of the loop
if(Section->type == st_loop)
{
Rover = Script->SectionLoop(Section);
return;
}
}
//==========================================================================
//
// 'if' statement -- haleyjd: changed to bool for else/elseif
//
//==========================================================================
bool FParser::spec_if()
{
int endtoken;
svalue_t eval;
if((endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
{
script_error("parse error in if statement\n");
return false;
}
// 2 to skip past the 'if' and '('
EvaluateExpression(eval, 2, endtoken-1);
bool ifresult = !!intvalue(eval);
if(Section && BraceType == bracket_open && endtoken == NumTokens-1)
{
// {} braces
if(!ifresult) // skip to end of section
Rover = Script->SectionEnd(Section) + 1;
}
else if(ifresult) // if() without {} braces
{
// nothing to do ?
if(endtoken != NumTokens-1)
EvaluateExpression(eval, endtoken+1, NumTokens-1);
}
return ifresult;
}
//==========================================================================
//
// 'elseif' statement
//
//==========================================================================
bool FParser::spec_elseif(bool lastif)
{
int endtoken;
svalue_t eval;
if((endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
{
script_error("parse error in elseif statement\n");
return false;
}
if(lastif)
{
Rover = Script->SectionEnd(Section) + 1;
return true;
}
// 2 to skip past the 'elseif' and '('
EvaluateExpression(eval, 2, endtoken-1);
bool ifresult = !!intvalue(eval);
if(Section && BraceType == bracket_open
&& endtoken == NumTokens-1)
{
// {} braces
if(!ifresult) // skip to end of section
Rover = Script->SectionEnd(Section) + 1;
}
else if(ifresult) // elseif() without {} braces
{
// nothing to do ?
if(endtoken != NumTokens-1)
EvaluateExpression(eval, endtoken+1, NumTokens-1);
}
return ifresult;
}
//==========================================================================
//
// 'else' statement
//
//==========================================================================
void FParser::spec_else(bool lastif)
{
if(lastif)
Rover = Script->SectionEnd(Section) + 1;
}
//==========================================================================
//
// while() loop
//
//==========================================================================
void FParser::spec_while()
{
int endtoken;
svalue_t eval;
if(!Section)
{
script_error("no {} section given for loop\n");
return;
}
if( (endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
{
script_error("parse error in loop statement\n");
return;
}
EvaluateExpression(eval, 2, endtoken-1);
// skip if no longer valid
if(!intvalue(eval)) Rover = Script->SectionEnd(Section) + 1;
}
//==========================================================================
//
// for() loop
//
//==========================================================================
void FParser::spec_for()
{
svalue_t eval;
int start;
int comma1, comma2; // token numbers of the seperating commas
if(!Section)
{
script_error("need {} delimiters for for()\n");
return;
}
// is a valid section
start = 2; // skip "for" and "(": start on third token(2)
// find the seperating commas first
if( (comma1 = FindOperator(start, NumTokens-1, ",")) == -1
|| (comma2 = FindOperator(comma1+1, NumTokens-1, ",")) == -1)
{
script_error("incorrect arguments to for()\n"); // haleyjd:
return; // said if()
}
// are we looping back from a previous loop?
if(Section == PrevSection)
{
// do the loop 'action' (third argument)
EvaluateExpression(eval, comma2+1, NumTokens-2);
// check if we should run the loop again (second argument)
EvaluateExpression(eval, comma1+1, comma2-1);
if(!intvalue(eval))
{
// stop looping
Rover = Script->SectionEnd(Section) + 1;
}
}
else
{
// first time: starting the loop
// just evaluate the starting expression (first arg)
EvaluateExpression(eval, start, comma1-1);
}
}
//==========================================================================
//
// Variable Creation
//
// called for each individual variable in a statement
//
//==========================================================================
void FParser::CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop)
{
if(TokenType[start] != name_)
{
script_error("invalid name for variable: '%s'\n", Tokens[start]);
return;
}
// check if already exists, only checking
// the current script
if(newvar_script->VariableForName (Tokens[start]))
{
// In Eternity this was fatal and in Legacy it was ignored
// So make this a warning.
Printf("FS: redefined symbol: '%s'\n", Tokens[start]);
return; // already one
}
// haleyjd: disallow mobj references in the hub script --
// they cause dangerous dangling references and are of no
// potential use
if(newvar_script != Script && newvar_type == svt_mobj)
{
script_error("cannot create mobj reference in hub script\n");
return;
}
newvar_script->NewVariable (Tokens[start], newvar_type);
if(stop != start)
{
svalue_t scratch;
EvaluateExpression(scratch, start, stop);
}
}
//==========================================================================
//
// divide a statement (without type prefix) into individual
// variables to create them using create_variable
//
//==========================================================================
void FParser::ParseVarLine(int newvar_type, DFsScript *newvar_script, int start)
{
int starttoken = start, endtoken;
while(1)
{
endtoken = FindOperator(starttoken, NumTokens-1, ",");
if(endtoken == -1) break;
CreateVariable(newvar_type, newvar_script, starttoken, endtoken-1);
starttoken = endtoken+1; //start next after end of this one
}
// dont forget the last one
CreateVariable(newvar_type, newvar_script, starttoken, NumTokens-1);
}
//==========================================================================
//
// variable definition
//
//==========================================================================
bool FParser::spec_variable()
{
int start = 0;
int newvar_type = -1; // init to -1
DFsScript *newvar_script = Script; // use current script
// check for 'hub' keyword to make a hub variable
if(!strcmp(Tokens[start], "hub"))
{
// The hub script doesn't work so it's probably safest to store the variable locally.
//newvar_script = &hub_script;
start++; // skip first token
}
// now find variable type
if(!strcmp(Tokens[start], "const"))
{
newvar_type = svt_const;
start++;
}
else if(!strcmp(Tokens[start], "string"))
{
newvar_type = svt_string;
start++;
}
else if(!strcmp(Tokens[start], "int"))
{
newvar_type = svt_int;
start++;
}
else if(!strcmp(Tokens[start], "mobj"))
{
newvar_type = svt_mobj;
start++;
}
else if(!strcmp(Tokens[start], "fixed") || !strcmp(Tokens[start], "float"))
{
newvar_type = svt_fixed;
start++;
}
else if(!strcmp(Tokens[start], "script")) // check for script creation
{
spec_script();
return true; // used tokens
}
// are we creating a new variable?
if(newvar_type != -1)
{
ParseVarLine(newvar_type, newvar_script, start);
return true; // used tokens
}
return false; // not used: try normal parsing
}
//==========================================================================
//
// ADD SCRIPT
//
// when the level is first loaded, all the
// scripts are simply stored in the levelscript.
// before the level starts, this script is
// preprocessed and run like any other. This allows
// the individual scripts to be derived from the
// levelscript. When the interpreter detects the
// 'script' keyword this function is called
//
//==========================================================================
void FParser::spec_script()
{
int scriptnum;
int datasize;
DFsScript *newscript;
scriptnum = 0;
if(!Section)
{
script_error("need seperators for newscript\n");
return;
}
// presume that the first token is "newscript"
if(NumTokens < 2)
{
script_error("need newscript number\n");
return;
}
svalue_t result;
EvaluateExpression(result, 1, NumTokens-1);
scriptnum = intvalue(result);
if(scriptnum < 0)
{
script_error("invalid newscript number\n");
return;
}
newscript = new DFsScript;
// add to scripts list of parent
Script->children[scriptnum] = newscript;
GC::WriteBarrier(Script, newscript);
// copy newscript data
// workout newscript size: -2 to ignore { and }
datasize = (Section->end_index - Section->start_index - 2);
// alloc extra 10 for safety
newscript->data = (char *)malloc(datasize+10);
// copy from parent newscript (levelscript)
// ignore first char which is {
memcpy(newscript->data, Script->SectionStart(Section) + 1, datasize);
// tack on a 0 to end the string
newscript->data[datasize] = '\0';
newscript->scriptnum = scriptnum;
newscript->parent = Script; // remember parent
// preprocess the newscript now
newscript->Preprocess();
// we dont want to run the newscript, only add it
// jump past the newscript in parsing
Rover = Script->SectionEnd(Section) + 1;
}
//==========================================================================
//
// evaluate_function: once parse.c is pretty
// sure it has a function to run it calls
// this. evaluate_function makes sure that
// it is a function call first, then evaluates all
// the arguments given to the function.
// these are built into an argc/argv-style
// list. the function 'handler' is then called.
//
//==========================================================================
void FParser::EvaluateFunction(svalue_t &result, int start, int stop)
{
DFsVariable *func = NULL;
int startpoint, endpoint;
// the arguments need to be built locally in case of
// function returns as function arguments eg
// print("here is a random number: ", rnd() );
int argc;
svalue_t argv[MAXARGS];
if(TokenType[start] != function || TokenType[stop] != operator_
|| Tokens[stop][0] != ')' )
{
script_error("misplaced closing paren\n");
}
// all the functions are stored in the global script
else if( !(func = global_script->VariableForName (Tokens[start])) )
{
script_error("no such function: '%s'\n",Tokens[start]);
}
else if(func->type != svt_function && func->type != svt_linespec)
{
script_error("'%s' not a function\n", Tokens[start]);
}
// build the argument list
// use a C command-line style system rather than
// a system using a fixed length list
argc = 0;
endpoint = start + 2; // ignore the function name and first bracket
while(endpoint < stop)
{
startpoint = endpoint;
endpoint = FindOperator(startpoint, stop-1, ",");
// check for -1: no more ','s
if(endpoint == -1)
{ // evaluate the last expression
endpoint = stop;
}
if(endpoint-1 < startpoint)
break;
EvaluateExpression(argv[argc], startpoint, endpoint-1);
endpoint++; // skip the ','
argc++;
}
// store the arguments in the global arglist
t_argc = argc;
t_argv = argv;
// haleyjd: return values can propagate to void functions, so
// t_return needs to be cleared now
t_return.type = svt_int;
t_return.value.i = 0;
// now run the function
if (func->type == svt_function)
{
(this->*func->value.handler)();
}
else
{
RunLineSpecial(func->value.ls);
}
// return the returned value
result = t_return;
}
//==========================================================================
//
// structure dot (.) operator
// there are not really any structs in FraggleScript, it's
// just a different way of calling a function that looks
// nicer. ie
// a.b() = a.b = b(a)
// a.b(c) = b(a,c)
//
// this function is just based on the one above
//
//==========================================================================
void FParser::OPstructure(svalue_t &result, int start, int n, int stop)
{
DFsVariable *func = NULL;
// the arguments need to be built locally in case of
// function returns as function arguments eg
// print("here is a random number: ", rnd() );
int argc;
svalue_t argv[MAXARGS];
// all the functions are stored in the global script
if( !(func = global_script->VariableForName (Tokens[n+1])) )
{
script_error("no such function: '%s'\n",Tokens[n+1]);
}
else if(func->type != svt_function)
{
script_error("'%s' not a function\n", Tokens[n+1]);
}
// build the argument list
// add the left part as first arg
EvaluateExpression(argv[0], start, n-1);
argc = 1; // start on second argv
if(stop != n+1) // can be a.b not a.b()
{
int startpoint, endpoint;
// ignore the function name and first bracket
endpoint = n + 3;
while(endpoint < stop)
{
startpoint = endpoint;
endpoint = FindOperator(startpoint, stop-1, ",");
// check for -1: no more ','s
if(endpoint == -1)
{ // evaluate the last expression
endpoint = stop;
}
if(endpoint-1 < startpoint)
break;
EvaluateExpression(argv[argc], startpoint, endpoint-1);
endpoint++; // skip the ','
argc++;
}
}
// store the arguments in the global arglist
t_argc = argc;
t_argv = argv;
t_func = func->Name;
// haleyjd: return values can propagate to void functions, so
// t_return needs to be cleared now
t_return.type = svt_int;
t_return.value.i = 0;
// now run the function
(this->*func->value.handler)();
// return the returned value
result = t_return;
}

View file

@ -0,0 +1,437 @@
// Emacs style mode select -*- C++ -*-
//----------------------------------------------------------------------------
//
// Copyright(C) 2000 Simon Howard
// Copyright(C) 2002-2008 Christoph Oelckers
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//--------------------------------------------------------------------------
//
// Variables.
//
// Variable code: create new variables, look up variables, get value,
// set value
//
// variables are stored inside the individual scripts, to allow for
// 'local' and 'global' variables. This way, individual scripts cannot
// access variables in other scripts. However, 'global' variables can
// be made which can be accessed by all scripts. These are stored inside
// a dedicated DFsScript which exists only to hold all of these global
// variables.
//
// functions are also stored as variables, these are kept in the global
// script so they can be accessed by all scripts. function variables
// cannot be set or changed inside the scripts themselves.
//
//---------------------------------------------------------------------------
//
// FraggleScript is from SMMU which is under the GPL. Technically,
// therefore, combining the FraggleScript code with the non-free
// ZDoom code is a violation of the GPL.
//
// As this may be a problem for you, I hereby grant an exception to my
// copyright on the SMMU source (including FraggleScript). You may use
// any code from SMMU in (G)ZDoom, provided that:
//
// * For any binary release of the port, the source code is also made
// available.
// * The copyright notice is kept on any file containing my code.
//
//
#include "t_script.h"
#include "a_pickups.h"
#include "farchive.h"
//==========================================================================
//
//
//
//==========================================================================
int intvalue(const svalue_t &v)
{
return (v.type == svt_string ? atoi(v.string) :
v.type == svt_fixed ? (int)(v.value.f / FRACUNIT) :
v.type == svt_mobj ? -1 : v.value.i );
}
//==========================================================================
//
//
//
//==========================================================================
fixed_t fixedvalue(const svalue_t &v)
{
return (v.type == svt_fixed ? v.value.f :
v.type == svt_string ? (fixed_t)(atof(v.string) * FRACUNIT) :
v.type == svt_mobj ? -1*FRACUNIT : v.value.i * FRACUNIT );
}
//==========================================================================
//
//
//
//==========================================================================
float floatvalue(const svalue_t &v)
{
return (float)( (v.type == svt_string ? atof(v.string) :
v.type == svt_fixed ? (float)(v.value.f / (float)FRACUNIT) :
v.type == svt_mobj ? -1.f : (float)v.value.i ));
}
//==========================================================================
//
// sf: string value of an svalue_t
//
//==========================================================================
const char *stringvalue(const svalue_t & v)
{
static char buffer[256];
switch(v.type)
{
case svt_string:
return v.string;
case svt_mobj:
// return the class name
return (const char *)v.value.mobj->GetClass()->TypeName;
case svt_fixed:
{
double val = ((double)v.value.f) / FRACUNIT;
mysnprintf(buffer, countof(buffer), "%g", val);
return buffer;
}
case svt_int:
default:
mysnprintf(buffer, countof(buffer), "%i", v.value.i);
return buffer;
}
}
//==========================================================================
//
//
//==========================================================================
AActor* actorvalue(const svalue_t &svalue)
{
int intval;
if(svalue.type == svt_mobj)
{
// Inventory items in the player's inventory have to be considered non-present.
if (svalue.value.mobj != NULL &&
svalue.value.mobj->IsKindOf(RUNTIME_CLASS(AInventory)) &&
static_cast<AInventory*>(svalue.value.mobj)->Owner != NULL)
{
return NULL;
}
return svalue.value.mobj;
}
else
{
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
// this requires some creativity. We use the intvalue
// as the thing number of a thing in the level.
intval = intvalue(svalue);
if(intval < 0 || intval >= (int)SpawnedThings.Size())
{
return NULL;
}
// Inventory items in the player's inventory have to be considered non-present.
if (SpawnedThings[intval] != NULL &&
SpawnedThings[intval]->IsKindOf(RUNTIME_CLASS(AInventory)) &&
barrier_cast<AInventory*>(SpawnedThings[intval])->Owner != NULL)
{
return NULL;
}
return SpawnedThings[intval];
}
}
//==========================================================================
//
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsVariable)
DECLARE_POINTER (next)
DECLARE_POINTER (actor)
END_POINTERS
//==========================================================================
//
//
//==========================================================================
DFsVariable::DFsVariable(const char * _name)
{
Name=_name;
type=svt_int;
actor = NULL;
value.i=0;
next=NULL;
}
//==========================================================================
//
// returns an svalue_t holding the current
// value of a particular variable.
//
//==========================================================================
void DFsVariable::GetValue(svalue_t &returnvar)
{
switch (type)
{
case svt_pInt:
returnvar.type = svt_int;
returnvar.value.i = *value.pI;
break;
case svt_pMobj:
returnvar.type = svt_mobj;
returnvar.value.mobj = *value.pMobj;
break;
case svt_mobj:
returnvar.type = type;
returnvar.value.mobj = actor;
break;
case svt_linespec:
returnvar.type = svt_int;
returnvar.value.i = value.ls->number;
break;
case svt_string:
returnvar.type = type;
returnvar.string = string;
break;
default:
// copy the value (also handles fixed)
returnvar.type = type;
returnvar.value.i = value.i;
break;
}
}
//==========================================================================
//
// set a variable to a value from an svalue_t
//
//==========================================================================
void DFsVariable::SetValue(const svalue_t &newvalue)
{
if(type == svt_const)
{
// const adapts to the value it is set to
type = newvalue.type;
}
switch (type)
{
case svt_int:
value.i = intvalue(newvalue);
break;
case svt_string:
if (newvalue.type == svt_string)
{
string = newvalue.string;
}
else
{
string = stringvalue(newvalue);
}
break;
case svt_fixed:
value.fixed = fixedvalue(newvalue);
break;
case svt_mobj:
actor = actorvalue(newvalue);
break;
case svt_pInt:
*value.pI = intvalue(newvalue);
break;
case svt_pMobj:
*value.pMobj = actorvalue(newvalue);
break;
case svt_function:
script_error("attempt to set function to a value\n");
break;
default:
script_error("invalid variable type\n");
break;
}
}
//==========================================================================
//
// Archive one script variable
//
//==========================================================================
void DFsVariable::Serialize(FArchive & ar)
{
Super::Serialize(ar);
ar << Name << type << string << actor << value.i << next;
}
//==========================================================================
//
// From here: variable related functions inside DFsScript
//
//==========================================================================
//==========================================================================
//
// create a new variable in a particular script.
// returns a pointer to the new variable.
//
//==========================================================================
DFsVariable *DFsScript::NewVariable(const char *name, int vtype)
{
DFsVariable *newvar = new DFsVariable(name);
newvar->type = vtype;
int n = variable_hash(name);
newvar->next = variables[n];
variables[n] = newvar;
GC::WriteBarrier(this, newvar);
return newvar;
}
void DFsScript::NewFunction(const char *name, void (FParser::*handler)() )
{
NewVariable (name, svt_function)->value.handler = handler;
}
//==========================================================================
//
// search a particular script for a variable, which
// is returned if it exists
//
//==========================================================================
DFsVariable *DFsScript::VariableForName(const char *name)
{
int n = variable_hash(name);
DFsVariable *current = variables[n];
while(current)
{
if(!strcmp(name, current->Name)) // found it?
return current;
current = current->next; // check next in chain
}
return NULL;
}
//==========================================================================
//
// find_variable checks through the current script, level script
// and global script to try to find the variable of the name wanted
//
//==========================================================================
DFsVariable *DFsScript::FindVariable(const char *name)
{
DFsVariable *var;
DFsScript *current = this;
while(current)
{
// check this script
if ((var = current->VariableForName(name)))
return var;
current = current->parent; // try the parent of this one
}
return NULL; // no variable
}
//==========================================================================
//
// free all the variables in a given script
//
//==========================================================================
void DFsScript::ClearVariables(bool complete)
{
int i;
DFsVariable *current, *next;
for(i=0; i<VARIABLESLOTS; i++)
{
current = variables[i];
// go thru this chain
while(current)
{
// labels are added before variables, during
// preprocessing, so will be at the end of the chain
// we can be sure there are no more variables to free
if(current->type == svt_label && !complete) break;
next = current->next; // save for after freeing
current->Destroy();
current = next; // go to next in chain
}
// start of labels or NULL
variables[i] = current;
}
}
//==========================================================================
//
//
//
//==========================================================================
char *DFsScript::LabelValue(const svalue_t &v)
{
if (v.type == svt_label) return data + v.value.i;
else return NULL;
}

View file

@ -142,6 +142,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
}
// [GZ] Calculates when the projectile will have reached destination
spit->special2 += level.maptime;
spit->flags6 |= MF6_BOSSCUBE;
}
if (!isdefault)

View file

@ -13,6 +13,7 @@
#include "a_specialspot.h"
#include "templates.h"
#include "m_bbox.h"
#include "farchive.h"
// Include all the other Doom stuff here to reduce compile time
#include "a_arachnotron.cpp"

View file

@ -586,7 +586,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
damage += (pr_bfgspray() & 7) + 1;
thingToHit = linetarget;
P_DamageMobj (thingToHit, self->target, self->target, damage, NAME_BFGSplash);
P_DamageMobj (thingToHit, self->target, self->target, damage, spray->DamageType);
P_TraceBleed (damage, thingToHit, self->target);
}
}

View file

@ -22,11 +22,18 @@ static const PClass *GetSpawnType(DECLARE_PARAMINFO)
}
enum PA_Flags
{
PAF_NOSKULLATTACK = 1,
PAF_AIMFACING = 2,
PAF_NOTARGET = 4,
};
//
// A_PainShootSkull
// Spawn a lost soul and launch it at the target
//
void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype)
void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int flags = 0, int limit = -1)
{
fixed_t x, y, z;
@ -50,11 +57,14 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype)
}
// [RH] make this optional
if (i_compatflags & COMPATF_LIMITPAIN)
if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN))
limit = 21;
if (limit)
{
// count total number of skulls currently on the level
// if there are already 21 skulls on the level, don't spit another one
int count = 21;
int count = limit;
FThinkerIterator iterator (spawntype);
DThinker *othink;
@ -124,9 +134,10 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype)
}
// [RH] Lost souls hate the same things as their pain elementals
other->CopyFriendliness (self, true);
other->CopyFriendliness (self, !(flags & PAF_NOTARGET));
A_SkullAttack(other, SKULLSPEED);
if (!(flags & PAF_NOSKULLATTACK))
A_SkullAttack(other, SKULLSPEED);
}
@ -139,9 +150,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack)
if (!self->target)
return;
const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO);
A_FaceTarget (self);
A_PainShootSkull (self, self->angle, spawntype);
ACTION_PARAM_START(4);
ACTION_PARAM_CLASS(spawntype, 0);
ACTION_PARAM_ANGLE(angle, 1);
ACTION_PARAM_INT(flags, 2);
ACTION_PARAM_INT(limit, 3);
if (spawntype == NULL) spawntype = PClass::FindClass("LostSoul");
if (!(flags & PAF_AIMFACING))
A_FaceTarget (self);
A_PainShootSkull (self, self->angle+angle, spawntype, flags, limit);
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DualPainAttack)

View file

@ -2,12 +2,11 @@
#include "actor.h"
#include "p_enemy.h"
#include "a_action.h"
#include "r_draw.h"
#include "m_random.h"
#include "p_local.h"
#include "a_doomglobal.h"
#include "s_sound.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/

View file

@ -37,7 +37,7 @@
#include "doomstat.h"
#include "d_protocol.h"
#include "d_netinf.h"
#include "f_finale.h"
#include "intermission/intermission.h"
#include "m_argv.h"
#include "m_misc.h"
#include "menu/menu.h"
@ -61,9 +61,7 @@
#include "p_local.h"
#include "s_sound.h"
#include "gstrings.h"
#include "r_data.h"
#include "r_sky.h"
#include "r_draw.h"
#include "g_game.h"
#include "g_level.h"
#include "b_bot.h" //Added by MC:
@ -73,12 +71,15 @@
#include "gi.h"
#include "a_keys.h"
#include "a_artifacts.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "cmdlib.h"
#include "d_net.h"
#include "d_event.h"
#include "p_acs.h"
#include "m_joy.h"
#include "farchive.h"
#include "r_renderer.h"
#include "r_data/colormaps.h"
#include <zlib.h>
@ -104,6 +105,9 @@ void G_DoWorldDone (void);
void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description);
void G_DoAutoSave ();
void STAT_Write(FILE *file);
void STAT_Read(PNGHandle *png);
FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH);
CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH);
CVAR (Bool, chasedemo, false, 0);
@ -177,8 +181,6 @@ wbstartstruct_t wminfo; // parms for world map / intermission
short consistancy[MAXPLAYERS][BACKUPTICS];
BYTE* savebuffer;
#define MAXPLMOVE (forwardmove[1])
@ -237,9 +239,9 @@ CUSTOM_CVAR (Float, turbo, 100.f, 0)
{
self = 10.f;
}
else if (self > 256.f)
else if (self > 255.f)
{
self = 256.f;
self = 255.f;
}
else
{
@ -454,6 +456,8 @@ CCMD (drop)
}
}
const PClass *GetFlechetteType(AActor *other);
CCMD (useflechette)
{ // Select from one of arti_poisonbag1-3, whichever the player has
static const ENamedName bagnames[3] =
@ -462,22 +466,26 @@ CCMD (useflechette)
NAME_ArtiPoisonBag2,
NAME_ArtiPoisonBag3
};
int i, j;
if (who == NULL)
return;
if (who->IsKindOf (PClass::FindClass (NAME_ClericPlayer)))
i = 0;
else if (who->IsKindOf (PClass::FindClass (NAME_MagePlayer)))
i = 1;
else
i = 2;
for (j = 0; j < 3; ++j)
const PClass *type = GetFlechetteType(who);
if (type != NULL)
{
AInventory *item;
if ( (item = who->FindInventory (bagnames[(i+j)%3])) )
if ( (item = who->FindInventory (type) ))
{
SendItemUse = item;
return;
}
}
// The default flechette could not be found. Try all 3 types then.
for (int j = 0; j < 3; ++j)
{
AInventory *item;
if ( (item = who->FindInventory (bagnames[j])) )
{
SendItemUse = item;
break;
@ -1008,6 +1016,7 @@ void G_Ticker ()
G_DoNewGame ();
break;
case ga_loadgame:
case ga_loadgamehidecon:
case ga_autoloadgame:
G_DoLoadGame ();
break;
@ -1028,7 +1037,7 @@ void G_Ticker ()
G_DoCompleted ();
break;
case ga_slideshow:
F_StartSlideshow ();
if (gamestate == GS_LEVEL) F_StartIntermission(level.info->slideshow, FSTATE_InLevel);
break;
case ga_worlddone:
G_DoWorldDone ();
@ -1624,12 +1633,12 @@ void G_ScreenShot (char *filename)
// G_InitFromSavegame
// Can be called by the startup code or the menu task.
//
void G_LoadGame (const char* name)
void G_LoadGame (const char* name, bool hidecon)
{
if (name != NULL)
{
savename = name;
gameaction = ga_loadgame;
gameaction = !hidecon ? ga_loadgame : ga_loadgamehidecon;
}
}
@ -1689,11 +1698,13 @@ void G_DoLoadGame ()
char sigcheck[20];
char *text = NULL;
char *map;
bool hidecon;
if (gameaction != ga_autoloadgame)
{
demoplayback = false;
}
hidecon = gameaction == ga_loadgamehidecon;
gameaction = ga_nothing;
FILE *stdfile = fopen (savename.GetChars(), "rb");
@ -1739,13 +1750,19 @@ void G_DoLoadGame ()
delete[] engine;
}
SaveVersion = 0;
if (!M_GetPNGText (png, "ZDoom Save Version", sigcheck, 20) ||
0 != strncmp (sigcheck, SAVESIG, 9) || // ZDOOMSAVE is the first 9 chars
(SaveVersion = atoi (sigcheck+9)) < MINSAVEVER)
{
Printf ("Savegame is from an incompatible version\n");
delete png;
fclose (stdfile);
Printf ("Savegame is from an incompatible version");
if (SaveVersion != 0)
{
Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER);
}
Printf("\n");
return;
}
@ -1763,6 +1780,13 @@ void G_DoLoadGame ()
return;
}
// Now that it looks like we can load this save, hide the fullscreen console if it was up
// when the game was selected from the menu.
if (hidecon && gamestate == GS_FULLCONSOLE)
{
gamestate = GS_HIDECONSOLE;
}
// Read intermission data for hubs
G_ReadHubInfo(png);
@ -1791,6 +1815,7 @@ void G_DoLoadGame ()
}
G_ReadSnapshots (png);
STAT_Read(png);
FRandom::StaticReadRNGState (png);
P_ReadACSDefereds (png);
@ -1902,6 +1927,7 @@ FString G_BuildSaveName (const char *prefix, int slot)
}
CVAR (Int, autosavenum, 0, CVAR_NOSET|CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
static int nextautosave = -1;
CVAR (Int, disableautosave, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Int, autosavecount, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
@ -1922,10 +1948,25 @@ void G_DoAutoSave ()
const char *readableTime;
int count = autosavecount != 0 ? autosavecount : 1;
num.Int = (autosavenum + 1) % count;
if (nextautosave == -1)
{
nextautosave = (autosavenum + 1) % count;
}
num.Int = nextautosave;
autosavenum.ForceSet (num, CVAR_Int);
file = G_BuildSaveName ("auto", num.Int);
file = G_BuildSaveName ("auto", nextautosave);
if (!(level.flags2 & LEVEL2_NOAUTOSAVEHINT))
{
nextautosave = (nextautosave + 1) % count;
}
else
{
// This flag can only be used once per level
level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
}
readableTime = myasctime ();
strcpy (description, "Autosave ");
@ -1994,7 +2035,7 @@ static void PutSavePic (FILE *file, int width, int height)
else
{
P_CheckPlayerSprites();
screen->WriteSavePic(&players[consoleplayer], file, width, height);
Renderer->WriteSavePic(&players[consoleplayer], file, width, height);
}
}
@ -2052,6 +2093,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
G_WriteSnapshots (stdfile);
STAT_Write(stdfile);
FRandom::StaticWriteRNGState (stdfile);
P_WriteACSDefereds (stdfile);
@ -2570,6 +2612,7 @@ bool G_CheckDemoStatus (void)
C_RestoreCVars (); // [RH] Restore cvars demo might have changed
M_Free (demobuffer);
demobuffer = NULL;
P_SetupWeapons_ntohton();
demoplayback = false;

View file

@ -36,7 +36,7 @@ void G_DeferedPlayDemo (const char* demo);
// Can be called by the startup code or M_Responder,
// calls P_SetupLevel or W_EnterWorld.
void G_LoadGame (const char* name);
void G_LoadGame (const char* name, bool hidecon=false);
void G_DoLoadGame (void);
@ -85,6 +85,8 @@ void G_AddViewAngle (int yaw);
class AActor;
extern AActor *bodyque[BODYQUESIZE];
extern int bodyqueslot;
class AInventory;
extern const AInventory *SendItemUse, *SendItemDrop;
#endif

View file

@ -258,8 +258,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard)
mo->z -= mo->GetDefault()->height/2;
if (!P_TestMobjLocation (mo))
{ // Didn't fit
mo->ClearCounters();
mo->Destroy ();
level.total_monsters--;
}
else
{ // [RH] Make the new wizards inherit D'Sparil's target

View file

@ -12,8 +12,9 @@
#include "g_level.h"
#include "a_sharedglobal.h"
#include "templates.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "doomstat.h"
#include "farchive.h"
// Include all the other Heretic stuff here to reduce compile time
#include "a_chicken.cpp"

View file

@ -10,7 +10,7 @@
#include "p_local.h"
#include "gstrings.h"
#include "gi.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
*/
@ -462,8 +462,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check)
self->velx = FixedMul(7*FRACUNIT, finecosine[angle]);
self->vely = FixedMul(7*FRACUNIT, finesine[angle]);
#else
double velscale = sqrtf ((float)self->velx * (float)self->velx +
(float)self->vely * (float)self->vely);
double velscale = sqrt ((double)self->velx * (double)self->velx +
(double)self->vely * (double)self->vely);
velscale = 458752 / velscale;
self->velx = (int)(self->velx * velscale);
self->vely = (int)(self->vely * velscale);
@ -1045,6 +1045,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
x = self->x + ((pr_storm()&127) - 64) * FRACUNIT;
y = self->y + ((pr_storm()&127) - 64) * FRACUNIT;
mo = Spawn<ARainPillar> (x, y, ONCEILINGZ, ALLOW_REPLACE);
#ifdef _3DFLOORS
// We used bouncecount to store the 3D floor index in A_HideInCeiling
if (!mo) return;
fixed_t newz;
if (self->bouncecount >= 0
&& (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size())
newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT;
else
newz = self->Sector->ceilingplane.ZatPoint(x, y);
int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz);
if (moceiling >= 0)
mo->z = newz - mo->height;
#endif
mo->Translation = multiplayer ?
TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0;
mo->target = self->target;
@ -1084,6 +1097,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact)
DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
{
#ifdef _3DFLOORS
// We use bouncecount to store the 3D floor index
fixed_t foo;
for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++)
{
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height))
{
self->z = foo + 4*FRACUNIT;
self->bouncecount = i;
return;
}
}
self->bouncecount = -1;
#endif
self->z = self->ceilingz + 4*FRACUNIT;
}

View file

@ -141,6 +141,27 @@ bool AArtiPoisonBag3::Use (bool pickup)
return false;
}
//============================================================================
//
// GetFlechetteType
//
//============================================================================
const PClass *GetFlechetteType(AActor *other)
{
const PClass *spawntype = NULL;
if (other->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
spawntype = static_cast<APlayerPawn*>(other)->FlechetteType;
}
if (spawntype == NULL)
{
// default fallback if nothing valid defined.
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
}
return spawntype;
}
//============================================================================
//
// AArtiPoisonBag :: HandlePickup
@ -155,21 +176,7 @@ bool AArtiPoisonBag::HandlePickup (AInventory *item)
return Super::HandlePickup (item);
}
bool matched;
if (Owner->IsKindOf (PClass::FindClass(NAME_ClericPlayer)))
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag1));
}
else if (Owner->IsKindOf (PClass::FindClass(NAME_MagePlayer)))
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag2));
}
else
{
matched = (GetClass() == RUNTIME_CLASS(AArtiPoisonBag3));
}
if (matched)
if (GetClass() == GetFlechetteType(Owner))
{
if (Amount < MaxAmount)
{
@ -204,20 +211,8 @@ AInventory *AArtiPoisonBag::CreateCopy (AActor *other)
}
AInventory *copy;
const PClass *spawntype;
if (other->IsKindOf (PClass::FindClass(NAME_ClericPlayer)))
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag1);
}
else if (other->IsKindOf (PClass::FindClass(NAME_MagePlayer)))
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag2);
}
else
{
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
}
const PClass *spawntype = GetFlechetteType(other);
copy = static_cast<AInventory *>(Spawn (spawntype, 0, 0, 0, NO_REPLACE));
copy->Amount = Amount;
copy->MaxAmount = MaxAmount;

View file

@ -859,8 +859,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop)
{
if (!P_TestMobjLocation(mo))
{
mo->ClearCounters();
mo->Destroy ();
level.total_monsters--;
}
else if (self->target != NULL)
{ // [RH] Make the new bishops inherit the Heriarch's target

View file

@ -17,6 +17,7 @@
#include "p_terrain.h"
#include "m_bbox.h"
#include "ravenshared.h"
#include "farchive.h"
// Include all the Hexen stuff here to reduce compile time
#include "a_bats.cpp"

View file

@ -332,7 +332,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BellReset1)
self->height <<= 2;
if (self->special)
{ // Initiate death action
LineSpecials[self->special] (NULL, NULL, false, self->args[0],
P_ExecuteSpecial(self->special, NULL, NULL, false, self->args[0],
self->args[1], self->args[2], self->args[3], self->args[4]);
self->special = 0;
}

View file

@ -134,7 +134,7 @@ int ATelOtherFX1::DoSpecialDamage (AActor *target, int damage)
if (target->flags3 & MF3_ISMONSTER && target->special)
{
target->RemoveFromHash ();
LineSpecials[target->special] (NULL, level.flags & LEVEL_ACTOWNSPECIAL
P_ExecuteSpecial(target->special, NULL, level.flags & LEVEL_ACTOWNSPECIAL
? target : (AActor *)(this->target), false, target->args[0], target->args[1],
target->args[2], target->args[3], target->args[4]);
target->special = 0;

View file

@ -76,7 +76,7 @@ struct FHubInfo
};
TArray<FHubInfo> hubdata;
static TArray<FHubInfo> hubdata;
void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
@ -182,3 +182,8 @@ void G_ReadHubInfo (PNGHandle *png)
G_SerializeHub(arc);
}
}
void G_ClearHubInfo()
{
hubdata.Clear();
}

View file

@ -42,7 +42,6 @@
#include "m_random.h"
#include "doomstat.h"
#include "wi_stuff.h"
#include "r_data.h"
#include "w_wad.h"
#include "am_map.h"
#include "c_dispatch.h"
@ -51,7 +50,7 @@
#include "p_local.h"
#include "r_sky.h"
#include "c_console.h"
#include "f_finale.h"
#include "intermission/intermission.h"
#include "gstrings.h"
#include "v_video.h"
#include "st_stuff.h"
@ -70,31 +69,26 @@
#include "version.h"
#include "statnums.h"
#include "sbarinfo.h"
#include "r_translate.h"
#include "r_data/r_translate.h"
#include "p_lnspec.h"
#include "r_interpolate.h"
#include "r_data/r_interpolate.h"
#include "cmdlib.h"
#include "d_net.h"
#include "d_netinf.h"
#include "v_palette.h"
#include "menu/menu.h"
#include "a_strifeglobal.h"
#include "r_data/colormaps.h"
#include "farchive.h"
#include "r_renderer.h"
#include "gi.h"
#include "g_hub.h"
void STAT_StartNewGame(const char *lev);
void STAT_ChangeLevel(const char *newl);
#ifndef STAT
#define STAT_NEW(map)
#define STAT_END(newl)
#define STAT_READ(png)
#define STAT_WRITE(f)
#else
void STAT_NEW(const char *lev);
void STAT_END(const char *newl);
void STAT_READ(PNGHandle *png);
void STAT_WRITE(FILE *f);
#endif
EXTERN_CVAR (Float, sv_gravity)
EXTERN_CVAR (Float, sv_aircontrol)
@ -108,22 +102,11 @@ EXTERN_CVAR (String, playerclass)
#define RCLS_ID MAKE_ID('r','c','L','s')
#define PCLS_ID MAKE_ID('p','c','L','s')
static void SetEndSequence (char *nextmap, int type);
void G_VerifySkill();
static FRandom pr_classchoice ("RandomPlayerClassChoice");
TArray<EndSequence> EndSequences;
EndSequence::EndSequence()
{
EndType = END_Pic;
Advanced = false;
MusicLooping = false;
PlayTheEnd = false;
}
extern level_info_t TheDefaultLevelInfo;
extern bool timingdemo;
@ -138,79 +121,11 @@ bool savegamerestore;
extern int mousex, mousey;
extern bool sendpause, sendsave, sendturn180, SendLand;
extern const AInventory *SendItemUse, *SendItemDrop;
void *statcopy; // for statistics driver
FLevelLocals level; // info about current level
//==========================================================================
//
//
//==========================================================================
int FindEndSequence (int type, const char *picname)
{
unsigned int i, num;
num = EndSequences.Size ();
for (i = 0; i < num; i++)
{
if (EndSequences[i].EndType == type && !EndSequences[i].Advanced &&
(type != END_Pic || stricmp (EndSequences[i].PicName, picname) == 0))
{
return (int)i;
}
}
return -1;
}
//==========================================================================
//
//
//==========================================================================
static void SetEndSequence (char *nextmap, int type)
{
int seqnum;
seqnum = FindEndSequence (type, NULL);
if (seqnum == -1)
{
EndSequence newseq;
newseq.EndType = type;
seqnum = (int)EndSequences.Push (newseq);
}
mysnprintf(nextmap, 11, "enDSeQ%04x", (WORD)seqnum);
}
//==========================================================================
//
//
//==========================================================================
void G_SetForEndGame (char *nextmap)
{
if (!strncmp(nextmap, "enDSeQ",6)) return; // If there is already an end sequence please leave it alone!!!
if (gameinfo.gametype == GAME_Strife)
{
SetEndSequence (nextmap, gameinfo.flags & GI_SHAREWARE ? END_BuyStrife : END_Strife);
}
else if (gameinfo.gametype == GAME_Hexen)
{
SetEndSequence (nextmap, END_Chess);
}
else if (gameinfo.gametype == GAME_Doom && (gameinfo.flags & GI_MAPxx))
{
SetEndSequence (nextmap, END_Cast);
}
else
{ // The ExMx games actually have different ends based on the episode,
// but I want to keep this simple.
SetEndSequence (nextmap, END_Pic1);
}
}
//==========================================================================
//
@ -233,7 +148,7 @@ void G_DeferedInitNew (const char *mapname, int newskill)
void G_DeferedInitNew (FGameStartup *gs)
{
playerclass = gs->PlayerClass;
if (gs->PlayerClass != NULL) playerclass = gs->PlayerClass;
d_mapname = AllEpisodes[gs->Episode].mEpisodeMap;
d_skill = gs->Skill;
CheckWarpTransMap (d_mapname, true);
@ -395,6 +310,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
bool wantFast;
int i;
G_ClearHubInfo();
if (!savegamerestore)
{
G_ClearSnapshots ();
@ -502,7 +418,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
for (i = 0; i < MAXPLAYERS; i++)
players[i].playerstate = PST_ENTER; // [BC]
STAT_NEW(mapname);
STAT_StartNewGame(mapname);
}
usergame = !bTitleLevel; // will be set false if a demo
@ -550,7 +466,6 @@ static bool unloading;
//
//==========================================================================
void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill)
{
level_info_t *nextinfo = NULL;
@ -561,7 +476,20 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
return;
}
if (strncmp(levelname, "enDSeQ", 6) != 0)
if (levelname == NULL || *levelname == 0)
{
// end the game
levelname = NULL;
if (!strncmp(level.nextmap, "enDSeQ",6))
{
levelname = level.nextmap; // If there is already an end sequence please leave it alone!
}
else
{
nextlevel.Format("enDSeQ%04x", int(gameinfo.DefaultEndSequence));
}
}
else if (strncmp(levelname, "enDSeQ", 6) != 0)
{
nextinfo = FindLevelInfo (levelname);
if (nextinfo != NULL)
@ -575,7 +503,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
}
}
nextlevel = levelname;
if (levelname != NULL) nextlevel = levelname;
if (nextSkill != -1)
NextSkill = nextSkill;
@ -614,7 +542,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true);
unloading = false;
STAT_END(nextlevel);
STAT_ChangeLevel(nextlevel);
if (thiscluster && (thiscluster->flags & CLUSTER_HUB))
{
@ -816,12 +744,7 @@ void G_DoCompleted (void)
{ // Reset world variables for the new hub.
P_ClearACSVars(false);
}
// With hub statistics the time should be per hub.
// Additionally there is a global time counter now so nothing is missed by changing it
//else if (mode == FINISH_NoHub)
{ // Reset time to zero if not entering/staying in a hub.
level.time = 0;
}
level.time = 0;
level.maptime = 0;
}
@ -950,6 +873,7 @@ void G_DoLoadLevel (int position, bool autosave)
level.flags2 &= ~LEVEL2_NOMONSTERS;
}
level.maptime = 0;
P_SetupLevel (level.mapname, position);
AM_LevelInit();
@ -991,7 +915,6 @@ void G_DoLoadLevel (int position, bool autosave)
}
level.starttime = gametic;
level.maptime = 0;
G_UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level.
G_FinishTravel ();
if (players[consoleplayer].camera == NULL ||
@ -1035,13 +958,28 @@ void G_WorldDone (void)
if (strncmp (nextlevel, "enDSeQ", 6) == 0)
{
FName endsequence = ENamedName(strtol(nextlevel.GetChars()+6, NULL, 16));
// Strife needs a special case here to choose between good and sad ending. Bad is handled elsewherw.
if (endsequence == NAME_Inter_Strife)
{
if (players[0].mo->FindInventory (QuestItemClasses[24]) ||
players[0].mo->FindInventory (QuestItemClasses[27]))
{
endsequence = NAME_Inter_Strife_Good;
}
else
{
endsequence = NAME_Inter_Strife_Sad;
}
}
F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder,
thiscluster->cdtrack, thiscluster->cdid,
thiscluster->FinaleFlat, thiscluster->ExitText,
thiscluster->flags & CLUSTER_EXITTEXTINLUMP,
thiscluster->flags & CLUSTER_FINALEPIC,
thiscluster->flags & CLUSTER_LOOKUPEXITTEXT,
true, strtol(nextlevel.GetChars()+6, NULL, 16));
true, endsequence);
}
else
{
@ -1412,7 +1350,7 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
{
int i = level.totaltime;
screen->StartSerialize(arc);
Renderer->StartSerialize(arc);
arc << level.flags
<< level.flags2
@ -1531,7 +1469,7 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
}
}
}
screen->EndSerialize(arc);
Renderer->EndSerialize(arc);
}
//==========================================================================
@ -1652,7 +1590,6 @@ void G_WriteSnapshots (FILE *file)
{
unsigned int i;
STAT_WRITE(file);
for (i = 0; i < wadlevelinfos.Size(); i++)
{
if (wadlevelinfos[i].snapshot)
@ -1803,7 +1740,6 @@ void G_ReadSnapshots (PNGHandle *png)
arc << pnum;
}
}
STAT_READ(png);
png->File->ResetFilePtr();
}
@ -1927,10 +1863,13 @@ CCMD(listmaps)
for(unsigned i = 0; i < wadlevelinfos.Size(); i++)
{
level_info_t *info = &wadlevelinfos[i];
MapData *map = P_OpenMapData(info->mapname);
if (P_CheckMapData(info->mapname))
if (map != NULL)
{
Printf("%s: '%s'\n", info->mapname, info->LookupLevelName().GetChars());
Printf("%s: '%s' (%s)\n", info->mapname, info->LookupLevelName().GetChars(),
Wads.GetWadName(Wads.GetLumpFile(map->lumpnum)));
delete map;
}
}
}

View file

@ -54,6 +54,8 @@ class FScanner;
#define GCC_YSEG __attribute__((section(SECTION_YREG)))
#endif
struct FIntermissionDescriptor;
struct FIntermissionAction;
struct FMapInfoParser
{
@ -98,6 +100,11 @@ struct FMapInfoParser
bool CheckFloat();
void SkipToNext();
void CheckEndOfFile(const char *block);
void ParseIntermissionAction(FIntermissionDescriptor *Desc);
void ParseIntermission();
FName CheckEndSequence();
FName ParseEndGame();
};
#define DEFINE_MAP_OPTION(name, old) \
@ -155,7 +162,7 @@ enum ELevelFlags
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_HEXENFORMAT = 0x08000000, // Level uses the Hexen map format
//LEVEL_HEXENFORMAT = 0x08000000, // Level uses the Hexen map format
LEVEL_SWAPSKIES = 0x10000000, // Used by lightning
LEVEL_NOALLIES = 0x20000000, // i.e. Inside Strife's front base
@ -163,7 +170,7 @@ enum ELevelFlags
LEVEL_VISITED = 0x80000000, // Used for intermission map
// The flags QWORD is now split into 2 DWORDs
LEVEL2_DEATHSLIDESHOW = 0x00000001, // Slideshow on death
//LEVEL2_DEATHSLIDESHOW = 0x00000001, // Slideshow on death
LEVEL2_ALLMAP = 0x00000002, // The player picked up a map on this level
LEVEL2_LAXMONSTERACTIVATION = 0x00000004, // Monsters can open doors depending on the door speed
@ -202,6 +209,10 @@ enum ELevelFlags
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
};
@ -242,13 +253,22 @@ struct FOptionalMapinfoDataPtr
typedef TMap<FName, FOptionalMapinfoDataPtr> FOptData;
typedef TMap<int, FName> FMusicMap;
enum EMapType
{
MAPTYPE_UNKNOWN = 0,
MAPTYPE_DOOM,
MAPTYPE_HEXEN,
MAPTYPE_BUILD,
MAPTYPE_UDMF // This does not distinguish between namespaces.
};
struct level_info_t
{
int levelnum;
char mapname[9];
char pname[9];
char nextmap[11]; // The endsequence string is 10 chars so we need more space here
char nextmap[11];
char secretmap[11];
char skypic1[9];
char skypic2[9];
@ -283,6 +303,9 @@ struct level_info_t
DWORD compatmask;
FString Translator; // for converting Doom-format linedef and sector types.
int DefaultEnvironment; // Default sound environment for the map.
FName Intermission;
FName deathsequence;
FName slideshow;
// Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one.
@ -366,6 +389,7 @@ struct FLevelLocals
char mapname[256]; // the lump name (E1M1, MAP01, etc)
char nextmap[11]; // go here when using the regular exit
char secretmap[11]; // map to go to when used secret exit
EMapType maptype;
DWORD flags;
DWORD flags2;
@ -412,36 +436,6 @@ struct FLevelLocals
bool IsFreelookAllowed() const;
};
enum EndTypes
{
END_Pic,
END_Pic1,
END_Pic2,
END_Pic3,
END_Bunny,
END_Cast,
END_Demon,
END_Underwater,
END_Chess,
END_Strife,
END_BuyStrife,
END_TitleScreen
};
struct EndSequence
{
BYTE EndType;
bool Advanced;
bool MusicLooping;
bool PlayTheEnd;
FString PicName;
FString PicName2;
FString Music;
EndSequence();
};
extern TArray<EndSequence> EndSequences;
struct cluster_info_t
{
@ -506,8 +500,6 @@ enum
void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1);
void G_SetForEndGame (char *nextmap);
void G_StartTravel ();
void G_FinishTravel ();
@ -533,6 +525,7 @@ void G_UnSnapshotLevel (bool keepPlayers);
struct PNGHandle;
void G_ReadSnapshots (PNGHandle *png);
void G_WriteSnapshots (FILE *file);
void G_ClearHubInfo();
enum ESkillProperty
{

View file

@ -53,9 +53,6 @@
#include "version.h"
#include "v_text.h"
int FindEndSequence (int type, const char *picname);
TArray<cluster_info_t> wadclusterinfos;
TArray<level_info_t> wadlevelinfos;
@ -234,7 +231,10 @@ void level_info_t::Reset()
partime = 0;
sucktime = 0;
flags = 0;
flags2 = gameinfo.gametype == GAME_Hexen? 0 : LEVEL2_LAXMONSTERACTIVATION;
if (gameinfo.gametype == GAME_Hexen)
flags2 = 0;
else
flags2 = LEVEL2_LAXMONSTERACTIVATION;
Music = "";
LevelName = "";
strcpy (fadetable, "COLORMAP");
@ -757,9 +757,6 @@ void FMapInfoParser::ParseCluster()
void FMapInfoParser::ParseNextMap(char *mapname)
{
EndSequence newSeq;
bool useseq = false;
if (sc.CheckNumber())
{
if (HexenHack)
@ -773,163 +770,14 @@ void FMapInfoParser::ParseNextMap(char *mapname)
}
else
{
*mapname = 0;
sc.MustGetString();
if (sc.Compare("endgame"))
strncpy (mapname, sc.String, 8);
mapname[8] = 0;
FName seq = CheckEndSequence();
if (seq != NAME_None)
{
if (!sc.CheckString("{"))
{
// Make Demon Eclipse work again
sc.UnGet();
goto standard_endgame;
}
newSeq.Advanced = true;
newSeq.EndType = END_Pic1;
newSeq.PlayTheEnd = false;
newSeq.MusicLooping = true;
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("pic"))
{
ParseAssign();
sc.MustGetString();
newSeq.EndType = END_Pic;
newSeq.PicName = sc.String;
}
else if (sc.Compare("hscroll"))
{
ParseAssign();
newSeq.EndType = END_Bunny;
sc.MustGetString();
newSeq.PicName = sc.String;
ParseComma();
sc.MustGetString();
newSeq.PicName2 = sc.String;
if (CheckNumber())
newSeq.PlayTheEnd = !!sc.Number;
}
else if (sc.Compare("vscroll"))
{
ParseAssign();
newSeq.EndType = END_Demon;
sc.MustGetString();
newSeq.PicName = sc.String;
ParseComma();
sc.MustGetString();
newSeq.PicName2 = sc.String;
}
else if (sc.Compare("cast"))
{
newSeq.EndType = END_Cast;
}
else if (sc.Compare("music"))
{
ParseAssign();
sc.MustGetString();
newSeq.Music = sc.String;
if (CheckNumber())
{
newSeq.MusicLooping = !!sc.Number;
}
}
else
{
if (format_type == FMT_New)
{
// Unknown
sc.ScriptMessage("Unknown property '%s' found in endgame definition\n", sc.String);
SkipToNext();
}
else
{
sc.ScriptError("Unknown property '%s' found in endgame definition\n", sc.String);
}
}
}
useseq = true;
}
else if (strnicmp (sc.String, "EndGame", 7) == 0)
{
int type;
switch (sc.String[7])
{
case '1': type = END_Pic1; break;
case '2': type = END_Pic2; break;
case '3': type = END_Bunny; break;
case 'C': type = END_Cast; break;
case 'W': type = END_Underwater; break;
case 'S': type = END_Strife; break;
standard_endgame:
default: type = END_Pic3; break;
}
newSeq.EndType = type;
useseq = true;
}
else if (sc.Compare("endpic"))
{
ParseComma();
sc.MustGetString ();
newSeq.EndType = END_Pic;
newSeq.PicName = sc.String;
useseq = true;
}
else if (sc.Compare("endbunny"))
{
newSeq.EndType = END_Bunny;
useseq = true;
}
else if (sc.Compare("endcast"))
{
newSeq.EndType = END_Cast;
useseq = true;
}
else if (sc.Compare("enddemon"))
{
newSeq.EndType = END_Demon;
useseq = true;
}
else if (sc.Compare("endchess"))
{
newSeq.EndType = END_Chess;
useseq = true;
}
else if (sc.Compare("endunderwater"))
{
newSeq.EndType = END_Underwater;
useseq = true;
}
else if (sc.Compare("endbuystrife"))
{
newSeq.EndType = END_BuyStrife;
useseq = true;
}
else if (sc.Compare("endtitle"))
{
newSeq.EndType = END_TitleScreen;
useseq = true;
}
else
{
strncpy (mapname, sc.String, 8);
mapname[8] = 0;
}
if (useseq)
{
int seqnum = -1;
if (!newSeq.Advanced)
{
seqnum = FindEndSequence (newSeq.EndType, newSeq.PicName);
}
if (seqnum == -1)
{
seqnum = (int)EndSequences.Push (newSeq);
}
// mapname can point to nextmap and secretmap which are both 12 characters long
mysnprintf(mapname, 11, "enDSeQ%04x", (WORD)seqnum);
mysnprintf(mapname, 11, "enDSeQ%04x", int(seq));
}
}
}
@ -1229,6 +1077,20 @@ DEFINE_MAP_OPTION(translator, true)
info->Translator = parse.sc.String;
}
DEFINE_MAP_OPTION(deathsequence, false)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->deathsequence = parse.sc.String;
}
DEFINE_MAP_OPTION(slideshow, false)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->slideshow = parse.sc.String;
}
DEFINE_MAP_OPTION(bordertexture, true)
{
parse.ParseAssign();
@ -1351,10 +1213,10 @@ MapFlagHandlers[] =
{ "missilesactivateimpactlines", MITYPE_SETFLAG2, LEVEL2_MISSILESACTIVATEIMPACT, 0 },
{ "missileshootersactivetimpactlines",MITYPE_CLRFLAG2, LEVEL2_MISSILESACTIVATEIMPACT, 0 },
{ "noinventorybar", MITYPE_SETFLAG, LEVEL_NOINVENTORYBAR, 0 },
{ "deathslideshow", MITYPE_SETFLAG2, LEVEL2_DEATHSLIDESHOW, 0 },
{ "deathslideshow", MITYPE_SETFLAG2, 0, 0 },
{ "strictmonsteractivation", MITYPE_CLRFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO },
{ "laxmonsteractivation", MITYPE_SETFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO },
{ "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL, 0 },
{ "keepfullinventory", MITYPE_SETFLAG2, LEVEL2_KEEPFULLINVENTORY, 0 },
{ "monsterfallingdamage", MITYPE_SETFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
{ "nomonsterfallingdamage", MITYPE_CLRFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
@ -1377,42 +1239,46 @@ MapFlagHandlers[] =
{ "no_grinding_polyobj", MITYPE_CLRFLAG2, LEVEL2_POLYGRIND, 0 },
{ "resetinventory", MITYPE_SETFLAG2, LEVEL2_RESETINVENTORY, 0 },
{ "resethealth", MITYPE_SETFLAG2, LEVEL2_RESETHEALTH, 0 },
{ "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 },
{ "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 0 },
{ "noautosavehint", MITYPE_SETFLAG2, LEVEL2_NOAUTOSAVEHINT, 0 },
{ "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 },
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
{ "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX},
{ "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX},
{ "compat_limitpain", MITYPE_COMPATFLAG, COMPATF_LIMITPAIN},
{ "compat_nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ},
{ "compat_notossdrops", MITYPE_COMPATFLAG, COMPATF_NOTOSSDROPS},
{ "compat_useblocking", MITYPE_COMPATFLAG, COMPATF_USEBLOCKING},
{ "compat_nodoorlight", MITYPE_COMPATFLAG, COMPATF_NODOORLIGHT},
{ "compat_ravenscroll", MITYPE_COMPATFLAG, COMPATF_RAVENSCROLL},
{ "compat_soundtarget", MITYPE_COMPATFLAG, COMPATF_SOUNDTARGET},
{ "compat_dehhealth", MITYPE_COMPATFLAG, COMPATF_DEHHEALTH},
{ "compat_trace", MITYPE_COMPATFLAG, COMPATF_TRACE},
{ "compat_dropoff", MITYPE_COMPATFLAG, COMPATF_DROPOFF},
{ "compat_boomscroll", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ "compat_invisibility", MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
{ "compat_silent_instant_floors", MITYPE_COMPATFLAG, COMPATF_SILENT_INSTANT_FLOORS},
{ "compat_sectorsounds", MITYPE_COMPATFLAG, COMPATF_SECTORSOUNDS},
{ "compat_missileclip", MITYPE_COMPATFLAG, COMPATF_MISSILECLIP},
{ "compat_crossdropoff", MITYPE_COMPATFLAG, COMPATF_CROSSDROPOFF},
{ "compat_anybossdeath", MITYPE_COMPATFLAG, COMPATF_ANYBOSSDEATH},
{ "compat_minotaur", MITYPE_COMPATFLAG, COMPATF_MINOTAUR},
{ "compat_mushroom", MITYPE_COMPATFLAG, COMPATF_MUSHROOM},
{ "compat_mbfmonstermove", MITYPE_COMPATFLAG, COMPATF_MBFMONSTERMOVE},
{ "compat_corpsegibs", MITYPE_COMPATFLAG, COMPATF_CORPSEGIBS},
{ "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS},
{ "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT},
{ "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT},
{ "compat_polyobj", MITYPE_COMPATFLAG, COMPATF_POLYOBJ},
{ "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 },
{ "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 },
{ "compat_limitpain", MITYPE_COMPATFLAG, COMPATF_LIMITPAIN, 0 },
{ "compat_nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 },
{ "compat_notossdrops", MITYPE_COMPATFLAG, COMPATF_NOTOSSDROPS, 0 },
{ "compat_useblocking", MITYPE_COMPATFLAG, COMPATF_USEBLOCKING, 0 },
{ "compat_nodoorlight", MITYPE_COMPATFLAG, COMPATF_NODOORLIGHT, 0 },
{ "compat_ravenscroll", MITYPE_COMPATFLAG, COMPATF_RAVENSCROLL, 0 },
{ "compat_soundtarget", MITYPE_COMPATFLAG, COMPATF_SOUNDTARGET, 0 },
{ "compat_dehhealth", MITYPE_COMPATFLAG, COMPATF_DEHHEALTH, 0 },
{ "compat_trace", MITYPE_COMPATFLAG, COMPATF_TRACE, 0 },
{ "compat_dropoff", MITYPE_COMPATFLAG, COMPATF_DROPOFF, 0 },
{ "compat_boomscroll", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL, 0 },
{ "compat_invisibility", MITYPE_COMPATFLAG, COMPATF_INVISIBILITY, 0 },
{ "compat_silent_instant_floors", MITYPE_COMPATFLAG, COMPATF_SILENT_INSTANT_FLOORS, 0 },
{ "compat_sectorsounds", MITYPE_COMPATFLAG, COMPATF_SECTORSOUNDS, 0 },
{ "compat_missileclip", MITYPE_COMPATFLAG, COMPATF_MISSILECLIP, 0 },
{ "compat_crossdropoff", MITYPE_COMPATFLAG, COMPATF_CROSSDROPOFF, 0 },
{ "compat_anybossdeath", MITYPE_COMPATFLAG, COMPATF_ANYBOSSDEATH, 0 },
{ "compat_minotaur", MITYPE_COMPATFLAG, COMPATF_MINOTAUR, 0 },
{ "compat_mushroom", MITYPE_COMPATFLAG, COMPATF_MUSHROOM, 0 },
{ "compat_mbfmonstermove", MITYPE_COMPATFLAG, COMPATF_MBFMONSTERMOVE, 0 },
{ "compat_corpsegibs", MITYPE_COMPATFLAG, COMPATF_CORPSEGIBS, 0 },
{ "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS, 0 },
{ "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT, 0 },
{ "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT, 0 },
{ "compat_polyobj", MITYPE_COMPATFLAG, COMPATF_POLYOBJ, 0 },
{ "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 },
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end3_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_intermission_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_title_track", MITYPE_EATNEXT, 0, 0 },
{ NULL, MITYPE_IGNORE, 0}
{ NULL, MITYPE_IGNORE, 0, 0}
};
//==========================================================================
@ -1765,7 +1631,13 @@ void FMapInfoParser::ParseEpisodeInfo ()
}
else
{
FEpisode *epi = &AllEpisodes[AllEpisodes.Reserve(1)];
// Only allocate a new entry if this doesn't replace an existing episode.
if (i >= AllEpisodes.Size())
{
i = AllEpisodes.Reserve(1);
}
FEpisode *epi = &AllEpisodes[i];
epi->mEpisodeMap = map;
epi->mEpisodeName = name;
@ -1906,6 +1778,18 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
sc.ScriptError("gameinfo definitions not supported with old MAPINFO syntax");
}
}
else if (sc.Compare("intermission"))
{
if (format_type != FMT_Old)
{
format_type = FMT_New;
ParseIntermission();
}
else
{
sc.ScriptError("intermission definitions not supported with old MAPINFO syntax");
}
}
else
{
sc.ScriptError("%s: Unknown top level keyword", sc.String);
@ -1914,6 +1798,25 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
}
//==========================================================================
//
//
//
//==========================================================================
void DeinitIntermissions();
static void ClearMapinfo()
{
wadclusterinfos.Clear();
wadlevelinfos.Clear();
ClearEpisodes();
AllSkills.Clear();
DefaultSkill = -1;
DeinitIntermissions();
level.info = NULL;
}
//==========================================================================
//
// G_ParseMapInfo
@ -1927,7 +1830,8 @@ void G_ParseMapInfo (const char *basemapinfo)
int lump, lastlump = 0;
level_info_t gamedefaults;
atterm(ClearEpisodes);
ClearMapinfo();
atterm(ClearMapinfo);
// Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3.
if (basemapinfo != NULL)
@ -1963,7 +1867,6 @@ void G_ParseMapInfo (const char *basemapinfo)
level_info_t defaultinfo;
parse.ParseMapInfo(lump, gamedefaults, defaultinfo);
}
EndSequences.ShrinkToFit ();
if (AllEpisodes.Size() == 0)
{

View file

@ -11,6 +11,7 @@
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "doomstat.h"
#include "farchive.h"
#define MAULATORTICS (25*35)

View file

@ -11,7 +11,8 @@
#include "p_enemy.h"
#include "statnums.h"
#include "templates.h"
#include "r_translate.h"
#include "farchive.h"
#include "r_data/r_translate.h"
static FRandom pr_freezedeath ("FreezeDeath");
static FRandom pr_icesettics ("IceSetTics");
@ -191,7 +192,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath)
}
else if (self->flags3 & MF3_ISMONSTER && self->special)
{ // Initiate monster death actions
LineSpecials [self->special] (NULL, self, false, self->args[0],
P_ExecuteSpecial(self->special, NULL, self, false, self->args[0],
self->args[1], self->args[2], self->args[3], self->args[4]);
self->special = 0;
}

View file

@ -2,10 +2,11 @@
#include "info.h"
#include "gi.h"
#include "r_data.h"
#include "a_pickups.h"
#include "templates.h"
#include "g_level.h"
#include "d_player.h"
#include "farchive.h"
IMPLEMENT_CLASS (AArmor)

View file

@ -19,6 +19,8 @@
#include "g_level.h"
#include "doomstat.h"
#include "v_palette.h"
#include "farchive.h"
#include "r_data/colormaps.h"
static FRandom pr_torch ("Torch");
@ -36,8 +38,6 @@ static FRandom pr_torch ("Torch");
#define TIMEFREEZE_TICS ( 12 * TICRATE )
*/
EXTERN_CVAR (Bool, r_drawfuzz);
IMPLEMENT_CLASS (APowerup)
// Powerup-Giver -------------------------------------------------------------
@ -465,7 +465,7 @@ void APowerInvulnerable::EndEffect ()
//
//===========================================================================
int APowerInvulnerable::AlterWeaponSprite (vissprite_t *vis)
int APowerInvulnerable::AlterWeaponSprite (visstyle_t *vis)
{
int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
if (Owner != NULL)
@ -656,7 +656,7 @@ void APowerInvisibility::EndEffect ()
//
//===========================================================================
int APowerInvisibility::AlterWeaponSprite (vissprite_t *vis)
int APowerInvisibility::AlterWeaponSprite (visstyle_t *vis)
{
int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
// Blink if the powerup is wearing off

View file

@ -54,7 +54,7 @@ protected:
void InitEffect ();
void DoEffect ();
void EndEffect ();
int AlterWeaponSprite (vissprite_t *vis);
int AlterWeaponSprite (visstyle_t *vis);
};
class APowerStrength : public APowerup
@ -76,7 +76,7 @@ protected:
void InitEffect ();
void DoEffect ();
void EndEffect ();
int AlterWeaponSprite (vissprite_t *vis);
int AlterWeaponSprite (visstyle_t *vis);
// FRenderStyle OwnersNormalStyle;
// fixed_t OwnersNormalAlpha;
};

View file

@ -35,8 +35,8 @@
#include "actor.h"
#include "info.h"
#include "a_sharedglobal.h"
#include "r_main.h"
#include "p_local.h"
#include "farchive.h"
/*
== SecurityCamera
@ -143,12 +143,21 @@ void AAimingCamera::PostBeginPlay ()
tracer = iterator.Next ();
if (tracer == NULL)
{
Printf ("AimingCamera %d: Can't find thing %d\n", tid, args[3]);
//Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]);
}
else
{ // Don't try for a new target upon losing this one.
args[3] = 0;
}
}
void AAimingCamera::Tick ()
{
if (tracer == NULL && args[3] != 0)
{ // Recheck, in case something with this TID was created since the last time.
TActorIterator<AActor> iterator (args[3]);
tracer = iterator.Next ();
}
if (tracer != NULL)
{
angle_t delta;

View file

@ -44,6 +44,7 @@
#include "d_net.h"
#include "colormatcher.h"
#include "v_palette.h"
#include "farchive.h"
static fixed_t DecalWidth, DecalLeft, DecalRight;
static fixed_t SpreadZ;
@ -414,7 +415,7 @@ static void GetWallStuff (side_t *wall, vertex_t *&v1, fixed_t &ldx, fixed_t &ld
static fixed_t Length (fixed_t dx, fixed_t dy)
{
return (fixed_t)sqrtf ((float)dx*(float)dx+(float)dy*(float)dy);
return (fixed_t)sqrt ((double)dx*(double)dx+(double)dy*(double)dy);
}
static side_t *NextWall (const side_t *wall)

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