mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-18 15:11:46 +00:00
- Update scripting branch to trunk.
SVN r3758 (scripting)
This commit is contained in:
commit
562cf04db2
614 changed files with 63480 additions and 31045 deletions
|
@ -13,6 +13,8 @@ if( CMAKE_COMPILER_IS_GNUCXX )
|
|||
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
find_package( BZip2 )
|
||||
find_package( JPEG )
|
||||
find_package( ZLIB )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -400,7 +400,7 @@ DUH *DUMBEXPORT dumb_load_it(const char *filename);
|
|||
DUH *DUMBEXPORT dumb_load_xm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_s3m(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_stm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict);
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int rstrict);
|
||||
DUH *DUMBEXPORT dumb_load_ptm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_669(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_psm(const char *filename, int subsong);
|
||||
|
@ -413,7 +413,7 @@ DUH *DUMBEXPORT dumb_read_it(DUMBFILE *f);
|
|||
DUH *DUMBEXPORT dumb_read_xm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_s3m(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_stm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict);
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int rstrict);
|
||||
DUH *DUMBEXPORT dumb_read_ptm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_669(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_psm(DUMBFILE *f, int subsong);
|
||||
|
@ -426,7 +426,7 @@ DUH *DUMBEXPORT dumb_load_it_quick(const char *filename);
|
|||
DUH *DUMBEXPORT dumb_load_xm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_s3m_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_stm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict);
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int rstrict);
|
||||
DUH *DUMBEXPORT dumb_load_ptm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_669_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_psm_quick(const char *filename, int subsong);
|
||||
|
@ -439,7 +439,7 @@ DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f);
|
|||
DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_s3m_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict);
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int rstrict);
|
||||
DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* pointer to the DUH struct. When you have finished with it, you must
|
||||
* pass the pointer to unload_duh() so that the memory can be freed.
|
||||
*/
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict)
|
||||
DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int rstrict)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
@ -34,7 +34,7 @@ DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict)
|
|||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_mod_quick(f, restrict);
|
||||
duh = dumb_read_mod_quick(f, rstrict);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict)
|
||||
DUH *DUMBEXPORT dumb_load_mod(const char *filename, int rstrict)
|
||||
{
|
||||
DUH *duh = dumb_load_mod_quick(filename, restrict);
|
||||
DUH *duh = dumb_load_mod_quick(filename, rstrict);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
||||
|
|
|
@ -441,7 +441,7 @@ static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int32 *remain)
|
|||
}
|
||||
|
||||
|
||||
static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
||||
static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
int n_channels;
|
||||
|
@ -550,7 +550,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
}
|
||||
|
||||
// moo
|
||||
if ( restrict && sigdata->n_samples == 15 )
|
||||
if ( rstrict && sigdata->n_samples == 15 )
|
||||
{
|
||||
free(sigdata);
|
||||
dumbfile_close(f);
|
||||
|
@ -758,13 +758,13 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict)
|
||||
DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int rstrict)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_mod_load_sigdata(f, restrict);
|
||||
sigdata = it_mod_load_sigdata(f, rstrict);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict)
|
||||
DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int rstrict)
|
||||
{
|
||||
DUH *duh = dumb_read_mod_quick(f, restrict);
|
||||
DUH *duh = dumb_read_mod_quick(f, rstrict);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -62,10 +62,10 @@ void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out )
|
|||
assert( blip_buf.samples_avail() == pair_count );
|
||||
|
||||
resampler.write( new_count );
|
||||
|
||||
|
||||
long count = resampler.read( sample_buf.begin(), sample_buf_size );
|
||||
assert( count == (long) sample_buf_size );
|
||||
|
||||
|
||||
mix_samples( blip_buf, out );
|
||||
blip_buf.remove_samples( pair_count );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
|
||||
public:
|
||||
// deprecated
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
|
||||
public:
|
||||
// deprecated
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
enum { gym_rate = 60 };
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
void ignore_silence( bool disable = true );
|
||||
|
||||
// Info for current track
|
||||
Gme_File::track_info;
|
||||
using Gme_File::track_info;
|
||||
blargg_err_t track_info( track_info_t* out ) const;
|
||||
|
||||
// Sound customization
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
|
||||
public:
|
||||
// deprecated
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
public:
|
||||
// deprecated
|
||||
struct header_t { char tag [4]; };
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
void disable_playlist( bool = true ); // use clear_playlist()
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
|
||||
public:
|
||||
// deprecated
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
byte const* trailer() const; // use track_info()
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
public:
|
||||
// deprecated
|
||||
Music_Emu::load;
|
||||
using Music_Emu::load;
|
||||
blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader
|
||||
{ return load_remaining_( &h, sizeof h, in ); }
|
||||
byte const* gd3_data( int* size_out = 0 ) const; // use track_info()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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} )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive.
|
||||
This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive or 4.34.
|
||||
Use of the latest 4.26 is recommended though due to technical issues with 4.28.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -39,7 +39,7 @@ between the TEXTMAP and ENDMAP lumps:
|
|||
BEHAVIOR = contains compiled ACS code
|
||||
DIALOGUE = contains compiled Strife conversation scripts.
|
||||
ZNODES = Nodes (must be stored as extended GL nodes. Compression is allowed
|
||||
but deprecated for portability reasons.)
|
||||
but deprecated for portability reasons.)
|
||||
BLOCKMAP = blockmap. It is recommended not to include this lump in UDMF maps.
|
||||
REJECT = reject table. Recommended use is for special effects only.
|
||||
|
||||
|
@ -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
|
||||
|
@ -105,10 +111,17 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
midtex3d = <bool>; // Actors can walk on mid texture.
|
||||
checkswitchrange = <bool>;// Switches can only be activated when vertically reachable.
|
||||
blockprojectiles = <bool>;// Line blocks all projectiles
|
||||
blockuse = <bool>; // Line blocks all use actions
|
||||
|
||||
blockuse = <bool>; // Line blocks all use actions
|
||||
blocksight = <bool>; // Line blocks monster line of sight
|
||||
locknumber = <int>; // Line special is locked
|
||||
arg0str = <string>; // Alternate string-based version of arg0
|
||||
|
||||
* Note about arg0str
|
||||
|
||||
For lines with ACS specials (80-86 and 226), if arg0str is present and non-null, it
|
||||
will be used as the name of the script to execute, and arg0 will be ignored.
|
||||
}
|
||||
|
||||
|
||||
sidedef
|
||||
{
|
||||
scalex_top = <float>; // X scale for upper texture, Default = 1.0.
|
||||
|
@ -128,16 +141,16 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
light = <integer>; // This side's light level. Default is 0.
|
||||
lightabsolute = <bool>; // true = 'light' is an absolute value. Default is
|
||||
// relative to the owning sector's light level.
|
||||
nofakecontrast = <bool>; // Disables use of fake contrast on this sidedef.
|
||||
smoothlighting = <bool>; // Use smooth fake contrast.
|
||||
nofakecontrast = <bool>; // Disables use of fake contrast on this sidedef.
|
||||
smoothlighting = <bool>; // Use smooth fake contrast.
|
||||
clipmidtex = <bool>; // Side's mid textures are clipped to floor and ceiling.
|
||||
wrapmidtex = <bool>; // Side's mid textures are wrapped.
|
||||
nodecals = <bool>; // Disables decals on the sidedef.
|
||||
nodecals = <bool>; // Disables decals on the sidedef.
|
||||
}
|
||||
|
||||
|
||||
sector
|
||||
{
|
||||
xpanningfloor = <float>; // X texture offset of floor texture, Default = 0.0.
|
||||
xpanningfloor = <float>; // X texture offset of floor texture, Default = 0.0.
|
||||
ypanningfloor = <float>; // Y texture offset of floor texture, Default = 0.0.
|
||||
xpanningceiling = <float>; // X texture offset of ceiling texture, Default = 0.0.
|
||||
ypanningceiling = <float>; // Y texture offset of ceiling texture, Default = 0.0.
|
||||
|
@ -153,39 +166,48 @@ 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
|
||||
dropactors = <bool>; // Actors drop with instantly moving floors (*)
|
||||
norespawn = <bool>; // Players can not respawn in this sector
|
||||
soundsequence = <string>; // The sound sequence to play when this sector moves. Placing a
|
||||
// sound sequence thing in the sector will override this property.
|
||||
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
||||
norespawn = <bool>; // Players can not respawn in this sector
|
||||
soundsequence = <string>; // The sound sequence to play when this sector moves. Placing a
|
||||
// sound sequence thing in the sector will override this property.
|
||||
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
conversation = <int> // Assigns a conversation dialogue to this thing.
|
||||
// Parameter is the conversation ID, 0 meaning none.
|
||||
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.
|
||||
arg0str = <string>; // Alternate string-based version of arg0
|
||||
|
||||
* Note about arg0str
|
||||
|
||||
For things with ACS specials (80-86 and 226), if arg0str is present and non-null, it
|
||||
will be used as the name of the script to execute, and arg0 will be ignored.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*** Special notes for map format conversions:
|
||||
|
||||
|
@ -194,7 +216,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
Unless mentioned differently the arg being used to define the line ID
|
||||
should be set to 0.
|
||||
The following line specials are affected:
|
||||
|
||||
|
||||
121: Line_SetIdentification, arg 0
|
||||
208: TranslucentLine, arg0 (arg0 must be preserved)
|
||||
1: Polyobj_StartLine, arg3
|
||||
|
@ -202,16 +224,17 @@ 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.
|
||||
This affects the following specials:
|
||||
|
||||
|
||||
121: Line_SetIdentification, arg1
|
||||
208: TranslucentLine, arg3
|
||||
|
||||
|
||||
These args are to be converted as follows to flags, bit by bit:
|
||||
|
||||
|
||||
Bit 0 (Value 1): zoneboundary
|
||||
Bit 1 (Value 2): jumpover
|
||||
Bit 2 (Value 4): blockfloaters
|
||||
|
@ -220,13 +243,13 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
Bit 5 (Value 32): midtex3d
|
||||
Bit 6 (Value 64): checkswitchrange
|
||||
Bit 7 (Value 128): firstsideonly
|
||||
|
||||
|
||||
When used in special 208 this arg should be cleared afterward.
|
||||
|
||||
|
||||
Special 121 is not being used by UDMF maps in ZDoom and should be completely
|
||||
deleted after conversion.
|
||||
|
||||
|
||||
|
||||
|
||||
=======================================
|
||||
Changelog
|
||||
=======================================
|
||||
|
@ -269,7 +292,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 +300,31 @@ 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
|
||||
|
||||
1.18 17.02.2012
|
||||
Added arg0str linedef property.
|
||||
Standardized whitespace.
|
||||
|
||||
1.19 24.02.2012
|
||||
Added back locknumber property.
|
||||
|
||||
1.20 25.02.2012
|
||||
Added arg0str thing property.
|
||||
|
||||
===============================================================================
|
||||
EOF
|
||||
===============================================================================
|
||||
|
|
|
@ -44,7 +44,7 @@ set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41"
|
|||
"27" "26" "25" "24" "23" "22" "21" "20" "21" "19" "18" "17" "16"
|
||||
"15" "14" "13" "12" "11" "10" "09" "08" "07" "06" "05" "04" "03"
|
||||
"02" "01" "00" )
|
||||
set( MAJOR_VERSIONS "30" "28" "26" "24" "22" "20" )
|
||||
set( MAJOR_VERSIONS "34" "28" "26" "24" "22" "20" )
|
||||
set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" )
|
||||
foreach( majver ${MAJOR_VERSIONS} )
|
||||
foreach( minver ${MINOR_VERSIONS} )
|
||||
|
@ -166,6 +166,19 @@ else( WIN32 )
|
|||
set( NO_GTK ON )
|
||||
endif( GTK2_FOUND )
|
||||
endif( NOT NO_GTK )
|
||||
|
||||
# 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 )
|
||||
|
||||
|
@ -244,7 +257,7 @@ endif( FMOD_LIBRARY )
|
|||
|
||||
# Search for FluidSynth
|
||||
|
||||
include( ../FindFluidSynth.cmake )
|
||||
find_package( FluidSynth )
|
||||
|
||||
# Search for NASM
|
||||
|
||||
|
@ -346,7 +359,7 @@ endif( NOT NO_ASM )
|
|||
set( SSE_MATTERS NO )
|
||||
|
||||
# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it.
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "4" )
|
||||
if( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc )
|
||||
CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH )
|
||||
CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 )
|
||||
if( CAN_DO_MFPMATH )
|
||||
|
@ -358,7 +371,7 @@ if( CMAKE_SIZEOF_VOID_P MATCHES "4" )
|
|||
set( SSE2_ENABLE -arch:SSE2 )
|
||||
set( SSE_MATTERS YES )
|
||||
endif( CAN_DO_MFPMATH )
|
||||
endif( CMAKE_SIZEOF_VOID_P MATCHES "4" )
|
||||
endif( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc )
|
||||
|
||||
if( SSE_MATTERS )
|
||||
if( WIN32 )
|
||||
|
@ -380,8 +393,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" )
|
||||
|
@ -391,17 +403,17 @@ AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
|||
if( NOT PROFILE )
|
||||
set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
endif( NOT PROFILE )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_CXX_FLAGS}" )
|
||||
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_RELEASE "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" )
|
||||
set( CMAKE_CXX_FLAGS_MINSIZEREL "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" )
|
||||
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused" )
|
||||
set( CMAKE_CXX_FLAGS "-Wall -Wno-unused -Wextra -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS}" )
|
||||
|
||||
# Remove extra warnings when using the official DirectX headers.
|
||||
# Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid,
|
||||
# which is a royal pain. The previous version I had been using was fine with them.
|
||||
if( WIN32 )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas -Wno-comment -Wno-format" )
|
||||
set( CMAKE_CXX_FLAGS "-Wno-unknown-pragmas -Wno-comment -Wno-format ${CMAKE_CXX_FLAGS}" )
|
||||
endif( WIN32 )
|
||||
|
||||
if( NOT NO_STRIP )
|
||||
|
@ -432,13 +444,6 @@ if( NOT STRNICMP_EXISTS )
|
|||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif( NOT STRNICMP_EXISTS )
|
||||
|
||||
if( NOT WIN32 )
|
||||
CHECK_FUNCTION_EXISTS( sigtimedwait SIGTIMEDWAIT_EXISTS )
|
||||
if( SIGTIMEDWAIT_EXISTS )
|
||||
add_definitions( -DHAVE_SIGTIMEDWAIT )
|
||||
endif( SIGTIMEDWAIT_EXISTS )
|
||||
endif( NOT WIN32)
|
||||
|
||||
if( NOT MSVC )
|
||||
add_definitions( -D__forceinline=inline )
|
||||
endif( NOT MSVC )
|
||||
|
@ -538,13 +543,14 @@ 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
|
||||
sdl/sdlvideo.cpp
|
||||
sdl/st_start.cpp )
|
||||
if( APPLE )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm sdl/i_system_cocoa.mm )
|
||||
endif( APPLE )
|
||||
endif( WIN32 )
|
||||
|
||||
|
@ -609,6 +615,7 @@ add_executable( zdoom WIN32
|
|||
${SYSTEM_SOURCES}
|
||||
${X86_SOURCES}
|
||||
x86.cpp
|
||||
actorptrselect.cpp
|
||||
am_map.cpp
|
||||
b_bot.cpp
|
||||
b_func.cpp
|
||||
|
@ -641,7 +648,6 @@ add_executable( zdoom WIN32
|
|||
doomstat.cpp
|
||||
dsectoreffect.cpp
|
||||
dthinker.cpp
|
||||
f_finale.cpp
|
||||
f_wipe.cpp
|
||||
farchive.cpp
|
||||
files.cpp
|
||||
|
@ -655,17 +661,17 @@ add_executable( zdoom WIN32
|
|||
hu_scores.cpp
|
||||
i_net.cpp
|
||||
info.cpp
|
||||
keysections.cpp
|
||||
lumpconfigfile.cpp
|
||||
m_alloc.cpp
|
||||
m_argv.cpp
|
||||
m_bbox.cpp
|
||||
m_cheat.cpp
|
||||
m_joy.cpp
|
||||
m_menu.cpp
|
||||
m_misc.cpp
|
||||
m_options.cpp
|
||||
m_png.cpp
|
||||
m_random.cpp
|
||||
memarena.cpp
|
||||
md5.cpp
|
||||
name.cpp
|
||||
nodebuild.cpp
|
||||
|
@ -715,19 +721,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
|
||||
|
@ -735,11 +740,14 @@ 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
|
||||
v_blend.cpp
|
||||
v_collection.cpp
|
||||
v_draw.cpp
|
||||
v_font.cpp
|
||||
|
@ -794,6 +802,21 @@ 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
|
||||
menu/loadsavemenu.cpp
|
||||
menu/menu.cpp
|
||||
menu/menudef.cpp
|
||||
menu/menuinput.cpp
|
||||
menu/messagebox.cpp
|
||||
menu/optionmenu.cpp
|
||||
menu/playerdisplay.cpp
|
||||
menu/playermenu.cpp
|
||||
menu/readthis.cpp
|
||||
menu/videomenu.cpp
|
||||
oplsynth/fmopl.cpp
|
||||
oplsynth/mlopl.cpp
|
||||
oplsynth/mlopl_io.cpp
|
||||
|
@ -820,6 +843,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
|
||||
|
@ -829,6 +853,9 @@ add_executable( zdoom WIN32
|
|||
sound/music_softsynth_mididevice.cpp
|
||||
sound/music_timidity_mididevice.cpp
|
||||
sound/music_win_mididevice.cpp
|
||||
sound/music_pseudo_mididevice.cpp
|
||||
textures/animations.cpp
|
||||
textures/anim_switches.cpp
|
||||
textures/automaptexture.cpp
|
||||
textures/bitmap.cpp
|
||||
textures/buildtexture.cpp
|
||||
|
@ -853,6 +880,7 @@ add_executable( zdoom WIN32
|
|||
thingdef/thingdef_data.cpp
|
||||
thingdef/thingdef_exp.cpp
|
||||
thingdef/thingdef_expression.cpp
|
||||
thingdef/thingdef_function.cpp
|
||||
thingdef/thingdef_parse.cpp
|
||||
thingdef/thingdef_properties.cpp
|
||||
thingdef/thingdef_states.cpp
|
||||
|
@ -866,12 +894,29 @@ add_executable( zdoom WIN32
|
|||
timidity/resample.cpp
|
||||
timidity/timidity.cpp
|
||||
xlat/parse_xlat.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
|
||||
zscript/vmbuilder.cpp
|
||||
zscript/vmdisasm.cpp
|
||||
zscript/vmexec.cpp
|
||||
zscript/vmframe.cpp
|
||||
zscript/zcc_parser.cpp
|
||||
autozend.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" )
|
||||
|
|
|
@ -36,7 +36,7 @@ DEFINE_SPECIAL(ClearForceField, 34, 1, 1, 1) // [RH] Remove Strife's forcefie
|
|||
DEFINE_SPECIAL(Floor_RaiseByValueTimes8, 35, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Floor_LowerByValueTimes8, 36, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Floor_MoveToValue, 37, 3, 4, 4)
|
||||
DEFINE_SPECIAL(Ceiling_Waggle, 38, 5, 5, 4) // [RH] Complement of Floor_Waggle
|
||||
DEFINE_SPECIAL(Ceiling_Waggle, 38, 5, 5, 5) // [RH] Complement of Floor_Waggle
|
||||
DEFINE_SPECIAL(Teleport_ZombieChanger, 39, 2, 2, 2) // [RH] Needed for Strife
|
||||
DEFINE_SPECIAL(Ceiling_LowerByValue, 40, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Ceiling_RaiseByValue, 41, 3, 3, 3)
|
||||
|
@ -69,7 +69,7 @@ DEFINE_SPECIAL(Floor_RaiseInstant, 67, 3, 3, 3)
|
|||
DEFINE_SPECIAL(Floor_MoveToValueTimes8, 68, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Ceiling_MoveToValueTimes8, 69, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Teleport, 70, 1, 3, 3)
|
||||
DEFINE_SPECIAL(Teleport_NoFog, 71, 1, 3, 3)
|
||||
DEFINE_SPECIAL(Teleport_NoFog, 71, 1, 4, 4)
|
||||
DEFINE_SPECIAL(ThrustThing, 72, 2, 4, 4)
|
||||
DEFINE_SPECIAL(DamageThing, 73, 1, 2, 2)
|
||||
DEFINE_SPECIAL(Teleport_NewMap, 74, 2, 3, 3)
|
||||
|
@ -82,7 +82,7 @@ DEFINE_SPECIAL(ACS_Execute, 80, 1, 5, 5)
|
|||
DEFINE_SPECIAL(ACS_Suspend, 81, 2, 2, 2)
|
||||
DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2, 2)
|
||||
DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5, 5)
|
||||
DEFINE_SPECIAL(ACS_ExecuteWithResult, 84, 1, 4, 4)
|
||||
DEFINE_SPECIAL(ACS_ExecuteWithResult, 84, 1, 5, 5)
|
||||
DEFINE_SPECIAL(ACS_LockedExecuteDoor, 85, 5, 5, 5)
|
||||
DEFINE_SPECIAL(Polyobj_MoveToSpot, 86, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Polyobj_Stop, 87, 1, 1, 1)
|
||||
|
@ -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)
|
||||
|
@ -144,6 +146,7 @@ DEFINE_SPECIAL(Sector_Set3DFloor, 160, -1, -1, 5)
|
|||
DEFINE_SPECIAL(Sector_SetContents, 161, -1, -1, 3)
|
||||
|
||||
// [RH] Begin new specials for ZDoom
|
||||
DEFINE_SPECIAL(Ceiling_CrushAndRaiseDist, 168, 3, 5, 5)
|
||||
DEFINE_SPECIAL(Generic_Crusher2, 169, 5, 5, 5)
|
||||
DEFINE_SPECIAL(Sector_SetCeilingScale2, 170, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Sector_SetFloorScale2, 171, 3, 3, 3)
|
||||
|
@ -203,7 +206,7 @@ DEFINE_SPECIAL(Scroll_Ceiling, 224, 4, 4, 5)
|
|||
DEFINE_SPECIAL(Scroll_Texture_Offsets, 225, -1, -1, 1)
|
||||
DEFINE_SPECIAL(ACS_ExecuteAlways, 226, 1, 5, 5)
|
||||
DEFINE_SPECIAL(PointPush_SetForce, 227, -1, -1, 4)
|
||||
DEFINE_SPECIAL(Plat_RaiseAndStayTx0, 228, 2, 2, 2)
|
||||
DEFINE_SPECIAL(Plat_RaiseAndStayTx0, 228, 2, 3, 3)
|
||||
DEFINE_SPECIAL(Thing_SetGoal, 229, 3, 4, 4)
|
||||
DEFINE_SPECIAL(Plat_UpByValueStayTx, 230, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Plat_ToggleCeiling, 231, 1, 1, 1)
|
||||
|
@ -217,7 +220,7 @@ DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 2, 2)
|
|||
DEFINE_SPECIAL(Floor_RaiseByValueTxTy, 239, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Floor_RaiseByTexture, 240, 2, 2, 2)
|
||||
DEFINE_SPECIAL(Floor_LowerToLowestTxTy, 241, 2, 2, 2)
|
||||
DEFINE_SPECIAL(Floor_LowerToHighest, 242, 3, 3, 3)
|
||||
DEFINE_SPECIAL(Floor_LowerToHighest, 242, 3, 4, 4)
|
||||
DEFINE_SPECIAL(Exit_Normal, 243, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Exit_Secret, 244, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Elevator_RaiseToNearest, 245, 2, 2, 2)
|
||||
|
@ -226,7 +229,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, 4, 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)
|
||||
|
|
67
src/actor.h
67
src/actor.h
|
@ -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;
|
||||
class PClassAmmo;
|
||||
|
@ -267,11 +268,11 @@ enum
|
|||
|
||||
// --- mobj.flags5 ---
|
||||
|
||||
MF5_FASTER = 0x00000001, // moves faster when DF_FAST_MONSTERS or nightmare is on.
|
||||
MF5_FASTMELEE = 0x00000002, // has a faster melee attack when DF_FAST_MONSTERS or nightmare is on.
|
||||
/* = 0x00000001, */
|
||||
/* = 0x00000002, */
|
||||
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.
|
||||
|
@ -291,7 +292,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
|
||||
|
@ -325,6 +326,14 @@ 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.
|
||||
MF6_INTRYMOVE = 0x10000000, // Executing P_TryMove
|
||||
MF6_NOTAUTOAIMED = 0x20000000, // Do not subject actor to player autoaim.
|
||||
|
||||
// --- mobj.renderflags ---
|
||||
|
||||
|
@ -395,7 +404,7 @@ enum EBounceFlags
|
|||
BOUNCE_Ceilings = 1<<2, // bounces off of ceilings
|
||||
BOUNCE_Actors = 1<<3, // bounces off of some actors
|
||||
BOUNCE_AllActors = 1<<4, // bounces off of all actors (requires BOUNCE_Actors to be set, too)
|
||||
BOUNCE_AutoOff = 1<<5, // when bouncing off a floor, if the new Z velocity is below 3.0, disable further bouncing
|
||||
BOUNCE_AutoOff = 1<<5, // when bouncing off a sector plane, if the new Z velocity is below 3.0, disable further bouncing
|
||||
BOUNCE_HereticType = 1<<6, // goes into Death state when bouncing on floors or ceilings
|
||||
|
||||
BOUNCE_UseSeeSound = 1<<7, // compatibility fallback. This will only be set by
|
||||
|
@ -407,6 +416,7 @@ enum EBounceFlags
|
|||
// MBF bouncing is a bit different from other modes as Killough coded many special behavioral cases
|
||||
// for them that are not present in ZDoom, so it is necessary to identify it properly.
|
||||
BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag.
|
||||
BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors
|
||||
|
||||
BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF,
|
||||
|
||||
|
@ -509,7 +519,6 @@ public:
|
|||
int Amount;
|
||||
};
|
||||
|
||||
|
||||
// Map Object definition.
|
||||
class AActor : public DThinker
|
||||
{
|
||||
|
@ -557,11 +566,11 @@ public:
|
|||
virtual void Tick ();
|
||||
|
||||
// Called when actor dies
|
||||
virtual void Die (AActor *source, AActor *inflictor);
|
||||
virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0);
|
||||
|
||||
// Perform some special damage action. Returns the amount of damage to do.
|
||||
// Returning -1 signals the damage routine to exit immediately
|
||||
virtual int DoSpecialDamage (AActor *target, int damage);
|
||||
virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype);
|
||||
|
||||
// Like DoSpecialDamage, but called on the actor receiving the damage.
|
||||
virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype);
|
||||
|
@ -616,6 +625,9 @@ public:
|
|||
// Tosses an item out of the inventory.
|
||||
virtual AInventory *DropInventory (AInventory *item);
|
||||
|
||||
// Removes all items from the inventory.
|
||||
void ClearInventory();
|
||||
|
||||
// Returns true if this view is considered "local" for the player.
|
||||
bool CheckLocalView (int playernum) const;
|
||||
|
||||
|
@ -647,7 +659,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);
|
||||
|
@ -675,11 +687,14 @@ public:
|
|||
|
||||
// Return starting health adjusted by skill level
|
||||
int SpawnHealth() const;
|
||||
|
||||
int GetGibHealth() const;
|
||||
|
||||
fixed_t GetCameraHeight() const;
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -724,6 +739,10 @@ public:
|
|||
return bloodcls;
|
||||
}
|
||||
|
||||
inline void SetFriendPlayer(player_t *player);
|
||||
|
||||
bool IsVisibleToPlayer() const;
|
||||
|
||||
// Calculate amount of missile damage
|
||||
virtual int GetMissileDamage(int mask, int add);
|
||||
|
||||
|
@ -732,7 +751,10 @@ public:
|
|||
fixed_t GetGravity() const;
|
||||
bool IsSentient() const;
|
||||
const char *GetTag(const char *def = NULL) const;
|
||||
void SetTag(const char *def);
|
||||
|
||||
// Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector
|
||||
void CheckSectorTransition(sector_t *oldsec);
|
||||
|
||||
// info for drawing
|
||||
// NOTE: The first member variable *must* be x.
|
||||
|
@ -767,12 +789,17 @@ 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
|
||||
DWORD flags4; // [RH] Even more flags!
|
||||
DWORD flags5; // OMG! We need another one.
|
||||
DWORD flags6; // Shit! Where did all the flags go?
|
||||
|
||||
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
|
||||
DWORD VisibleToTeam;
|
||||
|
||||
int special1; // Special info
|
||||
int special2; // Special info
|
||||
int health;
|
||||
|
@ -804,6 +831,8 @@ public:
|
|||
int special; // special
|
||||
int args[5]; // special arguments
|
||||
|
||||
int accuracy, stamina; // [RH] Strife stats -- [XA] moved here for DECORATE/ACS access.
|
||||
|
||||
AActor *inext, **iprev;// Links to other mobjs in same bucket
|
||||
TObjPtr<AActor> goal; // Monster's goal if not chasing anything
|
||||
int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes
|
||||
|
@ -811,7 +840,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.
|
||||
|
@ -827,16 +856,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.
|
||||
|
@ -873,8 +905,12 @@ public:
|
|||
SWORD PainChance;
|
||||
int PainThreshold;
|
||||
FNameNoInit DamageType;
|
||||
FNameNoInit DamageTypeReceived;
|
||||
fixed_t DamageFactor;
|
||||
|
||||
FNameNoInit PainType;
|
||||
FNameNoInit DeathType;
|
||||
|
||||
FState *SpawnState;
|
||||
FState *SeeState;
|
||||
FState *MeleeState;
|
||||
|
@ -899,6 +935,7 @@ public:
|
|||
private:
|
||||
static AActor *TIDHash[128];
|
||||
static inline int TIDHASH (int key) { return key & 127; }
|
||||
static FSharedStringArena mStringPropertyData;
|
||||
|
||||
friend class FActorIterator;
|
||||
|
||||
|
@ -916,6 +953,7 @@ public:
|
|||
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
|
||||
bool isFast();
|
||||
void SetIdle();
|
||||
void ClearCounters();
|
||||
|
||||
FState *FindState (FName label) const
|
||||
{
|
||||
|
@ -1007,6 +1045,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
179
src/actorptrselect.cpp
Normal 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;
|
||||
}
|
||||
}
|
93
src/actorptrselect.h
Normal file
93
src/actorptrselect.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
#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);
|
||||
|
||||
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) ;
|
||||
|
540
src/am_map.cpp
540
src/am_map.cpp
|
@ -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,29 @@ 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;
|
||||
static TArray<mline_t> EasyKey;
|
||||
|
||||
#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 +336,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 +351,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 +402,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 +427,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 +499,78 @@ 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();
|
||||
EasyKey.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");
|
||||
AM_ParseArrow(EasyKey, "maparrows/ravenkey.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 +625,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 +822,7 @@ void AM_changeWindowLoc ()
|
|||
{
|
||||
if (0 != (m_paninc.x | m_paninc.y))
|
||||
{
|
||||
followplayer = 0;
|
||||
am_followplayer = false;
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
}
|
||||
|
||||
|
@ -868,18 +894,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 +902,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 +915,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 +929,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 +972,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 +994,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 +1016,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 +1032,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 +1056,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 +1095,6 @@ void AM_Start ()
|
|||
if (!stopped) AM_Stop();
|
||||
stopped = false;
|
||||
AM_initVariables();
|
||||
AM_loadPics();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1228,7 +1206,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 +1253,10 @@ void AM_changeWindowScale ()
|
|||
{
|
||||
mtof_zoommul = int(M_ZOOMOUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtof_zoommul = MAPUNIT;
|
||||
}
|
||||
am_zoomdir = 0;
|
||||
|
||||
// Change the scaling multipliers
|
||||
|
@ -1341,7 +1323,7 @@ void AM_Ticker ()
|
|||
|
||||
amclock++;
|
||||
|
||||
if (followplayer)
|
||||
if (am_followplayer)
|
||||
{
|
||||
AM_doFollowPlayer();
|
||||
}
|
||||
|
@ -1484,28 +1466,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 +1543,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 +1637,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 +1657,65 @@ 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 seczb, seczt;
|
||||
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]);
|
||||
}
|
||||
seczb = floorplane->ZatPoint(secx, secy);
|
||||
seczt = sec->ceilingplane.ZatPoint(secx, secy);
|
||||
|
||||
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;
|
||||
double roverz = rover->top.plane->ZatPoint(secx, secy);
|
||||
// Ignore 3D floors that are above or below the sector itself:
|
||||
// they are hidden. Since 3D floors are sorted top to bottom,
|
||||
// if we get below the sector floor, we can stop.
|
||||
if (roverz > seczt) continue;
|
||||
if (roverz < seczb) break;
|
||||
if (roverz < 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,16 +1731,19 @@ void AM_drawSubsectors()
|
|||
}
|
||||
|
||||
// Draw the polygon.
|
||||
screen->FillSimplePoly(
|
||||
TexMan(sec->GetTexture(sector_t::floor)),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
rotation,
|
||||
colormap,
|
||||
floorlight
|
||||
);
|
||||
FTexture *pic = TexMan(maptex);
|
||||
if (pic != NULL && pic->UseType != FTexture::TEX_Null)
|
||||
{
|
||||
screen->FillSimplePoly(TexMan(maptex),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
rotation,
|
||||
colormap,
|
||||
floorlight
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1806,6 +1849,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.
|
||||
|
@ -1817,6 +1923,7 @@ void AM_drawWalls (bool allmap)
|
|||
{
|
||||
int i;
|
||||
static mline_t l;
|
||||
int lock, color;
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
|
@ -1852,8 +1959,16 @@ void AM_drawWalls (bool allmap)
|
|||
AM_drawMline(&l, SecretWallColor);
|
||||
else
|
||||
AM_drawMline(&l, WallColor);
|
||||
}
|
||||
else if ((lines[i].special == Teleport ||
|
||||
} else if (lines[i].locknumber > 0) { // [Dusk] specials w/ locknumbers
|
||||
lock = lines[i].locknumber;
|
||||
color = P_GetMapColorForLock(lock);
|
||||
|
||||
AMColor c;
|
||||
if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color));
|
||||
else c = LockedColor;
|
||||
|
||||
AM_drawMline (&l, c);
|
||||
} else if ((lines[i].special == Teleport ||
|
||||
lines[i].special == Teleport_NoFog ||
|
||||
lines[i].special == Teleport_ZombieChanger ||
|
||||
lines[i].special == Teleport_Line) &&
|
||||
|
@ -1873,17 +1988,18 @@ 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);
|
||||
color = P_GetMapColorForLock(lock);
|
||||
|
||||
AMColor c;
|
||||
|
||||
|
@ -1897,6 +2013,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 +2038,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 +2192,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 +2253,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2138,6 +2264,49 @@ void AM_drawPlayers ()
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_drawKeys ()
|
||||
{
|
||||
AMColor color;
|
||||
mpoint_t p;
|
||||
angle_t angle;
|
||||
|
||||
TThinkerIterator<AKey> it;
|
||||
AKey *key;
|
||||
|
||||
while ((key = it.Next()) != NULL)
|
||||
{
|
||||
p.x = key->x >> FRACTOMAPBITS;
|
||||
p.y = key->y >> FRACTOMAPBITS;
|
||||
angle = key->angle;
|
||||
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
AM_rotatePoint (&p.x, &p.y);
|
||||
angle += ANG90 - players[consoleplayer].camera->angle;
|
||||
}
|
||||
|
||||
color = ThingColor;
|
||||
if (key->flags & MF_SPECIAL)
|
||||
{
|
||||
// Find the key's own color.
|
||||
// Only works correctly if single-key locks have lower numbers than any-key locks.
|
||||
// That is the case for all default keys, however.
|
||||
int P_GetMapColorForKey (AInventory * key);
|
||||
int c = P_GetMapColorForKey(key);
|
||||
|
||||
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
|
||||
else color = ThingColor_CountItem;
|
||||
AM_drawLineCharacter(&EasyKey[0], EasyKey.Size(), 0, 0, color, p.x, p.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_drawThings ()
|
||||
{
|
||||
AMColor color;
|
||||
|
@ -2176,14 +2345,19 @@ void AM_drawThings ()
|
|||
// That is the case for all default keys, however.
|
||||
if (t->IsKindOf(RUNTIME_CLASS(AKey)))
|
||||
{
|
||||
if (am_showkeys)
|
||||
if (G_SkillProperty(SKILLP_EasyKey))
|
||||
{
|
||||
// Already drawn by AM_drawKeys(), so don't draw again
|
||||
color.Index = -1;
|
||||
}
|
||||
else if (am_showkeys)
|
||||
{
|
||||
int P_GetMapColorForKey (AInventory * key);
|
||||
int c = P_GetMapColorForKey(static_cast<AKey *>(t));
|
||||
|
||||
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
|
||||
|
@ -2398,6 +2572,8 @@ void AM_Drawer ()
|
|||
|
||||
AM_drawWalls(allmap);
|
||||
AM_drawPlayers();
|
||||
if (G_SkillProperty(SKILLP_EasyKey))
|
||||
AM_drawKeys();
|
||||
if (am_cheat >= 2 || allthings)
|
||||
AM_drawThings();
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
struct event_t;
|
||||
class FArchive;
|
||||
|
||||
|
||||
void AM_StaticInit();
|
||||
|
||||
// Called by main loop.
|
||||
bool AM_Responder (event_t* ev, bool last);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
{
|
||||
|
@ -478,6 +474,7 @@ static void appendinfo (char *&front, const char *back)
|
|||
{
|
||||
size_t newlen = strlen (back) + 2;
|
||||
newstr = new char[newlen];
|
||||
newstr[0] = 0;
|
||||
}
|
||||
strcat (newstr, "\\");
|
||||
strcat (newstr, back);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
||||
|
@ -583,7 +583,7 @@ void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second)
|
||||
int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
|
@ -609,7 +609,7 @@ int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindACommand (char *str)
|
||||
void FKeyBindings::UnbindACommand (const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -829,6 +829,7 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
|
|||
bool dclick;
|
||||
int dclickspot;
|
||||
BYTE dclickmask;
|
||||
unsigned int nowtime;
|
||||
|
||||
if (ev->type != EV_KeyDown && ev->type != EV_KeyUp)
|
||||
return false;
|
||||
|
@ -841,10 +842,11 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
|
|||
dclick = false;
|
||||
|
||||
// This used level.time which didn't work outside a level.
|
||||
if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown)
|
||||
nowtime = I_MSTime();
|
||||
if (doublebinds != NULL && DClickTime[ev->data1] > nowtime && ev->type == EV_KeyDown)
|
||||
{
|
||||
// Key pressed for a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] |= dclickmask;
|
||||
dclick = true;
|
||||
}
|
||||
|
@ -853,11 +855,11 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
|
|||
if (ev->type == EV_KeyDown)
|
||||
{ // Key pressed for a normal press
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
DClickTime[ev->data1] = I_MSTime() + 571;
|
||||
DClickTime[ev->data1] = nowtime + 571;
|
||||
}
|
||||
else if (DClicked[dclickspot] & dclickmask)
|
||||
else if (doublebinds != NULL && DClicked[dclickspot] & dclickmask)
|
||||
{ // Key released from a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] &= ~dclickmask;
|
||||
DClickTime[ev->data1] = 0;
|
||||
dclick = true;
|
||||
|
|
19
src/c_bind.h
19
src/c_bind.h
|
@ -57,8 +57,8 @@ public:
|
|||
void SetBinds(const FBinding *binds);
|
||||
bool DoKey(event_t *ev);
|
||||
void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL);
|
||||
int GetKeysForCommand (char *cmd, int *first, int *second);
|
||||
void UnbindACommand (char *str);
|
||||
int GetKeysForCommand (const char *cmd, int *first, int *second);
|
||||
void UnbindACommand (const char *str);
|
||||
void UnbindAll ();
|
||||
void UnbindKey(const char *key);
|
||||
void DoBind (const char *key, const char *bind);
|
||||
|
@ -85,6 +85,7 @@ public:
|
|||
extern FKeyBindings Bindings;
|
||||
extern FKeyBindings DoubleBindings;
|
||||
extern FKeyBindings AutomapBindings;
|
||||
extern FKeyBindings MenuBindings;
|
||||
|
||||
|
||||
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds);
|
||||
|
@ -95,4 +96,18 @@ void C_UnbindAll ();
|
|||
|
||||
extern const char *KeyNames[];
|
||||
|
||||
struct FKeyAction
|
||||
{
|
||||
FString mTitle;
|
||||
FString mAction;
|
||||
};
|
||||
|
||||
struct FKeySection
|
||||
{
|
||||
FString mTitle;
|
||||
FString mSection;
|
||||
TArray<FKeyAction> mActions;
|
||||
};
|
||||
extern TArray<FKeySection> KeySections;
|
||||
|
||||
#endif //__C_BINDINGS_H__
|
||||
|
|
246
src/c_cmds.cpp
246
src/c_cmds.cpp
|
@ -30,8 +30,6 @@
|
|||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** It might be a good idea to move these into files that they are more
|
||||
** closely related to, but right now, I am too lazy to do that.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
@ -61,13 +59,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;
|
||||
|
@ -449,9 +449,9 @@ CCMD (puke)
|
|||
{
|
||||
int argc = argv.argc();
|
||||
|
||||
if (argc < 2 || argc > 5)
|
||||
if (argc < 2 || argc > 6)
|
||||
{
|
||||
Printf (" puke <script> [arg1] [arg2] [arg3]\n");
|
||||
Printf ("Usage: puke <script> [arg1] [arg2] [arg3] [arg4]\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -461,8 +461,8 @@ CCMD (puke)
|
|||
{ // Script 0 is reserved for Strife support. It is not pukable.
|
||||
return;
|
||||
}
|
||||
int arg[3] = { 0, 0, 0 };
|
||||
int argn = MIN (argc - 2, 3), i;
|
||||
int arg[4] = { 0, 0, 0, 0 };
|
||||
int argn = MIN<int>(argc - 2, countof(arg)), i;
|
||||
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
|
@ -487,6 +487,90 @@ CCMD (puke)
|
|||
}
|
||||
}
|
||||
|
||||
CCMD (pukename)
|
||||
{
|
||||
int argc = argv.argc();
|
||||
|
||||
if (argc < 2 || argc > 7)
|
||||
{
|
||||
Printf ("Usage: pukename \"<script>\" [\"always\"] [arg1] [arg2] [arg3] [arg4]\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool always = false;
|
||||
int argstart = 2;
|
||||
int arg[4] = { 0, 0, 0, 0 };
|
||||
int argn = 0, i;
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
if (stricmp(argv[2], "always") == 0)
|
||||
{
|
||||
always = true;
|
||||
argstart = 3;
|
||||
}
|
||||
argn = MIN<int>(argc - argstart, countof(arg));
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
arg[i] = atoi(argv[argstart + i]);
|
||||
}
|
||||
}
|
||||
Net_WriteByte(DEM_RUNNAMEDSCRIPT);
|
||||
Net_WriteString(argv[1]);
|
||||
Net_WriteByte(argn | (always << 7));
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
Net_WriteLong(arg[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +698,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 +987,7 @@ CCMD(nextsecret)
|
|||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CCMD(currentpos)
|
||||
{
|
||||
AActor *mo = players[consoleplayer].mo;
|
||||
|
@ -936,7 +995,6 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
@ -964,3 +1022,123 @@ CCMD(vmengine)
|
|||
}
|
||||
Printf("Usage: vmengine <default|checked|unchecked>\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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);
|
||||
const char *ln = !(info->flags & LEVEL_LOOKUPLEVELNAME)? info->LevelName.GetChars() : GStrings[info->LevelName.GetChars()];
|
||||
levelname.Format("%s - %s\n", mapname, ln);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
@ -773,7 +768,7 @@ void AddToConsole (int printlevel, const char *text)
|
|||
// The line start is outside the buffer.
|
||||
// Make space for the newly inserted stuff.
|
||||
size_t movesize = work-linestart;
|
||||
memmove(work + movesize, work, strlen(work));
|
||||
memmove(work + movesize, work, strlen(work)+1);
|
||||
work_p += movesize;
|
||||
linestart = work;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
133
src/c_cvars.cpp
133
src/c_cvars.cpp
|
@ -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
|
||||
//
|
||||
|
@ -1119,7 +1138,7 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
|
|||
// exec scripts because all flags will base their changes off of the value of
|
||||
// the "master" cvar at the time the script was run, overriding any changes
|
||||
// another flag might have made to the same cvar earlier in the script.
|
||||
if ((ValueVar.Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
{
|
||||
if (netgame && !players[consoleplayer].settings_controller)
|
||||
{
|
||||
|
@ -1139,6 +1158,114 @@ void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Mask cvar implementation
|
||||
//
|
||||
// Similar to FFlagCVar but can have multiple bits
|
||||
//
|
||||
|
||||
FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, DWORD bitval)
|
||||
: FBaseCVar (name, 0, NULL),
|
||||
ValueVar (realvar),
|
||||
BitVal (bitval)
|
||||
{
|
||||
int bit;
|
||||
|
||||
Flags &= ~CVAR_ISDEFAULT;
|
||||
|
||||
assert (bitval != 0);
|
||||
|
||||
bit = 0;
|
||||
while ((bitval & 1) == 0)
|
||||
{
|
||||
++bit;
|
||||
bitval >>= 1;
|
||||
}
|
||||
BitNum = bit;
|
||||
}
|
||||
|
||||
ECVarType FMaskCVar::GetRealType () const
|
||||
{
|
||||
return CVAR_Dummy;
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const
|
||||
{
|
||||
return FromInt ((ValueVar & BitVal) >> BitNum, type);
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const
|
||||
{
|
||||
UCVarValue ret;
|
||||
*type = CVAR_Int;
|
||||
ret.Int = (ValueVar & BitVal) >> BitNum;
|
||||
return ret;
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const
|
||||
{
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
return FromInt ((def.Int & BitVal) >> BitNum, type);
|
||||
}
|
||||
|
||||
UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const
|
||||
{
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
def.Int = (def.Int & BitVal) >> BitNum;
|
||||
*type = CVAR_Int;
|
||||
return def;
|
||||
}
|
||||
|
||||
void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
|
||||
{
|
||||
int val = ToInt(value, type) << BitNum;
|
||||
ECVarType dummy;
|
||||
UCVarValue def;
|
||||
def = ValueVar.GetFavoriteRepDefault (&dummy);
|
||||
def.Int &= ~BitVal;
|
||||
def.Int |= val;
|
||||
ValueVar.SetGenericRepDefault (def, CVAR_Int);
|
||||
}
|
||||
|
||||
void FMaskCVar::DoSet (UCVarValue value, ECVarType type)
|
||||
{
|
||||
int val = ToInt(value, type) << BitNum;
|
||||
|
||||
// Server cvars that get changed by this need to use a special message, because
|
||||
// changes are not processed until the next net update. This is a problem with
|
||||
// exec scripts because all flags will base their changes off of the value of
|
||||
// the "master" cvar at the time the script was run, overriding any changes
|
||||
// another flag might have made to the same cvar earlier in the script.
|
||||
if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
|
||||
{
|
||||
if (netgame && !players[consoleplayer].settings_controller)
|
||||
{
|
||||
Printf ("Only setting controllers can change %s\n", Name);
|
||||
return;
|
||||
}
|
||||
// Ugh...
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
if (BitVal & (1<<i))
|
||||
{
|
||||
D_SendServerFlagChange (&ValueVar, i, !!(val & (1<<i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int vval = *ValueVar;
|
||||
vval &= ~BitVal;
|
||||
vval |= val;
|
||||
ValueVar = vval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
static int STACK_ARGS sortcvars (const void *a, const void *b)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
@ -344,6 +345,30 @@ protected:
|
|||
int BitNum;
|
||||
};
|
||||
|
||||
class FMaskCVar : public FBaseCVar
|
||||
{
|
||||
public:
|
||||
FMaskCVar (const char *name, FIntCVar &realvar, uint32 bitval);
|
||||
|
||||
virtual ECVarType GetRealType () const;
|
||||
|
||||
virtual UCVarValue GetGenericRep (ECVarType type) const;
|
||||
virtual UCVarValue GetFavoriteRep (ECVarType *type) const;
|
||||
virtual UCVarValue GetGenericRepDefault (ECVarType type) const;
|
||||
virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const;
|
||||
virtual void SetGenericRepDefault (UCVarValue value, ECVarType type);
|
||||
|
||||
inline operator int () const { return (ValueVar & BitVal) >> BitNum; }
|
||||
inline int operator *() const { return (ValueVar & BitVal) >> BitNum; }
|
||||
|
||||
protected:
|
||||
virtual void DoSet (UCVarValue value, ECVarType type);
|
||||
|
||||
FIntCVar &ValueVar;
|
||||
uint32 BitVal;
|
||||
int BitNum;
|
||||
};
|
||||
|
||||
class FGUIDCVar : public FBaseCVar
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -550,7 +550,7 @@ exists: if (p != NULL)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// strbin1 -- In-place version
|
||||
// strbin -- In-place version
|
||||
//
|
||||
// [RH] Replaces the escape sequences in a string with actual escaped characters.
|
||||
// This operation is done in-place. The result is the new length of the string.
|
||||
|
@ -600,18 +600,20 @@ int strbin (char *str)
|
|||
case 'x':
|
||||
case 'X':
|
||||
c = 0;
|
||||
p++;
|
||||
for (i = 0; i < 2; i++) {
|
||||
c <<= 4;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c += *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c += 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c += 10 + *p-'A';
|
||||
else
|
||||
break;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c = (c << 4) + *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c = (c << 4) + 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c = (c << 4) + 10 + *p-'A';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str++ = c;
|
||||
break;
|
||||
|
@ -650,7 +652,7 @@ int strbin (char *str)
|
|||
// strbin1 -- String-creating version
|
||||
//
|
||||
// [RH] Replaces the escape sequences in a string with actual escaped characters.
|
||||
// This operation is done in-place.
|
||||
// The result is a new string.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -698,18 +700,20 @@ FString strbin1 (const char *start)
|
|||
case 'x':
|
||||
case 'X':
|
||||
c = 0;
|
||||
p++;
|
||||
for (i = 0; i < 2; i++) {
|
||||
c <<= 4;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c += *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c += 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c += 10 + *p-'A';
|
||||
else
|
||||
break;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c = (c << 4) + *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c = (c << 4) + 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c = (c << 4) + 10 + *p-'A';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result << c;
|
||||
break;
|
||||
|
@ -1004,7 +1008,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 +1017,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 +1043,6 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
|||
}
|
||||
}
|
||||
fts_close(fts);
|
||||
delete[] argv[0];
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -59,7 +59,14 @@ struct FCompatOption
|
|||
{
|
||||
const char *Name;
|
||||
int CompatFlags;
|
||||
int BCompatFlags;
|
||||
int WhichSlot;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SLOT_COMPAT,
|
||||
SLOT_COMPAT2,
|
||||
SLOT_BCOMPAT
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -67,7 +74,9 @@ enum
|
|||
CP_END,
|
||||
CP_CLEARFLAGS,
|
||||
CP_SETFLAGS,
|
||||
CP_SETSPECIAL
|
||||
CP_SETSPECIAL,
|
||||
CP_CLEARSPECIAL,
|
||||
CP_SETACTIVATION
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -86,39 +95,44 @@ TMap<FMD5Holder, FCompatValues, FMD5HashTraits> BCompatMap;
|
|||
|
||||
static FCompatOption Options[] =
|
||||
{
|
||||
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
|
||||
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
|
||||
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
|
||||
{ "setslopeoverflow", BCOMPATF_SETSLOPEOVERFLOW, SLOT_BCOMPAT },
|
||||
{ "resetplayerspeed", BCOMPATF_RESETPLAYERSPEED, SLOT_BCOMPAT },
|
||||
{ "vileghosts", BCOMPATF_VILEGHOSTS, SLOT_BCOMPAT },
|
||||
{ "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT },
|
||||
|
||||
// list copied from g_mapinfo.cpp
|
||||
{ "shorttex", COMPATF_SHORTTEX, 0 },
|
||||
{ "stairs", COMPATF_STAIRINDEX, 0 },
|
||||
{ "limitpain", COMPATF_LIMITPAIN, 0 },
|
||||
{ "nopassover", COMPATF_NO_PASSMOBJ, 0 },
|
||||
{ "notossdrops", COMPATF_NOTOSSDROPS, 0 },
|
||||
{ "useblocking", COMPATF_USEBLOCKING, 0 },
|
||||
{ "nodoorlight", COMPATF_NODOORLIGHT, 0 },
|
||||
{ "ravenscroll", COMPATF_RAVENSCROLL, 0 },
|
||||
{ "soundtarget", COMPATF_SOUNDTARGET, 0 },
|
||||
{ "dehhealth", COMPATF_DEHHEALTH, 0 },
|
||||
{ "trace", COMPATF_TRACE, 0 },
|
||||
{ "dropoff", COMPATF_DROPOFF, 0 },
|
||||
{ "boomscroll", COMPATF_BOOMSCROLL, 0 },
|
||||
{ "invisibility", COMPATF_INVISIBILITY, 0 },
|
||||
{ "silentinstantfloors", COMPATF_SILENT_INSTANT_FLOORS, 0 },
|
||||
{ "sectorsounds", COMPATF_SECTORSOUNDS, 0 },
|
||||
{ "missileclip", COMPATF_MISSILECLIP, 0 },
|
||||
{ "crossdropoff", COMPATF_CROSSDROPOFF, 0 },
|
||||
{ "wallrun", COMPATF_WALLRUN, 0 }, // [GZ] Added for CC MAP29
|
||||
{ "anybossdeath", COMPATF_ANYBOSSDEATH, 0}, // [GZ] Added for UAC_DEAD
|
||||
{ "mushroom", COMPATF_MUSHROOM, 0},
|
||||
{ "mbfmonstermove", COMPATF_MBFMONSTERMOVE, 0 },
|
||||
{ "corpsegibs", COMPATF_CORPSEGIBS, 0 },
|
||||
{ "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 },
|
||||
{ "spritesort", COMPATF_SPRITESORT, 0 },
|
||||
{ "hitscan", COMPATF_HITSCAN, 0 },
|
||||
{ "lightlevel", COMPATF_LIGHT, 0 },
|
||||
{ "polyobj", COMPATF_POLYOBJ, 0 },
|
||||
{ "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT },
|
||||
{ "stairs", COMPATF_STAIRINDEX, SLOT_COMPAT },
|
||||
{ "limitpain", COMPATF_LIMITPAIN, SLOT_COMPAT },
|
||||
{ "nopassover", COMPATF_NO_PASSMOBJ, SLOT_COMPAT },
|
||||
{ "notossdrops", COMPATF_NOTOSSDROPS, SLOT_COMPAT },
|
||||
{ "useblocking", COMPATF_USEBLOCKING, SLOT_COMPAT },
|
||||
{ "nodoorlight", COMPATF_NODOORLIGHT, SLOT_COMPAT },
|
||||
{ "ravenscroll", COMPATF_RAVENSCROLL, SLOT_COMPAT },
|
||||
{ "soundtarget", COMPATF_SOUNDTARGET, SLOT_COMPAT },
|
||||
{ "dehhealth", COMPATF_DEHHEALTH, SLOT_COMPAT },
|
||||
{ "trace", COMPATF_TRACE, SLOT_COMPAT },
|
||||
{ "dropoff", COMPATF_DROPOFF, SLOT_COMPAT },
|
||||
{ "boomscroll", COMPATF_BOOMSCROLL, SLOT_COMPAT },
|
||||
{ "invisibility", COMPATF_INVISIBILITY, SLOT_COMPAT },
|
||||
{ "silentinstantfloors", COMPATF_SILENT_INSTANT_FLOORS, SLOT_COMPAT },
|
||||
{ "sectorsounds", COMPATF_SECTORSOUNDS, SLOT_COMPAT },
|
||||
{ "missileclip", COMPATF_MISSILECLIP, SLOT_COMPAT },
|
||||
{ "crossdropoff", COMPATF_CROSSDROPOFF, SLOT_COMPAT },
|
||||
{ "wallrun", COMPATF_WALLRUN, SLOT_COMPAT }, // [GZ] Added for CC MAP29
|
||||
{ "anybossdeath", COMPATF_ANYBOSSDEATH, SLOT_COMPAT },// [GZ] Added for UAC_DEAD
|
||||
{ "mushroom", COMPATF_MUSHROOM, SLOT_COMPAT },
|
||||
{ "mbfmonstermove", COMPATF_MBFMONSTERMOVE, SLOT_COMPAT },
|
||||
{ "corpsegibs", COMPATF_CORPSEGIBS, SLOT_COMPAT },
|
||||
{ "noblockfriends", COMPATF_NOBLOCKFRIENDS, SLOT_COMPAT },
|
||||
{ "spritesort", COMPATF_SPRITESORT, SLOT_COMPAT },
|
||||
{ "hitscan", COMPATF_HITSCAN, SLOT_COMPAT },
|
||||
{ "lightlevel", COMPATF_LIGHT, SLOT_COMPAT },
|
||||
{ "polyobj", COMPATF_POLYOBJ, SLOT_COMPAT },
|
||||
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT },
|
||||
{ "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 },
|
||||
{ "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 },
|
||||
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -141,6 +155,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"));
|
||||
|
@ -184,15 +201,13 @@ void ParseCompatibility()
|
|||
md5array.Push(md5);
|
||||
sc.MustGetString();
|
||||
} while (!sc.Compare("{"));
|
||||
flags.CompatFlags = 0;
|
||||
flags.BCompatFlags = 0;
|
||||
memset(flags.CompatFlags, 0, sizeof(flags.CompatFlags));
|
||||
flags.ExtCommandIndex = ~0u;
|
||||
while (sc.GetString())
|
||||
{
|
||||
if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0)
|
||||
{
|
||||
flags.CompatFlags |= Options[i].CompatFlags;
|
||||
flags.BCompatFlags |= Options[i].BCompatFlags;
|
||||
flags.CompatFlags[Options[i].WhichSlot] |= Options[i].CompatFlags;
|
||||
}
|
||||
else if (sc.Compare("clearlineflags"))
|
||||
{
|
||||
|
@ -221,12 +236,28 @@ void ParseCompatibility()
|
|||
|
||||
sc.MustGetString();
|
||||
CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL));
|
||||
for(int i=0;i<5;i++)
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("clearlinespecial"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_CLEARSPECIAL);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
else if (sc.Compare("setactivation"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETACTIVATION);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet();
|
||||
|
@ -256,62 +287,83 @@ void CheckCompatibility(MapData *map)
|
|||
{
|
||||
FMD5Holder md5;
|
||||
FCompatValues *flags;
|
||||
bool onlyparams = true;
|
||||
|
||||
// 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;
|
||||
ii_compatflags2 = 0;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
else if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATPOLY1) && Wads.CheckLumpName(map->lumpnum, "MAP36"))
|
||||
{
|
||||
ii_compatflags = COMPATF_POLYOBJ;
|
||||
ii_compatflags2 = 0;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
else if (Wads.GetLumpFile(map->lumpnum) == 2 && (gameinfo.flags & GI_COMPATPOLY2) && Wads.CheckLumpName(map->lumpnum, "MAP47"))
|
||||
{
|
||||
ii_compatflags = COMPATF_POLYOBJ;
|
||||
ii_compatflags2 = 0;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
map->GetChecksum(md5.Bytes);
|
||||
onlyparams = false;
|
||||
}
|
||||
|
||||
flags = BCompatMap.CheckKey(md5);
|
||||
map->GetChecksum(md5.Bytes);
|
||||
|
||||
if (developer)
|
||||
flags = BCompatMap.CheckKey(md5);
|
||||
|
||||
if (developer)
|
||||
{
|
||||
Printf("MD5 = ");
|
||||
for (size_t j = 0; j < sizeof(md5.Bytes); ++j)
|
||||
{
|
||||
Printf("MD5 = ");
|
||||
for (size_t j = 0; j < sizeof(md5.Bytes); ++j)
|
||||
{
|
||||
Printf("%02X", md5.Bytes[j]);
|
||||
}
|
||||
if (flags != NULL) Printf(", cflags = %08x, bflags = %08x\n", flags->CompatFlags, flags->BCompatFlags);
|
||||
else Printf("\n");
|
||||
Printf("%02X", md5.Bytes[j]);
|
||||
}
|
||||
|
||||
if (flags != NULL)
|
||||
{
|
||||
ii_compatflags = flags->CompatFlags;
|
||||
ib_compatflags = flags->BCompatFlags;
|
||||
ii_compatparams = flags->ExtCommandIndex;
|
||||
Printf(", cflags = %08x, cflags2 = %08x, bflags = %08x\n",
|
||||
flags->CompatFlags[SLOT_COMPAT], flags->CompatFlags[SLOT_COMPAT2], flags->CompatFlags[SLOT_BCOMPAT]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ii_compatflags = 0;
|
||||
ib_compatflags = 0;
|
||||
ii_compatparams = -1;
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags != NULL)
|
||||
{
|
||||
if (!onlyparams)
|
||||
{
|
||||
ii_compatflags = flags->CompatFlags[SLOT_COMPAT];
|
||||
ii_compatflags2 = flags->CompatFlags[SLOT_COMPAT2];
|
||||
ib_compatflags = flags->CompatFlags[SLOT_BCOMPAT];
|
||||
}
|
||||
ii_compatparams = flags->ExtCommandIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!onlyparams)
|
||||
{
|
||||
ii_compatflags = 0;
|
||||
ii_compatflags2 = 0;
|
||||
ib_compatflags = 0;
|
||||
}
|
||||
ii_compatparams = -1;
|
||||
}
|
||||
// Reset i_compatflags
|
||||
compatflags.Callback();
|
||||
compatflags2.Callback();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -364,6 +416,27 @@ void SetCompatibilityParams()
|
|||
i+=8;
|
||||
break;
|
||||
}
|
||||
case CP_CLEARSPECIAL:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line->special = 0;
|
||||
memset(line->args, 0, sizeof(line->args));
|
||||
}
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
case CP_SETACTIVATION:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
{
|
||||
line_t *line = &lines[CompatParams[i+1]];
|
||||
line->activation = CompatParams[i+2];
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -412,5 +485,5 @@ CCMD (mapchecksum)
|
|||
|
||||
CCMD (hiddencompatflags)
|
||||
{
|
||||
Printf("%08x %08x\n", ii_compatflags, ib_compatflags);
|
||||
Printf("%08x %08x %08x\n", ii_compatflags, ii_compatflags2, ib_compatflags);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,7 @@ union FMD5Holder
|
|||
|
||||
struct FCompatValues
|
||||
{
|
||||
int CompatFlags;
|
||||
int BCompatFlags;
|
||||
int CompatFlags[3];
|
||||
unsigned int ExtCommandIndex;
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ FConfigFile::FConfigFile ()
|
|||
LastSectionPtr = &Sections;
|
||||
CurrentEntry = NULL;
|
||||
PathName = "";
|
||||
OkayToWrite = true;
|
||||
FileExisted = true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -70,6 +72,8 @@ FConfigFile::FConfigFile (const char *pathname,
|
|||
CurrentEntry = NULL;
|
||||
ChangePathName (pathname);
|
||||
LoadConfigFile (nosechandler, userdata);
|
||||
OkayToWrite = true;
|
||||
FileExisted = true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -85,6 +89,8 @@ FConfigFile::FConfigFile (const FConfigFile &other)
|
|||
CurrentEntry = NULL;
|
||||
ChangePathName (other.PathName);
|
||||
*this = other;
|
||||
OkayToWrite = other.OkayToWrite;
|
||||
FileExisted = other.FileExisted;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -587,11 +593,15 @@ void FConfigFile::LoadConfigFile (void (*nosechandler)(const char *pathname, FCo
|
|||
FILE *file = fopen (PathName, "r");
|
||||
bool succ;
|
||||
|
||||
FileExisted = false;
|
||||
if (file == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
succ = ReadConfig (file);
|
||||
fclose (file);
|
||||
FileExisted = succ;
|
||||
|
||||
if (!succ)
|
||||
{ // First valid line did not define a section
|
||||
|
@ -695,6 +705,13 @@ char *FConfigFile::ReadLine (char *string, int n, void *file) const
|
|||
|
||||
bool FConfigFile::WriteConfigFile () const
|
||||
{
|
||||
if (!OkayToWrite && FileExisted)
|
||||
{ // Pretend it was written anyway so that the user doesn't get
|
||||
// any "config not written" notifications, but only if the file
|
||||
// already existed. Otherwise, let it write out a default one.
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE *file = fopen (PathName, "w");
|
||||
FConfigSection *section;
|
||||
FConfigEntry *entry;
|
||||
|
|
|
@ -79,6 +79,9 @@ protected:
|
|||
virtual char *ReadLine (char *string, int n, void *file) const;
|
||||
bool ReadConfig (void *file);
|
||||
|
||||
bool OkayToWrite;
|
||||
bool FileExisted;
|
||||
|
||||
private:
|
||||
struct FConfigEntry
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
@ -162,6 +162,41 @@ struct CodePointerAlias
|
|||
};
|
||||
static TArray<CodePointerAlias> MBFCodePointers;
|
||||
|
||||
struct AmmoPerAttack
|
||||
{
|
||||
VMFunction *func;
|
||||
int ammocount;
|
||||
};
|
||||
|
||||
DECLARE_ACTION(A_Punch)
|
||||
DECLARE_ACTION(A_FirePistol)
|
||||
DECLARE_ACTION(A_FireShotgun)
|
||||
DECLARE_ACTION(A_FireShotgun2)
|
||||
DECLARE_ACTION(A_FireCGun)
|
||||
DECLARE_ACTION(A_FireMissile)
|
||||
DECLARE_ACTION(A_Saw)
|
||||
DECLARE_ACTION(A_FirePlasma)
|
||||
DECLARE_ACTION(A_FireBFG)
|
||||
DECLARE_ACTION(A_FireOldBFG)
|
||||
DECLARE_ACTION(A_FireRailgun)
|
||||
|
||||
// Default ammo use of the various weapon attacks
|
||||
static AmmoPerAttack AmmoPerAttacks[] = {
|
||||
{ A_Punch_VMPtr, 0},
|
||||
{ A_FirePistol_VMPtr, 1},
|
||||
{ A_FireShotgun_VMPtr, 1},
|
||||
{ A_FireShotgun2_VMPtr, 2},
|
||||
{ A_FireCGun_VMPtr, 1},
|
||||
{ A_FireMissile_VMPtr, 1},
|
||||
{ A_Saw_VMPtr, 0},
|
||||
{ A_FirePlasma_VMPtr, 1},
|
||||
{ A_FireBFG_VMPtr, -1}, // uses deh.BFGCells
|
||||
{ A_FireOldBFG_VMPtr, 1},
|
||||
{ A_FireRailgun_VMPtr, 1},
|
||||
{ NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
// Miscellaneous info that used to be constant
|
||||
DehInfo deh =
|
||||
{
|
||||
|
@ -183,6 +218,7 @@ DehInfo deh =
|
|||
255, // Rocket explosion style, 255=use cvar
|
||||
FRACUNIT*2/3, // Rocket explosion alpha
|
||||
false, // .NoAutofreeze
|
||||
40, // BFG cells per shot
|
||||
};
|
||||
|
||||
// Doom identified pickup items by their sprites. ZDoom prefers to use their
|
||||
|
@ -309,7 +345,7 @@ static const struct {
|
|||
{ "[PARS]", PatchPars },
|
||||
{ "[CODEPTR]", PatchCodePtrs },
|
||||
{ "[MUSIC]", PatchMusic },
|
||||
{ NULL, },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static int HandleMode (const char *mode, int num);
|
||||
|
@ -691,8 +727,11 @@ void SetDehParams(FState * state, int codepointer)
|
|||
if (value2) StateParams.Set(ParamIndex+1, new FxConstant(SoundMap[value2-1], *pos)); // hit sound
|
||||
break;
|
||||
case MBF_PlaySound:
|
||||
StateParams.Set(ParamIndex+0, new FxConstant(SoundMap[value1-1], *pos)); // soundid
|
||||
StateParams.Set(ParamIndex+4, new FxConstant((value2?ATTN_NONE:ATTN_NORM), *pos)); // attenuation
|
||||
StateParams.Set(ParamIndex+0, new FxConstant(SoundMap[value1-1], *pos)); // soundid
|
||||
StateParams.Set(ParamIndex+1, new FxConstant(CHAN_BODY, *pos)); // channel
|
||||
StateParams.Set(ParamIndex+2, new FxConstant(1.0, *pos)); // volume
|
||||
StateParams.Set(ParamIndex+3, new FxConstant(false, *pos)); // looping
|
||||
StateParams.Set(ParamIndex+4, new FxConstant((value2 ? ATTN_NONE : ATTN_NORM), *pos)); // attenuation
|
||||
break;
|
||||
case MBF_RandomJump:
|
||||
StateParams.Set(ParamIndex+0, new FxConstant(2, *pos)); // count
|
||||
|
@ -1088,6 +1127,15 @@ static int PatchThing (int thingy)
|
|||
value[0] &= ~MF_TRANSLUCENT; // clean the slot
|
||||
vchanged[2] = true; value[2] |= 2; // let the TRANSLUCxx code below handle it
|
||||
}
|
||||
if ((info->flags & MF_MISSILE) && (info->flags2 & MF2_NOTELEPORT)
|
||||
&& !(value[0] & MF_MISSILE))
|
||||
{
|
||||
// ZDoom gives missiles flags that did not exist in Doom: MF2_NOTELEPORT,
|
||||
// MF2_IMPACT, and MF2_PCROSS. The NOTELEPORT one can be a problem since
|
||||
// some projectile actors (those new to Doom II) were not excluded from
|
||||
// triggering line effects and can teleport when the missile flag is removed.
|
||||
info->flags2 &= ~MF2_NOTELEPORT;
|
||||
}
|
||||
info->flags = value[0];
|
||||
}
|
||||
if (vchanged[1])
|
||||
|
@ -1183,15 +1231,24 @@ static int PatchThing (int thingy)
|
|||
PushTouchedActor(const_cast<PClassActor *>(type));
|
||||
}
|
||||
|
||||
// Make MF3_ISMONSTER match MF_COUNTKILL
|
||||
if (info->flags & MF_COUNTKILL)
|
||||
// If MF_COUNTKILL is set, make sure the other standard monster flags are
|
||||
// set, too. And vice versa.
|
||||
if (thingy != 1) // don't mess with the player's flags
|
||||
{
|
||||
info->flags3 |= MF3_ISMONSTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->flags3 &= ~MF3_ISMONSTER;
|
||||
if (info->flags & MF_COUNTKILL)
|
||||
{
|
||||
info->flags2 |= MF2_PUSHWALL | MF2_MCROSS | MF2_PASSMOBJ;
|
||||
info->flags3 |= MF3_ISMONSTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->flags2 &= ~(MF2_PUSHWALL | MF2_MCROSS);
|
||||
info->flags3 &= ~MF3_ISMONSTER;
|
||||
}
|
||||
}
|
||||
// Everything that's altered here gets the CANUSEWALLS flag, just in case
|
||||
// it calls P_Move().
|
||||
info->flags4 |= MF4_CANUSEWALLS;
|
||||
if (patchedStates)
|
||||
{
|
||||
statedef.InstallStates(type, info);
|
||||
|
@ -1406,7 +1463,7 @@ static int PatchSprite (int sprNum)
|
|||
|
||||
static int PatchAmmo (int ammoNum)
|
||||
{
|
||||
const PClass *ammoType = NULL;
|
||||
PClassAmmo *ammoType = NULL;
|
||||
AAmmo *defaultAmmo = NULL;
|
||||
int result;
|
||||
int oldclip;
|
||||
|
@ -1572,6 +1629,7 @@ static int PatchWeapon (int weapNum)
|
|||
else if (stricmp (Line1, "Ammo use") == 0 || stricmp (Line1, "Ammo per shot") == 0)
|
||||
{
|
||||
info->AmmoUse1 = val;
|
||||
info->flags6 |= MF6_INTRYMOVE; // flag the weapon for postprocessing (reuse a flag that can't be set by external means)
|
||||
}
|
||||
else if (stricmp (Line1, "Min ammo") == 0)
|
||||
{
|
||||
|
@ -1713,7 +1771,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;
|
||||
|
||||
|
@ -1725,7 +1783,7 @@ static int PatchMisc (int dummy)
|
|||
{
|
||||
if (stricmp (Line1, "BFG Cells/Shot") == 0)
|
||||
{
|
||||
((AWeapon*)GetDefaultByName ("BFG9000"))->AmmoUse1 = atoi (Line2);
|
||||
deh.BFGCells = atoi (Line2);
|
||||
}
|
||||
else if (stricmp (Line1, "Rocket Explosion Style") == 0)
|
||||
{
|
||||
|
@ -2479,8 +2537,6 @@ static void UnloadDehSupp ()
|
|||
BitNames.ShrinkToFit();
|
||||
StyleNames.Clear();
|
||||
StyleNames.ShrinkToFit();
|
||||
WeaponNames.Clear();
|
||||
WeaponNames.ShrinkToFit();
|
||||
AmmoNames.Clear();
|
||||
AmmoNames.ShrinkToFit();
|
||||
|
||||
|
@ -2774,6 +2830,7 @@ static bool LoadDehSupp ()
|
|||
}
|
||||
else if (sc.Compare("WeaponNames"))
|
||||
{
|
||||
WeaponNames.Clear(); // This won't be cleared by UnloadDEHSupp so we need to do it here explicitly
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
|
@ -2877,6 +2934,57 @@ void FinishDehPatch ()
|
|||
// Now that all Dehacked patches have been processed, it's okay to free StateMap.
|
||||
StateMap.Clear();
|
||||
StateMap.ShrinkToFit();
|
||||
TouchedActors.Clear();
|
||||
TouchedActors.ShrinkToFit();
|
||||
|
||||
// Now it gets nasty: We have to fiddle around with the weapons' ammo use info to make Doom's original
|
||||
// ammo consumption work as intended.
|
||||
|
||||
for(unsigned i = 0; i < WeaponNames.Size(); i++)
|
||||
{
|
||||
AWeapon *weap = (AWeapon*)GetDefaultByType(WeaponNames[i]);
|
||||
bool found = false;
|
||||
if (weap->flags6 & MF6_INTRYMOVE)
|
||||
{
|
||||
// Weapon sets an explicit amount of ammo to use so we won't need any special processing here
|
||||
weap->flags6 &= ~MF6_INTRYMOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
weap->WeaponFlags |= WIF_DEHAMMO;
|
||||
weap->AmmoUse1 = 0;
|
||||
// to allow proper checks in CheckAmmo we have to find the first attack pointer in the Fire sequence
|
||||
// and set its default ammo use as the weapon's AmmoUse1.
|
||||
|
||||
TMap<FState*, bool> StateVisited;
|
||||
|
||||
FState *state = WeaponNames[i]->FindState(NAME_Fire);
|
||||
while (state != NULL)
|
||||
{
|
||||
bool *check = StateVisited.CheckKey(state);
|
||||
if (check != NULL && *check)
|
||||
{
|
||||
break; // State has already been checked so we reached a loop
|
||||
}
|
||||
StateVisited[state] = true;
|
||||
for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++)
|
||||
{
|
||||
if (state->ActionFunc == AmmoPerAttacks[j].func)
|
||||
{
|
||||
found = true;
|
||||
int use = AmmoPerAttacks[j].ammocount;
|
||||
if (use < 0) use = deh.BFGCells;
|
||||
weap->AmmoUse1 = use;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
state = state->GetNextState();
|
||||
}
|
||||
}
|
||||
}
|
||||
WeaponNames.Clear();
|
||||
WeaponNames.ShrinkToFit();
|
||||
}
|
||||
|
||||
void ModifyDropAmount(AInventory *inv, int dropamount);
|
||||
|
@ -2892,11 +3000,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;
|
||||
|
|
|
@ -62,6 +62,8 @@ typedef enum
|
|||
ga_newgame,
|
||||
ga_newgame2,
|
||||
ga_loadgame,
|
||||
ga_loadgamehidecon,
|
||||
ga_loadgameplaydemo,
|
||||
ga_autoloadgame,
|
||||
ga_savegame,
|
||||
ga_autosave,
|
||||
|
@ -88,8 +90,8 @@ typedef enum
|
|||
BT_CROUCH = 1<<3,
|
||||
BT_TURN180 = 1<<4,
|
||||
BT_ALTATTACK = 1<<5, // Press your other "Fire".
|
||||
BT_RELOAD = 1<<6, // Not connected to anything at the moment.
|
||||
BT_ZOOM = 1<<7, // Neither is this.
|
||||
BT_RELOAD = 1<<6, // [XA] Reload key. Causes state jump in A_WeaponReady.
|
||||
BT_ZOOM = 1<<7, // [XA] Zoom key. Ditto.
|
||||
|
||||
// The rest are all ignored by the play simulation and are for scripts.
|
||||
BT_SPEED = 1<<8,
|
||||
|
|
39
src/d_gui.h
39
src/d_gui.h
|
@ -43,27 +43,34 @@ enum EGUIEvent
|
|||
EV_GUI_KeyRepeat, // same
|
||||
EV_GUI_KeyUp, // same
|
||||
EV_GUI_Char, // data1: translated character (for user text input), data2: alt down?
|
||||
EV_GUI_MouseMove,
|
||||
EV_GUI_LButtonDown,
|
||||
EV_GUI_LButtonUp,
|
||||
EV_GUI_LButtonDblClick,
|
||||
EV_GUI_MButtonDown,
|
||||
EV_GUI_MButtonUp,
|
||||
EV_GUI_MButtonDblClick,
|
||||
EV_GUI_RButtonDown,
|
||||
EV_GUI_RButtonUp,
|
||||
EV_GUI_RButtonDblClick,
|
||||
EV_GUI_WheelUp, // data3: shift/ctrl/alt
|
||||
EV_GUI_WheelDown, // "
|
||||
EV_GUI_WheelRight, // "
|
||||
EV_GUI_WheelLeft, // "
|
||||
EV_GUI_FirstMouseEvent,
|
||||
EV_GUI_MouseMove,
|
||||
EV_GUI_LButtonDown,
|
||||
EV_GUI_LButtonUp,
|
||||
EV_GUI_LButtonDblClick,
|
||||
EV_GUI_MButtonDown,
|
||||
EV_GUI_MButtonUp,
|
||||
EV_GUI_MButtonDblClick,
|
||||
EV_GUI_RButtonDown,
|
||||
EV_GUI_RButtonUp,
|
||||
EV_GUI_RButtonDblClick,
|
||||
EV_GUI_WheelUp, // data3: shift/ctrl/alt
|
||||
EV_GUI_WheelDown, // "
|
||||
EV_GUI_WheelRight, // "
|
||||
EV_GUI_WheelLeft, // "
|
||||
EV_GUI_BackButtonDown,
|
||||
EV_GUI_BackButtonUp,
|
||||
EV_GUI_FwdButtonDown,
|
||||
EV_GUI_FwdButtonUp,
|
||||
EV_GUI_LastMouseEvent,
|
||||
};
|
||||
|
||||
enum GUIKeyModifiers
|
||||
{
|
||||
GKM_SHIFT = 1,
|
||||
GKM_CTRL = 2,
|
||||
GKM_ALT = 4
|
||||
GKM_ALT = 4,
|
||||
GKM_LBUTTON = 8
|
||||
};
|
||||
|
||||
// Special codes for some GUI keys, including a few real ASCII codes.
|
||||
|
@ -100,7 +107,7 @@ enum ESpecialGUIKeys
|
|||
GK_ESCAPE = 27, // ASCII
|
||||
GK_FREE1 = 28,
|
||||
GK_FREE2 = 29,
|
||||
GK_FREE3 = 30,
|
||||
GK_BACK = 30, // browser back key
|
||||
GK_CESCAPE = 31 // color escape
|
||||
};
|
||||
|
||||
|
|
687
src/d_iwad.cpp
687
src/d_iwad.cpp
|
@ -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" },
|
||||
{ "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,12 +408,12 @@ 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]);
|
||||
}
|
||||
}
|
||||
|
||||
if (iwadparm == NULL || wads[0].Path.IsEmpty())
|
||||
if (iwadparm == NULL || wads[0].Path.IsEmpty() || mIWads[wads[0].Type].Required.IsNotEmpty())
|
||||
{
|
||||
if (GameConfig->SetSection ("IWADSearch.Directories"))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
1085
src/d_main.cpp
1085
src/d_main.cpp
File diff suppressed because it is too large
Load diff
104
src/d_main.h
104
src/d_main.h
|
@ -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,77 @@ 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
|
||||
FString Song;
|
||||
int Type;
|
||||
enum
|
||||
{
|
||||
DefaultStartup,
|
||||
DoomStartup,
|
||||
HereticStartup,
|
||||
HexenStartup,
|
||||
StrifeStartup,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
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
|
||||
|
|
141
src/d_net.cpp
141
src/d_net.cpp
|
@ -25,7 +25,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "m_menu.h"
|
||||
#include "menu/menu.h"
|
||||
#include "m_random.h"
|
||||
#include "i_system.h"
|
||||
#include "i_video.h"
|
||||
|
@ -57,9 +57,10 @@
|
|||
#include "g_level.h"
|
||||
#include "d_event.h"
|
||||
#include "m_argv.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);
|
||||
#include "p_lnspec.h"
|
||||
#include "v_video.h"
|
||||
#include "p_spec.h"
|
||||
#include "intermission/intermission.h"
|
||||
|
||||
EXTERN_CVAR (Int, disableautosave)
|
||||
EXTERN_CVAR (Int, autosavecount)
|
||||
|
@ -119,6 +120,7 @@ void G_BuildTiccmd (ticcmd_t *cmd);
|
|||
void D_DoAdvanceDemo (void);
|
||||
|
||||
static void SendSetup (DWORD playersdetected[MAXNETNODES], BYTE gotsetup[MAXNETNODES], int len);
|
||||
static void RunScript(BYTE **stream, APlayerPawn *pawn, int snum, int argn, int always);
|
||||
|
||||
int reboundpacket;
|
||||
BYTE reboundstore[MAX_MSGLEN];
|
||||
|
@ -590,13 +592,16 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
Printf ("%s left the game\n", players[netconsole].userinfo.netname);
|
||||
}
|
||||
|
||||
// [RH] Revert to your own view if spying through the player who left
|
||||
if (players[consoleplayer].camera == players[netconsole].mo)
|
||||
// [RH] Revert each player to their own view if spying through the player who left
|
||||
for (int ii = 0; ii < MAXPLAYERS; ++ii)
|
||||
{
|
||||
players[consoleplayer].camera = players[consoleplayer].mo;
|
||||
if (StatusBar != NULL)
|
||||
if (playeringame[ii] && players[ii].camera == players[netconsole].mo)
|
||||
{
|
||||
StatusBar->AttachToPlayer (&players[consoleplayer]);
|
||||
players[ii].camera = players[ii].mo;
|
||||
if (ii == consoleplayer && StatusBar != NULL)
|
||||
{
|
||||
StatusBar->AttachToPlayer (&players[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,6 +612,11 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
P_DisconnectEffect (players[netconsole].mo);
|
||||
players[netconsole].mo->player = NULL;
|
||||
players[netconsole].mo->Destroy ();
|
||||
if (!(players[netconsole].mo->ObjectFlags & OF_EuthanizeMe))
|
||||
{ // We just destroyed a morphed player, so now the original player
|
||||
// has taken their place. Destroy that one too.
|
||||
players[netconsole].mo->Destroy();
|
||||
}
|
||||
players[netconsole].mo = NULL;
|
||||
players[netconsole].camera = NULL;
|
||||
}
|
||||
|
@ -746,6 +756,7 @@ void GetPackets (void)
|
|||
}
|
||||
|
||||
if (netbuffer[0] & NCMD_QUITTERS)
|
||||
|
||||
{
|
||||
numplayers = netbuffer[k++];
|
||||
for (int i = 0; i < numplayers; ++i)
|
||||
|
@ -1538,7 +1549,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)
|
||||
{
|
||||
|
@ -1917,7 +1927,7 @@ BYTE *FDynamicBuffer::GetData (int *len)
|
|||
}
|
||||
|
||||
|
||||
static int KillAll(const PClass *cls)
|
||||
static int KillAll(PClassActor *cls)
|
||||
{
|
||||
AActor *actor;
|
||||
int killcount = 0;
|
||||
|
@ -2057,10 +2067,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
break;
|
||||
|
||||
case DEM_CENTERVIEW:
|
||||
if (players[player].mo != NULL)
|
||||
{
|
||||
players[player].mo->pitch = 0;
|
||||
}
|
||||
players[player].centering = true;
|
||||
break;
|
||||
|
||||
case DEM_INVUSEALL:
|
||||
|
@ -2312,22 +2319,47 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
{
|
||||
int snum = ReadWord (stream);
|
||||
int argn = ReadByte (stream);
|
||||
int arg[3] = { 0, 0, 0 };
|
||||
|
||||
|
||||
RunScript(stream, players[player].mo, snum, argn, (type == DEM_RUNSCRIPT2) ? ACS_ALWAYS : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DEM_RUNNAMEDSCRIPT:
|
||||
{
|
||||
char *sname = ReadString(stream);
|
||||
int argn = ReadByte(stream);
|
||||
|
||||
RunScript(stream, players[player].mo, -FName(sname), argn & 127, (argn & 128) ? ACS_ALWAYS : 0);
|
||||
}
|
||||
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)
|
||||
{
|
||||
arg[i] = ReadLong (stream);
|
||||
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]);
|
||||
}
|
||||
P_StartScript (players[player].mo, NULL, snum, level.mapname, false,
|
||||
arg[0], arg[1], arg[2], type == DEM_RUNSCRIPT2, false, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case DEM_CROUCH:
|
||||
if (gamestate == GS_LEVEL && players[player].mo != NULL &&
|
||||
players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP))
|
||||
players[player].health > 0 && !(players[player].oldbuttons & BT_JUMP) &&
|
||||
!P_IsPlayerTotallyFrozen(&players[player]))
|
||||
{
|
||||
players[player].crouching = players[player].crouchdir<0? 1 : -1;
|
||||
players[player].crouching = players[player].crouchdir < 0 ? 1 : -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2371,7 +2403,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
if (cls != NULL)
|
||||
{
|
||||
killcount = KillAll(cls);
|
||||
const PClass *cls_rep = cls->GetReplacement();
|
||||
PClassActor *cls_rep = cls->GetReplacement();
|
||||
if (cls != cls_rep)
|
||||
{
|
||||
killcount += KillAll(cls_rep);
|
||||
|
@ -2393,17 +2425,27 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
break;
|
||||
|
||||
case DEM_SETSLOT:
|
||||
case DEM_SETSLOTPNUM:
|
||||
{
|
||||
int pnum;
|
||||
if (type == DEM_SETSLOTPNUM)
|
||||
{
|
||||
pnum = ReadByte(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
pnum = player;
|
||||
}
|
||||
unsigned int slot = ReadByte(stream);
|
||||
int count = ReadByte(stream);
|
||||
if (slot < NUM_WEAPON_SLOTS)
|
||||
{
|
||||
players[player].weapons.Slots[slot].Clear();
|
||||
players[pnum].weapons.Slots[slot].Clear();
|
||||
}
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
PClassWeapon *wpn = Net_ReadWeapon(stream);
|
||||
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
|
||||
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2424,6 +2466,19 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
}
|
||||
break;
|
||||
|
||||
case DEM_SETPITCHLIMIT:
|
||||
players[player].MinPitch = ReadByte(stream) * -ANGLE_1; // up
|
||||
players[player].MaxPitch = ReadByte(stream) * ANGLE_1; // down
|
||||
break;
|
||||
|
||||
case DEM_ADVANCEINTER:
|
||||
F_AdvanceIntermission();
|
||||
break;
|
||||
|
||||
case DEM_REVERTCAMERA:
|
||||
players[player].camera = players[player].mo;
|
||||
break;
|
||||
|
||||
default:
|
||||
I_Error ("Unknown net command: %d", type);
|
||||
break;
|
||||
|
@ -2433,6 +2488,23 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
delete[] s;
|
||||
}
|
||||
|
||||
// Used by DEM_RUNSCRIPT, DEM_RUNSCRIPT2, and DEM_RUNNAMEDSCRIPT
|
||||
static void RunScript(BYTE **stream, APlayerPawn *pawn, int snum, int argn, int always)
|
||||
{
|
||||
int arg[4] = { 0, 0, 0, 0 };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
int argval = ReadLong(stream);
|
||||
if ((unsigned)i < countof(arg))
|
||||
{
|
||||
arg[i] = argval;
|
||||
}
|
||||
}
|
||||
P_StartScript(pawn, NULL, snum, level.mapname, arg, MIN<int>(countof(arg), argn), ACS_NET | always);
|
||||
}
|
||||
|
||||
void Net_SkipCommand (int type, BYTE **stream)
|
||||
{
|
||||
BYTE t;
|
||||
|
@ -2521,14 +2593,24 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
skip = 3 + *(*stream + 2) * 4;
|
||||
break;
|
||||
|
||||
case DEM_RUNNAMEDSCRIPT:
|
||||
skip = strlen((char *)(*stream)) + 2;
|
||||
skip += ((*(*stream + skip - 1)) & 127) * 4;
|
||||
break;
|
||||
|
||||
case DEM_RUNSPECIAL:
|
||||
skip = 2 + *(*stream + 1) * 4;
|
||||
break;
|
||||
|
||||
case DEM_CONVREPLY:
|
||||
skip = 3;
|
||||
break;
|
||||
|
||||
case DEM_SETSLOT:
|
||||
case DEM_SETSLOTPNUM:
|
||||
{
|
||||
skip = 2;
|
||||
for(int numweapons = (*stream)[1]; numweapons > 0; numweapons--)
|
||||
skip = 2 + (type == DEM_SETSLOTPNUM);
|
||||
for(int numweapons = (*stream)[skip-1]; numweapons > 0; numweapons--)
|
||||
{
|
||||
skip += 1 + ((*stream)[skip] >> 7);
|
||||
}
|
||||
|
@ -2540,6 +2622,9 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
skip = 2 + ((*stream)[1] >> 7);
|
||||
break;
|
||||
|
||||
case DEM_SETPITCHLIMIT:
|
||||
skip = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
@ -597,8 +598,8 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
|
|||
,
|
||||
D_EscapeUserInfo(info->netname).GetChars(),
|
||||
(double)info->aimdist / (float)ANGLE_1,
|
||||
info->colorset,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
info->colorset,
|
||||
D_EscapeUserInfo(skins[info->skin].name).GetChars(),
|
||||
info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
|
@ -744,6 +745,7 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
|
|||
if (infotype == INFO_Color)
|
||||
{
|
||||
info->color = V_GetColorFromString (NULL, value);
|
||||
info->colorset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -761,6 +763,7 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
|
|||
if (players[i].mo != NULL)
|
||||
{
|
||||
if (players[i].cls != NULL &&
|
||||
!(players[i].mo->flags4 & MF4_NOSKIN) &&
|
||||
players[i].mo->state->sprite ==
|
||||
GetDefaultByType (players[i].cls)->SpawnState->sprite)
|
||||
{ // Only change the sprite if the player is using a standard one
|
||||
|
@ -833,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,12 @@ class player_t;
|
|||
// Standard pre-defined skin colors
|
||||
struct FPlayerColorSet
|
||||
{
|
||||
struct ExtraRange
|
||||
{
|
||||
BYTE RangeStart, RangeEnd; // colors to remap
|
||||
BYTE FirstColor, LastColor; // colors to map to
|
||||
};
|
||||
|
||||
FName Name; // Name of this color
|
||||
|
||||
int Lump; // Lump to read the translation from, otherwise use next 2 fields
|
||||
|
@ -56,10 +62,11 @@ struct FPlayerColorSet
|
|||
|
||||
BYTE RepresentativeColor; // A palette entry representative of this translation,
|
||||
// for map arrows and status bar backgrounds and such
|
||||
BYTE NumExtraRanges;
|
||||
ExtraRange Extra[6];
|
||||
};
|
||||
typedef TMap<int, FPlayerColorSet> FPlayerColorSetMap;
|
||||
|
||||
|
||||
class PClassPlayerPawn : public PClassActor
|
||||
{
|
||||
DECLARE_CLASS(PClassPlayerPawn, PClassActor);
|
||||
|
@ -73,6 +80,7 @@ public:
|
|||
FString DisplayName; // Display name (used in menus, etc.)
|
||||
FString SoundClass; // Sound class
|
||||
FString Face; // Doom status bar face (when used)
|
||||
FString Portrait;
|
||||
FString Slot[10];
|
||||
FName InvulMode;
|
||||
FName HealingRadiusType;
|
||||
|
@ -81,6 +89,7 @@ public:
|
|||
BYTE ColorRangeEnd;
|
||||
FPlayerColorSetMap ColorSets;
|
||||
};
|
||||
FString GetPrintableDisplayName(PClassPlayerPawn *cls);
|
||||
|
||||
class player_t;
|
||||
|
||||
|
@ -103,9 +112,9 @@ public:
|
|||
virtual void TweakSpeeds (int &forwardmove, int &sidemove);
|
||||
virtual void MorphPlayerThink ();
|
||||
virtual void ActivateMorphWeapon ();
|
||||
AWeapon *PickNewWeapon (const PClass *ammotype);
|
||||
AWeapon *BestWeapon (const PClass *ammotype);
|
||||
void CheckWeaponSwitch(const PClass *ammotype);
|
||||
AWeapon *PickNewWeapon (PClassAmmo *ammotype);
|
||||
AWeapon *BestWeapon (PClassAmmo *ammotype);
|
||||
void CheckWeaponSwitch(PClassAmmo *ammotype);
|
||||
virtual void GiveDeathmatchInventory ();
|
||||
virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
|
||||
|
||||
|
@ -124,7 +133,7 @@ public:
|
|||
};
|
||||
|
||||
void BeginPlay ();
|
||||
void Die (AActor *source, AActor *inflictor);
|
||||
void Die (AActor *source, AActor *inflictor, int dmgflags);
|
||||
|
||||
int crouchsprite;
|
||||
int MaxHealth;
|
||||
|
@ -143,6 +152,7 @@ public:
|
|||
int SpawnMask;
|
||||
FNameNoInit MorphWeapon;
|
||||
fixed_t AttackZOffset; // attack height, relative to player center
|
||||
PClassActor *FlechetteType;
|
||||
|
||||
// [CW] Fades for when you are being damaged.
|
||||
PalEntry DamageFade;
|
||||
|
@ -197,9 +207,7 @@ typedef enum
|
|||
CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use
|
||||
CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted
|
||||
CF_WEAPONREADY = 1 << 14, // [RH] Weapon is in the ready state and can fire its primary attack
|
||||
CF_TIMEFREEZE = 1 << 15, // Player has an active time freezer
|
||||
CF_DRAIN = 1 << 16, // Player owns a drain powerup
|
||||
CF_REGENERATION = 1 << 17, // Player owns a regeneration artifact
|
||||
CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;)
|
||||
CF_REFLECTION = 1 << 19,
|
||||
CF_PROSPERITY = 1 << 20,
|
||||
|
@ -210,6 +218,8 @@ typedef enum
|
|||
CF_WEAPONREADYALT = 1 << 25, // Weapon can fire its secondary attack
|
||||
CF_WEAPONSWITCHOK = 1 << 26, // It is okay to switch away from this weapon
|
||||
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
|
||||
CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon.
|
||||
CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function.
|
||||
} cheat_t;
|
||||
|
||||
#define WPIECE1 1
|
||||
|
@ -261,6 +271,7 @@ public:
|
|||
|
||||
void SetLogNumber (int num);
|
||||
void SetLogText (const char *text);
|
||||
void SendPitchLimits() const;
|
||||
|
||||
APlayerPawn *mo;
|
||||
BYTE playerstate;
|
||||
|
@ -287,6 +298,8 @@ public:
|
|||
|
||||
bool centering;
|
||||
BYTE turnticks;
|
||||
|
||||
|
||||
bool attackdown;
|
||||
bool usedown;
|
||||
DWORD oldbuttons;
|
||||
|
@ -307,12 +320,15 @@ public:
|
|||
AWeapon *PendingWeapon; // WP_NOCHANGE if not changing
|
||||
|
||||
int cheats; // bit flags
|
||||
int timefreezer; // Player has an active time freezer
|
||||
short refire; // refired shots are less accurate
|
||||
short inconsistant;
|
||||
int killcount, itemcount, secretcount; // for intermission
|
||||
int damagecount, bonuscount;// for screen flashing
|
||||
int hazardcount; // for delayed Strife damage
|
||||
int poisoncount; // screen flash for poison damage
|
||||
FName poisontype; // type of poison damage to apply
|
||||
FName poisonpaintype; // type of Pain state to enter for poison damage
|
||||
TObjPtr<AActor> poisoner; // NULL for non-player actors
|
||||
TObjPtr<AActor> attacker; // who did damage (NULL for floors)
|
||||
int extralight; // so gun flashes light up areas
|
||||
|
@ -332,8 +348,6 @@ public:
|
|||
|
||||
int air_finished; // [RH] Time when you start drowning
|
||||
|
||||
WORD accuracy, stamina; // [RH] Strife stats
|
||||
|
||||
FName LastDamageType; // [RH] For damage-specific pain and death sounds
|
||||
|
||||
//Added by MC:
|
||||
|
@ -347,9 +361,9 @@ public:
|
|||
|
||||
|
||||
TObjPtr<AActor> enemy; // The dead meat.
|
||||
TObjPtr<AActor> missile; // A threathing missile that got to be avoided.
|
||||
TObjPtr<AActor> mate; // Friend (used for grouping in templay or coop.
|
||||
TObjPtr<AActor> last_mate; // If bots mate dissapeared (not if died) that mate is
|
||||
TObjPtr<AActor> missile; // A threatening missile that needs to be avoided.
|
||||
TObjPtr<AActor> mate; // Friend (used for grouping in teamplay or coop).
|
||||
TObjPtr<AActor> last_mate; // If bots mate disappeared (not if died) that mate is
|
||||
// pointed to by this. Allows bot to roam to it if
|
||||
// necessary.
|
||||
|
||||
|
@ -385,6 +399,9 @@ public:
|
|||
|
||||
FString LogText; // [RH] Log for Strife
|
||||
|
||||
int MinPitch; // Viewpitch limits (negative is up, positive is down)
|
||||
int MaxPitch;
|
||||
|
||||
SBYTE crouching;
|
||||
SBYTE crouchdir;
|
||||
fixed_t crouchfactor;
|
||||
|
@ -418,16 +435,27 @@ 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();
|
||||
|
||||
inline void AActor::SetFriendPlayer(player_t *player)
|
||||
{
|
||||
if (player == NULL)
|
||||
{
|
||||
FriendPlayer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FriendPlayer = int(player - players) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define CROUCHSPEED (FRACUNIT/12)
|
||||
|
||||
bool P_IsPlayerTotallyFrozen(const player_t *player);
|
||||
|
||||
// [GRB] Custom player classes
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -217,10 +217,10 @@ int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream)
|
|||
buttons_changed = ucmd->buttons ^ basis->buttons;
|
||||
if (buttons_changed != 0)
|
||||
{
|
||||
BYTE bytes[4] = { ucmd->buttons & 0x7F,
|
||||
(ucmd->buttons >> 7) & 0x7F,
|
||||
(ucmd->buttons >> 14) & 0x7F,
|
||||
(ucmd->buttons >> 21) & 0xFF };
|
||||
BYTE bytes[4] = { BYTE(ucmd->buttons & 0x7F),
|
||||
BYTE((ucmd->buttons >> 7) & 0x7F),
|
||||
BYTE((ucmd->buttons >> 14) & 0x7F),
|
||||
BYTE((ucmd->buttons >> 21) & 0xFF) };
|
||||
|
||||
flags |= UCMDF_BUTTONS;
|
||||
|
||||
|
|
|
@ -158,6 +158,12 @@ 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
|
||||
DEM_SETPITCHLIMIT, // 63 Byte: Up limit, Byte: Down limit (in degrees)
|
||||
DEM_ADVANCEINTER, // 64 Advance intermission screen state
|
||||
DEM_RUNNAMEDSCRIPT, // 65 String: Script name, Byte: Arg count + Always flag; each arg is a 4-byte int
|
||||
DEM_REVERTCAMERA, // 66
|
||||
DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT
|
||||
};
|
||||
|
||||
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
||||
|
|
|
@ -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);
|
||||
|
@ -591,14 +602,14 @@ void FDecalLib::ParseDecalGroup (FScanner &sc)
|
|||
|
||||
void FDecalLib::ParseGenerator (FScanner &sc)
|
||||
{
|
||||
const PClass *type;
|
||||
PClassActor *type;
|
||||
FDecalBase *decal;
|
||||
AActor *actor;
|
||||
|
||||
// Get name of generator (actor)
|
||||
sc.MustGetString ();
|
||||
type = PClass::FindClass (sc.String);
|
||||
if (type == NULL || !type->IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||
type = PClass::FindActor(sc.String);
|
||||
if (type == NULL)
|
||||
{
|
||||
sc.ScriptError ("%s is not an actor.", sc.String);
|
||||
}
|
||||
|
@ -1110,16 +1121,19 @@ FDecalLib::FTranslation *FDecalLib::FTranslation::LocateTranslation (DWORD start
|
|||
const FDecalTemplate *FDecalGroup::GetDecal () const
|
||||
{
|
||||
const FDecalBase *decal = Choices.PickEntry ();
|
||||
const FDecalBase *remember;
|
||||
const FDecalBase *remember = decal;
|
||||
|
||||
// Repeatedly GetDecal() until the result is constant, since
|
||||
// the choice might be another FDecalGroup.
|
||||
do
|
||||
if (decal != NULL)
|
||||
{
|
||||
remember = decal;
|
||||
decal = decal->GetDecal ();
|
||||
} while (decal != remember);
|
||||
return static_cast<const FDecalTemplate *>(decal);
|
||||
do
|
||||
{
|
||||
remember = decal;
|
||||
decal = decal->GetDecal ();
|
||||
} while (decal != NULL && decal != remember);
|
||||
}
|
||||
return static_cast<const FDecalTemplate *>(remember);
|
||||
}
|
||||
|
||||
FDecalAnimator::FDecalAnimator (const char *name)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "stats.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "dsectoreffect.h"
|
||||
#include "farchive.h"
|
||||
|
||||
ClassReg DObject::RegistrationInfo =
|
||||
{
|
||||
|
@ -320,8 +321,9 @@ size_t DObject::PropagateMark()
|
|||
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||
offsets++;
|
||||
}
|
||||
return info->Size;
|
||||
}
|
||||
return info->Size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
|
||||
|
@ -409,12 +411,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;
|
||||
|
||||
|
|
|
@ -302,6 +302,9 @@ namespace GC
|
|||
// Marks an array of objects.
|
||||
void MarkArray(DObject **objs, size_t count);
|
||||
|
||||
// For cleanup
|
||||
void DelSoftRootHead();
|
||||
|
||||
// Soft-roots an object.
|
||||
void AddSoftRoot(DObject *obj);
|
||||
|
||||
|
|
|
@ -61,18 +61,20 @@
|
|||
#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 "autosegs.h"
|
||||
#include "v_video.h"
|
||||
#include "menu/menu.h"
|
||||
#include "intermission/intermission.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -242,8 +244,10 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
|
|||
// be in a thinker list, then I need to add write barriers for every time a
|
||||
// thinker pointer is changed. This seems easier and perfectly reasonable, since
|
||||
// a live thinker that isn't on a thinker list isn't much of a thinker.
|
||||
assert(FinalGC || !curr->IsKindOf(RUNTIME_CLASS(DThinker)) || (curr->ObjectFlags & OF_Sentinel));
|
||||
assert(FinalGC || !curr->IsKindOf(RUNTIME_CLASS(DInterpolation)));
|
||||
|
||||
// However, this can happen during deletion of the thinker list while cleaning up
|
||||
// from a savegame error so we can't assume that any thinker that gets here is an error.
|
||||
|
||||
curr->Destroy();
|
||||
}
|
||||
curr->ObjectFlags |= OF_Cleanup;
|
||||
|
@ -316,6 +320,8 @@ static void MarkRoot()
|
|||
Mark(Args);
|
||||
Mark(screen);
|
||||
Mark(StatusBar);
|
||||
Mark(DMenu::CurrentMenu);
|
||||
Mark(DIntermissionController::CurrentIntermission);
|
||||
DThinker::MarkRoots();
|
||||
FCanvasTextureInfo::Mark();
|
||||
Mark(DACSThinker::ActiveThinker);
|
||||
|
@ -556,6 +562,17 @@ void Barrier(DObject *pointing, DObject *pointed)
|
|||
}
|
||||
}
|
||||
|
||||
void DelSoftRootHead()
|
||||
{
|
||||
if (SoftRoots != NULL)
|
||||
{
|
||||
// Don't let the destructor print a warning message
|
||||
SoftRoots->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete SoftRoots;
|
||||
}
|
||||
SoftRoots = NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AddSoftRoot
|
||||
|
|
|
@ -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)
|
||||
|
@ -397,11 +400,25 @@ enum EMapThingFlags
|
|||
STF_ALTSHADOW = 0x0200,
|
||||
};
|
||||
|
||||
// A simplified mapthing for player starts
|
||||
struct FPlayerStart
|
||||
{
|
||||
fixed_t x, y, z;
|
||||
short angle, type;
|
||||
|
||||
FPlayerStart() { }
|
||||
FPlayerStart(const FMapThing *mthing)
|
||||
: x(mthing->x), y(mthing->y), z(mthing->z),
|
||||
angle(mthing->angle),
|
||||
type(mthing->type)
|
||||
{ }
|
||||
};
|
||||
// Player spawn spots for deathmatch.
|
||||
extern TArray<FMapThing> deathmatchstarts;
|
||||
extern TArray<FPlayerStart> deathmatchstarts;
|
||||
|
||||
// Player spawn spots.
|
||||
extern FMapThing playerstarts[MAXPLAYERS];
|
||||
extern FPlayerStart playerstarts[MAXPLAYERS];
|
||||
extern TArray<FPlayerStart> AllPlayerStarts;
|
||||
|
||||
|
||||
#endif // __DOOMDATA__
|
||||
|
|
|
@ -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,10 @@ 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
|
||||
|
||||
COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW.
|
||||
COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom.
|
||||
};
|
||||
|
||||
// Emulate old bugs for select maps. These are not exposed by a cvar
|
||||
|
@ -339,6 +346,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:
|
||||
|
|
|
@ -67,3 +67,5 @@ int NextSkill = -1;
|
|||
int SinglePlayerClass[MAXPLAYERS];
|
||||
|
||||
bool ToggleFullscreen;
|
||||
int BorderTopRefresh;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -234,6 +230,7 @@ struct DehInfo
|
|||
BYTE ExplosionStyle;
|
||||
fixed_t ExplosionAlpha;
|
||||
int NoAutofreeze;
|
||||
int BFGCells;
|
||||
};
|
||||
extern DehInfo deh;
|
||||
EXTERN_CVAR (Int, infighting)
|
||||
|
@ -244,6 +241,7 @@ EXTERN_CVAR (Int, dmflags);
|
|||
EXTERN_CVAR (Int, dmflags2); // [BC]
|
||||
|
||||
EXTERN_CVAR (Int, compatflags);
|
||||
extern int i_compatflags, ii_compatflags, ib_compatflags;
|
||||
EXTERN_CVAR (Int, compatflags2);
|
||||
extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -222,7 +223,7 @@ DMover::EResult DMover::MovePlane (fixed_t speed, fixed_t dest, int crush,
|
|||
//destheight = (dest < m_Sector->ceilingheight) ? dest : m_Sector->ceilingheight;
|
||||
if ((m_Sector->ceilingplane.a | m_Sector->ceilingplane.b |
|
||||
m_Sector->floorplane.a | m_Sector->floorplane.b) == 0 &&
|
||||
-dest > m_Sector->ceilingplane.d)
|
||||
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && -dest > m_Sector->ceilingplane.d))
|
||||
{
|
||||
dest = -m_Sector->ceilingplane.d;
|
||||
}
|
||||
|
@ -291,7 +292,7 @@ DMover::EResult DMover::MovePlane (fixed_t speed, fixed_t dest, int crush,
|
|||
//destheight = (dest > m_Sector->floorheight) ? dest : m_Sector->floorheight;
|
||||
if ((m_Sector->ceilingplane.a | m_Sector->ceilingplane.b |
|
||||
m_Sector->floorplane.a | m_Sector->floorplane.b) == 0 &&
|
||||
dest < -m_Sector->floorplane.d)
|
||||
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && dest < -m_Sector->floorplane.d))
|
||||
{
|
||||
dest = -m_Sector->floorplane.d;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "statnums.h"
|
||||
#include "i_system.h"
|
||||
#include "doomerrors.h"
|
||||
#include "farchive.h"
|
||||
|
||||
|
||||
static cycle_t ThinkCycles;
|
||||
|
@ -191,19 +192,10 @@ void DThinker::SerializeAll(FArchive &arc, bool hubLoad)
|
|||
statcount--;
|
||||
}
|
||||
}
|
||||
catch (class CDoomError &err)
|
||||
catch (class CDoomError &)
|
||||
{
|
||||
bSerialOverride = false;
|
||||
|
||||
// DestroyAllThinkers cannot be called here. It will try to delete the corrupted
|
||||
// object table left behind by the serializer and crash.
|
||||
// Trying to continue is not an option here because the garbage collector will
|
||||
// crash the next time it runs.
|
||||
// Even making this a fatal error will crash but at least the message can be seen
|
||||
// before the crash - which is not the case with all other options.
|
||||
|
||||
//DestroyAllThinkers();
|
||||
I_FatalError("%s", err.GetMessage());
|
||||
DestroyAllThinkers();
|
||||
throw;
|
||||
}
|
||||
bSerialOverride = false;
|
||||
|
|
1374
src/f_finale.cpp
1374
src/f_finale.cpp
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -54,8 +54,8 @@
|
|||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_player.h"
|
||||
#include "m_misc.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
|
||||
|
@ -406,7 +406,7 @@ void FCompressedFile::Explode ()
|
|||
if (r != Z_OK || newlen != expandsize)
|
||||
{
|
||||
M_Free (expand);
|
||||
I_Error ("Could not decompress cfile");
|
||||
I_Error ("Could not decompress buffer: %s", M_ZLibError(r).GetChars());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -498,7 +498,18 @@ bool FCompressedMemFile::Reopen ()
|
|||
m_Mode = EReading;
|
||||
m_Buffer = m_ImplodedBuffer;
|
||||
m_SourceFromMem = true;
|
||||
Explode ();
|
||||
try
|
||||
{
|
||||
Explode ();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// If we just leave things as they are, m_Buffer and m_ImplodedBuffer
|
||||
// both point to the same memory block and both will try to free it.
|
||||
m_Buffer = NULL;
|
||||
m_SourceFromMem = false;
|
||||
throw;
|
||||
}
|
||||
m_SourceFromMem = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -561,6 +572,20 @@ bool FCompressedMemFile::IsOpen () const
|
|||
return !!m_Buffer;
|
||||
}
|
||||
|
||||
void FCompressedMemFile::GetSizes(unsigned int &compressed, unsigned int &uncompressed) const
|
||||
{
|
||||
if (m_ImplodedBuffer != NULL)
|
||||
{
|
||||
compressed = BigLong(*(unsigned int *)m_ImplodedBuffer);
|
||||
uncompressed = BigLong(*(unsigned int *)(m_ImplodedBuffer + 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
compressed = 0;
|
||||
uncompressed = m_BufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
FPNGChunkFile::FPNGChunkFile (FILE *file, DWORD id)
|
||||
: FCompressedFile (file, EWriting, true, false), m_ChunkID (id)
|
||||
{
|
||||
|
@ -1480,3 +1505,28 @@ FArchive &operator<< (FArchive &arc, 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));
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "dobject.h"
|
||||
#include "r_state.h"
|
||||
|
||||
class FFile
|
||||
{
|
||||
|
@ -123,6 +124,7 @@ public:
|
|||
bool Reopen (); // Re-opens imploded file for reading only
|
||||
void Close ();
|
||||
bool IsOpen () const;
|
||||
void GetSizes(unsigned int &one, unsigned int &two) const;
|
||||
|
||||
void Serialize (FArchive &arc);
|
||||
|
||||
|
@ -283,7 +285,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);
|
||||
|
||||
|
||||
|
||||
|
@ -306,4 +312,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__
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "files.h"
|
||||
#include "i_system.h"
|
||||
#include "templates.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -145,11 +146,16 @@ long FileReader::Read (void *buffer, long len)
|
|||
|
||||
char *FileReader::Gets(char *strbuf, int len)
|
||||
{
|
||||
if (len <= 0) return 0;
|
||||
if (len <= 0 || FilePos >= StartPos + Length) return NULL;
|
||||
char *p = fgets(strbuf, len, File);
|
||||
if (p != NULL)
|
||||
{
|
||||
FilePos = ftell(File) - StartPos;
|
||||
int old = FilePos;
|
||||
FilePos = ftell(File);
|
||||
if (FilePos - StartPos > Length)
|
||||
{
|
||||
strbuf[Length - old + StartPos] = 0;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -218,7 +224,7 @@ FileReaderZ::FileReaderZ (FileReader &file, bool zip)
|
|||
|
||||
if (err != Z_OK)
|
||||
{
|
||||
I_Error ("FileReaderZ: inflateInit failed: %d\n", err);
|
||||
I_Error ("FileReaderZ: inflateInit failed: %s\n", M_ZLibError(err).GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
204
src/fragglescript/t_cmd.cpp
Normal file
204
src/fragglescript/t_cmd.cpp
Normal 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
14
src/fragglescript/t_fs.h
Normal 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
|
203
src/fragglescript/t_fspic.cpp
Normal file
203
src/fragglescript/t_fspic.cpp
Normal 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
4845
src/fragglescript/t_func.cpp
Normal file
File diff suppressed because it is too large
Load diff
367
src/fragglescript/t_load.cpp
Normal file
367
src/fragglescript/t_load.cpp
Normal 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));
|
||||
}
|
||||
}
|
653
src/fragglescript/t_oper.cpp
Normal file
653
src/fragglescript/t_oper.cpp
Normal 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));
|
||||
}
|
||||
|
746
src/fragglescript/t_parse.cpp
Normal file
746
src/fragglescript/t_parse.cpp
Normal 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
|
445
src/fragglescript/t_prepro.cpp
Normal file
445
src/fragglescript/t_prepro.cpp
Normal 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;
|
||||
}
|
||||
|
725
src/fragglescript/t_script.cpp
Normal file
725
src/fragglescript/t_script.cpp
Normal 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 = §ors[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);
|
||||
}
|
||||
}
|
698
src/fragglescript/t_script.h
Normal file
698
src/fragglescript/t_script.h
Normal 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
|
||||
|
628
src/fragglescript/t_spec.cpp
Normal file
628
src/fragglescript/t_spec.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
437
src/fragglescript/t_variable.cpp
Normal file
437
src/fragglescript/t_variable.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -130,10 +130,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
|
|||
|
||||
// Boss cubes should move freely to their destination so it's
|
||||
// probably best to disable all collision detection for them.
|
||||
if (spit->flags & MF_NOCLIP) spit->flags5 |= MF5_NOINTERACTION;
|
||||
|
||||
if (spit != NULL)
|
||||
{
|
||||
if (spit->flags & MF_NOCLIP) spit->flags5 |= MF5_NOINTERACTION;
|
||||
spit->target = targ;
|
||||
spit->master = self;
|
||||
// [RH] Do this correctly for any trajectory. Doom would divide by 0
|
||||
|
@ -152,6 +152,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)
|
||||
|
@ -268,9 +269,14 @@ static void SpawnFly(AActor *self, PClassActor *spawntype, FSoundID sound)
|
|||
{
|
||||
newmobj->CopyFriendliness (eye, false);
|
||||
}
|
||||
if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL))
|
||||
newmobj->SetState (newmobj->SeeState);
|
||||
// Make it act as if it was around when the player first made noise
|
||||
// (if the player has made noise).
|
||||
newmobj->LastHeard = newmobj->Sector->SoundTarget;
|
||||
|
||||
if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL))
|
||||
{
|
||||
newmobj->SetState (newmobj->SeeState);
|
||||
}
|
||||
if (!(newmobj->ObjectFlags & OF_EuthanizeMe))
|
||||
{
|
||||
// telefrag anything in this spot
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
void BeginPlay ();
|
||||
void Tick ();
|
||||
void SetWeapon (EMarineWeapon);
|
||||
void SetSprite (const PClass *source);
|
||||
void SetSprite (PClassActor *source);
|
||||
void Serialize (FArchive &arc);
|
||||
|
||||
int CurrentWeapon;
|
||||
|
|
|
@ -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"
|
||||
|
@ -39,8 +40,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy)
|
|||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
||||
if ((dmflags2 & DF2_BARRELS_RESPAWN) &&
|
||||
(deathmatch || alwaysapplydmflags))
|
||||
if (dmflags2 & DF2_BARRELS_RESPAWN)
|
||||
{
|
||||
self->height = self->GetDefault()->height;
|
||||
self->renderflags |= RF_INVISIBLE;
|
||||
|
@ -52,4 +52,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
|
|||
if (self->player != NULL)
|
||||
{
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO))
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
return 0;
|
||||
|
@ -83,7 +83,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
|
||||
P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
|
@ -158,17 +158,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
|
|||
angle = self->angle + (pr_saw.Random2() * (spread_xy / 255));
|
||||
slope = P_AimLineAttack (self, angle, range, &linetarget) + (pr_saw.Random2() * (spread_z / 255));
|
||||
|
||||
P_LineAttack (self, angle, range,
|
||||
slope, damage,
|
||||
NAME_None, pufftype);
|
||||
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!linetarget && (flags & SF_NOUSEAMMOMISS)))
|
||||
if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO))
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
return 0;
|
||||
}
|
||||
|
||||
P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &linetarget);
|
||||
|
||||
if (!linetarget)
|
||||
{
|
||||
if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64))
|
||||
|
@ -243,7 +241,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
}
|
||||
|
@ -279,7 +277,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
|
||||
return 0;
|
||||
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
}
|
||||
|
@ -304,7 +302,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
|
|||
angle,
|
||||
PLAYERMISSILERANGE,
|
||||
pitch + (pr_fireshotgun2.Random2() * 332063), damage,
|
||||
NAME_None, NAME_BulletPuff);
|
||||
NAME_Hitscan, NAME_BulletPuff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -392,7 +390,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun)
|
|||
AWeapon *weapon = player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
|
||||
|
@ -436,7 +434,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
}
|
||||
P_SpawnPlayerMissile (self, PClass::FindActor("Rocket"));
|
||||
|
@ -491,7 +489,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
|
||||
FState *flash = weapon->FindState(NAME_Flash);
|
||||
|
@ -521,7 +519,7 @@ static void FireRailgun(AActor *self, int RailOffset)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return;
|
||||
|
||||
FState *flash = weapon->FindState(NAME_Flash);
|
||||
|
@ -582,7 +580,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -640,7 +638,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 != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash));
|
||||
P_TraceBleed (damage, thingToHit, self->target);
|
||||
}
|
||||
return 0;
|
||||
|
@ -681,7 +679,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
}
|
||||
self->player->extralight = 2;
|
||||
|
|
|
@ -31,11 +31,18 @@ static PClassActor *GetSpawnType(VMValue *param)
|
|||
}
|
||||
|
||||
|
||||
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, PClassActor *spawntype)
|
||||
void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int flags = 0, int limit = -1)
|
||||
{
|
||||
fixed_t x, y, z;
|
||||
|
||||
|
@ -59,11 +66,14 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *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;
|
||||
|
||||
|
@ -133,9 +143,10 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,9 +161,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack)
|
|||
if (!self->target)
|
||||
return 0;
|
||||
|
||||
PClassActor *spawntype = GetSpawnType(numparam > NAP ? ¶m[NAP] : NULL);
|
||||
A_FaceTarget (self);
|
||||
A_PainShootSkull (self, self->angle, spawntype);
|
||||
PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; }
|
||||
PARAM_ANGLE_OPT (angle) { angle = 0; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_INT_OPT (limit) { limit = -1; }
|
||||
|
||||
if (spawntype == NULL) spawntype = PClass::FindActor("LostSoul");
|
||||
|
||||
if (!(flags & PAF_AIMFACING))
|
||||
A_FaceTarget (self);
|
||||
A_PainShootSkull (self, self->angle+angle, spawntype, flags, limit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PosAttack)
|
|||
S_Sound (self, CHAN_WEAPON, "grunt/attack", 1, ATTN_NORM);
|
||||
angle += pr_posattack.Random2() << 20;
|
||||
damage = ((pr_posattack()%5)+1)*3;
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff);
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ static void A_SPosAttack2 (AActor *self)
|
|||
{
|
||||
int angle = bangle + (pr_sposattack.Random2() << 20);
|
||||
int damage = ((pr_sposattack()%5)+1)*3;
|
||||
P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff);
|
||||
P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack)
|
|||
|
||||
angle = bangle + (pr_cposattack.Random2() << 20);
|
||||
damage = ((pr_cposattack()%5)+1)*3;
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff);
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue