mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 06:42:08 +00:00
Merge remote-tracking branch 'origin' into openal
Conflicts: src/sound/fmodsound.cpp
This commit is contained in:
commit
18597a93a7
507 changed files with 30037 additions and 11065 deletions
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
/Debug
|
||||
*.ncb
|
||||
*.suo
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.aps
|
||||
/Release
|
||||
/wadsrc_wad
|
||||
*.user
|
||||
/debug
|
||||
/release
|
||||
*/debug
|
||||
*/release
|
||||
/release_gcc
|
||||
/dumb/vc6/dumb_static/release
|
||||
/dumb/vc6/dumb_static/debug
|
||||
/DOOMSTATS.TXT
|
||||
/src/gitinfo.h
|
||||
/src/sc_man_scanner.h
|
||||
/src/xlat/xlat_parser.c
|
||||
/src/xlat/xlat_parser.h
|
||||
/src/xlat/xlat_parser.out
|
||||
/tools/*/debug
|
||||
/tools/*/release
|
||||
/tools/*/*.exe
|
||||
/tools/lemon/build
|
||||
/tools/re2c/build
|
||||
/wadsrc/*.pk3
|
|
@ -1,4 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
project(ZDoom)
|
||||
|
||||
IF( NOT CMAKE_BUILD_TYPE )
|
||||
SET( CMAKE_BUILD_TYPE Debug CACHE STRING
|
||||
|
@ -9,9 +10,11 @@ ENDIF( NOT CMAKE_BUILD_TYPE )
|
|||
set( ZDOOM_OUTPUT_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Directory where zdoom.pk3 and the executable will be created." )
|
||||
set( ZDOOM_EXE_NAME "zdoom" CACHE FILEPATH "Name of the executable to create." )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
option( NO_FMOD "Disable FMODEx sound support" )
|
||||
option( NO_OPENAL "Disable OpenAL sound support" )
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUC )
|
||||
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
|
||||
endif( CMAKE_COMPILER_IS_GNUC )
|
||||
endif( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
add_definitions( -DBZ_NO_STDIO )
|
||||
add_library( bz2
|
||||
|
|
|
@ -11,9 +11,9 @@ endif( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
|||
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DDEBUGMODE=1" )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUC )
|
||||
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" )
|
||||
endif( CMAKE_COMPILER_IS_GNUC )
|
||||
endif( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS )
|
||||
if( NOT ITOA_EXISTS )
|
||||
|
@ -36,6 +36,7 @@ add_library( dumb
|
|||
src/core/rendsig.c
|
||||
src/core/unload.c
|
||||
src/helpers/barray.c
|
||||
src/helpers/blip_buf.c
|
||||
src/helpers/clickrem.c
|
||||
src/helpers/memfile.c
|
||||
src/helpers/resample.c
|
||||
|
@ -60,6 +61,8 @@ add_library( dumb
|
|||
src/it/loadmod2.c
|
||||
src/it/loadmtm.c
|
||||
src/it/loadmtm2.c
|
||||
src/it/loadokt.c
|
||||
src/it/loadokt2.c
|
||||
src/it/loadoldpsm.c
|
||||
src/it/loadoldpsm2.c
|
||||
src/it/loadpsm.c
|
||||
|
@ -83,6 +86,8 @@ add_library( dumb
|
|||
src/it/readmod.c
|
||||
src/it/readmod2.c
|
||||
src/it/readmtm.c
|
||||
src/it/readokt.c
|
||||
src/it/readokt2.c
|
||||
src/it/readoldpsm.c
|
||||
src/it/readpsm.c
|
||||
src/it/readptm.c
|
||||
|
@ -96,6 +101,6 @@ add_library( dumb
|
|||
src/it/xmeffect.c )
|
||||
target_link_libraries( dumb )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
|
|
@ -233,7 +233,6 @@ int32 DUMBEXPORT duh_get_length(DUH *duh);
|
|||
|
||||
const char *DUMBEXPORT duh_get_tag(DUH *duh, const char *key);
|
||||
|
||||
|
||||
/* Signal Rendering Functions */
|
||||
|
||||
typedef struct DUH_SIGRENDERER DUH_SIGRENDERER;
|
||||
|
@ -396,11 +395,13 @@ void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sig
|
|||
int DUMBCALLBACK dumb_it_callback_terminate(void *data);
|
||||
int DUMBCALLBACK dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte);
|
||||
|
||||
/* dumb_*_mod*: restrict |= 1-Don't read 15 sample files / 2-Use old pattern counting method */
|
||||
|
||||
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);
|
||||
|
@ -408,12 +409,13 @@ DUH *DUMBEXPORT dumb_load_old_psm(const char * filename);
|
|||
DUH *DUMBEXPORT dumb_load_mtm(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_riff(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_asy(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_okt(const char *filename);
|
||||
|
||||
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);
|
||||
|
@ -421,12 +423,13 @@ DUH *DUMBEXPORT dumb_read_old_psm(DUMBFILE *f);
|
|||
DUH *DUMBEXPORT dumb_read_mtm(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_riff(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_asy(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f);
|
||||
|
||||
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);
|
||||
|
@ -434,12 +437,13 @@ DUH *DUMBEXPORT dumb_load_old_psm_quick(const char * filename);
|
|||
DUH *DUMBEXPORT dumb_load_mtm_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_riff_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_asy_quick(const char *filename);
|
||||
DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename);
|
||||
|
||||
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);
|
||||
|
@ -447,6 +451,7 @@ DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f);
|
|||
DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_riff_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f);
|
||||
DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f);
|
||||
|
||||
int32 DUMBEXPORT dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder);
|
||||
void DUMBEXPORT dumb_it_do_initial_runthrough(DUH *duh);
|
||||
|
@ -606,6 +611,8 @@ sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type);
|
|||
DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 pos);
|
||||
sigrenderer_t *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type);
|
||||
|
||||
int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata);
|
||||
|
||||
|
||||
/* Standard Signal Types */
|
||||
|
||||
|
@ -662,6 +669,8 @@ typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO;
|
|||
|
||||
typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data);
|
||||
|
||||
#include "internal/blip_buf.h"
|
||||
|
||||
struct DUMB_RESAMPLER
|
||||
{
|
||||
void *src;
|
||||
|
@ -679,6 +688,9 @@ struct DUMB_RESAMPLER
|
|||
signed char x8[3*2];
|
||||
} x;
|
||||
int overshot;
|
||||
int last_clock;
|
||||
int last_amp[2];
|
||||
blip_t* blip_buffer[2];
|
||||
};
|
||||
|
||||
struct DUMB_VOLUME_RAMP_INFO
|
||||
|
|
77
dumb/include/internal/blip_buf.h
Normal file
77
dumb/include/internal/blip_buf.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/** \file
|
||||
Sample buffer that resamples from input clock rate to output sample rate */
|
||||
|
||||
/* blip_buf 1.1.0 */
|
||||
#ifndef BLIP_BUF_H
|
||||
#define BLIP_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
|
||||
is changed. */
|
||||
typedef struct blip_t blip_t;
|
||||
|
||||
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
||||
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||
buffer, or NULL if insufficient memory. */
|
||||
blip_t* blip_new( int sample_count );
|
||||
|
||||
blip_t* blip_dup( blip_t* );
|
||||
|
||||
/** Sets approximate input clock rate and output sample rate. For every
|
||||
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
||||
|
||||
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20 };
|
||||
|
||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||
void blip_clear( blip_t* );
|
||||
|
||||
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
||||
|
||||
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||
samples available. */
|
||||
int blip_clocks_needed( const blip_t*, int sample_count );
|
||||
|
||||
enum { /** Maximum number of samples that can be generated from one time frame. */
|
||||
blip_max_frame = 4000 };
|
||||
|
||||
/** Makes input clocks before clock_duration available for reading as output
|
||||
samples. Also begins new time frame at clock_duration, so that clock time 0 in
|
||||
the new time frame specifies the same clock as clock_duration in the old time
|
||||
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||
however many clocks there are in two output samples). */
|
||||
void blip_end_frame( blip_t*, unsigned int clock_duration );
|
||||
|
||||
/** Number of buffered samples available for reading. */
|
||||
int blip_samples_avail( const blip_t* );
|
||||
|
||||
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
||||
'stereo' is true, writes output to every other element of 'out', allowing easy
|
||||
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||
samples. Returns number of samples actually read. */
|
||||
int blip_read_samples( blip_t*, int out [], int count );
|
||||
|
||||
/** Reads the current integrator and returns it */
|
||||
int blip_peek_sample( blip_t* );
|
||||
|
||||
/** Frees buffer. No effect if NULL is passed. */
|
||||
void blip_delete( blip_t* );
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef blip_t blip_buffer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -54,7 +54,7 @@ sigdata->flags & IT_COMPATIBLE_GXX
|
|||
* handle ambiguities in the format specification. The correct code in each
|
||||
* case will be determined most likely by experimentation.
|
||||
*/
|
||||
#define STEREO_SAMPLES_COUNT_AS_TWO
|
||||
//#define STEREO_SAMPLES_COUNT_AS_TWO
|
||||
#define INVALID_ORDERS_END_SONG
|
||||
#define INVALID_NOTES_CAUSE_NOTE_CUT
|
||||
#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP
|
||||
|
@ -300,7 +300,18 @@ struct IT_SAMPLE
|
|||
#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36
|
||||
#define IT_PTM_NOTE_SLIDE_UP_RETRIG 37
|
||||
|
||||
#define IT_N_EFFECTS 38
|
||||
/* More effects needed for OKT compatibility */
|
||||
#define IT_OKT_NOTE_SLIDE_DOWN 38
|
||||
#define IT_OKT_NOTE_SLIDE_DOWN_ROW 39
|
||||
#define IT_OKT_NOTE_SLIDE_UP 40
|
||||
#define IT_OKT_NOTE_SLIDE_UP_ROW 41
|
||||
#define IT_OKT_ARPEGGIO_3 42
|
||||
#define IT_OKT_ARPEGGIO_4 43
|
||||
#define IT_OKT_ARPEGGIO_5 44
|
||||
#define IT_OKT_VOLUME_SLIDE_DOWN 45
|
||||
#define IT_OKT_VOLUME_SLIDE_UP 46
|
||||
|
||||
#define IT_N_EFFECTS 47
|
||||
|
||||
/* These represent the top nibble of the command value. */
|
||||
#define IT_S_SET_FILTER 0 /* Greyed out in IT... */
|
||||
|
@ -399,6 +410,10 @@ struct IT_PATTERN
|
|||
|
||||
#define IT_WAS_A_669 1024
|
||||
|
||||
#define IT_WAS_AN_OKT 2048
|
||||
|
||||
#define IT_WAS_AN_STM 4096
|
||||
|
||||
#define IT_ORDER_END 255
|
||||
#define IT_ORDER_SKIP 254
|
||||
|
||||
|
@ -452,6 +467,7 @@ struct IT_PLAYING_ENVELOPE
|
|||
#define IT_PLAYING_SUSTAINOFF 2
|
||||
#define IT_PLAYING_FADING 4
|
||||
#define IT_PLAYING_DEAD 8
|
||||
#define IT_PLAYING_REVERSE 16
|
||||
|
||||
struct IT_PLAYING
|
||||
{
|
||||
|
@ -586,7 +602,8 @@ struct IT_CHANNEL
|
|||
|
||||
unsigned char new_note_action;
|
||||
|
||||
int arpeggio;
|
||||
unsigned int arpeggio;
|
||||
int arpeggio_shift;
|
||||
unsigned char retrig;
|
||||
unsigned char xm_retrig;
|
||||
int retrig_tick;
|
||||
|
@ -601,7 +618,7 @@ struct IT_CHANNEL
|
|||
int portamento;
|
||||
int toneporta;
|
||||
int toneslide;
|
||||
unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide;
|
||||
unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide, okt_toneslide;
|
||||
unsigned char destnote;
|
||||
unsigned char toneslide_retrig;
|
||||
|
||||
|
@ -643,6 +660,10 @@ struct IT_CHANNEL
|
|||
unsigned char xm_lastX1;
|
||||
unsigned char xm_lastX2;
|
||||
|
||||
unsigned char inv_loop_delay;
|
||||
unsigned char inv_loop_speed;
|
||||
int inv_loop_offset;
|
||||
|
||||
IT_PLAYING *playing;
|
||||
|
||||
#ifdef BIT_ARRAY_BULLSHIT
|
||||
|
@ -802,6 +823,7 @@ extern DUH_SIGTYPE_DESC _dumb_sigtype_it;
|
|||
#define XM_E_NOTE_CUT 0xC
|
||||
#define XM_E_NOTE_DELAY 0xD
|
||||
#define XM_E_PATTERN_DELAY 0xE
|
||||
#define XM_E_SET_MIDI_MACRO 0xF
|
||||
|
||||
#define XM_X_EXTRAFINE_PORTA_UP 1
|
||||
#define XM_X_EXTRAFINE_PORTA_DOWN 2
|
||||
|
@ -880,4 +902,6 @@ void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry);
|
|||
|
||||
int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f);
|
||||
|
||||
void _dumb_it_interleave_stereo_sample(IT_SAMPLE *sample);
|
||||
|
||||
#endif /* INTERNAL_IT_H */
|
||||
|
|
|
@ -130,3 +130,22 @@ DUH *make_duh(
|
|||
|
||||
return duh;
|
||||
}
|
||||
|
||||
int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
|
||||
{
|
||||
DUH_SIGNAL **signal;
|
||||
|
||||
if ( !duh || !desc || !sigdata ) return -1;
|
||||
|
||||
signal = ( DUH_SIGNAL ** ) realloc( duh->signal, ( duh->n_signals + 1 ) * sizeof( *duh->signal ) );
|
||||
if ( !signal ) return -1;
|
||||
duh->signal = signal;
|
||||
|
||||
memmove( signal + 1, signal, duh->n_signals * sizeof( *signal ) );
|
||||
duh->n_signals++;
|
||||
|
||||
signal[ 0 ] = make_signal( desc, sigdata );
|
||||
if ( !signal[ 0 ] ) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -29,16 +29,30 @@
|
|||
*/
|
||||
sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type)
|
||||
{
|
||||
int i;
|
||||
DUH_SIGNAL *signal;
|
||||
|
||||
if (!duh) return NULL;
|
||||
|
||||
if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
|
||||
if ( sig >= 0 )
|
||||
{
|
||||
if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
|
||||
|
||||
signal = duh->signal[sig];
|
||||
signal = duh->signal[sig];
|
||||
|
||||
if (signal && signal->desc->type == type)
|
||||
return signal->sigdata;
|
||||
if (signal && signal->desc->type == type)
|
||||
return signal->sigdata;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = 0; i < duh->n_signals; i++ )
|
||||
{
|
||||
signal = duh->signal[i];
|
||||
|
||||
if (signal && signal->desc->type == type)
|
||||
return signal->sigdata;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
354
dumb/src/helpers/blip_buf.c
Normal file
354
dumb/src/helpers/blip_buf.c
Normal file
|
@ -0,0 +1,354 @@
|
|||
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "internal/blip_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
library 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#if defined (BLARGG_TEST) && BLARGG_TEST
|
||||
#include "blargg_test.h"
|
||||
#endif
|
||||
|
||||
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
|
||||
Avoids constants that don't fit in 32 bits. */
|
||||
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
|
||||
typedef unsigned long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#elif defined(ULLONG_MAX)
|
||||
typedef unsigned long long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#else
|
||||
typedef unsigned fixed_t;
|
||||
enum { pre_shift = 0 };
|
||||
|
||||
#endif
|
||||
|
||||
enum { time_bits = pre_shift + 20 };
|
||||
|
||||
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
|
||||
|
||||
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
|
||||
|
||||
enum { half_width = 8 };
|
||||
enum { buf_extra = half_width*2 + end_frame_extra };
|
||||
enum { phase_bits = 5 };
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { delta_bits = 15 };
|
||||
enum { delta_unit = 1 << delta_bits };
|
||||
enum { frac_bits = time_bits - pre_shift };
|
||||
|
||||
/* We could eliminate avail and encode whole samples in offset, but that would
|
||||
limit the total buffered samples to blip_max_frame. That could only be
|
||||
increased by decreasing time_bits, which would reduce resample ratio accuracy.
|
||||
*/
|
||||
|
||||
/** Sample buffer that resamples to output rate and accumulates samples
|
||||
until they're read out */
|
||||
struct blip_t
|
||||
{
|
||||
fixed_t factor;
|
||||
fixed_t offset;
|
||||
int avail;
|
||||
int size;
|
||||
int integrator;
|
||||
};
|
||||
|
||||
typedef int buf_t;
|
||||
|
||||
/* probably not totally portable */
|
||||
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
|
||||
|
||||
/* Arithmetic (sign-preserving) right shift */
|
||||
#define ARITH_SHIFT( n, shift ) \
|
||||
((n) >> (shift))
|
||||
|
||||
enum { max_sample = +32767 };
|
||||
enum { min_sample = -32768 };
|
||||
|
||||
#define CLAMP( n ) \
|
||||
{\
|
||||
if ( (short) n != n )\
|
||||
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
|
||||
}
|
||||
|
||||
static void check_assumptions( void )
|
||||
{
|
||||
int n;
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
|
||||
|
||||
n = max_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == max_sample );
|
||||
|
||||
n = min_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == min_sample );
|
||||
|
||||
assert( blip_max_ratio <= time_unit );
|
||||
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
|
||||
}
|
||||
|
||||
blip_t* blip_new( int size )
|
||||
{
|
||||
blip_t* m;
|
||||
assert( size >= 0 );
|
||||
|
||||
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( m )
|
||||
{
|
||||
m->factor = time_unit / blip_max_ratio;
|
||||
m->size = size;
|
||||
blip_clear( m );
|
||||
check_assumptions();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
blip_t* blip_dup( blip_t* m )
|
||||
{
|
||||
size_t size = sizeof *m + (m->size + buf_extra) * sizeof(buf_t);
|
||||
blip_t* r = (blip_t*) malloc( size );
|
||||
if ( r ) memcpy( r, m, size );
|
||||
return r;
|
||||
}
|
||||
|
||||
void blip_delete( blip_t* m )
|
||||
{
|
||||
if ( m != NULL )
|
||||
{
|
||||
/* Clear fields in case user tries to use after freeing */
|
||||
memset( m, 0, sizeof *m );
|
||||
free( m );
|
||||
}
|
||||
}
|
||||
|
||||
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
|
||||
{
|
||||
double factor = time_unit * sample_rate / clock_rate;
|
||||
m->factor = (fixed_t) factor;
|
||||
|
||||
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
|
||||
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
|
||||
|
||||
/* Avoid requiring math.h. Equivalent to
|
||||
m->factor = (int) ceil( factor ) */
|
||||
if ( m->factor < factor )
|
||||
m->factor++;
|
||||
|
||||
/* At this point, factor is most likely rounded up, but could still
|
||||
have been rounded down in the floating-point calculation. */
|
||||
}
|
||||
|
||||
void blip_clear( blip_t* m )
|
||||
{
|
||||
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
|
||||
factor is rounded up. factor-1 is suitable if factor is rounded down.
|
||||
Since we don't know rounding direction, factor/2 accommodates either,
|
||||
with the slight loss of showing an error in half the time. Since for
|
||||
a 64-bit factor this is years, the halving isn't a problem. */
|
||||
|
||||
m->offset = m->factor / 2;
|
||||
m->avail = 0;
|
||||
m->integrator = 0;
|
||||
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_t* m, int samples )
|
||||
{
|
||||
fixed_t needed;
|
||||
|
||||
/* Fails if buffer can't hold that many more samples */
|
||||
assert( samples >= 0 && m->avail + samples <= m->size );
|
||||
|
||||
needed = (fixed_t) samples * time_unit;
|
||||
if ( needed < m->offset )
|
||||
return 0;
|
||||
|
||||
return (int)((needed - m->offset + m->factor - 1) / m->factor);
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_t* m, unsigned t )
|
||||
{
|
||||
fixed_t off = t * m->factor + m->offset;
|
||||
m->avail += (int)(off >> time_bits);
|
||||
m->offset = off & (time_unit - 1);
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( m->avail <= m->size );
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_t* m )
|
||||
{
|
||||
return m->avail;
|
||||
}
|
||||
|
||||
static void remove_samples( blip_t* m, int count )
|
||||
{
|
||||
buf_t* buf = SAMPLES( m );
|
||||
int remain = m->avail + buf_extra - count;
|
||||
m->avail -= count;
|
||||
|
||||
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
||||
memset( &buf [remain], 0, count * sizeof buf [0] );
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_t* m, int out [], int count )
|
||||
{
|
||||
assert( count >= 0 );
|
||||
|
||||
if ( count > m->avail )
|
||||
count = m->avail;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
buf_t const* in = SAMPLES( m );
|
||||
buf_t const* end = in + count;
|
||||
int sum = m->integrator;
|
||||
do
|
||||
{
|
||||
/* Eliminate fraction */
|
||||
int s = ARITH_SHIFT( sum, delta_bits - 8 );
|
||||
|
||||
sum += *in++;
|
||||
|
||||
*out = s;
|
||||
out++;
|
||||
|
||||
/* High-pass filter */
|
||||
sum -= s >> (8 - (delta_bits - bass_shift)); //<< (delta_bits - bass_shift - 8);
|
||||
}
|
||||
while ( in != end );
|
||||
m->integrator = sum;
|
||||
|
||||
remove_samples( m, count );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int blip_peek_sample( blip_t* m )
|
||||
{
|
||||
return ARITH_SHIFT( m->integrator, delta_bits - 8 );
|
||||
}
|
||||
|
||||
/* Things that didn't help performance on x86:
|
||||
__attribute__((aligned(128)))
|
||||
#define short int
|
||||
restrict
|
||||
*/
|
||||
|
||||
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
|
||||
static short const bl_step [phase_count + 1] [half_width] =
|
||||
{
|
||||
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
|
||||
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
|
||||
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
|
||||
{ 46, -122, 336, -431, 942, -549, 4156,20829},
|
||||
{ 47, -123, 327, -404, 868, -418, 3629,20679},
|
||||
{ 47, -122, 316, -375, 792, -285, 3124,20488},
|
||||
{ 47, -120, 303, -344, 714, -151, 2644,20256},
|
||||
{ 46, -117, 289, -310, 634, -17, 2188,19985},
|
||||
{ 46, -114, 273, -275, 553, 117, 1758,19675},
|
||||
{ 44, -108, 255, -237, 471, 247, 1356,19327},
|
||||
{ 43, -103, 237, -199, 390, 373, 981,18944},
|
||||
{ 42, -98, 218, -160, 310, 495, 633,18527},
|
||||
{ 40, -91, 198, -121, 231, 611, 314,18078},
|
||||
{ 38, -84, 178, -81, 153, 722, 22,17599},
|
||||
{ 36, -76, 157, -43, 80, 824, -241,17092},
|
||||
{ 34, -68, 135, -3, 8, 919, -476,16558},
|
||||
{ 32, -61, 115, 34, -60, 1006, -683,16001},
|
||||
{ 29, -52, 94, 70, -123, 1083, -862,15422},
|
||||
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
|
||||
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
|
||||
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
|
||||
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
|
||||
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
|
||||
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
|
||||
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
|
||||
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
|
||||
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
|
||||
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
|
||||
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
|
||||
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
|
||||
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
|
||||
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
|
||||
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||
};
|
||||
|
||||
/* Shifting by pre_shift allows calculation using unsigned int rather than
|
||||
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
|
||||
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||
simply ignoring the low half. */
|
||||
|
||||
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int const phase_shift = frac_bits - phase_bits;
|
||||
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||
short const* in = bl_step [phase];
|
||||
short const* rev = bl_step [phase_count - phase];
|
||||
|
||||
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = (delta * interp) >> delta_bits;
|
||||
delta -= delta2;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [0] += in[0]*delta + in[half_width+0]*delta2;
|
||||
out [1] += in[1]*delta + in[half_width+1]*delta2;
|
||||
out [2] += in[2]*delta + in[half_width+2]*delta2;
|
||||
out [3] += in[3]*delta + in[half_width+3]*delta2;
|
||||
out [4] += in[4]*delta + in[half_width+4]*delta2;
|
||||
out [5] += in[5]*delta + in[half_width+5]*delta2;
|
||||
out [6] += in[6]*delta + in[half_width+6]*delta2;
|
||||
out [7] += in[7]*delta + in[half_width+7]*delta2;
|
||||
|
||||
in = rev;
|
||||
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
|
||||
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
|
||||
out [10] += in[5]*delta + in[5-half_width]*delta2;
|
||||
out [11] += in[4]*delta + in[4-half_width]*delta2;
|
||||
out [12] += in[3]*delta + in[3-half_width]*delta2;
|
||||
out [13] += in[2]*delta + in[2-half_width]*delta2;
|
||||
out [14] += in[1]*delta + in[1-half_width]*delta2;
|
||||
out [15] += in[0]*delta + in[0-half_width]*delta2;
|
||||
}
|
||||
|
||||
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = delta * interp;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
|
||||
out [7] += delta * delta_unit - delta2;
|
||||
out [8] += delta2;
|
||||
}
|
|
@ -95,7 +95,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES
|
||||
#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES
|
||||
#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO
|
||||
#define MIX_ALIAS(op, upd, offset) MONO_DEST_MIX_ALIAS(op, upd, offset)
|
||||
#define MIX_ALIAS(count) MONO_DEST_MIX_ALIAS(count)
|
||||
#define PEEK_ALIAS MONO_DEST_PEEK_ALIAS
|
||||
#define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||
#define MIX_ZEROS(op) *dst++ op 0
|
||||
|
@ -137,7 +138,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||
}
|
||||
#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||
#define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset)
|
||||
#define MIX_ALIAS(count) STEREO_DEST_MIX_ALIAS(count)
|
||||
#define PEEK_ALIAS STEREO_DEST_PEEK_ALIAS
|
||||
#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1)
|
||||
#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3)
|
||||
#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; }
|
||||
|
@ -157,6 +159,9 @@ static int process_pickup(DUMB_RESAMPLER *resampler)
|
|||
#undef MONO_DEST_VOLUME_ZEROS
|
||||
#undef MONO_DEST_VOLUME_VARIABLES
|
||||
#undef MONO_DEST_VOLUME_PARAMETERS
|
||||
#undef STEREO_DEST_PEEK_ALIAS
|
||||
#undef MONO_DEST_PEEK_ALIAS
|
||||
#undef POKE_ALIAS
|
||||
#undef COPYSRC2
|
||||
#undef COPYSRC
|
||||
#undef DIVIDE_BY_SRC_CHANNELS
|
||||
|
|
|
@ -46,12 +46,13 @@
|
|||
|
||||
int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta)
|
||||
{
|
||||
int dt;
|
||||
int dt, inv_dt;
|
||||
int VOLUME_VARIABLES;
|
||||
long done;
|
||||
long todo;
|
||||
LONG_LONG todo64;
|
||||
int quality;
|
||||
int blip_samples[256*SRC_CHANNELS];
|
||||
|
||||
if (!resampler || resampler->dir == 0) return 0;
|
||||
ASSERT(resampler->dir == -1 || resampler->dir == 1);
|
||||
|
@ -59,6 +60,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
done = 0;
|
||||
dt = (int)(delta * 65536.0 + 0.5);
|
||||
if (dt == 0 || dt == 0x80000000) return 0;
|
||||
inv_dt = (int)(1.0 / delta * 65536.0 + 0.5);
|
||||
SET_VOLUME_VARIABLES;
|
||||
|
||||
if (VOLUMES_ARE_ZERO) dst = NULL;
|
||||
|
@ -104,29 +106,33 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
subpos = (long)new_subpos & 65535;
|
||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
// TODO: check what happens when multiple tempo slides occur per row
|
||||
HEAVYASSERT(pos >= resampler->start);
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x -= (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
POKE_ALIAS(0);
|
||||
pos--;
|
||||
x += SRC_CHANNELS;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
while ( todo_clocks ) {
|
||||
todo_clocks_set = todo_clocks;
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
todo_clocks -= todo_clocks_set;
|
||||
while ( resampler->last_clock < todo_clocks_set )
|
||||
{
|
||||
POKE_ALIAS(2);
|
||||
pos--;
|
||||
x -= SRC_CHANNELS;
|
||||
}
|
||||
todo = todo_clocks_set >> 16;
|
||||
MIX_ALIAS( todo );
|
||||
}
|
||||
x = xstart = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
MIX_ALIAS(+=, 1, 2);
|
||||
subpos += dt;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart));
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
/* Linear interpolation, backwards */
|
||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||
|
@ -205,28 +211,32 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO
|
|||
subpos = (long)new_subpos & 65535;
|
||||
} else if (quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, forwards */
|
||||
int todo_clocks = todo << 16, todo_clocks_set = todo_clocks;
|
||||
SRCTYPE xbuf[2*SRC_CHANNELS];
|
||||
SRCTYPE *x = &xbuf[0];
|
||||
SRCTYPE *xstart;
|
||||
COPYSRC(xbuf, 0, resampler->X, 1);
|
||||
COPYSRC(xbuf, 1, resampler->X, 2);
|
||||
while (todo && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) {
|
||||
HEAVYASSERT(pos < resampler->end);
|
||||
MIX_ALIAS(+=, 1, 0);
|
||||
subpos += dt;
|
||||
pos += subpos >> 16;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
todo--;
|
||||
POKE_ALIAS(0);
|
||||
pos++;
|
||||
x += SRC_CHANNELS;
|
||||
}
|
||||
x = &src[pos*SRC_CHANNELS];
|
||||
while ( todo_clocks ) {
|
||||
todo_clocks_set = todo_clocks;
|
||||
if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536;
|
||||
todo_clocks -= todo_clocks_set;
|
||||
while ( resampler->last_clock < todo_clocks_set )
|
||||
{
|
||||
POKE_ALIAS(-2);
|
||||
pos++;
|
||||
x += SRC_CHANNELS;
|
||||
}
|
||||
todo = todo_clocks_set >> 16;
|
||||
MIX_ALIAS( todo );
|
||||
}
|
||||
x = xstart = &src[pos*SRC_CHANNELS];
|
||||
LOOP4(todo,
|
||||
MIX_ALIAS(+=, 1, -2);
|
||||
subpos += dt;
|
||||
x += (subpos >> 16) * SRC_CHANNELS;
|
||||
subpos &= 65535;
|
||||
);
|
||||
pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart));
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
/* Linear interpolation, forwards */
|
||||
SRCTYPE xbuf[3*SRC_CHANNELS];
|
||||
|
@ -339,7 +349,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
HEAVYASSERT(pos >= resampler->start);
|
||||
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing, backwards */
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
PEEK_ALIAS;
|
||||
} else if (quality <= DUMB_RQ_LINEAR) {
|
||||
/* Linear interpolation, backwards */
|
||||
MIX_LINEAR(=, 0, 2, 1);
|
||||
|
@ -351,7 +361,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
HEAVYASSERT(pos < resampler->end);
|
||||
if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
|
||||
/* Aliasing */
|
||||
MIX_ALIAS(=, 0, 1);
|
||||
PEEK_ALIAS;
|
||||
} else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
|
||||
/* Linear interpolation, forwards */
|
||||
MIX_LINEAR(=, 0, 1, 2);
|
||||
|
@ -368,6 +378,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
|||
#undef MIX_CUBIC
|
||||
#undef MIX_LINEAR
|
||||
#undef MIX_ALIAS
|
||||
#undef PEEK_ALIAS
|
||||
#undef VOLUMES_ARE_ZERO
|
||||
#undef SET_VOLUME_VARIABLES
|
||||
#undef RETURN_VOLUME_VARIABLES
|
||||
|
|
|
@ -117,9 +117,9 @@ int dumb_resampling_quality = DUMB_RQ_CUBIC;
|
|||
*/
|
||||
#define LOOP4(iterator, CONTENT) \
|
||||
{ \
|
||||
while (iterator) { \
|
||||
while ( (iterator)-- ) \
|
||||
{ \
|
||||
CONTENT; \
|
||||
(iterator)--; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
@ -189,7 +189,7 @@ static void init_cubic(void)
|
|||
|
||||
#define SRCTYPE sample_t
|
||||
#define SRCBITS 24
|
||||
#define ALIAS(x, vol) MULSC(x, vol)
|
||||
#define ALIAS(x) (x >> 8)
|
||||
#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
|
@ -225,7 +225,7 @@ static void init_cubic(void)
|
|||
#define SUFFIX _16
|
||||
#define SRCTYPE short
|
||||
#define SRCBITS 16
|
||||
#define ALIAS(x, vol) (x * vol >> 8)
|
||||
#define ALIAS(x) (x)
|
||||
#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
|
@ -247,7 +247,7 @@ static void init_cubic(void)
|
|||
#define SUFFIX _8
|
||||
#define SRCTYPE signed char
|
||||
#define SRCBITS 8
|
||||
#define ALIAS(x, vol) (x * vol)
|
||||
#define ALIAS(x) (x << 8)
|
||||
#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
|
||||
/*
|
||||
#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
|
||||
|
|
|
@ -69,6 +69,11 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann
|
|||
}
|
||||
for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0;
|
||||
resampler->overshot = -1;
|
||||
resampler->last_clock = 0;
|
||||
resampler->last_amp[0] = 0;
|
||||
resampler->last_amp[1] = 0;
|
||||
blip_clear(resampler->blip_buffer[0]);
|
||||
blip_clear(resampler->blip_buffer[1]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,6 +82,21 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
{
|
||||
DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
|
||||
if (!resampler) return NULL;
|
||||
resampler->blip_buffer[0] = blip_new( 256 );
|
||||
if (!resampler->blip_buffer[0])
|
||||
{
|
||||
free(resampler);
|
||||
return NULL;
|
||||
}
|
||||
resampler->blip_buffer[1] = blip_new( 256 );
|
||||
if (!resampler->blip_buffer[1])
|
||||
{
|
||||
free(resampler->blip_buffer[0]);
|
||||
free(resampler);
|
||||
return NULL;
|
||||
}
|
||||
blip_set_rates(resampler->blip_buffer[0], 65536, 1);
|
||||
blip_set_rates(resampler->blip_buffer[1], 65536, 1);
|
||||
dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
|
||||
return resampler;
|
||||
}
|
||||
|
@ -123,16 +143,41 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
}
|
||||
#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f
|
||||
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
|
||||
#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
*dst++ op ALIAS(x[offset], vol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume, vol ); \
|
||||
#define POKE_ALIAS(offset) { \
|
||||
int delta = ALIAS(x[offset]) - resampler->last_amp[0]; \
|
||||
resampler->last_amp[0] += delta; \
|
||||
if ( delta ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, delta ); \
|
||||
resampler->last_clock += inv_dt; \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
int xm = x[offset]; \
|
||||
*dst++ op ALIAS(xm, lvol); \
|
||||
*dst++ op ALIAS(xm, rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
#define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol )
|
||||
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], vol ); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume, vol ); \
|
||||
); \
|
||||
}
|
||||
#define STEREO_DEST_PEEK_ALIAS { \
|
||||
int sample = blip_peek_sample( resampler->blip_buffer[0] ); \
|
||||
*dst++ = MULSC( sample, lvol ); \
|
||||
*dst++ = MULSC( sample, rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||
int sample, n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
LOOP4( count, \
|
||||
sample = blip_samples[n++]; \
|
||||
*dst++ += MULSC( sample, lvol ); \
|
||||
*dst++ += MULSC( sample, rvol ); \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
*dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \
|
||||
|
@ -208,16 +253,51 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos,
|
|||
if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \
|
||||
}
|
||||
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
|
||||
#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
*dst++ op ALIAS(x[(offset)*2], lvol) + ALIAS(x[(offset)*2+1], rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
#define POKE_ALIAS(offset) { \
|
||||
int deltal = ALIAS(x[(offset)*2+0]) - resampler->last_amp[0]; \
|
||||
int deltar = ALIAS(x[(offset)*2+1]) - resampler->last_amp[1]; \
|
||||
resampler->last_amp[0] += deltal; \
|
||||
resampler->last_amp[1] += deltar; \
|
||||
if ( deltal ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, deltal ); \
|
||||
if ( deltar ) blip_add_delta( resampler->blip_buffer[1], resampler->last_clock, deltar ); \
|
||||
resampler->last_clock += inv_dt; \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \
|
||||
*dst++ op ALIAS(x[(offset)*2], lvol); \
|
||||
*dst++ op ALIAS(x[(offset)*2+1], rvol); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \
|
||||
if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \
|
||||
#define MONO_DEST_PEEK_ALIAS { \
|
||||
*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
|
||||
MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||
}
|
||||
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], lvol ) + MULSC( blip_samples[256+n], rvol ); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define STEREO_DEST_PEEK_ALIAS { \
|
||||
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ); \
|
||||
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||
}
|
||||
#define STEREO_DEST_MIX_ALIAS(count) { \
|
||||
int n = 0; \
|
||||
resampler->last_clock -= count * 65536; \
|
||||
blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \
|
||||
blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \
|
||||
blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \
|
||||
blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \
|
||||
LOOP4( count, \
|
||||
*dst++ += MULSC( blip_samples[n], lvol); \
|
||||
*dst++ += MULSC( blip_samples[256+n], rvol); \
|
||||
n++; \
|
||||
UPDATE_VOLUME( volume_left, lvol ); \
|
||||
UPDATE_VOLUME( volume_right, rvol ); \
|
||||
); \
|
||||
}
|
||||
#define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \
|
||||
*dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh)
|
||||
{
|
||||
return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT);
|
||||
return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,18 +31,71 @@
|
|||
//#define INVESTIGATE_OLD_INSTRUMENTS
|
||||
|
||||
|
||||
|
||||
static int it_seek(DUMBFILE *f, int32 offset)
|
||||
typedef struct tdumbfile_mem_status
|
||||
{
|
||||
int32 pos = dumbfile_pos(f);
|
||||
const unsigned char * ptr;
|
||||
unsigned offset, size;
|
||||
} dumbfile_mem_status;
|
||||
|
||||
if (pos > offset)
|
||||
static int dumbfile_mem_skip(void * f, int32 n)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
s->offset += n;
|
||||
if (s->offset > s->size)
|
||||
{
|
||||
s->offset = s->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int dumbfile_mem_getc(void * f)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
if (s->offset < s->size)
|
||||
{
|
||||
return *(s->ptr + s->offset++);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32 dumbfile_mem_getnc(char * ptr, int32 n, void * f)
|
||||
{
|
||||
dumbfile_mem_status * s = (dumbfile_mem_status *) f;
|
||||
int32 max = s->size - s->offset;
|
||||
if (max > n) max = n;
|
||||
if (max)
|
||||
{
|
||||
memcpy(ptr, s->ptr + s->offset, max);
|
||||
s->offset += max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DUMBFILE_SYSTEM mem_dfs = {
|
||||
NULL, // open
|
||||
&dumbfile_mem_skip,
|
||||
&dumbfile_mem_getc,
|
||||
&dumbfile_mem_getnc,
|
||||
NULL // close
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int it_seek(dumbfile_mem_status * s, int32 offset)
|
||||
{
|
||||
if ( (unsigned)offset > s->size )
|
||||
return -1;
|
||||
|
||||
if (pos < offset)
|
||||
if (dumbfile_skip(f, offset - pos))
|
||||
return -1;
|
||||
|
||||
s->offset = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -306,6 +359,8 @@ static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
|
|||
envelope->loop_end = dumbfile_getc(f);
|
||||
envelope->sus_loop_start = dumbfile_getc(f);
|
||||
envelope->sus_loop_end = dumbfile_getc(f);
|
||||
if (envelope->n_nodes > 25)
|
||||
envelope->n_nodes = 25;
|
||||
for (n = 0; n < envelope->n_nodes; n++) {
|
||||
envelope->node_y[n] = dumbfile_getc(f);
|
||||
envelope->node_t[n] = dumbfile_igetw(f);
|
||||
|
@ -629,7 +684,7 @@ int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
signed char * ptr, * end;
|
||||
signed char compression_table[16];
|
||||
if (dumbfile_getnc(compression_table, 16, f) != 16)
|
||||
return -1;
|
||||
return -1;
|
||||
ptr = (signed char *) sample->data;
|
||||
delta = 0;
|
||||
|
||||
|
@ -682,15 +737,36 @@ static int32 it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char conv
|
|||
else
|
||||
decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
|
||||
} else if (sample->flags & IT_SAMPLE_16BIT) {
|
||||
if (convert & 2)
|
||||
if (sample->flags & IT_SAMPLE_STEREO) {
|
||||
if (convert & 2) {
|
||||
for (n = 0; n < datasize; n += 2)
|
||||
((short *)sample->data)[n] = dumbfile_mgetw(f);
|
||||
for (n = 1; n < datasize; n += 2)
|
||||
((short *)sample->data)[n] = dumbfile_mgetw(f);
|
||||
} else {
|
||||
for (n = 0; n < datasize; n += 2)
|
||||
((short *)sample->data)[n] = dumbfile_igetw(f);
|
||||
for (n = 1; n < datasize; n += 2)
|
||||
((short *)sample->data)[n] = dumbfile_igetw(f);
|
||||
}
|
||||
} else {
|
||||
if (convert & 2)
|
||||
for (n = 0; n < datasize; n++)
|
||||
((short *)sample->data)[n] = dumbfile_mgetw(f);
|
||||
else
|
||||
for (n = 0; n < datasize; n++)
|
||||
((short *)sample->data)[n] = dumbfile_igetw(f);
|
||||
}
|
||||
} else {
|
||||
if (sample->flags & IT_SAMPLE_STEREO) {
|
||||
for (n = 0; n < datasize; n += 2)
|
||||
((signed char *)sample->data)[n] = dumbfile_getc(f);
|
||||
for (n = 1; n < datasize; n += 2)
|
||||
((signed char *)sample->data)[n] = dumbfile_getc(f);
|
||||
} else
|
||||
for (n = 0; n < datasize; n++)
|
||||
((short *)sample->data)[n] = dumbfile_mgetw(f);
|
||||
else
|
||||
for (n = 0; n < datasize; n++)
|
||||
((short *)sample->data)[n] = dumbfile_igetw(f);
|
||||
} else
|
||||
for (n = 0; n < datasize; n++)
|
||||
((signed char *)sample->data)[n] = dumbfile_getc(f);
|
||||
((signed char *)sample->data)[n] = dumbfile_getc(f);
|
||||
}
|
||||
|
||||
if (dumbfile_error(f))
|
||||
return -1;
|
||||
|
@ -934,13 +1010,58 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
|
||||
unsigned char *buffer;
|
||||
|
||||
unsigned char *file_buffer = NULL;
|
||||
unsigned int file_size = 0;
|
||||
int block_size;
|
||||
|
||||
dumbfile_mem_status memdata;
|
||||
|
||||
do
|
||||
{
|
||||
void * temp = realloc( file_buffer, file_size + 32768 );
|
||||
if ( !temp )
|
||||
{
|
||||
if ( file_buffer ) free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
file_buffer = temp;
|
||||
block_size = dumbfile_getnc( file_buffer + file_size, 32768, f );
|
||||
if ( block_size < 0 )
|
||||
{
|
||||
free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
file_size += block_size;
|
||||
}
|
||||
while ( block_size == 32768 );
|
||||
|
||||
memdata.ptr = file_buffer;
|
||||
memdata.offset = 0;
|
||||
memdata.size = file_size;
|
||||
|
||||
f = dumbfile_open_ex(&memdata, &mem_dfs);
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
free( file_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dumbfile_mgetl(f) != IT_SIGNATURE)
|
||||
{
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
|
||||
if (!sigdata)
|
||||
{
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
|
@ -989,12 +1110,16 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
// XXX sample count
|
||||
if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->order = malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1002,6 +1127,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
|
||||
if (!sigdata->instrument) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1010,6 +1137,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (n = 0; n < sigdata->n_samples; n++)
|
||||
|
@ -1020,6 +1149,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
|
||||
if (!sigdata->pattern) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (n = 0; n < sigdata->n_patterns; n++)
|
||||
|
@ -1032,6 +1163,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
component = malloc(769 * sizeof(*component));
|
||||
if (!component) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1076,6 +1209,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_error(f)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1096,6 +1231,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (!sigdata->midi) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
// Should we be happy with this outcome in some situations?
|
||||
}
|
||||
|
@ -1104,6 +1241,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
/* Read embedded MIDI configuration */
|
||||
|
@ -1111,6 +1250,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_skip(f, 32*9)) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
@ -1119,6 +1260,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
if (dumbfile_getnc(mididata, 32, f) < 32) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->midi->SFmacroz[i] = 0;
|
||||
|
@ -1174,12 +1317,14 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
|
||||
sigdata->flags &= IT_REAL_FLAGS;
|
||||
|
||||
qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
|
||||
qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
|
||||
|
||||
buffer = malloc(65536);
|
||||
if (!buffer) {
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1208,10 +1353,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (it_seek(f, component[n].offset)) {
|
||||
if (it_seek(&memdata, component[n].offset)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1227,6 +1374,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
sigdata->song_message[message_length] = 0;
|
||||
|
@ -1243,6 +1392,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -1252,6 +1403,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -1261,6 +1414,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1287,10 +1442,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
m = component[n].sampfirst;
|
||||
|
||||
while (m >= 0) {
|
||||
if (it_seek(f, component[m].offset)) {
|
||||
if (it_seek(&memdata, component[m].offset)) {
|
||||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1298,16 +1455,79 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f)
|
|||
free(buffer);
|
||||
free(component);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = component[m].sampnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
for ( n = 0; n < 10; n++ )
|
||||
{
|
||||
if ( dumbfile_getc( f ) == 'X' )
|
||||
{
|
||||
if ( dumbfile_getc( f ) == 'T' )
|
||||
{
|
||||
if ( dumbfile_getc( f ) == 'P' )
|
||||
{
|
||||
if ( dumbfile_getc( f ) == 'M' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !dumbfile_error( f ) && n < 10 )
|
||||
{
|
||||
unsigned int mptx_id = dumbfile_igetl( f );
|
||||
while ( !dumbfile_error( f ) && mptx_id != DUMB_ID('M','P','T','S') )
|
||||
{
|
||||
unsigned int size = dumbfile_igetw( f );
|
||||
switch (mptx_id)
|
||||
{
|
||||
/* TODO: Add instrument extension readers */
|
||||
|
||||
default:
|
||||
dumbfile_skip(f, size * sigdata->n_instruments);
|
||||
break;
|
||||
}
|
||||
|
||||
mptx_id = dumbfile_igetl( f );
|
||||
}
|
||||
|
||||
mptx_id = dumbfile_igetl( f );
|
||||
while ( memdata.offset < file_size )
|
||||
{
|
||||
unsigned int size = dumbfile_igetw( f );
|
||||
switch (mptx_id)
|
||||
{
|
||||
/* TODO: Add more song extension readers */
|
||||
|
||||
case DUMB_ID('D','T','.','.'):
|
||||
if ( size == 2 )
|
||||
sigdata->tempo = dumbfile_igetw( f );
|
||||
else if ( size == 4 )
|
||||
sigdata->tempo = dumbfile_igetl( f );
|
||||
break;
|
||||
|
||||
default:
|
||||
dumbfile_skip(f, size);
|
||||
break;
|
||||
}
|
||||
mptx_id = dumbfile_igetl( f );
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(component);
|
||||
|
||||
dumbfile_close(f);
|
||||
free(file_buffer);
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
|
@ -1327,9 +1547,11 @@ DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f)
|
|||
return NULL;
|
||||
|
||||
{
|
||||
const char *tag[1][2];
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
tag[1][0] = "FORMAT";
|
||||
tag[1][1] = "IT";
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
||||
|
|
42
dumb/src/it/loadokt.c
Normal file
42
dumb/src/it/loadokt.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadokt.c - Code to read an Oktalyzer module / / \ \
|
||||
* file, opening and closing it for | < / \_
|
||||
* you. | \/ /\ /
|
||||
* \_ / > /
|
||||
* By Chris Moeller. | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
/* dumb_load_okt_quick(): loads an OKT file into a DUH struct, returning a
|
||||
* 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_okt_quick(const char *filename)
|
||||
{
|
||||
DUH *duh;
|
||||
DUMBFILE *f = dumbfile_open(filename);
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
duh = dumb_read_okt_quick(f);
|
||||
|
||||
dumbfile_close(f);
|
||||
|
||||
return duh;
|
||||
}
|
29
dumb/src/it/loadokt2.c
Normal file
29
dumb/src/it/loadokt2.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* loadokt2.c - Function to read an Oktalyzer / / \ \
|
||||
* module file, opening and closing | < / \_
|
||||
* it for you, and do an initial run- | \/ /\ /
|
||||
* through. \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_load_okt(const char *filename)
|
||||
{
|
||||
DUH *duh = dumb_load_okt_quick(filename);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -331,6 +331,7 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
|
|||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
|
@ -553,6 +554,7 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
|
|||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
}
|
||||
|
||||
_dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 );
|
||||
_dumb_it_xm_convert_effect( buffer[ pos + 2 ], buffer[ pos + 3 ], entry, 1 );
|
||||
|
||||
if ( entry->mask ) ++entry;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
|
||||
static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
|
||||
{
|
||||
int finetune;
|
||||
int finetune, key_offset;
|
||||
|
||||
/**
|
||||
21 22 Chars Sample 1 name. If the name is not a full
|
||||
|
@ -111,7 +111,7 @@ assumed not to be an instrument name, and is probably a message.
|
|||
sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead?
|
||||
sample->global_volume = 64;
|
||||
if ( sample->default_volume > 64 ) sample->default_volume = 64;
|
||||
dumbfile_skip( f, 1 ); /* XXX unknown */
|
||||
key_offset = ( signed char ) dumbfile_getc( f ); /* base key offset */
|
||||
sample->length = dumbfile_igetl( f );
|
||||
sample->loop_start = dumbfile_igetl( f );
|
||||
sample->loop_end = sample->loop_start + dumbfile_igetl( f );
|
||||
|
@ -124,7 +124,7 @@ assumed not to be an instrument name, and is probably a message.
|
|||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
sample->default_pan = 0;
|
||||
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( int32 )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
|
||||
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
|
||||
sample->finetune = finetune * 32;
|
||||
// the above line might be wrong
|
||||
|
||||
|
|
|
@ -265,6 +265,7 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
|
|||
|
||||
sigdata->n_instruments = 0;
|
||||
sigdata->n_orders = 0;
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
|
||||
|
|
|
@ -393,10 +393,12 @@ static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, uint32 *fft)
|
|||
return dumbfile_open_ex(bm, &buffer_mod_dfs);
|
||||
}
|
||||
|
||||
static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int32 *remain)
|
||||
static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int n_samples, IT_SAMPLE *sample, int32 *total_sample_size, int32 *remain)
|
||||
{
|
||||
int32 read;
|
||||
int sample_number;
|
||||
BUFFERED_MOD *bm = malloc(sizeof(*bm));
|
||||
unsigned char *ptr;
|
||||
if (!bm) return NULL;
|
||||
|
||||
bm->buffered = malloc(32768);
|
||||
|
@ -430,6 +432,21 @@ static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int32 *remain)
|
|||
|
||||
if (*remain) {
|
||||
bm->ptr = 0;
|
||||
ptr = bm->buffered + *remain;
|
||||
sample_number = n_samples - 1;
|
||||
*total_sample_size = 0;
|
||||
while (ptr > bm->buffered && sample_number >= 0) {
|
||||
if (sample[sample_number].flags & IT_SAMPLE_EXISTS) {
|
||||
ptr -= (sample[sample_number].length + 1) / 2 + 5 + 16;
|
||||
if (ptr >= bm->buffered && !memcmp(ptr, "ADPCM", 5)) { /* BAH */
|
||||
*total_sample_size += (sample[sample_number].length + 1) / 2 + 5 + 16;
|
||||
} else {
|
||||
*total_sample_size += sample[sample_number].length;
|
||||
ptr -= sample[sample_number].length - ((sample[sample_number].length + 1) / 2 + 5 + 16);
|
||||
}
|
||||
}
|
||||
sample_number--;
|
||||
}
|
||||
} else {
|
||||
free(bm->buffered);
|
||||
bm->buffered = NULL;
|
||||
|
@ -441,13 +458,13 @@ 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;
|
||||
int i;
|
||||
uint32 fft = 0;
|
||||
DUMBFILE *rem;
|
||||
DUMBFILE *rem = NULL;
|
||||
|
||||
f = dumbfile_buffer_mod(f, &fft);
|
||||
if (!f)
|
||||
|
@ -550,7 +567,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
}
|
||||
|
||||
// moo
|
||||
if ( restrict && sigdata->n_samples == 15 )
|
||||
if ( ( rstrict & 1 ) && sigdata->n_samples == 15 )
|
||||
{
|
||||
free(sigdata);
|
||||
dumbfile_close(f);
|
||||
|
@ -629,12 +646,48 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
if (sigdata->n_samples == 31)
|
||||
dumbfile_skip(f, 4);
|
||||
|
||||
/* Work out how many patterns there are. */
|
||||
sigdata->n_patterns = -1;
|
||||
for (i = 0; i < 128; i++)
|
||||
if (sigdata->n_patterns < sigdata->order[i])
|
||||
sigdata->n_patterns = sigdata->order[i];
|
||||
sigdata->n_patterns++;
|
||||
|
||||
if ( ( rstrict & 2 ) )
|
||||
{
|
||||
long total_sample_size;
|
||||
long remain;
|
||||
rem = f;
|
||||
f = dumbfile_buffer_mod_2(rem, sigdata->n_samples, sigdata->sample, &total_sample_size, &remain);
|
||||
if (!f) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
if (remain > total_sample_size) {
|
||||
sigdata->n_patterns = ( remain - total_sample_size + 4 ) / ( 256 * sigdata->n_pchannels );
|
||||
if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
|
||||
remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels;
|
||||
if (dumbfile_skip(f, remain - total_sample_size)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
if (sigdata->order[i] > sigdata->n_patterns)
|
||||
sigdata->n_patterns = sigdata->order[i];
|
||||
}
|
||||
sigdata->n_patterns++;
|
||||
}
|
||||
|
||||
if ( sigdata->n_patterns <= 0 ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* May as well try to save a tiny bit of memory. */
|
||||
if (sigdata->n_orders < 128) {
|
||||
|
@ -646,6 +699,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
if (!sigdata->pattern) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++)
|
||||
|
@ -653,10 +707,11 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
|
||||
/* Read in the patterns */
|
||||
{
|
||||
unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
|
||||
unsigned char *buffer = malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */
|
||||
if (!buffer) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < sigdata->n_patterns; i++) {
|
||||
|
@ -664,40 +719,13 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
free(buffer);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
if (rem) dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
rem = NULL;
|
||||
|
||||
/* uggly */
|
||||
if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
|
||||
int32 skip;
|
||||
int32 remain;
|
||||
rem = f;
|
||||
f = dumbfile_buffer_mod_2(rem, &remain);
|
||||
if (!f) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
for (skip = 0, i = 0; i < sigdata->n_samples; i++) {
|
||||
if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
|
||||
skip += sigdata->sample[i].length;
|
||||
}
|
||||
}
|
||||
if (remain - skip) {
|
||||
if (dumbfile_skip(f, remain - skip)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
dumbfile_close(f);
|
||||
dumbfile_close(rem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* And finally, the sample data */
|
||||
for (i = 0; i < sigdata->n_samples; i++) {
|
||||
if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
|
||||
|
@ -727,8 +755,8 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
|
|||
}*/
|
||||
|
||||
dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
|
||||
if (rem) dumbfile_close(rem); /* And the BUFFERED_MOD DUMBFILE used to pre-read the signature. */
|
||||
/* The DUMBFILE originally passed to our function is intact. */
|
||||
if (rem) dumbfile_close(rem);
|
||||
|
||||
/* Now let's initialise the remaining variables, and we're done! */
|
||||
sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
|
||||
|
@ -758,13 +786,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;
|
||||
}
|
||||
|
|
558
dumb/src/it/readokt.c
Normal file
558
dumb/src/it/readokt.c
Normal file
|
@ -0,0 +1,558 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readokt.c - Code to read an Oktalyzer module / / \ \
|
||||
* from an open file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Chris Moeller. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
|
||||
|
||||
static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data, int length, int n_channels)
|
||||
{
|
||||
int pos;
|
||||
int channel;
|
||||
int row;
|
||||
int n_rows;
|
||||
IT_ENTRY *entry;
|
||||
|
||||
if (length < 2) return -1;
|
||||
|
||||
n_rows = (data[0] << 8) | data[1];
|
||||
if (!n_rows) n_rows = 64;
|
||||
|
||||
if (length < 2 + (n_rows * n_channels * 4)) return -1;
|
||||
|
||||
pattern->n_rows = n_rows;
|
||||
|
||||
/* compute number of entries */
|
||||
pattern->n_entries = n_rows; /* Account for the row end markers */
|
||||
pos = 2;
|
||||
for (row = 0; row < pattern->n_rows; row++) {
|
||||
for (channel = 0; channel < n_channels; channel++) {
|
||||
if (data[pos+0] | data[pos+2])
|
||||
pattern->n_entries++;
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
pattern->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry));
|
||||
if (!pattern->entry)
|
||||
return -1;
|
||||
|
||||
entry = pattern->entry;
|
||||
pos = 2;
|
||||
for (row = 0; row < n_rows; row++) {
|
||||
for (channel = 0; channel < n_channels; channel++) {
|
||||
if (data[pos+0] | data[pos+2]) {
|
||||
entry->channel = channel;
|
||||
entry->mask = 0;
|
||||
|
||||
if (data[pos+0] > 0 && data[pos+0] <= 36) {
|
||||
entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
|
||||
|
||||
entry->note = data[pos+0] + 35;
|
||||
entry->instrument = data[pos+1] + 1;
|
||||
}
|
||||
|
||||
entry->effect = 0;
|
||||
entry->effectvalue = data[pos+3];
|
||||
|
||||
switch (data[pos+2]) {
|
||||
case 2: if (data[pos+3]) entry->effect = IT_PORTAMENTO_DOWN; break; // XXX code calls this rs_portu, but it's adding to the period, which decreases the pitch
|
||||
case 13: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN; break;
|
||||
case 21: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW; break;
|
||||
|
||||
case 1: if (data[pos+3]) entry->effect = IT_PORTAMENTO_UP; break; // XXX same deal here, increasing the pitch
|
||||
case 17: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP; break;
|
||||
case 30: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW; break;
|
||||
|
||||
case 10: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_3; break;
|
||||
case 11: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_4; break;
|
||||
case 12: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_5; break;
|
||||
|
||||
case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break;
|
||||
|
||||
case 25: entry->effect = IT_JUMP_TO_ORDER; break;
|
||||
|
||||
case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break;
|
||||
|
||||
case 28: entry->effect = IT_SET_SPEED; break;
|
||||
|
||||
case 31:
|
||||
if ( data[pos+3] <= 0x40 ) entry->effect = IT_SET_CHANNEL_VOLUME;
|
||||
else if ( data[pos+3] <= 0x50 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x40; }
|
||||
else if ( data[pos+3] <= 0x60 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x50; }
|
||||
else if ( data[pos+3] <= 0x70 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x50; }
|
||||
else if ( data[pos+3] <= 0x80 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x60; }
|
||||
break;
|
||||
}
|
||||
|
||||
if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT;
|
||||
|
||||
entry++;
|
||||
}
|
||||
pos += 4;
|
||||
}
|
||||
IT_SET_END_ROW(entry);
|
||||
entry++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void it_okt_read_sample_header(IT_SAMPLE *sample, const unsigned char * data)
|
||||
{
|
||||
int loop_start, loop_length;
|
||||
|
||||
memcpy(sample->name, data, 20);
|
||||
sample->name[20] = 0;
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
||||
sample->length = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23];
|
||||
sample->global_volume = 64;
|
||||
sample->default_volume = data[29];
|
||||
loop_start = ((data[24] << 8) | data[25]) << 1;
|
||||
loop_length = ((data[26] << 8) | data[27]) << 1;
|
||||
sample->sus_loop_start = loop_start;
|
||||
sample->sus_loop_end = loop_start + loop_length;
|
||||
|
||||
if (sample->length <= 0) {
|
||||
sample->flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sample->flags = IT_SAMPLE_EXISTS;
|
||||
|
||||
sample->default_pan = 0;
|
||||
sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
|
||||
sample->finetune = 0;
|
||||
|
||||
if (sample->sus_loop_end > sample->length)
|
||||
sample->sus_loop_end = sample->length;
|
||||
|
||||
if (loop_length > 2)
|
||||
sample->flags |= IT_SAMPLE_SUS_LOOP;
|
||||
|
||||
sample->vibrato_speed = 0;
|
||||
sample->vibrato_depth = 0;
|
||||
sample->vibrato_rate = 0;
|
||||
sample->vibrato_waveform = 0; // do we have to set _all_ these?
|
||||
sample->max_resampling_quality = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int it_okt_read_sample_data(IT_SAMPLE *sample, const char * data, int length)
|
||||
{
|
||||
if (length && sample->length) {
|
||||
if (length < sample->length) {
|
||||
sample->length = length;
|
||||
if (length < sample->sus_loop_end) sample->sus_loop_end = length;
|
||||
}
|
||||
|
||||
sample->data = malloc(length);
|
||||
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
memcpy(sample->data, data, length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct IFF_CHUNK IFF_CHUNK;
|
||||
typedef struct IFF_CHUNKED IFF_CHUNKED;
|
||||
|
||||
struct IFF_CHUNK
|
||||
{
|
||||
unsigned type;
|
||||
unsigned char * data;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
struct IFF_CHUNKED
|
||||
{
|
||||
unsigned chunk_count;
|
||||
IFF_CHUNK * chunks;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f)
|
||||
{
|
||||
IFF_CHUNKED *mod = (IFF_CHUNKED *) malloc(sizeof(*mod));
|
||||
if (!mod) return NULL;
|
||||
|
||||
mod->chunk_count = 0;
|
||||
mod->chunks = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
long bytes_read;
|
||||
IFF_CHUNK * chunk = ( IFF_CHUNK * ) realloc( mod->chunks, ( mod->chunk_count + 1 ) * sizeof( IFF_CHUNK ) );
|
||||
if ( !chunk )
|
||||
{
|
||||
if ( mod->chunks ) free( mod->chunks );
|
||||
free( mod );
|
||||
return NULL;
|
||||
}
|
||||
mod->chunks = chunk;
|
||||
chunk += mod->chunk_count;
|
||||
|
||||
bytes_read = dumbfile_mgetl( f );
|
||||
if ( bytes_read < 0 ) break;
|
||||
|
||||
chunk->type = bytes_read;
|
||||
chunk->size = dumbfile_mgetl( f );
|
||||
|
||||
if ( dumbfile_error( f ) ) break;
|
||||
|
||||
chunk->data = (unsigned char *) malloc( chunk->size );
|
||||
if ( !chunk->data )
|
||||
{
|
||||
free( mod->chunks );
|
||||
free( mod );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f );
|
||||
if ( bytes_read < (long)chunk->size )
|
||||
{
|
||||
if ( bytes_read <= 0 ) {
|
||||
free( chunk->data );
|
||||
break;
|
||||
} else {
|
||||
chunk->size = bytes_read;
|
||||
mod->chunk_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mod->chunk_count++;
|
||||
}
|
||||
|
||||
if ( !mod->chunk_count ) {
|
||||
if ( mod->chunks ) free(mod->chunks);
|
||||
free(mod);
|
||||
mod = NULL;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
void free_okt(IFF_CHUNKED * mod)
|
||||
{
|
||||
unsigned i;
|
||||
if (mod)
|
||||
{
|
||||
if (mod->chunks)
|
||||
{
|
||||
for (i = 0; i < mod->chunk_count; i++)
|
||||
{
|
||||
if (mod->chunks[i].data) free(mod->chunks[i].data);
|
||||
}
|
||||
free(mod->chunks);
|
||||
}
|
||||
free(mod);
|
||||
}
|
||||
}
|
||||
|
||||
const IFF_CHUNK * get_chunk_by_type(IFF_CHUNKED * mod, unsigned type, unsigned offset)
|
||||
{
|
||||
unsigned i;
|
||||
if (mod)
|
||||
{
|
||||
if (mod->chunks)
|
||||
{
|
||||
for (i = 0; i < mod->chunk_count; i++)
|
||||
{
|
||||
if (mod->chunks[i].type == type)
|
||||
{
|
||||
if (!offset) return &mod->chunks[i];
|
||||
else offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type)
|
||||
{
|
||||
unsigned i, count = 0;
|
||||
if (mod)
|
||||
{
|
||||
if (mod->chunks)
|
||||
{
|
||||
for (i = 0; i < mod->chunk_count; i++)
|
||||
{
|
||||
if (mod->chunks[i].type == type) count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
unsigned n_channels;
|
||||
unsigned i, j, k, l;
|
||||
IFF_CHUNKED *mod;
|
||||
const IFF_CHUNK *chunk;
|
||||
|
||||
char signature[8];
|
||||
|
||||
if (dumbfile_getnc(signature, 8, f) < 8 ||
|
||||
memcmp(signature, "OKTASONG", 8)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mod = dumbfile_read_okt(f);
|
||||
if (!mod)
|
||||
return NULL;
|
||||
|
||||
sigdata = (DUMB_IT_SIGDATA *) malloc(sizeof(*sigdata));
|
||||
if (!sigdata) {
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->name[0] = 0;
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','P','E','E'), 0);
|
||||
if (!chunk || chunk->size < 2) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->speed = (chunk->data[0] << 8) | chunk->data[1];
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0);
|
||||
if (!chunk || chunk->size < 32) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_samples = chunk->size / 32;
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0);
|
||||
if (!chunk || chunk->size < 8) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_channels = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1];
|
||||
if (!j) n_channels++;
|
||||
else if (j == 1) n_channels += 2;
|
||||
}
|
||||
|
||||
if (!n_channels) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_pchannels = n_channels;
|
||||
|
||||
sigdata->sample = (IT_SAMPLE *) malloc(sigdata->n_samples * sizeof(*sigdata->sample));
|
||||
if (!sigdata->sample) {
|
||||
free(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
sigdata->instrument = NULL;
|
||||
sigdata->pattern = NULL;
|
||||
sigdata->midi = NULL;
|
||||
sigdata->checkpoint = NULL;
|
||||
|
||||
sigdata->n_instruments = 0;
|
||||
|
||||
for (i = 0; i < (unsigned)sigdata->n_samples; i++)
|
||||
sigdata->sample[i].data = NULL;
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0);
|
||||
|
||||
for (i = 0; i < (unsigned)sigdata->n_samples; i++) {
|
||||
it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i);
|
||||
}
|
||||
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('P','L','E','N'), 0);
|
||||
if (!chunk || chunk->size < 2) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1];
|
||||
// what if this is > 128?
|
||||
|
||||
if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0);
|
||||
if (!chunk || chunk->size < (unsigned)sigdata->n_orders) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->order = (unsigned char *) malloc(sigdata->n_orders);
|
||||
if (!sigdata->order) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(sigdata->order, chunk->data, sigdata->n_orders);
|
||||
|
||||
/* Work out how many patterns there are. */
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','L','E','N'), 0);
|
||||
if (!chunk || chunk->size < 2) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1];
|
||||
|
||||
j = get_chunk_count(mod, DUMB_ID('P','B','O','D'));
|
||||
if (sigdata->n_patterns > (int)j) sigdata->n_patterns = (int)j;
|
||||
|
||||
if (!sigdata->n_patterns) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->pattern = (IT_PATTERN *) malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
|
||||
if (!sigdata->pattern) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < (unsigned)sigdata->n_patterns; i++)
|
||||
sigdata->pattern[i].entry = NULL;
|
||||
|
||||
/* Read in the patterns */
|
||||
for (i = 0; i < (unsigned)sigdata->n_patterns; i++) {
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('P','B','O','D'), i);
|
||||
if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size, n_channels) != 0) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* And finally, the sample data */
|
||||
k = get_chunk_count(mod, DUMB_ID('S','B','O','D'));
|
||||
for (i = 0, j = 0; i < (unsigned)sigdata->n_samples, j < k; i++) {
|
||||
if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('S','B','O','D'), j);
|
||||
if (it_okt_read_sample_data(&sigdata->sample[i], (const char *)chunk->data, chunk->size)) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
free_okt(mod);
|
||||
return NULL;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (; i < (unsigned)sigdata->n_samples; i++) {
|
||||
sigdata->sample[i].flags = 0;
|
||||
}
|
||||
|
||||
chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0);
|
||||
|
||||
for (i = 0, j = 0; i < n_channels, j < 4; j++) {
|
||||
k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1];
|
||||
l = (j == 1 || j == 2) ? 48 : 16;
|
||||
if (k == 0) {
|
||||
sigdata->channel_pan[i++] = l;
|
||||
}
|
||||
else if (k == 1) {
|
||||
sigdata->channel_pan[i++] = l;
|
||||
sigdata->channel_pan[i++] = l;
|
||||
}
|
||||
}
|
||||
|
||||
free_okt(mod);
|
||||
|
||||
/* Now let's initialise the remaining variables, and we're done! */
|
||||
sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
|
||||
|
||||
sigdata->global_volume = 128;
|
||||
sigdata->mixing_volume = 48;
|
||||
/* We want 50 ticks per second; 50/6 row advances per second;
|
||||
* 50*10=500 row advances per minute; 500/4=125 beats per minute.
|
||||
*/
|
||||
sigdata->tempo = 125;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
|
||||
memset(sigdata->channel_pan + n_channels, 32, DUMB_IT_N_CHANNELS - n_channels);
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_okt_load_sigdata(f);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
const char *tag[1][2];
|
||||
tag[0][0] = "FORMAT";
|
||||
tag[0][1] = "Oktalyzer";
|
||||
return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
29
dumb/src/it/readokt2.c
Normal file
29
dumb/src/it/readokt2.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readokt2.c - Function to read an Oktalyzer / / \ \
|
||||
* module from an open file and do | < / \_
|
||||
* an initial run-through. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* By Chris Moeller. | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f)
|
||||
{
|
||||
DUH *duh = dumb_read_okt_quick(f);
|
||||
dumb_it_do_initial_runthrough(duh);
|
||||
return duh;
|
||||
}
|
|
@ -296,7 +296,7 @@ static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num,
|
|||
if (flags & 0x80) {
|
||||
if ((*ptr < 60) && (channel < pchans)) {
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = *ptr + 36;
|
||||
entry->note = *ptr + 35;
|
||||
}
|
||||
ptr++;
|
||||
if (*ptr) {
|
||||
|
|
|
@ -557,8 +557,8 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sigdata->global_volume = dumbfile_getc(f) << 1;
|
||||
if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128;
|
||||
sigdata->global_volume = dumbfile_getc(f) * 16 / 11;
|
||||
if ( !sigdata->global_volume || sigdata->global_volume > 93 ) sigdata->global_volume = 93;
|
||||
sigdata->speed = dumbfile_getc(f);
|
||||
if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
|
||||
sigdata->tempo = dumbfile_getc(f);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// IT_STEREO... :o
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
@ -28,14 +29,16 @@
|
|||
#define strnicmp strncasecmp
|
||||
#endif
|
||||
|
||||
static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
|
||||
static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned short *offset )
|
||||
{
|
||||
dumbfile_getnc( sample->filename, 12, f );
|
||||
sample->filename[12] = 0;
|
||||
|
||||
memcpy( sample->name, sample->filename, 13 );
|
||||
|
||||
dumbfile_skip( f, 2 + 2 );
|
||||
dumbfile_skip( f, 2 );
|
||||
|
||||
*offset = dumbfile_igetw( f );
|
||||
|
||||
sample->length = dumbfile_igetw( f );
|
||||
sample->loop_start = dumbfile_igetw( f );
|
||||
|
@ -78,24 +81,15 @@ static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
|
|||
return dumbfile_error(f);
|
||||
}
|
||||
|
||||
static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
|
||||
static int it_stm_read_sample_data( IT_SAMPLE *sample, void *data_block, long offset )
|
||||
{
|
||||
int32 n;
|
||||
|
||||
if ( ! sample->length ) return 0;
|
||||
|
||||
n = dumbfile_pos( f );
|
||||
if ( n & 15 ) {
|
||||
if ( dumbfile_skip( f, 16 - ( n & 15 ) ) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
sample->data = malloc( sample->length );
|
||||
if (!sample->data)
|
||||
return -1;
|
||||
|
||||
if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length )
|
||||
return -1;
|
||||
memcpy( sample->data, (unsigned char*)data_block + offset, sample->length );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -141,10 +135,6 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
entry->effectvalue = buffer[ pos + 3 ];
|
||||
if ( entry->instrument && entry->instrument < 32 )
|
||||
entry->mask |= IT_ENTRY_INSTRUMENT;
|
||||
if ( note == 0xFC || note == 0xFE ) {
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = IT_NOTE_CUT;
|
||||
}
|
||||
if ( note < 251 ) {
|
||||
entry->mask |= IT_ENTRY_NOTE;
|
||||
entry->note = ( note >> 4 ) * 12 + ( note & 0x0F );
|
||||
|
@ -153,9 +143,9 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
entry->mask |= IT_ENTRY_VOLPAN;
|
||||
entry->mask |= IT_ENTRY_EFFECT;
|
||||
switch ( entry->effect ) {
|
||||
case IT_SET_SPEED:
|
||||
entry->effectvalue >>= 4;
|
||||
break;
|
||||
case IT_SET_SPEED:
|
||||
/* taken care of in the renderer */
|
||||
break;
|
||||
|
||||
case IT_BREAK_TO_ROW:
|
||||
entry->effectvalue -= (entry->effectvalue >> 4) * 6;
|
||||
|
@ -192,14 +182,20 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char
|
|||
|
||||
|
||||
|
||||
static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
||||
static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
|
||||
{
|
||||
DUMB_IT_SIGDATA *sigdata;
|
||||
|
||||
char tracker_name[ 8 ];
|
||||
|
||||
unsigned short sample_offset[ 31 ];
|
||||
|
||||
void *data_block;
|
||||
|
||||
int n;
|
||||
|
||||
long o, p, q;
|
||||
|
||||
sigdata = malloc(sizeof(*sigdata));
|
||||
if (!sigdata) return NULL;
|
||||
|
||||
|
@ -227,8 +223,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* *version = dumbfile_mgetw(f); */
|
||||
dumbfile_skip( f, 2 );
|
||||
*version = dumbfile_mgetw(f);
|
||||
|
||||
sigdata->song_message = NULL;
|
||||
sigdata->order = NULL;
|
||||
|
@ -242,16 +237,17 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
|||
sigdata->n_samples = 31;
|
||||
sigdata->n_pchannels = 4;
|
||||
|
||||
sigdata->tempo = 125;
|
||||
sigdata->mixing_volume = 48;
|
||||
sigdata->tempo = 125;
|
||||
sigdata->mixing_volume = 48;
|
||||
sigdata->pan_separation = 128;
|
||||
|
||||
/** WARNING: which ones? */
|
||||
sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
|
||||
sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_WAS_AN_STM | IT_STEREO;
|
||||
|
||||
sigdata->speed = dumbfile_getc(f) >> 4;
|
||||
if ( sigdata->speed < 1 ) sigdata->speed = 1;
|
||||
sigdata->n_patterns = dumbfile_getc(f);
|
||||
n = dumbfile_getc(f);
|
||||
if ( n < 32 ) n = 32;
|
||||
sigdata->speed = n;
|
||||
sigdata->n_patterns = dumbfile_getc(f);
|
||||
sigdata->global_volume = dumbfile_getc(f) << 1;
|
||||
if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128;
|
||||
|
||||
|
@ -287,7 +283,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
|||
sigdata->channel_pan[ 3 ] = 16;
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) {
|
||||
if ( it_stm_read_sample_header( &sigdata->sample[ n ], f, &sample_offset[ n ] ) ) {
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
@ -300,7 +296,8 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
|||
}
|
||||
|
||||
/* Orders, byte each, length = sigdata->n_orders (should be even) */
|
||||
dumbfile_getnc( sigdata->order, 128, f );
|
||||
dumbfile_getnc( sigdata->order, *version >= 0x200 ? 128 : 64, f );
|
||||
if (*version < 0x200) memset( sigdata->order + 64, 0xFF, 64 );
|
||||
sigdata->restart_position = 0;
|
||||
|
||||
for ( n = 127; n >= 0; --n ) {
|
||||
|
@ -332,54 +329,105 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
|
|||
free( buffer );
|
||||
}
|
||||
|
||||
o = LONG_MAX;
|
||||
p = 0;
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) {
|
||||
if ((sigdata->sample[ n ].flags & IT_SAMPLE_EXISTS) && sample_offset[ n ]) {
|
||||
q = ((long)sample_offset[ n ]) * 16;
|
||||
if (q < o) {
|
||||
o = q;
|
||||
}
|
||||
if (q + sigdata->sample[ n ].length > p) {
|
||||
p = q + sigdata->sample[ n ].length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sigdata->sample[ n ].flags = 0;
|
||||
sigdata->sample[ n ].length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
data_block = malloc( p - o );
|
||||
if ( !data_block ) {
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( n = 0, q = o / 16; n < sigdata->n_samples; ++n ) {
|
||||
if ( sample_offset[ n ] ) {
|
||||
sample_offset[ n ] = (unsigned short)(sample_offset[ n ] - q);
|
||||
}
|
||||
}
|
||||
|
||||
q = o - dumbfile_pos( f );
|
||||
p -= o;
|
||||
o = 0;
|
||||
if ( q >= 0 ) dumbfile_skip( f, q );
|
||||
else {
|
||||
o = -q;
|
||||
memset ( data_block, 0, o );
|
||||
}
|
||||
if ( dumbfile_getnc( (char*)data_block + o, p - o, f ) != p - o ) {
|
||||
free( data_block );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( n = 0; n < sigdata->n_samples; ++n ) {
|
||||
if ( it_stm_read_sample_data( &sigdata->sample[ n ], data_block, ((long)sample_offset[ n ]) * 16 ) ) {
|
||||
free( data_block );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free( data_block );
|
||||
|
||||
_dumb_it_fix_invalid_orders(sigdata);
|
||||
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
/*static char hexdigit(int in)
|
||||
{
|
||||
if (in < 10) return in + '0';
|
||||
else return in + 'A' - 10;
|
||||
}*/
|
||||
|
||||
DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f)
|
||||
{
|
||||
sigdata_t *sigdata;
|
||||
/*int ver;*/
|
||||
int ver;
|
||||
|
||||
DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
|
||||
|
||||
sigdata = it_stm_load_sigdata(f /*, &ver*/);
|
||||
sigdata = it_stm_load_sigdata(f , &ver);
|
||||
|
||||
if (!sigdata)
|
||||
return NULL;
|
||||
|
||||
{
|
||||
/*char version[16];*/
|
||||
char version[16];
|
||||
const char *tag[2][2];
|
||||
tag[0][0] = "TITLE";
|
||||
tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
|
||||
tag[1][0] = "FORMAT";
|
||||
tag[1][1] = "STM";
|
||||
/*version[0] = 'S';
|
||||
version[0] = 'S';
|
||||
version[1] = 'T';
|
||||
version[2] = 'M';
|
||||
version[3] = ' ';
|
||||
version[4] = 'v';
|
||||
version[5] = hexdigit((ver >> 8) & 15);
|
||||
version[5] = '0' + ((ver >> 8) & 15);
|
||||
version[6] = '.';
|
||||
version[7] = hexdigit((ver >> 4) & 15);
|
||||
version[8] = hexdigit(ver & 15);
|
||||
version[9] = 0;
|
||||
tag[1][1] = (const char *) &version;*/
|
||||
if ((ver & 255) > 99)
|
||||
{
|
||||
version[7] = '0' + ((ver & 255) / 100 );
|
||||
version[8] = '0' + (((ver & 255) / 10) % 10);
|
||||
version[9] = '0' + ((ver & 255) % 10);
|
||||
version[10] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
version[7] = '0' + ((ver & 255) / 10);
|
||||
version[8] = '0' + ((ver & 255) % 10);
|
||||
version[9] = 0;
|
||||
}
|
||||
tag[1][1] = (const char *) &version;
|
||||
return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,11 +111,20 @@ typedef struct XM_INSTRUMENT_EXTRA
|
|||
int vibrato_sweep; /* 0-0xFF */
|
||||
int vibrato_depth; /* 0-0x0F */
|
||||
int vibrato_speed; /* 0-0x3F */
|
||||
int sample_header_size;
|
||||
}
|
||||
XM_INSTRUMENT_EXTRA;
|
||||
|
||||
|
||||
|
||||
/* Trims off trailing white space, usually added by the tracker on file creation
|
||||
*/
|
||||
static void trim_whitespace(char *ptr, size_t size)
|
||||
{
|
||||
char *p = ptr + size - 1;
|
||||
while (p >= ptr && *p <= 0x20) *p-- = '\0';
|
||||
}
|
||||
|
||||
/* Frees the original block if it can't resize it or if size is 0, and acts
|
||||
* as malloc if ptr is NULL.
|
||||
*/
|
||||
|
@ -329,7 +338,7 @@ static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
|
|||
|
||||
static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset)
|
||||
{
|
||||
int i, pos;
|
||||
int i, pos, val;
|
||||
|
||||
if (envelope->n_nodes > 12) {
|
||||
/* XXX
|
||||
|
@ -346,12 +355,13 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data
|
|||
pos = 0;
|
||||
for (i = 0; i < envelope->n_nodes; i++) {
|
||||
envelope->node_t[i] = data[pos++];
|
||||
if (data[pos] > 64) {
|
||||
TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]);
|
||||
envelope->n_nodes = 0;
|
||||
return -1;
|
||||
val = data[pos++];
|
||||
if (val > 64) {
|
||||
TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, val);
|
||||
/* FT2 seems to simply clip the value */
|
||||
val = 64;
|
||||
}
|
||||
envelope->node_y[i] = (signed char)(data[pos++] + y_offset);
|
||||
envelope->node_y[i] = (signed char)(val + y_offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -359,21 +369,153 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data
|
|||
|
||||
|
||||
|
||||
typedef struct LIMITED_XM LIMITED_XM;
|
||||
|
||||
struct LIMITED_XM
|
||||
{
|
||||
unsigned char *buffered;
|
||||
long ptr, limit, allocated;
|
||||
DUMBFILE *remaining;
|
||||
};
|
||||
|
||||
/* XXX */
|
||||
struct DUMBFILE
|
||||
{
|
||||
DUMBFILE_SYSTEM *dfs;
|
||||
void *file;
|
||||
long pos;
|
||||
};
|
||||
|
||||
static int limit_xm_resize(void *f, long n)
|
||||
{
|
||||
DUMBFILE *df = f;
|
||||
LIMITED_XM *lx = df->file;
|
||||
if (lx->buffered || n) {
|
||||
if (n > lx->allocated) {
|
||||
unsigned char *buffered = realloc( lx->buffered, n );
|
||||
if ( !buffered ) return -1;
|
||||
lx->buffered = buffered;
|
||||
memset( buffered + lx->allocated, 0, n - lx->allocated );
|
||||
lx->allocated = n;
|
||||
}
|
||||
if ( dumbfile_getnc( lx->buffered, n, lx->remaining ) < n ) return -1;
|
||||
} else if (!n) {
|
||||
if ( lx->buffered ) free( lx->buffered );
|
||||
lx->buffered = NULL;
|
||||
lx->allocated = 0;
|
||||
}
|
||||
lx->limit = n;
|
||||
lx->ptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int limit_xm_skip_end(void *f, int32 n)
|
||||
{
|
||||
DUMBFILE *df = f;
|
||||
LIMITED_XM *lx = df->file;
|
||||
return dumbfile_skip( lx->remaining, n );
|
||||
}
|
||||
|
||||
static int limit_xm_skip(void *f, int32 n)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
lx->ptr += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int limit_xm_getc(void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
if (lx->ptr >= lx->allocated) {
|
||||
return 0;
|
||||
}
|
||||
return lx->buffered[lx->ptr++];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static long limit_xm_getnc(char *ptr, int32 n, void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
int left;
|
||||
left = lx->allocated - lx->ptr;
|
||||
if (n > left) {
|
||||
if (left > 0) {
|
||||
memcpy( ptr, lx->buffered + lx->ptr, left );
|
||||
memset( ptr + left, 0, n - left );
|
||||
} else {
|
||||
memset( ptr, 0, n );
|
||||
}
|
||||
} else {
|
||||
memcpy( ptr, lx->buffered + lx->ptr, n );
|
||||
}
|
||||
lx->ptr += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void limit_xm_close(void *f)
|
||||
{
|
||||
LIMITED_XM *lx = f;
|
||||
if (lx->buffered) free(lx->buffered);
|
||||
/* Do NOT close lx->remaining */
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DUMBFILE_SYSTEM limit_xm_dfs = {
|
||||
NULL,
|
||||
&limit_xm_skip,
|
||||
&limit_xm_getc,
|
||||
&limit_xm_getnc,
|
||||
&limit_xm_close
|
||||
};
|
||||
|
||||
static DUMBFILE *dumbfile_limit_xm(DUMBFILE *f)
|
||||
{
|
||||
LIMITED_XM * lx = malloc(sizeof(*lx));
|
||||
lx->remaining = f;
|
||||
lx->buffered = NULL;
|
||||
lx->ptr = 0;
|
||||
lx->limit = 0;
|
||||
lx->allocated = 0;
|
||||
return dumbfile_open_ex( lx, &limit_xm_dfs );
|
||||
}
|
||||
|
||||
static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
|
||||
{
|
||||
uint32 size, bytes_read;
|
||||
unsigned short vol_points[24];
|
||||
unsigned short pan_points[24];
|
||||
int i, type;
|
||||
const unsigned long max_size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2;
|
||||
unsigned long skip_end = 0;
|
||||
|
||||
/* Header size. Tends to be more than the actual size of the structure.
|
||||
* So unread bytes must be skipped before reading the first sample
|
||||
* header.
|
||||
*/
|
||||
|
||||
if ( limit_xm_resize( f, 4 ) < 0 ) return -1;
|
||||
|
||||
size = dumbfile_igetl(f);
|
||||
|
||||
if ( size == 0 ) size = max_size;
|
||||
else if ( size > max_size )
|
||||
{
|
||||
skip_end = size - max_size;
|
||||
size = max_size;
|
||||
}
|
||||
|
||||
if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1;
|
||||
|
||||
dumbfile_getnc(instrument->name, 22, f);
|
||||
instrument->name[22] = 0;
|
||||
trim_whitespace(instrument->name, 22);
|
||||
instrument->filename[0] = 0;
|
||||
dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
|
||||
extra->n_samples = dumbfile_igetw(f);
|
||||
|
@ -385,12 +527,11 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
|
|||
|
||||
if (extra->n_samples) {
|
||||
/* sample header size */
|
||||
dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here
|
||||
/*i = dumbfile_igetl(f);
|
||||
if (i && i != 0x28) { // XXX some crap with 0 here
|
||||
TRACE("XM error: unexpected sample header size\n");
|
||||
return -1;
|
||||
}*/
|
||||
if (!i || i > 0x28) i = 0x28;*/
|
||||
dumbfile_skip(f, 4);
|
||||
i = 0x28;
|
||||
extra->sample_header_size = i;
|
||||
|
||||
/* sample map */
|
||||
for (i = 0; i < 96; i++) {
|
||||
|
@ -476,7 +617,10 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
|
|||
for (i = 0; i < 96; i++)
|
||||
instrument->map_sample[i] = 0;
|
||||
|
||||
if (dumbfile_skip(f, size - bytes_read))
|
||||
if (size > bytes_read && dumbfile_skip(f, size - bytes_read))
|
||||
return -1;
|
||||
|
||||
if (skip_end && limit_xm_skip_end(f, skip_end))
|
||||
return -1;
|
||||
|
||||
instrument->new_note_action = NNA_NOTE_CUT;
|
||||
|
@ -531,6 +675,7 @@ static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
|
|||
|
||||
dumbfile_getnc(sample->name, 22, f);
|
||||
sample->name[22] = 0;
|
||||
trim_whitespace(sample->name, 22);
|
||||
|
||||
sample->filename[0] = 0;
|
||||
|
||||
|
@ -785,6 +930,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
return NULL;
|
||||
}
|
||||
sigdata->name[20] = 0;
|
||||
trim_whitespace(sigdata->name, 20);
|
||||
|
||||
if (dumbfile_getc(f) != 0x1A) {
|
||||
TRACE("XM error: 0x1A not found\n");
|
||||
|
@ -924,16 +1070,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
for (i = 0; i < sigdata->n_instruments; i++) {
|
||||
XM_INSTRUMENT_EXTRA extra;
|
||||
|
||||
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
|
||||
DUMBFILE * lf = dumbfile_limit_xm( f );
|
||||
if ( !lf ) {
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) {
|
||||
// XXX
|
||||
if ( ! i )
|
||||
{
|
||||
TRACE("XM error: instrument %d\n", i+1);
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dumbfile_close( lf );
|
||||
sigdata->n_instruments = i;
|
||||
break;
|
||||
}
|
||||
|
@ -948,17 +1102,31 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
|
||||
sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
|
||||
if (!sigdata->sample) {
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
for (j = total_samples; j < total_samples+extra.n_samples; j++)
|
||||
sigdata->sample[j].data = NULL;
|
||||
|
||||
if ( limit_xm_resize( lf, 0 ) < 0 ) {
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read instrument's samples */
|
||||
for (j = 0; j < extra.n_samples; j++) {
|
||||
IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
|
||||
int b = it_xm_read_sample_header(sample, f);
|
||||
int b;
|
||||
if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) {
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
b = it_xm_read_sample_header(sample, lf);
|
||||
if (b < 0) {
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -975,12 +1143,15 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
}
|
||||
for (j = 0; j < extra.n_samples; j++) {
|
||||
if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
|
||||
dumbfile_close( lf );
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
total_samples += extra.n_samples;
|
||||
}
|
||||
|
||||
dumbfile_close( lf );
|
||||
}
|
||||
|
||||
sigdata->n_samples = total_samples;
|
||||
|
@ -1012,8 +1183,16 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
for (i = 0; i < sigdata->n_instruments; i++) {
|
||||
XM_INSTRUMENT_EXTRA extra;
|
||||
|
||||
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
|
||||
DUMBFILE * lf = dumbfile_limit_xm( f );
|
||||
if ( !lf ) {
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) {
|
||||
TRACE("XM error: instrument %d\n", i+1);
|
||||
dumbfile_close(lf);
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
|
@ -1026,6 +1205,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
|
||||
sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
|
||||
if (!sigdata->sample) {
|
||||
dumbfile_close( lf );
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
return NULL;
|
||||
|
@ -1033,10 +1213,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
for (j = total_samples; j < total_samples+extra.n_samples; j++)
|
||||
sigdata->sample[j].data = NULL;
|
||||
|
||||
if ( limit_xm_resize( lf, 0 ) < 0 ) {
|
||||
dumbfile_close( lf );
|
||||
free( roguebytes );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read instrument's samples */
|
||||
for (j = 0; j < extra.n_samples; j++) {
|
||||
IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
|
||||
int b = it_xm_read_sample_header(sample, f);
|
||||
int b;
|
||||
if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) {
|
||||
dumbfile_close( lf );
|
||||
free( roguebytes );
|
||||
_dumb_it_unload_sigdata( sigdata );
|
||||
return NULL;
|
||||
}
|
||||
b = it_xm_read_sample_header(sample, lf);
|
||||
if (b < 0) {
|
||||
free(roguebytes);
|
||||
_dumb_it_unload_sigdata(sigdata);
|
||||
|
@ -1055,6 +1249,8 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
|
|||
}
|
||||
total_samples += extra.n_samples;
|
||||
}
|
||||
|
||||
dumbfile_close( lf );
|
||||
}
|
||||
|
||||
sigdata->n_samples = total_samples;
|
||||
|
|
|
@ -167,6 +167,7 @@ if (log) printf(" - %2d %02X", effect, value);
|
|||
case XM_SET_GLOBAL_VOLUME:
|
||||
effect = IT_SET_GLOBAL_VOLUME;
|
||||
value *= 2;
|
||||
if (value > 128) value = 128;
|
||||
break;
|
||||
|
||||
case XM_KEY_OFF:
|
||||
|
@ -187,6 +188,7 @@ if (log) printf(" - %2d %02X", effect, value);
|
|||
case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
|
||||
case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
|
||||
case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
|
||||
case EBASE+XM_E_SET_MIDI_MACRO: effect = SBASE+IT_S_SET_MIDI_MACRO; break;
|
||||
|
||||
case EBASE + XM_E_FINE_PORTA_UP:
|
||||
effect = IT_PORTAMENTO_UP;
|
||||
|
|
|
@ -877,6 +877,10 @@
|
|||
RelativePath="..\..\src\helpers\barray.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\helpers\blip_buf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\helpers\clickrem.c"
|
||||
>
|
||||
|
@ -1560,6 +1564,14 @@
|
|||
RelativePath="..\..\src\it\loadmtm2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\loadokt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\loadokt2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\loadoldpsm.c"
|
||||
>
|
||||
|
@ -1778,6 +1790,14 @@
|
|||
RelativePath="..\..\src\it\readmtm.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\readokt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\readokt2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\it\readoldpsm.c"
|
||||
>
|
||||
|
@ -1960,6 +1980,10 @@
|
|||
<Filter
|
||||
Name="internal"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\include\internal\blip_buf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\internal\dumb.h"
|
||||
>
|
||||
|
|
|
@ -6,7 +6,7 @@ if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
|||
set( CMAKE_BUILD_TYPE "RelWithDebInfo" )
|
||||
endif( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
|
||||
if( NOT PROFILE )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
|
@ -15,7 +15,7 @@ if( CMAKE_COMPILER_IS_GNUCXX )
|
|||
if( HAVE_NO_ARRAY_BOUNDS )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-array-bounds" )
|
||||
endif( HAVE_NO_ARRAY_BOUNDS )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
add_library( gme
|
||||
gme/Blip_Buffer.cpp
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -8,9 +8,9 @@ if( MSVC )
|
|||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102" )
|
||||
endif( MSVC )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
add_definitions( -DINFNAN_CHECK -DMULTIPLE_THREADS )
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUC )
|
||||
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
|
||||
endif( CMAKE_COMPILER_IS_GNUC )
|
||||
endif( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
add_library( jpeg
|
||||
jcomapi.c
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUC )
|
||||
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fomit-frame-pointer" )
|
||||
endif( CMAKE_COMPILER_IS_GNUC )
|
||||
endif( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
set( LZMA_FILES
|
||||
C/Archive/7z/7zDecode.c
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -111,11 +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
|
||||
blocksight = <bool>; // Line blocks monster line of sight
|
||||
|
||||
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.
|
||||
|
@ -135,16 +141,19 @@ 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.
|
||||
lightfog = <bool>; // true = This side's relative lighting is used even in
|
||||
// foggy sectors. Default is to disable relative
|
||||
// lighting in foggy sectors.
|
||||
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.
|
||||
|
@ -163,9 +172,9 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
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".
|
||||
// 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".
|
||||
// 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.
|
||||
|
@ -173,29 +182,35 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
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
|
||||
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-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.
|
||||
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:
|
||||
|
||||
|
@ -204,7 +219,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
|
||||
|
@ -213,16 +228,16 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
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
|
||||
|
@ -231,13 +246,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
|
||||
=======================================
|
||||
|
@ -303,6 +318,16 @@ Removed remarks of 8 being the maximum number of player classes/skill levels the
|
|||
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
|
||||
===============================================================================
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
===============================================================================
|
||||
Universal Strife Dialog Format Specification v2.0 - 08/20/10
|
||||
Universal Strife Dialog Format Specification v2.1 - 01/06/13
|
||||
|
||||
Written by Braden "Blzut3" Obrzut - admin@maniacsvault.net
|
||||
|
||||
|
@ -11,7 +11,7 @@ Graf Zahl
|
|||
Quasar
|
||||
et al.
|
||||
|
||||
Copyright (c) 2010 Braden Obrzut.
|
||||
Copyright (c) 2013 Braden Obrzut.
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2
|
||||
or any later version published by the Free Software Foundation;
|
||||
|
@ -19,6 +19,14 @@ et al.
|
|||
|
||||
===============================================================================
|
||||
|
||||
=======================================
|
||||
Changes in v2.1
|
||||
=======================================
|
||||
|
||||
* Pages are specified as starting as being indexed from 1 instead of 0. While
|
||||
this technically renders the spec incompatible, all known implementations
|
||||
used this convention as it was inline with the binary format.
|
||||
|
||||
=======================================
|
||||
I. Grammar / Syntax
|
||||
=======================================
|
||||
|
@ -77,7 +85,7 @@ conversation // Starts a dialog.
|
|||
actor = <integer>; // mobj for this conversation's actor. If previously
|
||||
// used, this will override the previous conversation.
|
||||
|
||||
page // Starts a new page. Pages are automatically numbered starting at 0.
|
||||
page // Starts a new page. Pages are automatically numbered starting at 1.
|
||||
{
|
||||
name = <string>; // Name that goes in the upper left hand corner
|
||||
panel = <string>; // Name of lump to render as the background.
|
||||
|
@ -105,14 +113,14 @@ conversation // Starts a dialog.
|
|||
|
||||
// The amount of an item needed to successfully pick this option.
|
||||
// This can be repeated, but only the first will be shown (provided
|
||||
// diaplaycost is true). All costs must be satisfied for success.
|
||||
// displaycost is true). All costs must be satisfied for success.
|
||||
cost
|
||||
{
|
||||
item = <integer>; // Item that is required for this option.
|
||||
amount = <integer>; // Minimum amount of the item needed.
|
||||
}
|
||||
|
||||
displaycost = <bool>; // Weather the cost should be
|
||||
displaycost = <bool>; // Whether the cost should be
|
||||
// displayed with the option.
|
||||
// If no cost is specified this should
|
||||
// be ignored.
|
||||
|
|
|
@ -10,14 +10,14 @@ include( CheckCXXCompilerFlag )
|
|||
include( FindPkgConfig )
|
||||
|
||||
option( NO_ASM "Disable assembly code" )
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
option( NO_STRIP "Do not strip Release or MinSizeRel builds" )
|
||||
# At least some versions of Xcode fail if you strip with the linker
|
||||
# instead of the separate strip utility.
|
||||
if( APPLE )
|
||||
set( NO_STRIP ON )
|
||||
endif( APPLE )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" )
|
||||
|
||||
|
@ -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 "44" "34" "28" "26" "24" "22" "20" )
|
||||
set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" )
|
||||
foreach( majver ${MAJOR_VERSIONS} )
|
||||
foreach( minver ${MINOR_VERSIONS} )
|
||||
|
@ -401,7 +401,7 @@ endif( NO_OPENAL )
|
|||
|
||||
# Search for FluidSynth
|
||||
|
||||
include( ../FindFluidSynth.cmake )
|
||||
find_package( FluidSynth )
|
||||
|
||||
# Search for NASM
|
||||
|
||||
|
@ -503,7 +503,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 )
|
||||
|
@ -515,7 +515,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 )
|
||||
|
@ -535,7 +535,7 @@ endif( SSE_MATTERS )
|
|||
|
||||
# Set up flags for GCC
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
if( PROFILE )
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
|
||||
|
@ -547,24 +547,24 @@ if( CMAKE_COMPILER_IS_GNUCXX )
|
|||
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 -Wextra -Wno-missing-field-initializers" )
|
||||
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 )
|
||||
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" )
|
||||
set (CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s" )
|
||||
endif( NOT NO_STRIP )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
# Check for functions that may or may not exist.
|
||||
|
||||
|
@ -588,13 +588,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 )
|
||||
|
@ -634,10 +627,12 @@ if( BACKPATCH )
|
|||
add_definitions( -DBACKPATCH )
|
||||
endif( BACKPATCH )
|
||||
|
||||
# Update svnrevision.h
|
||||
# Update gitinfo.h
|
||||
|
||||
get_target_property( UPDATEREVISION_EXE updaterevision LOCATION )
|
||||
|
||||
add_custom_target( revision_check ALL
|
||||
COMMAND ${CMAKE_BINARY_DIR}/tools/updaterevision/updaterevision . src/svnrevision.h
|
||||
COMMAND ${UPDATEREVISION_EXE} src/gitinfo.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
DEPENDS updaterevision )
|
||||
|
||||
|
@ -678,15 +673,15 @@ if( WIN32 )
|
|||
win32/i_system.cpp
|
||||
win32/st_start.cpp
|
||||
win32/win32video.cpp )
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
# CMake is not set up to compile and link rc files with GCC. :(
|
||||
add_custom_command( OUTPUT zdoom-rc.o
|
||||
COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc
|
||||
DEPENDS win32/zdoom.rc )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o )
|
||||
else( CMAKE_COMPILER_IS_GNUCXX )
|
||||
else( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
else( WIN32 )
|
||||
set( SYSTEM_SOURCES_DIR sdl )
|
||||
set( SYSTEM_SOURCES
|
||||
|
@ -701,7 +696,7 @@ else( WIN32 )
|
|||
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 )
|
||||
|
||||
|
@ -717,21 +712,19 @@ else( NO_ASM )
|
|||
ADD_ASM_FILE( asm_ia32 tmap2 )
|
||||
ADD_ASM_FILE( asm_ia32 tmap3 )
|
||||
endif( X64 )
|
||||
if( WIN32 )
|
||||
if( NOT X64 )
|
||||
ADD_ASM_FILE( win32 wrappers )
|
||||
endif( NOT X64 )
|
||||
endif( WIN32 )
|
||||
endif( NO_ASM )
|
||||
|
||||
get_target_property( LEMON_EXE lemon LOCATION )
|
||||
get_target_property( RE2C_EXE re2c LOCATION )
|
||||
|
||||
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y .
|
||||
COMMAND ${CMAKE_BINARY_DIR}/tools/lemon/lemon xlat_parser.y
|
||||
COMMAND ${LEMON_EXE} xlat_parser.y
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y )
|
||||
|
||||
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
|
||||
COMMAND ${CMAKE_BINARY_DIR}/tools/re2c/re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re
|
||||
COMMAND ${RE2C_EXE} --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re
|
||||
DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re )
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
@ -754,7 +747,37 @@ elseif( FLUIDSYNTH_FOUND )
|
|||
add_definitions( -DHAVE_FLUIDSYNTH )
|
||||
endif( DYN_FLUIDSYNTH )
|
||||
|
||||
# Project files should be aware of the header files. We can GLOB these since
|
||||
# there's generally a new cpp for every header so this file will get changed
|
||||
if( WIN32 )
|
||||
set( EXTRA_HEADER_DIRS win32/*.h )
|
||||
else( WIN32 )
|
||||
set( EXTRA_HEADER_DIRS sdl/*.h )
|
||||
endif( WIN32 )
|
||||
file( GLOB HEADER_FILES
|
||||
${EXTRA_HEADER_DIRS}
|
||||
fragglescript/*.h
|
||||
g_doom/*.h
|
||||
g_heretic/*.h
|
||||
g_hexen/*.h
|
||||
g_raven/*.h
|
||||
g_shared/*.h
|
||||
g_strife/*.h
|
||||
intermission/*.h
|
||||
menu/*.h
|
||||
oplsynth/*.h
|
||||
r_data/*.h
|
||||
resourcefiles/*.h
|
||||
sfmt/*.h
|
||||
sound/*.h
|
||||
textures/*.h
|
||||
thingdef/*.h
|
||||
xlat/*.h
|
||||
*.h
|
||||
)
|
||||
|
||||
add_executable( zdoom WIN32
|
||||
${HEADER_FILES}
|
||||
autostart.cpp
|
||||
${ASM_SOURCES}
|
||||
${SYSTEM_SOURCES}
|
||||
|
@ -803,6 +826,7 @@ add_executable( zdoom WIN32
|
|||
g_skill.cpp
|
||||
gameconfigfile.cpp
|
||||
gi.cpp
|
||||
gitinfo.cpp
|
||||
hu_scores.cpp
|
||||
i_net.cpp
|
||||
info.cpp
|
||||
|
@ -892,6 +916,7 @@ add_executable( zdoom WIN32
|
|||
tables.cpp
|
||||
teaminfo.cpp
|
||||
tempfiles.cpp
|
||||
v_blend.cpp
|
||||
v_collection.cpp
|
||||
v_draw.cpp
|
||||
v_font.cpp
|
||||
|
@ -967,6 +992,8 @@ add_executable( zdoom WIN32
|
|||
oplsynth/music_opldumper_mididevice.cpp
|
||||
oplsynth/music_opl_mididevice.cpp
|
||||
oplsynth/opl_mus_player.cpp
|
||||
oplsynth/dosbox/opl.cpp
|
||||
oplsynth/OPL3.cpp
|
||||
resourcefiles/ancientzip.cpp
|
||||
resourcefiles/file_7z.cpp
|
||||
resourcefiles/file_grp.cpp
|
||||
|
@ -1025,6 +1052,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
|
||||
|
@ -1098,7 +1126,7 @@ if( NOT WIN32 )
|
|||
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
|
||||
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
|
||||
endif( NOT WIN32 )
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
# GCC misoptimizes this file
|
||||
set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" )
|
||||
|
||||
|
@ -1106,4 +1134,8 @@ if( CMAKE_COMPILER_IS_GNUCXX )
|
|||
if( SSE_MATTERS )
|
||||
set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" )
|
||||
endif( SSE_MATTERS )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
if( MSVC )
|
||||
set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO")
|
||||
endif( MSVC )
|
||||
|
|
|
@ -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)
|
||||
|
@ -97,7 +97,7 @@ 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(Floor_RaiseAndCrushDoom, 99, 3, 4, 4)
|
||||
DEFINE_SPECIAL(Scroll_Texture_Left, 100, -1, -1, 2)
|
||||
DEFINE_SPECIAL(Scroll_Texture_Right, 101, -1, -1, 2)
|
||||
DEFINE_SPECIAL(Scroll_Texture_Up, 102, -1, -1, 2)
|
||||
|
@ -146,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)
|
||||
|
@ -205,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)
|
||||
|
@ -219,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)
|
||||
|
@ -228,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, 4)
|
||||
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)
|
||||
|
|
73
src/actor.h
73
src/actor.h
|
@ -30,9 +30,7 @@
|
|||
#include "dthinker.h"
|
||||
|
||||
|
||||
// States are tied to finite states are
|
||||
// tied to animation frames.
|
||||
// Needs precompiled tables/data structures.
|
||||
// States are tied to finite states are tied to animation frames.
|
||||
#include "info.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
|
@ -40,6 +38,7 @@
|
|||
#include "r_data/renderstyle.h"
|
||||
#include "s_sound.h"
|
||||
#include "memarena.h"
|
||||
#include "g_level.h"
|
||||
|
||||
struct subsector_t;
|
||||
//
|
||||
|
@ -266,8 +265,8 @@ 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.
|
||||
MF5_DONTDRAIN = 0x00000001, // cannot be drained health from.
|
||||
/* = 0x00000002, */
|
||||
MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances.
|
||||
/* = 0x00000008, */
|
||||
MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret
|
||||
|
@ -330,6 +329,8 @@ enum
|
|||
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 ---
|
||||
|
||||
|
@ -400,7 +401,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
|
||||
|
@ -412,6 +413,8 @@ 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_UseBounceState = 1<<14, // Use Bounce[.*] states
|
||||
|
||||
BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF,
|
||||
|
||||
|
@ -581,15 +584,14 @@ public:
|
|||
bool AdjustReflectionAngle (AActor *thing, angle_t &angle);
|
||||
|
||||
// Returns true if this actor is within melee range of its target
|
||||
bool CheckMeleeRange ();
|
||||
bool CheckMeleeRange();
|
||||
|
||||
// BeginPlay: Called just after the actor is created
|
||||
virtual void BeginPlay ();
|
||||
virtual void PostBeginPlay ();
|
||||
// LevelSpawned: Called after BeginPlay if this actor was spawned by the world
|
||||
virtual void LevelSpawned ();
|
||||
// Translates SpawnFlags into in-game flags.
|
||||
virtual void HandleSpawnFlags ();
|
||||
virtual void BeginPlay(); // Called immediately after the actor is created
|
||||
virtual void PostBeginPlay(); // Called immediately before the actor's first tick
|
||||
virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
|
||||
virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.
|
||||
|
||||
virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching.
|
||||
|
||||
virtual void Activate (AActor *activator);
|
||||
virtual void Deactivate (AActor *activator);
|
||||
|
@ -597,11 +599,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);
|
||||
|
@ -656,6 +658,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;
|
||||
|
||||
|
@ -696,7 +701,7 @@ public:
|
|||
virtual bool Massacre ();
|
||||
|
||||
// Transforms the actor into a finely-ground paste
|
||||
bool Grind(bool items);
|
||||
virtual bool Grind(bool items);
|
||||
|
||||
// Is the other actor on my team?
|
||||
bool IsTeammate (AActor *other);
|
||||
|
@ -707,9 +712,20 @@ public:
|
|||
// Do I hate the other actor?
|
||||
bool IsHostile (AActor *other);
|
||||
|
||||
inline bool IsNoClip2() const;
|
||||
|
||||
// What species am I?
|
||||
virtual FName GetSpecies();
|
||||
|
||||
|
||||
fixed_t GetBobOffset(fixed_t ticfrac=0) const
|
||||
{
|
||||
if (!(flags2 & MF2_FLOATBOB))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return finesine[MulScale22(((FloatBobPhase + level.maptime) << FRACBITS) + ticfrac, FINEANGLES) & FINEMASK] * 8;
|
||||
}
|
||||
|
||||
// Enter the crash state
|
||||
void Crash();
|
||||
|
||||
|
@ -763,6 +779,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);
|
||||
|
||||
|
@ -773,6 +793,8 @@ public:
|
|||
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.
|
||||
|
@ -814,6 +836,10 @@ public:
|
|||
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;
|
||||
|
@ -845,6 +871,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
|
||||
|
@ -950,6 +978,7 @@ private:
|
|||
static FSharedStringArena mStringPropertyData;
|
||||
|
||||
friend class FActorIterator;
|
||||
friend bool P_IsTIDUsed(int tid);
|
||||
|
||||
sector_t *LinkToWorldForMapThing ();
|
||||
|
||||
|
@ -978,6 +1007,11 @@ public:
|
|||
return GetClass()->ActorInfo->FindState(2, names, exact);
|
||||
}
|
||||
|
||||
FState *FindState(int numnames, FName *names, bool exact = false) const
|
||||
{
|
||||
return GetClass()->ActorInfo->FindState(numnames, names, exact);
|
||||
}
|
||||
|
||||
bool HasSpecialDeathStates () const;
|
||||
};
|
||||
|
||||
|
@ -1044,6 +1078,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool P_IsTIDUsed(int tid);
|
||||
int P_FindUniqueTID(int start_tid, int limit);
|
||||
|
||||
inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)
|
||||
{
|
||||
return AActor::StaticSpawn (type, x, y, z, allowreplacement);
|
||||
|
|
166
src/am_map.cpp
166
src/am_map.cpp
|
@ -40,6 +40,8 @@
|
|||
#include "c_bind.h"
|
||||
#include "farchive.h"
|
||||
#include "r_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "sbar.h"
|
||||
|
||||
#include "m_cheat.h"
|
||||
#include "i_system.h"
|
||||
|
@ -308,6 +310,7 @@ struct islope_t
|
|||
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
|
||||
|
@ -536,10 +539,12 @@ 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];
|
||||
|
@ -1077,7 +1082,7 @@ void AM_Stop ()
|
|||
{
|
||||
automapactive = false;
|
||||
stopped = true;
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
viewactive = true;
|
||||
}
|
||||
|
||||
|
@ -1155,7 +1160,10 @@ void AM_NewResolution()
|
|||
|
||||
CCMD (togglemap)
|
||||
{
|
||||
gameaction = ga_togglemap;
|
||||
if (gameaction == ga_nothing)
|
||||
{
|
||||
gameaction = ga_togglemap;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -1173,7 +1181,7 @@ void AM_ToggleMap ()
|
|||
if (dmflags2 & DF2_NO_AUTOMAP)
|
||||
return;
|
||||
|
||||
SB_state = screen->GetPageCount ();
|
||||
ST_SetNeedRefresh();
|
||||
if (!automapactive)
|
||||
{
|
||||
AM_Start ();
|
||||
|
@ -1184,7 +1192,7 @@ void AM_ToggleMap ()
|
|||
if (am_overlay==1 && viewactive)
|
||||
{
|
||||
viewactive = false;
|
||||
SB_state = screen->GetPageCount ();
|
||||
ST_SetNeedRefresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1605,9 +1613,10 @@ void AM_drawSubsectors()
|
|||
angle_t rotation;
|
||||
sector_t tempsec;
|
||||
int floorlight, ceilinglight;
|
||||
fixed_t scalex, scaley;
|
||||
double originx, originy;
|
||||
FDynamicColormap *colormap;
|
||||
|
||||
mpoint_t originpt;
|
||||
|
||||
for (int i = 0; i < numsubsectors; ++i)
|
||||
{
|
||||
|
@ -1636,27 +1645,17 @@ void AM_drawSubsectors()
|
|||
// For lighting and texture determination
|
||||
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 };
|
||||
originpt.x = -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS;
|
||||
originpt.y = sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS;
|
||||
rotation = 0 - sec->GetAngle(sector_t::floor);
|
||||
// Apply the floor's rotation to the texture origin.
|
||||
if (rotation != 0)
|
||||
{
|
||||
AM_rotate(&originpt.x, &originpt.y, rotation);
|
||||
}
|
||||
// Apply the automap's rotation to the texture origin.
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
rotation += ANG90 - players[consoleplayer].camera->angle;
|
||||
AM_rotatePoint(&originpt.x, &originpt.y);
|
||||
}
|
||||
originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24));
|
||||
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);
|
||||
|
||||
scalex = sec->GetXScale(sector_t::floor);
|
||||
scaley = sec->GetYScale(sector_t::floor);
|
||||
|
||||
#ifdef _3DFLOORS
|
||||
|
||||
if (sec->e->XFloor.ffloors.Size())
|
||||
|
@ -1670,6 +1669,7 @@ void AM_drawSubsectors()
|
|||
// (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)
|
||||
|
@ -1683,17 +1683,33 @@ void AM_drawSubsectors()
|
|||
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->flags & FF_RENDERPLANES)) continue;
|
||||
if (rover->alpha == 0) continue;
|
||||
if (rover->top.plane->ZatPoint(secx, secy) < cmpz)
|
||||
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;
|
||||
sector_t *model = rover->top.model;
|
||||
int selector = (rover->flags & FF_INVERTPLANES) ? sector_t::floor : sector_t::ceiling;
|
||||
rotation = 0 - model->GetAngle(selector);
|
||||
scalex = model->GetXScale(selector);
|
||||
scaley = model->GetYScale(selector);
|
||||
originpt.x = -model->GetXOffset(selector) >> FRACTOMAPBITS;
|
||||
originpt.y = model->GetYOffset(selector) >> FRACTOMAPBITS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1703,6 +1719,24 @@ void AM_drawSubsectors()
|
|||
colormap = light->extra_colormap;
|
||||
}
|
||||
#endif
|
||||
if (maptex == skyflatnum)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply the floor's rotation to the texture origin.
|
||||
if (rotation != 0)
|
||||
{
|
||||
AM_rotate(&originpt.x, &originpt.y, rotation);
|
||||
}
|
||||
// Apply the automap's rotation to the texture origin.
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
rotation += ANG90 - players[consoleplayer].camera->angle;
|
||||
AM_rotatePoint(&originpt.x, &originpt.y);
|
||||
}
|
||||
originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24));
|
||||
originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24));
|
||||
|
||||
// If this subsector has not actually been seen yet (because you are cheating
|
||||
// to see it on the map), tint and desaturate it.
|
||||
|
@ -1719,15 +1753,19 @@ void AM_drawSubsectors()
|
|||
}
|
||||
|
||||
// Draw the polygon.
|
||||
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
|
||||
);
|
||||
FTexture *pic = TexMan(maptex);
|
||||
if (pic != NULL && pic->UseType != FTexture::TEX_Null)
|
||||
{
|
||||
screen->FillSimplePoly(TexMan(maptex),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2DBL(scalex) * float(1 << MAPBITS)),
|
||||
scale / (FIXED2DBL(scaley) * float(1 << MAPBITS)),
|
||||
rotation,
|
||||
colormap,
|
||||
floorlight
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1907,6 +1945,7 @@ void AM_drawWalls (bool allmap)
|
|||
{
|
||||
int i;
|
||||
static mline_t l;
|
||||
int lock, color;
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
|
@ -1942,8 +1981,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) &&
|
||||
|
@ -1969,13 +2016,12 @@ void AM_drawWalls (bool allmap)
|
|||
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 || 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;
|
||||
|
||||
|
@ -2240,6 +2286,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;
|
||||
|
@ -2278,7 +2367,12 @@ 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));
|
||||
|
@ -2500,6 +2594,8 @@ void AM_Drawer ()
|
|||
|
||||
AM_drawWalls(allmap);
|
||||
AM_drawPlayers();
|
||||
if (G_SkillProperty(SKILLP_EasyKey))
|
||||
AM_drawKeys();
|
||||
if (am_cheat >= 2 || allthings)
|
||||
AM_drawThings();
|
||||
|
||||
|
|
|
@ -51,15 +51,16 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
|
|||
players[i].mo = NULL;
|
||||
}
|
||||
botinfo_t *bot = botinfo;
|
||||
while (bot && stricmp (players[i].userinfo.netname, bot->name))
|
||||
while (bot && stricmp (players[i].userinfo.GetName(), bot->name))
|
||||
bot = bot->next;
|
||||
if (bot)
|
||||
{
|
||||
bot->inuse = false;
|
||||
bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_NONE;
|
||||
bot->lastteam = keepTeam ? players[i].userinfo.GetTeam() : TEAM_NONE;
|
||||
}
|
||||
players[i].~player_t();
|
||||
::new(&players[i]) player_t;
|
||||
players[i].userinfo.Reset();
|
||||
playeringame[i] = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ void FCajunMaster::Main (int buf)
|
|||
//Check if player should go observer. Or un observe
|
||||
if (bot_observer && !observer && !netgame)
|
||||
{
|
||||
Printf ("%s is now observer\n", players[consoleplayer].userinfo.netname);
|
||||
Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
|
||||
observer = true;
|
||||
players[consoleplayer].mo->UnlinkFromWorld ();
|
||||
players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
|
||||
|
@ -149,7 +149,7 @@ void FCajunMaster::Main (int buf)
|
|||
}
|
||||
else if (!bot_observer && observer && !netgame) //Go back
|
||||
{
|
||||
Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.netname);
|
||||
Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
|
||||
observer = false;
|
||||
players[consoleplayer].mo->UnlinkFromWorld ();
|
||||
players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
|
||||
|
@ -218,7 +218,7 @@ void FCajunMaster::End ()
|
|||
{
|
||||
if (deathmatch)
|
||||
{
|
||||
getspawned.Push(players[i].userinfo.netname);
|
||||
getspawned.Push(players[i].userinfo.GetName());
|
||||
}
|
||||
CleanBotstuff (&players[i]);
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ void FCajunMaster::DoAddBot (int bnum, char *info)
|
|||
if (!deathmatch && playerstarts[bnum].type == 0)
|
||||
{
|
||||
Printf ("%s tried to join, but there was no player %d start\n",
|
||||
players[bnum].userinfo.netname, bnum+1);
|
||||
players[bnum].userinfo.GetName(), bnum+1);
|
||||
ClearPlayer (bnum, false); // Make the bot inactive again
|
||||
if (botnum > 0)
|
||||
{
|
||||
|
@ -370,9 +370,9 @@ void FCajunMaster::DoAddBot (int bnum, char *info)
|
|||
botingame[bnum] = true;
|
||||
|
||||
if (teamplay)
|
||||
Printf ("%s joined the %s team\n", players[bnum].userinfo.netname,Teams[players[bnum].userinfo.team].GetName ());
|
||||
Printf ("%s joined the %s team\n", players[bnum].userinfo.GetName(), Teams[players[bnum].userinfo.GetTeam()].GetName());
|
||||
else
|
||||
Printf ("%s joined the game\n", players[bnum].userinfo.netname);
|
||||
Printf ("%s joined the game\n", players[bnum].userinfo.GetName());
|
||||
|
||||
G_DoReborn (bnum, true);
|
||||
if (StatusBar != NULL)
|
||||
|
@ -474,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);
|
||||
|
|
|
@ -231,7 +231,7 @@ bool AnnounceKill (AActor *killer, AActor *killee)
|
|||
|
||||
if (killer == NULL)
|
||||
{ // The world killed the player
|
||||
if (killee->player->userinfo.gender == GENDER_MALE)
|
||||
if (killee->player->userinfo.GetGender() == GENDER_MALE)
|
||||
{ // Only males have scrotums to separate
|
||||
choice = &WorldKillSounds[rannum % 3];
|
||||
}
|
||||
|
@ -244,11 +244,11 @@ bool AnnounceKill (AActor *killer, AActor *killee)
|
|||
else if (killer == killee)
|
||||
{ // The player killed self
|
||||
choice = &SuicideSounds[rannum & 3];
|
||||
killerName = killer->player->userinfo.netname;
|
||||
killerName = killer->player->userinfo.GetName();
|
||||
}
|
||||
else
|
||||
{ // Another player did the killing
|
||||
if (killee->player->userinfo.gender == GENDER_MALE)
|
||||
if (killee->player->userinfo.GetGender() == GENDER_MALE)
|
||||
{ // Only males can be castrated
|
||||
choice = &KillSounds[rannum % countof(KillSounds)];
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ bool AnnounceKill (AActor *killer, AActor *killee)
|
|||
{
|
||||
choice = &KillSounds[rannum % (countof(KillSounds) - 1)];
|
||||
}
|
||||
killerName = killer->player->userinfo.netname;
|
||||
killerName = killer->player->userinfo.GetName();
|
||||
|
||||
// Blood only plays the announcement sound on the killer's
|
||||
// computer. I think it sounds neater to also hear it on
|
||||
|
@ -269,8 +269,8 @@ bool AnnounceKill (AActor *killer, AActor *killee)
|
|||
{
|
||||
char assembled[1024];
|
||||
|
||||
SexMessage (message, assembled, killee->player->userinfo.gender,
|
||||
killee->player->userinfo.netname, killerName);
|
||||
SexMessage (message, assembled, killee->player->userinfo.GetGender(),
|
||||
killee->player->userinfo.GetName(), killerName);
|
||||
Printf (PRINT_MEDIUM, "%s\n", assembled);
|
||||
}
|
||||
if (playSound)
|
||||
|
@ -301,8 +301,8 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee)
|
|||
{
|
||||
char assembled[1024];
|
||||
|
||||
SexMessage (message, assembled, killee->player->userinfo.gender,
|
||||
killee->player->userinfo.netname, killer->player->userinfo.netname);
|
||||
SexMessage (message, assembled, killee->player->userinfo.GetGender(),
|
||||
killee->player->userinfo.GetName(), killer->player->userinfo.GetName());
|
||||
Printf (PRINT_MEDIUM, "%s\n", assembled);
|
||||
}
|
||||
if (killee->CheckLocalView (consoleplayer) ||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -175,6 +175,15 @@ CCMD (noclip)
|
|||
Net_WriteByte (CHT_NOCLIP);
|
||||
}
|
||||
|
||||
CCMD (noclip2)
|
||||
{
|
||||
if (CheckCheatmode())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_NOCLIP2);
|
||||
}
|
||||
|
||||
CCMD (powerup)
|
||||
{
|
||||
if (CheckCheatmode ())
|
||||
|
@ -245,7 +254,7 @@ CCMD (chase)
|
|||
else
|
||||
{
|
||||
// Check if we're allowed to use chasecam.
|
||||
if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && CheckCheatmode ()))
|
||||
if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && deathmatch && CheckCheatmode ()))
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
|
@ -320,7 +329,7 @@ CCMD (hxvisit)
|
|||
|
||||
CCMD (changemap)
|
||||
{
|
||||
if (who == NULL)
|
||||
if (who == NULL || !usergame)
|
||||
{
|
||||
Printf ("Use the map command when not in a game.\n");
|
||||
return;
|
||||
|
@ -386,7 +395,7 @@ CCMD (take)
|
|||
|
||||
CCMD (gameversion)
|
||||
{
|
||||
Printf ("%s : " __DATE__ "\n", DOTVERSIONSTR);
|
||||
Printf ("%s @ %s\nCommit %s", GetVersionString(), GetGitTime(), GetGitHash());
|
||||
}
|
||||
|
||||
CCMD (print)
|
||||
|
@ -451,9 +460,9 @@ CCMD (puke)
|
|||
{
|
||||
int argc = argv.argc();
|
||||
|
||||
if (argc < 2 || argc > 5)
|
||||
if (argc < 2 || argc > 6)
|
||||
{
|
||||
Printf ("Usage: puke <script> [arg1] [arg2] [arg3]\n");
|
||||
Printf ("Usage: puke <script> [arg1] [arg2] [arg3] [arg4]\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -463,8 +472,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)
|
||||
{
|
||||
|
@ -489,6 +498,44 @@ 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();
|
||||
|
@ -911,9 +958,16 @@ CCMD(thaw)
|
|||
//-----------------------------------------------------------------------------
|
||||
CCMD(nextmap)
|
||||
{
|
||||
char * next=NULL;
|
||||
if (netgame)
|
||||
{
|
||||
Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextmap"
|
||||
TEXTCOLOR_NORMAL" is for single-player only.\n");
|
||||
return;
|
||||
}
|
||||
char *next = NULL;
|
||||
|
||||
if (*level.nextmap) next = level.nextmap;
|
||||
if (*level.nextmap)
|
||||
next = level.nextmap;
|
||||
|
||||
if (next != NULL && strncmp(next, "enDSeQ", 6))
|
||||
{
|
||||
|
@ -932,9 +986,16 @@ CCMD(nextmap)
|
|||
//-----------------------------------------------------------------------------
|
||||
CCMD(nextsecret)
|
||||
{
|
||||
char * next=NULL;
|
||||
if (netgame)
|
||||
{
|
||||
Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextsecret"
|
||||
TEXTCOLOR_NORMAL" is for single-player only.\n");
|
||||
return;
|
||||
}
|
||||
char *next = NULL;
|
||||
|
||||
if (*level.secretmap) next = level.secretmap;
|
||||
if (*level.secretmap)
|
||||
next = level.secretmap;
|
||||
|
||||
if (next != NULL && strncmp(next, "enDSeQ", 6))
|
||||
{
|
||||
|
@ -1050,7 +1111,8 @@ CCMD(secret)
|
|||
{
|
||||
FString levelname;
|
||||
level_info_t *info = FindLevelInfo(mapname);
|
||||
levelname.Format("%s - %s\n", mapname, info->LevelName.GetChars());
|
||||
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());
|
||||
|
|
|
@ -768,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;
|
||||
}
|
||||
|
@ -1134,7 +1134,7 @@ void C_DrawConsole (bool hw2d)
|
|||
(viewwindowx || viewwindowy) &&
|
||||
viewactive)
|
||||
{
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
}
|
||||
|
||||
oldbottom = ConBottom;
|
||||
|
@ -1167,9 +1167,9 @@ void C_DrawConsole (bool hw2d)
|
|||
if (ConBottom >= 12)
|
||||
{
|
||||
screen->DrawText (ConFont, CR_ORANGE, SCREENWIDTH - 8 -
|
||||
ConFont->StringWidth ("v" DOTVERSIONSTR),
|
||||
ConFont->StringWidth (GetVersionString()),
|
||||
ConBottom - ConFont->GetHeight() - 4,
|
||||
"v" DOTVERSIONSTR, TAG_DONE);
|
||||
GetVersionString(), TAG_DONE);
|
||||
if (TickerMax)
|
||||
{
|
||||
char tickstr[256];
|
||||
|
@ -1224,8 +1224,8 @@ void C_DrawConsole (bool hw2d)
|
|||
{
|
||||
screen->Dim (PalEntry ((unsigned char)(player->BlendR*255), (unsigned char)(player->BlendG*255), (unsigned char)(player->BlendB*255)),
|
||||
player->BlendA, 0, ConBottom, screen->GetWidth(), screen->GetHeight() - ConBottom);
|
||||
SB_state = screen->GetPageCount ();
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
ST_SetNeedRefresh();
|
||||
V_SetBorderNeedRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
167
src/c_cvars.cpp
167
src/c_cvars.cpp
|
@ -132,10 +132,10 @@ FBaseCVar::~FBaseCVar ()
|
|||
}
|
||||
}
|
||||
|
||||
void FBaseCVar::ForceSet (UCVarValue value, ECVarType type)
|
||||
void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend)
|
||||
{
|
||||
DoSet (value, type);
|
||||
if (Flags & CVAR_USERINFO)
|
||||
if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE))
|
||||
D_UserInfoChanged (this);
|
||||
if (m_UseCallback)
|
||||
Callback ();
|
||||
|
@ -266,7 +266,7 @@ static GUID cGUID;
|
|||
static char truestr[] = "true";
|
||||
static char falsestr[] = "false";
|
||||
|
||||
char *FBaseCVar::ToString (UCVarValue value, ECVarType type)
|
||||
const char *FBaseCVar::ToString (UCVarValue value, ECVarType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -849,9 +849,7 @@ UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const
|
|||
|
||||
void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
|
||||
{
|
||||
if (DefaultValue)
|
||||
delete[] DefaultValue;
|
||||
DefaultValue = ToString (value, type);
|
||||
ReplaceString(&DefaultValue, ToString(value, type));
|
||||
if (Flags & CVAR_ISDEFAULT)
|
||||
{
|
||||
SetGenericRep (value, type);
|
||||
|
@ -1274,52 +1272,56 @@ static int STACK_ARGS sortcvars (const void *a, const void *b)
|
|||
|
||||
void FilterCompactCVars (TArray<FBaseCVar *> &cvars, DWORD filter)
|
||||
{
|
||||
FBaseCVar *cvar = CVars;
|
||||
while (cvar)
|
||||
// Accumulate all cvars that match the filter flags.
|
||||
for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
|
||||
{
|
||||
if (cvar->Flags & filter)
|
||||
cvars.Push (cvar);
|
||||
cvar = cvar->m_Next;
|
||||
if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE))
|
||||
cvars.Push(cvar);
|
||||
}
|
||||
if (cvars.Size () > 0)
|
||||
// Now sort them, so they're in a deterministic order and not whatever
|
||||
// order the linker put them in.
|
||||
if (cvars.Size() > 0)
|
||||
{
|
||||
cvars.ShrinkToFit ();
|
||||
qsort (&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars);
|
||||
qsort(&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars);
|
||||
}
|
||||
}
|
||||
|
||||
void C_WriteCVars (BYTE **demo_p, DWORD filter, bool compact)
|
||||
{
|
||||
FBaseCVar *cvar = CVars;
|
||||
BYTE *ptr = *demo_p;
|
||||
FString dump = C_GetMassCVarString(filter, compact);
|
||||
size_t dumplen = dump.Len() + 1; // include terminating \0
|
||||
memcpy(*demo_p, dump.GetChars(), dumplen);
|
||||
*demo_p += dumplen;
|
||||
}
|
||||
|
||||
FString C_GetMassCVarString (DWORD filter, bool compact)
|
||||
{
|
||||
FBaseCVar *cvar;
|
||||
FString dump;
|
||||
|
||||
if (compact)
|
||||
{
|
||||
TArray<FBaseCVar *> cvars;
|
||||
ptr += sprintf ((char *)ptr, "\\\\%ux", filter);
|
||||
FilterCompactCVars (cvars, filter);
|
||||
dump.AppendFormat("\\\\%ux", filter);
|
||||
FilterCompactCVars(cvars, filter);
|
||||
while (cvars.Pop (cvar))
|
||||
{
|
||||
UCVarValue val = cvar->GetGenericRep (CVAR_String);
|
||||
ptr += sprintf ((char *)ptr, "\\%s", val.String);
|
||||
UCVarValue val = cvar->GetGenericRep(CVAR_String);
|
||||
dump << '\\' << val.String;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cvar = CVars;
|
||||
while (cvar)
|
||||
for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
|
||||
{
|
||||
if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSAVE))
|
||||
if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE)))
|
||||
{
|
||||
UCVarValue val = cvar->GetGenericRep (CVAR_String);
|
||||
ptr += sprintf ((char *)ptr, "\\%s\\%s",
|
||||
cvar->GetName (), val.String);
|
||||
UCVarValue val = cvar->GetGenericRep(CVAR_String);
|
||||
dump << '\\' << cvar->GetName() << '\\' << val.String;
|
||||
}
|
||||
cvar = cvar->m_Next;
|
||||
}
|
||||
}
|
||||
|
||||
*demo_p = ptr + 1;
|
||||
return dump;
|
||||
}
|
||||
|
||||
void C_ReadCVars (BYTE **demo_p)
|
||||
|
@ -1390,58 +1392,42 @@ void C_ReadCVars (BYTE **demo_p)
|
|||
*demo_p += strlen (*((char **)demo_p)) + 1;
|
||||
}
|
||||
|
||||
static struct backup_s
|
||||
struct FCVarBackup
|
||||
{
|
||||
char *name, *string;
|
||||
} CVarBackups[MAX_DEMOCVARS];
|
||||
|
||||
static int numbackedup = 0;
|
||||
FString Name, String;
|
||||
};
|
||||
static TArray<FCVarBackup> CVarBackups;
|
||||
|
||||
void C_BackupCVars (void)
|
||||
{
|
||||
struct backup_s *backup = CVarBackups;
|
||||
FBaseCVar *cvar = CVars;
|
||||
assert(CVarBackups.Size() == 0);
|
||||
CVarBackups.Clear();
|
||||
|
||||
while (cvar)
|
||||
FCVarBackup backup;
|
||||
|
||||
for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
|
||||
{
|
||||
if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE))
|
||||
&& !(cvar->Flags & CVAR_LATCH))
|
||||
if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) && !(cvar->Flags & CVAR_LATCH))
|
||||
{
|
||||
if (backup == &CVarBackups[MAX_DEMOCVARS])
|
||||
I_Error ("C_BackupDemoCVars: Too many cvars to save (%d)", MAX_DEMOCVARS);
|
||||
backup->name = copystring (cvar->GetName());
|
||||
backup->string = copystring (cvar->GetGenericRep (CVAR_String).String);
|
||||
backup++;
|
||||
backup.Name = cvar->GetName();
|
||||
backup.String = cvar->GetGenericRep(CVAR_String).String;
|
||||
CVarBackups.Push(backup);
|
||||
}
|
||||
cvar = cvar->m_Next;
|
||||
}
|
||||
numbackedup = int(backup - CVarBackups);
|
||||
}
|
||||
|
||||
void C_RestoreCVars (void)
|
||||
{
|
||||
struct backup_s *backup = CVarBackups;
|
||||
int i;
|
||||
|
||||
for (i = numbackedup; i; i--, backup++)
|
||||
for (unsigned int i = 0; i < CVarBackups.Size(); ++i)
|
||||
{
|
||||
cvar_set (backup->name, backup->string);
|
||||
cvar_set(CVarBackups[i].Name, CVarBackups[i].String);
|
||||
}
|
||||
C_ForgetCVars();
|
||||
}
|
||||
|
||||
void C_ForgetCVars (void)
|
||||
{
|
||||
struct backup_s *backup = CVarBackups;
|
||||
int i;
|
||||
|
||||
for (i = numbackedup; i; i--, backup++)
|
||||
{
|
||||
delete[] backup->name;
|
||||
delete[] backup->string;
|
||||
backup->name = backup->string = NULL;
|
||||
}
|
||||
numbackedup = 0;
|
||||
CVarBackups.Clear();
|
||||
}
|
||||
|
||||
FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev)
|
||||
|
@ -1489,6 +1475,30 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen)
|
|||
return var;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// C_CreateCVar
|
||||
//
|
||||
// Create a new cvar with the specified name and type. It should not already
|
||||
// exist.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags)
|
||||
{
|
||||
assert(FindCVar(var_name, NULL) == NULL);
|
||||
flags |= CVAR_AUTO;
|
||||
switch (var_type)
|
||||
{
|
||||
case CVAR_Bool: return new FBoolCVar(var_name, 0, flags);
|
||||
case CVAR_Int: return new FIntCVar(var_name, 0, flags);
|
||||
case CVAR_Float: return new FFloatCVar(var_name, 0, flags);
|
||||
case CVAR_String: return new FStringCVar(var_name, NULL, flags);
|
||||
case CVAR_Color: return new FColorCVar(var_name, 0, flags);
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void UnlatchCVars (void)
|
||||
{
|
||||
FLatchedValue var;
|
||||
|
@ -1522,33 +1532,14 @@ void C_SetCVarsToDefaults (void)
|
|||
}
|
||||
}
|
||||
|
||||
void C_ArchiveCVars (FConfigFile *f, int type)
|
||||
void C_ArchiveCVars (FConfigFile *f, uint32 filter)
|
||||
{
|
||||
// type 0: Game-specific cvars
|
||||
// type 1: Global cvars
|
||||
// type 2: Unknown cvars
|
||||
// type 3: Unknown global cvars
|
||||
// type 4: User info cvars
|
||||
// type 5: Server info cvars
|
||||
static const DWORD filters[6] =
|
||||
{
|
||||
CVAR_ARCHIVE,
|
||||
CVAR_ARCHIVE|CVAR_GLOBALCONFIG,
|
||||
CVAR_ARCHIVE|CVAR_AUTO,
|
||||
CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO,
|
||||
CVAR_ARCHIVE|CVAR_USERINFO,
|
||||
CVAR_ARCHIVE|CVAR_SERVERINFO
|
||||
};
|
||||
|
||||
FBaseCVar *cvar = CVars;
|
||||
DWORD filter;
|
||||
|
||||
filter = filters[type];
|
||||
|
||||
while (cvar)
|
||||
{
|
||||
if ((cvar->Flags &
|
||||
(CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE))
|
||||
(CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE))
|
||||
== filter)
|
||||
{
|
||||
UCVarValue val;
|
||||
|
@ -1679,14 +1670,16 @@ void FBaseCVar::ListVars (const char *filter, bool plain)
|
|||
else
|
||||
{
|
||||
++count;
|
||||
Printf ("%c%c%c %s : :%s\n",
|
||||
Printf ("%c%c%c%c%c %s = %s\n",
|
||||
flags & CVAR_ARCHIVE ? 'A' : ' ',
|
||||
flags & CVAR_USERINFO ? 'U' :
|
||||
flags & CVAR_SERVERINFO ? 'S' :
|
||||
flags & CVAR_AUTO ? 'C' : ' ',
|
||||
flags & CVAR_SERVERINFO ? 'S' :
|
||||
flags & CVAR_AUTO ? 'C' : ' ',
|
||||
flags & CVAR_NOSET ? '-' :
|
||||
flags & CVAR_LATCH ? 'L' :
|
||||
flags & CVAR_UNSETTABLE ? '*' : ' ',
|
||||
flags & CVAR_LATCH ? 'L' :
|
||||
flags & CVAR_UNSETTABLE ? '*' : ' ',
|
||||
flags & CVAR_MOD ? 'M' : ' ',
|
||||
flags & CVAR_IGNORE ? 'X' : ' ',
|
||||
var->GetName(),
|
||||
var->GetGenericRep (CVAR_String).String);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ enum
|
|||
CVAR_GLOBALCONFIG = 1024, // cvar is saved to global config section
|
||||
CVAR_VIDEOCONFIG = 2048, // cvar is saved to video config section (not implemented)
|
||||
CVAR_NOSAVE = 4096, // when used with CVAR_SERVERINFO, do not save var to savegame
|
||||
CVAR_MOD = 8192, // cvar was defined by a mod
|
||||
CVAR_IGNORE = 16384,// do not send cvar across the network/inaccesible from ACS (dummy mod cvar)
|
||||
};
|
||||
|
||||
union UCVarValue
|
||||
|
@ -68,7 +70,7 @@ union UCVarValue
|
|||
bool Bool;
|
||||
int Int;
|
||||
float Float;
|
||||
char *String;
|
||||
const char *String;
|
||||
const GUID *pGUID;
|
||||
};
|
||||
|
||||
|
@ -96,9 +98,10 @@ public:
|
|||
|
||||
inline const char *GetName () const { return Name; }
|
||||
inline uint32 GetFlags () const { return Flags; }
|
||||
inline FBaseCVar *GetNext() const { return m_Next; }
|
||||
|
||||
void CmdSet (const char *newval);
|
||||
void ForceSet (UCVarValue value, ECVarType type);
|
||||
void ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend=false);
|
||||
void SetGenericRep (UCVarValue value, ECVarType type);
|
||||
void ResetToDefault ();
|
||||
void SetArchiveBit () { Flags |= CVAR_ARCHIVE; }
|
||||
|
@ -129,7 +132,7 @@ protected:
|
|||
static bool ToBool (UCVarValue value, ECVarType type);
|
||||
static int ToInt (UCVarValue value, ECVarType type);
|
||||
static float ToFloat (UCVarValue value, ECVarType type);
|
||||
static char *ToString (UCVarValue value, ECVarType type);
|
||||
static const char *ToString (UCVarValue value, ECVarType type);
|
||||
static const GUID *ToGUID (UCVarValue value, ECVarType type);
|
||||
static UCVarValue FromBool (bool value, ECVarType type);
|
||||
static UCVarValue FromInt (int value, ECVarType type);
|
||||
|
@ -150,18 +153,22 @@ private:
|
|||
static bool m_UseCallback;
|
||||
static bool m_DoNoSet;
|
||||
|
||||
friend void C_WriteCVars (BYTE **demo_p, uint32 filter, bool compact);
|
||||
friend FString C_GetMassCVarString (uint32 filter, bool compact);
|
||||
friend void C_ReadCVars (BYTE **demo_p);
|
||||
friend void C_BackupCVars (void);
|
||||
friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
|
||||
friend FBaseCVar *FindCVarSub (const char *var_name, int namelen);
|
||||
friend void UnlatchCVars (void);
|
||||
friend void C_ArchiveCVars (FConfigFile *f, int type);
|
||||
friend void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
||||
friend void C_SetCVarsToDefaults (void);
|
||||
friend void FilterCompactCVars (TArray<FBaseCVar *> &cvars, uint32 filter);
|
||||
friend void C_DeinitConsole();
|
||||
};
|
||||
|
||||
// Returns a string with all cvars whose flags match filter. In compact mode,
|
||||
// the cvar names are omitted to save space.
|
||||
FString C_GetMassCVarString (uint32 filter, bool compact=false);
|
||||
|
||||
// Writes all cvars that could effect demo sync to *demo_p. These are
|
||||
// cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set.
|
||||
void C_WriteCVars (BYTE **demo_p, uint32 filter, bool compact=false);
|
||||
|
@ -177,11 +184,14 @@ void C_BackupCVars (void);
|
|||
FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
|
||||
FBaseCVar *FindCVarSub (const char *var_name, int namelen);
|
||||
|
||||
// Create a new cvar with the specified name and type
|
||||
FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags);
|
||||
|
||||
// Called from G_InitNew()
|
||||
void UnlatchCVars (void);
|
||||
|
||||
// archive cvars to FILE f
|
||||
void C_ArchiveCVars (FConfigFile *f, int type);
|
||||
void C_ArchiveCVars (FConfigFile *f, uint32 filter);
|
||||
|
||||
// initialize cvars to default values after they are created
|
||||
void C_SetCVarsToDefaults (void);
|
||||
|
@ -404,10 +414,6 @@ inline FBaseCVar *cvar_forceset (const char *var_name, const BYTE *value) { retu
|
|||
|
||||
|
||||
|
||||
// Maximum number of cvars that can be saved across a demo. If you need
|
||||
// to save more, bump this up.
|
||||
#define MAX_DEMOCVARS 32
|
||||
|
||||
// Restore demo cvars. Called after demo playback to restore all cvars
|
||||
// that might possibly have been changed during the course of demo playback.
|
||||
void C_RestoreCVars (void);
|
||||
|
@ -425,5 +431,6 @@ void C_ForgetCVars (void);
|
|||
|
||||
#define EXTERN_CVAR(type,name) extern F##type##CVar name;
|
||||
|
||||
extern FBaseCVar *CVars;
|
||||
|
||||
#endif //__C_CVARS_H__
|
||||
|
|
|
@ -1019,32 +1019,7 @@ FConsoleAlias::~FConsoleAlias ()
|
|||
m_Command[1] = m_Command[0] = FString();
|
||||
}
|
||||
|
||||
FString BuildString (int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
return *argv;
|
||||
}
|
||||
else
|
||||
{
|
||||
FString buf;
|
||||
int arg;
|
||||
|
||||
for (arg = 0; arg < argc; arg++)
|
||||
{
|
||||
if (strchr (argv[arg], ' '))
|
||||
{
|
||||
buf.AppendFormat ("\"%s\" ", argv[arg]);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.AppendFormat ("%s ", argv[arg]);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
// Given an argument vector, reconstitute the command line it could have been produced from.
|
||||
FString BuildString (int argc, FString *argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
|
@ -1058,8 +1033,23 @@ FString BuildString (int argc, FString *argv)
|
|||
|
||||
for (arg = 0; arg < argc; arg++)
|
||||
{
|
||||
if (strchr (argv[arg], ' '))
|
||||
{
|
||||
if (strchr(argv[arg], '"'))
|
||||
{ // If it contains one or more quotes, we need to escape them.
|
||||
buf << '"';
|
||||
long substr_start = 0, quotepos;
|
||||
while ((quotepos = argv[arg].IndexOf('"', substr_start)) >= 0)
|
||||
{
|
||||
if (substr_start < quotepos)
|
||||
{
|
||||
buf << argv[arg].Mid(substr_start, quotepos - substr_start);
|
||||
}
|
||||
buf << "\\\"";
|
||||
substr_start = quotepos + 1;
|
||||
}
|
||||
buf << argv[arg].Mid(substr_start) << "\" ";
|
||||
}
|
||||
else if (strchr(argv[arg], ' '))
|
||||
{ // If it contains a space, it needs to be quoted.
|
||||
buf << '"' << argv[arg] << "\" ";
|
||||
}
|
||||
else
|
||||
|
|
|
@ -61,7 +61,6 @@ 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);
|
||||
FString BuildString (int argc, FString *argv);
|
||||
|
||||
// Class that can parse command lines
|
||||
|
|
|
@ -537,6 +537,7 @@ void CreatePath(const char *fn)
|
|||
}
|
||||
if (mkdir(copy, 0755) == -1)
|
||||
{ // failed
|
||||
free(copy);
|
||||
return;
|
||||
}
|
||||
exists: if (p != NULL)
|
||||
|
@ -550,7 +551,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 +601,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 +653,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 +701,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;
|
||||
|
@ -751,7 +756,7 @@ FString strbin1 (const char *start)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void CleanseString(char *str)
|
||||
char *CleanseString(char *str)
|
||||
{
|
||||
char *escape = strrchr(str, TEXTCOLOR_ESCAPE);
|
||||
if (escape != NULL)
|
||||
|
@ -769,6 +774,7 @@ void CleanseString(char *str)
|
|||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -47,7 +47,7 @@ const char *myasctime ();
|
|||
|
||||
int strbin (char *str);
|
||||
FString strbin1 (const char *start);
|
||||
void CleanseString (char *str);
|
||||
char *CleanseString (char *str);
|
||||
|
||||
void CreatePath(const char * fn);
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "g_level.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "r_state.h"
|
||||
#include "w_wad.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -58,8 +59,15 @@
|
|||
struct FCompatOption
|
||||
{
|
||||
const char *Name;
|
||||
int CompatFlags;
|
||||
int BCompatFlags;
|
||||
DWORD CompatFlags;
|
||||
int WhichSlot;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SLOT_COMPAT,
|
||||
SLOT_COMPAT2,
|
||||
SLOT_BCOMPAT
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -67,7 +75,12 @@ enum
|
|||
CP_END,
|
||||
CP_CLEARFLAGS,
|
||||
CP_SETFLAGS,
|
||||
CP_SETSPECIAL
|
||||
CP_SETSPECIAL,
|
||||
CP_CLEARSPECIAL,
|
||||
CP_SETACTIVATION,
|
||||
CP_SECTORFLOOROFFSET,
|
||||
CP_SETWALLYSCALE,
|
||||
CP_SETTHINGZ,
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -77,6 +90,7 @@ enum
|
|||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
extern TArray<FMapThing> MapThingsConverted;
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
|
@ -86,44 +100,58 @@ TMap<FMD5Holder, FCompatValues, FMD5HashTraits> BCompatMap;
|
|||
|
||||
static FCompatOption Options[] =
|
||||
{
|
||||
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
|
||||
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
|
||||
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
|
||||
{ "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS },
|
||||
{ "setslopeoverflow", BCOMPATF_SETSLOPEOVERFLOW, SLOT_BCOMPAT },
|
||||
{ "resetplayerspeed", BCOMPATF_RESETPLAYERSPEED, SLOT_BCOMPAT },
|
||||
{ "vileghosts", BCOMPATF_VILEGHOSTS, SLOT_BCOMPAT },
|
||||
{ "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT },
|
||||
{ "rebuildnodes", BCOMPATF_REBUILDNODES, 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 },
|
||||
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, 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 }
|
||||
};
|
||||
|
||||
static const char *const LineSides[] =
|
||||
{
|
||||
"Front", "Back", NULL
|
||||
};
|
||||
|
||||
static const char *const WallTiers[] =
|
||||
{
|
||||
"Top", "Mid", "Bot", NULL
|
||||
};
|
||||
|
||||
static TArray<int> CompatParams;
|
||||
static int ii_compatparams;
|
||||
|
||||
|
@ -189,15 +217,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"))
|
||||
{
|
||||
|
@ -226,12 +252,59 @@ 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 if (sc.Compare("sectorflooroffset"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SECTORFLOOROFFSET);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetFloat();
|
||||
CompatParams.Push(FLOAT2FIXED(sc.Float));
|
||||
}
|
||||
else if (sc.Compare("setwallyscale"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETWALLYSCALE);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetString();
|
||||
CompatParams.Push(sc.MustMatchString(LineSides));
|
||||
sc.MustGetString();
|
||||
CompatParams.Push(sc.MustMatchString(WallTiers));
|
||||
sc.MustGetFloat();
|
||||
CompatParams.Push(FLOAT2FIXED(sc.Float));
|
||||
}
|
||||
else if (sc.Compare("setthingz"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETTHINGZ);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetFloat();
|
||||
CompatParams.Push(FLOAT2FIXED(sc.Float));
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet();
|
||||
|
@ -261,6 +334,7 @@ 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.
|
||||
|
@ -269,53 +343,74 @@ void CheckCompatibility(MapData *map)
|
|||
{
|
||||
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();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -368,6 +463,61 @@ 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;
|
||||
}
|
||||
case CP_SECTORFLOOROFFSET:
|
||||
{
|
||||
if (CompatParams[i+1] < numsectors)
|
||||
{
|
||||
sector_t *sec = §ors[CompatParams[i+1]];
|
||||
sec->floorplane.ChangeHeight(CompatParams[i+2]);
|
||||
sec->ChangePlaneTexZ(sector_t::floor, CompatParams[i+2]);
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
case CP_SETWALLYSCALE:
|
||||
{
|
||||
if (CompatParams[i+1] < numlines)
|
||||
{
|
||||
side_t *side = lines[CompatParams[i+1]].sidedef[CompatParams[i+2]];
|
||||
if (side != NULL)
|
||||
{
|
||||
side->SetTextureYScale(CompatParams[i+3], CompatParams[i+4]);
|
||||
}
|
||||
}
|
||||
i += 5;
|
||||
break;
|
||||
}
|
||||
case CP_SETTHINGZ:
|
||||
{
|
||||
// When this is called, the things haven't been spawned yet so we can alter the position inside the MapThings array.
|
||||
if ((unsigned)CompatParams[i+1] < MapThingsConverted.Size())
|
||||
{
|
||||
MapThingsConverted[CompatParams[i+1]].z = CompatParams[i+2];
|
||||
}
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,5 +566,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;
|
||||
};
|
||||
|
||||
|
|
|
@ -38,9 +38,12 @@
|
|||
|
||||
#include "doomtype.h"
|
||||
#include "configfile.h"
|
||||
#include "m_random.h"
|
||||
|
||||
#define READBUFFERSIZE 256
|
||||
|
||||
static FRandom pr_endtag;
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile Constructor
|
||||
|
@ -53,6 +56,8 @@ FConfigFile::FConfigFile ()
|
|||
LastSectionPtr = &Sections;
|
||||
CurrentEntry = NULL;
|
||||
PathName = "";
|
||||
OkayToWrite = true;
|
||||
FileExisted = true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -70,6 +75,8 @@ FConfigFile::FConfigFile (const char *pathname,
|
|||
CurrentEntry = NULL;
|
||||
ChangePathName (pathname);
|
||||
LoadConfigFile (nosechandler, userdata);
|
||||
OkayToWrite = true;
|
||||
FileExisted = true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -85,6 +92,8 @@ FConfigFile::FConfigFile (const FConfigFile &other)
|
|||
CurrentEntry = NULL;
|
||||
ChangePathName (other.PathName);
|
||||
*this = other;
|
||||
OkayToWrite = other.OkayToWrite;
|
||||
FileExisted = other.FileExisted;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -587,11 +596,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
|
||||
|
@ -669,13 +682,68 @@ bool FConfigFile::ReadConfig (void *file)
|
|||
whiteprobe++;
|
||||
}
|
||||
*(whiteprobe - 1) = 0;
|
||||
NewConfigEntry (section, start, whiteprobe);
|
||||
// Check for multi-line value
|
||||
if (whiteprobe[0] == '<' && whiteprobe[1] == '<' && whiteprobe[2] == '<' && whiteprobe[3] != '\0')
|
||||
{
|
||||
ReadMultiLineValue (file, section, start, whiteprobe + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewConfigEntry (section, start, whiteprobe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: ReadMultiLineValue
|
||||
//
|
||||
// Reads a multi-line value, with format as follows:
|
||||
//
|
||||
// key=<<<ENDTAG
|
||||
// ... blah blah blah ...
|
||||
// >>>ENDTAG
|
||||
//
|
||||
// The final ENDTAG must be on a line all by itself.
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSection *section, const char *key, const char *endtag)
|
||||
{
|
||||
char readbuf[READBUFFERSIZE];
|
||||
FString value;
|
||||
size_t endlen = strlen(endtag);
|
||||
|
||||
// Keep on reading lines until we reach a line that matches >>>endtag
|
||||
while (ReadLine(readbuf, READBUFFERSIZE, file) != NULL)
|
||||
{
|
||||
// Does the start of this line match the endtag?
|
||||
if (readbuf[0] == '>' && readbuf[1] == '>' && readbuf[2] == '>' &&
|
||||
strncmp(readbuf + 3, endtag, endlen) == 0)
|
||||
{ // Is there nothing but line break characters after the match?
|
||||
size_t i;
|
||||
for (i = endlen + 3; readbuf[i] != '\0'; ++i)
|
||||
{
|
||||
if (readbuf[i] != '\n' && readbuf[i] != '\r')
|
||||
{ // Not a line break character
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (readbuf[i] == '\0')
|
||||
{ // We're done; strip the previous line's line breaks, since it's not part of the value.
|
||||
value.StripRight("\n\r");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Append this line to the value.
|
||||
value << readbuf;
|
||||
}
|
||||
return NewConfigEntry(section, key, value);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: ReadLine
|
||||
|
@ -695,6 +763,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;
|
||||
|
@ -715,7 +790,16 @@ bool FConfigFile::WriteConfigFile () const
|
|||
fprintf (file, "[%s]\n", section->Name);
|
||||
while (entry != NULL)
|
||||
{
|
||||
fprintf (file, "%s=%s\n", entry->Key, entry->Value);
|
||||
if (strpbrk(entry->Value, "\r\n") == NULL)
|
||||
{ // Single-line value
|
||||
fprintf (file, "%s=%s\n", entry->Key, entry->Value);
|
||||
}
|
||||
else
|
||||
{ // Multi-line value
|
||||
const char *endtag = GenerateEndTag(entry->Value);
|
||||
fprintf (file, "%s=<<<%s\n%s\n>>>%s\n", entry->Key,
|
||||
endtag, entry->Value, endtag);
|
||||
}
|
||||
entry = entry->Next;
|
||||
}
|
||||
section = section->Next;
|
||||
|
@ -725,6 +809,44 @@ bool FConfigFile::WriteConfigFile () const
|
|||
return true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: GenerateEndTag
|
||||
//
|
||||
// Generates a terminator sequence for multi-line values that does
|
||||
// not appear anywhere in the value.
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
const char *FConfigFile::GenerateEndTag(const char *value)
|
||||
{
|
||||
static const char Base64Table[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
|
||||
static char EndTag[25] = "EOV-";
|
||||
|
||||
// Try different 20-character sequences until we find one that
|
||||
// isn't in the value. We create the sequences by generating two
|
||||
// 64-bit random numbers and Base64 encoding the first 15 bytes
|
||||
// from them.
|
||||
union { QWORD rand_num[2]; BYTE rand_bytes[16]; };
|
||||
do
|
||||
{
|
||||
rand_num[0] = pr_endtag.GenRand64();
|
||||
rand_num[1] = pr_endtag.GenRand64();
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
DWORD three_bytes = (rand_bytes[i*3] << 16) | (rand_bytes[i*3+1] << 8) | (rand_bytes[i*3+2]);
|
||||
EndTag[4+i*4 ] = Base64Table[rand_bytes[i*3] >> 2];
|
||||
EndTag[4+i*4+1] = Base64Table[((rand_bytes[i*3] & 3) << 4) | (rand_bytes[i*3+1] >> 4)];
|
||||
EndTag[4+i*4+2] = Base64Table[((rand_bytes[i*3+1] & 15) << 2) | (rand_bytes[i*3+2] >> 6)];
|
||||
EndTag[4+i*4+3] = Base64Table[rand_bytes[i*3+2] & 63];
|
||||
}
|
||||
}
|
||||
while (strstr(value, EndTag) != NULL);
|
||||
return EndTag;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: WriteCommentHeader
|
||||
|
|
|
@ -78,6 +78,10 @@ protected:
|
|||
|
||||
virtual char *ReadLine (char *string, int n, void *file) const;
|
||||
bool ReadConfig (void *file);
|
||||
static const char *GenerateEndTag(const char *value);
|
||||
|
||||
bool OkayToWrite;
|
||||
bool FileExisted;
|
||||
|
||||
private:
|
||||
struct FConfigEntry
|
||||
|
@ -107,6 +111,7 @@ private:
|
|||
FConfigEntry *FindEntry (FConfigSection *section, const char *key) const;
|
||||
FConfigSection *NewConfigSection (const char *name);
|
||||
FConfigEntry *NewConfigEntry (FConfigSection *section, const char *key, const char *value);
|
||||
FConfigEntry *ReadMultiLineValue (void *file, FConfigSection *section, const char *key, const char *terminator);
|
||||
void SetSectionNote (FConfigSection *section, const char *note);
|
||||
|
||||
public:
|
||||
|
|
|
@ -273,7 +273,9 @@ void CT_Drawer (void)
|
|||
|
||||
if (players[consoleplayer].camera != NULL &&
|
||||
(Button_ShowScores.bDown ||
|
||||
players[consoleplayer].camera->health <= 0))
|
||||
players[consoleplayer].camera->health <= 0) &&
|
||||
// Don't draw during intermission, since it has its own scoreboard in wi_stuff.cpp.
|
||||
gamestate != GS_INTERMISSION)
|
||||
{
|
||||
HU_DrawScores (&players[consoleplayer]);
|
||||
}
|
||||
|
|
|
@ -162,6 +162,41 @@ struct CodePointerAlias
|
|||
};
|
||||
static TArray<CodePointerAlias> MBFCodePointers;
|
||||
|
||||
struct AmmoPerAttack
|
||||
{
|
||||
actionf_p 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_PARAMS(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[] = {
|
||||
{ AF_A_Punch, 0},
|
||||
{ AF_A_FirePistol, 1},
|
||||
{ AF_A_FireShotgun, 1},
|
||||
{ AF_A_FireShotgun2, 2},
|
||||
{ AF_A_FireCGun, 1},
|
||||
{ AF_A_FireMissile, 1},
|
||||
{ AFP_A_Saw, 0},
|
||||
{ AF_A_FirePlasma, 1},
|
||||
{ AF_A_FireBFG, -1}, // uses deh.BFGCells
|
||||
{ AF_A_FireOldBFG, 1},
|
||||
{ AF_A_FireRailgun, 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
|
||||
|
@ -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
|
||||
|
@ -1087,6 +1126,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])
|
||||
|
@ -1182,15 +1230,24 @@ static int PatchThing (int thingy)
|
|||
PushTouchedActor(const_cast<PClass *>(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->ActorInfo, info);
|
||||
|
@ -1296,7 +1353,7 @@ static int PatchFrame (int frameNum)
|
|||
|
||||
if (keylen == 8 && stricmp (Line1, "Duration") == 0)
|
||||
{
|
||||
tics = clamp (val, -1, 65534);
|
||||
tics = clamp (val, -1, SHRT_MAX);
|
||||
}
|
||||
else if (keylen == 9 && stricmp (Line1, "Unknown 1") == 0)
|
||||
{
|
||||
|
@ -1571,6 +1628,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)
|
||||
{
|
||||
|
@ -1724,7 +1782,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)
|
||||
{
|
||||
|
@ -2279,6 +2337,28 @@ int D_LoadDehLumps()
|
|||
{
|
||||
count += D_LoadDehLump(lumpnum);
|
||||
}
|
||||
|
||||
if (0 == PatchSize)
|
||||
{
|
||||
// No DEH/BEX patch is loaded yet, try to find lump(s) with specific extensions
|
||||
|
||||
for (lumpnum = 0, lastlump = Wads.GetNumLumps();
|
||||
lumpnum < lastlump;
|
||||
++lumpnum)
|
||||
{
|
||||
const char* const fullName = Wads.GetLumpFullName(lumpnum);
|
||||
const char* const extension = strrchr(fullName, '.');
|
||||
|
||||
const bool isDehOrBex = NULL != extension
|
||||
&& (0 == stricmp(extension, ".deh") || 0 == stricmp(extension, ".bex"));
|
||||
|
||||
if (isDehOrBex)
|
||||
{
|
||||
count += D_LoadDehLump(lumpnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -2482,8 +2562,6 @@ static void UnloadDehSupp ()
|
|||
BitNames.ShrinkToFit();
|
||||
StyleNames.Clear();
|
||||
StyleNames.ShrinkToFit();
|
||||
WeaponNames.Clear();
|
||||
WeaponNames.ShrinkToFit();
|
||||
AmmoNames.Clear();
|
||||
AmmoNames.ShrinkToFit();
|
||||
|
||||
|
@ -2776,6 +2854,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("}"))
|
||||
{
|
||||
|
@ -2882,6 +2961,55 @@ void FinishDehPatch ()
|
|||
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]->ActorInfo->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);
|
||||
|
|
|
@ -63,6 +63,7 @@ typedef enum
|
|||
ga_newgame2,
|
||||
ga_loadgame,
|
||||
ga_loadgamehidecon,
|
||||
ga_loadgameplaydemo,
|
||||
ga_autoloadgame,
|
||||
ga_savegame,
|
||||
ga_autosave,
|
||||
|
@ -89,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,
|
||||
|
|
|
@ -413,7 +413,7 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
}
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
|
@ -441,7 +441,8 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
"heretic shadow of the serpent riders/base",
|
||||
"hexen/base",
|
||||
"hexen deathkings of the dark citadel/base",
|
||||
"ultimate doom/base"
|
||||
"ultimate doom/base",
|
||||
"DOOM 3 BFG Edition/base/wads"
|
||||
};
|
||||
steam_path += "/SteamApps/common/";
|
||||
for (i = 0; i < countof(steam_dirs); ++i)
|
||||
|
|
341
src/d_main.cpp
341
src/d_main.cpp
|
@ -106,6 +106,7 @@
|
|||
#include "po_man.h"
|
||||
#include "resourcefiles/resourcefile.h"
|
||||
#include "r_renderer.h"
|
||||
#include "p_local.h"
|
||||
|
||||
#ifdef USE_POLYMOST
|
||||
#include "r_polymost.h"
|
||||
|
@ -157,7 +158,6 @@ EXTERN_CVAR (Bool, sv_unlimited_pickup)
|
|||
|
||||
extern int testingmode;
|
||||
extern bool setmodeneeded;
|
||||
extern bool netdemo;
|
||||
extern int NewWidth, NewHeight, NewBits, DisplayBits;
|
||||
EXTERN_CVAR (Bool, st_scale)
|
||||
extern bool gameisdead;
|
||||
|
@ -515,8 +515,8 @@ CVAR (Flag, sv_nocountendmonst, dmflags2, DF2_NOCOUNTENDMONST);
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int i_compatflags; // internal compatflags composed from the compatflags CVAR and MAPINFO settings
|
||||
int ii_compatflags, ib_compatflags;
|
||||
int i_compatflags, i_compatflags2; // internal compatflags composed from the compatflags CVAR and MAPINFO settings
|
||||
int ii_compatflags, ii_compatflags2, ib_compatflags;
|
||||
|
||||
EXTERN_CVAR(Int, compatmode)
|
||||
|
||||
|
@ -526,19 +526,30 @@ static int GetCompatibility(int mask)
|
|||
else return (mask & ~level.info->compatmask) | (level.info->compatflags & level.info->compatmask);
|
||||
}
|
||||
|
||||
static int GetCompatibility2(int mask)
|
||||
{
|
||||
return (level.info == NULL) ? mask
|
||||
: (mask & ~level.info->compatmask2) | (level.info->compatflags2 & level.info->compatmask2);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||
{
|
||||
int old = i_compatflags;
|
||||
i_compatflags = GetCompatibility(self) | ii_compatflags;
|
||||
if ((old ^i_compatflags) & COMPATF_POLYOBJ)
|
||||
if ((old ^ i_compatflags) & COMPATF_POLYOBJ)
|
||||
{
|
||||
FPolyObj::ClearAllSubsectorLinks();
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Int, compatflags2, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||
{
|
||||
i_compatflags2 = GetCompatibility2(self) | ii_compatflags2;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
int v;
|
||||
int v, w = 0;
|
||||
|
||||
switch (self)
|
||||
{
|
||||
|
@ -551,6 +562,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
|||
v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT|
|
||||
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_DEHHEALTH|COMPATF_CROSSDROPOFF|
|
||||
COMPATF_LIGHT;
|
||||
w= COMPATF2_FLOORMOVE;
|
||||
break;
|
||||
|
||||
case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set)
|
||||
|
@ -558,6 +570,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
|||
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN|
|
||||
COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|
|
||||
COMPATF_WALLRUN|COMPATF_NOTOSSDROPS|COMPATF_LIGHT|COMPATF_MASKEDMIDTEX;
|
||||
w = COMPATF2_BADANGLES|COMPATF2_FLOORMOVE;
|
||||
break;
|
||||
|
||||
case 3: // Boom compat mode
|
||||
|
@ -573,47 +586,50 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
|||
COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS;
|
||||
break;
|
||||
|
||||
case 6: // Boom with some added settings to reenable spme 'broken' behavior
|
||||
case 6: // Boom with some added settings to reenable some 'broken' behavior
|
||||
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_NO_PASSMOBJ|
|
||||
COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS;
|
||||
break;
|
||||
|
||||
}
|
||||
compatflags = v;
|
||||
compatflags2 = w;
|
||||
}
|
||||
|
||||
CVAR (Flag, compat_shortTex, compatflags, COMPATF_SHORTTEX);
|
||||
CVAR (Flag, compat_stairs, compatflags, COMPATF_STAIRINDEX);
|
||||
CVAR (Flag, compat_limitpain, compatflags, COMPATF_LIMITPAIN);
|
||||
CVAR (Flag, compat_silentpickup,compatflags, COMPATF_SILENTPICKUP);
|
||||
CVAR (Flag, compat_nopassover, compatflags, COMPATF_NO_PASSMOBJ);
|
||||
CVAR (Flag, compat_soundslots, compatflags, COMPATF_MAGICSILENCE);
|
||||
CVAR (Flag, compat_wallrun, compatflags, COMPATF_WALLRUN);
|
||||
CVAR (Flag, compat_notossdrops, compatflags, COMPATF_NOTOSSDROPS);
|
||||
CVAR (Flag, compat_useblocking, compatflags, COMPATF_USEBLOCKING);
|
||||
CVAR (Flag, compat_nodoorlight, compatflags, COMPATF_NODOORLIGHT);
|
||||
CVAR (Flag, compat_ravenscroll, compatflags, COMPATF_RAVENSCROLL);
|
||||
CVAR (Flag, compat_soundtarget, compatflags, COMPATF_SOUNDTARGET);
|
||||
CVAR (Flag, compat_dehhealth, compatflags, COMPATF_DEHHEALTH);
|
||||
CVAR (Flag, compat_trace, compatflags, COMPATF_TRACE);
|
||||
CVAR (Flag, compat_dropoff, compatflags, COMPATF_DROPOFF);
|
||||
CVAR (Flag, compat_boomscroll, compatflags, COMPATF_BOOMSCROLL);
|
||||
CVAR (Flag, compat_invisibility,compatflags, COMPATF_INVISIBILITY);
|
||||
CVAR (Flag, compat_silentinstantfloors,compatflags, COMPATF_SILENT_INSTANT_FLOORS);
|
||||
CVAR (Flag, compat_sectorsounds,compatflags, COMPATF_SECTORSOUNDS);
|
||||
CVAR (Flag, compat_missileclip, compatflags, COMPATF_MISSILECLIP);
|
||||
CVAR (Flag, compat_crossdropoff,compatflags, COMPATF_CROSSDROPOFF);
|
||||
CVAR (Flag, compat_anybossdeath,compatflags, COMPATF_ANYBOSSDEATH);
|
||||
CVAR (Flag, compat_minotaur, compatflags, COMPATF_MINOTAUR);
|
||||
CVAR (Flag, compat_mushroom, compatflags, COMPATF_MUSHROOM);
|
||||
CVAR (Flag, compat_mbfmonstermove,compatflags, COMPATF_MBFMONSTERMOVE);
|
||||
CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS);
|
||||
CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS);
|
||||
CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT);
|
||||
CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN);
|
||||
CVAR (Flag, compat_light, compatflags,COMPATF_LIGHT);
|
||||
CVAR (Flag, compat_polyobj, compatflags,COMPATF_POLYOBJ);
|
||||
CVAR (Flag, compat_maskedmidtex,compatflags,COMPATF_MASKEDMIDTEX);
|
||||
CVAR (Flag, compat_shortTex, compatflags, COMPATF_SHORTTEX);
|
||||
CVAR (Flag, compat_stairs, compatflags, COMPATF_STAIRINDEX);
|
||||
CVAR (Flag, compat_limitpain, compatflags, COMPATF_LIMITPAIN);
|
||||
CVAR (Flag, compat_silentpickup, compatflags, COMPATF_SILENTPICKUP);
|
||||
CVAR (Flag, compat_nopassover, compatflags, COMPATF_NO_PASSMOBJ);
|
||||
CVAR (Flag, compat_soundslots, compatflags, COMPATF_MAGICSILENCE);
|
||||
CVAR (Flag, compat_wallrun, compatflags, COMPATF_WALLRUN);
|
||||
CVAR (Flag, compat_notossdrops, compatflags, COMPATF_NOTOSSDROPS);
|
||||
CVAR (Flag, compat_useblocking, compatflags, COMPATF_USEBLOCKING);
|
||||
CVAR (Flag, compat_nodoorlight, compatflags, COMPATF_NODOORLIGHT);
|
||||
CVAR (Flag, compat_ravenscroll, compatflags, COMPATF_RAVENSCROLL);
|
||||
CVAR (Flag, compat_soundtarget, compatflags, COMPATF_SOUNDTARGET);
|
||||
CVAR (Flag, compat_dehhealth, compatflags, COMPATF_DEHHEALTH);
|
||||
CVAR (Flag, compat_trace, compatflags, COMPATF_TRACE);
|
||||
CVAR (Flag, compat_dropoff, compatflags, COMPATF_DROPOFF);
|
||||
CVAR (Flag, compat_boomscroll, compatflags, COMPATF_BOOMSCROLL);
|
||||
CVAR (Flag, compat_invisibility, compatflags, COMPATF_INVISIBILITY);
|
||||
CVAR (Flag, compat_silentinstantfloors, compatflags, COMPATF_SILENT_INSTANT_FLOORS);
|
||||
CVAR (Flag, compat_sectorsounds, compatflags, COMPATF_SECTORSOUNDS);
|
||||
CVAR (Flag, compat_missileclip, compatflags, COMPATF_MISSILECLIP);
|
||||
CVAR (Flag, compat_crossdropoff, compatflags, COMPATF_CROSSDROPOFF);
|
||||
CVAR (Flag, compat_anybossdeath, compatflags, COMPATF_ANYBOSSDEATH);
|
||||
CVAR (Flag, compat_minotaur, compatflags, COMPATF_MINOTAUR);
|
||||
CVAR (Flag, compat_mushroom, compatflags, COMPATF_MUSHROOM);
|
||||
CVAR (Flag, compat_mbfmonstermove, compatflags, COMPATF_MBFMONSTERMOVE);
|
||||
CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS);
|
||||
CVAR (Flag, compat_noblockfriends, compatflags, COMPATF_NOBLOCKFRIENDS);
|
||||
CVAR (Flag, compat_spritesort, compatflags, COMPATF_SPRITESORT);
|
||||
CVAR (Flag, compat_hitscan, compatflags, COMPATF_HITSCAN);
|
||||
CVAR (Flag, compat_light, compatflags, COMPATF_LIGHT);
|
||||
CVAR (Flag, compat_polyobj, compatflags, COMPATF_POLYOBJ);
|
||||
CVAR (Flag, compat_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX);
|
||||
CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES);
|
||||
CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -665,6 +681,8 @@ void D_Display ()
|
|||
// Reload crosshair if transitioned to a different size
|
||||
ST_LoadCrosshair (true);
|
||||
AM_NewResolution ();
|
||||
// Reset the mouse cursor in case the bit depth changed
|
||||
vid_cursor.Callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,21 +697,21 @@ void D_Display ()
|
|||
|
||||
if (screen->Lock (false))
|
||||
{
|
||||
SB_state = screen->GetPageCount ();
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
ST_SetNeedRefresh();
|
||||
V_SetBorderNeedRefresh();
|
||||
}
|
||||
|
||||
// [RH] Allow temporarily disabling wipes
|
||||
if (NoWipe)
|
||||
{
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
NoWipe--;
|
||||
wipe = false;
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL)
|
||||
{ // save the current screen if about to wipe
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
switch (wipegamestate)
|
||||
{
|
||||
default:
|
||||
|
@ -756,13 +774,14 @@ void D_Display ()
|
|||
}
|
||||
screen->SetBlendingRect(viewwindowx, viewwindowy,
|
||||
viewwindowx + viewwidth, viewwindowy + viewheight);
|
||||
P_CheckPlayerSprites();
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
Renderer->RenderView(&players[consoleplayer]);
|
||||
P_UnPredictPlayer();
|
||||
if ((hw2d = screen->Begin2D(viewactive)))
|
||||
{
|
||||
// Redraw everything every frame when using 2D accel
|
||||
SB_state = screen->GetPageCount();
|
||||
BorderNeedRefresh = screen->GetPageCount();
|
||||
ST_SetNeedRefresh();
|
||||
V_SetBorderNeedRefresh();
|
||||
}
|
||||
Renderer->DrawRemainingPlayerSprites();
|
||||
screen->DrawBlendingRect();
|
||||
|
@ -783,17 +802,22 @@ void D_Display ()
|
|||
|
||||
if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10)
|
||||
{
|
||||
StatusBar->DrawBottomStuff (HUD_AltHud);
|
||||
if (DrawFSHUD || automapactive) DrawHUD();
|
||||
StatusBar->DrawTopStuff (HUD_None);
|
||||
StatusBar->Draw (HUD_AltHud);
|
||||
StatusBar->DrawTopStuff (HUD_AltHud);
|
||||
}
|
||||
else
|
||||
if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10)
|
||||
{
|
||||
StatusBar->Draw (DrawFSHUD ? HUD_Fullscreen : HUD_None);
|
||||
StatusBar->DrawTopStuff (DrawFSHUD ? HUD_Fullscreen : HUD_None);
|
||||
EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None;
|
||||
StatusBar->DrawBottomStuff (state);
|
||||
StatusBar->Draw (state);
|
||||
StatusBar->DrawTopStuff (state);
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusBar->DrawBottomStuff (HUD_StatusBar);
|
||||
StatusBar->Draw (HUD_StatusBar);
|
||||
StatusBar->DrawTopStuff (HUD_StatusBar);
|
||||
}
|
||||
|
@ -912,6 +936,7 @@ void D_Display ()
|
|||
|
||||
void D_ErrorCleanup ()
|
||||
{
|
||||
savegamerestore = false;
|
||||
screen->Unlock ();
|
||||
bglobal.RemoveAllBots (true);
|
||||
D_QuitNetGame ();
|
||||
|
@ -1210,12 +1235,17 @@ void D_DoAdvanceDemo (void)
|
|||
static int pagecount;
|
||||
const char *pagename = NULL;
|
||||
|
||||
advancedemo = false;
|
||||
|
||||
if (gameaction != ga_nothing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
V_SetBlend (0,0,0,0);
|
||||
players[consoleplayer].playerstate = PST_LIVE; // not reborn
|
||||
advancedemo = false;
|
||||
usergame = false; // no save / end game here
|
||||
paused = 0;
|
||||
gameaction = ga_nothing;
|
||||
|
||||
// [RH] If you want something more dynamic for your title, create a map
|
||||
// and name it TITLEMAP. That map will be loaded and used as the title.
|
||||
|
@ -1248,7 +1278,7 @@ void D_DoAdvanceDemo (void)
|
|||
Advisory = NULL;
|
||||
if (!M_DemoNoPlay)
|
||||
{
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
democount++;
|
||||
mysnprintf (demoname + 4, countof(demoname) - 4, "%d", democount);
|
||||
if (Wads.CheckNumForName (demoname) < 0)
|
||||
|
@ -1328,6 +1358,136 @@ CCMD (endgame)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ParseCVarInfo
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseCVarInfo()
|
||||
{
|
||||
int lump, lastlump = 0;
|
||||
bool addedcvars = false;
|
||||
|
||||
while ((lump = Wads.FindLump("CVARINFO", &lastlump)) != -1)
|
||||
{
|
||||
FScanner sc(lump);
|
||||
sc.SetCMode(true);
|
||||
|
||||
while (sc.GetToken())
|
||||
{
|
||||
FString cvarname;
|
||||
char *cvardefault = NULL;
|
||||
ECVarType cvartype = CVAR_Dummy;
|
||||
int cvarflags = CVAR_MOD|CVAR_ARCHIVE;
|
||||
FBaseCVar *cvar;
|
||||
|
||||
// Check for flag tokens.
|
||||
while (sc.TokenType == TK_Identifier)
|
||||
{
|
||||
if (stricmp(sc.String, "server") == 0)
|
||||
{
|
||||
cvarflags |= CVAR_SERVERINFO;
|
||||
}
|
||||
else if (stricmp(sc.String, "user") == 0)
|
||||
{
|
||||
cvarflags |= CVAR_USERINFO;
|
||||
}
|
||||
else if (stricmp(sc.String, "noarchive") == 0)
|
||||
{
|
||||
cvarflags &= ~CVAR_ARCHIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown cvar attribute '%s'", sc.String);
|
||||
}
|
||||
sc.MustGetAnyToken();
|
||||
}
|
||||
// Do some sanity checks.
|
||||
if ((cvarflags & (CVAR_SERVERINFO|CVAR_USERINFO)) == 0 ||
|
||||
(cvarflags & (CVAR_SERVERINFO|CVAR_USERINFO)) == (CVAR_SERVERINFO|CVAR_USERINFO))
|
||||
{
|
||||
sc.ScriptError("One of 'server' or 'user' must be specified");
|
||||
}
|
||||
// The next token must be the cvar type.
|
||||
if (sc.TokenType == TK_Bool)
|
||||
{
|
||||
cvartype = CVAR_Bool;
|
||||
}
|
||||
else if (sc.TokenType == TK_Int)
|
||||
{
|
||||
cvartype = CVAR_Int;
|
||||
}
|
||||
else if (sc.TokenType == TK_Float)
|
||||
{
|
||||
cvartype = CVAR_Float;
|
||||
}
|
||||
else if (sc.TokenType == TK_Color)
|
||||
{
|
||||
cvartype = CVAR_Color;
|
||||
}
|
||||
else if (sc.TokenType == TK_String)
|
||||
{
|
||||
cvartype = CVAR_String;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Bad cvar type '%s'", sc.String);
|
||||
}
|
||||
// The next token must be the cvar name.
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
if (FindCVar(sc.String, NULL) != NULL)
|
||||
{
|
||||
sc.ScriptError("cvar '%s' already exists", sc.String);
|
||||
}
|
||||
cvarname = sc.String;
|
||||
// A default value is optional and signalled by a '=' token.
|
||||
if (sc.CheckToken('='))
|
||||
{
|
||||
switch (cvartype)
|
||||
{
|
||||
case CVAR_Bool:
|
||||
if (!sc.CheckToken(TK_True) && !sc.CheckToken(TK_False))
|
||||
{
|
||||
sc.ScriptError("Expected true or false");
|
||||
}
|
||||
cvardefault = sc.String;
|
||||
break;
|
||||
case CVAR_Int:
|
||||
sc.MustGetNumber();
|
||||
cvardefault = sc.String;
|
||||
break;
|
||||
case CVAR_Float:
|
||||
sc.MustGetFloat();
|
||||
cvardefault = sc.String;
|
||||
break;
|
||||
default:
|
||||
sc.MustGetString();
|
||||
cvardefault = sc.String;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now create the cvar.
|
||||
cvar = C_CreateCVar(cvarname, cvartype, cvarflags);
|
||||
if (cvardefault != NULL)
|
||||
{
|
||||
UCVarValue val;
|
||||
val.String = cvardefault;
|
||||
cvar->SetGenericRepDefault(val, CVAR_String);
|
||||
}
|
||||
// To be like C and ACS, require a semicolon after everything.
|
||||
sc.MustGetToken(';');
|
||||
addedcvars = true;
|
||||
}
|
||||
}
|
||||
// Only load mod cvars from the config if we defined some, so we don't
|
||||
// clutter up the cvar space when not playing mods with custom cvars.
|
||||
if (addedcvars)
|
||||
{
|
||||
GameConfig->DoModSetup (gameinfo.ConfigName);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D_AddFile
|
||||
|
@ -1681,6 +1841,25 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
|
|||
sc.MustGetString();
|
||||
DoomStartupInfo.BkColor = V_GetColor(NULL, sc.String);
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("STARTUPTYPE"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
FString sttype = sc.String;
|
||||
if (!sttype.CompareNoCase("DOOM"))
|
||||
DoomStartupInfo.Type = FStartupInfo::DoomStartup;
|
||||
else if (!sttype.CompareNoCase("HERETIC"))
|
||||
DoomStartupInfo.Type = FStartupInfo::HereticStartup;
|
||||
else if (!sttype.CompareNoCase("HEXEN"))
|
||||
DoomStartupInfo.Type = FStartupInfo::HexenStartup;
|
||||
else if (!sttype.CompareNoCase("STRIFE"))
|
||||
DoomStartupInfo.Type = FStartupInfo::StrifeStartup;
|
||||
else DoomStartupInfo.Type = FStartupInfo::DefaultStartup;
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("STARTUPSONG"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
DoomStartupInfo.Song = sc.String;
|
||||
}
|
||||
}
|
||||
return iwad;
|
||||
}
|
||||
|
@ -2010,6 +2189,21 @@ static void CheckCmdLine()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FinalGC
|
||||
//
|
||||
// If this doesn't free everything, the debug CRT will let us know.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void FinalGC()
|
||||
{
|
||||
Args = NULL;
|
||||
GC::FullGC();
|
||||
GC::DelSoftRootHead(); // the soft root head will not be collected by a GC so we have to do it explicitly
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D_DoomMain
|
||||
|
@ -2028,6 +2222,7 @@ void D_DoomMain (void)
|
|||
|
||||
D_DoomInit();
|
||||
PClass::StaticInit ();
|
||||
atterm(FinalGC);
|
||||
|
||||
// [RH] Make sure zdoom.pk3 is always loaded,
|
||||
// as it contains magic stuff we need.
|
||||
|
@ -2099,7 +2294,10 @@ void D_DoomMain (void)
|
|||
allwads.Clear();
|
||||
allwads.ShrinkToFit();
|
||||
SetMapxxFlag();
|
||||
|
||||
|
||||
// Now that wads are loaded, define mod-specific cvars.
|
||||
ParseCVarInfo();
|
||||
|
||||
// [RH] Initialize localizable strings.
|
||||
GStrings.LoadStrings (false);
|
||||
|
||||
|
@ -2127,8 +2325,14 @@ void D_DoomMain (void)
|
|||
S_Init ();
|
||||
|
||||
Printf ("ST_Init: Init startup screen.\n");
|
||||
if (!restart) StartScreen = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5);
|
||||
else StartScreen = new FStartupScreen(0);
|
||||
if (!restart)
|
||||
{
|
||||
StartScreen = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartScreen = new FStartupScreen(0);
|
||||
}
|
||||
|
||||
ParseCompatibility();
|
||||
|
||||
|
@ -2137,14 +2341,17 @@ void D_DoomMain (void)
|
|||
// [RH] Load sound environments
|
||||
S_ParseReverbDef ();
|
||||
|
||||
// [RH] Parse any SNDINFO lumps
|
||||
Printf ("S_InitData: Load sound definitions.\n");
|
||||
S_InitData ();
|
||||
|
||||
// [RH] Parse through all loaded mapinfo lumps
|
||||
Printf ("G_ParseMapInfo: Load map definitions.\n");
|
||||
G_ParseMapInfo (iwad_info->MapInfo);
|
||||
ReadStatistics();
|
||||
|
||||
// [RH] Parse any SNDINFO lumps
|
||||
Printf ("S_InitData: Load sound definitions.\n");
|
||||
S_InitData ();
|
||||
// MUSINFO must be parsed after MAPINFO
|
||||
S_ParseMusInfo();
|
||||
|
||||
Printf ("Texman.Init: Init texture manager.\n");
|
||||
TexMan.Init();
|
||||
|
@ -2275,6 +2482,7 @@ void D_DoomMain (void)
|
|||
|
||||
delete StartScreen;
|
||||
StartScreen = NULL;
|
||||
S_Sound (CHAN_BODY, "misc/startupdone", 1, ATTN_NONE);
|
||||
|
||||
if (Args->CheckParm("-norun"))
|
||||
{
|
||||
|
@ -2282,6 +2490,16 @@ void D_DoomMain (void)
|
|||
}
|
||||
|
||||
V_Init2();
|
||||
UpdateJoystickMenu(NULL);
|
||||
|
||||
v = Args->CheckValue ("-loadgame");
|
||||
if (v)
|
||||
{
|
||||
FString file(v);
|
||||
FixPathSeperator (file);
|
||||
DefaultExtension (file, ".zds");
|
||||
G_LoadGame (file);
|
||||
}
|
||||
|
||||
v = Args->CheckValue("-playdemo");
|
||||
if (v != NULL)
|
||||
|
@ -2297,15 +2515,6 @@ void D_DoomMain (void)
|
|||
G_TimeDemo (v);
|
||||
D_DoomLoop (); // never returns
|
||||
}
|
||||
|
||||
v = Args->CheckValue ("-loadgame");
|
||||
if (v)
|
||||
{
|
||||
FString file(v);
|
||||
FixPathSeperator (file);
|
||||
DefaultExtension (file, ".zds");
|
||||
G_LoadGame (file);
|
||||
}
|
||||
|
||||
if (gameaction != ga_loadgame && gameaction != ga_loadgamehidecon)
|
||||
{
|
||||
|
|
11
src/d_main.h
11
src/d_main.h
|
@ -94,6 +94,17 @@ 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;
|
||||
|
|
199
src/d_net.cpp
199
src/d_net.cpp
|
@ -59,9 +59,9 @@
|
|||
#include "m_argv.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "v_video.h"
|
||||
|
||||
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
||||
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
||||
#include "p_spec.h"
|
||||
#include "hardware.h"
|
||||
#include "intermission/intermission.h"
|
||||
|
||||
EXTERN_CVAR (Int, disableautosave)
|
||||
EXTERN_CVAR (Int, autosavecount)
|
||||
|
@ -108,6 +108,8 @@ int resendcount[MAXNETNODES];
|
|||
|
||||
unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings
|
||||
unsigned int currrecvtime[MAXPLAYERS];
|
||||
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
|
||||
bool hadlate;
|
||||
|
||||
int nodeforplayer[MAXPLAYERS];
|
||||
int playerfornode[MAXNETNODES];
|
||||
|
@ -121,6 +123,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];
|
||||
|
@ -135,7 +138,18 @@ static int oldentertics;
|
|||
|
||||
extern bool advancedemo;
|
||||
|
||||
CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
// Do not use the separate FPS limit timer if we are limiting FPS with this.
|
||||
if (self)
|
||||
{
|
||||
I_SetFPSLimit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
I_SetFPSLimit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Special "ticcmds" get stored in here
|
||||
static struct TicSpecial
|
||||
|
@ -299,6 +313,8 @@ void Net_ClearBuffers ()
|
|||
oldentertics = entertic;
|
||||
gametic = 0;
|
||||
maketic = 0;
|
||||
|
||||
lastglobalrecvtime = 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -584,21 +600,24 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
if (deathmatch)
|
||||
{
|
||||
Printf ("%s left the game with %d frags\n",
|
||||
players[netconsole].userinfo.netname,
|
||||
players[netconsole].fragcount);
|
||||
players[netconsole].userinfo.GetName(),
|
||||
players[netconsole].fragcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("%s left the game\n", players[netconsole].userinfo.netname);
|
||||
Printf ("%s left the game\n", players[netconsole].userinfo.GetName());
|
||||
}
|
||||
|
||||
// [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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,6 +628,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;
|
||||
}
|
||||
|
@ -626,7 +650,7 @@ void PlayerIsGone (int netnode, int netconsole)
|
|||
{
|
||||
Net_Arbitrator = i;
|
||||
players[i].settings_controller = true;
|
||||
Printf ("%s is the new arbitrator\n", players[i].userinfo.netname);
|
||||
Printf ("%s is the new arbitrator\n", players[i].userinfo.GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -680,6 +704,8 @@ void GetPackets (void)
|
|||
}
|
||||
continue; // extra setup packet
|
||||
}
|
||||
|
||||
lastglobalrecvtime = I_GetTime (false); //Update the last time a packet was recieved
|
||||
|
||||
netnode = doomcom.remotenode;
|
||||
netconsole = playerfornode[netnode] & ~PL_DRONE;
|
||||
|
@ -748,6 +774,7 @@ void GetPackets (void)
|
|||
}
|
||||
|
||||
if (netbuffer[0] & NCMD_QUITTERS)
|
||||
|
||||
{
|
||||
numplayers = netbuffer[k++];
|
||||
for (int i = 0; i < numplayers; ++i)
|
||||
|
@ -1340,7 +1367,7 @@ bool DoArbitrate (void *userdata)
|
|||
data->playersdetected[0] |= 1 << netbuffer[1];
|
||||
|
||||
StartScreen->NetMessage ("Found %s (node %d, player %d)",
|
||||
players[netbuffer[1]].userinfo.netname,
|
||||
players[netbuffer[1]].userinfo.GetName(),
|
||||
node, netbuffer[1]+1);
|
||||
}
|
||||
}
|
||||
|
@ -1799,6 +1826,33 @@ void TryRunTics (void)
|
|||
if (lowtic < gametic)
|
||||
I_Error ("TryRunTics: lowtic < gametic");
|
||||
|
||||
// [Ed850] Check to see the last time a packet was recieved.
|
||||
// If it's longer then 3 seconds, a node has likely stalled. Check which one and re-request its last packet.
|
||||
if(I_GetTime(false) - lastglobalrecvtime >= TICRATE*3)
|
||||
{
|
||||
int latenode = 0; // Node 0 is the local player, and should always be the highest
|
||||
lastglobalrecvtime = I_GetTime(false); //Bump the count
|
||||
|
||||
if(NetMode == NET_PeerToPeer || consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
if (nodeingame[i] && nettics[i] < nettics[latenode])
|
||||
latenode = i;
|
||||
}
|
||||
else if (nodeingame[nodeforplayer[Net_Arbitrator]] &&
|
||||
nettics[nodeforplayer[Net_Arbitrator]] < nettics[0])
|
||||
{ // Likely a packet server game. Only check the packet host.
|
||||
latenode = Net_Arbitrator;
|
||||
}
|
||||
|
||||
if (debugfile)
|
||||
fprintf (debugfile, "lost tics from %i (%i to %i)\n",
|
||||
latenode, nettics[latenode], gametic);
|
||||
|
||||
if(latenode != 0) // Send resend request to late node (if not yourself... somehow). Also mark the node as waiting to display it in the hud.
|
||||
remoteresend[latenode] = players[playerfornode[latenode]].waiting = hadlate = true;
|
||||
}
|
||||
|
||||
// don't stay in here forever -- give the menu a chance to work
|
||||
if (I_GetTime (false) - entertic >= TICRATE/3)
|
||||
{
|
||||
|
@ -1808,6 +1862,13 @@ void TryRunTics (void)
|
|||
}
|
||||
}
|
||||
|
||||
if (hadlate)
|
||||
{
|
||||
hadlate = false;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
players[i].waiting = false;
|
||||
}
|
||||
|
||||
// run the count tics
|
||||
if (counts > 0)
|
||||
{
|
||||
|
@ -1947,12 +2008,12 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
{
|
||||
case DEM_SAY:
|
||||
{
|
||||
const char *name = players[player].userinfo.netname;
|
||||
const char *name = players[player].userinfo.GetName();
|
||||
BYTE who = ReadByte (stream);
|
||||
|
||||
s = ReadString (stream);
|
||||
CleanseString (s);
|
||||
if (((who & 1) == 0) || players[player].userinfo.team == TEAM_NONE)
|
||||
if (((who & 1) == 0) || players[player].userinfo.GetTeam() == TEAM_NONE)
|
||||
{ // Said to everyone
|
||||
if (who & 2)
|
||||
{
|
||||
|
@ -1964,7 +2025,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
}
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE);
|
||||
}
|
||||
else if (players[player].userinfo.team == players[consoleplayer].userinfo.team)
|
||||
else if (players[player].userinfo.GetTeam() == players[consoleplayer].userinfo.GetTeam())
|
||||
{ // Said only to members of the player's team
|
||||
if (who & 2)
|
||||
{
|
||||
|
@ -2058,10 +2119,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:
|
||||
|
@ -2227,7 +2285,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
paused = player + 1;
|
||||
S_PauseSound (false, false);
|
||||
}
|
||||
BorderNeedRefresh = screen->GetPageCount ();
|
||||
V_SetBorderNeedRefresh();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2313,18 +2371,17 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
{
|
||||
int snum = ReadWord (stream);
|
||||
int argn = ReadByte (stream);
|
||||
int arg[3] = { 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < argn; ++i)
|
||||
{
|
||||
int argval = ReadLong(stream);
|
||||
if ((unsigned)i < countof(arg))
|
||||
{
|
||||
arg[i] = argval;
|
||||
}
|
||||
}
|
||||
P_StartScript (players[player].mo, NULL, snum, level.mapname, false,
|
||||
arg[0], arg[1], arg[2], type == DEM_RUNSCRIPT2, false, true);
|
||||
|
||||
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;
|
||||
|
||||
|
@ -2351,9 +2408,10 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
|
||||
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;
|
||||
|
||||
|
@ -2374,7 +2432,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
players[playernum].settings_controller = true;
|
||||
|
||||
if (consoleplayer == playernum || consoleplayer == Net_Arbitrator)
|
||||
Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.netname);
|
||||
Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2384,7 +2442,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
players[playernum].settings_controller = false;
|
||||
|
||||
if (consoleplayer == playernum || consoleplayer == Net_Arbitrator)
|
||||
Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.netname);
|
||||
Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.GetName());
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2419,17 +2477,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(i = 0; i < count; ++i)
|
||||
{
|
||||
const PClass *wpn = Net_ReadWeapon(stream);
|
||||
players[player].weapons.AddSlot(slot, wpn, player == consoleplayer);
|
||||
players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2450,6 +2518,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;
|
||||
|
@ -2459,6 +2540,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;
|
||||
|
@ -2547,6 +2645,11 @@ 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;
|
||||
|
@ -2556,9 +2659,10 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
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);
|
||||
}
|
||||
|
@ -2570,6 +2674,9 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
skip = 2 + ((*stream)[1] >> 7);
|
||||
break;
|
||||
|
||||
case DEM_SETPITCHLIMIT:
|
||||
skip = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
@ -2586,7 +2693,7 @@ CCMD (pings)
|
|||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||
players[i].userinfo.netname);
|
||||
players[i].userinfo.GetName());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -2608,13 +2715,13 @@ static void Network_Controller (int playernum, bool add)
|
|||
|
||||
if (players[playernum].settings_controller && add)
|
||||
{
|
||||
Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.netname);
|
||||
Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!players[playernum].settings_controller && !add)
|
||||
{
|
||||
Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.netname);
|
||||
Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2713,7 +2820,7 @@ CCMD (net_listcontrollers)
|
|||
|
||||
if (players[i].settings_controller)
|
||||
{
|
||||
Printf ("- %s\n", players[i].userinfo.netname);
|
||||
Printf ("- %s\n", players[i].userinfo.GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,22 +92,6 @@ enum
|
|||
|
||||
const char *GenderNames[3] = { "male", "female", "other" };
|
||||
|
||||
static const char *UserInfoStrings[] =
|
||||
{
|
||||
"name",
|
||||
"autoaim",
|
||||
"color",
|
||||
"skin",
|
||||
"team",
|
||||
"gender",
|
||||
"neverswitchonpickup",
|
||||
"movebob",
|
||||
"stillbob",
|
||||
"playerclass",
|
||||
"colorset",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Replace \ with %/ and % with %%
|
||||
FString D_EscapeUserInfo (const char *str)
|
||||
{
|
||||
|
@ -192,11 +176,12 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet
|
|||
{
|
||||
userinfo_t *info = &players[player].userinfo;
|
||||
FPlayerColorSet *colorset = NULL;
|
||||
int color;
|
||||
uint32 color;
|
||||
int team;
|
||||
|
||||
if (players[player].mo != NULL)
|
||||
{
|
||||
colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->colorset);
|
||||
colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->GetColorSet());
|
||||
}
|
||||
if (colorset != NULL)
|
||||
{
|
||||
|
@ -204,25 +189,28 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet
|
|||
}
|
||||
else
|
||||
{
|
||||
color = info->color;
|
||||
color = info->GetColor();
|
||||
}
|
||||
|
||||
RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f,
|
||||
h, s, v);
|
||||
|
||||
if (teamplay && TeamLibrary.IsValidTeam(info->team) && !Teams[info->team].GetAllowCustomPlayerColor ())
|
||||
if (teamplay && TeamLibrary.IsValidTeam((team = info->GetTeam())) && !Teams[team].GetAllowCustomPlayerColor())
|
||||
{
|
||||
// In team play, force the player to use the team's hue
|
||||
// and adjust the saturation and value so that the team
|
||||
// hue is visible in the final color.
|
||||
float ts, tv;
|
||||
int tcolor = Teams[info->team].GetPlayerColor ();
|
||||
int tcolor = Teams[team].GetPlayerColor ();
|
||||
|
||||
RGBtoHSV (RPART(tcolor)/255.f, GPART(tcolor)/255.f, BPART(tcolor)/255.f,
|
||||
h, &ts, &tv);
|
||||
|
||||
*s = clamp(ts + *s * 0.15f - 0.075f, 0.f, 1.f);
|
||||
*v = clamp(tv + *v * 0.5f - 0.25f, 0.f, 1.f);
|
||||
|
||||
// Make sure not to pass back any colorset in teamplay.
|
||||
colorset = NULL;
|
||||
}
|
||||
if (set != NULL)
|
||||
{
|
||||
|
@ -261,9 +249,10 @@ int D_PickRandomTeam ()
|
|||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
if (TeamLibrary.IsValidTeam (players[i].userinfo.team))
|
||||
team = players[i].userinfo.GetTeam();
|
||||
if (TeamLibrary.IsValidTeam(team))
|
||||
{
|
||||
if (Teams[players[i].userinfo.team].m_iPresent++ == 0)
|
||||
if (Teams[team].m_iPresent++ == 0)
|
||||
{
|
||||
numTeams++;
|
||||
}
|
||||
|
@ -275,7 +264,7 @@ int D_PickRandomTeam ()
|
|||
{
|
||||
do
|
||||
{
|
||||
team = pr_pickteam() % Teams.Size ();
|
||||
team = pr_pickteam() % Teams.Size();
|
||||
} while (Teams[team].m_iPresent != 0);
|
||||
}
|
||||
else
|
||||
|
@ -316,7 +305,7 @@ static void UpdateTeam (int pnum, int team, bool update)
|
|||
{
|
||||
userinfo_t *info = &players[pnum].userinfo;
|
||||
|
||||
if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->team))
|
||||
if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->GetTeam()))
|
||||
{
|
||||
Printf ("Team changing has been disabled!\n");
|
||||
return;
|
||||
|
@ -328,19 +317,15 @@ static void UpdateTeam (int pnum, int team, bool update)
|
|||
{
|
||||
team = TEAM_NONE;
|
||||
}
|
||||
oldteam = info->team;
|
||||
info->team = team;
|
||||
oldteam = info->GetTeam();
|
||||
team = info->TeamChanged(team);
|
||||
|
||||
if (teamplay && !TeamLibrary.IsValidTeam (info->team))
|
||||
{ // Force players onto teams in teamplay mode
|
||||
info->team = D_PickRandomTeam ();
|
||||
}
|
||||
if (update && oldteam != info->team)
|
||||
if (update && oldteam != team)
|
||||
{
|
||||
if (TeamLibrary.IsValidTeam (info->team))
|
||||
Printf ("%s joined the %s team\n", info->netname, Teams[info->team].GetName ());
|
||||
if (TeamLibrary.IsValidTeam (team))
|
||||
Printf ("%s joined the %s team\n", info->GetName(), Teams[team].GetName ());
|
||||
else
|
||||
Printf ("%s is now a loner\n", info->netname);
|
||||
Printf ("%s is now a loner\n", info->GetName());
|
||||
}
|
||||
// Let the player take on the team's color
|
||||
R_BuildPlayerTranslation (pnum);
|
||||
|
@ -348,25 +333,28 @@ static void UpdateTeam (int pnum, int team, bool update)
|
|||
{
|
||||
StatusBar->AttachToPlayer (&players[pnum]);
|
||||
}
|
||||
if (!TeamLibrary.IsValidTeam (info->team))
|
||||
info->team = TEAM_NONE;
|
||||
// Double-check
|
||||
if (!TeamLibrary.IsValidTeam (team))
|
||||
{
|
||||
*static_cast<FIntCVar *>((*info)[NAME_Team]) = TEAM_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
int D_GetFragCount (player_t *player)
|
||||
{
|
||||
if (!teamplay || !TeamLibrary.IsValidTeam (player->userinfo.team))
|
||||
const int team = player->userinfo.GetTeam();
|
||||
if (!teamplay || !TeamLibrary.IsValidTeam(team))
|
||||
{
|
||||
return player->fragcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count total frags for this player's team
|
||||
const int team = player->userinfo.team;
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].userinfo.team == team)
|
||||
if (playeringame[i] && players[i].userinfo.GetTeam() == team)
|
||||
{
|
||||
count += players[i].fragcount;
|
||||
}
|
||||
|
@ -378,37 +366,146 @@ int D_GetFragCount (player_t *player)
|
|||
void D_SetupUserInfo ()
|
||||
{
|
||||
int i;
|
||||
userinfo_t *coninfo = &players[consoleplayer].userinfo;
|
||||
userinfo_t *coninfo;
|
||||
|
||||
// Reset everybody's userinfo to a default state.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
memset (&players[i].userinfo, 0, sizeof(userinfo_t));
|
||||
{
|
||||
players[i].userinfo.Reset();
|
||||
}
|
||||
// Initialize the console player's user info
|
||||
coninfo = &players[consoleplayer].userinfo;
|
||||
|
||||
strncpy (coninfo->netname, name, MAXPLAYERNAME);
|
||||
if (teamplay && !TeamLibrary.IsValidTeam (team))
|
||||
for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext())
|
||||
{
|
||||
coninfo->team = D_PickRandomTeam ();
|
||||
if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO)
|
||||
{
|
||||
FBaseCVar **newcvar;
|
||||
FName cvarname(cvar->GetName());
|
||||
|
||||
switch (cvarname.GetIndex())
|
||||
{
|
||||
// Some cvars don't copy their original value directly.
|
||||
case NAME_Team: coninfo->TeamChanged(team); break;
|
||||
case NAME_Skin: coninfo->SkinChanged(skin); break;
|
||||
case NAME_Gender: coninfo->GenderChanged(gender); break;
|
||||
case NAME_PlayerClass: coninfo->PlayerClassChanged(playerclass); break;
|
||||
// The rest do.
|
||||
default:
|
||||
newcvar = coninfo->CheckKey(cvarname);
|
||||
(*newcvar)->SetGenericRep(cvar->GetGenericRep(CVAR_String), CVAR_String);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
R_BuildPlayerTranslation(consoleplayer);
|
||||
}
|
||||
|
||||
void userinfo_t::Reset()
|
||||
{
|
||||
// Clear this player's userinfo.
|
||||
TMapIterator<FName, FBaseCVar *> it(*this);
|
||||
TMap<FName, FBaseCVar *>::Pair *pair;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
coninfo->team = team;
|
||||
delete pair->Value;
|
||||
}
|
||||
if (autoaim > 35.f || autoaim < 0.f)
|
||||
Clear();
|
||||
|
||||
// Create userinfo vars for this player, initialized to their defaults.
|
||||
for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext())
|
||||
{
|
||||
coninfo->aimdist = ANGLE_1*35;
|
||||
if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO)
|
||||
{
|
||||
ECVarType type;
|
||||
FName cvarname(cvar->GetName());
|
||||
FBaseCVar *newcvar;
|
||||
|
||||
// Some cvars have different types for their shadow copies.
|
||||
switch (cvarname.GetIndex())
|
||||
{
|
||||
case NAME_Skin: type = CVAR_Int; break;
|
||||
case NAME_Gender: type = CVAR_Int; break;
|
||||
case NAME_PlayerClass: type = CVAR_Int; break;
|
||||
default: type = cvar->GetRealType(); break;
|
||||
}
|
||||
newcvar = C_CreateCVar(NULL, type, cvar->GetFlags() & CVAR_MOD);
|
||||
newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String);
|
||||
Insert(cvarname, newcvar);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1));
|
||||
}
|
||||
|
||||
int userinfo_t::TeamChanged(int team)
|
||||
{
|
||||
if (teamplay && !TeamLibrary.IsValidTeam(team))
|
||||
{ // Force players onto teams in teamplay mode
|
||||
team = D_PickRandomTeam();
|
||||
}
|
||||
coninfo->color = color;
|
||||
coninfo->colorset = colorset;
|
||||
coninfo->skin = R_FindSkin (skin, 0);
|
||||
coninfo->gender = D_GenderToInt (gender);
|
||||
coninfo->neverswitch = neverswitchonpickup;
|
||||
coninfo->MoveBob = (fixed_t)(65536.f * movebob);
|
||||
coninfo->StillBob = (fixed_t)(65536.f * stillbob);
|
||||
coninfo->PlayerClass = D_PlayerClassToInt (playerclass);
|
||||
R_BuildPlayerTranslation (consoleplayer);
|
||||
*static_cast<FIntCVar *>((*this)[NAME_Team]) = team;
|
||||
return team;
|
||||
}
|
||||
|
||||
int userinfo_t::SkinChanged(const char *skinname)
|
||||
{
|
||||
int skinnum = R_FindSkin(skinname, 0);
|
||||
*static_cast<FIntCVar *>((*this)[NAME_Skin]) = skinnum;
|
||||
return skinnum;
|
||||
}
|
||||
|
||||
int userinfo_t::SkinNumChanged(int skinnum)
|
||||
{
|
||||
*static_cast<FIntCVar *>((*this)[NAME_Skin]) = skinnum;
|
||||
return skinnum;
|
||||
}
|
||||
|
||||
int userinfo_t::GenderChanged(const char *gendername)
|
||||
{
|
||||
int gendernum = D_GenderToInt(gendername);
|
||||
*static_cast<FIntCVar *>((*this)[NAME_Gender]) = gendernum;
|
||||
return gendernum;
|
||||
}
|
||||
|
||||
int userinfo_t::PlayerClassChanged(const char *classname)
|
||||
{
|
||||
int classnum = D_PlayerClassToInt(classname);
|
||||
*static_cast<FIntCVar *>((*this)[NAME_PlayerClass]) = classnum;
|
||||
return classnum;
|
||||
}
|
||||
|
||||
int userinfo_t::PlayerClassNumChanged(int classnum)
|
||||
{
|
||||
*static_cast<FIntCVar *>((*this)[NAME_PlayerClass]) = classnum;
|
||||
return classnum;
|
||||
}
|
||||
|
||||
int userinfo_t::ColorSetChanged(int setnum)
|
||||
{
|
||||
*static_cast<FIntCVar *>((*this)[NAME_ColorSet]) = setnum;
|
||||
return setnum;
|
||||
}
|
||||
|
||||
uint32 userinfo_t::ColorChanged(const char *colorname)
|
||||
{
|
||||
FColorCVar *color = static_cast<FColorCVar *>((*this)[NAME_Color]);
|
||||
assert(color != NULL);
|
||||
UCVarValue val;
|
||||
val.String = const_cast<char *>(colorname);
|
||||
color->SetGenericRep(val, CVAR_String);
|
||||
*static_cast<FIntCVar *>((*this)[NAME_ColorSet]) = -1;
|
||||
return *color;
|
||||
}
|
||||
|
||||
uint32 userinfo_t::ColorChanged(uint32 colorval)
|
||||
{
|
||||
FColorCVar *color = static_cast<FColorCVar *>((*this)[NAME_Color]);
|
||||
assert(color != NULL);
|
||||
UCVarValue val;
|
||||
val.Int = colorval;
|
||||
color->SetGenericRep(val, CVAR_Int);
|
||||
// This version is called by the menu code. Do not implicitly set colorset.
|
||||
return colorval;
|
||||
}
|
||||
|
||||
void D_UserInfoChanged (FBaseCVar *cvar)
|
||||
|
@ -500,7 +597,7 @@ static const char *SetServerVar (char *name, ECVarType type, BYTE **stream, bool
|
|||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
UpdateTeam (i, players[i].userinfo.team, true);
|
||||
UpdateTeam (i, players[i].userinfo.GetTeam(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -569,113 +666,131 @@ void D_DoServerInfoChange (BYTE **stream, bool singlebit)
|
|||
}
|
||||
}
|
||||
|
||||
void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
|
||||
static int STACK_ARGS userinfosortfunc(const void *a, const void *b)
|
||||
{
|
||||
if (i >= MAXPLAYERS)
|
||||
{
|
||||
WriteByte (0, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
userinfo_t *info = &players[i].userinfo;
|
||||
|
||||
const PClass *type = PlayerClasses[info->PlayerClass].Type;
|
||||
|
||||
if (!compact)
|
||||
{
|
||||
sprintf (*((char **)stream),
|
||||
"\\name\\%s"
|
||||
"\\autoaim\\%g"
|
||||
"\\color\\%x %x %x"
|
||||
"\\colorset\\%d"
|
||||
"\\skin\\%s"
|
||||
"\\team\\%d"
|
||||
"\\gender\\%s"
|
||||
"\\neverswitchonpickup\\%d"
|
||||
"\\movebob\\%g"
|
||||
"\\stillbob\\%g"
|
||||
"\\playerclass\\%s"
|
||||
,
|
||||
D_EscapeUserInfo(info->netname).GetChars(),
|
||||
(double)info->aimdist / (float)ANGLE_1,
|
||||
info->colorset,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
D_EscapeUserInfo(skins[info->skin].name).GetChars(),
|
||||
info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
info->gender == GENDER_NEUTER ? "other" : "male",
|
||||
info->neverswitch,
|
||||
(float)(info->MoveBob) / 65536.f,
|
||||
(float)(info->StillBob) / 65536.f,
|
||||
info->PlayerClass == -1 ? "Random" :
|
||||
D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (*((char **)stream),
|
||||
"\\"
|
||||
"\\%s" // name
|
||||
"\\%g" // autoaim
|
||||
"\\%x %x %x" // color
|
||||
"\\%s" // skin
|
||||
"\\%d" // team
|
||||
"\\%s" // gender
|
||||
"\\%d" // neverswitchonpickup
|
||||
"\\%g" // movebob
|
||||
"\\%g" // stillbob
|
||||
"\\%s" // playerclass
|
||||
"\\%d" // colorset
|
||||
,
|
||||
D_EscapeUserInfo(info->netname).GetChars(),
|
||||
(double)info->aimdist / (float)ANGLE_1,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
D_EscapeUserInfo(skins[info->skin].name).GetChars(),
|
||||
info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
info->gender == GENDER_NEUTER ? "other" : "male",
|
||||
info->neverswitch,
|
||||
(float)(info->MoveBob) / 65536.f,
|
||||
(float)(info->StillBob) / 65536.f,
|
||||
info->PlayerClass == -1 ? "Random" :
|
||||
D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars(),
|
||||
info->colorset
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*stream += strlen (*((char **)stream)) + 1;
|
||||
TMap<FName, FBaseCVar *>::ConstPair *pair1 = *(TMap<FName, FBaseCVar *>::ConstPair **)a;
|
||||
TMap<FName, FBaseCVar *>::ConstPair *pair2 = *(TMap<FName, FBaseCVar *>::ConstPair **)b;
|
||||
return stricmp(pair1->Key.GetChars(), pair2->Key.GetChars());
|
||||
}
|
||||
|
||||
void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
|
||||
static int STACK_ARGS namesortfunc(const void *a, const void *b)
|
||||
{
|
||||
userinfo_t *info = &players[i].userinfo;
|
||||
FName *name1 = (FName *)a;
|
||||
FName *name2 = (FName *)b;
|
||||
return stricmp(name1->GetChars(), name2->GetChars());
|
||||
}
|
||||
|
||||
void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact)
|
||||
{
|
||||
if (pnum >= MAXPLAYERS)
|
||||
{
|
||||
WriteByte (0, stream);
|
||||
return;
|
||||
}
|
||||
|
||||
userinfo_t *info = &players[pnum].userinfo;
|
||||
TArray<TMap<FName, FBaseCVar *>::Pair *> userinfo_pairs(info->CountUsed());
|
||||
TMap<FName, FBaseCVar *>::Iterator it(*info);
|
||||
TMap<FName, FBaseCVar *>::Pair *pair;
|
||||
UCVarValue cval;
|
||||
|
||||
// Create a simple array of all userinfo cvars
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
userinfo_pairs.Push(pair);
|
||||
}
|
||||
// For compact mode, these need to be sorted. Verbose mode doesn't matter.
|
||||
if (compact)
|
||||
{
|
||||
qsort(&userinfo_pairs[0], userinfo_pairs.Size(), sizeof(pair), userinfosortfunc);
|
||||
// Compact mode is signified by starting the string with two backslash characters.
|
||||
// We output one now. The second will be output as part of the first value.
|
||||
*(*stream)++ = '\\';
|
||||
}
|
||||
for (unsigned int i = 0; i < userinfo_pairs.Size(); ++i)
|
||||
{
|
||||
pair = userinfo_pairs[i];
|
||||
|
||||
if (!compact)
|
||||
{ // In verbose mode, prepend the cvar's name
|
||||
*stream += sprintf(*((char **)stream), "\\%s\\", pair->Key.GetChars());
|
||||
}
|
||||
// A few of these need special handling for compatibility reasons.
|
||||
switch (pair->Key.GetIndex())
|
||||
{
|
||||
case NAME_Gender:
|
||||
*stream += sprintf(*((char **)stream), "\\%s",
|
||||
*static_cast<FIntCVar *>(pair->Value) == GENDER_FEMALE ? "female" :
|
||||
*static_cast<FIntCVar *>(pair->Value) == GENDER_NEUTER ? "other" : "male");
|
||||
break;
|
||||
|
||||
case NAME_PlayerClass:
|
||||
*stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" :
|
||||
D_EscapeUserInfo(info->GetPlayerClassType()->Meta.GetMetaString(APMETA_DisplayName)).GetChars());
|
||||
break;
|
||||
|
||||
case NAME_Skin:
|
||||
*stream += sprintf(*((char **)stream), "\\%s", D_EscapeUserInfo(skins[info->GetSkin()].name).GetChars());
|
||||
break;
|
||||
|
||||
default:
|
||||
cval = pair->Value->GetGenericRep(CVAR_String);
|
||||
*stream += sprintf(*((char **)stream), "\\%s", cval.String);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(*stream)++ = '\0';
|
||||
}
|
||||
|
||||
void D_ReadUserInfoStrings (int pnum, BYTE **stream, bool update)
|
||||
{
|
||||
userinfo_t *info = &players[pnum].userinfo;
|
||||
TArray<FName> compact_names(info->CountUsed());
|
||||
FBaseCVar **cvar_ptr;
|
||||
const char *ptr = *((const char **)stream);
|
||||
const char *breakpt;
|
||||
FString value;
|
||||
bool compact;
|
||||
int infotype = -1;
|
||||
FName keyname;
|
||||
unsigned int infotype = 0;
|
||||
|
||||
if (*ptr++ != '\\')
|
||||
return;
|
||||
|
||||
compact = (*ptr == '\\') ? ptr++, true : false;
|
||||
|
||||
if (i < MAXPLAYERS)
|
||||
// We need the cvar names in sorted order for compact mode
|
||||
if (compact)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int j;
|
||||
TMap<FName, FBaseCVar *>::Iterator it(*info);
|
||||
TMap<FName, FBaseCVar *>::Pair *pair;
|
||||
|
||||
breakpt = strchr (ptr, '\\');
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
compact_names.Push(pair->Key);
|
||||
}
|
||||
qsort(&compact_names[0], compact_names.Size(), sizeof(FName), namesortfunc);
|
||||
}
|
||||
|
||||
if (pnum < MAXPLAYERS)
|
||||
{
|
||||
for (breakpt = ptr; breakpt != NULL; ptr = breakpt + 1)
|
||||
{
|
||||
breakpt = strchr(ptr, '\\');
|
||||
|
||||
if (compact)
|
||||
{
|
||||
// Compact has just the value.
|
||||
if (infotype >= compact_names.Size())
|
||||
{ // Too many entries! OMG!
|
||||
break;
|
||||
}
|
||||
keyname = compact_names[infotype++];
|
||||
value = D_UnescapeUserInfo(ptr, breakpt != NULL ? breakpt - ptr : strlen(ptr));
|
||||
infotype++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Verbose has both the key name and its value.
|
||||
assert(breakpt != NULL);
|
||||
// A malicious remote machine could invalidate the above assert.
|
||||
if (breakpt == NULL)
|
||||
|
@ -691,154 +806,187 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
|
|||
{
|
||||
value = D_UnescapeUserInfo(valstart, strlen(valstart));
|
||||
}
|
||||
|
||||
for (j = 0;
|
||||
UserInfoStrings[j] && strnicmp (UserInfoStrings[j], ptr, valstart - ptr - 1) != 0;
|
||||
++j)
|
||||
{ }
|
||||
if (UserInfoStrings[j] == NULL)
|
||||
{
|
||||
infotype = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
infotype = j;
|
||||
}
|
||||
keyname = FName(ptr, valstart - ptr - 1, true);
|
||||
}
|
||||
switch (infotype)
|
||||
|
||||
// A few of these need special handling.
|
||||
switch (keyname)
|
||||
{
|
||||
case INFO_Autoaim: {
|
||||
double angles;
|
||||
|
||||
angles = atof (value);
|
||||
if (angles > 35.f || angles < 0.f)
|
||||
{
|
||||
info->aimdist = ANGLE_1*35;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->aimdist = abs ((int)(angles * (float)ANGLE_1));
|
||||
}
|
||||
}
|
||||
case NAME_Gender:
|
||||
info->GenderChanged(value);
|
||||
break;
|
||||
|
||||
case INFO_Name:
|
||||
{
|
||||
char oldname[MAXPLAYERNAME+1];
|
||||
|
||||
strcpy (oldname, info->netname);
|
||||
strncpy (info->netname, value, MAXPLAYERNAME);
|
||||
info->netname[MAXPLAYERNAME] = 0;
|
||||
CleanseString(info->netname);
|
||||
|
||||
if (update && strcmp (oldname, info->netname) != 0)
|
||||
{
|
||||
Printf ("%s is now known as %s\n", oldname, info->netname);
|
||||
}
|
||||
}
|
||||
case NAME_PlayerClass:
|
||||
info->PlayerClassChanged(value);
|
||||
break;
|
||||
|
||||
case INFO_Team:
|
||||
UpdateTeam (i, atoi(value), update);
|
||||
break;
|
||||
|
||||
case INFO_Color:
|
||||
case INFO_ColorSet:
|
||||
if (infotype == INFO_Color)
|
||||
case NAME_Skin:
|
||||
info->SkinChanged(value);
|
||||
if (players[pnum].mo != NULL)
|
||||
{
|
||||
info->color = V_GetColorFromString (NULL, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->colorset = atoi(value);
|
||||
}
|
||||
R_BuildPlayerTranslation (i);
|
||||
if (StatusBar != NULL && i == StatusBar->GetPlayer())
|
||||
{
|
||||
StatusBar->AttachToPlayer (&players[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case INFO_Skin:
|
||||
info->skin = R_FindSkin (value, players[i].CurrentPlayerClass);
|
||||
if (players[i].mo != NULL)
|
||||
{
|
||||
if (players[i].cls != NULL &&
|
||||
players[i].mo->state->sprite ==
|
||||
GetDefaultByType (players[i].cls)->SpawnState->sprite)
|
||||
if (players[pnum].cls != NULL &&
|
||||
!(players[pnum].mo->flags4 & MF4_NOSKIN) &&
|
||||
players[pnum].mo->state->sprite ==
|
||||
GetDefaultByType (players[pnum].cls)->SpawnState->sprite)
|
||||
{ // Only change the sprite if the player is using a standard one
|
||||
players[i].mo->sprite = skins[info->skin].sprite;
|
||||
players[i].mo->scaleX = skins[info->skin].ScaleX;
|
||||
players[i].mo->scaleY = skins[info->skin].ScaleY;
|
||||
players[pnum].mo->sprite = skins[info->GetSkin()].sprite;
|
||||
}
|
||||
}
|
||||
// Rebuild translation in case the new skin uses a different range
|
||||
// than the old one.
|
||||
R_BuildPlayerTranslation (i);
|
||||
R_BuildPlayerTranslation(pnum);
|
||||
break;
|
||||
|
||||
case INFO_Gender:
|
||||
info->gender = D_GenderToInt (value);
|
||||
case NAME_Team:
|
||||
UpdateTeam(pnum, atoi(value), update);
|
||||
break;
|
||||
|
||||
case INFO_NeverSwitchOnPickup:
|
||||
if (value[0] >= '0' && value[0] <= '9')
|
||||
{
|
||||
info->neverswitch = atoi (value) ? true : false;
|
||||
}
|
||||
else if (stricmp (value, "true") == 0)
|
||||
{
|
||||
info->neverswitch = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->neverswitch = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case INFO_MoveBob:
|
||||
info->MoveBob = (fixed_t)(atof (value) * 65536.f);
|
||||
break;
|
||||
|
||||
case INFO_StillBob:
|
||||
info->StillBob = (fixed_t)(atof (value) * 65536.f);
|
||||
break;
|
||||
|
||||
case INFO_PlayerClass:
|
||||
info->PlayerClass = D_PlayerClassToInt (value);
|
||||
case NAME_Color:
|
||||
info->ColorChanged(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
cvar_ptr = info->CheckKey(keyname);
|
||||
if (cvar_ptr != NULL)
|
||||
{
|
||||
assert(*cvar_ptr != NULL);
|
||||
UCVarValue val;
|
||||
FString oldname;
|
||||
|
||||
if (keyname == NAME_Name)
|
||||
{
|
||||
val = (*cvar_ptr)->GetGenericRep(CVAR_String);
|
||||
oldname = val.String;
|
||||
}
|
||||
val.String = CleanseString(value.LockBuffer());
|
||||
(*cvar_ptr)->SetGenericRep(val, CVAR_String);
|
||||
value.UnlockBuffer();
|
||||
if (keyname == NAME_Name && update && oldname != value)
|
||||
{
|
||||
Printf("%s is now known as %s\n", oldname.GetChars(), value.GetChars());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (breakpt)
|
||||
if (keyname == NAME_Color || keyname == NAME_ColorSet)
|
||||
{
|
||||
ptr = breakpt + 1;
|
||||
R_BuildPlayerTranslation(pnum);
|
||||
if (StatusBar != NULL && pnum == StatusBar->GetPlayer())
|
||||
{
|
||||
StatusBar->AttachToPlayer(&players[pnum]);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
*stream += strlen (*((char **)stream)) + 1;
|
||||
}
|
||||
|
||||
void ReadCompatibleUserInfo(FArchive &arc, userinfo_t &info)
|
||||
{
|
||||
char netname[MAXPLAYERNAME + 1];
|
||||
BYTE team;
|
||||
int aimdist, color, colorset, skin, gender;
|
||||
bool neverswitch;
|
||||
//fixed_t movebob, stillbob; These were never serialized!
|
||||
//int playerclass; "
|
||||
|
||||
info.Reset();
|
||||
|
||||
arc.Read(&netname, sizeof(netname));
|
||||
arc << team << aimdist << color << skin << gender << neverswitch << colorset;
|
||||
|
||||
*static_cast<FStringCVar *>(info[NAME_Name]) = netname;
|
||||
*static_cast<FIntCVar *>(info[NAME_Team]) = team;
|
||||
*static_cast<FFloatCVar *>(info[NAME_Autoaim]) = (float)aimdist / ANGLE_1;
|
||||
*static_cast<FIntCVar *>(info[NAME_Skin]) = skin;
|
||||
*static_cast<FIntCVar *>(info[NAME_Gender]) = gender;
|
||||
*static_cast<FBoolCVar *>(info[NAME_NeverSwitchOnPickup]) = neverswitch;
|
||||
*static_cast<FIntCVar *>(info[NAME_ColorSet]) = colorset;
|
||||
|
||||
UCVarValue val;
|
||||
val.Int = color;
|
||||
static_cast<FColorCVar *>(info[NAME_Color])->SetGenericRep(val, CVAR_Int);
|
||||
}
|
||||
|
||||
void WriteUserInfo(FArchive &arc, userinfo_t &info)
|
||||
{
|
||||
TMapIterator<FName, FBaseCVar *> it(info);
|
||||
TMap<FName, FBaseCVar *>::Pair *pair;
|
||||
FName name;
|
||||
UCVarValue val;
|
||||
int i;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
name = pair->Key;
|
||||
arc << name;
|
||||
switch (name.GetIndex())
|
||||
{
|
||||
case NAME_Skin:
|
||||
arc.WriteString(skins[info.GetSkin()].name);
|
||||
break;
|
||||
|
||||
case NAME_PlayerClass:
|
||||
i = info.GetPlayerClassNum();
|
||||
arc.WriteString(i == -1 ? "Random" : PlayerClasses[i].Type->Meta.GetMetaString(APMETA_DisplayName));
|
||||
break;
|
||||
|
||||
default:
|
||||
val = pair->Value->GetGenericRep(CVAR_String);
|
||||
arc.WriteString(val.String);
|
||||
break;
|
||||
}
|
||||
}
|
||||
name = NAME_None;
|
||||
arc << name;
|
||||
}
|
||||
|
||||
void ReadUserInfo(FArchive &arc, userinfo_t &info)
|
||||
{
|
||||
FName name;
|
||||
FBaseCVar **cvar;
|
||||
char *str = NULL;
|
||||
UCVarValue val;
|
||||
|
||||
info.Reset();
|
||||
for (arc << name; name != NAME_None; arc << name)
|
||||
{
|
||||
cvar = info.CheckKey(name);
|
||||
arc << str;
|
||||
if (cvar != NULL && *cvar != NULL)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case NAME_Team: info.TeamChanged(atoi(str)); break;
|
||||
case NAME_Skin: info.SkinChanged(str); break;
|
||||
case NAME_PlayerClass: info.PlayerClassChanged(str); break;
|
||||
default:
|
||||
val.String = str;
|
||||
(*cvar)->SetGenericRep(val, CVAR_String);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*stream += strlen (*((char **)stream)) + 1;
|
||||
if (str != NULL)
|
||||
{
|
||||
delete[] str;
|
||||
}
|
||||
}
|
||||
|
||||
FArchive &operator<< (FArchive &arc, userinfo_t &info)
|
||||
{
|
||||
if (arc.IsStoring ())
|
||||
if (SaveVersion < 4253)
|
||||
{
|
||||
arc.Write (&info.netname, sizeof(info.netname));
|
||||
ReadCompatibleUserInfo(arc, info);
|
||||
}
|
||||
else if (arc.IsStoring())
|
||||
{
|
||||
WriteUserInfo(arc, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
arc.Read (&info.netname, sizeof(info.netname));
|
||||
ReadUserInfo(arc, info);
|
||||
}
|
||||
arc << info.team << info.aimdist << info.color
|
||||
<< info.skin << info.gender << info.neverswitch
|
||||
<< info.colorset;
|
||||
return arc;
|
||||
}
|
||||
|
||||
|
@ -852,27 +1000,51 @@ CCMD (playerinfo)
|
|||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
Printf ("%d. %s\n", i, players[i].userinfo.netname);
|
||||
Printf("%d. %s\n", i, players[i].userinfo.GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = atoi (argv[1]);
|
||||
int i = atoi(argv[1]);
|
||||
|
||||
if (i < 0 || i >= MAXPLAYERS)
|
||||
{
|
||||
Printf("Bad player number\n");
|
||||
return;
|
||||
}
|
||||
userinfo_t *ui = &players[i].userinfo;
|
||||
Printf ("Name: %s\n", ui->netname);
|
||||
Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team);
|
||||
Printf ("Aimdist: %d\n", ui->aimdist);
|
||||
Printf ("Color: %06x\n", ui->color);
|
||||
Printf ("ColorSet: %d\n", ui->colorset);
|
||||
Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin);
|
||||
Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender);
|
||||
Printf ("NeverSwitch: %d\n", ui->neverswitch);
|
||||
Printf ("MoveBob: %g\n", ui->MoveBob/65536.f);
|
||||
Printf ("StillBob: %g\n", ui->StillBob/65536.f);
|
||||
Printf ("PlayerClass: %s (%d)\n",
|
||||
ui->PlayerClass == -1 ? "Random" : PlayerClasses[ui->PlayerClass].Type->Meta.GetMetaString (APMETA_DisplayName),
|
||||
ui->PlayerClass);
|
||||
if (argv.argc() > 2) PrintMiscActorInfo(players[i].mo);
|
||||
|
||||
if (!playeringame[i])
|
||||
{
|
||||
Printf(TEXTCOLOR_ORANGE "Player %d is not in the game\n", i);
|
||||
}
|
||||
|
||||
// Print special info
|
||||
Printf("%20s: %s\n", "Name", ui->GetName());
|
||||
Printf("%20s: %s (%d)\n", "Team", ui->GetTeam() == TEAM_NONE ? "None" : Teams[ui->GetTeam()].GetName(), ui->GetTeam());
|
||||
Printf("%20s: %s (%d)\n", "Skin", skins[ui->GetSkin()].name, ui->GetSkin());
|
||||
Printf("%20s: %s (%d)\n", "Gender", GenderNames[ui->GetGender()], ui->GetGender());
|
||||
Printf("%20s: %s (%d)\n", "PlayerClass",
|
||||
ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->Meta.GetMetaString (APMETA_DisplayName),
|
||||
ui->GetPlayerClassNum());
|
||||
|
||||
// Print generic info
|
||||
TMapIterator<FName, FBaseCVar *> it(*ui);
|
||||
TMap<FName, FBaseCVar *>::Pair *pair;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (pair->Key != NAME_Name && pair->Key != NAME_Team && pair->Key != NAME_Skin &&
|
||||
pair->Key != NAME_Gender && pair->Key != NAME_PlayerClass)
|
||||
{
|
||||
UCVarValue val = pair->Value->GetGenericRep(CVAR_String);
|
||||
Printf("%20s: %s\n", pair->Key.GetChars(), val.String);
|
||||
}
|
||||
}
|
||||
if (argv.argc() > 2)
|
||||
{
|
||||
PrintMiscActorInfo(players[i].mo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
203
src/d_player.h
203
src/d_player.h
|
@ -90,6 +90,7 @@ public:
|
|||
virtual void AddInventory (AInventory *item);
|
||||
virtual void RemoveInventory (AInventory *item);
|
||||
virtual bool UseInventory (AInventory *item);
|
||||
virtual void MarkPrecacheSounds () const;
|
||||
|
||||
virtual void PlayIdle ();
|
||||
virtual void PlayRunning ();
|
||||
|
@ -107,7 +108,7 @@ public:
|
|||
void GiveDefaultInventory ();
|
||||
void PlayAttacking ();
|
||||
void PlayAttacking2 ();
|
||||
const char *GetSoundClass ();
|
||||
const char *GetSoundClass () const;
|
||||
|
||||
enum EInvulState
|
||||
{
|
||||
|
@ -118,7 +119,7 @@ public:
|
|||
};
|
||||
|
||||
void BeginPlay ();
|
||||
void Die (AActor *source, AActor *inflictor);
|
||||
void Die (AActor *source, AActor *inflictor, int dmgflags);
|
||||
|
||||
int crouchsprite;
|
||||
int MaxHealth;
|
||||
|
@ -130,6 +131,8 @@ public:
|
|||
|
||||
// [GRB] Player class properties
|
||||
fixed_t JumpZ;
|
||||
fixed_t GruntSpeed;
|
||||
fixed_t FallingScreamMinSpeed, FallingScreamMaxSpeed;
|
||||
fixed_t ViewHeight;
|
||||
fixed_t ForwardMove1, ForwardMove2;
|
||||
fixed_t SideMove1, SideMove2;
|
||||
|
@ -159,6 +162,8 @@ class APlayerChunk : public APlayerPawn
|
|||
enum
|
||||
{
|
||||
PPF_NOTHRUSTWHENINVUL = 1, // Attacks do not thrust the player if they are invulnerable.
|
||||
PPF_CANSUPERMORPH = 2, // Being remorphed into this class can give you a Tome of Power
|
||||
PPF_CROUCHABLEMORPH = 4, // This morphed player can crouch
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -191,22 +196,29 @@ typedef enum
|
|||
CF_INSTANTWEAPSWITCH= 1 << 11, // [RH] Switch weapons instantly
|
||||
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,
|
||||
CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact
|
||||
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
|
||||
CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact
|
||||
CF_WEAPONBOBBING = 1 << 24, // [HW] Bob weapon while the player is moving
|
||||
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_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
|
||||
} cheat_t;
|
||||
|
||||
enum
|
||||
{
|
||||
WF_WEAPONREADY = 1 << 0, // [RH] Weapon is in the ready state and can fire its primary attack
|
||||
WF_WEAPONBOBBING = 1 << 1, // [HW] Bob weapon while the player is moving
|
||||
WF_WEAPONREADYALT = 1 << 2, // Weapon can fire its secondary attack
|
||||
WF_WEAPONSWITCHOK = 1 << 3, // It is okay to switch away from this weapon
|
||||
WF_DISABLESWITCH = 1 << 4, // Disable weapon switching completely
|
||||
WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon.
|
||||
WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function.
|
||||
WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire
|
||||
};
|
||||
|
||||
#define WPIECE1 1
|
||||
#define WPIECE2 2
|
||||
#define WPIECE3 4
|
||||
|
@ -216,6 +228,29 @@ typedef enum
|
|||
|
||||
#define MAXPLAYERNAME 15
|
||||
|
||||
// [GRB] Custom player classes
|
||||
enum
|
||||
{
|
||||
PCF_NOMENU = 1, // Hide in new game menu
|
||||
};
|
||||
|
||||
class FPlayerClass
|
||||
{
|
||||
public:
|
||||
FPlayerClass ();
|
||||
FPlayerClass (const FPlayerClass &other);
|
||||
~FPlayerClass ();
|
||||
|
||||
bool CheckSkin (int skin);
|
||||
|
||||
const PClass *Type;
|
||||
DWORD Flags;
|
||||
TArray<int> Skins;
|
||||
};
|
||||
|
||||
extern TArray<FPlayerClass> PlayerClasses;
|
||||
|
||||
// User info (per-player copies of each CVAR_USERINFO cvar)
|
||||
enum
|
||||
{
|
||||
GENDER_MALE,
|
||||
|
@ -223,20 +258,80 @@ enum
|
|||
GENDER_NEUTER
|
||||
};
|
||||
|
||||
struct userinfo_t
|
||||
struct userinfo_t : TMap<FName,FBaseCVar *>
|
||||
{
|
||||
char netname[MAXPLAYERNAME+1];
|
||||
BYTE team;
|
||||
int aimdist;
|
||||
int color;
|
||||
int colorset;
|
||||
int skin;
|
||||
int gender;
|
||||
bool neverswitch;
|
||||
fixed_t MoveBob, StillBob;
|
||||
int PlayerClass;
|
||||
int GetAimDist() const
|
||||
{
|
||||
if (dmflags2 & DF2_NOAUTOAIM)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetAimDist() const { return (dmflags2 & DF2_NOAUTOAIM)? 0 : aimdist; }
|
||||
float aim = *static_cast<FFloatCVar *>(*CheckKey(NAME_Autoaim));
|
||||
if (aim > 35 || aim < 0)
|
||||
{
|
||||
return ANGLE_1*35;
|
||||
}
|
||||
else
|
||||
{
|
||||
return xs_RoundToInt(fabs(aim * ANGLE_1));
|
||||
}
|
||||
}
|
||||
const char *GetName() const
|
||||
{
|
||||
return *static_cast<FStringCVar *>(*CheckKey(NAME_Name));
|
||||
}
|
||||
int GetTeam() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_Team));
|
||||
}
|
||||
int GetColorSet() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_ColorSet));
|
||||
}
|
||||
uint32 GetColor() const
|
||||
{
|
||||
return *static_cast<FColorCVar *>(*CheckKey(NAME_Color));
|
||||
}
|
||||
bool GetNeverSwitch() const
|
||||
{
|
||||
return *static_cast<FBoolCVar *>(*CheckKey(NAME_NeverSwitchOnPickup));
|
||||
}
|
||||
fixed_t GetMoveBob() const
|
||||
{
|
||||
return FLOAT2FIXED(*static_cast<FFloatCVar *>(*CheckKey(NAME_MoveBob)));
|
||||
}
|
||||
fixed_t GetStillBob() const
|
||||
{
|
||||
return FLOAT2FIXED(*static_cast<FFloatCVar *>(*CheckKey(NAME_StillBob)));
|
||||
}
|
||||
int GetPlayerClassNum() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
|
||||
}
|
||||
const PClass *GetPlayerClassType() const
|
||||
{
|
||||
return PlayerClasses[GetPlayerClassNum()].Type;
|
||||
}
|
||||
int GetSkin() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_Skin));
|
||||
}
|
||||
int GetGender() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_Gender));
|
||||
}
|
||||
|
||||
void Reset();
|
||||
int TeamChanged(int team);
|
||||
int SkinChanged(const char *skinname);
|
||||
int SkinNumChanged(int skinnum);
|
||||
int GenderChanged(const char *gendername);
|
||||
int PlayerClassChanged(const char *classname);
|
||||
int PlayerClassNumChanged(int classnum);
|
||||
uint32 ColorChanged(const char *colorname);
|
||||
uint32 ColorChanged(uint32 colorval);
|
||||
int ColorSetChanged(int setnum);
|
||||
};
|
||||
|
||||
FArchive &operator<< (FArchive &arc, userinfo_t &info);
|
||||
|
@ -256,6 +351,7 @@ public:
|
|||
|
||||
void SetLogNumber (int num);
|
||||
void SetLogText (const char *text);
|
||||
void SendPitchLimits() const;
|
||||
|
||||
APlayerPawn *mo;
|
||||
BYTE playerstate;
|
||||
|
@ -282,6 +378,8 @@ public:
|
|||
|
||||
bool centering;
|
||||
BYTE turnticks;
|
||||
|
||||
|
||||
bool attackdown;
|
||||
bool usedown;
|
||||
DWORD oldbuttons;
|
||||
|
@ -297,17 +395,22 @@ public:
|
|||
int lastkilltime; // [RH] For multikills
|
||||
BYTE multicount;
|
||||
BYTE spreecount; // [RH] Keep track of killing sprees
|
||||
BYTE WeaponState;
|
||||
|
||||
AWeapon *ReadyWeapon;
|
||||
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;
|
||||
bool waiting;
|
||||
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
|
||||
|
@ -327,8 +430,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:
|
||||
|
@ -342,9 +443,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.
|
||||
|
||||
|
@ -380,6 +481,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;
|
||||
|
@ -406,6 +510,11 @@ public:
|
|||
crouching = 0;
|
||||
crouchviewdelta = 0;
|
||||
}
|
||||
|
||||
bool CanCrouch() const
|
||||
{
|
||||
return morphTics == 0 || mo->PlayerFlags & PPF_CROUCHABLEMORPH;
|
||||
}
|
||||
|
||||
int GetSpawnClass();
|
||||
};
|
||||
|
@ -415,31 +524,31 @@ extern player_t players[MAXPLAYERS];
|
|||
|
||||
FArchive &operator<< (FArchive &arc, player_t *&p);
|
||||
|
||||
void P_CheckPlayerSprites();
|
||||
void P_CheckPlayerSprite(AActor *mo, int &spritenum, fixed_t &scalex, fixed_t &scaley);
|
||||
|
||||
inline void AActor::SetFriendPlayer(player_t *player)
|
||||
{
|
||||
if (player == NULL)
|
||||
{
|
||||
FriendPlayer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FriendPlayer = int(player - players) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool AActor::IsNoClip2() const
|
||||
{
|
||||
if (player != NULL && player->mo == this)
|
||||
{
|
||||
return (player->cheats & CF_NOCLIP2) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CROUCHSPEED (FRACUNIT/12)
|
||||
|
||||
// [GRB] Custom player classes
|
||||
enum
|
||||
{
|
||||
PCF_NOMENU = 1, // Hide in new game menu
|
||||
};
|
||||
|
||||
class FPlayerClass
|
||||
{
|
||||
public:
|
||||
FPlayerClass ();
|
||||
FPlayerClass (const FPlayerClass &other);
|
||||
~FPlayerClass ();
|
||||
|
||||
bool CheckSkin (int skin);
|
||||
|
||||
const PClass *Type;
|
||||
DWORD Flags;
|
||||
TArray<int> Skins;
|
||||
};
|
||||
|
||||
extern TArray<FPlayerClass> PlayerClasses;
|
||||
bool P_IsPlayerTotallyFrozen(const player_t *player);
|
||||
|
||||
#endif // __D_PLAYER_H__
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -159,6 +159,11 @@ enum EDemoCommand
|
|||
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
|
||||
|
@ -213,7 +218,8 @@ enum ECheatCommand
|
|||
CHT_GIMMIEI,
|
||||
CHT_GIMMIEJ,
|
||||
CHT_GIMMIEZ,
|
||||
CHT_BUDDHA
|
||||
CHT_BUDDHA,
|
||||
CHT_NOCLIP2
|
||||
};
|
||||
|
||||
void StartChunk (int id, BYTE **stream);
|
||||
|
|
|
@ -631,7 +631,10 @@ void FDecalLib::ParseGenerator (FScanner &sc)
|
|||
}
|
||||
|
||||
actor->DecalGenerator = decal;
|
||||
decal->Users.Push (type);
|
||||
if (decal != NULL)
|
||||
{
|
||||
decal->Users.Push (type);
|
||||
}
|
||||
}
|
||||
|
||||
void FDecalLib::ParseFader (FScanner &sc)
|
||||
|
@ -1121,16 +1124,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)
|
||||
|
|
|
@ -453,8 +453,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)
|
||||
|
|
|
@ -242,8 +242,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(!curr->IsKindOf(RUNTIME_CLASS(DThinker)) || (curr->ObjectFlags & OF_Sentinel));
|
||||
assert(!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;
|
||||
|
@ -305,6 +307,7 @@ static void MarkRoot()
|
|||
DThinker::MarkRoots();
|
||||
FCanvasTextureInfo::Mark();
|
||||
Mark(DACSThinker::ActiveThinker);
|
||||
Mark(level.DefaultSkybox);
|
||||
// Mark dead bodies.
|
||||
for (i = 0; i < BODYQUESIZE; ++i)
|
||||
{
|
||||
|
@ -531,7 +534,12 @@ void Barrier(DObject *pointing, DObject *pointed)
|
|||
|
||||
void DelSoftRootHead()
|
||||
{
|
||||
if (SoftRoots != NULL) delete SoftRoots;
|
||||
if (SoftRoots != NULL)
|
||||
{
|
||||
// Don't let the destructor print a warning message
|
||||
SoftRoots->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete SoftRoots;
|
||||
}
|
||||
SoftRoots = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -357,8 +357,8 @@ unsigned int PClass::Extend(unsigned int extension)
|
|||
}
|
||||
|
||||
// Like FindClass but creates a placeholder if no class
|
||||
// is found. CreateDerivedClass will automatcally fill in
|
||||
// the placeholder when the actual class is defined.
|
||||
// is found. CreateDerivedClass will automatically fill
|
||||
// in the placeholder when the actual class is defined.
|
||||
const PClass *PClass::FindClassTentative (FName name)
|
||||
{
|
||||
if (name == NAME_None)
|
||||
|
|
|
@ -400,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__
|
||||
|
|
|
@ -333,7 +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
|
||||
COMPATF_MASKEDMIDTEX = 1u << 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
|
||||
|
@ -345,6 +348,7 @@ enum
|
|||
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
|
||||
BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild
|
||||
};
|
||||
|
||||
// phares 3/20/98:
|
||||
|
|
|
@ -230,6 +230,7 @@ struct DehInfo
|
|||
BYTE ExplosionStyle;
|
||||
fixed_t ExplosionAlpha;
|
||||
int NoAutofreeze;
|
||||
int BFGCells;
|
||||
};
|
||||
extern DehInfo deh;
|
||||
EXTERN_CVAR (Int, infighting)
|
||||
|
@ -240,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
|
||||
|
|
|
@ -223,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;
|
||||
}
|
||||
|
@ -292,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;
|
||||
}
|
||||
|
|
|
@ -192,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;
|
||||
|
@ -457,7 +448,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
|
|||
NextToThink = node->NextThinker;
|
||||
if (node->ObjectFlags & OF_JustSpawned)
|
||||
{
|
||||
node->ObjectFlags &= ~OF_JustSpawned;
|
||||
// Leave OF_JustSpawn set until after Tick() so the ticker can check it.
|
||||
if (dest != NULL)
|
||||
{ // Move thinker from this list to the destination list
|
||||
node->Remove();
|
||||
|
@ -472,7 +463,8 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
|
|||
|
||||
if (!(node->ObjectFlags & OF_EuthanizeMe))
|
||||
{ // Only tick thinkers not scheduled for destruction
|
||||
node->Tick ();
|
||||
node->Tick();
|
||||
node->ObjectFlags &= ~OF_JustSpawned;
|
||||
GC::CheckGC();
|
||||
}
|
||||
node = NextToThink;
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "c_cvars.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_player.h"
|
||||
#include "m_misc.h"
|
||||
#include "dobject.h"
|
||||
|
||||
// These are special tokens found in the data stream of an archive.
|
||||
|
@ -405,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
|
||||
|
@ -497,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;
|
||||
}
|
||||
|
@ -560,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)
|
||||
{
|
||||
|
|
|
@ -124,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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -774,7 +774,7 @@ void FParser::SF_PlayerName(void)
|
|||
if(plnum !=-1)
|
||||
{
|
||||
t_return.type = svt_string;
|
||||
t_return.string = players[plnum].userinfo.netname;
|
||||
t_return.string = players[plnum].userinfo.GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3367,7 +3367,7 @@ void FParser::SF_RadiusAttack()
|
|||
|
||||
if (spot && source)
|
||||
{
|
||||
P_RadiusAttack(spot, source, damage, damage, NAME_None, true);
|
||||
P_RadiusAttack(spot, source, damage, damage, NAME_None, RADF_HURTSOURCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3747,7 +3747,7 @@ void FParser::SF_LineAttack()
|
|||
angle = (intvalue(t_argv[1]) * (ANG45 / 45));
|
||||
slope = P_AimLineAttack(mo, angle, MISSILERANGE);
|
||||
|
||||
P_LineAttack(mo, angle, MISSILERANGE, slope, damage, NAME_None, NAME_BulletPuff);
|
||||
P_LineAttack(mo, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4256,7 +4256,7 @@ void FParser::SF_SpawnShot2(void)
|
|||
S_Sound (mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM);
|
||||
mo->target = source;
|
||||
P_ThrustMobj(mo, mo->angle = source->angle, mo->Speed);
|
||||
if (!P_CheckMissileSpawn(mo)) mo = NULL;
|
||||
if (!P_CheckMissileSpawn(mo, source->radius)) mo = NULL;
|
||||
}
|
||||
t_return.value.mobj = mo;
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ bool FScriptLoader::ParseInfo(MapData * map)
|
|||
}
|
||||
|
||||
|
||||
delete lump;
|
||||
delete[] lump;
|
||||
return HasScripts;
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ void T_LoadScripts(MapData *map)
|
|||
// the default translator is being used.
|
||||
// Custom translators will not be patched.
|
||||
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() &&
|
||||
level.maptype == MAPTYPE_DOOM && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
|
||||
level.maptype == MAPTYPE_DOOM && SimpleLineTranslations.Size() > 272 && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
|
||||
{
|
||||
FLineTrans t = SimpleLineTranslations[270];
|
||||
SimpleLineTranslations[270] = SimpleLineTranslations[272];
|
||||
|
|
|
@ -123,8 +123,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack)
|
|||
return;
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM);
|
||||
P_TraceBleed (dmg, target);
|
||||
P_DamageMobj (target, self, self, dmg, NAME_None);
|
||||
int newdam = P_DamageMobj (target, self, self, dmg, NAME_None);
|
||||
P_TraceBleed (newdam > 0 ? newdam : dmg, target);
|
||||
|
||||
an = self->angle >> ANGLETOFINESHIFT;
|
||||
fire = self->tracer;
|
||||
|
@ -136,7 +136,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack)
|
|||
target->y - FixedMul (24*FRACUNIT, finesine[an]),
|
||||
target->z);
|
||||
|
||||
P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, false);
|
||||
P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0);
|
||||
}
|
||||
target->velz = Scale(thrust, 1000, target->Mass);
|
||||
}
|
||||
|
|
|
@ -79,16 +79,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainDie)
|
|||
// New dmflag: Kill all boss spawned monsters before ending the level.
|
||||
if (dmflags2 & DF2_KILLBOSSMONST)
|
||||
{
|
||||
TThinkerIterator<AActor> it;
|
||||
AActor *mo;
|
||||
while ((mo = it.Next()))
|
||||
int count; // Repeat until we have no more boss-spawned monsters.
|
||||
do // (e.g. Pain Elementals can spawn more to kill upon death.)
|
||||
{
|
||||
if (mo->flags4 & MF4_BOSSSPAWNED)
|
||||
TThinkerIterator<AActor> it;
|
||||
AActor *mo;
|
||||
count = 0;
|
||||
while ((mo = it.Next()))
|
||||
{
|
||||
P_DamageMobj(mo, self, self, mo->health, NAME_None,
|
||||
DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR);
|
||||
if (mo->health > 0 && mo->flags4 & MF4_BOSSSPAWNED)
|
||||
{
|
||||
P_DamageMobj(mo, self, self, mo->health, NAME_None,
|
||||
DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (count != 0);
|
||||
}
|
||||
|
||||
G_ExitLevel (0, false);
|
||||
|
@ -118,12 +124,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
|
|||
// spawn brain missile
|
||||
spit = P_SpawnMissile (self, targ, spawntype);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
spit->target = targ;
|
||||
spit->master = self;
|
||||
// [RH] Do this correctly for any trajectory. Doom would divide by 0
|
||||
|
@ -258,9 +264,14 @@ static void SpawnFly(AActor *self, const PClass *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
|
||||
|
|
|
@ -10,8 +10,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack)
|
|||
{
|
||||
int damage = (pr_bruisattack()%8+1)*10;
|
||||
S_Sound (self, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM);
|
||||
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (damage, self->target, self);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack)
|
|||
{
|
||||
int damage = (pr_headattack()%6+1)*10;
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (damage, self->target, self);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SargAttack)
|
|||
if (self->CheckMeleeRange ())
|
||||
{
|
||||
int damage = ((pr_sargattack()%10)+1)*4;
|
||||
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (damage, self->target, self);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack)
|
|||
{
|
||||
int damage = (pr_troopattack()%8+1)*3;
|
||||
S_Sound (self, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM);
|
||||
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (damage, self->target, self);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue