diff --git a/src/Makefile b/src/Makefile index f2d532cd5..c33e42daa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -64,6 +64,7 @@ # Compile without 3D sound support, add 'NOHS=1' # Compile with GDBstubs, add 'RDB=1' # Compile without PNG, add 'NOPNG=1' +# Compile without zlib, add 'NOZLIB=1' # # Addon for SDL: # To Cross-Compile, add 'SDL_CONFIG=/usr/*/bin/sdl-config' @@ -107,6 +108,7 @@ include Makefile.cfg ifdef DUMMY NOPNG=1 +NOZLIB=1 NONET=1 NOHW=1 NOHS=1 @@ -269,13 +271,6 @@ LIBS+=$(PNG_LDFLAGS) CFLAGS+=$(PNG_CFLAGS) endif -ZLIB_PKGCONFIG?=zlib -ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags) -ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs) - -LIBS+=$(ZLIB_LDFLAGS) -CFLAGS+=$(ZLIB_CFLAGS) - ifdef HAVE_LIBGME OPTS+=-DHAVE_LIBGME @@ -287,6 +282,18 @@ LIBS+=$(LIBGME_LDFLAGS) CFLAGS+=$(LIBGME_CFLAGS) endif +ifndef NOZLIB +OPTS+=-DHAVE_ZLIB +ZLIB_PKGCONFIG?=zlib +ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags) +ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs) + +LIBS+=$(ZLIB_LDFLAGS) +CFLAGS+=$(ZLIB_CFLAGS) +else +NOPNG=1 +endif + ifdef STATIC LIBS:=-static $(LIBS) endif diff --git a/src/android/i_sound.c b/src/android/i_sound.c index ecf96f2f0..2bb304424 100644 --- a/src/android/i_sound.c +++ b/src/android/i_sound.c @@ -21,13 +21,14 @@ void I_ShutdownSound(void){} // SFX I/O // -INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority) +INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority, INT32 channel) { (void)id; (void)vol; (void)sep; (void)pitch; (void)priority; + (void)channel; return -1; } @@ -55,90 +56,87 @@ void I_SetSfxVolume(INT32 volume) (void)volume; } -// -// MUSIC I/O -// +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ + UINT8 music_started = 0; +UINT8 digmusic_started = 0; void I_InitMusic(void){} void I_ShutdownMusic(void){} -void I_PauseSong(INT32 handle) +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ + +musictype_t I_SongType(void) { - (void)handle; + return MU_NONE; } -void I_ResumeSong(INT32 handle) +boolean I_SongPlaying(void) { - (void)handle; + return false; } -// -// MIDI I/O -// - -UINT8 midimusic_started = 0; - -void I_InitMIDIMusic(void){} - -void I_ShutdownMIDIMusic(void){} - -void I_SetMIDIMusicVolume(INT32 volume) +boolean I_SongPaused(void) { - (void)volume; + return false; } -INT32 I_RegisterSong(void *data, size_t len) -{ - (void)data; - (void)len; - return -1; -} - -boolean I_PlaySong(INT32 handle, INT32 looping) -{ - (void)handle; - (void)looping; - return false; -} - -void I_StopSong(INT32 handle) -{ - (void)handle; -} - -void I_UnRegisterSong(INT32 handle) -{ - (void)handle; -} - -// -// DIGMUSIC I/O -// - -UINT8 digmusic_started = 0; - -void I_InitDigMusic(void){} - -void I_ShutdownDigMusic(void){} - -boolean I_StartDigSong(const char *musicname, INT32 looping) -{ - (void)musicname; - (void)looping; - return false; -} - -void I_StopDigSong(void){} - -void I_SetDigMusicVolume(INT32 volume) -{ - (void)volume; -} +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ boolean I_SetSongSpeed(float speed) { (void)speed; return false; } + +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ + +UINT8 midimusic_started = 0; + +boolean I_LoadSong(char *data, size_t len) +{ + (void)data; + (void)len; + return -1; +} + +void I_UnloadSong() +{ + +} + +boolean I_PlaySong(boolean looping) +{ + (void)handle; + (void)looping; + return false; +} + +void I_StopSong(void) +{ + (void)handle; +} + +void I_PauseSong(void) +{ + (void)handle; +} + +void I_ResumeSong(void) +{ + (void)handle; +} + +void I_SetMusicVolume(INT32 volume) +{ + (void)volume; +} diff --git a/src/d_main.c b/src/d_main.c index c6dd9dc46..d2d7ff710 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -112,13 +112,10 @@ INT32 postimgparam; postimg_t postimgtype2 = postimg_none; INT32 postimgparam2; -boolean nomidimusic = false, nosound = false; -boolean nodigimusic = false; // No fmod-based music - // These variables are only true if -// the respective sound system is initialized -// and active, but no sounds/music should play. -boolean music_disabled = false; +// whether the respective sound system is disabled +// or they're init'ed, but the player just toggled them +boolean midi_disabled = false; boolean sound_disabled = false; boolean digital_disabled = false; @@ -1195,27 +1192,27 @@ void D_SRB2Main(void) // setting up sound if (dedicated) { - nosound = true; - nomidimusic = nodigimusic = true; + sound_disabled = true; + midi_disabled = digital_disabled = true; } else { - CONS_Printf("S_Init(): Setting up sound.\n"); + CONS_Printf("S_InitSfxChannels(): Setting up sound channels.\n"); } if (M_CheckParm("-nosound")) - nosound = true; + sound_disabled = true; if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic - nomidimusic = nodigimusic = true; + midi_disabled = digital_disabled = true; else { if (M_CheckParm("-nomidimusic")) - nomidimusic = true; ; // WARNING: DOS version initmusic in I_StartupSound + midi_disabled = true; ; // WARNING: DOS version initmusic in I_StartupSound if (M_CheckParm("-nodigmusic")) - nodigimusic = true; // WARNING: DOS version initmusic in I_StartupSound + digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound } I_StartupSound(); I_InitMusic(); - S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); + S_InitSfxChannels(cv_soundvolume.value); CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e96d98f11..528d79f3b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4063,6 +4063,7 @@ static void Command_RestartAudio_f(void) return; S_StopMusic(); + S_StopSounds(); I_ShutdownMusic(); I_ShutdownSound(); I_StartupSound(); @@ -4071,11 +4072,9 @@ static void Command_RestartAudio_f(void) // These must be called or no sound and music until manually set. I_SetSfxVolume(cv_soundvolume.value); - I_SetDigMusicVolume(cv_digmusicvolume.value); - I_SetMIDIMusicVolume(cv_midimusicvolume.value); + S_SetMusicVolume(cv_digmusicvolume.value, cv_midimusicvolume.value); if (Playing()) // Gotta make sure the player is in a level P_RestoreMusic(&players[consoleplayer]); - } /** Quits a game and returns to the title screen. diff --git a/src/dehacked.c b/src/dehacked.c index 1b80b8393..e33c7a641 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1196,8 +1196,10 @@ static void readlevelheader(MYFILE *f, INT32 num) else if (fastcmp(word2, "NORMAL")) i = 0; else if (fastcmp(word2, "BOSS")) i = 1; else if (fastcmp(word2, "ERZ3")) i = 2; + else if (fastcmp(word2, "NIGHTS")) i = 3; + else if (fastcmp(word2, "NIGHTSLINK")) i = 4; - if (i >= -1 && i <= 2) // -1 for no bonus. Max is 2. + if (i >= -1 && i <= 4) // -1 for no bonus. Max is 4. mapheaderinfo[num-1]->bonustype = (SINT8)i; else deh_warning("Level header %d: invalid bonus type number %d", num, i); @@ -5412,6 +5414,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_01_FLAP1", "S_FLICKY_01_FLAP2", "S_FLICKY_01_FLAP3", + "S_FLICKY_01_STAND", + "S_FLICKY_01_CENTER", // Rabbit "S_FLICKY_02_OUT", @@ -5419,6 +5423,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_02_HOP", "S_FLICKY_02_UP", "S_FLICKY_02_DOWN", + "S_FLICKY_02_STAND", + "S_FLICKY_02_CENTER", // Chicken "S_FLICKY_03_OUT", @@ -5427,6 +5433,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_03_UP", "S_FLICKY_03_FLAP1", "S_FLICKY_03_FLAP2", + "S_FLICKY_03_STAND", + "S_FLICKY_03_CENTER", // Seal "S_FLICKY_04_OUT", @@ -5438,6 +5446,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_04_SWIM2", "S_FLICKY_04_SWIM3", "S_FLICKY_04_SWIM4", + "S_FLICKY_04_STAND", + "S_FLICKY_04_CENTER", // Pig "S_FLICKY_05_OUT", @@ -5445,6 +5455,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_05_HOP", "S_FLICKY_05_UP", "S_FLICKY_05_DOWN", + "S_FLICKY_05_STAND", + "S_FLICKY_05_CENTER", // Chipmunk "S_FLICKY_06_OUT", @@ -5452,6 +5464,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_06_HOP", "S_FLICKY_06_UP", "S_FLICKY_06_DOWN", + "S_FLICKY_06_STAND", + "S_FLICKY_06_CENTER", // Penguin "S_FLICKY_07_OUT", @@ -5466,6 +5480,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_07_SWIM1", "S_FLICKY_07_SWIM2", "S_FLICKY_07_SWIM3", + "S_FLICKY_07_STAND", + "S_FLICKY_07_CENTER", // Fish "S_FLICKY_08_OUT", @@ -5479,6 +5495,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_08_SWIM2", "S_FLICKY_08_SWIM3", "S_FLICKY_08_SWIM4", + "S_FLICKY_08_STAND", + "S_FLICKY_08_CENTER", // Ram "S_FLICKY_09_OUT", @@ -5486,11 +5504,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_09_HOP", "S_FLICKY_09_UP", "S_FLICKY_09_DOWN", + "S_FLICKY_09_STAND", + "S_FLICKY_09_CENTER", // Puffin "S_FLICKY_10_OUT", "S_FLICKY_10_FLAP1", "S_FLICKY_10_FLAP2", + "S_FLICKY_10_STAND", + "S_FLICKY_10_CENTER", // Cow "S_FLICKY_11_OUT", @@ -5498,6 +5520,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_11_RUN1", "S_FLICKY_11_RUN2", "S_FLICKY_11_RUN3", + "S_FLICKY_11_STAND", + "S_FLICKY_11_CENTER", // Rat "S_FLICKY_12_OUT", @@ -5505,6 +5529,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_12_RUN1", "S_FLICKY_12_RUN2", "S_FLICKY_12_RUN3", + "S_FLICKY_12_STAND", + "S_FLICKY_12_CENTER", // Bear "S_FLICKY_13_OUT", @@ -5512,12 +5538,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_13_HOP", "S_FLICKY_13_UP", "S_FLICKY_13_DOWN", + "S_FLICKY_13_STAND", + "S_FLICKY_13_CENTER", // Dove "S_FLICKY_14_OUT", "S_FLICKY_14_FLAP1", "S_FLICKY_14_FLAP2", "S_FLICKY_14_FLAP3", + "S_FLICKY_14_STAND", + "S_FLICKY_14_CENTER", // Cat "S_FLICKY_15_OUT", @@ -5525,12 +5555,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_15_HOP", "S_FLICKY_15_UP", "S_FLICKY_15_DOWN", + "S_FLICKY_15_STAND", + "S_FLICKY_15_CENTER", // Canary "S_FLICKY_16_OUT", "S_FLICKY_16_FLAP1", "S_FLICKY_16_FLAP2", "S_FLICKY_16_FLAP3", + "S_FLICKY_16_STAND", + "S_FLICKY_16_CENTER", // Spider "S_SECRETFLICKY_01_OUT", @@ -5538,12 +5572,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SECRETFLICKY_01_HOP", "S_SECRETFLICKY_01_UP", "S_SECRETFLICKY_01_DOWN", + "S_SECRETFLICKY_01_STAND", + "S_SECRETFLICKY_01_CENTER", // Bat "S_SECRETFLICKY_02_OUT", "S_SECRETFLICKY_02_FLAP1", "S_SECRETFLICKY_02_FLAP2", "S_SECRETFLICKY_02_FLAP3", + "S_SECRETFLICKY_02_STAND", + "S_SECRETFLICKY_02_CENTER", // Fan "S_FAN", @@ -6742,23 +6780,41 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Flickies "MT_FLICKY_01", // Bluebird + "MT_FLICKY_01_CENTER", "MT_FLICKY_02", // Rabbit + "MT_FLICKY_02_CENTER", "MT_FLICKY_03", // Chicken + "MT_FLICKY_03_CENTER", "MT_FLICKY_04", // Seal + "MT_FLICKY_04_CENTER", "MT_FLICKY_05", // Pig + "MT_FLICKY_05_CENTER", "MT_FLICKY_06", // Chipmunk + "MT_FLICKY_06_CENTER", "MT_FLICKY_07", // Penguin + "MT_FLICKY_07_CENTER", "MT_FLICKY_08", // Fish + "MT_FLICKY_08_CENTER", "MT_FLICKY_09", // Ram + "MT_FLICKY_09_CENTER", "MT_FLICKY_10", // Puffin + "MT_FLICKY_10_CENTER", "MT_FLICKY_11", // Cow + "MT_FLICKY_11_CENTER", "MT_FLICKY_12", // Rat + "MT_FLICKY_12_CENTER", "MT_FLICKY_13", // Bear + "MT_FLICKY_13_CENTER", "MT_FLICKY_14", // Dove + "MT_FLICKY_14_CENTER", "MT_FLICKY_15", // Cat + "MT_FLICKY_15_CENTER", "MT_FLICKY_16", // Canary + "MT_FLICKY_16_CENTER", "MT_SECRETFLICKY_01", // Spider + "MT_SECRETFLICKY_01_CENTER", "MT_SECRETFLICKY_02", // Bat + "MT_SECRETFLICKY_02_CENTER", "MT_SEED", // Environmental Effects @@ -8826,17 +8882,17 @@ static int lib_getActionName(lua_State *L) { lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be) // get the name for this action, if possible. - lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); - lua_pushnil(gL); + lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); + lua_pushnil(L); // Lua stack at this point: // 1 ... -2 -1 // arg ... LREG_ACTIONS nil - while (lua_next(gL, -2)) + while (lua_next(L, -2)) { // Lua stack at this point: // 1 ... -3 -2 -1 // arg ... LREG_ACTIONS "A_ACTION" function - if (lua_rawequal(gL, -1, 1)) // is this the same as the arg? + if (lua_rawequal(L, -1, 1)) // is this the same as the arg? { // make sure the key (i.e. "A_ACTION") is a string first // (note: we don't use lua_isstring because it also returns true for numbers) @@ -8845,12 +8901,12 @@ static int lib_getActionName(lua_State *L) lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack return 1; } - lua_pop(gL, 2); // pop the name and function + lua_pop(L, 2); // pop the name and function break; // probably should have succeeded but we didn't, so end the loop } - lua_pop(gL, 1); + lua_pop(L, 1); } - lua_pop(gL, 1); // pop LREG_ACTIONS + lua_pop(L, 1); // pop LREG_ACTIONS return 0; // return nothing (don't error) } diff --git a/src/djgppdos/i_sound.c b/src/djgppdos/i_sound.c index 88fc807f4..52c90aac2 100644 --- a/src/djgppdos/i_sound.c +++ b/src/djgppdos/i_sound.c @@ -134,21 +134,12 @@ FUNCINLINE static ATTRINLINE int Volset(int vol) void I_SetSfxVolume(INT32 volume) { - if (nosound) + if (sound_disabled) return; set_volume (Volset(volume),-1); } -void I_SetMIDIMusicVolume(INT32 volume) -{ - if (nomidimusic) - return; - - // Now set volume on output device. - set_volume (-1, Volset(volume)); -} - // // Starting a sound means adding it // to the current list of active sounds @@ -165,11 +156,13 @@ INT32 I_StartSound ( sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, - INT32 priority ) + INT32 priority, + INT32 channel) { int voice; + (void)channel; - if (nosound) + if (sound_disabled) return 0; // UNUSED @@ -190,7 +183,7 @@ void I_StopSound (INT32 handle) // an setting the channel to zero. int voice=handle & (VIRTUAL_VOICES-1); - if (nosound) + if (sound_disabled) return; if (voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data) @@ -199,7 +192,7 @@ void I_StopSound (INT32 handle) INT32 I_SoundIsPlaying(INT32 handle) { - if (nosound) + if (sound_disabled) return FALSE; if (voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data) @@ -229,7 +222,7 @@ void I_UpdateSoundParams( INT32 handle, int voice=handle & (VIRTUAL_VOICES-1); int numsfx=handle>>VOICESSHIFT; - if (nosound) + if (sound_disabled) return; if (voice_check(voice)==S_sfx[numsfx].data) @@ -270,17 +263,17 @@ void I_StartupSound(void) char err[255]; #endif - if (nosound) + if (sound_disabled) sfxcard=DIGI_NONE; else sfxcard=DIGI_AUTODETECT; - if (nomidimusic) + if (midi_disabled) midicard=MIDI_NONE; else midicard=MIDI_AUTODETECT; //DetectMusicCard(); - nodigimusic=true; //Alam: No OGG/MP3/IT/MOD support + digital_disabled=true; //Alam: No OGG/MP3/IT/MOD support // Secure and configure sound device first. CONS_Printf("I_StartupSound: "); @@ -293,8 +286,8 @@ void I_StartupSound(void) { sprintf (err,"Sound init error : %s\n",allegro_error); CONS_Error (err); - nosound=true; - nomidimusic=true; + sound_disabled=true; + midi_disabled=true; } else { @@ -321,7 +314,11 @@ static MIDI* currsong; //im assuming only 1 song will be played at once static int islooping=0; static int musicdies=-1; UINT8 music_started=0; +boolean songpaused=false; +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ /* load_midi_mem: * Loads a standard MIDI file from memory, returning a pointer to @@ -389,116 +386,66 @@ static MIDI *load_midi_mem(char *mempointer,int *e) return midi; } -void I_InitMIDIMusic(void) +void I_InitMusic(void) { - if (nomidimusic) + if (midi_disabled) return; I_AddExitFunc(I_ShutdownMusic); music_started = true; -} - -void I_ShutdownMIDIMusic(void) -{ - if ( !music_started ) - return; - - I_StopSong(1); - - music_started=false; -} - -void I_InitDigMusic(void) -{ -// CONS_Printf("Digital music not yet supported under DOS.\n"); -} - -void I_ShutdownDigMusic(void) -{ -// CONS_Printf("Digital music not yet supported under DOS.\n"); -} - -void I_InitMusic(void) -{ - if (!nodigimusic) - I_InitDigMusic(); - if (!nomidimusic) - I_InitMIDIMusic(); + songpaused = false; } void I_ShutdownMusic(void) { - I_ShutdownMIDIMusic(); - I_ShutdownDigMusic(); + if ( !music_started ) + return; + + I_StopSong(); + + music_started=false; } -boolean I_PlaySong(INT32 handle, INT32 looping) -{ - handle = 0; - if (nomidimusic) - return false; +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ - islooping = looping; - musicdies = gametic + NEWTICRATE*30; - if (play_midi(currsong,looping)==0) - return true; +musictype_t I_SongType(void) +{ + if (currsong) + return MU_MID; + else + return MU_NONE; +} + +boolean I_SongPlaying() +{ + return (boolean)currsong; +} + +boolean I_SongPaused() +{ + return songpaused; +} + +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ + +boolean I_SetSongSpeed(float speed) +{ + (void)speed; return false; } -void I_PauseSong (INT32 handle) -{ - handle = 0; - if (nomidimusic) - return; +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ - midi_pause(); -} - -void I_ResumeSong (INT32 handle) -{ - handle = 0; - if (nomidimusic) - return; - - midi_resume(); -} - -void I_StopSong(INT32 handle) -{ - handle = 0; - if (nomidimusic) - return; - - islooping = 0; - musicdies = 0; - stop_midi(); -} - -// Is the song playing? -#if 0 -int I_QrySongPlaying(int handle) -{ - if (nomidimusic) - return 0; - - //return islooping || musicdies > gametic; - return (midi_pos==-1); -} -#endif - -void I_UnRegisterSong(INT32 handle) -{ - handle = 0; - if (nomidimusic) - return; - - //destroy_midi(currsong); -} - -INT32 I_RegisterSong(void *data, size_t len) +boolean I_LoadSong(char *data, size_t len) { int e = len; //Alam: For error - if (nomidimusic) + if (midi_disabled) return 0; if (memcmp(data,"MThd",4)==0) // support mid file in WAD !!! @@ -520,32 +467,81 @@ INT32 I_RegisterSong(void *data, size_t len) return 1; } -/// \todo Add OGG/MP3 support for dos -boolean I_StartDigSong(const char *musicname, INT32 looping) +void I_UnloadSong(void) { - musicname = NULL; - looping = 0; - //CONS_Printf("I_StartDigSong: Not yet supported under DOS.\n"); + handle = 0; + if (midi_disabled) + return; + + //destroy_midi(currsong); +} + +boolean I_PlaySong(boolean looping) +{ + handle = 0; + if (midi_disabled) + return false; + + islooping = looping; + musicdies = gametic + NEWTICRATE*30; + if (play_midi(currsong,looping)==0) + return true; return false; } -void I_StopDigSong(void) +void I_StopSong(void) { -// CONS_Printf("I_StopDigSong: Not yet supported under DOS.\n"); + handle = 0; + if (midi_disabled) + return; + + islooping = 0; + musicdies = 0; + stop_midi(); + songpaused = false; } -void I_SetDigMusicVolume(INT32 volume) +void I_PauseSong (INT32 handle) { - volume = 0; - if (nodigimusic) + handle = 0; + if (midi_disabled) + return; + midi_pause(); + songpaused = true; +} + +void I_ResumeSong (INT32 handle) +{ + handle = 0; + if (midi_disabled) + return; + midi_resume(); + songpaused = false; +} + +void I_SetMusicVolume(INT32 volume) +{ + if (midi_disabled) return; // Now set volume on output device. -// CONS_Printf("Digital music not yet supported under DOS.\n"); + set_volume (-1, Volset(volume)); } -boolean I_SetSongSpeed(float speed) +boolean I_SetSongTrack(INT32 track) { - (void)speed; + (void)track; return false; } + +// Is the song playing? +#if 0 +int I_QrySongPlaying(int handle) +{ + if (midi_disabled) + return 0; + + //return islooping || musicdies > gametic; + return (midi_pos==-1); +} +#endif diff --git a/src/doomstat.h b/src/doomstat.h index 9a3bff7c0..421b6579f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -90,10 +90,7 @@ extern boolean fromlevelselect; // Internal parameters for sound rendering. // ======================================== -extern boolean nomidimusic; // defined in d_main.c -extern boolean nosound; -extern boolean nodigimusic; -extern boolean music_disabled; +extern boolean midi_disabled; extern boolean sound_disabled; extern boolean digital_disabled; diff --git a/src/dummy/i_sound.c b/src/dummy/i_sound.c index 51dbb610d..7275bb1ae 100644 --- a/src/dummy/i_sound.c +++ b/src/dummy/i_sound.c @@ -23,13 +23,14 @@ void I_UpdateSound(void){}; // SFX I/O // -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) { (void)id; (void)vol; (void)sep; (void)pitch; (void)priority; + (void)channel; return -1; } @@ -57,82 +58,36 @@ void I_SetSfxVolume(UINT8 volume) (void)volume; } -// -// MUSIC I/O -// +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ void I_InitMusic(void){} void I_ShutdownMusic(void){} -void I_PauseSong(INT32 handle) +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ + +musictype_t I_SongType(void) { - (void)handle; + return MU_NONE; } -void I_ResumeSong(INT32 handle) +boolean I_SongPlaying(void) { - (void)handle; -} - -// -// MIDI I/O -// - -void I_InitMIDIMusic(void){} - -void I_ShutdownMIDIMusic(void){} - -void I_SetMIDIMusicVolume(UINT8 volume) -{ - (void)volume; -} - -INT32 I_RegisterSong(void *data, size_t len) -{ - (void)data; - (void)len; - return -1; -} - -boolean I_PlaySong(INT32 handle, boolean looping) -{ - (void)handle; - (void)looping; return false; } -void I_StopSong(INT32 handle) +boolean I_SongPaused(void) { - (void)handle; -} - -void I_UnRegisterSong(INT32 handle) -{ - (void)handle; -} - -// -// DIGMUSIC I/O -// - -void I_InitDigMusic(void){} - -void I_ShutdownDigMusic(void){} - -boolean I_StartDigSong(const char *musicname, boolean looping) -{ - (void)musicname; - (void)looping; return false; } -void I_StopDigSong(void){} - -void I_SetDigMusicVolume(UINT8 volume) -{ - (void)volume; -} +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ boolean I_SetSongSpeed(float speed) { @@ -140,8 +95,51 @@ boolean I_SetSongSpeed(float speed) return false; } +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ + +boolean I_LoadSong(char *data, size_t len) +{ + (void)data; + (void)len; + return -1; +} + +void I_UnloadSong(void) +{ + (void)handle; +} + +boolean I_PlaySong(boolean looping) +{ + (void)handle; + (void)looping; + return false; +} + +void I_StopSong(void) +{ + (void)handle; +} + +void I_PauseSong(void) +{ + (void)handle; +} + +void I_ResumeSong(void) +{ + (void)handle; +} + +void I_SetMusicVolume(UINT8 volume) +{ + (void)volume; +} + boolean I_SetSongTrack(int track) { (void)track; return false; -} +} \ No newline at end of file diff --git a/src/hardware/hw3sound.c b/src/hardware/hw3sound.c index c68430921..f7c6e1da0 100644 --- a/src/hardware/hw3sound.c +++ b/src/hardware/hw3sound.c @@ -361,7 +361,7 @@ INT32 HW3S_I_StartSound(const void *origin_p, source3D_data_t *source_parm, chan if (splitscreen) listenmobj2 = players[secondarydisplayplayer].mo; - if (nosound) + if (sound_disabled) return -1; sfx = &S_sfx[sfx_id]; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 119be6b46..349103602 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1126,7 +1126,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, else { lightnum = *list[i].lightlevel; - colormap = list[i].extra_colormap; + colormap = *list[i].extra_colormap; } } @@ -2116,6 +2116,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) else { fixed_t texturevpeg; + boolean attachtobottom = false; +#ifdef ESLOPE + boolean slopeskew = false; // skew FOF walls with slopes? +#endif // Wow, how was this missing from OpenGL for so long? // ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software @@ -2123,24 +2127,50 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (newline) { texturevpeg = sides[newline->sidenum[0]].rowoffset; - if (newline->flags & ML_DONTPEGBOTTOM) - texturevpeg -= *rover->topheight - *rover->bottomheight; + attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM); +#ifdef ESLOPE + slopeskew = !!(newline->flags & ML_DONTPEGTOP); +#endif } else { texturevpeg = sides[rover->master->sidenum[0]].rowoffset; - if (gr_linedef->flags & ML_DONTPEGBOTTOM) - texturevpeg -= *rover->topheight - *rover->bottomheight; + attachtobottom = !!(gr_linedef->flags & ML_DONTPEGBOTTOM); +#ifdef ESLOPE + slopeskew = !!(rover->master->flags & ML_DONTPEGTOP); +#endif } grTex = HWR_GetTexture(texnum); #ifdef ESLOPE - wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; - wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY; - wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; - wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY; + if (!slopeskew) // no skewing + { + if (attachtobottom) + texturevpeg -= *rover->topheight - *rover->bottomheight; + wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; + wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY; + wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; + wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY; + } + else + { + if (!attachtobottom) // skew by top + { + wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; + wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; + wallVerts[1].t = (hS - lS + texturevpeg) * grTex->scaleY; + } + else // skew by bottom + { + wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY; + wallVerts[3].t = wallVerts[0].t - (h - l) * grTex->scaleY; + wallVerts[2].t = wallVerts[1].t - (hS - lS) * grTex->scaleY; + } + } #else + if (attachtobottom) + texturevpeg -= *rover->topheight - *rover->bottomheight; wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; #endif @@ -3486,12 +3516,12 @@ static void HWR_Subsector(size_t num) light = R_GetPlaneLight(gr_frontsector, locFloorHeight, false); if (gr_frontsector->floorlightsec == -1) floorlightlevel = *gr_frontsector->lightlist[light].lightlevel; - floorcolormap = gr_frontsector->lightlist[light].extra_colormap; + floorcolormap = *gr_frontsector->lightlist[light].extra_colormap; light = R_GetPlaneLight(gr_frontsector, locCeilingHeight, false); if (gr_frontsector->ceilinglightsec == -1) ceilinglightlevel = *gr_frontsector->lightlist[light].lightlevel; - ceilingcolormap = gr_frontsector->lightlist[light].extra_colormap; + ceilingcolormap = *gr_frontsector->lightlist[light].extra_colormap; } sub->sector->extra_colormap = gr_frontsector->extra_colormap; @@ -3617,7 +3647,7 @@ static void HWR_Subsector(size_t num) *rover->bottomheight, *gr_frontsector->lightlist[light].lightlevel, rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent, - false, gr_frontsector->lightlist[light].extra_colormap); + false, *gr_frontsector->lightlist[light].extra_colormap); #endif } else @@ -3625,7 +3655,7 @@ static void HWR_Subsector(size_t num) HWR_GetFlat(levelflats[*rover->bottompic].lumpnum); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum, - rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap); + rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); } } @@ -3680,7 +3710,7 @@ static void HWR_Subsector(size_t num) *rover->topheight, *gr_frontsector->lightlist[light].lightlevel, rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent, - false, gr_frontsector->lightlist[light].extra_colormap); + false, *gr_frontsector->lightlist[light].extra_colormap); #endif } @@ -3689,7 +3719,7 @@ static void HWR_Subsector(size_t num) HWR_GetFlat(levelflats[*rover->toppic].lumpnum); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum, - rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap); + rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); } } } @@ -4200,8 +4230,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; + if (*sector->lightlist[light].extra_colormap) + colormap = *sector->lightlist[light].extra_colormap; } else { @@ -4362,7 +4392,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) // Start with the lightlevel and colormap from the top of the sprite lightlevel = *list[sector->numlights - 1].lightlevel; - colormap = list[sector->numlights - 1].extra_colormap; + colormap = *list[sector->numlights - 1].extra_colormap; i = 0; temp = FLOAT_TO_FIXED(realtop); @@ -4378,7 +4408,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *list[i-1].lightlevel; - colormap = list[i-1].extra_colormap; + colormap = *list[i-1].extra_colormap; break; } } @@ -4386,7 +4416,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) i = R_GetPlaneLight(sector, temp, false); if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *list[i].lightlevel; - colormap = list[i].extra_colormap; + colormap = *list[i].extra_colormap; #endif for (i = 0; i < sector->numlights; i++) @@ -4402,7 +4432,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *list[i].lightlevel; - colormap = list[i].extra_colormap; + colormap = *list[i].extra_colormap; } #ifdef ESLOPE @@ -4734,8 +4764,8 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; + if (*sector->lightlist[light].extra_colormap) + colormap = *sector->lightlist[light].extra_colormap; } else { @@ -5270,8 +5300,10 @@ static void HWR_AddSprites(sector_t *sec) approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - if (approx_dist <= limit_dist) - HWR_ProjectSprite(thing); + if (approx_dist > limit_dist) + continue; + + HWR_ProjectSprite(thing); } } else @@ -5293,8 +5325,10 @@ static void HWR_AddSprites(sector_t *sec) approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); - if (approx_dist <= limit_dist) - HWR_ProjectPrecipitationSprite(precipthing); + if (approx_dist > limit_dist) + continue; + + HWR_ProjectPrecipitationSprite(precipthing); } } else @@ -5624,6 +5658,16 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) x1 = tr_x + x1 * rightcos; x2 = tr_x - x2 * rightcos; + // okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } + // // store information in a vissprite // diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index bfb2638ee..d69233a9b 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1194,8 +1194,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel; - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; + if (*sector->lightlist[light].extra_colormap) + colormap = *sector->lightlist[light].extra_colormap; } else { diff --git a/src/i_sound.h b/src/i_sound.h index 084479ee1..2f73017dd 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -18,6 +18,21 @@ #include "sounds.h" #include "command.h" +// copied from SDL mixer, plus GME +typedef enum { + MU_NONE, + MU_CMD, + MU_WAV, + MU_MOD, + MU_MID, + MU_OGG, + MU_MP3, + MU_MP3_MAD_UNUSED, // use MU_MP3 instead + MU_FLAC, + MU_MODPLUG_UNUSED, // use MU_MOD instead + MU_GME +} musictype_t; + /** \brief Sound subsystem runing and waiting */ extern UINT8 sound_started; @@ -51,9 +66,9 @@ void I_StartupSound(void); */ void I_ShutdownSound(void); -// -// SFX I/O -// +/// ------------------------ +/// SFX I/O +/// ------------------------ /** \brief Starts a sound in a particular sound channel. \param id sfxid @@ -64,7 +79,7 @@ void I_ShutdownSound(void); \return sfx handle */ -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority); +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel); /** \brief Stops a sound channel. @@ -105,9 +120,10 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch); */ void I_SetSfxVolume(UINT8 volume); -// -// MUSIC I/O -// +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ + /** \brief Init the music systems */ void I_InitMusic(void); @@ -116,41 +132,23 @@ void I_InitMusic(void); */ void I_ShutdownMusic(void); -/** \brief PAUSE game handling. +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ - \param handle song handle +musictype_t I_SongType(void); +boolean I_SongPlaying(void); +boolean I_SongPaused(void); - \return void -*/ -void I_PauseSong(INT32 handle); +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ -/** \brief RESUME game handling +boolean I_SetSongSpeed(float speed); - \param handle song handle - - \return void -*/ -void I_ResumeSong(INT32 handle); - -// -// MIDI I/O -// - -/** \brief Startup the MIDI music system -*/ -void I_InitMIDIMusic(void); - -/** \brief Shutdown the MIDI music system -*/ -void I_ShutdownMIDIMusic(void); - -/** \brief The I_SetMIDIMusicVolume function - - \param volume volume to set at - - \return void -*/ -void I_SetMIDIMusicVolume(UINT8 volume); +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ /** \brief Registers a song handle to song data. @@ -161,7 +159,16 @@ void I_SetMIDIMusicVolume(UINT8 volume); \todo Remove this */ -INT32 I_RegisterSong(void *data, size_t len); +boolean I_LoadSong(char *data, size_t len); + +/** \brief See ::I_LoadSong, then think backwards + + \param handle song handle + + \sa I_LoadSong + \todo remove midi handle +*/ +void I_UnloadSong(void); /** \brief Called by anything that wishes to start music @@ -172,7 +179,7 @@ INT32 I_RegisterSong(void *data, size_t len); \todo pass music name, not handle */ -boolean I_PlaySong(INT32 handle, boolean looping); +boolean I_PlaySong(boolean looping); /** \brief Stops a song over 3 seconds @@ -181,58 +188,37 @@ boolean I_PlaySong(INT32 handle, boolean looping); /todo drop handle */ -void I_StopSong(INT32 handle); +void I_StopSong(void); -/** \brief See ::I_RegisterSong, then think backwards +/** \brief PAUSE game handling. \param handle song handle - \sa I_RegisterSong - \todo remove midi handle + \return void */ -void I_UnRegisterSong(INT32 handle); +void I_PauseSong(void); -// -// DIGMUSIC I/O -// +/** \brief RESUME game handling -/** \brief Startup the music system + \param handle song handle + + \return void */ -void I_InitDigMusic(void); +void I_ResumeSong(void); -/** \brief Shutdown the music system -*/ -void I_ShutdownDigMusic(void); - -boolean I_SetSongSpeed(float speed); - -boolean I_SetSongTrack(INT32 track); - -/** \brief The I_StartDigSong function - - \param musicname music lump name - \param looping if true, loop the song - - \return if true, song playing -*/ -boolean I_StartDigSong(const char *musicname, boolean looping); - -/** \brief stop non-MIDI song -*/ -void I_StopDigSong(void); - -/** \brief The I_SetDigMusicVolume function +/** \brief The I_SetMusicVolume function \param volume volume to set at \return void */ -void I_SetDigMusicVolume(UINT8 volume); +void I_SetMusicVolume(UINT8 volume); -// -// CD MUSIC I/O -// +boolean I_SetSongTrack(INT32 track); +/// ------------------------ +// CD MUSIC I/O +/// ------------------------ /** \brief cd music interface */ @@ -279,4 +265,4 @@ void I_PlayCD(UINT8 track, UINT8 looping); */ boolean I_SetVolumeCD(INT32 volume); -#endif +#endif \ No newline at end of file diff --git a/src/i_tcp.c b/src/i_tcp.c index 9bb4ec630..044bf4e4c 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -649,14 +649,29 @@ static boolean SOCK_CanGet(void) #endif #ifndef NONET -static void SOCK_Send(void) +static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr) { - ssize_t c = ERRSOCKET; socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in); #ifdef HAVE_IPV6 socklen_t d6 = (socklen_t)sizeof(struct sockaddr_in6); #endif socklen_t d, da = (socklen_t)sizeof(mysockaddr_t); + + switch (sockaddr->any.sa_family) + { + case AF_INET: d = d4; break; +#ifdef HAVE_IPV6 + case AF_INET6: d = d6; break; +#endif + default: d = da; break; + } + + return sendto(socket, (char *)&doomcom->data, doomcom->datalength, 0, &sockaddr->any, d); +} + +static void SOCK_Send(void) +{ + ssize_t c = ERRSOCKET; size_t i, j; if (!nodeconnected[doomcom->remotenode]) @@ -669,19 +684,7 @@ static void SOCK_Send(void) for (j = 0; j < broadcastaddresses; j++) { if (myfamily[i] == broadcastaddress[j].any.sa_family) - { - if (broadcastaddress[i].any.sa_family == AF_INET) - d = d4; -#ifdef HAVE_IPV6 - else if (broadcastaddress[i].any.sa_family == AF_INET6) - d = d6; -#endif - else - d = da; - - c = sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0, - &broadcastaddress[j].any, d); - } + SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); } } return; @@ -691,35 +694,13 @@ static void SOCK_Send(void) for (i = 0; i < mysocketses; i++) { if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) - { - if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET) - d = d4; -#ifdef HAVE_IPV6 - else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6) - d = d6; -#endif - else - d = da; - - sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0, - &clientaddress[doomcom->remotenode].any, d); - } + SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); } return; } else { - if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET) - d = d4; -#ifdef HAVE_IPV6 - else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6) - d = d6; -#endif - else - d = da; - - c = sendto(nodesocket[doomcom->remotenode], (char *)&doomcom->data, doomcom->datalength, 0, - &clientaddress[doomcom->remotenode].any, d); + c = SOCK_SendToAddr(nodesocket[doomcom->remotenode], &clientaddress[doomcom->remotenode]); } if (c == ERRSOCKET && errno != ECONNREFUSED && errno != EWOULDBLOCK) @@ -1007,7 +988,7 @@ static boolean UDP_Socket(void) if (gaie == 0) { runp = ai; - while (runp != NULL) + while (runp != NULL && s < MAXNETNODES+1) { memcpy(&clientaddress[s], runp->ai_addr, runp->ai_addrlen); s++; @@ -1022,12 +1003,15 @@ static boolean UDP_Socket(void) clientaddress[s].ip4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //GetLocalAddress(); // my own ip s++; } + + s = 0; + // setup broadcast adress to BROADCASTADDR entry gaie = I_getaddrinfo("255.255.255.255", "0", &hints, &ai); if (gaie == 0) { runp = ai; - while (runp != NULL) + while (runp != NULL && s < MAXNETNODES+1) { memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen); s++; @@ -1050,7 +1034,7 @@ static boolean UDP_Socket(void) if (gaie == 0) { runp = ai; - while (runp != NULL) + while (runp != NULL && s < MAXNETNODES+1) { memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen); s++; diff --git a/src/info.c b/src/info.c index a6d847235..3140bd7de 100644 --- a/src/info.c +++ b/src/info.c @@ -2641,6 +2641,8 @@ state_t states[NUMSTATES] = {SPR_FL01, 1, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_FLICKY_01_FLAP2}, // S_FLICKY_01_FLAP1 {SPR_FL01, 2, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_FLICKY_01_FLAP3}, // S_FLICKY_01_FLAP2 {SPR_FL01, 3, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_FLICKY_01_FLAP1}, // S_FLICKY_01_FLAP3 + {SPR_FL01, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_01_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_01, 384*FRACUNIT, S_FLICKY_01_CENTER}, // S_FLICKY_01_CENTER // Rabbit {SPR_FL02, 0, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, 0, S_FLICKY_02_OUT}, // S_FLICKY_02_OUT @@ -2648,6 +2650,8 @@ state_t states[NUMSTATES] = {SPR_FL02, 1, 1, {A_FlickyHop}, 6*FRACUNIT, 4*FRACUNIT, S_FLICKY_02_UP}, // S_FLICKY_02_HOP {SPR_FL02, 2, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, S_FLICKY_02_DOWN, S_FLICKY_02_UP}, // S_FLICKY_02_UP {SPR_FL02, 3, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, 0, S_FLICKY_02_DOWN}, // S_FLICKY_02_DOWN + {SPR_FL02, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_02_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_02, 384*FRACUNIT, S_FLICKY_02_CENTER}, // S_FLICKY_02_CENTER // Chicken {SPR_FL03, 0, 2, {A_FlickyCheck}, S_FLICKY_03_AIM, S_FLICKY_03_FLAP1, S_FLICKY_03_OUT}, // S_FLICKY_03_OUT @@ -2656,6 +2660,8 @@ state_t states[NUMSTATES] = {SPR_FL03, 2, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, S_FLICKY_03_FLAP1, S_FLICKY_03_UP}, // S_FLICKY_03_UP {SPR_FL03, 3, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, 0, S_FLICKY_03_FLAP2}, // S_FLICKY_03_FLAP1 {SPR_FL03, 4, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, 0, S_FLICKY_03_FLAP1}, // S_FLICKY_03_FLAP2 + {SPR_FL03, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_03_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_03, 384*FRACUNIT, S_FLICKY_03_CENTER}, // S_FLICKY_03_CENTER // Seal {SPR_FL04, 0, 2, {A_FlickyCheck}, S_FLICKY_04_AIM, 0, S_FLICKY_04_OUT}, // S_FLICKY_04_OUT @@ -2667,6 +2673,8 @@ state_t states[NUMSTATES] = {SPR_FL04, 4, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM3}, // S_FLICKY_04_SWIM2 {SPR_FL04, 3, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM4}, // S_FLICKY_04_SWIM3 {SPR_FL04, 5, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM1}, // S_FLICKY_04_SWIM4 + {SPR_FL04, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_04_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_04, 384*FRACUNIT, S_FLICKY_04_CENTER}, // S_FLICKY_04_CENTER // Pig {SPR_FL05, 0, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, 0, S_FLICKY_05_OUT}, // S_FLICKY_05_OUT @@ -2674,6 +2682,8 @@ state_t states[NUMSTATES] = {SPR_FL05, 1, 1, {A_FlickyHop}, 4*FRACUNIT, 3*FRACUNIT, S_FLICKY_05_UP}, // S_FLICKY_05_HOP {SPR_FL05, 2, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, S_FLICKY_05_DOWN, S_FLICKY_05_UP}, // S_FLICKY_05_UP {SPR_FL05, 3, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, 0, S_FLICKY_05_DOWN}, // S_FLICKY_05_DOWN + {SPR_FL05, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_05_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_05, 384*FRACUNIT, S_FLICKY_05_CENTER}, // S_FLICKY_05_CENTER // Chipmunk {SPR_FL06, 0, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, 0, S_FLICKY_06_OUT}, // S_FLICKY_06_OUT @@ -2681,6 +2691,8 @@ state_t states[NUMSTATES] = {SPR_FL06, 1, 1, {A_FlickyHop}, 5*FRACUNIT, 6*FRACUNIT, S_FLICKY_06_UP}, // S_FLICKY_06_HOP {SPR_FL06, 2, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, S_FLICKY_06_DOWN, S_FLICKY_06_UP}, // S_FLICKY_06_UP {SPR_FL06, 3, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, 0, S_FLICKY_06_DOWN}, // S_FLICKY_06_DOWN + {SPR_FL06, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_06_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_06, 384*FRACUNIT, S_FLICKY_06_CENTER}, // S_FLICKY_06_CENTER // Penguin {SPR_FL07, 0, 2, {A_FlickyCheck}, S_FLICKY_07_AIML, 0, S_FLICKY_07_OUT}, // S_FLICKY_07_OUT @@ -2695,6 +2707,8 @@ state_t states[NUMSTATES] = {SPR_FL07, 4, 4, {A_FlickyFly}, 3*FRACUNIT, 72*FRACUNIT, S_FLICKY_07_SWIM2}, // S_FLICKY_07_SWIM1 {SPR_FL07, 5, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM2 {SPR_FL07, 6, 4, {A_FlickyCoast}, 2*FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM3 + {SPR_FL07, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_07_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_07, 384*FRACUNIT, S_FLICKY_07_CENTER}, // S_FLICKY_07_CENTER // Fish {SPR_FL08, 0, 2, {A_FlickyCheck}, S_FLICKY_08_AIM, 0, S_FLICKY_08_OUT}, // S_FLICKY_08_OUT @@ -2708,6 +2722,8 @@ state_t states[NUMSTATES] = {SPR_FL08, 1, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM3}, // S_FLICKY_08_SWIM2 {SPR_FL08, 0, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM3 {SPR_FL08, 2, 4, {A_FlickyCoast}, FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM4 + {SPR_FL08, FF_ANIMATE, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_08_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_08, 384*FRACUNIT, S_FLICKY_08_CENTER}, // S_FLICKY_08_CENTER // Ram {SPR_FL09, 0, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, 0, S_FLICKY_09_OUT}, // S_FLICKY_09_OUT @@ -2715,11 +2731,15 @@ state_t states[NUMSTATES] = {SPR_FL09, 1, 1, {A_FlickyHop}, 7*FRACUNIT, 2*FRACUNIT, S_FLICKY_09_UP}, // S_FLICKY_09_HOP {SPR_FL09, 2, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, S_FLICKY_09_DOWN, S_FLICKY_09_UP}, // S_FLICKY_09_UP {SPR_FL09, 3, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, 0, S_FLICKY_09_DOWN}, // S_FLICKY_09_DOWN + {SPR_FL09, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_09_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_09, 384*FRACUNIT, S_FLICKY_09_CENTER}, // S_FLICKY_09_CENTER // Puffin {SPR_FL10, 0, 2, {A_FlickyCheck}, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP1, S_FLICKY_10_OUT}, // S_FLICKY_10_OUT {SPR_FL10, 1, 3, {A_FlickySoar}, 4*FRACUNIT, 16*FRACUNIT, S_FLICKY_10_FLAP2}, // S_FLICKY_10_FLAP1 {SPR_FL10, 2, 3, {A_FlickySoar}, 4*FRACUNIT, 16*FRACUNIT, S_FLICKY_10_FLAP1}, // S_FLICKY_10_FLAP2 + {SPR_FL10, FF_ANIMATE|1, -1, {NULL}, 1, 3, S_NULL}, // S_FLICKY_10_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_10, 384*FRACUNIT, S_FLICKY_10_CENTER}, // S_FLICKY_10_CENTER // Cow {SPR_FL11, 0, 2, {A_FlickyCheck}, S_FLICKY_11_AIM, 0, S_FLICKY_11_OUT}, // S_FLICKY_11_OUT @@ -2727,6 +2747,8 @@ state_t states[NUMSTATES] = {SPR_FL11, 1, 3, {A_FlickyHop}, FRACUNIT/2, 2*FRACUNIT, S_FLICKY_11_RUN2}, // S_FLICKY_11_RUN1 {SPR_FL11, 2, 4, {A_FlickyHop}, FRACUNIT/2, 2*FRACUNIT, S_FLICKY_11_RUN3}, // S_FLICKY_11_RUN2 {SPR_FL11, 3, 4, {A_FlickyHop}, FRACUNIT/2, 2*FRACUNIT, S_FLICKY_11_AIM}, // S_FLICKY_11_RUN3 + {SPR_FL11, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_11_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_11, 384*FRACUNIT, S_FLICKY_11_CENTER}, // S_FLICKY_11_CENTER // Rat {SPR_FL12, 0, 2, {A_FlickyCheck}, S_FLICKY_12_AIM, 0, S_FLICKY_12_OUT}, // S_FLICKY_12_OUT @@ -2734,6 +2756,8 @@ state_t states[NUMSTATES] = {SPR_FL12, 1, 2, {A_FlickyHop}, 1, 12*FRACUNIT, S_FLICKY_12_RUN2}, // S_FLICKY_12_RUN1 {SPR_FL12, 2, 3, {A_FlickyHop}, 1, 12*FRACUNIT, S_FLICKY_12_RUN3}, // S_FLICKY_12_RUN2 {SPR_FL12, 3, 3, {A_FlickyHop}, 1, 12*FRACUNIT, S_FLICKY_12_AIM}, // S_FLICKY_12_RUN3 + {SPR_FL12, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_12_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_12, 384*FRACUNIT, S_FLICKY_12_CENTER}, // S_FLICKY_12_CENTER // Bear {SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, 0, S_FLICKY_13_OUT}, // S_FLICKY_13_OUT @@ -2741,12 +2765,16 @@ state_t states[NUMSTATES] = {SPR_FL13, 1, 1, {A_FlickyHop}, 5*FRACUNIT, 3*FRACUNIT, S_FLICKY_13_UP}, // S_FLICKY_13_HOP {SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP}, // S_FLICKY_13_UP {SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, 0, S_FLICKY_13_DOWN}, // S_FLICKY_13_DOWN + {SPR_FL13, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_13_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_13, 384*FRACUNIT, S_FLICKY_13_CENTER}, // S_FLICKY_13_CENTER // Dove {SPR_FL14, 0, 2, {A_FlickyCheck}, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP1, S_FLICKY_14_OUT}, // S_FLICKY_14_OUT {SPR_FL14, 1, 3, {A_FlickySoar}, 4*FRACUNIT, 32*FRACUNIT, S_FLICKY_14_FLAP2}, // S_FLICKY_14_FLAP1 {SPR_FL14, 2, 3, {A_FlickySoar}, 4*FRACUNIT, 32*FRACUNIT, S_FLICKY_14_FLAP3}, // S_FLICKY_14_FLAP2 {SPR_FL14, 3, 3, {A_FlickySoar}, 4*FRACUNIT, 32*FRACUNIT, S_FLICKY_14_FLAP1}, // S_FLICKY_14_FLAP3 + {SPR_FL14, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_14_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_14, 384*FRACUNIT, S_FLICKY_14_CENTER}, // S_FLICKY_14_CENTER // Cat {SPR_FL15, 0, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, 0, S_FLICKY_15_OUT}, // S_FLICKY_15_OUT @@ -2754,12 +2782,16 @@ state_t states[NUMSTATES] = {SPR_FL15, 1, 1, {A_FlickyFlounder}, 2*FRACUNIT, 6*FRACUNIT, S_FLICKY_15_UP}, // S_FLICKY_15_HOP {SPR_FL15, 2, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, S_FLICKY_15_DOWN, S_FLICKY_15_UP}, // S_FLICKY_15_UP {SPR_FL15, 3, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, 0, S_FLICKY_15_DOWN}, // S_FLICKY_15_DOWN + {SPR_FL15, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_15_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_15, 384*FRACUNIT, S_FLICKY_15_CENTER}, // S_FLICKY_15_CENTER // Canary {SPR_FL16, 0, 2, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1, 0, S_FLICKY_16_OUT}, // S_FLICKY_16_OUT {SPR_FL16, 1, 3, {A_FlickyFly}, 4*FRACUNIT, 8*FRACUNIT, S_FLICKY_16_FLAP2}, // S_FLICKY_16_FLAP1 {SPR_FL16, 2, 3, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP2 {SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1, 0, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP3 + {SPR_FL16, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_16_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_16, 384*FRACUNIT, S_FLICKY_16_CENTER}, // S_FLICKY_16_CENTER // Spider {SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, 0, S_SECRETFLICKY_01_OUT}, // S_SECRETFLICKY_01_OUT @@ -2767,12 +2799,16 @@ state_t states[NUMSTATES] = {SPR_FS01, 1, 1, {A_FlickyFlounder}, 2*FRACUNIT, 6*FRACUNIT, S_SECRETFLICKY_01_UP}, // S_SECRETFLICKY_01_HOP {SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP}, // S_SECRETFLICKY_01_UP {SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, 0, S_SECRETFLICKY_01_DOWN}, // S_SECRETFLICKY_01_DOWN + {SPR_FS01, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_SECRETFLICKY_01_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_01, 384*FRACUNIT, S_SECRETFLICKY_01_CENTER}, // S_SECRETFLICKY_01_CENTER // Bat {SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT}, // S_SECRETFLICKY_02_OUT {SPR_FS02, 1, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP2}, // S_SECRETFLICKY_02_FLAP1 {SPR_FS02, 2, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP3}, // S_SECRETFLICKY_02_FLAP2 {SPR_FS02, 3, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP1}, // S_SECRETFLICKY_02_FLAP3 + {SPR_FS02, FF_ANIMATE|1, -1, {NULL}, 2, 2, S_NULL}, // S_SECRETFLICKY_02_STAND + {SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_02, 384*FRACUNIT, S_SECRETFLICKY_02_CENTER}, // S_SECRETFLICKY_02_CENTER // Fan {SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2}, // S_FAN @@ -3422,8 +3458,8 @@ state_t states[NUMSTATES] = {SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT {SPR_FMCE, 0, 4, {A_ZThrust}, 4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1 - {SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE1 - {SPR_FMCE, 0, 2, {A_ZThrust}, -6, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL + {SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE2 + {SPR_FMCE, 0, 2, {A_ZThrust}, -6, 1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL {SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1 {SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2 {SPR_FMCE, 1, 2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1 @@ -13747,7 +13783,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = -1, // doomednum S_FLICKY_01_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_01_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13770,11 +13806,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_01_CENTER + 2200, // doomednum + S_FLICKY_01_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_02 -1, // doomednum S_FLICKY_02_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_02_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13797,11 +13860,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_02_CENTER + 2201, // doomednum + S_FLICKY_02_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_03 -1, // doomednum S_FLICKY_03_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_03_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13824,11 +13914,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_03_CENTER + 2202, // doomednum + S_FLICKY_03_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_04 -1, // doomednum S_FLICKY_04_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_04_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13851,9 +13968,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_FLICKY_05 - -1, // doomednum - S_FLICKY_05_OUT, // spawnstate + { // MT_FLICKY_04_CENTER + 2203, // doomednum + S_FLICKY_04_CENTER, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -13874,15 +13991,69 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_FLICKY_05 + -1, // doomednum + S_FLICKY_05_OUT, // spawnstate + 1000, // spawnhealth + S_FLICKY_05_STAND, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound MF_NOCLIPTHING, // flags S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_05_CENTER + 2204, // doomednum + S_FLICKY_05_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_06 -1, // doomednum S_FLICKY_06_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_06_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13905,11 +14076,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_06_CENTER + 2205, // doomednum + S_FLICKY_06_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_07 -1, // doomednum S_FLICKY_07_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_07_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13932,11 +14130,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_FLICKY_07_CENTER + 2206, // doomednum + S_FLICKY_07_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_08 -1, // doomednum S_FLICKY_08_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_08_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -13959,9 +14184,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_FLICKY_09 - -1, // doomednum - S_FLICKY_09_OUT, // spawnstate + { // MT_FLICKY_08_CENTER + 2207, // doomednum + S_FLICKY_08_CENTER, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -13982,15 +14207,69 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_FLICKY_09 + -1, // doomednum + S_FLICKY_09_OUT, // spawnstate + 1000, // spawnhealth + S_FLICKY_09_STAND, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound MF_NOCLIPTHING, // flags S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_09_CENTER + 2208, // doomednum + S_FLICKY_09_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_10 -1, // doomednum S_FLICKY_10_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_10_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14013,11 +14292,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_10_CENTER + 2209, // doomednum + S_FLICKY_10_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_11 -1, // doomednum S_FLICKY_11_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_11_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14040,11 +14346,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_11_CENTER + 2210, // doomednum + S_FLICKY_11_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_12 -1, // doomednum S_FLICKY_12_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_12_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14067,11 +14400,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_12_CENTER + 2211, // doomednum + S_FLICKY_12_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_13 -1, // doomednum S_FLICKY_13_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_13_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14094,11 +14454,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_13_CENTER + 2212, // doomednum + S_FLICKY_13_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_14 -1, // doomednum S_FLICKY_14_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_14_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14121,11 +14508,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_14_CENTER + 2213, // doomednum + S_FLICKY_14_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_15 -1, // doomednum S_FLICKY_15_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_15_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14148,11 +14562,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_15_CENTER + 2214, // doomednum + S_FLICKY_15_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_FLICKY_16 -1, // doomednum S_FLICKY_16_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_FLICKY_16_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14175,11 +14616,38 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_FLICKY_16_CENTER + 2215, // doomednum + S_FLICKY_16_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_SECRETFLICKY_01 -1, // doomednum S_SECRETFLICKY_01_OUT, // spawnstate 1000, // spawnhealth - S_NULL, // seestate + S_SECRETFLICKY_01_STAND, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -14202,9 +14670,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, - { // MT_SECRETFLICKY_02 - -1, // doomednum - S_SECRETFLICKY_02_OUT, // spawnstate + { // MT_SECRETFLICKY_01_CENTER + 2216, // doomednum + S_SECRETFLICKY_01_CENTER, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -14225,10 +14693,64 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_SECRETFLICKY_02 + -1, // doomednum + S_SECRETFLICKY_02_OUT, // spawnstate + 1000, // spawnhealth + S_SECRETFLICKY_02_STAND, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound MF_NOCLIPTHING, // flags S_FLICKY_BUBBLE // raisestate }, + { // MT_SECRETFLICKY_02_CENTER + 2217, // doomednum + S_SECRETFLICKY_02_CENTER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_SEED -1, // doomednum S_SEED, // spawnstate diff --git a/src/info.h b/src/info.h index 89bfd3504..b757deec0 100644 --- a/src/info.h +++ b/src/info.h @@ -216,6 +216,7 @@ void A_BrakLobShot(); void A_NapalmScatter(); void A_SpawnFreshCopy(); void A_FlickySpawn(); +void A_FlickyCenter(); void A_FlickyAim(); void A_FlickyFly(); void A_FlickySoar(); @@ -2748,6 +2749,8 @@ typedef enum state S_FLICKY_01_FLAP1, S_FLICKY_01_FLAP2, S_FLICKY_01_FLAP3, + S_FLICKY_01_STAND, + S_FLICKY_01_CENTER, // Rabbit S_FLICKY_02_OUT, @@ -2755,6 +2758,8 @@ typedef enum state S_FLICKY_02_HOP, S_FLICKY_02_UP, S_FLICKY_02_DOWN, + S_FLICKY_02_STAND, + S_FLICKY_02_CENTER, // Chicken S_FLICKY_03_OUT, @@ -2763,6 +2768,8 @@ typedef enum state S_FLICKY_03_UP, S_FLICKY_03_FLAP1, S_FLICKY_03_FLAP2, + S_FLICKY_03_STAND, + S_FLICKY_03_CENTER, // Seal S_FLICKY_04_OUT, @@ -2774,6 +2781,8 @@ typedef enum state S_FLICKY_04_SWIM2, S_FLICKY_04_SWIM3, S_FLICKY_04_SWIM4, + S_FLICKY_04_STAND, + S_FLICKY_04_CENTER, // Pig S_FLICKY_05_OUT, @@ -2781,6 +2790,8 @@ typedef enum state S_FLICKY_05_HOP, S_FLICKY_05_UP, S_FLICKY_05_DOWN, + S_FLICKY_05_STAND, + S_FLICKY_05_CENTER, // Chipmunk S_FLICKY_06_OUT, @@ -2788,6 +2799,8 @@ typedef enum state S_FLICKY_06_HOP, S_FLICKY_06_UP, S_FLICKY_06_DOWN, + S_FLICKY_06_STAND, + S_FLICKY_06_CENTER, // Penguin S_FLICKY_07_OUT, @@ -2802,6 +2815,8 @@ typedef enum state S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM2, S_FLICKY_07_SWIM3, + S_FLICKY_07_STAND, + S_FLICKY_07_CENTER, // Fish S_FLICKY_08_OUT, @@ -2815,6 +2830,8 @@ typedef enum state S_FLICKY_08_SWIM2, S_FLICKY_08_SWIM3, S_FLICKY_08_SWIM4, + S_FLICKY_08_STAND, + S_FLICKY_08_CENTER, // Ram S_FLICKY_09_OUT, @@ -2822,11 +2839,15 @@ typedef enum state S_FLICKY_09_HOP, S_FLICKY_09_UP, S_FLICKY_09_DOWN, + S_FLICKY_09_STAND, + S_FLICKY_09_CENTER, // Puffin S_FLICKY_10_OUT, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP2, + S_FLICKY_10_STAND, + S_FLICKY_10_CENTER, // Cow S_FLICKY_11_OUT, @@ -2834,6 +2855,8 @@ typedef enum state S_FLICKY_11_RUN1, S_FLICKY_11_RUN2, S_FLICKY_11_RUN3, + S_FLICKY_11_STAND, + S_FLICKY_11_CENTER, // Rat S_FLICKY_12_OUT, @@ -2841,6 +2864,8 @@ typedef enum state S_FLICKY_12_RUN1, S_FLICKY_12_RUN2, S_FLICKY_12_RUN3, + S_FLICKY_12_STAND, + S_FLICKY_12_CENTER, // Bear S_FLICKY_13_OUT, @@ -2848,12 +2873,16 @@ typedef enum state S_FLICKY_13_HOP, S_FLICKY_13_UP, S_FLICKY_13_DOWN, + S_FLICKY_13_STAND, + S_FLICKY_13_CENTER, // Dove S_FLICKY_14_OUT, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP2, S_FLICKY_14_FLAP3, + S_FLICKY_14_STAND, + S_FLICKY_14_CENTER, // Cat S_FLICKY_15_OUT, @@ -2861,12 +2890,16 @@ typedef enum state S_FLICKY_15_HOP, S_FLICKY_15_UP, S_FLICKY_15_DOWN, + S_FLICKY_15_STAND, + S_FLICKY_15_CENTER, // Canary S_FLICKY_16_OUT, S_FLICKY_16_FLAP1, S_FLICKY_16_FLAP2, S_FLICKY_16_FLAP3, + S_FLICKY_16_STAND, + S_FLICKY_16_CENTER, // Spider S_SECRETFLICKY_01_OUT, @@ -2874,12 +2907,16 @@ typedef enum state S_SECRETFLICKY_01_HOP, S_SECRETFLICKY_01_UP, S_SECRETFLICKY_01_DOWN, + S_SECRETFLICKY_01_STAND, + S_SECRETFLICKY_01_CENTER, // Bat S_SECRETFLICKY_02_OUT, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP2, S_SECRETFLICKY_02_FLAP3, + S_SECRETFLICKY_02_STAND, + S_SECRETFLICKY_02_CENTER, // Fan S_FAN, @@ -4098,23 +4135,41 @@ typedef enum mobj_type // Flickies MT_FLICKY_01, // Bluebird + MT_FLICKY_01_CENTER, MT_FLICKY_02, // Rabbit + MT_FLICKY_02_CENTER, MT_FLICKY_03, // Chicken + MT_FLICKY_03_CENTER, MT_FLICKY_04, // Seal + MT_FLICKY_04_CENTER, MT_FLICKY_05, // Pig + MT_FLICKY_05_CENTER, MT_FLICKY_06, // Chipmunk + MT_FLICKY_06_CENTER, MT_FLICKY_07, // Penguin + MT_FLICKY_07_CENTER, MT_FLICKY_08, // Fish + MT_FLICKY_08_CENTER, MT_FLICKY_09, // Ram + MT_FLICKY_09_CENTER, MT_FLICKY_10, // Puffin + MT_FLICKY_10_CENTER, MT_FLICKY_11, // Cow + MT_FLICKY_11_CENTER, MT_FLICKY_12, // Rat + MT_FLICKY_12_CENTER, MT_FLICKY_13, // Bear + MT_FLICKY_13_CENTER, MT_FLICKY_14, // Dove + MT_FLICKY_14_CENTER, MT_FLICKY_15, // Cat + MT_FLICKY_15_CENTER, MT_FLICKY_16, // Canary + MT_FLICKY_16_CENTER, MT_SECRETFLICKY_01, // Spider + MT_SECRETFLICKY_01_CENTER, MT_SECRETFLICKY_02, // Bat + MT_SECRETFLICKY_02_CENTER, MT_SEED, // Environmental Effects diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c1fd87af3..ce017620c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1809,9 +1809,11 @@ static int lib_pFadeLight(lua_State *L) INT16 tag = (INT16)luaL_checkinteger(L, 1); INT32 destvalue = (INT32)luaL_checkinteger(L, 2); INT32 speed = (INT32)luaL_checkinteger(L, 3); + boolean ticbased = lua_optboolean(L, 4); + boolean force = lua_optboolean(L, 5); NOHUD INLEVEL - P_FadeLight(tag, destvalue, speed); + P_FadeLight(tag, destvalue, speed, ticbased, force); return 0; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 1583bd3c4..da0e99ab2 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -40,6 +40,8 @@ enum mobj_e { mobj_subsector, mobj_floorz, mobj_ceilingz, + mobj_floorrover, + mobj_ceilingrover, mobj_radius, mobj_height, mobj_momx, @@ -100,6 +102,8 @@ static const char *const mobj_opt[] = { "subsector", "floorz", "ceilingz", + "floorrover", + "ceilingrover", "radius", "height", "momx", @@ -208,6 +212,12 @@ static int mobj_get(lua_State *L) case mobj_ceilingz: lua_pushfixed(L, mo->ceilingz); break; + case mobj_floorrover: + LUA_PushUserdata(L, mo->floorrover, META_FFLOOR); + break; + case mobj_ceilingrover: + LUA_PushUserdata(L, mo->ceilingrover, META_FFLOOR); + break; case mobj_radius: lua_pushfixed(L, mo->radius); break; @@ -396,6 +406,8 @@ static int mobj_set(lua_State *L) P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; + mo->floorrover = tmfloorrover; + mo->ceilingrover = tmceilingrover; P_SetTarget(&tmthing, ptmthing); break; } @@ -430,6 +442,10 @@ static int mobj_set(lua_State *L) return NOSETPOS; case mobj_ceilingz: return NOSETPOS; + case mobj_floorrover: + return NOSET; + case mobj_ceilingrover: + return NOSET; case mobj_radius: { mobj_t *ptmthing = tmthing; @@ -439,6 +455,8 @@ static int mobj_set(lua_State *L) P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; + mo->floorrover = tmfloorrover; + mo->ceilingrover = tmceilingrover; P_SetTarget(&tmthing, ptmthing); break; } @@ -451,6 +469,8 @@ static int mobj_set(lua_State *L) P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; + mo->floorrover = tmfloorrover; + mo->ceilingrover = tmceilingrover; P_SetTarget(&tmthing, ptmthing); break; } diff --git a/src/lua_script.c b/src/lua_script.c index d5736f9e5..3225e332a 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -193,25 +193,27 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) { MYFILE f; char *name; - + size_t len; f.wad = wad; f.size = W_LumpLengthPwad(wad, lump); f.data = Z_Malloc(f.size, PU_LUA, NULL); W_ReadLumpPwad(wad, lump, f.data); f.curpos = f.data; + len = strlen(wadfiles[wad]->filename); // length of file name + if (wadfiles[wad]->type == RET_LUA) { - name = malloc(strlen(wadfiles[wad]->filename)+1); + name = malloc(len+1); strcpy(name, wadfiles[wad]->filename); } else // If it's not a .lua file, copy the lump name in too. { lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump]; - size_t length = strlen(wadfiles[wad]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name - name = malloc(length + 1); + len += 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + name = malloc(len+1); sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2); - name[length] = '\0'; + name[len] = '\0'; } LUA_LoadFile(&f, name); // actually load file! diff --git a/src/m_anigif.c b/src/m_anigif.c index 6ae112ea8..4ebf2aff3 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -497,7 +497,9 @@ static void GIF_framewrite(void) // screen regions are handled in GIF_lzw { - UINT16 delay = 3; // todo + int d1 = (int)((100.0/NEWTICRATE)*(gif_frames+1)); + int d2 = (int)((100.0/NEWTICRATE)*(gif_frames)); + UINT16 delay = d1-d2; INT32 startline; WRITEMEM(p, gifframe_gchead, 4); diff --git a/src/m_menu.c b/src/m_menu.c index 41fb1319d..69c609db0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9380,7 +9380,7 @@ static void M_SoundMenu(INT32 choice) { (void)choice; - OP_SoundOptionsMenu[6].status = ((nosound || sound_disabled) ? IT_GRAYEDOUT : (IT_STRING | IT_CVAR)); + OP_SoundOptionsMenu[6].status = (sound_disabled ? IT_GRAYEDOUT : (IT_STRING | IT_CVAR)); M_SetupNextMenu(&OP_SoundOptionsDef); } @@ -9393,25 +9393,25 @@ void M_DrawSoundMenu(void) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y+currentMenu->menuitems[0].alphaKey, - (nosound ? V_REDMAP : V_YELLOWMAP), - ((nosound || sound_disabled) ? offstring : onstring)); + (sound_disabled ? V_REDMAP : V_YELLOWMAP), + (sound_disabled ? offstring : onstring)); V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y+currentMenu->menuitems[2].alphaKey, - (nodigimusic ? V_REDMAP : V_YELLOWMAP), - ((nodigimusic || digital_disabled) ? offstring : onstring)); + (digital_disabled ? V_REDMAP : V_YELLOWMAP), + (digital_disabled ? offstring : onstring)); V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y+currentMenu->menuitems[4].alphaKey, - (nomidimusic ? V_REDMAP : V_YELLOWMAP), - ((nomidimusic || music_disabled) ? offstring : onstring)); + (midi_disabled ? V_REDMAP : V_YELLOWMAP), + (midi_disabled ? offstring : onstring)); if (itemOn == 0) - lengthstring = ((nosound || sound_disabled) ? 3 : 2); + lengthstring = (sound_disabled ? 3 : 2); else if (itemOn == 2) - lengthstring = ((nodigimusic || digital_disabled) ? 3 : 2); + lengthstring = (digital_disabled ? 3 : 2); else if (itemOn == 4) - lengthstring = ((nomidimusic || music_disabled) ? 3 : 2); + lengthstring = (midi_disabled ? 3 : 2); else return; @@ -9446,32 +9446,20 @@ static void M_ToggleSFX(INT32 choice) break; } - if (nosound) + if (sound_disabled) { - nosound = false; - I_StartupSound(); - if (nosound) return; - S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); + sound_disabled = false; + S_InitSfxChannels(cv_soundvolume.value); S_StartSound(NULL, sfx_strpst); OP_SoundOptionsMenu[6].status = IT_STRING | IT_CVAR; //M_StartMessage(M_GetText("SFX Enabled\n"), NULL, MM_NOTHING); } else { - if (sound_disabled) - { - sound_disabled = false; - S_StartSound(NULL, sfx_strpst); - OP_SoundOptionsMenu[6].status = IT_STRING | IT_CVAR; - //M_StartMessage(M_GetText("SFX Enabled\n"), NULL, MM_NOTHING); - } - else - { - sound_disabled = true; - S_StopSounds(); - OP_SoundOptionsMenu[6].status = IT_GRAYEDOUT; - //M_StartMessage(M_GetText("SFX Disabled\n"), NULL, MM_NOTHING); - } + sound_disabled = true; + S_StopSounds(); + OP_SoundOptionsMenu[6].status = IT_GRAYEDOUT; + //M_StartMessage(M_GetText("SFX Disabled\n"), NULL, MM_NOTHING); } } @@ -9499,12 +9487,10 @@ static void M_ToggleDigital(INT32 choice) break; } - if (nodigimusic) + if (digital_disabled) { - nodigimusic = false; - I_InitDigMusic(); - if (nodigimusic) return; - S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); + digital_disabled = false; + I_InitMusic(); S_StopMusic(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); @@ -9514,21 +9500,27 @@ static void M_ToggleDigital(INT32 choice) } else { - if (digital_disabled) + digital_disabled = true; + if (S_MusicType() != MU_MID) { - digital_disabled = false; - if (Playing()) - P_RestoreMusic(&players[consoleplayer]); + if (midi_disabled) + S_StopMusic(); else - S_ChangeMusicInternal("_clear", false); - //M_StartMessage(M_GetText("Digital Music Enabled\n"), NULL, MM_NOTHING); - } - else - { - digital_disabled = true; - S_StopMusic(); - //M_StartMessage(M_GetText("Digital Music Disabled\n"), NULL, MM_NOTHING); + { + char mmusic[7]; + UINT16 mflags; + boolean looping; + + if (S_MusicInfo(mmusic, &mflags, &looping) && S_MIDIExists(mmusic)) + { + S_StopMusic(); + S_ChangeMusic(mmusic, mflags, looping); + } + else + S_StopMusic(); + } } + //M_StartMessage(M_GetText("Digital Music Disabled\n"), NULL, MM_NOTHING); } } @@ -9546,6 +9538,12 @@ static void M_ToggleMIDI(INT32 choice) itemOn--; return; + case KEY_LEFTARROW: + case KEY_RIGHTARROW: + if (S_MusicType() != MU_MID && S_MusicType() != MU_NONE) + S_StartSound(NULL, sfx_menu1); + break; + case KEY_ESCAPE: if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); @@ -9555,13 +9553,10 @@ static void M_ToggleMIDI(INT32 choice) default: break; } - - if (nomidimusic) + if (midi_disabled) { - nomidimusic = false; - I_InitMIDIMusic(); - if (nomidimusic) return; - S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); + midi_disabled = false; + I_InitMusic(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); else @@ -9570,21 +9565,27 @@ static void M_ToggleMIDI(INT32 choice) } else { - if (music_disabled) + midi_disabled = true; + if (S_MusicType() == MU_MID) { - music_disabled = false; - if (Playing()) - P_RestoreMusic(&players[consoleplayer]); + if (digital_disabled) + S_StopMusic(); else - S_ChangeMusicInternal("_clear", false); - //M_StartMessage(M_GetText("MIDI Music Enabled\n"), NULL, MM_NOTHING); - } - else - { - music_disabled = true; - S_StopMusic(); - //M_StartMessage(M_GetText("MIDI Music Disabled\n"), NULL, MM_NOTHING); + { + char mmusic[7]; + UINT16 mflags; + boolean looping; + + if (S_MusicInfo(mmusic, &mflags, &looping) && S_DigExists(mmusic)) + { + S_StopMusic(); + S_ChangeMusic(mmusic, mflags, looping); + } + else + S_StopMusic(); + } } + //M_StartMessage(M_GetText("MIDI Music Disabled\n"), NULL, MM_NOTHING); } } diff --git a/src/p_enemy.c b/src/p_enemy.c index 52044dfae..8088c20a8 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -243,6 +243,7 @@ void A_BrakLobShot(mobj_t *actor); void A_NapalmScatter(mobj_t *actor); void A_SpawnFreshCopy(mobj_t *actor); void A_FlickySpawn(mobj_t *actor); +void A_FlickyCenter(mobj_t *actor); void A_FlickyAim(mobj_t *actor); void A_FlickyFly(mobj_t *actor); void A_FlickySoar(mobj_t *actor); @@ -10774,6 +10775,145 @@ void A_FlickySpawn(mobj_t *actor) P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true); } +// Internal Flicky color setting +void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo) +{ + UINT8 flickycolors[] = { + SKINCOLOR_RED, + SKINCOLOR_CYAN, + SKINCOLOR_BLUE, + SKINCOLOR_VAPOR, + SKINCOLOR_PURPLE, + SKINCOLOR_BUBBLEGUM, + SKINCOLOR_NEON, + SKINCOLOR_BLACK, + SKINCOLOR_BEIGE, + SKINCOLOR_LAVENDER, + SKINCOLOR_RUBY, + SKINCOLOR_SALMON, + SKINCOLOR_SUNSET, + SKINCOLOR_ORANGE, + SKINCOLOR_YELLOW, + }; + + if (extrainfo == 0) + // until we can customize flicky colors by level header, just stick to SRB2's defaults + actor->color = flickycolors[P_RandomKey(2)]; //flickycolors[P_RandomKey(sizeof(flickycolors))]; + else + actor->color = flickycolors[min(extrainfo-1, 14)]; // sizeof(flickycolors)-1 +} + +// Function: A_FlickyCenter +// +// Description: Place flickies in-level. +// +// var1: +// Lower 16 bits = if 0, spawns random flicky based on level header. Else, spawns the designated thing type. +// Bits 17-20 = Flicky color, up to 15. Applies to fish. +// Bit 21 = Flag MF_SLIDEME (see below) +// Bit 22 = Flag MF_GRENADEBOUNCE (see below) +// Bit 23 = Flag MF_NOCLIPTHING (see below) +// +// If actor is placed from a spawnpoint (map Thing), the Thing's properties take precedence. +// +// var2 = maximum default distance away from spawn the flickies are allowed to travel. If angle != 0, then that's the radius. +// +// If MTF_EXTRA (MF_SLIDEME): is flagged, Flickies move aimlessly. Else, orbit around the target. +// If MTF_OBJECTSPECIAL (MF_GRENADEBOUNCE): Flickies stand in-place without gravity (unless they hop, then gravity is applied.) +// If MTF_AMBUSH (MF_NOCLIPTHING): is flagged, Flickies hop. +// +void A_FlickyCenter(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + UINT16 flickytype = (locvar1 & 0xFFFF); + UINT8 flickycolor = ((locvar1 >> 16) & 0xFF); + UINT8 flickyflags = ((locvar1 >> 20) & 0xF); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCenter", actor)) + return; +#endif + + if (!actor->tracer) + { + mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false); + P_SetTarget(&flicky->target, actor); + P_SetTarget(&actor->tracer, flicky); + + if (actor->spawnpoint) + { + actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING); + actor->flags |= ( + ((actor->spawnpoint->options & MTF_EXTRA) ? MF_SLIDEME : 0) + | ((actor->spawnpoint->options & MTF_OBJECTSPECIAL) ? MF_GRENADEBOUNCE : 0) + | ((actor->spawnpoint->options & MTF_AMBUSH) ? MF_NOCLIPTHING : 0) + ); + actor->extravalue1 = actor->spawnpoint->angle ? abs(actor->spawnpoint->angle) * FRACUNIT + : locvar2 ? abs(locvar2) : 384 * FRACUNIT; + actor->extravalue2 = actor->spawnpoint->extrainfo; + actor->friction = actor->spawnpoint->x*FRACUNIT; + actor->movefactor = actor->spawnpoint->y*FRACUNIT; + actor->watertop = actor->spawnpoint->z*FRACUNIT; + } + else + { + actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING); + actor->flags |= ( + ((flickyflags & 1) ? MF_SLIDEME : 0) + | ((flickyflags & 2) ? MF_GRENADEBOUNCE : 0) + | ((flickyflags & 4) ? MF_NOCLIPTHING : 0) + ); + actor->extravalue1 = abs(locvar2); + actor->extravalue2 = flickycolor; + actor->friction = actor->x; + actor->movefactor = actor->y; + actor->watertop = actor->z; + locvar1 = flickytype; + } + + if (actor->flags & MF_GRENADEBOUNCE) // in-place + actor->tracer->fuse = 0; + else if (actor->flags & MF_SLIDEME) // aimless + { + actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly. + actor->tracer->angle = P_RandomKey(180)*ANG2; + } + else //orbit + actor->tracer->fuse = FRACUNIT; + + if (locvar1 == MT_FLICKY_08) + P_InternalFlickySetColor(actor->tracer, actor->extravalue2); + + actor->extravalue2 = 0; + } + + if (!(actor->flags & MF_SLIDEME) && !(actor->flags & MF_GRENADEBOUNCE)) + { + fixed_t originx = actor->friction; + fixed_t originy = actor->movefactor; + fixed_t originz = actor->watertop; + + actor->tracer->fuse = FRACUNIT; + + // Impose default home radius if flicky orbits around player + if (!actor->extravalue1) + actor->extravalue1 = locvar2 ? abs(locvar2) : 384 * FRACUNIT; + + P_LookForPlayers(actor, true, false, actor->extravalue1); + + if (actor->target && P_AproxDistance(actor->target->x - originx, actor->target->y - originy) < actor->extravalue1) + { + actor->extravalue2 = 1; + P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z); + } + else if(actor->extravalue2) + { + actor->extravalue2 = 0; + P_TeleportMove(actor, originx, originy, originz); + } + } +} + // Internal Flicky bubbling function. void P_InternalFlickyBubble(mobj_t *actor) { @@ -10816,7 +10956,10 @@ void A_FlickyAim(mobj_t *actor) return; #endif - if (actor->momx == actor->momy && actor->momy == 0) + if ((actor->momx == actor->momy && actor->momy == 0) + || (actor->target && P_IsFlickyCenter(actor->target->type) + && actor->target->extravalue1 && (actor->target->flags & MF_SLIDEME) + && P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) >= actor->target->extravalue1)) flickyhitwall = true; P_InternalFlickyBubble(actor); @@ -10848,7 +10991,10 @@ void A_FlickyAim(mobj_t *actor) } else if (flickyhitwall) { - actor->angle += ANGLE_180; + if (actor->target && P_IsFlickyCenter(actor->target->type)) + actor->angle = R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + P_RandomRange(112, 248) * ANG1; + else + actor->angle += P_RandomRange(112, 248)*ANG1; actor->threshold = 0; } } @@ -10884,7 +11030,13 @@ void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fi if (actor->target && abs(chasez - actor->z) > targetdist) targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK; + if (actor->target + && P_IsFlickyCenter(actor->target->type) + && (actor->target->flags & MF_SLIDEME)) + vertangle = 0; + else + vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK; + P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed)); actor->momz = FixedMul(FINESINE(vertangle), flyspeed); } @@ -11036,7 +11188,19 @@ void A_FlickyCheck(mobj_t *actor) if (LUA_CallAction("A_FlickyCheck", actor)) return; #endif - if (locvar2 && P_MobjFlip(actor)*actor->momz < 1) + if (actor->target + && P_IsFlickyCenter(actor->target->type) + && (actor->target->flags & MF_GRENADEBOUNCE)) + { + if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping + { + actor->momz = 0; + actor->flags |= MF_NOGRAVITY; + } + actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY; + P_SetMobjState(actor, mobjinfo[actor->type].seestate); + } + else if (locvar2 && P_MobjFlip(actor)*actor->momz < 1) P_SetMobjState(actor, locvar2); else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))) @@ -11061,7 +11225,19 @@ void A_FlickyHeightCheck(mobj_t *actor) if (LUA_CallAction("A_FlickyHeightCheck", actor)) return; #endif - if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1 + if (actor->target + && P_IsFlickyCenter(actor->target->type) + && (actor->target->flags & MF_GRENADEBOUNCE)) + { + if (!(actor->target->flags & MF_NOCLIPTHING)) // no hopping + { + actor->momz = 0; + actor->flags |= MF_NOGRAVITY; + } + actor->flags |= MF_NOCLIP | MF_NOBLOCKMAP | MF_SCENERY; + P_SetMobjState(actor, mobjinfo[actor->type].seestate); + } + else if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1 && ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2) || (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz))) P_SetMobjState(actor, locvar1); @@ -11636,4 +11812,4 @@ void A_CheckFlags2(mobj_t *actor) if (actor->flags2 & locvar1) P_SetMobjState(actor, (statenum_t)locvar2); -} \ No newline at end of file +} diff --git a/src/p_floor.c b/src/p_floor.c index 0e28b831f..8f1afaeba 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1839,6 +1839,7 @@ void T_ThwompSector(levelspecthink_t *thwomp) #define ceilingwasheight vars[5] fixed_t thwompx, thwompy; sector_t *actionsector; + ffloor_t *rover = NULL; INT32 secnum; // If you just crashed down, wait a second before coming back up. @@ -1853,7 +1854,16 @@ void T_ThwompSector(levelspecthink_t *thwomp) secnum = P_FindSectorFromTag((INT16)thwomp->vars[0], -1); if (secnum > 0) + { actionsector = §ors[secnum]; + + // Look for thwomp FFloor + for (rover = actionsector->ffloors; rover; rover = rover->next) + { + if (rover->master == thwomp->sourceline) + break; + } + } else return; // Bad bad bad! @@ -1942,10 +1952,13 @@ void T_ThwompSector(levelspecthink_t *thwomp) { mobj_t *mp = (void *)&actionsector->soundorg; - if (thwomp->sourceline->flags & ML_EFFECT4) - S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS); - else - S_StartSound(mp, sfx_thwomp); + if (!rover || (rover->flags & FF_EXISTS)) + { + if (thwomp->sourceline->flags & ML_EFFECT4) + S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS); + else + S_StartSound(mp, sfx_thwomp); + } thwomp->direction = 1; // start heading back up thwomp->distance = TICRATE; // but only after a small delay @@ -1959,18 +1972,22 @@ void T_ThwompSector(levelspecthink_t *thwomp) thinker_t *th; mobj_t *mo; - // scan the thinkers to find players! - for (th = thinkercap.next; th != &thinkercap; th = th->next) + if (!rover || (rover->flags & FF_EXISTS)) { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo = (mobj_t *)th; - if (mo->type == MT_PLAYER && mo->health && mo->z <= thwomp->sector->ceilingheight - && P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT) + // scan the thinkers to find players! + for (th = thinkercap.next; th != &thinkercap; th = th->next) { - thwomp->direction = -1; - break; + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator + && mo->z <= thwomp->sector->ceilingheight + && P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT) + { + thwomp->direction = -1; + break; + } } } diff --git a/src/p_inter.c b/src/p_inter.c index 9a05bae28..63abf4c0e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3313,12 +3313,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else if (player->powers[pw_carry] == CR_NIGHTSFALL) { - if (player->spheres > 0) - { - damage = player->spheres; - P_RingDamage(player, inflictor, source, damage, damagetype, true); - damage = 0; - } + // always damage so we can recoil upon losing points + damage = player->spheres; + P_RingDamage(player, inflictor, source, damage, damagetype, true); + damage = 0; } else if (player->rings > 0) // No shield but have rings. { diff --git a/src/p_lights.c b/src/p_lights.c index 8aa2eedca..c0b46f74c 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -23,7 +23,7 @@ * * \param sector The sector to remove effects from. */ -static void P_RemoveLighting(sector_t *sector) +void P_RemoveLighting(sector_t *sector) { if (sector->lightingdata) { @@ -322,39 +322,70 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, return g; } -/** Fades all the lights in sectors with a particular tag to a new +/** Fades all the lights in specified sector to a new * value. * - * \param tag Tag to look for sectors by. + * \param sector Target sector * \param destvalue The final light value in these sectors. - * \param speed Speed of the fade; the change to the ligh + * \param speed If tic-based: total duration of effect. + * If speed-based: Speed of the fade; the change to the ligh * level in each sector per tic. - * \todo Calculate speed better so that it is possible to specify - * the time for completion of the fade, and all lights fade - * in this time regardless of initial values. + * \param ticbased Use a specific duration for the fade, defined by speed * \sa T_LightFade */ -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed) +void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean ticbased) +{ + lightlevel_t *ll; + + P_RemoveLighting(sector); // remove the old lighting effect first + + if ((ticbased && !speed) || sector->lightlevel == destvalue) // set immediately + { + sector->lightlevel = destvalue; + return; + } + + ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL); + ll->thinker.function.acp1 = (actionf_p1)T_LightFade; + sector->lightingdata = ll; // set it to the lightlevel_t + + P_AddThinker(&ll->thinker); // add thinker + + ll->sector = sector; + ll->sourcelevel = sector->lightlevel; + ll->destlevel = destvalue; + + ll->fixedcurlevel = sector->lightlevel<timer = abs(speed); + ll->fixedpertic = FixedDiv((destvalue<fixedcurlevel, speed<timer = FixedDiv((destvalue<fixedcurlevel, speed<>FRACBITS; + ll->fixedpertic = speed<= 0 ;) { - sector = §ors[i]; - - P_RemoveLighting(sector); // remove the old lighting effect first - ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL); - ll->thinker.function.acp1 = (actionf_p1)T_LightFade; - sector->lightingdata = ll; // set it to the lightlevel_t - - P_AddThinker(&ll->thinker); // add thinker - - ll->sector = sector; - ll->destlevel = destvalue; - ll->speed = speed; + if (!force && ticbased // always let speed fader execute + && sectors[i].lightingdata + && ((lightlevel_t*)sectors[i].lightingdata)->thinker.function.acp1 == (actionf_p1)T_LightFade) + // && ((lightlevel_t*)sectors[i].lightingdata)->timer > 2) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 420 Executor: Fade light thinker already exists, timer: %d\n", ((lightlevel_t*)sectors[i].lightingdata)->timer); + continue; + } + P_FadeLightBySector(§ors[i], destvalue, speed, ticbased); } } @@ -365,30 +396,13 @@ void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed) */ void T_LightFade(lightlevel_t *ll) { - if (ll->sector->lightlevel < ll->destlevel) + if (--ll->timer <= 0) { - // increase the lightlevel - if (ll->sector->lightlevel + ll->speed >= ll->destlevel) - { - // stop changing light level - ll->sector->lightlevel = (INT16)ll->destlevel; // set to dest lightlevel - - P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker - } - else - ll->sector->lightlevel = (INT16)(ll->sector->lightlevel + (INT16)ll->speed); // move lightlevel + ll->sector->lightlevel = ll->destlevel; // set to dest lightlevel + P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker + return; } - else - { - // decrease lightlevel - if (ll->sector->lightlevel - ll->speed <= ll->destlevel) - { - // stop changing light level - ll->sector->lightlevel = (INT16)ll->destlevel; // set to dest lightlevel - P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker - } - else - ll->sector->lightlevel = (INT16)(ll->sector->lightlevel - (INT16)ll->speed); // move lightlevel - } + ll->fixedcurlevel = ll->fixedcurlevel + ll->fixedpertic; + ll->sector->lightlevel = (ll->fixedcurlevel)>>FRACBITS; } diff --git a/src/p_local.h b/src/p_local.h index 682fb7b55..b98eeae1c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -311,6 +311,8 @@ void P_NewChaseDir(mobj_t *actor); boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist); mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers); +void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo); +#define P_IsFlickyCenter(type) (type > MT_FLICKY_01 && type < MT_SEED && (type - MT_FLICKY_01) % 2 ? 1 : 0) void P_InternalFlickyBubble(mobj_t *actor); void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez); void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle); @@ -324,6 +326,7 @@ void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angl extern boolean floatok; extern fixed_t tmfloorz; extern fixed_t tmceilingz; +extern ffloor_t *tmfloorrover, *tmceilingrover; extern mobj_t *tmfloorthing, *tmhitthing, *tmthing; extern camera_t *mapcampointer; extern fixed_t tmx; diff --git a/src/p_map.c b/src/p_map.c index f951621e2..648bb2bcc 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -52,6 +52,7 @@ fixed_t tmfloorz, tmceilingz; static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) +ffloor_t *tmfloorrover, *tmceilingrover; #ifdef ESLOPE pslope_t *tmfloorslope, *tmceilingslope; #endif @@ -101,6 +102,8 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; + thing->floorrover = tmfloorrover; + thing->ceilingrover = tmceilingrover; return true; } @@ -1417,6 +1420,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z + thing->height > tmfloorz) { tmfloorz = thing->z + thing->height; + tmfloorrover = NULL; #ifdef ESLOPE tmfloorslope = NULL; #endif @@ -1437,6 +1441,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; tmfloorz = tmceilingz = topz; // block while in air + tmceilingrover = NULL; #ifdef ESLOPE tmceilingslope = NULL; #endif @@ -1445,6 +1450,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) { tmceilingz = topz; + tmceilingrover = NULL; #ifdef ESLOPE tmceilingslope = NULL; #endif @@ -1461,6 +1467,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->z < tmceilingz) { tmceilingz = thing->z; + tmceilingrover = NULL; #ifdef ESLOPE tmceilingslope = NULL; #endif @@ -1481,6 +1488,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; tmfloorz = tmceilingz = topz; // block while in air + tmfloorrover = NULL; #ifdef ESLOPE tmfloorslope = NULL; #endif @@ -1489,6 +1497,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) { tmfloorz = topz; + tmfloorrover = NULL; #ifdef ESLOPE tmfloorslope = NULL; #endif @@ -1640,6 +1649,7 @@ static boolean PIT_CheckLine(line_t *ld) { tmceilingz = opentop; ceilingline = ld; + tmceilingrover = NULL; #ifdef ESLOPE tmceilingslope = opentopslope; #endif @@ -1648,6 +1658,7 @@ static boolean PIT_CheckLine(line_t *ld) if (openbottom > tmfloorz) { tmfloorz = openbottom; + tmfloorrover = NULL; #ifdef ESLOPE tmfloorslope = openbottomslope; #endif @@ -1729,6 +1740,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // will adjust them. tmfloorz = tmdropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; + tmfloorrover = NULL; + tmceilingrover = NULL; #ifdef ESLOPE tmfloorslope = newsubsec->sector->f_slope; tmceilingslope = newsubsec->sector->c_slope; @@ -1772,6 +1785,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { if (tmfloorz < topheight - sinklevel) { tmfloorz = topheight - sinklevel; + tmfloorrover = rover; #ifdef ESLOPE tmfloorslope = *rover->t_slope; #endif @@ -1781,6 +1795,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { if (tmceilingz > bottomheight + sinklevel) { tmceilingz = bottomheight + sinklevel; + tmceilingrover = rover; #ifdef ESLOPE tmceilingslope = *rover->b_slope; #endif @@ -1805,6 +1820,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { if (tmfloorz < thing->z) { tmfloorz = thing->z; + tmfloorrover = rover; #ifdef ESLOPE tmfloorslope = NULL; #endif @@ -1823,6 +1839,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) && !(rover->flags & FF_REVERSEPLATFORM)) { tmfloorz = tmdropoffz = topheight; + tmfloorrover = rover; #ifdef ESLOPE tmfloorslope = *rover->t_slope; #endif @@ -1832,6 +1849,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) && !(thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))) { tmceilingz = tmdrpoffceilz = bottomheight; + tmceilingrover = rover; #ifdef ESLOPE tmceilingslope = *rover->b_slope; #endif @@ -2328,6 +2346,8 @@ boolean PIT_PushableMoved(mobj_t *thing) mobj_t *oldthing = tmthing; line_t *oldceilline = ceilingline; line_t *oldblockline = blockingline; + ffloor_t *oldflrrover = tmfloorrover; + ffloor_t *oldceilrover = tmceilingrover; #ifdef ESLOPE pslope_t *oldfslope = tmfloorslope; pslope_t *oldcslope = tmceilingslope; @@ -2344,6 +2364,8 @@ boolean PIT_PushableMoved(mobj_t *thing) P_SetTarget(&tmthing, oldthing); ceilingline = oldceilline; blockingline = oldblockline; + tmfloorrover = oldflrrover; + tmceilingrover = oldceilrover; #ifdef ESLOPE tmfloorslope = oldfslope; tmceilingslope = oldcslope; @@ -2465,6 +2487,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep) { thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; + thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #ifdef ESLOPE @@ -2472,6 +2495,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) else if (tmceilingslope && tmceilingz < thingtop && thingtop - tmceilingz <= maxstep) { thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height; + thing->ceilingrover = tmceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #endif @@ -2479,6 +2503,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep) { thing->z = thing->floorz = tmfloorz; + thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #ifdef ESLOPE @@ -2486,6 +2511,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) else if (tmfloorslope && tmfloorz > thing->z && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; + thing->floorrover = tmfloorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } #endif @@ -2557,6 +2583,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; + thing->floorrover = tmfloorrover; + thing->ceilingrover = tmceilingrover; #ifdef ESLOPE if (!(thing->flags & MF_NOCLIPHEIGHT)) @@ -2637,6 +2665,8 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; + thing->floorrover = tmfloorrover; + thing->ceilingrover = tmceilingrover; thing->x = x; thing->y = y; @@ -2663,7 +2693,10 @@ static boolean P_ThingHeightClip(mobj_t *thing) { boolean floormoved; fixed_t oldfloorz = thing->floorz; + ffloor_t *oldfloorrover = thing->floorrover; + ffloor_t *oldceilingrover = thing->ceilingrover; boolean onfloor = P_IsObjectOnGround(thing);//(thing->z <= thing->floorz); + ffloor_t *rover = NULL; if (thing->flags & MF_NOCLIPHEIGHT) return true; @@ -2678,6 +2711,8 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; + thing->floorrover = tmfloorrover; + thing->ceilingrover = tmceilingrover; // Ugly hack?!?! As long as just ceilingz is the lowest, // you'll still get crushed, right? @@ -2686,16 +2721,23 @@ static boolean P_ThingHeightClip(mobj_t *thing) if (onfloor && !(thing->flags & MF_NOGRAVITY) && floormoved) { - if (thing->eflags & MFE_VERTICALFLIP) - thing->pmomz = thing->ceilingz - (thing->z + thing->height); - else - thing->pmomz = thing->floorz - thing->z; - thing->eflags |= MFE_APPLYPMOMZ; + rover = (thing->eflags & MFE_VERTICALFLIP) ? oldceilingrover : oldfloorrover; - if (thing->eflags & MFE_VERTICALFLIP) - thing->z = thing->ceilingz - thing->height; - else - thing->z = thing->floorz; + // Match the Thing's old floorz to an FOF and check for FF_EXISTS + // If ~FF_EXISTS, don't set mobj Z. + if (!rover || ((rover->flags & FF_EXISTS) && (rover->flags & FF_SOLID))) + { + if (thing->eflags & MFE_VERTICALFLIP) + thing->pmomz = thing->ceilingz - (thing->z + thing->height); + else + thing->pmomz = thing->floorz - thing->z; + thing->eflags |= MFE_APPLYPMOMZ; + + if (thing->eflags & MFE_VERTICALFLIP) + thing->z = thing->ceilingz - thing->height; + else + thing->z = thing->floorz; + } } else if (!tmfloorthing) { diff --git a/src/p_mobj.c b/src/p_mobj.c index bbe0080ff..717bb92b6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4059,7 +4059,8 @@ void P_RecalcPrecipInSector(sector_t *sector) // void P_NullPrecipThinker(precipmobj_t *mobj) { - (void)mobj; + //(void)mobj; + mobj->precipflags &= ~PCF_THUNK; } void P_SnowThinker(precipmobj_t *mobj) @@ -4079,25 +4080,26 @@ void P_RainThinker(precipmobj_t *mobj) { // cycle through states, // calling action functions at transitions - if (mobj->tics > 0 && --mobj->tics == 0) - { - // you can cycle through multiple states in a tic - if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) - return; // freed itself - } + if (mobj->tics <= 0) + return; + + if (--mobj->tics) + return; + + if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) + return; + + if (mobj->state != &states[S_RAINRETURN]) + return; + + mobj->z = mobj->ceilingz; + P_SetPrecipMobjState(mobj, S_RAIN1); - if (mobj->state == &states[S_RAINRETURN]) - { - mobj->z = mobj->ceilingz; - P_SetPrecipMobjState(mobj, S_RAIN1); - } return; } // adjust height - mobj->z += mobj->momz; - - if (mobj->z <= mobj->floorz) + if ((mobj->z += mobj->momz) <= mobj->floorz) { // no splashes on sky or bottomless pits if (mobj->precipflags & PCF_PIT) @@ -7119,6 +7121,34 @@ void P_MobjThinker(mobj_t *mobj) S_StartSound(flame, sfx_fire); } break; + case MT_FLICKY_01_CENTER: + case MT_FLICKY_02_CENTER: + case MT_FLICKY_03_CENTER: + case MT_FLICKY_04_CENTER: + case MT_FLICKY_05_CENTER: + case MT_FLICKY_06_CENTER: + case MT_FLICKY_07_CENTER: + case MT_FLICKY_08_CENTER: + case MT_FLICKY_09_CENTER: + case MT_FLICKY_10_CENTER: + case MT_FLICKY_11_CENTER: + case MT_FLICKY_12_CENTER: + case MT_FLICKY_13_CENTER: + case MT_FLICKY_14_CENTER: + case MT_FLICKY_15_CENTER: + case MT_FLICKY_16_CENTER: + case MT_SECRETFLICKY_01_CENTER: + case MT_SECRETFLICKY_02_CENTER: + if (mobj->tracer && (mobj->flags & MF_NOCLIPTHING) + && (mobj->flags & MF_GRENADEBOUNCE)) + // for now: only do this bounce routine if flicky is in-place. \todo allow in all movements + { + if (!(mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z <= mobj->tracer->floorz) + mobj->tracer->momz = 7*FRACUNIT; + else if ((mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z >= mobj->tracer->ceilingz - mobj->tracer->height) + mobj->tracer->momz = -7*FRACUNIT; + } + break; case MT_SEED: if (P_MobjFlip(mobj)*mobj->momz < mobj->info->speed) mobj->momz = P_MobjFlip(mobj)*mobj->info->speed; @@ -7999,6 +8029,8 @@ void P_MobjThinker(mobj_t *mobj) return; mobj->floorz = tmfloorz; mobj->ceilingz = tmceilingz; + mobj->floorrover = tmfloorrover; + mobj->ceilingrover = tmceilingrover; if ((mobj->eflags & MFE_UNDERWATER) && mobj->health > 0) { @@ -8517,6 +8549,8 @@ void P_SceneryThinker(mobj_t *mobj) return; mobj->floorz = tmfloorz; mobj->ceilingz = tmceilingz; + mobj->floorrover = tmfloorrover; + mobj->ceilingrover = tmceilingrover; } else { @@ -8599,6 +8633,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) #endif mobj->subsector->sector->ceilingheight; + mobj->floorrover = NULL; + mobj->ceilingrover = NULL; + // Tells MobjCheckWater that the water height was not set. mobj->watertop = INT32_MAX; @@ -8862,6 +8899,9 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype #endif mobj->subsector->sector->ceilingheight; + mobj->floorrover = NULL; + mobj->ceilingrover = NULL; + mobj->z = z; mobj->momz = mobjinfo[type].speed; @@ -8883,14 +8923,15 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; + mo->precipflags |= PCF_RAIN; + //mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; return mo; } static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; + //mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; return mo; } @@ -9197,7 +9238,7 @@ void P_PrecipitationEffects(void) if (!playeringame[displayplayer] || !players[displayplayer].mo) return; - if (nosound || sound_disabled) + if (sound_disabled) return; // Sound off? D'aw, no fun. if (players[displayplayer].mo->subsector->sector->ceilingpic == skyflatnum) diff --git a/src/p_mobj.h b/src/p_mobj.h index afab6fda6..5c0408e1b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -254,6 +254,10 @@ typedef enum { PCF_FOF = 4, // Above MOVING FOF (this means we need to keep floorz up to date...) PCF_MOVINGFOF = 8, + // Is rain. + PCF_RAIN = 16, + // Ran the thinker this tic. + PCF_THUNK = 32, } precipflag_t; // Map Object definition. typedef struct mobj_s @@ -282,6 +286,8 @@ typedef struct mobj_s // The closest interval over all contacted sectors (or things). fixed_t floorz; // Nearest floor below. fixed_t ceilingz; // Nearest ceiling above. + struct ffloor_s *floorrover; // FOF referred by floorz + struct ffloor_s *ceilingrover; // FOF referred by ceilingz // For movement checking. fixed_t radius; @@ -398,6 +404,8 @@ typedef struct precipmobj_s // The closest interval over all contacted sectors (or things). fixed_t floorz; // Nearest floor below. fixed_t ceilingz; // Nearest ceiling above. + struct ffloor_s *floorrover; // FOF referred by floorz + struct ffloor_s *ceilingrover; // FOF referred by ceilingz // For movement checking. fixed_t radius; // Fixed at 2*FRACUNIT diff --git a/src/p_polyobj.c b/src/p_polyobj.c index fd3237c9d..875210435 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -985,6 +985,8 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) P_CheckPosition(mo, mo->x + momx, mo->y + momy); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; + mo->floorrover = tmfloorrover; + mo->ceilingrover = tmceilingrover; } } @@ -2853,6 +2855,165 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) return 1; } +void T_PolyObjFade(polyfade_t *th) +{ + boolean stillfading = false; + polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); + + if (!po) +#ifdef RANGECHECK + I_Error("T_PolyObjFade: thinker has invalid id %d\n", th->polyObjNum); +#else + { + CONS_Debug(DBG_POLYOBJ, "T_PolyObjFade: thinker with invalid id %d removed.\n", th->polyObjNum); + P_RemoveThinkerDelayed(&th->thinker); + return; + } +#endif + + // check for displacement due to override and reattach when possible + if (po->thinker == NULL) + po->thinker = &th->thinker; + + stillfading = th->ticbased ? !(--(th->timer) <= 0) + : !((th->timer -= th->duration) <= 0); + + if (th->timer <= 0) + { + po->translucency = max(min(th->destvalue, NUMTRANSMAPS), 0); + + // remove thinker + if (po->thinker == &th->thinker) + po->thinker = NULL; + P_RemoveThinker(&th->thinker); + } + else + { + INT16 delta = abs(th->destvalue - th->sourcevalue); + INT32 duration = th->ticbased ? th->duration + : abs(FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->destvalue) + - FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->sourcevalue)); // speed-based internal counter duration: delta in 256 scale + fixed_t factor = min(FixedDiv(duration - th->timer, duration), 1*FRACUNIT); + if (th->destvalue < th->sourcevalue) + po->translucency = max(min(po->translucency, th->sourcevalue - (INT16)FixedMul(delta, factor)), th->destvalue); + else if (th->destvalue > th->sourcevalue) + po->translucency = min(max(po->translucency, th->sourcevalue + (INT16)FixedMul(delta, factor)), th->destvalue); + } + + if (!stillfading) + { + // set render flags + if (po->translucency >= NUMTRANSMAPS) // invisible + po->flags &= ~POF_RENDERALL; + else + po->flags |= (po->spawnflags & POF_RENDERALL); + + // set collision + if (th->docollision) + { + if (th->destvalue > th->sourcevalue) // faded out + { + po->flags &= ~POF_SOLID; + po->flags |= POF_NOSPECIALS; + } + else + { + po->flags |= (po->spawnflags & POF_SOLID); + if (!(po->spawnflags & POF_NOSPECIALS)) + po->flags &= ~POF_NOSPECIALS; + } + } + } + else + { + if (po->translucency >= NUMTRANSMAPS) + // HACK: OpenGL renders fully opaque when >= NUMTRANSMAPS + po->translucency = NUMTRANSMAPS-1; + + po->flags |= (po->spawnflags & POF_RENDERALL); + + // set collision + if (th->docollision) + { + if (th->doghostfade) + { + po->flags &= ~POF_SOLID; + po->flags |= POF_NOSPECIALS; + } + else + { + po->flags |= (po->spawnflags & POF_SOLID); + if (!(po->spawnflags & POF_NOSPECIALS)) + po->flags &= ~POF_NOSPECIALS; + } + } + } +} + +INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata) +{ + polyobj_t *po; + polyobj_t *oldpo; + polyfade_t *th; + INT32 start; + + if (!(po = Polyobj_GetForNum(pfdata->polyObjNum))) + { + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjFade: bad polyobj %d\n", pfdata->polyObjNum); + return 0; + } + + // don't allow line actions to affect bad polyobjects + if (po->isBad) + return 0; + + // already equal, nothing to do + if (po->translucency == pfdata->destvalue) + return 1; + + if (po->thinker && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade) + P_RemoveThinker(po->thinker); + + // create a new thinker + th = Z_Malloc(sizeof(polyfade_t), PU_LEVSPEC, NULL); + th->thinker.function.acp1 = (actionf_p1)T_PolyObjFade; + PolyObj_AddThinker(&th->thinker); + po->thinker = &th->thinker; + + // set fields + th->polyObjNum = pfdata->polyObjNum; + th->sourcevalue = po->translucency; + th->destvalue = pfdata->destvalue; + th->docollision = pfdata->docollision; + th->doghostfade = pfdata->doghostfade; + + if (pfdata->ticbased) + { + th->ticbased = true; + th->timer = th->duration = abs(pfdata->speed); // pfdata->speed is duration + } + else + { + th->ticbased = false; + th->timer = abs(FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->destvalue) + - FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->sourcevalue)); // delta converted to 256 scale, use as internal counter + th->duration = abs(pfdata->speed); // use th->duration as speed decrement + } + + oldpo = po; + + // apply action to mirroring polyobjects as well + start = 0; + while ((po = Polyobj_GetChild(oldpo, &start))) + { + pfdata->polyObjNum = po->id; + EV_DoPolyObjFade(pfdata); + } + + // action was successful + return 1; +} + #endif // ifdef POLYOBJECTS // EOF diff --git a/src/p_polyobj.h b/src/p_polyobj.h index c9838a922..524518f2a 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -207,6 +207,20 @@ typedef struct polydisplace_s fixed_t oldHeights; } polydisplace_t; +typedef struct polyfade_s +{ + thinker_t thinker; // must be first + + INT32 polyObjNum; + INT32 sourcevalue; + INT32 destvalue; + boolean docollision; + boolean doghostfade; + boolean ticbased; + INT32 duration; + INT32 timer; +} polyfade_t; + // // Line Activation Data Structures // @@ -266,6 +280,16 @@ typedef struct polydisplacedata_s fixed_t dy; } polydisplacedata_t; +typedef struct polyfadedata_s +{ + INT32 polyObjNum; + INT32 destvalue; + boolean docollision; + boolean doghostfade; + boolean ticbased; + INT32 speed; +} polyfadedata_t; + // // Functions // @@ -287,6 +311,7 @@ void T_PolyDoorSlide(polyslidedoor_t *); void T_PolyDoorSwing(polyswingdoor_t *); void T_PolyObjDisplace (polydisplace_t *); void T_PolyObjFlag (polymove_t *); +void T_PolyObjFade (polyfade_t *); INT32 EV_DoPolyDoor(polydoordata_t *); INT32 EV_DoPolyObjMove(polymovedata_t *); @@ -294,6 +319,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *); INT32 EV_DoPolyObjRotate(polyrotdata_t *); INT32 EV_DoPolyObjDisplace(polydisplacedata_t *); INT32 EV_DoPolyObjFlag(struct line_s *); +INT32 EV_DoPolyObjFade(polyfadedata_t *); // diff --git a/src/p_saveg.c b/src/p_saveg.c index 22d43f358..6a07e513f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -21,6 +21,7 @@ #include "p_local.h" #include "p_setup.h" #include "p_saveg.h" +#include "r_data.h" #include "r_things.h" #include "r_state.h" #include "w_wad.h" @@ -473,6 +474,243 @@ static void P_NetUnArchivePlayers(void) } } +/// +/// Colormaps +/// + +static extracolormap_t *net_colormaps = NULL; +static UINT32 num_net_colormaps = 0; +static UINT32 num_ffloors = 0; // for loading + +// Copypasta from r_data.c AddColormapToList +// But also check for equality and return the matching index +static UINT32 CheckAddNetColormapToList(extracolormap_t *extra_colormap) +{ + extracolormap_t *exc, *exc_prev; + UINT32 i = 0; + + if (!net_colormaps) + { + net_colormaps = R_CopyColormap(extra_colormap, false); + net_colormaps->next = 0; + net_colormaps->prev = 0; + num_net_colormaps = i+1; + return i; + } + + for (exc = net_colormaps; exc; exc_prev = exc, exc = exc->next) + { + if (R_CheckEqualColormaps(exc, extra_colormap, true, true, true)) + return i; + i++; + } + + exc_prev->next = R_CopyColormap(extra_colormap, false); + extra_colormap->prev = exc_prev; + extra_colormap->next = 0; + + num_net_colormaps = i+1; + return i; +} + +static extracolormap_t *GetNetColormapFromList(UINT32 index) +{ + // For loading, we have to be tricky: + // We load the sectors BEFORE knowing the colormap values + // So if an index doesn't exist, fill our list with dummy colormaps + // until we get the index we want + // Then when we load the color data, we set up the dummy colormaps + + extracolormap_t *exc, *last_exc = NULL; + UINT32 i = 0; + + if (!net_colormaps) // initialize our list + net_colormaps = R_CreateDefaultColormap(false); + + for (exc = net_colormaps; exc; last_exc = exc, exc = exc->next) + { + if (i++ == index) + return exc; + } + + + // LET'S HOPE that index is a sane value, because we create up to [index] + // entries in net_colormaps. At this point, we don't know + // what the total colormap count is + if (index >= numsectors*3 + num_ffloors) + // if every sector had a unique colormap change AND a fade color thinker which has two colormap entries + // AND every ffloor had a fade FOF thinker with one colormap entry + I_Error("Colormap %d from server is too high for sectors %d", index, (UINT32)numsectors); + + // our index doesn't exist, so just make the entry + for (; i <= index; i++) + { + exc = R_CreateDefaultColormap(false); + if (last_exc) + last_exc->next = exc; + exc->prev = last_exc; + exc->next = NULL; + last_exc = exc; + } + return exc; +} + +static void ClearNetColormaps(void) +{ + // We're actually Z_Freeing each entry here, + // so don't call this in P_NetUnArchiveColormaps (where entries will be used in-game) + extracolormap_t *exc, *exc_next; + + for (exc = net_colormaps; exc; exc = exc_next) + { + exc_next = exc->next; + Z_Free(exc); + } + num_net_colormaps = 0; + num_ffloors = 0; + net_colormaps = NULL; +} + +static void P_NetArchiveColormaps(void) +{ + // We save and then we clean up our colormap mess + extracolormap_t *exc, *exc_next; + UINT32 i = 0; + WRITEUINT32(save_p, num_net_colormaps); // save for safety + + for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) + { + // We must save num_net_colormaps worth of data + // So fill non-existent entries with default. + if (!exc) + exc = R_CreateDefaultColormap(false); + + WRITEUINT8(save_p, exc->fadestart); + WRITEUINT8(save_p, exc->fadeend); + WRITEUINT8(save_p, exc->fog); + + WRITEINT32(save_p, exc->rgba); + WRITEINT32(save_p, exc->fadergba); + +#ifdef EXTRACOLORMAPLUMPS + WRITESTRINGN(save_p, exc->lumpname, 9); +#endif + + exc_next = exc->next; + Z_Free(exc); // don't need anymore + } + + num_net_colormaps = 0; + num_ffloors = 0; + net_colormaps = NULL; +} + +static void P_NetUnArchiveColormaps(void) +{ + // When we reach this point, we already populated our list with + // dummy colormaps. Now that we are loading the color data, + // set up the dummies. + extracolormap_t *exc, *existing_exc, *exc_next = NULL; + UINT32 i = 0; + + num_net_colormaps = READUINT32(save_p); + + for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) + { + UINT8 fadestart, fadeend, fog; + INT32 rgba, fadergba; +#ifdef EXTRACOLORMAPLUMPS + char lumpname[9]; +#endif + + fadestart = READUINT8(save_p); + fadeend = READUINT8(save_p); + fog = READUINT8(save_p); + + rgba = READINT32(save_p); + fadergba = READINT32(save_p); + +#ifdef EXTRACOLORMAPLUMPS + READSTRINGN(save_p, lumpname, 9); + + if (lumpname[0]) + { + if (!exc) + // no point making a new entry since nothing points to it, + // but we needed to read the data so now continue + continue; + + exc_next = exc->next; // this gets overwritten during our operations here, so get it now + existing_exc = R_ColormapForName(lumpname); + *exc = *existing_exc; + R_AddColormapToList(exc); // see HACK note below on why we're adding duplicates + continue; + } +#endif + + if (!exc) + // no point making a new entry since nothing points to it, + // but we needed to read the data so now continue + continue; + + exc_next = exc->next; // this gets overwritten during our operations here, so get it now + + exc->fadestart = fadestart; + exc->fadeend = fadeend; + exc->fog = fog; + + exc->rgba = rgba; + exc->fadergba = fadergba; + +#ifdef EXTRACOLORMAPLUMPS + exc->lump = LUMPERROR; + exc->lumpname[0] = 0; +#endif + + existing_exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, fog); + + if (existing_exc) + exc->colormap = existing_exc->colormap; + else + // CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n", + // R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba), + // R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba)); + exc->colormap = R_CreateLightTable(exc); + + // HACK: If this dummy is a duplicate, we're going to add it + // to the extra_colormaps list anyway. I think this is faster + // than going through every loaded sector and correcting their + // colormap address to the pre-existing one, PER net_colormap entry + R_AddColormapToList(exc); + + if (i < num_net_colormaps-1 && !exc_next) + exc_next = R_CreateDefaultColormap(false); + } + + // if we still have a valid net_colormap after iterating up to num_net_colormaps, + // some sector had a colormap index higher than num_net_colormaps. We done goofed or $$$ was corrupted. + // In any case, add them to the colormap list too so that at least the sectors' colormap + // addresses are valid and accounted properly + if (exc_next) + { + existing_exc = R_GetDefaultColormap(); + for (exc = exc_next; exc; exc = exc->next) + { + exc->colormap = existing_exc->colormap; // all our dummies are default values + R_AddColormapToList(exc); + } + } + + // Don't need these anymore + num_net_colormaps = 0; + num_ffloors = 0; + net_colormaps = NULL; +} + +/// +/// World Archiving +/// + #define SD_FLOORHT 0x01 #define SD_CEILHT 0x02 #define SD_FLOORPIC 0x04 @@ -487,10 +725,14 @@ static void P_NetUnArchivePlayers(void) #define SD_FYOFFS 0x02 #define SD_CXOFFS 0x04 #define SD_CYOFFS 0x08 -#define SD_TAG 0x10 -#define SD_FLOORANG 0x20 -#define SD_CEILANG 0x40 -#define SD_TAGLIST 0x80 +#define SD_FLOORANG 0x10 +#define SD_CEILANG 0x20 +#define SD_TAG 0x40 +#define SD_DIFF3 0x80 + +// diff3 flags +#define SD_TAGLIST 0x01 +#define SD_COLORMAP 0x02 #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 @@ -523,7 +765,10 @@ static void P_NetArchiveWorld(void) mapsidedef_t *msd; maplinedef_t *mld; const sector_t *ss = sectors; - UINT8 diff, diff2; + UINT8 diff, diff2, diff3; + + // initialize colormap vars because paranoia + ClearNetColormaps(); WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); put = save_p; @@ -550,7 +795,7 @@ static void P_NetArchiveWorld(void) for (i = 0; i < numsectors; i++, ss++, ms++) { - diff = diff2 = 0; + diff = diff2 = diff3 = 0; if (ss->floorheight != SHORT(ms->floorheight)<ceilingheight != SHORT(ms->ceilingheight)<tag != SHORT(ms->tag)) diff2 |= SD_TAG; if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag) - diff2 |= SD_TAGLIST; + diff3 |= SD_TAGLIST; + + if (ss->extra_colormap != ss->spawn_extra_colormap) + diff3 |= SD_COLORMAP; // Check if any of the sector's FOFs differ from how they spawned if (ss->ffloors) @@ -601,6 +849,9 @@ static void P_NetArchiveWorld(void) } } + if (diff3) + diff2 |= SD_DIFF3; + if (diff2) diff |= SD_DIFF2; @@ -612,6 +863,8 @@ static void P_NetArchiveWorld(void) WRITEUINT8(put, diff); if (diff & SD_DIFF2) WRITEUINT8(put, diff2); + if (diff2 & SD_DIFF3) + WRITEUINT8(put, diff3); if (diff & SD_FLOORHT) WRITEFIXED(put, ss->floorheight); if (diff & SD_CEILHT) @@ -632,18 +885,22 @@ static void P_NetArchiveWorld(void) WRITEFIXED(put, ss->ceiling_xoffs); if (diff2 & SD_CYOFFS) WRITEFIXED(put, ss->ceiling_yoffs); - if (diff2 & SD_TAG) // save only the tag - WRITEINT16(put, ss->tag); if (diff2 & SD_FLOORANG) WRITEANGLE(put, ss->floorpic_angle); if (diff2 & SD_CEILANG) WRITEANGLE(put, ss->ceilingpic_angle); - if (diff2 & SD_TAGLIST) // save both firsttag and nexttag + if (diff2 & SD_TAG) // save only the tag + WRITEINT16(put, ss->tag); + if (diff3 & SD_TAGLIST) // save both firsttag and nexttag { // either of these could be changed even if tag isn't WRITEINT32(put, ss->firsttag); WRITEINT32(put, ss->nexttag); } + if (diff3 & SD_COLORMAP) + WRITEUINT32(put, CheckAddNetColormapToList(ss->extra_colormap)); + // returns existing index if already added, or appends to net_colormaps and returns new index + // Special case: save the stats of all modified ffloors along with their ffloor "number"s // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed if (diff & SD_FFLOORS) @@ -680,7 +937,7 @@ static void P_NetArchiveWorld(void) // do lines for (i = 0; i < numlines; i++, mld++, li++) { - diff = diff2 = 0; + diff = diff2 = diff3 = 0; if (li->special != SHORT(mld->special)) diff |= LD_SPECIAL; @@ -772,11 +1029,22 @@ static void P_NetUnArchiveWorld(void) line_t *li; side_t *si; UINT8 *get; - UINT8 diff, diff2; + UINT8 diff, diff2, diff3; if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD) I_Error("Bad $$$.sav at archive block World"); + // initialize colormap vars because paranoia + ClearNetColormaps(); + + // count the level's ffloors so that colormap loading can have an upper limit + for (i = 0; i < numsectors; i++) + { + ffloor_t *rover; + for (rover = sectors[i].ffloors; rover; rover = rover->next) + num_ffloors++; + } + get = save_p; for (;;) @@ -794,6 +1062,10 @@ static void P_NetUnArchiveWorld(void) diff2 = READUINT8(get); else diff2 = 0; + if (diff2 & SD_DIFF3) + diff3 = READUINT8(get); + else + diff3 = 0; if (diff & SD_FLOORHT) sectors[i].floorheight = READFIXED(get); @@ -822,17 +1094,20 @@ static void P_NetUnArchiveWorld(void) sectors[i].ceiling_xoffs = READFIXED(get); if (diff2 & SD_CYOFFS) sectors[i].ceiling_yoffs = READFIXED(get); - if (diff2 & SD_TAG) - sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag - if (diff2 & SD_TAGLIST) - { - sectors[i].firsttag = READINT32(get); - sectors[i].nexttag = READINT32(get); - } if (diff2 & SD_FLOORANG) sectors[i].floorpic_angle = READANGLE(get); if (diff2 & SD_CEILANG) sectors[i].ceilingpic_angle = READANGLE(get); + if (diff2 & SD_TAG) + sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag + if (diff3 & SD_TAGLIST) + { + sectors[i].firsttag = READINT32(get); + sectors[i].nexttag = READINT32(get); + } + + if (diff3 & SD_COLORMAP) + sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(get)); if (diff & SD_FFLOORS) { @@ -891,6 +1166,9 @@ static void P_NetUnArchiveWorld(void) diff2 = READUINT8(get); else diff2 = 0; + + diff3 = 0; + if (diff & LD_FLAG) li->flags = READINT16(get); if (diff & LD_SPECIAL) @@ -972,11 +1250,13 @@ typedef enum MD2_EXTVAL1 = 1<<5, MD2_EXTVAL2 = 1<<6, MD2_HNEXT = 1<<7, -#ifdef ESLOPE MD2_HPREV = 1<<8, - MD2_SLOPE = 1<<9 + MD2_FLOORROVER = 1<<9, +#ifdef ESLOPE + MD2_CEILINGROVER = 1<<10, + MD2_SLOPE = 1<<11 #else - MD2_HPREV = 1<<8 + MD2_CEILINGROVER = 1<<10 #endif } mobj_diff2_t; @@ -996,6 +1276,7 @@ typedef enum tc_bouncecheese, tc_startcrumble, tc_marioblock, + tc_marioblockchecker, tc_spikesector, tc_floatsector, tc_bridgethinker, @@ -1010,6 +1291,8 @@ typedef enum tc_noenemies, tc_eachtime, tc_disappear, + tc_fade, + tc_fadecolormap, tc_planedisplace, #ifdef POLYOBJECTS tc_polyrotate, // haleyjd 03/26/06: polyobjects @@ -1019,6 +1302,7 @@ typedef enum tc_polyswingdoor, tc_polyflag, tc_polydisplace, + tc_polyfade, #endif tc_end } specials_e; @@ -1170,6 +1454,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_HNEXT; if (mobj->hprev) diff2 |= MD2_HPREV; + if (mobj->floorrover) + diff2 |= MD2_FLOORROVER; + if (mobj->ceilingrover) + diff2 |= MD2_CEILINGROVER; #ifdef ESLOPE if (mobj->standingslope) diff2 |= MD2_SLOPE; @@ -1193,6 +1481,46 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, mobj->floorz); WRITEFIXED(save_p, mobj->ceilingz); + if (diff2 & MD2_FLOORROVER) + { + ffloor_t *rover; + size_t i = 0; + UINT32 roverindex = 0; + + for (rover = mobj->floorrover->target->ffloors; rover; rover = rover->next) + { + if (rover == mobj->floorrover) + { + roverindex = i; + break; + } + i++; + } + + WRITEUINT32(save_p, (UINT32)(mobj->floorrover->target - sectors)); + WRITEUINT32(save_p, rover ? roverindex : i); // store max index to denote invalid ffloor ref + } + + if (diff2 & MD2_CEILINGROVER) + { + ffloor_t *rover; + size_t i = 0; + UINT32 roverindex = 0; + + for (rover = mobj->ceilingrover->target->ffloors; rover; rover = rover->next) + { + if (rover == mobj->ceilingrover) + { + roverindex = i; + break; + } + i++; + } + + WRITEUINT32(save_p, (UINT32)(mobj->ceilingrover->target - sectors)); + WRITEUINT32(save_p, rover ? roverindex : i); // store max index to denote invalid ffloor ref + } + if (diff & MD_SPAWNPOINT) { size_t z; @@ -1311,7 +1639,10 @@ static void SaveSpecialLevelThinker(const thinker_t *th, const UINT8 type) size_t i; WRITEUINT8(save_p, type); for (i = 0; i < 16; i++) + { WRITEFIXED(save_p, ht->vars[i]); //var[16] + WRITEFIXED(save_p, ht->var2s[i]); //var[16] + } WRITEUINT32(save_p, SaveLine(ht->sourceline)); WRITEUINT32(save_p, SaveSector(ht->sector)); } @@ -1537,8 +1868,11 @@ static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type) const lightlevel_t *ht = (const void *)th; WRITEUINT8(save_p, type); WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->destlevel); - WRITEINT32(save_p, ht->speed); + WRITEINT16(save_p, ht->sourcelevel); + WRITEINT16(save_p, ht->destlevel); + WRITEFIXED(save_p, ht->fixedcurlevel); + WRITEFIXED(save_p, ht->fixedpertic); + WRITEINT32(save_p, ht->timer); } // @@ -1574,6 +1908,51 @@ static void SaveDisappearThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->exists); } +// +// SaveFadeThinker +// +// Saves a fade_t thinker +// +static void SaveFadeThinker(const thinker_t *th, const UINT8 type) +{ + const fade_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc)); + WRITEUINT32(save_p, ht->sectornum); + WRITEUINT32(save_p, ht->ffloornum); + WRITEINT32(save_p, ht->alpha); + WRITEINT16(save_p, ht->sourcevalue); + WRITEINT16(save_p, ht->destvalue); + WRITEINT16(save_p, ht->destlightlevel); + WRITEINT16(save_p, ht->speed); + WRITEUINT8(save_p, (UINT8)ht->ticbased); + WRITEINT32(save_p, ht->timer); + WRITEUINT8(save_p, ht->doexists); + WRITEUINT8(save_p, ht->dotranslucent); + WRITEUINT8(save_p, ht->dolighting); + WRITEUINT8(save_p, ht->docolormap); + WRITEUINT8(save_p, ht->docollision); + WRITEUINT8(save_p, ht->doghostfade); + WRITEUINT8(save_p, ht->exactalpha); +} + +// +// SaveFadeColormapThinker +// +// Saves a fadecolormap_t thinker +// +static void SaveFadeColormapThinker(const thinker_t *th, const UINT8 type) +{ + const fadecolormap_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEUINT32(save_p, CheckAddNetColormapToList(ht->source_exc)); + WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc)); + WRITEUINT8(save_p, (UINT8)ht->ticbased); + WRITEINT32(save_p, ht->duration); + WRITEINT32(save_p, ht->timer); +} + // // SavePlaneDisplaceThinker // @@ -1699,6 +2078,20 @@ static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->oldHeights); } +static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type) +{ + const polyfade_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEINT32(save_p, ht->polyObjNum); + WRITEINT32(save_p, ht->sourcevalue); + WRITEINT32(save_p, ht->destvalue); + WRITEUINT8(save_p, (UINT8)ht->docollision); + WRITEUINT8(save_p, (UINT8)ht->doghostfade); + WRITEUINT8(save_p, (UINT8)ht->ticbased); + WRITEINT32(save_p, ht->duration); + WRITEINT32(save_p, ht->timer); +} + #endif /* // @@ -1728,8 +2121,7 @@ static void P_NetArchiveThinkers(void) for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed - || th->function.acp1 == (actionf_p1)P_RainThinker - || th->function.acp1 == (actionf_p1)P_SnowThinker)) + || th->function.acp1 == (actionf_p1)P_NullPrecipThinker)) numsaved++; if (th->function.acp1 == (actionf_p1)P_MobjThinker) @@ -1738,8 +2130,7 @@ static void P_NetArchiveThinkers(void) continue; } #ifdef PARANOIA - else if (th->function.acp1 == (actionf_p1)P_RainThinker - || th->function.acp1 == (actionf_p1)P_SnowThinker); + else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker); #endif else if (th->function.acp1 == (actionf_p1)T_MoveCeiling) { @@ -1841,6 +2232,11 @@ static void P_NetArchiveThinkers(void) SaveSpecialLevelThinker(th, tc_marioblock); continue; } + else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker) + { + SaveSpecialLevelThinker(th, tc_marioblockchecker); + continue; + } else if (th->function.acp1 == (actionf_p1)T_SpikeSector) { SaveSpecialLevelThinker(th, tc_spikesector); @@ -1876,7 +2272,16 @@ static void P_NetArchiveThinkers(void) SaveDisappearThinker(th, tc_disappear); continue; } - + else if (th->function.acp1 == (actionf_p1)T_Fade) + { + SaveFadeThinker(th, tc_fade); + continue; + } + else if (th->function.acp1 == (actionf_p1)T_FadeColormap) + { + SaveFadeColormapThinker(th, tc_fadecolormap); + continue; + } else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace) { SavePlaneDisplaceThinker(th, tc_planedisplace); @@ -1918,6 +2323,11 @@ static void P_NetArchiveThinkers(void) SavePolydisplaceThinker(th, tc_polydisplace); continue; } + else if (th->function.acp1 == (actionf_p1)T_PolyObjFade) + { + SavePolyfadeThinker(th, tc_polyfade); + continue; + } #endif #ifdef PARANOIA else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection @@ -1989,6 +2399,7 @@ static void LoadMobjThinker(actionf_p1 thinker) UINT16 diff2; INT32 i; fixed_t z, floorz, ceilingz; + ffloor_t *floorrover = NULL, *ceilingrover = NULL; diff = READUINT32(save_p); if (diff & MD_MORE) @@ -2002,6 +2413,38 @@ static void LoadMobjThinker(actionf_p1 thinker) floorz = READFIXED(save_p); ceilingz = READFIXED(save_p); + if (diff2 & MD2_FLOORROVER) + { + size_t floor_sectornum = (size_t)READUINT32(save_p); + size_t floor_rovernum = (size_t)READUINT32(save_p); + ffloor_t *rover = NULL; + size_t rovernum = 0; + + for (rover = sectors[floor_sectornum].ffloors; rover; rover = rover->next) + { + if (rovernum == floor_rovernum) + break; + rovernum++; + } + floorrover = rover; + } + + if (diff2 & MD2_CEILINGROVER) + { + size_t ceiling_sectornum = (size_t)READUINT32(save_p); + size_t ceiling_rovernum = (size_t)READUINT32(save_p); + ffloor_t *rover = NULL; + size_t rovernum = 0; + + for (rover = sectors[ceiling_sectornum].ffloors; rover; rover = rover->next) + { + if (rovernum == ceiling_rovernum) + break; + rovernum++; + } + ceilingrover = rover; + } + if (diff & MD_SPAWNPOINT) { UINT16 spawnpointnum = READUINT16(save_p); @@ -2026,6 +2469,8 @@ static void LoadMobjThinker(actionf_p1 thinker) mobj->z = z; mobj->floorz = floorz; mobj->ceilingz = ceilingz; + mobj->floorrover = floorrover; + mobj->ceilingrover = ceilingrover; if (diff & MD_TYPE) mobj->type = READUINT32(save_p); @@ -2236,7 +2681,10 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling) size_t i; ht->thinker.function.acp1 = thinker; for (i = 0; i < 16; i++) + { ht->vars[i] = READFIXED(save_p); //var[16] + ht->var2s[i] = READFIXED(save_p); //var[16] + } ht->sourceline = LoadLine(READUINT32(save_p)); ht->sector = LoadSector(READUINT32(save_p)); @@ -2510,8 +2958,11 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker) lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; ht->sector = LoadSector(READUINT32(save_p)); - ht->destlevel = READINT32(save_p); - ht->speed = READINT32(save_p); + ht->sourcelevel = READINT16(save_p); + ht->destlevel = READINT16(save_p); + ht->fixedcurlevel = READFIXED(save_p); + ht->fixedpertic = READFIXED(save_p); + ht->timer = READINT32(save_p); if (ht->sector) ht->sector->lightingdata = ht; P_AddThinker(&ht->thinker); @@ -2552,6 +3003,72 @@ static inline void LoadDisappearThinker(actionf_p1 thinker) P_AddThinker(&ht->thinker); } +// +// LoadFadeThinker +// +// Loads a fade_t thinker +// +static inline void LoadFadeThinker(actionf_p1 thinker) +{ + sector_t *ss; + fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->dest_exc = GetNetColormapFromList(READUINT32(save_p)); + ht->sectornum = READUINT32(save_p); + ht->ffloornum = READUINT32(save_p); + ht->alpha = READINT32(save_p); + ht->sourcevalue = READINT16(save_p); + ht->destvalue = READINT16(save_p); + ht->destlightlevel = READINT16(save_p); + ht->speed = READINT16(save_p); + ht->ticbased = (boolean)READUINT8(save_p); + ht->timer = READINT32(save_p); + ht->doexists = READUINT8(save_p); + ht->dotranslucent = READUINT8(save_p); + ht->dolighting = READUINT8(save_p); + ht->docolormap = READUINT8(save_p); + ht->docollision = READUINT8(save_p); + ht->doghostfade = READUINT8(save_p); + ht->exactalpha = READUINT8(save_p); + + ss = LoadSector(ht->sectornum); + if (ss) + { + size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc + ffloor_t *rover; + for (rover = ss->ffloors; rover; rover = rover->next) + { + if (j == ht->ffloornum) + { + ht->rover = rover; + rover->fadingdata = ht; + break; + } + j++; + } + } + P_AddThinker(&ht->thinker); +} + +// LoadFadeColormapThinker +// +// Loads a fadecolormap_t from a save game +// +static inline void LoadFadeColormapThinker(actionf_p1 thinker) +{ + fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->sector = LoadSector(READUINT32(save_p)); + ht->source_exc = GetNetColormapFromList(READUINT32(save_p)); + ht->dest_exc = GetNetColormapFromList(READUINT32(save_p)); + ht->ticbased = (boolean)READUINT8(save_p); + ht->duration = READINT32(save_p); + ht->timer = READINT32(save_p); + if (ht->sector) + ht->sector->fadecolormapdata = ht; + P_AddThinker(&ht->thinker); +} + // // LoadPlaneDisplaceThinker // @@ -2689,6 +3206,26 @@ static inline void LoadPolydisplaceThinker(actionf_p1 thinker) ht->oldHeights = READFIXED(save_p); P_AddThinker(&ht->thinker); } + +// +// LoadPolyfadeThinker +// +// Loads a polyfadet_t thinker +// +static void LoadPolyfadeThinker(actionf_p1 thinker) +{ + polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->polyObjNum = READINT32(save_p); + ht->sourcevalue = READINT32(save_p); + ht->destvalue = READINT32(save_p); + ht->docollision = (boolean)READUINT8(save_p); + ht->doghostfade = (boolean)READUINT8(save_p); + ht->ticbased = (boolean)READUINT8(save_p); + ht->duration = READINT32(save_p); + ht->timer = READINT32(save_p); + P_AddThinker(&ht->thinker); +} #endif /* @@ -2738,7 +3275,7 @@ static void P_NetUnArchiveThinkers(void) // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity for (i = 0; i < numsectors; i++) { - sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL; + sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = sectors[i].fadecolormapdata = NULL; } // read in saved thinkers @@ -2826,6 +3363,10 @@ static void P_NetUnArchiveThinkers(void) LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3); break; + case tc_marioblockchecker: + LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0); + break; + case tc_spikesector: LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0); break; @@ -2855,6 +3396,14 @@ static void P_NetUnArchiveThinkers(void) LoadDisappearThinker((actionf_p1)T_Disappear); break; + case tc_fade: + LoadFadeThinker((actionf_p1)T_Fade); + break; + + case tc_fadecolormap: + LoadFadeColormapThinker((actionf_p1)T_FadeColormap); + break; + case tc_planedisplace: LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace); break; @@ -2886,6 +3435,10 @@ static void P_NetUnArchiveThinkers(void) case tc_polydisplace: LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace); break; + + case tc_polyfade: + LoadPolyfadeThinker((actionf_p1)T_PolyObjFade); + break; #endif case tc_scroll: LoadScrollThinker((actionf_p1)T_Scroll); @@ -3438,6 +3991,7 @@ void P_SaveNetGame(void) #endif P_NetArchiveThinkers(); P_NetArchiveSpecials(); + P_NetArchiveColormaps(); } #ifdef HAVE_BLUA LUA_Archive(); @@ -3480,6 +4034,7 @@ boolean P_LoadNetGame(void) #endif P_NetUnArchiveThinkers(); P_NetUnArchiveSpecials(); + P_NetUnArchiveColormaps(); P_RelinkPointers(); P_FinishMobjs(); } diff --git a/src/p_setup.c b/src/p_setup.c index 2361d1efd..eb25c51c8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -678,6 +678,7 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats); ss->lightlevel = SHORT(ms->lightlevel); + ss->spawn_lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->nexttag = ss->firsttag = -1; @@ -713,12 +714,12 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) ss->moved = true; ss->extra_colormap = NULL; + ss->spawn_extra_colormap = NULL; ss->floor_xoffs = ss->ceiling_xoffs = ss->floor_yoffs = ss->ceiling_yoffs = 0; ss->spawn_flr_xoffs = ss->spawn_ceil_xoffs = ss->spawn_flr_yoffs = ss->spawn_ceil_yoffs = 0; ss->floorpic_angle = ss->ceilingpic_angle = 0; ss->spawn_flrpic_angle = ss->spawn_ceilpic_angle = 0; - ss->bottommap = ss->midmap = ss->topmap = -1; ss->gravity = NULL; ss->cullheight = NULL; ss->verticalflip = false; @@ -1331,7 +1332,8 @@ static void P_LoadLineDefs2(void) ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0; // Repeat count for midtexture - if ((ld->flags & ML_EFFECT5) && (ld->sidenum[1] != 0xffff)) + if ((ld->flags & ML_EFFECT5) && (ld->sidenum[1] != 0xffff) + && !(ld->special >= 300 && ld->special < 500)) // exempt linedef exec specials { sides[ld->sidenum[0]].repeatcnt = (INT16)(((unsigned)sides[ld->sidenum[0]].textureoffset >> FRACBITS) >> 12); sides[ld->sidenum[0]].textureoffset = (((unsigned)sides[ld->sidenum[0]].textureoffset >> FRACBITS) & 2047) << FRACBITS; @@ -1438,7 +1440,6 @@ static inline void P_LoadSideDefs(lumpnum_t lumpnum) static void P_LoadRawSideDefs2(void *data) { UINT16 i; - INT32 num; for (i = 0; i < numsides; i++) { @@ -1460,117 +1461,23 @@ static void P_LoadRawSideDefs2(void *data) sd->sector = sec = §ors[sector_num]; } - // refined to allow colormaps to work as wall textures if invalid as colormaps - // but valid as textures. - sd->sector = sec = §ors[SHORT(msd->sector)]; + sd->colormap_data = NULL; + // Colormaps! switch (sd->special) { case 63: // variable colormap via 242 linedef case 606: //SoM: 4/4/2000: Just colormap transfer + case 447: // Change colormap of tagged sectors! -- Monster Iestyn 14/06/18 + case 455: // Fade colormaps! mazmazz 9/12/2018 (:flag_us:) // SoM: R_CreateColormap will only create a colormap in software mode... // Perhaps we should just call it instead of doing the calculations here. - if (rendermode == render_soft || rendermode == render_none) - { - if (msd->toptexture[0] == '#' || msd->bottomtexture[0] == '#') - { - sec->midmap = R_CreateColormap(msd->toptexture, msd->midtexture, - msd->bottomtexture); - sd->toptexture = sd->bottomtexture = 0; - } - else - { - if ((num = R_CheckTextureNumForName(msd->toptexture)) == -1) - sd->toptexture = 0; - else - sd->toptexture = num; - if ((num = R_CheckTextureNumForName(msd->midtexture)) == -1) - sd->midtexture = 0; - else - sd->midtexture = num; - if ((num = R_CheckTextureNumForName(msd->bottomtexture)) == -1) - sd->bottomtexture = 0; - else - sd->bottomtexture = num; - } - break; - } -#ifdef HWRENDER - else - { - // for now, full support of toptexture only - if ((msd->toptexture[0] == '#' && msd->toptexture[1] && msd->toptexture[2] && msd->toptexture[3] && msd->toptexture[4] && msd->toptexture[5] && msd->toptexture[6]) - || (msd->bottomtexture[0] == '#' && msd->bottomtexture[1] && msd->bottomtexture[2] && msd->bottomtexture[3] && msd->bottomtexture[4] && msd->bottomtexture[5] && msd->bottomtexture[6])) - { - char *col; - - sec->midmap = R_CreateColormap(msd->toptexture, msd->midtexture, - msd->bottomtexture); - sd->toptexture = sd->bottomtexture = 0; -#define HEX2INT(x) (x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) -#define ALPHA2INT(x) (x >= 'a' && x <= 'z' ? x - 'a' : x >= 'A' && x <= 'Z' ? x - 'A' : x >= '0' && x <= '9' ? 25 : 0) - sec->extra_colormap = &extra_colormaps[sec->midmap]; - - if (msd->toptexture[0] == '#' && msd->toptexture[1] && msd->toptexture[2] && msd->toptexture[3] && msd->toptexture[4] && msd->toptexture[5] && msd->toptexture[6]) - { - col = msd->toptexture; - - sec->extra_colormap->rgba = - (HEX2INT(col[1]) << 4) + (HEX2INT(col[2]) << 0) + - (HEX2INT(col[3]) << 12) + (HEX2INT(col[4]) << 8) + - (HEX2INT(col[5]) << 20) + (HEX2INT(col[6]) << 16); - - // alpha - if (msd->toptexture[7]) - sec->extra_colormap->rgba += (ALPHA2INT(col[7]) << 24); - else - sec->extra_colormap->rgba += (25 << 24); - } - else - sec->extra_colormap->rgba = 0; - - if (msd->bottomtexture[0] == '#' && msd->bottomtexture[1] && msd->bottomtexture[2] && msd->bottomtexture[3] && msd->bottomtexture[4] && msd->bottomtexture[5] && msd->bottomtexture[6]) - { - col = msd->bottomtexture; - - sec->extra_colormap->fadergba = - (HEX2INT(col[1]) << 4) + (HEX2INT(col[2]) << 0) + - (HEX2INT(col[3]) << 12) + (HEX2INT(col[4]) << 8) + - (HEX2INT(col[5]) << 20) + (HEX2INT(col[6]) << 16); - - // alpha - if (msd->bottomtexture[7]) - sec->extra_colormap->fadergba += (ALPHA2INT(col[7]) << 24); - else - sec->extra_colormap->fadergba += (25 << 24); - } - else - sec->extra_colormap->fadergba = 0x19000000; // default alpha, (25 << 24) -#undef ALPHA2INT -#undef HEX2INT - } - else - { - if ((num = R_CheckTextureNumForName(msd->toptexture)) == -1) - sd->toptexture = 0; - else - sd->toptexture = num; - - if ((num = R_CheckTextureNumForName(msd->midtexture)) == -1) - sd->midtexture = 0; - else - sd->midtexture = num; - - if ((num = R_CheckTextureNumForName(msd->bottomtexture)) == -1) - sd->bottomtexture = 0; - else - sd->bottomtexture = num; - } - break; - } -#endif + sd->colormap_data = R_CreateColormap(msd->toptexture, msd->midtexture, + msd->bottomtexture); + sd->toptexture = sd->midtexture = sd->bottomtexture = 0; + break; case 413: // Change music { @@ -2937,7 +2844,6 @@ boolean P_SetupLevel(boolean skipprecip) // Important: take care of the ordering of the next functions. if (!loadedbm) P_CreateBlockMap(); // Graue 02-29-2004 - R_MakeColormaps(); P_LoadLineDefs2(); P_GroupLines(); numdmstarts = numredctfstarts = numbluectfstarts = 0; @@ -2974,7 +2880,6 @@ boolean P_SetupLevel(boolean skipprecip) // Important: take care of the ordering of the next functions. if (!loadedbm) P_CreateBlockMap(); // Graue 02-29-2004 - R_MakeColormaps(); P_LoadLineDefs2(); P_GroupLines(); numdmstarts = numredctfstarts = numbluectfstarts = 0; diff --git a/src/p_spec.c b/src/p_spec.c index 6c359c9cc..9f9e80ecc 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -103,6 +103,18 @@ static void P_SpawnFriction(void); static void P_SpawnPushers(void); static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *source, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider); //SoM: 3/9/2000 static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t offset, INT32 line, INT32 sourceline); +static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finalize); +#define P_RemoveFakeFloorFader(l) P_ResetFakeFloorFader(l, NULL, false); +static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destvalue, INT16 speed, boolean ticbased, INT32 *timer, + boolean doexists, boolean dotranslucent, boolean dolighting, boolean docolormap, + boolean docollision, boolean doghostfade, boolean exactalpha); +static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloornum, + INT16 destvalue, INT16 speed, boolean ticbased, boolean relative, + boolean doexists, boolean dotranslucent, boolean dolighting, boolean docolormap, + boolean docollision, boolean doghostfade, boolean exactalpha); +static void P_ResetColormapFader(sector_t *sector); +static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, extracolormap_t *dest_exc, + boolean ticbased, INT32 duration); static void P_AddBlockThinker(sector_t *sec, line_t *sourceline); static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline); //static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec); @@ -1218,7 +1230,7 @@ static void PolyVisible(line_t *line) po->flags |= POF_SOLID; po->flags &= ~POF_NOSPECIALS; - po->flags |= POF_RENDERALL; + po->flags |= (po->spawnflags & POF_RENDERALL); } // @@ -1242,7 +1254,94 @@ static void PolyTranslucency(line_t *line) if (po->isBad) return; - po->translucency = (line->frontsector->floorheight >> FRACBITS) / 100; + // if DONTPEGBOTTOM, specify raw translucency value in Front X Offset + // else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight. + if (line->flags & ML_EFFECT3) // relative calc + po->translucency = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ? + (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS) + : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)) + : (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100 + : max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)), + NUMTRANSMAPS), 0); + else + po->translucency = (line->flags & ML_DONTPEGBOTTOM) ? + (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0) + : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0)) + : (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100 + : max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100); +} + +// +// PolyFade +// +// Makes a polyobject translucency fade and applies tangibility +// +static boolean PolyFade(line_t *line) +{ + INT32 polyObjNum = line->tag; + polyobj_t *po; + polyfadedata_t pfd; + + if (!(po = Polyobj_GetForNum(polyObjNum))) + { + CONS_Debug(DBG_POLYOBJ, "PolyFade: bad polyobj %d\n", polyObjNum); + return 0; + } + + // don't allow line actions to affect bad polyobjects + if (po->isBad) + return 0; + + // Prevent continuous execs from interfering on an existing fade + if (!(line->flags & ML_EFFECT5) + && po->thinker + && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade) + { + CONS_Debug(DBG_POLYOBJ, "Line type 492 Executor: Fade PolyObject thinker already exists\n"); + return 0; + } + + pfd.polyObjNum = polyObjNum; + + // if DONTPEGBOTTOM, specify raw translucency value in Front X Offset + // else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight. + if (line->flags & ML_EFFECT3) // relative calc + pfd.destvalue = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ? + (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS) + : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)) + : (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100 + : max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)), + NUMTRANSMAPS), 0); + else + pfd.destvalue = (line->flags & ML_DONTPEGBOTTOM) ? + (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0) + : max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0)) + : (sides[line->sidenum[0]].textureoffset ? + max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100 + : max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100); + + // already equal, nothing to do + if (po->translucency == pfd.destvalue) + return 1; + + pfd.docollision = !(line->flags & ML_BOUNCY); // do not handle collision flags + pfd.doghostfade = (line->flags & ML_EFFECT1); // do ghost fade (no collision flags during fade) + pfd.ticbased = (line->flags & ML_EFFECT4); // Speed = Tic Duration + + // allow Back Y Offset to be consistent with other fade specials + pfd.speed = (line->sidenum[1] != 0xFFFF && !sides[line->sidenum[0]].rowoffset) ? + abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) + : abs(sides[line->sidenum[0]].rowoffset>>FRACBITS); + + + return EV_DoPolyObjFade(&pfd); } // @@ -2127,8 +2226,7 @@ void P_SwitchWeather(INT32 weathernum) for (think = thinkercap.next; think != &thinkercap; think = think->next) { - if ((think->function.acp1 != (actionf_p1)P_SnowThinker) - && (think->function.acp1 != (actionf_p1)P_RainThinker)) + if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) continue; // not a precipmobj thinker precipmobj = (precipmobj_t *)think; @@ -2144,14 +2242,12 @@ void P_SwitchWeather(INT32 weathernum) for (think = thinkercap.next; think != &thinkercap; think = think->next) { + if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) + continue; // not a precipmobj thinker + precipmobj = (precipmobj_t *)think; + if (swap == PRECIP_RAIN) // Snow To Rain { - if (!(think->function.acp1 == (actionf_p1)P_SnowThinker - || think->function.acp1 == (actionf_p1)P_NullPrecipThinker)) - continue; // not a precipmobj thinker - - precipmobj = (precipmobj_t *)think; - precipmobj->flags = mobjinfo[MT_RAIN].flags; st = &states[mobjinfo[MT_RAIN].spawnstate]; precipmobj->state = st; @@ -2162,18 +2258,13 @@ void P_SwitchWeather(INT32 weathernum) precipmobj->precipflags &= ~PCF_INVISIBLE; - think->function.acp1 = (actionf_p1)P_RainThinker; + precipmobj->precipflags |= PCF_RAIN; + //think->function.acp1 = (actionf_p1)P_RainThinker; } else if (swap == PRECIP_SNOW) // Rain To Snow { INT32 z; - if (!(think->function.acp1 == (actionf_p1)P_RainThinker - || think->function.acp1 == (actionf_p1)P_NullPrecipThinker)) - continue; // not a precipmobj thinker - - precipmobj = (precipmobj_t *)think; - precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags; z = M_RandomByte(); @@ -2191,19 +2282,13 @@ void P_SwitchWeather(INT32 weathernum) precipmobj->frame = st->frame; precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed; - precipmobj->precipflags &= ~PCF_INVISIBLE; + precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN); - think->function.acp1 = (actionf_p1)P_SnowThinker; + //think->function.acp1 = (actionf_p1)P_SnowThinker; } else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse. { - if (!(think->function.acp1 == (actionf_p1)P_RainThinker - || think->function.acp1 == (actionf_p1)P_SnowThinker)) - continue; - - precipmobj = (precipmobj_t *)think; - - think->function.acp1 = (actionf_p1)P_NullPrecipThinker; + //think->function.acp1 = (actionf_p1)P_NullPrecipThinker; precipmobj->precipflags |= PCF_INVISIBLE; } @@ -2778,7 +2863,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 420: // Fade light levels in tagged sectors to new value - P_FadeLight(line->tag, line->frontsector->lightlevel, P_AproxDistance(line->dx, line->dy)>>FRACBITS); + P_FadeLight(line->tag, + (line->flags & ML_DONTPEGBOTTOM) ? max(sides[line->sidenum[0]].textureoffset>>FRACBITS, 0) : line->frontsector->lightlevel, + // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset + // to be consistent with other light and fade specials + (line->flags & ML_DONTPEGBOTTOM) ? + ((line->sidenum[1] != 0xFFFF && !(sides[line->sidenum[0]].rowoffset>>FRACBITS)) ? + max(min(sides[line->sidenum[1]].rowoffset>>FRACBITS, 255), 0) + : max(min(sides[line->sidenum[0]].rowoffset>>FRACBITS, 255), 0)) + : abs(P_AproxDistance(line->dx, line->dy))>>FRACBITS, + (line->flags & ML_EFFECT4), + (line->flags & ML_EFFECT5)); break; case 421: // Stop lighting effect in tagged sectors @@ -2982,6 +3077,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to crumble + boolean foundrover = false; // for debug, "Can't find a FOF" message for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) { @@ -2996,16 +3092,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { if (rover->master->frontsector->tag == foftag) - break; + { + foundrover = true; + + EV_CrumbleChain(sec, rover); + } } - if (!rover) + if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Line type 436 Executor: Can't find a FOF control sector with tag %d\n", foftag); return; } - - EV_CrumbleChain(sec, rover); } } break; @@ -3166,6 +3264,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); sector_t *sec; // Sector that the FOF is visible (or not visible) in ffloor_t *rover; // FOF to vanish/un-vanish + boolean foundrover = false; // for debug, "Can't find a FOF" message ffloortype_e oldflags; // store FOF's old flags for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) @@ -3181,26 +3280,28 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { if (rover->master->frontsector->tag == foftag) - break; + { + foundrover = true; + + oldflags = rover->flags; + + // Abracadabra! + if (line->flags & ML_NOCLIMB) + rover->flags |= FF_EXISTS; + else + rover->flags &= ~FF_EXISTS; + + // if flags changed, reset sector's light list + if (rover->flags != oldflags) + sec->moved = true; + } } - if (!rover) + if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Line type 445 Executor: Can't find a FOF control sector with tag %d\n", foftag); return; } - - oldflags = rover->flags; - - // Abracadabra! - if (line->flags & ML_NOCLIMB) - rover->flags |= FF_EXISTS; - else - rover->flags &= ~FF_EXISTS; - - // if flags changed, reset sector's light list - if (rover->flags != oldflags) - sec->moved = true; } } break; @@ -3211,6 +3312,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to make fall down + boolean foundrover = false; // for debug, "Can't find a FOF" message player_t *player = NULL; // player that caused FOF to fall boolean respawn = true; // should the fallen FOF respawn? @@ -3233,23 +3335,85 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { if (rover->master->frontsector->tag == foftag) - break; + { + foundrover = true; + + if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead? + respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts + + EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn); + } } - if (!rover) + if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Line type 446 Executor: Can't find a FOF control sector with tag %d\n", foftag); return; } - - if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead? - respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts - - EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn); } } break; + case 447: // Change colormap of tagged sectors! + // Basically this special applies a colormap to the tagged sectors, just like 606 (the colormap linedef) + // Except it is activated by linedef executor, not level load + // This could even override existing colormaps I believe + // -- Monster Iestyn 14/06/18 + for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + { + P_ResetColormapFader(§ors[secnum]); + + if (line->flags & ML_EFFECT3) // relative calc + { + extracolormap_t *exc = R_AddColormaps( + (line->flags & ML_TFERLINE) && line->sidenum[1] != 0xFFFF ? + sides[line->sidenum[1]].colormap_data : sectors[secnum].extra_colormap, // use back colormap instead of target sector + sides[line->sidenum[0]].colormap_data, + line->flags & ML_EFFECT1, // subtract R + line->flags & ML_NOCLIMB, // subtract G + line->flags & ML_EFFECT2, // subtract B + false, // subtract A (no flag for this, just pass negative alpha) + line->flags & ML_EFFECT1, // subtract FadeR + line->flags & ML_NOCLIMB, // subtract FadeG + line->flags & ML_EFFECT2, // subtract FadeB + false, // subtract FadeA (no flag for this, just pass negative alpha) + false, // subtract FadeStart (we ran out of flags) + false, // subtract FadeEnd (we ran out of flags) + false, // ignore Fog (we ran out of flags) + line->flags & ML_DONTPEGBOTTOM, + (line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].textureoffset >> FRACBITS) : 0, + (line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].rowoffset >> FRACBITS) : 0, + false); + + if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc))) + { + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + sectors[secnum].extra_colormap = exc; + } + else + Z_Free(exc); + } + else if (line->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets) + { + extracolormap_t *exc = R_CopyColormap(sides[line->sidenum[0]].colormap_data, false); + exc->rgba = R_GetRgbaRGB(exc->rgba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].textureoffset >> FRACBITS, 25), 0)); + exc->fadergba = R_GetRgbaRGB(exc->fadergba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].rowoffset >> FRACBITS, 25), 0)); + + if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc))) + { + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + sectors[secnum].extra_colormap = exc; + } + else + Z_Free(exc); + } + else + sectors[secnum].extra_colormap = sides[line->sidenum[0]].colormap_data; + } + break; + case 448: // Change skybox viewpoint/centerpoint if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB)) { @@ -3310,6 +3474,289 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } + case 452: // Set FOF alpha + { + INT16 destvalue = line->sidenum[1] != 0xffff ? + (INT16)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : (INT16)(P_AproxDistance(line->dx, line->dy)>>FRACBITS); + INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + sector_t *sec; // Sector that the FOF is visible in + ffloor_t *rover; // FOF that we are going to operate + boolean foundrover = false; // for debug, "Can't find a FOF" message + + for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + { + sec = sectors + secnum; + + if (!sec->ffloors) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 452 Executor: Target sector #%d has no FOFs.\n", secnum); + return; + } + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector->tag == foftag) + { + foundrover = true; + + // If fading an invisible FOF whose render flags we did not yet set, + // initialize its alpha to 1 + // for relative alpha calc + if (!(line->flags & ML_NOCLIMB) && // do translucent + (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES) && + !(rover->flags & FF_RENDERALL)) + rover->alpha = 1; + + P_RemoveFakeFloorFader(rover); + P_FadeFakeFloor(rover, + rover->alpha, + max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)), + 0, // set alpha immediately + false, NULL, // tic-based logic + false, // do not handle FF_EXISTS + !(line->flags & ML_NOCLIMB), // handle FF_TRANSLUCENT + false, // do not handle lighting + false, // do not handle colormap + false, // do not handle collision + false, // do not do ghost fade (no collision during fade) + true); // use exact alpha values (for opengl) + } + } + + if (!foundrover) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 452 Executor: Can't find a FOF control sector with tag %d\n", foftag); + return; + } + } + break; + } + + case 453: // Fade FOF + { + INT16 destvalue = line->sidenum[1] != 0xffff ? + (INT16)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : (INT16)(line->dx>>FRACBITS); + INT16 speed = line->sidenum[1] != 0xffff ? + (INT16)(abs(sides[line->sidenum[1]].rowoffset>>FRACBITS)) : (INT16)(abs(line->dy)>>FRACBITS); + INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + sector_t *sec; // Sector that the FOF is visible in + ffloor_t *rover; // FOF that we are going to operate + boolean foundrover = false; // for debug, "Can't find a FOF" message + size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc + + for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + { + sec = sectors + secnum; + + if (!sec->ffloors) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Target sector #%d has no FOFs.\n", secnum); + return; + } + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector->tag == foftag) + { + foundrover = true; + + // Prevent continuous execs from interfering on an existing fade + if (!(line->flags & ML_EFFECT5) + && rover->fadingdata) + //&& ((fade_t*)rover->fadingdata)->timer > (ticbased ? 2 : speed*2)) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Fade FOF thinker already exists, timer: %d\n", ((fade_t*)rover->fadingdata)->timer); + continue; + } + + if (speed > 0) + P_AddFakeFloorFader(rover, secnum, j, + destvalue, + speed, + (line->flags & ML_EFFECT4), // tic-based logic + (line->flags & ML_EFFECT3), // Relative destvalue + !(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS + !(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT + !(line->flags & ML_EFFECT2), // do not handle lighting + !(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags) + !(line->flags & ML_BOUNCY), // do not handle collision + (line->flags & ML_EFFECT1), // do ghost fade (no collision during fade) + (line->flags & ML_TFERLINE)); // use exact alpha values (for opengl) + else + { + // If fading an invisible FOF whose render flags we did not yet set, + // initialize its alpha to 1 + // for relative alpha calc + if (!(line->flags & ML_NOCLIMB) && // do translucent + (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES) && + !(rover->flags & FF_RENDERALL)) + rover->alpha = 1; + + P_RemoveFakeFloorFader(rover); + P_FadeFakeFloor(rover, + rover->alpha, + max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)), + 0, // set alpha immediately + false, NULL, // tic-based logic + !(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS + !(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT + !(line->flags & ML_EFFECT2), // do not handle lighting + !(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags) + !(line->flags & ML_BOUNCY), // do not handle collision + (line->flags & ML_EFFECT1), // do ghost fade (no collision during fade) + (line->flags & ML_TFERLINE)); // use exact alpha values (for opengl) + } + } + j++; + } + + if (!foundrover) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Can't find a FOF control sector with tag %d\n", foftag); + return; + } + } + break; + } + + case 454: // Stop fading FOF + { + INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + sector_t *sec; // Sector that the FOF is visible in + ffloor_t *rover; // FOF that we are going to operate + boolean foundrover = false; // for debug, "Can't find a FOF" message + + for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + { + sec = sectors + secnum; + + if (!sec->ffloors) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 454 Executor: Target sector #%d has no FOFs.\n", secnum); + return; + } + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector->tag == foftag) + { + foundrover = true; + + P_ResetFakeFloorFader(rover, NULL, + !(line->flags & ML_BLOCKMONSTERS)); // do not finalize collision flags + } + } + + if (!foundrover) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 454 Executor: Can't find a FOF control sector with tag %d\n", foftag); + return; + } + } + break; + } + + case 455: // Fade colormap + for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + { + extracolormap_t *source_exc, *dest_exc, *exc; + INT32 speed = (INT32)((line->flags & ML_DONTPEGBOTTOM) || !sides[line->sidenum[0]].rowoffset) && line->sidenum[1] != 0xFFFF ? + abs(sides[line->sidenum[1]].rowoffset >> FRACBITS) + : abs(sides[line->sidenum[0]].rowoffset >> FRACBITS); + + // Prevent continuous execs from interfering on an existing fade + if (!(line->flags & ML_EFFECT5) + && sectors[secnum].fadecolormapdata) + //&& ((fadecolormap_t*)sectors[secnum].fadecolormapdata)->timer > (ticbased ? 2 : speed*2)) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 455 Executor: Fade color thinker already exists, timer: %d\n", ((fadecolormap_t*)sectors[secnum].fadecolormapdata)->timer); + continue; + } + + if (line->flags & ML_TFERLINE) // use back colormap instead of target sector + sectors[secnum].extra_colormap = (line->sidenum[1] != 0xFFFF) ? + sides[line->sidenum[1]].colormap_data : NULL; + + exc = sectors[secnum].extra_colormap; + + if (!(line->flags & ML_BOUNCY) // BOUNCY: Do not override fade from default rgba + && !R_CheckDefaultColormap(sides[line->sidenum[0]].colormap_data, true, false, false) + && R_CheckDefaultColormap(exc, true, false, false)) + { + exc = R_CopyColormap(exc, false); + exc->rgba = R_GetRgbaRGB(sides[line->sidenum[0]].colormap_data->rgba) + R_PutRgbaA(R_GetRgbaA(exc->rgba)); + //exc->fadergba = R_GetRgbaRGB(sides[line->sidenum[0]].colormap_data->rgba) + R_PutRgbaA(R_GetRgbaA(exc->fadergba)); + + if (!(source_exc = R_GetColormapFromList(exc))) + { + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + source_exc = exc; + } + else + Z_Free(exc); + + sectors[secnum].extra_colormap = source_exc; + } + else + source_exc = exc ? exc : R_GetDefaultColormap(); + + if (line->flags & ML_EFFECT3) // relative calc + { + exc = R_AddColormaps( + source_exc, + sides[line->sidenum[0]].colormap_data, + line->flags & ML_EFFECT1, // subtract R + line->flags & ML_NOCLIMB, // subtract G + line->flags & ML_EFFECT2, // subtract B + false, // subtract A (no flag for this, just pass negative alpha) + line->flags & ML_EFFECT1, // subtract FadeR + line->flags & ML_NOCLIMB, // subtract FadeG + line->flags & ML_EFFECT2, // subtract FadeB + false, // subtract FadeA (no flag for this, just pass negative alpha) + false, // subtract FadeStart (we ran out of flags) + false, // subtract FadeEnd (we ran out of flags) + false, // ignore Fog (we ran out of flags) + line->flags & ML_DONTPEGBOTTOM, + (line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].textureoffset >> FRACBITS) : 0, + (line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].rowoffset >> FRACBITS) : 0, + false); + } + else if (line->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets) + { + exc = R_CopyColormap(sides[line->sidenum[0]].colormap_data, false); + exc->rgba = R_GetRgbaRGB(exc->rgba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].textureoffset >> FRACBITS, 25), 0)); + exc->fadergba = R_GetRgbaRGB(exc->fadergba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].rowoffset >> FRACBITS, 25), 0)); + } + else + exc = R_CopyColormap(sides[line->sidenum[0]].colormap_data, false); + + if (!(dest_exc = R_GetColormapFromList(exc))) + { + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + dest_exc = exc; + } + else + Z_Free(exc); + + Add_ColormapFader(§ors[secnum], source_exc, dest_exc, (line->flags & ML_EFFECT4), // tic-based timing + speed); + } + break; + + case 456: // Stop fade colormap + for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;) + P_ResetColormapFader(§ors[secnum]); + break; + #ifdef POLYOBJECTS case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing @@ -3337,6 +3784,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 491: PolyTranslucency(line); break; + case 492: + PolyFade(line); + break; #endif default: @@ -5155,7 +5605,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f ffloor->spawnflags = ffloor->flags = flags; ffloor->master = master; ffloor->norender = INFTICS; - + ffloor->fadingdata = NULL; // Scan the thinkers to check for special conditions applying to this FOF. // If we have thinkers sorted by sector, just check the relevant ones; @@ -6760,7 +7210,7 @@ void P_SpawnSpecials(INT32 fromnetsave) case 606: // HACK! Copy colormaps. Just plain colormaps. for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].midmap = lines[i].frontsector->midmap; + sectors[s].extra_colormap = sectors[s].spawn_extra_colormap = sides[lines[i].sidenum[0]].colormap_data; break; #ifdef ESLOPE // Slope copy specials. Handled here for sanity. @@ -7322,6 +7772,591 @@ void T_Disappear(disappear_t *d) } } +/** Removes fadingdata from FOF control sector + * + * \param line line to search for target faders + * \param data pointer to set new fadingdata to. Can be NULL to erase. + */ +static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finalize) +{ + fade_t *fadingdata = (fade_t *)rover->fadingdata; + // find any existing thinkers and remove them, then replace with new data + if (fadingdata != data) + { + if (fadingdata) + { + if (finalize) + P_FadeFakeFloor(rover, + fadingdata->sourcevalue, + fadingdata->alpha >= fadingdata->destvalue ? + fadingdata->alpha - 1 : // trigger fade-out finish + fadingdata->alpha + 1, // trigger fade-in finish + 0, + fadingdata->ticbased, + &fadingdata->timer, + fadingdata->doexists, + fadingdata->dotranslucent, + fadingdata->dolighting, + fadingdata->docolormap, + fadingdata->docollision, + fadingdata->doghostfade, + fadingdata->exactalpha); + rover->alpha = fadingdata->alpha; + + if (fadingdata->dolighting) + P_RemoveLighting(§ors[rover->secnum]); + + if (fadingdata->docolormap) + P_ResetColormapFader(§ors[rover->secnum]); + + P_RemoveThinker(&fadingdata->thinker); + } + + rover->fadingdata = data; + } +} + +static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destvalue, INT16 speed, boolean ticbased, INT32 *timer, + boolean doexists, boolean dotranslucent, boolean dolighting, boolean docolormap, + boolean docollision, boolean doghostfade, boolean exactalpha) +{ + boolean stillfading = false; + INT32 alpha; + fade_t *fadingdata = (fade_t *)rover->fadingdata; + (void)docolormap; // *shrug* maybe we can use this in the future. For now, let's be consistent with our other function params + + if (rover->master->special == 258) // Laser block + return false; + + // If fading an invisible FOF whose render flags we did not yet set, + // initialize its alpha to 1 + if (dotranslucent && + (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->flags & FF_FOG) && // do not include fog + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES) && + !(rover->flags & FF_RENDERALL)) + rover->alpha = 1; + + if (fadingdata) + alpha = fadingdata->alpha; + else + alpha = rover->alpha; + + // routines specific to fade in and fade out + if (!ticbased && alpha == destvalue) + return stillfading; + else if (alpha > destvalue) // fade out + { + // finish fading out + if (speed < 1 || (!ticbased && alpha - speed <= destvalue + speed) || + (ticbased && (--(*timer) <= 0 || alpha <= destvalue))) + { + alpha = destvalue; + + if (docollision) + { + if (rover->spawnflags & FF_SOLID) + rover->flags &= ~FF_SOLID; + if (rover->spawnflags & FF_SWIMMABLE) + rover->flags &= ~FF_SWIMMABLE; + if (rover->spawnflags & FF_QUICKSAND) + rover->flags &= ~FF_QUICKSAND; + if (rover->spawnflags & FF_BUSTUP) + rover->flags &= ~FF_BUSTUP; + if (rover->spawnflags & FF_MARIO) + rover->flags &= ~FF_MARIO; + } + } + else // continue fading out + { + if (!ticbased) + alpha -= speed; + else + { + INT16 delta = abs(destvalue - sourcevalue); + fixed_t factor = min(FixedDiv(speed - (*timer), speed), 1*FRACUNIT); + alpha = max(min(alpha, sourcevalue - (INT16)FixedMul(delta, factor)), destvalue); + } + stillfading = true; + } + } + else // fade in + { + // finish fading in + if (speed < 1 || (!ticbased && alpha + speed >= destvalue - speed) || + (ticbased && (--(*timer) <= 0 || alpha >= destvalue))) + { + alpha = destvalue; + + if (docollision) + { + if (rover->spawnflags & FF_SOLID) + rover->flags |= FF_SOLID; + if (rover->spawnflags & FF_SWIMMABLE) + rover->flags |= FF_SWIMMABLE; + if (rover->spawnflags & FF_QUICKSAND) + rover->flags |= FF_QUICKSAND; + if (rover->spawnflags & FF_BUSTUP) + rover->flags |= FF_BUSTUP; + if (rover->spawnflags & FF_MARIO) + rover->flags |= FF_MARIO; + } + } + else // continue fading in + { + if (!ticbased) + alpha += speed; + else + { + INT16 delta = abs(destvalue - sourcevalue); + fixed_t factor = min(FixedDiv(speed - (*timer), speed), 1*FRACUNIT); + alpha = min(max(alpha, sourcevalue + (INT16)FixedMul(delta, factor)), destvalue); + } + stillfading = true; + } + } + + // routines common to both fade in and fade out + if (!stillfading) + { + if (doexists && !(rover->spawnflags & FF_BUSTUP)) + { + if (alpha <= 1) + rover->flags &= ~FF_EXISTS; + else + rover->flags |= FF_EXISTS; + + // Re-render lighting at end of fade + if (dolighting && !(rover->spawnflags & FF_NOSHADE) && !(rover->flags & FF_EXISTS)) + rover->target->moved = true; + } + + if (dotranslucent && !(rover->flags & FF_FOG)) + { + if (alpha >= 256) + { + if (!(rover->flags & FF_CUTSOLIDS) && + (rover->spawnflags & FF_CUTSOLIDS)) + { + rover->flags |= FF_CUTSOLIDS; + rover->target->moved = true; + } + + rover->flags &= ~FF_TRANSLUCENT; + } + else + { + rover->flags |= FF_TRANSLUCENT; + + if ((rover->flags & FF_CUTSOLIDS) && + (rover->spawnflags & FF_CUTSOLIDS)) + { + rover->flags &= ~FF_CUTSOLIDS; + rover->target->moved = true; + } + } + + if ((rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES)) + { + if (rover->alpha > 1) + rover->flags |= FF_RENDERALL; + else + rover->flags &= ~FF_RENDERALL; + } + } + } + else + { + if (doexists && !(rover->spawnflags & FF_BUSTUP)) + { + // Re-render lighting if we haven't yet set FF_EXISTS (beginning of fade) + if (dolighting && !(rover->spawnflags & FF_NOSHADE) && !(rover->flags & FF_EXISTS)) + rover->target->moved = true; + + rover->flags |= FF_EXISTS; + } + + if (dotranslucent && !(rover->flags & FF_FOG)) + { + rover->flags |= FF_TRANSLUCENT; + + if ((rover->flags & FF_CUTSOLIDS) && + (rover->spawnflags & FF_CUTSOLIDS)) + { + rover->flags &= ~FF_CUTSOLIDS; + rover->target->moved = true; + } + + if ((rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES)) + rover->flags |= FF_RENDERALL; + } + + if (docollision) + { + if (doghostfade) // remove collision flags during fade + { + if (rover->spawnflags & FF_SOLID) + rover->flags &= ~FF_SOLID; + if (rover->spawnflags & FF_SWIMMABLE) + rover->flags &= ~FF_SWIMMABLE; + if (rover->spawnflags & FF_QUICKSAND) + rover->flags &= ~FF_QUICKSAND; + if (rover->spawnflags & FF_BUSTUP) + rover->flags &= ~FF_BUSTUP; + if (rover->spawnflags & FF_MARIO) + rover->flags &= ~FF_MARIO; + } + else // keep collision during fade + { + if (rover->spawnflags & FF_SOLID) + rover->flags |= FF_SOLID; + if (rover->spawnflags & FF_SWIMMABLE) + rover->flags |= FF_SWIMMABLE; + if (rover->spawnflags & FF_QUICKSAND) + rover->flags |= FF_QUICKSAND; + if (rover->spawnflags & FF_BUSTUP) + rover->flags |= FF_BUSTUP; + if (rover->spawnflags & FF_MARIO) + rover->flags |= FF_MARIO; + } + } + } + + if (!(rover->flags & FF_FOG)) // don't set FOG alpha + { + if (!stillfading || exactalpha) + rover->alpha = alpha; + else // clamp fadingdata->alpha to software's alpha levels + { + if (alpha < 12) + rover->alpha = destvalue < 12 ? destvalue : 1; // Don't even draw it + else if (alpha < 38) + rover->alpha = destvalue >= 12 && destvalue < 38 ? destvalue : 25; + else if (alpha < 64) + rover->alpha = destvalue >=38 && destvalue < 64 ? destvalue : 51; + else if (alpha < 89) + rover->alpha = destvalue >= 64 && destvalue < 89 ? destvalue : 76; + else if (alpha < 115) + rover->alpha = destvalue >= 89 && destvalue < 115 ? destvalue : 102; + else if (alpha < 140) + rover->alpha = destvalue >= 115 && destvalue < 140 ? destvalue : 128; + else if (alpha < 166) + rover->alpha = destvalue >= 140 && destvalue < 166 ? destvalue : 154; + else if (alpha < 192) + rover->alpha = destvalue >= 166 && destvalue < 192 ? destvalue : 179; + else if (alpha < 217) + rover->alpha = destvalue >= 192 && destvalue < 217 ? destvalue : 204; + else if (alpha < 243) + rover->alpha = destvalue >= 217 && destvalue < 243 ? destvalue : 230; + else // Opaque + rover->alpha = destvalue >= 243 ? destvalue : 256; + } + } + + if (fadingdata) + fadingdata->alpha = alpha; + + return stillfading; +} + +/** Adds fake floor fader thinker. + * + * \param destvalue transparency value to fade to + * \param speed speed to fade by + * \param ticbased tic-based logic, speed = duration + * \param relative Destvalue is relative to rover->alpha + * \param doexists handle FF_EXISTS + * \param dotranslucent handle FF_TRANSLUCENT + * \param dolighting fade FOF light + * \param docollision handle interactive flags + * \param doghostfade no interactive flags during fading + * \param exactalpha use exact alpha values (opengl) + */ +static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloornum, + INT16 destvalue, INT16 speed, boolean ticbased, boolean relative, + boolean doexists, boolean dotranslucent, boolean dolighting, boolean docolormap, + boolean docollision, boolean doghostfade, boolean exactalpha) +{ + fade_t *d; + + // If fading an invisible FOF whose render flags we did not yet set, + // initialize its alpha to 1 + if (dotranslucent && + (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE + !(rover->spawnflags & FF_RENDERSIDES) && + !(rover->spawnflags & FF_RENDERPLANES) && + !(rover->flags & FF_RENDERALL)) + rover->alpha = 1; + + // already equal, nothing to do + if (rover->alpha == max(1, min(256, relative ? rover->alpha + destvalue : destvalue))) + return; + + d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL); + + d->thinker.function.acp1 = (actionf_p1)T_Fade; + d->rover = rover; + d->sectornum = (UINT32)sectornum; + d->ffloornum = (UINT32)ffloornum; + + d->alpha = d->sourcevalue = rover->alpha; + d->destvalue = max(1, min(256, relative ? rover->alpha + destvalue : destvalue)); // ffloor->alpha is 1-256 + + if (ticbased) + { + d->ticbased = true; + d->timer = d->speed = abs(speed); // use d->speed as total duration + } + else + { + d->ticbased = false; + d->speed = max(1, speed); // minimum speed 1/tic // if speed < 1, alpha is set immediately in thinker + d->timer = -1; + } + + d->doexists = doexists; + d->dotranslucent = dotranslucent; + d->dolighting = dolighting; + d->docolormap = docolormap; + d->docollision = docollision; + d->doghostfade = doghostfade; + d->exactalpha = exactalpha; + + // find any existing thinkers and remove them, then replace with new data + P_ResetFakeFloorFader(rover, d, false); + + // Set a separate thinker for shadow fading + if (dolighting && !(rover->flags & FF_NOSHADE)) + { + UINT16 lightdelta = abs(sectors[rover->secnum].spawn_lightlevel - rover->target->lightlevel); + fixed_t alphapercent = min(FixedDiv(d->destvalue, rover->spawnalpha), 1*FRACUNIT); // don't make darker than spawn_lightlevel + fixed_t adjustedlightdelta = FixedMul(lightdelta, alphapercent); + + if (rover->target->lightlevel >= sectors[rover->secnum].spawn_lightlevel) // fading out, get lighter + d->destlightlevel = rover->target->lightlevel - adjustedlightdelta; + else // fading in, get darker + d->destlightlevel = rover->target->lightlevel + adjustedlightdelta; + + P_FadeLightBySector(§ors[rover->secnum], + d->destlightlevel, + ticbased ? d->timer : + FixedFloor(FixedDiv(abs(d->destvalue - d->alpha), d->speed))/FRACUNIT, + true); + } + else + d->destlightlevel = -1; + + // Set a separate thinker for colormap fading + if (docolormap && !(rover->flags & FF_NOSHADE) && sectors[rover->secnum].spawn_extra_colormap) + { + extracolormap_t *dest_exc, + *source_exc = sectors[rover->secnum].extra_colormap ? sectors[rover->secnum].extra_colormap : R_GetDefaultColormap(); + + INT32 colordelta = R_GetRgbaA(sectors[rover->secnum].spawn_extra_colormap->rgba); // alpha is from 0 + fixed_t alphapercent = min(FixedDiv(d->destvalue, rover->spawnalpha), 1*FRACUNIT); // don't make darker than spawn_lightlevel + fixed_t adjustedcolordelta = FixedMul(colordelta, alphapercent); + INT32 coloralpha; + + coloralpha = adjustedcolordelta; + + dest_exc = R_CopyColormap(sectors[rover->secnum].spawn_extra_colormap, false); + dest_exc->rgba = R_GetRgbaRGB(dest_exc->rgba) + R_PutRgbaA(coloralpha); + + if (!(d->dest_exc = R_GetColormapFromList(dest_exc))) + { + dest_exc->colormap = R_CreateLightTable(dest_exc); + R_AddColormapToList(dest_exc); + d->dest_exc = dest_exc; + } + else + Z_Free(dest_exc); + + // If fading from 0, set source_exc rgb same to dest_exc + if (!R_CheckDefaultColormap(d->dest_exc, true, false, false) + && R_CheckDefaultColormap(source_exc, true, false, false)) + { + extracolormap_t *exc = R_CopyColormap(source_exc, false); + exc->rgba = R_GetRgbaRGB(d->dest_exc->rgba) + R_PutRgbaA(R_GetRgbaA(source_exc->rgba)); + exc->fadergba = R_GetRgbaRGB(d->dest_exc->rgba) + R_PutRgbaA(R_GetRgbaA(source_exc->fadergba)); + + if (!(source_exc = R_GetColormapFromList(exc))) + { + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + source_exc = exc; + } + else + Z_Free(exc); + } + + Add_ColormapFader(§ors[rover->secnum], source_exc, d->dest_exc, true, + ticbased ? d->timer : + FixedFloor(FixedDiv(abs(d->destvalue - d->alpha), d->speed))/FRACUNIT); + } + + P_AddThinker(&d->thinker); +} + +/** Makes a FOF fade + * + * \param d Fade thinker. + * \sa P_AddFakeFloorFader + */ +void T_Fade(fade_t *d) +{ + if (d->rover && !P_FadeFakeFloor(d->rover, d->sourcevalue, d->destvalue, d->speed, d->ticbased, &d->timer, + d->doexists, d->dotranslucent, d->dolighting, d->docolormap, d->docollision, d->doghostfade, d->exactalpha)) + { + // Finalize lighting, copypasta from P_AddFakeFloorFader + if (d->dolighting && !(d->rover->flags & FF_NOSHADE) && d->destlightlevel > -1) + sectors[d->rover->secnum].lightlevel = d->destlightlevel; + + // Finalize colormap + if (d->docolormap && !(d->rover->flags & FF_NOSHADE) && sectors[d->rover->secnum].spawn_extra_colormap) + sectors[d->rover->secnum].extra_colormap = d->dest_exc; + + P_RemoveFakeFloorFader(d->rover); + } +} + +static void P_ResetColormapFader(sector_t *sector) +{ + if (sector->fadecolormapdata) + { + // The thinker is the first member in all the action structs, + // so just let the thinker get freed, and that will free the whole + // structure. + P_RemoveThinker(&((elevator_t *)sector->fadecolormapdata)->thinker); + sector->fadecolormapdata = NULL; + } +} + +static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, extracolormap_t *dest_exc, + boolean ticbased, INT32 duration) +{ + fadecolormap_t *d; + + P_ResetColormapFader(sector); + + // nothing to do, set immediately + if (!duration || R_CheckEqualColormaps(source_exc, dest_exc, true, true, true)) + { + sector->extra_colormap = dest_exc; + return; + } + + d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL); + d->thinker.function.acp1 = (actionf_p1)T_FadeColormap; + d->sector = sector; + d->source_exc = source_exc; + d->dest_exc = dest_exc; + + if (ticbased) + { + d->ticbased = true; + d->duration = d->timer = duration; + } + else + { + d->ticbased = false; + d->timer = 256; + d->duration = duration; // use as speed + } + + sector->fadecolormapdata = d; + P_AddThinker(&d->thinker); // add thinker +} + +void T_FadeColormap(fadecolormap_t *d) +{ + if ((d->ticbased && --d->timer <= 0) + || (!d->ticbased && (d->timer -= d->duration) <= 0)) // d->duration used as speed decrement + { + d->sector->extra_colormap = d->dest_exc; + P_ResetColormapFader(d->sector); + } + else + { + extracolormap_t *exc; + INT32 duration = d->ticbased ? d->duration : 256; + fixed_t factor = min(FixedDiv(duration - d->timer, duration), 1*FRACUNIT); + INT16 cr, cg, cb, ca, fadestart, fadeend, fog; + INT32 rgba, fadergba; + + // NULL failsafes (or intentionally set to signify default) + if (!d->sector->extra_colormap) + d->sector->extra_colormap = R_GetDefaultColormap(); + + if (!d->source_exc) + d->source_exc = R_GetDefaultColormap(); + + if (!d->dest_exc) + d->dest_exc = R_GetDefaultColormap(); + + // For each var (rgba + fadergba + params = 11 vars), we apply + // percentage fading: currentval = sourceval + (delta * percent of duration elapsed) + // delta is negative when fading out (destval is lower) + // max/min are used to ensure progressive calcs don't go backwards and to cap values to dest. + +#define APPLYFADE(dest, src, cur) (\ +(dest-src < 0) ? \ + max(\ + min(cur,\ + src + (INT16)FixedMul(dest-src, factor)),\ + dest)\ +: (dest-src > 0) ? \ + min(\ + max(cur,\ + src + (INT16)FixedMul(dest-src, factor)),\ + dest)\ +: \ + dest\ +) + + cr = APPLYFADE(R_GetRgbaR(d->dest_exc->rgba), R_GetRgbaR(d->source_exc->rgba), R_GetRgbaR(d->sector->extra_colormap->rgba)); + cg = APPLYFADE(R_GetRgbaG(d->dest_exc->rgba), R_GetRgbaG(d->source_exc->rgba), R_GetRgbaG(d->sector->extra_colormap->rgba)); + cb = APPLYFADE(R_GetRgbaB(d->dest_exc->rgba), R_GetRgbaB(d->source_exc->rgba), R_GetRgbaB(d->sector->extra_colormap->rgba)); + ca = APPLYFADE(R_GetRgbaA(d->dest_exc->rgba), R_GetRgbaA(d->source_exc->rgba), R_GetRgbaA(d->sector->extra_colormap->rgba)); + + rgba = R_PutRgbaRGBA(cr, cg, cb, ca); + + cr = APPLYFADE(R_GetRgbaR(d->dest_exc->fadergba), R_GetRgbaR(d->source_exc->fadergba), R_GetRgbaR(d->sector->extra_colormap->fadergba)); + cg = APPLYFADE(R_GetRgbaG(d->dest_exc->fadergba), R_GetRgbaG(d->source_exc->fadergba), R_GetRgbaG(d->sector->extra_colormap->fadergba)); + cb = APPLYFADE(R_GetRgbaB(d->dest_exc->fadergba), R_GetRgbaB(d->source_exc->fadergba), R_GetRgbaB(d->sector->extra_colormap->fadergba)); + ca = APPLYFADE(R_GetRgbaA(d->dest_exc->fadergba), R_GetRgbaA(d->source_exc->fadergba), R_GetRgbaA(d->sector->extra_colormap->fadergba)); + + fadergba = R_PutRgbaRGBA(cr, cg, cb, ca); + + fadestart = APPLYFADE(d->dest_exc->fadestart, d->source_exc->fadestart, d->sector->extra_colormap->fadestart); + fadeend = APPLYFADE(d->dest_exc->fadeend, d->source_exc->fadeend, d->sector->extra_colormap->fadeend); + fog = abs(factor) > FRACUNIT/2 ? d->dest_exc->fog : d->source_exc->fog; // set new fog flag halfway through fade + +#undef APPLYFADE + + ////////////////// + // setup new colormap + ////////////////// + + if (!(d->sector->extra_colormap = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, fog))) + { + exc = R_CreateDefaultColormap(false); + exc->fadestart = fadestart; + exc->fadeend = fadeend; + exc->fog = (boolean)fog; + exc->rgba = rgba; + exc->fadergba = fadergba; + exc->colormap = R_CreateLightTable(exc); + R_AddColormapToList(exc); + d->sector->extra_colormap = exc; + } + } +} + /* SoM: 3/8/2000: Friction functions start. Add_Friction, diff --git a/src/p_spec.h b/src/p_spec.h index e0bcc18eb..f04e6590f 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -134,10 +134,15 @@ typedef struct */ typedef struct { - thinker_t thinker; ///< Thinker in use for the effect. - sector_t *sector; ///< Sector where action is taking place. - INT32 destlevel; ///< Light level we're fading to. - INT32 speed; ///< Speed at which to change light level. + thinker_t thinker; ///< Thinker in use for the effect. + sector_t *sector; ///< Sector where action is taking place. + INT16 sourcelevel; ///< Light level we're fading from. + INT16 destlevel; ///< Light level we're fading to. + + fixed_t fixedcurlevel; ///< Fixed point for current light level. + fixed_t fixedpertic; ///< Fixed point for increment per tic. + // The reason for those two above to be fixed point is to deal with decimal values that would otherwise get trimmed away. + INT32 timer; ///< Internal timer. } lightlevel_t; #define GLOWSPEED 8 @@ -145,6 +150,8 @@ typedef struct #define FASTDARK 15 #define SLOWDARK 35 +void P_RemoveLighting(sector_t *sector); + void T_FireFlicker(fireflicker_t *flick); fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxsector, INT32 length); void T_LightningFlash(lightflash_t *flash); @@ -156,7 +163,8 @@ strobe_t * P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector void T_Glow(glow_t *g); glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, INT32 length); -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed); +void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean ticbased); +void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force); void T_LightFade(lightlevel_t *ll); typedef enum @@ -453,6 +461,47 @@ typedef struct void T_Disappear(disappear_t *d); +// Model for fading FOFs +typedef struct +{ + thinker_t thinker; ///< Thinker structure for effect. + ffloor_t *rover; ///< Target ffloor + extracolormap_t *dest_exc; ///< Colormap to fade to + UINT32 sectornum; ///< Number of ffloor target sector + UINT32 ffloornum; ///< Number of ffloor of target sector + INT32 alpha; ///< Internal alpha counter + INT16 sourcevalue; ///< Transparency value to fade from + INT16 destvalue; ///< Transparency value to fade to + INT16 destlightlevel; ///< Light level to fade to + INT16 speed; ///< Speed to fade by + boolean ticbased; ///< Tic-based logic toggle + INT32 timer; ///< Timer for tic-based logic + boolean doexists; ///< Handle FF_EXISTS + boolean dotranslucent; ///< Handle FF_TRANSLUCENT + boolean dolighting; ///< Handle shadows and light blocks + boolean docolormap; ///< Handle colormaps + boolean docollision; ///< Handle interactive flags + boolean doghostfade; ///< No interactive flags during fading + boolean exactalpha; ///< Use exact alpha values (opengl) +} fade_t; + +void T_Fade(fade_t *d); + +// Model for fading colormaps + +typedef struct +{ + thinker_t thinker; ///< Thinker structure for effect. + sector_t *sector; ///< Sector where action is taking place. + extracolormap_t *source_exc; + extracolormap_t *dest_exc; + boolean ticbased; ///< Tic-based timing + INT32 duration; ///< Total duration for tic-based logic (OR: speed increment) + INT32 timer; ///< Timer for tic-based logic (OR: internal speed counter) +} fadecolormap_t; + +void T_FadeColormap(fadecolormap_t *d); + // Prototype functions for pushers void T_Pusher(pusher_t *p); mobj_t *P_GetPushThing(UINT32 s); diff --git a/src/p_tick.c b/src/p_tick.c index a51ce2eb6..eb47e0c36 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -56,12 +56,12 @@ void Command_Numthinkers_f(void) CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n")); CONS_Printf( "\t1: P_MobjThinker\n" - "\t2: P_RainThinker\n" - "\t3: P_SnowThinker\n" - "\t4: P_NullPrecipThinker\n" - "\t5: T_Friction\n" - "\t6: T_Pusher\n" - "\t7: P_RemoveThinkerDelayed\n"); + /*"\t2: P_RainThinker\n" + "\t3: P_SnowThinker\n"*/ + "\t2: P_NullPrecipThinker\n" + "\t3: T_Friction\n" + "\t4: T_Pusher\n" + "\t5: P_RemoveThinkerDelayed\n"); return; } @@ -73,27 +73,27 @@ void Command_Numthinkers_f(void) action = (actionf_p1)P_MobjThinker; CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker"); break; - case 2: + /*case 2: action = (actionf_p1)P_RainThinker; CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker"); break; case 3: action = (actionf_p1)P_SnowThinker; CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker"); - break; - case 4: + break;*/ + case 2: action = (actionf_p1)P_NullPrecipThinker; CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker"); break; - case 5: + case 3: action = (actionf_p1)T_Friction; CONS_Printf(M_GetText("Number of %s: "), "T_Friction"); break; - case 6: + case 4: action = (actionf_p1)T_Pusher; CONS_Printf(M_GetText("Number of %s: "), "T_Pusher"); break; - case 7: + case 5: action = (actionf_p1)P_RemoveThinkerDelayed; CONS_Printf(M_GetText("Number of %s: "), "P_RemoveThinkerDelayed"); break; diff --git a/src/p_user.c b/src/p_user.c index 4137673dd..dd2ddbc82 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -596,10 +596,6 @@ static void P_DeNightserizePlayer(player_t *player) else if (player == &players[secondarydisplayplayer]) localaiming2 = 0; - // If you screwed up, kiss your score and ring bonus goodbye. - player->marescore = 0; - player->rings = 0; - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); // If in a special stage, add some preliminary exit time. @@ -611,6 +607,11 @@ static void P_DeNightserizePlayer(player_t *player) players[i].nightstime = 1; // force everyone else to fall too. player->exiting = 3*TICRATE; stagefailed = true; // NIGHT OVER + + // If you screwed up, kiss your score and ring bonus goodbye. + // But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground. + player->marescore = player->spheres =\ + player->rings = 0; } // Check to see if the player should be killed. @@ -624,7 +625,11 @@ static void P_DeNightserizePlayer(player_t *player) continue; if (mo2->flags2 & MF2_AMBUSH) + { + player->marescore = player->spheres =\ + player->rings = 0; P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); + } break; } @@ -7077,8 +7082,14 @@ static void P_MovePlayer(player_t *player) if (playeringame[i]) players[i].exiting = (14*TICRATE)/5 + 1; } - else if (player->spheres > 0) + else { + // Damage whether or not we have spheres, as player should recoil upon losing points P_DamageMobj(player->mo, NULL, NULL, 1, 0); + + // Now deduct our mare score! + player->marescore = player->spheres =\ + player->rings = 0; + } player->powers[pw_carry] = CR_NONE; } } @@ -8766,7 +8777,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall subsector_t *newsubsec; fixed_t f1, f2; - cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (player->mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!! + // We probably shouldn't move the camera if there is no player or player mobj somehow + if (!player || !player->mo) + return true; + + mo = player->mo; + + cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!! if (!(player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD)) { @@ -8787,7 +8804,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else if (player == &players[secondarydisplayplayer]) focusangle = localangle2; else - focusangle = player->mo->angle; + focusangle = mo->angle; if (thiscam == &camera) camrotate = cv_cam_rotate.value; else if (thiscam == &camera2) @@ -8799,17 +8816,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall return true; } - if (!player || !player->mo) - return true; - - mo = player->mo; - thiscam->radius = FixedMul(20*FRACUNIT, mo->scale); thiscam->height = FixedMul(16*FRACUNIT, mo->scale); - if (!mo) - return true; - // Don't run while respawning from a starpost // Inu 4/8/13 Why not?! // if (leveltime > 0 && timeinmap <= 0) @@ -8817,7 +8826,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (player->powers[pw_carry] == CR_NIGHTSMODE) { - focusangle = player->mo->angle; + focusangle = mo->angle; focusaiming = 0; } else if (player == &players[consoleplayer]) @@ -8832,7 +8841,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else { - focusangle = player->mo->angle; + focusangle = mo->angle; focusaiming = player->aiming; } @@ -8879,12 +8888,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall angle = R_PointToAngle2(player->axis1->x, player->axis1->y, player->axis2->x, player->axis2->y); angle += ANGLE_90; } - else if (player->mo->target) + else if (mo->target) { - if (player->mo->target->flags2 & MF2_AMBUSH) - angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); + if (mo->target->flags2 & MF2_AMBUSH) + angle = R_PointToAngle2(mo->target->x, mo->target->y, mo->x, mo->y); else - angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y); + angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y); } } else if (P_AnalogMove(player)) // Analog @@ -8973,7 +8982,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (twodlevel || (mo->flags2 & MF2_TWOD)) { // Camera doesn't ALWAYS need to move, only when running... - if (abs(player->mo->momx) > 10) + if (abs(mo->momx) > 10) { // Move the camera all smooth-like, not jerk it around... if (mo->momx > 0) @@ -9291,13 +9300,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall vy = thiscam->y; } - if (P_AproxDistance(vx - player->mo->x, vy - player->mo->y) < FixedMul(48*FRACUNIT, mo->scale)) - player->mo->flags2 |= MF2_SHADOW; + if (P_AproxDistance(vx - mo->x, vy - mo->y) < FixedMul(48*FRACUNIT, mo->scale)) + mo->flags2 |= MF2_SHADOW; else - player->mo->flags2 &= ~MF2_SHADOW; + mo->flags2 &= ~MF2_SHADOW; } else - player->mo->flags2 &= ~MF2_SHADOW; + mo->flags2 &= ~MF2_SHADOW; /* if (!resetcalled && (player->powers[pw_carry] == CR_NIGHTSMODE && player->exiting)) { diff --git a/src/r_bsp.c b/src/r_bsp.c index 183def25a..cbb012b28 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -234,8 +234,6 @@ static INT32 R_DoorClosed(void) sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, INT32 *ceilinglightlevel, boolean back) { - INT32 mapnum = -1; - if (floorlightlevel) *floorlightlevel = sec->floorlightsec == -1 ? sec->lightlevel : sectors[sec->floorlightsec].lightlevel; @@ -244,10 +242,10 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, *ceilinglightlevel = sec->ceilinglightsec == -1 ? sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; - // If the sector has a midmap, it's probably from 280 type - if (sec->midmap != -1) - mapnum = sec->midmap; - else if (sec->heightsec != -1) + // if (sec->midmap != -1) + // mapnum = sec->midmap; + // In original colormap code, this block did not run if sec->midmap was set + if (!sec->extra_colormap && sec->heightsec != -1) { const sector_t *s = §ors[sec->heightsec]; mobj_t *viewmobj = viewplayer->mo; @@ -271,8 +269,6 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->floorheight = s->floorheight; tempsec->ceilingheight = s->ceilingheight; - mapnum = s->midmap; - if ((underwater && (tempsec-> floorheight = sec->floorheight, tempsec->ceilingheight = s->floorheight - 1, !back)) || viewz <= s->floorheight) { // head-below-floor hack @@ -298,7 +294,6 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->ceiling_yoffs = s->ceiling_yoffs; tempsec->ceilingpic_angle = s->ceilingpic_angle; } - mapnum = s->bottommap; } tempsec->lightlevel = s->lightlevel; @@ -322,8 +317,6 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; tempsec->floorpic_angle = tempsec->ceilingpic_angle = s->ceilingpic_angle; - mapnum = s->topmap; - if (s->floorpic == skyflatnum) // SKYFIX? { tempsec->ceilingheight = tempsec->floorheight-1; @@ -354,11 +347,6 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, sec = tempsec; } - if (mapnum >= 0 && (size_t)mapnum < num_extra_colormaps) - sec->extra_colormap = &extra_colormaps[mapnum]; - else - sec->extra_colormap = NULL; - return sec; } @@ -937,11 +925,11 @@ static void R_Subsector(size_t num) light = R_GetPlaneLight(frontsector, floorcenterz, false); if (frontsector->floorlightsec == -1) floorlightlevel = *frontsector->lightlist[light].lightlevel; - floorcolormap = frontsector->lightlist[light].extra_colormap; + floorcolormap = *frontsector->lightlist[light].extra_colormap; light = R_GetPlaneLight(frontsector, ceilingcenterz, false); if (frontsector->ceilinglightsec == -1) ceilinglightlevel = *frontsector->lightlist[light].lightlevel; - ceilingcolormap = frontsector->lightlist[light].extra_colormap; + ceilingcolormap = *frontsector->lightlist[light].extra_colormap; } sub->sector->extra_colormap = frontsector->extra_colormap; @@ -1038,7 +1026,7 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, - *rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover + *rover->bottomyoffs, *rover->bottomangle, *frontsector->lightlist[light].extra_colormap, rover #ifdef POLYOBJECTS_PLANES , NULL #endif @@ -1084,7 +1072,7 @@ static void R_Subsector(size_t num) ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle, - frontsector->lightlist[light].extra_colormap, rover + *frontsector->lightlist[light].extra_colormap, rover #ifdef POLYOBJECTS_PLANES , NULL #endif @@ -1237,7 +1225,7 @@ void R_Prep3DFloors(sector_t *sector) ffloor_t *rover; ffloor_t *best; fixed_t bestheight, maxheight; - INT32 count, i, mapnum; + INT32 count, i; sector_t *sec; #ifdef ESLOPE pslope_t *bestslope = NULL; @@ -1276,7 +1264,7 @@ void R_Prep3DFloors(sector_t *sector) #endif sector->lightlist[0].lightlevel = §or->lightlevel; sector->lightlist[0].caster = NULL; - sector->lightlist[0].extra_colormap = sector->extra_colormap; + sector->lightlist[0].extra_colormap = §or->extra_colormap; sector->lightlist[0].flags = 0; maxheight = INT32_MAX; @@ -1342,11 +1330,6 @@ void R_Prep3DFloors(sector_t *sector) sector->lightlist[i].slope = bestslope; #endif sec = §ors[best->secnum]; - mapnum = sec->midmap; - if (mapnum >= 0 && (size_t)mapnum < num_extra_colormaps) - sec->extra_colormap = &extra_colormaps[mapnum]; - else - sec->extra_colormap = NULL; if (best->flags & FF_NOSHADE) { @@ -1356,12 +1339,12 @@ void R_Prep3DFloors(sector_t *sector) else if (best->flags & FF_COLORMAPONLY) { sector->lightlist[i].lightlevel = sector->lightlist[i-1].lightlevel; - sector->lightlist[i].extra_colormap = sec->extra_colormap; + sector->lightlist[i].extra_colormap = &sec->extra_colormap; } else { sector->lightlist[i].lightlevel = best->toplightlevel; - sector->lightlist[i].extra_colormap = sec->extra_colormap; + sector->lightlist[i].extra_colormap = &sec->extra_colormap; } if (best->flags & FF_DOUBLESHADOW) diff --git a/src/r_data.c b/src/r_data.c index 6aede0396..08e3d91b6 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1144,6 +1144,10 @@ void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex) Z_Free((void *)texturesText); } +#ifdef EXTRACOLORMAPLUMPS +static lumplist_t *colormaplumps = NULL; ///\todo free leak +static size_t numcolormaplumps = 0; + static inline lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t *list, size_t listsize) { size_t i; @@ -1160,9 +1164,6 @@ static inline lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t *list return LUMPERROR; } -static lumplist_t *colormaplumps = NULL; ///\todo free leak -static size_t numcolormaplumps = 0; - static void R_InitExtraColormaps(void) { lumpnum_t startnum, endnum; @@ -1195,6 +1196,7 @@ static void R_InitExtraColormaps(void) } CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps)); } +#endif // Search for flat name through all lumpnum_t R_GetFlatNumForName(const char *name) @@ -1291,7 +1293,9 @@ static void R_InitColormaps(void) // Init Boom colormaps. R_ClearColormaps(); +#ifdef EXTRACOLORMAPLUMPS R_InitExtraColormaps(); +#endif } void R_ReInitColormaps(UINT16 num) @@ -1311,11 +1315,6 @@ void R_ReInitColormaps(UINT16 num) R_ClearColormaps(); } -static lumpnum_t foundcolormaps[MAXCOLORMAPS]; - -static char colormapFixingArray[MAXCOLORMAPS][3][9]; -static size_t carrayindex; - // // R_ClearColormaps // @@ -1323,51 +1322,264 @@ static size_t carrayindex; // void R_ClearColormaps(void) { - size_t i; - - num_extra_colormaps = 0; - - carrayindex = 0; - - for (i = 0; i < MAXCOLORMAPS; i++) - foundcolormaps[i] = LUMPERROR; - - memset(extra_colormaps, 0, sizeof (extra_colormaps)); + // Purged by PU_LEVEL, just overwrite the pointer + extra_colormaps = R_CreateDefaultColormap(true); } -INT32 R_ColormapNumForName(char *name) +// +// R_CreateDefaultColormap() +// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself! +// +extracolormap_t *R_CreateDefaultColormap(boolean lighttable) { - lumpnum_t lump, i; + extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL); + exc->fadestart = 0; + exc->fadeend = 31; + exc->fog = 0; + exc->rgba = 0; + exc->fadergba = 0x19000000; + exc->colormap = lighttable ? R_CreateLightTable(exc) : NULL; +#ifdef EXTRACOLORMAPLUMPS + exc->lump = LUMPERROR; + exc->lumpname[0] = 0; +#endif + exc->next = exc->prev = NULL; + return exc; +} - if (num_extra_colormaps == MAXCOLORMAPS) - I_Error("R_ColormapNumForName: Too many colormaps! the limit is %d\n", MAXCOLORMAPS); +// +// R_GetDefaultColormap() +// +extracolormap_t *R_GetDefaultColormap(void) +{ +#ifdef COLORMAPREVERSELIST + extracolormap_t *exc; +#endif + + if (!extra_colormaps) + return (extra_colormaps = R_CreateDefaultColormap(true)); + +#ifdef COLORMAPREVERSELIST + for (exc = extra_colormaps; exc->next; exc = exc->next); + return exc; +#else + return extra_colormaps; +#endif +} + +// +// R_CopyColormap() +// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself! +// +extracolormap_t *R_CopyColormap(extracolormap_t *extra_colormap, boolean lighttable) +{ + extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL); + + if (!extra_colormap) + extra_colormap = R_GetDefaultColormap(); + + *exc = *extra_colormap; + exc->next = exc->prev = NULL; + +#ifdef EXTRACOLORMAPLUMPS + strncpy(exc->lumpname, extra_colormap->lumpname, 9); + + if (exc->lump != LUMPERROR && lighttable) + { + // aligned on 8 bit for asm code + exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16); + W_ReadLump(lump, exc->colormap); + } + else +#endif + if (lighttable) + exc->colormap = R_CreateLightTable(exc); + else + exc->colormap = NULL; + + return exc; +} + +// +// R_AddColormapToList +// +// Sets prev/next chain for extra_colormaps var +// Copypasta from P_AddFFloorToList +// +void R_AddColormapToList(extracolormap_t *extra_colormap) +{ +#ifndef COLORMAPREVERSELIST + extracolormap_t *exc; +#endif + + if (!extra_colormaps) + { + extra_colormaps = extra_colormap; + extra_colormap->next = 0; + extra_colormap->prev = 0; + return; + } + +#ifdef COLORMAPREVERSELIST + extra_colormaps->prev = extra_colormap; + extra_colormap->next = extra_colormaps; + extra_colormaps = extra_colormap; + extra_colormap->prev = 0; +#else + for (exc = extra_colormaps; exc->next; exc = exc->next); + + exc->next = extra_colormap; + extra_colormap->prev = exc; + extra_colormap->next = 0; +#endif +} + +// +// R_CheckDefaultColormapByValues() +// +#ifdef EXTRACOLORMAPLUMPS +boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams, + INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog, lumpnum_t lump) +#else +boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams, + INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog) +#endif +{ + return ( + (!checkparams ? true : + (fadestart == 0 + && fadeend == 31 + && !fog) + ) + && (!checkrgba ? true : rgba == 0) + && (!checkfadergba ? true : fadergba == 0x19000000) +#ifdef EXTRACOLORMAPLUMPS + && lump == LUMPERROR + && extra_colormap->lumpname[0] == 0 +#endif + ); +} + +boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams) +{ + if (!extra_colormap) + return true; + +#ifdef EXTRACOLORMAPLUMPS + return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog, extra_colormap->lump); +#else + return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog); +#endif +} + +boolean R_CheckEqualColormaps(extracolormap_t *exc_a, extracolormap_t *exc_b, boolean checkrgba, boolean checkfadergba, boolean checkparams) +{ + // Treat NULL as default colormap + // We need this because what if one exc is a default colormap, and the other is NULL? They're really both equal. + if (!exc_a) + exc_a = R_GetDefaultColormap(); + if (!exc_b) + exc_b = R_GetDefaultColormap(); + + if (exc_a == exc_b) + return true; + + return ( + (!checkparams ? true : + (exc_a->fadestart == exc_b->fadestart + && exc_a->fadeend == exc_b->fadeend + && exc_a->fog == exc_b->fog) + ) + && (!checkrgba ? true : exc_a->rgba == exc_b->rgba) + && (!checkfadergba ? true : exc_a->fadergba == exc_b->fadergba) +#ifdef EXTRACOLORMAPLUMPS + && exc_a->lump == exc_b->lump + && !strncmp(exc_a->lumpname, exc_b->lumpname, 9) +#endif + ); +} + +// +// R_GetColormapFromListByValues() +// NOTE: Returns NULL if no match is found +// +#ifdef EXTRACOLORMAPLUMPS +extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog, lumpnum_t lump) +#else +extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog) +#endif +{ + extracolormap_t *exc; + UINT32 dbg_i = 0; + + for (exc = extra_colormaps; exc; exc = exc->next) + { + if (rgba == exc->rgba + && fadergba == exc->fadergba + && fadestart == exc->fadestart + && fadeend == exc->fadeend + && fog == exc->fog +#ifdef EXTRACOLORMAPLUMPS + && (lump != LUMPERROR && lump == exc->lump) +#endif + ) + { + CONS_Debug(DBG_RENDER, "Found Colormap %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n", + dbg_i, R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba), + R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba)); + return exc; + } + dbg_i++; + } + return NULL; +} + +extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap) +{ +#ifdef EXTRACOLORMAPLUMPS + return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog, extra_colormap->lump); +#else + return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog); +#endif +} + +#ifdef EXTRACOLORMAPLUMPS +extracolormap_t *R_ColormapForName(char *name) +{ + lumpnum_t lump; + extracolormap_t *exc; lump = R_CheckNumForNameList(name, colormaplumps, numcolormaplumps); if (lump == LUMPERROR) - I_Error("R_ColormapNumForName: Cannot find colormap lump %.8s\n", name); + I_Error("R_ColormapForName: Cannot find colormap lump %.8s\n", name); - for (i = 0; i < num_extra_colormaps; i++) - if (lump == foundcolormaps[i]) - return i; + exc = R_GetColormapFromListByValues(0, 0x19000000, 0, 31, 0, lump); + if (exc) + return exc; - foundcolormaps[num_extra_colormaps] = lump; + exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL); + + exc->lump = lump; + strncpy(exc->lumpname, name, 9); + exc->lumpname[8] = 0; // aligned on 8 bit for asm code - extra_colormaps[num_extra_colormaps].colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16); - W_ReadLump(lump, extra_colormaps[num_extra_colormaps].colormap); + exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16); + W_ReadLump(lump, exc->colormap); // We set all params of the colormap to normal because there // is no real way to tell how GL should handle a colormap lump anyway.. - extra_colormaps[num_extra_colormaps].maskcolor = 0xffff; - extra_colormaps[num_extra_colormaps].fadecolor = 0x0; - extra_colormaps[num_extra_colormaps].maskamt = 0x0; - extra_colormaps[num_extra_colormaps].fadestart = 0; - extra_colormaps[num_extra_colormaps].fadeend = 31; - extra_colormaps[num_extra_colormaps].fog = 0; + exc->fadestart = 0; + exc->fadeend = 31; + exc->fog = 0; + exc->rgba = 0; + exc->fadergba = 0x19000000; - num_extra_colormaps++; - return (INT32)num_extra_colormaps - 1; + R_AddColormapToList(exc); + + return exc; } +#endif // // R_CreateColormap @@ -1382,244 +1594,71 @@ static double deltas[256][3], map[256][3]; static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); static int RoundUp(double number); -INT32 R_CreateColormap(char *p1, char *p2, char *p3) +lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap) { double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb; - double r, g, b, cbrightness, maskamt = 0, othermask = 0; - int mask, fog = 0; - size_t mapnum = num_extra_colormaps; - size_t i; - UINT32 cr, cg, cb, maskcolor, fadecolor; - UINT32 fadestart = 0, fadeend = 31, fadedist = 31; - -#define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) - if (p1[0] == '#') - { - cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2])); - cmaskr = cr; - cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); - cmaskg = cg; - cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); - cmaskb = cb; - // Create a rough approximation of the color (a 16 bit color) - maskcolor = ((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11); - if (p1[7] >= 'a' && p1[7] <= 'z') - mask = (p1[7] - 'a'); - else if (p1[7] >= 'A' && p1[7] <= 'Z') - mask = (p1[7] - 'A'); - else - mask = 24; - - maskamt = (double)(mask/24.0l); - - othermask = 1 - maskamt; - maskamt /= 0xff; - cmaskr *= maskamt; - cmaskg *= maskamt; - cmaskb *= maskamt; - } - else - { - cmaskr = cmaskg = cmaskb = 0xff; - maskamt = 0; - maskcolor = ((0xff) >> 3) + (((0xff) >> 2) << 5) + (((0xff) >> 3) << 11); - } - -#define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0) - if (p2[0] == '#') - { - // Get parameters like fadestart, fadeend, and the fogflag - fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10); - fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10); - if (fadestart > 30) - fadestart = 0; - if (fadeend > 31 || fadeend < 1) - fadeend = 31; - fadedist = fadeend - fadestart; - fog = NUMFROMCHAR(p2[1]); - } -#undef getnum - - if (p3[0] == '#') - { - cdestr = cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); - cdestg = cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); - cdestb = cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); - fadecolor = (((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11)); - } - else - cdestr = cdestg = cdestb = fadecolor = 0; -#undef HEX2INT - - for (i = 0; i < num_extra_colormaps; i++) - { - if (foundcolormaps[i] != LUMPERROR) - continue; - if (maskcolor == extra_colormaps[i].maskcolor - && fadecolor == extra_colormaps[i].fadecolor - && (float)maskamt == (float)extra_colormaps[i].maskamt - && fadestart == extra_colormaps[i].fadestart - && fadeend == extra_colormaps[i].fadeend - && fog == extra_colormaps[i].fog) - { - return (INT32)i; - } - } - - if (num_extra_colormaps == MAXCOLORMAPS) - I_Error("R_CreateColormap: Too many colormaps! the limit is %d\n", MAXCOLORMAPS); - - strncpy(colormapFixingArray[num_extra_colormaps][0], p1, 8); - strncpy(colormapFixingArray[num_extra_colormaps][1], p2, 8); - strncpy(colormapFixingArray[num_extra_colormaps][2], p3, 8); - - num_extra_colormaps++; - - if (rendermode == render_soft) - { - for (i = 0; i < 256; i++) - { - r = pMasterPalette[i].s.red; - g = pMasterPalette[i].s.green; - b = pMasterPalette[i].s.blue; - cbrightness = sqrt((r*r) + (g*g) + (b*b)); - - map[i][0] = (cbrightness * cmaskr) + (r * othermask); - if (map[i][0] > 255.0l) - map[i][0] = 255.0l; - deltas[i][0] = (map[i][0] - cdestr) / (double)fadedist; - - map[i][1] = (cbrightness * cmaskg) + (g * othermask); - if (map[i][1] > 255.0l) - map[i][1] = 255.0l; - deltas[i][1] = (map[i][1] - cdestg) / (double)fadedist; - - map[i][2] = (cbrightness * cmaskb) + (b * othermask); - if (map[i][2] > 255.0l) - map[i][2] = 255.0l; - deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist; - } - } - - foundcolormaps[mapnum] = LUMPERROR; - - // aligned on 8 bit for asm code - extra_colormaps[mapnum].colormap = NULL; - extra_colormaps[mapnum].maskcolor = (UINT16)maskcolor; - extra_colormaps[mapnum].fadecolor = (UINT16)fadecolor; - extra_colormaps[mapnum].maskamt = maskamt; - extra_colormaps[mapnum].fadestart = (UINT16)fadestart; - extra_colormaps[mapnum].fadeend = (UINT16)fadeend; - extra_colormaps[mapnum].fog = fog; - - return (INT32)mapnum; -} - -void R_MakeColormaps(void) -{ - size_t i; - - carrayindex = num_extra_colormaps; - num_extra_colormaps = 0; - - for (i = 0; i < carrayindex; i++) - R_CreateColormap2(colormapFixingArray[i][0], colormapFixingArray[i][1], - colormapFixingArray[i][2]); -} - -void R_CreateColormap2(char *p1, char *p2, char *p3) -{ - double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb; - double r, g, b, cbrightness; double maskamt = 0, othermask = 0; - int mask, p, fog = 0; - size_t mapnum = num_extra_colormaps; + + UINT8 cr = R_GetRgbaR(extra_colormap->rgba), + cg = R_GetRgbaG(extra_colormap->rgba), + cb = R_GetRgbaB(extra_colormap->rgba), + ca = R_GetRgbaA(extra_colormap->rgba), + cfr = R_GetRgbaR(extra_colormap->fadergba), + cfg = R_GetRgbaG(extra_colormap->fadergba), + cfb = R_GetRgbaB(extra_colormap->fadergba); +// cfa = R_GetRgbaA(extra_colormap->fadergba); // unused in software + + UINT8 fadestart = extra_colormap->fadestart, + fadedist = extra_colormap->fadeend - extra_colormap->fadestart; + + lighttable_t *lighttable = NULL; size_t i; - char *colormap_p; - UINT32 cr, cg, cb, maskcolor, fadecolor; - UINT32 fadestart = 0, fadeend = 31, fadedist = 31; -#define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) - if (p1[0] == '#') - { - cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2])); - cmaskr = cr; - cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); - cmaskg = cg; - cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); - cmaskb = cb; - // Create a rough approximation of the color (a 16 bit color) - maskcolor = ((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11); - if (p1[7] >= 'a' && p1[7] <= 'z') - mask = (p1[7] - 'a'); - else if (p1[7] >= 'A' && p1[7] <= 'Z') - mask = (p1[7] - 'A'); - else - mask = 24; + ///////////////////// + // Calc the RGBA mask + ///////////////////// + cmaskr = cr; + cmaskg = cg; + cmaskb = cb; - maskamt = (double)(mask/24.0l); + maskamt = (double)(ca/24.0l); + othermask = 1 - maskamt; + maskamt /= 0xff; - othermask = 1 - maskamt; - maskamt /= 0xff; - cmaskr *= maskamt; - cmaskg *= maskamt; - cmaskb *= maskamt; - } - else - { - cmaskr = cmaskg = cmaskb = 0xff; - maskamt = 0; - maskcolor = ((0xff) >> 3) + (((0xff) >> 2) << 5) + (((0xff) >> 3) << 11); - } + cmaskr *= maskamt; + cmaskg *= maskamt; + cmaskb *= maskamt; -#define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0) - if (p2[0] == '#') - { - // Get parameters like fadestart, fadeend, and the fogflag - fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10); - fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10); - if (fadestart > 30) - fadestart = 0; - if (fadeend > 31 || fadeend < 1) - fadeend = 31; - fadedist = fadeend - fadestart; - fog = NUMFROMCHAR(p2[1]); - } -#undef getnum + ///////////////////// + // Calc the RGBA fade mask + ///////////////////// + cdestr = cfr; + cdestg = cfg; + cdestb = cfb; - if (p3[0] == '#') - { - cdestr = cr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); - cdestg = cg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); - cdestb = cb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); - fadecolor = (((cb) >> 3) + (((cg) >> 2) << 5) + (((cr) >> 3) << 11)); - } - else - cdestr = cdestg = cdestb = fadecolor = 0; -#undef HEX2INT + // fade alpha unused in software + // maskamt = (double)(cfa/24.0l); + // othermask = 1 - maskamt; + // maskamt /= 0xff; - for (i = 0; i < num_extra_colormaps; i++) - { - if (foundcolormaps[i] != LUMPERROR) - continue; - if (maskcolor == extra_colormaps[i].maskcolor - && fadecolor == extra_colormaps[i].fadecolor - && (float)maskamt == (float)extra_colormaps[i].maskamt - && fadestart == extra_colormaps[i].fadestart - && fadeend == extra_colormaps[i].fadeend - && fog == extra_colormaps[i].fog) - { - return; - } - } - - if (num_extra_colormaps == MAXCOLORMAPS) - I_Error("R_CreateColormap: Too many colormaps! the limit is %d\n", MAXCOLORMAPS); - - num_extra_colormaps++; + // cdestr *= maskamt; + // cdestg *= maskamt; + // cdestb *= maskamt; + ///////////////////// + // This code creates the colormap array used by software renderer + ///////////////////// if (rendermode == render_soft) { + double r, g, b, cbrightness; + int p; + char *colormap_p; + + // Initialise the map and delta arrays + // map[i] stores an RGB color (as double) for index i, + // which is then converted to SRB2's palette later + // deltas[i] stores a corresponding fade delta between the RGB color and the final fade color; + // map[i]'s values are decremented by after each use for (i = 0; i < 256; i++) { r = pMasterPalette[i].s.red; @@ -1642,25 +1681,14 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) map[i][2] = 255.0l; deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist; } - } - foundcolormaps[mapnum] = LUMPERROR; - - // aligned on 8 bit for asm code - extra_colormaps[mapnum].colormap = NULL; - extra_colormaps[mapnum].maskcolor = (UINT16)maskcolor; - extra_colormaps[mapnum].fadecolor = (UINT16)fadecolor; - extra_colormaps[mapnum].maskamt = maskamt; - extra_colormaps[mapnum].fadestart = (UINT16)fadestart; - extra_colormaps[mapnum].fadeend = (UINT16)fadeend; - extra_colormaps[mapnum].fog = fog; - -#define ABS2(x) ((x) < 0 ? -(x) : (x)) - if (rendermode == render_soft) - { + // Now allocate memory for the actual colormap array itself! + // aligned on 8 bit for asm code colormap_p = Z_MallocAlign((256 * 34) + 10, PU_LEVEL, NULL, 8); - extra_colormaps[mapnum].colormap = (UINT8 *)colormap_p; + lighttable = (UINT8 *)colormap_p; + // Calculate the palette index for each palette index, for each light level + // (as well as the two unused colormap lines we inherited from Doom) for (p = 0; p < 34; p++) { for (i = 0; i < 256; i++) @@ -1672,7 +1700,7 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) if ((UINT32)p < fadestart) continue; - +#define ABS2(x) ((x) < 0 ? -(x) : (x)) if (ABS2(map[i][0] - cdestr) > ABS2(deltas[i][0])) map[i][0] -= deltas[i][0]; else @@ -1687,12 +1715,290 @@ void R_CreateColormap2(char *p1, char *p2, char *p3) map[i][2] -= deltas[i][2]; else map[i][2] = cdestb; +#undef ABS2 } } } -#undef ABS2 - return; + return lighttable; +} + +extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3) +{ + extracolormap_t *extra_colormap, *exc; + + // default values + UINT8 cr = 0, cg = 0, cb = 0, ca = 0, cfr = 0, cfg = 0, cfb = 0, cfa = 25; + UINT32 fadestart = 0, fadeend = 31; + UINT8 fog = 0; + INT32 rgba = 0, fadergba = 0x19000000; + +#define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0) +#define ALPHA2INT(x) (x >= 'a' && x <= 'z' ? x - 'a' : x >= 'A' && x <= 'Z' ? x - 'A' : x >= '0' && x <= '9' ? 25 : 0) + + // Get base colormap value + // First alpha-only, then full value + if (p1[0] >= 'a' && p1[0] <= 'z' && !p1[1]) + ca = (p1[0] - 'a'); + else if (p1[0] == '#' && p1[1] >= 'a' && p1[1] <= 'z' && !p1[2]) + ca = (p1[1] - 'a'); + else if (p1[0] >= 'A' && p1[0] <= 'Z' && !p1[1]) + ca = (p1[0] - 'A'); + else if (p1[0] == '#' && p1[1] >= 'A' && p1[1] <= 'Z' && !p1[2]) + ca = (p1[1] - 'A'); + else if (p1[0] == '#') + { + // For each subsequent value, the value before it must exist + // If we don't get every value, then set alpha to max + if (p1[1] && p1[2]) + { + cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2])); + if (p1[3] && p1[4]) + { + cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4])); + if (p1[5] && p1[6]) + { + cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6])); + + if (p1[7] >= 'a' && p1[7] <= 'z') + ca = (p1[7] - 'a'); + else if (p1[7] >= 'A' && p1[7] <= 'Z') + ca = (p1[7] - 'A'); + else + ca = 25; + } + else + ca = 25; + } + else + ca = 25; + } + else + ca = 25; + } + +#define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0) + + // Get parameters like fadestart, fadeend, and the fogflag + if (p2[0] == '#') + { + if (p2[1]) + { + fog = NUMFROMCHAR(p2[1]); + if (p2[2] && p2[3]) + { + fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10); + if (p2[4] && p2[5]) + fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10); + } + } + + if (fadestart > 30) + fadestart = 0; + if (fadeend > 31 || fadeend < 1) + fadeend = 31; + } + +#undef NUMFROMCHAR + + // Get fade (dark) colormap value + // First alpha-only, then full value + if (p3[0] >= 'a' && p3[0] <= 'z' && !p3[1]) + cfa = (p3[0] - 'a'); + else if (p3[0] == '#' && p3[1] >= 'a' && p3[1] <= 'z' && !p3[2]) + cfa = (p3[1] - 'a'); + else if (p3[0] >= 'A' && p3[0] <= 'Z' && !p3[1]) + cfa = (p3[0] - 'A'); + else if (p3[0] == '#' && p3[1] >= 'A' && p3[1] <= 'Z' && !p3[2]) + cfa = (p3[1] - 'A'); + else if (p3[0] == '#') + { + // For each subsequent value, the value before it must exist + // If we don't get every value, then set alpha to max + if (p3[1] && p3[2]) + { + cfr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2])); + if (p3[3] && p3[4]) + { + cfg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4])); + if (p3[5] && p3[6]) + { + cfb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6])); + + if (p3[7] >= 'a' && p3[7] <= 'z') + cfa = (p3[7] - 'a'); + else if (p3[7] >= 'A' && p3[7] <= 'Z') + cfa = (p3[7] - 'A'); + else + cfa = 25; + } + else + cfa = 25; + } + else + cfa = 25; + } + else + cfa = 25; + } +#undef ALPHA2INT +#undef HEX2INT + + // Pack rgba values into combined var + // OpenGL also uses this instead of lighttables for rendering + rgba = R_PutRgbaRGBA(cr, cg, cb, ca); + fadergba = R_PutRgbaRGBA(cfr, cfg, cfb, cfa); + + // Did we just make a default colormap? +#ifdef EXTRACOLORMAPLUMPS + if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog, LUMPERROR)) + return NULL; +#else + if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog)) + return NULL; +#endif + + // Look for existing colormaps +#ifdef EXTRACOLORMAPLUMPS + exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, fog, LUMPERROR); +#else + exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, fog); +#endif + if (exc) + return exc; + + CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n", + cr, cg, cb, ca, cfr, cfg, cfb, cfa); + + extra_colormap = Z_Calloc(sizeof (*extra_colormap), PU_LEVEL, NULL); + + extra_colormap->fadestart = (UINT16)fadestart; + extra_colormap->fadeend = (UINT16)fadeend; + extra_colormap->fog = fog; + + extra_colormap->rgba = rgba; + extra_colormap->fadergba = fadergba; + +#ifdef EXTRACOLORMAPLUMPS + extra_colormap->lump = LUMPERROR; + extra_colormap->lumpname[0] = 0; +#endif + + // Having lighttables for alpha-only entries is kind of pointless, + // but if there happens to be a matching rgba entry that is NOT alpha-only (but has same rgb values), + // then it needs this lighttable because we share matching entries. + extra_colormap->colormap = R_CreateLightTable(extra_colormap); + + R_AddColormapToList(extra_colormap); + + return extra_colormap; +} + +// +// R_AddColormaps() +// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself! +// +extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend, + boolean subR, boolean subG, boolean subB, boolean subA, + boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA, + boolean subFadeStart, boolean subFadeEnd, boolean ignoreFog, + boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha, + boolean lighttable) +{ + INT16 red, green, blue, alpha; + + // exc_augend is added (or subtracted) onto by exc_addend + // In Rennaisance times, the first number was considered the augend, the second number the addend + // But since the commutative property was discovered, today they're both called addends! + // So let's be Olde English for a hot second. + + exc_augend = R_CopyColormap(exc_augend, false); + if(!exc_addend) + exc_addend = R_GetDefaultColormap(); + + /////////////////// + // base rgba + /////////////////// + + red = max(min( + R_GetRgbaR(exc_augend->rgba) + + (subR ? -1 : 1) // subtract R + * R_GetRgbaR(exc_addend->rgba) + , 255), 0); + + green = max(min( + R_GetRgbaG(exc_augend->rgba) + + (subG ? -1 : 1) // subtract G + * R_GetRgbaG(exc_addend->rgba) + , 255), 0); + + blue = max(min( + R_GetRgbaB(exc_augend->rgba) + + (subB ? -1 : 1) // subtract B + * R_GetRgbaB(exc_addend->rgba) + , 255), 0); + + alpha = useAltAlpha ? altAlpha : R_GetRgbaA(exc_addend->rgba); + alpha = max(min(R_GetRgbaA(exc_augend->rgba) + (subA ? -1 : 1) * alpha, 25), 0); + + exc_augend->rgba = R_PutRgbaRGBA(red, green, blue, alpha); + + /////////////////// + // fade/dark rgba + /////////////////// + + red = max(min( + R_GetRgbaR(exc_augend->fadergba) + + (subFadeR ? -1 : 1) // subtract R + * R_GetRgbaR(exc_addend->fadergba) + , 255), 0); + + green = max(min( + R_GetRgbaG(exc_augend->fadergba) + + (subFadeG ? -1 : 1) // subtract G + * R_GetRgbaG(exc_addend->fadergba) + , 255), 0); + + blue = max(min( + R_GetRgbaB(exc_augend->fadergba) + + (subFadeB ? -1 : 1) // subtract B + * R_GetRgbaB(exc_addend->fadergba) + , 255), 0); + + alpha = useAltAlpha ? altFadeAlpha : R_GetRgbaA(exc_addend->fadergba); + if (alpha == 25 && !useAltAlpha && !R_GetRgbaRGB(exc_addend->fadergba)) + alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case + alpha = max(min(R_GetRgbaA(exc_augend->fadergba) + (subFadeA ? -1 : 1) * alpha, 25), 0); + + exc_augend->fadergba = R_PutRgbaRGBA(red, green, blue, alpha); + + /////////////////// + // parameters + /////////////////// + + exc_augend->fadestart = max(min( + exc_augend->fadestart + + (subFadeStart ? -1 : 1) // subtract fadestart + * exc_addend->fadestart + , 31), 0); + + exc_augend->fadeend = max(min( + exc_augend->fadeend + + (subFadeEnd ? -1 : 1) // subtract fadeend + * (exc_addend->fadeend == 31 && !exc_addend->fadestart ? 0 : exc_addend->fadeend) + // HACK: fadeend defaults to 31, so don't add anything in this case + , 31), 0); + + if (!ignoreFog) // overwrite fog with new value + exc_augend->fog = exc_addend->fog; + + /////////////////// + // put it together + /////////////////// + + exc_augend->colormap = lighttable ? R_CreateLightTable(exc_augend) : NULL; + exc_augend->next = exc_augend->prev = NULL; + return exc_augend; } // Thanks to quake2 source! @@ -1735,20 +2041,18 @@ static int RoundUp(double number) return (int)number; } -const char *R_ColormapNameForNum(INT32 num) +#ifdef EXTRACOLORMAPLUMPS +const char *R_NameForColormap(extracolormap_t *extra_colormap) { - if (num == -1) + if (!extra_colormap) return "NONE"; - if (num < 0 || num > MAXCOLORMAPS) - I_Error("R_ColormapNameForNum: num %d is invalid!\n", num); - - if (foundcolormaps[num] == LUMPERROR) + if (extra_colormap->lump == LUMPERROR) return "INLEVEL"; - return W_CheckNameForNum(foundcolormaps[num]); + return extra_colormap->lumpname; } - +#endif // // build a table for quick conversion from 8bpp to 15bpp diff --git a/src/r_data.h b/src/r_data.h index 53bf27835..54857661a 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -96,13 +96,57 @@ void R_ClearTextureNumCache(boolean btell); INT32 R_TextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name); +// Extra Colormap lumps (C_START/C_END) are not used anywhere +// Uncomment to enable +//#define EXTRACOLORMAPLUMPS + +// Uncomment to make extra_colormaps order Newest -> Oldest +//#define COLORMAPREVERSELIST + void R_ReInitColormaps(UINT16 num); void R_ClearColormaps(void); -INT32 R_ColormapNumForName(char *name); -INT32 R_CreateColormap(char *p1, char *p2, char *p3); -void R_CreateColormap2(char *p1, char *p2, char *p3); -void R_MakeColormaps(void); -const char *R_ColormapNameForNum(INT32 num); +extracolormap_t *R_CreateDefaultColormap(boolean lighttable); +extracolormap_t *R_GetDefaultColormap(void); +extracolormap_t *R_CopyColormap(extracolormap_t *extra_colormap, boolean lighttable); +void R_AddColormapToList(extracolormap_t *extra_colormap); + +#ifdef EXTRACOLORMAPLUMPS +boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams, + INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog, lumpnum_t lump); +extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog, lumpnum_t lump); +#else +boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams, + INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog); +extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 fog); +#endif +boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams); +boolean R_CheckEqualColormaps(extracolormap_t *exc_a, extracolormap_t *exc_b, boolean checkrgba, boolean checkfadergba, boolean checkparams); +extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap); + +lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap); +extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3); +extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend, + boolean subR, boolean subG, boolean subB, boolean subA, + boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA, + boolean subFadeStart, boolean subFadeEnd, boolean ignoreFog, + boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha, + boolean lighttable); +#ifdef EXTRACOLORMAPLUMPS +extracolormap_t *R_ColormapForName(char *name); +const char *R_NameForColormap(extracolormap_t *extra_colormap); +#endif + +#define R_GetRgbaR(rgba) (rgba & 0xFF) +#define R_GetRgbaG(rgba) ((rgba >> 8) & 0xFF) +#define R_GetRgbaB(rgba) ((rgba >> 16) & 0xFF) +#define R_GetRgbaA(rgba) ((rgba >> 24) & 0xFF) +#define R_GetRgbaRGB(rgba) (rgba & 0xFFFFFF) +#define R_PutRgbaR(r) (r) +#define R_PutRgbaG(g) (g << 8) +#define R_PutRgbaB(b) (b << 16) +#define R_PutRgbaA(a) (a << 24) +#define R_PutRgbaRGB(r, g, b) (R_PutRgbaR(r) + R_PutRgbaG(g) + R_PutRgbaB(b)) +#define R_PutRgbaRGBA(r, g, b, a) (R_PutRgbaRGB(r, g, b) + R_PutRgbaA(a)) extern INT32 numtextures; diff --git a/src/r_defs.h b/src/r_defs.h index 7c8f2a73f..0e63eec64 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -50,18 +50,25 @@ typedef struct typedef UINT8 lighttable_t; // ExtraColormap type. Use for extra_colormaps from now on. -typedef struct +typedef struct extracolormap_s { - UINT16 maskcolor, fadecolor; - double maskamt; - UINT16 fadestart, fadeend; - INT32 fog; + UINT8 fadestart, fadeend; + UINT8 fog; // categorical value, not boolean - // rgba is used in hw mode for colored sector lighting + // store rgba values in combined bitwise + // also used in OpenGL instead lighttables INT32 rgba; // similar to maskcolor in sw mode INT32 fadergba; // The colour the colourmaps fade to lighttable_t *colormap; + +#ifdef EXTRACOLORMAPLUMPS + lumpnum_t lump; // for colormap lump matching, init to LUMPERROR + char lumpname[9]; // for netsyncing +#endif + + struct extracolormap_s *next; + struct extracolormap_s *prev; } extracolormap_t; // @@ -177,6 +184,8 @@ typedef struct ffloor_s // these are saved for netgames, so do not let Lua touch these! ffloortype_e spawnflags; // flags the 3D floor spawned with INT32 spawnalpha; // alpha the 3D floor spawned with + + void *fadingdata; // fading FOF thinker } ffloor_t; @@ -187,7 +196,7 @@ typedef struct lightlist_s { fixed_t height; INT16 *lightlevel; - extracolormap_t *extra_colormap; + extracolormap_t **extra_colormap; // pointer-to-a-pointer, so we can react to colormap changes INT32 flags; ffloor_t *caster; #ifdef ESLOPE @@ -308,6 +317,7 @@ typedef struct sector_s void *floordata; // floor move thinker void *ceilingdata; // ceiling move thinker void *lightingdata; // lighting change thinker + void *fadecolormapdata; // fade colormap thinker // floor and ceiling texture offsets fixed_t floor_xoffs, floor_yoffs; @@ -323,8 +333,6 @@ typedef struct sector_s INT32 floorlightsec, ceilinglightsec; INT32 crumblestate; // used for crumbling and bobbing - INT32 bottommap, midmap, topmap; // dynamic colormaps - // list of mobjs that are at least partially in the sector // thinglist is a subset of touching_thinglist struct msecnode_s *touching_thinglist; @@ -383,6 +391,9 @@ typedef struct sector_s boolean hasslope; // The sector, or one of its visible FOFs, contains a slope #endif + // for fade thinker + INT16 spawn_lightlevel; + // these are saved for netgames, so do not let Lua touch these! INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed @@ -393,6 +404,9 @@ typedef struct sector_s // flag angles sector spawned with (via linedef type 7) angle_t spawn_flrpic_angle; angle_t spawn_ceilpic_angle; + + // colormap structure + extracolormap_t *spawn_extra_colormap; } sector_t; // @@ -468,6 +482,8 @@ typedef struct INT16 repeatcnt; // # of times to repeat midtexture char *text; // a concatination of all top, bottom, and mid texture names, for linedef specials that require a string. + + extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors. } side_t; // diff --git a/src/r_draw8.c b/src/r_draw8.c index 76eb58c0d..bda146546 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -261,7 +261,7 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void) val = source[frac>>FRACBITS]; if (val != TRANSPARENTPIXEL) - *dest = colormap[*(transmap + (val<<8) + (*dest))]; + *dest = *(transmap + (colormap[val]<<8) + (*dest)); dest += vid.width; @@ -281,12 +281,12 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void) { val = source[(frac>>FRACBITS) & heightmask]; if (val != TRANSPARENTPIXEL) - *dest = colormap[*(transmap + (val<<8) + (*dest))]; + *dest = *(transmap + (colormap[val]<<8) + (*dest)); dest += vid.width; frac += fracstep; val = source[(frac>>FRACBITS) & heightmask]; if (val != TRANSPARENTPIXEL) - *dest = colormap[*(transmap + (val<<8) + (*dest))]; + *dest = *(transmap + (colormap[val]<<8) + (*dest)); dest += vid.width; frac += fracstep; } @@ -294,7 +294,7 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void) { val = source[(frac>>FRACBITS) & heightmask]; if (val != TRANSPARENTPIXEL) - *dest = colormap[*(transmap + (val<<8) + (*dest))]; + *dest = *(transmap + (colormap[val]<<8) + (*dest)); } } } diff --git a/src/r_main.c b/src/r_main.c index 8e58906d4..bfca180d0 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -118,8 +118,7 @@ lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // Hack to support extra boom colormaps. -size_t num_extra_colormaps; -extracolormap_t extra_colormaps[MAXCOLORMAPS]; +extracolormap_t *extra_colormaps = NULL; static CV_PossibleValue_t drawdist_cons_t[] = { {256, "256"}, {512, "512"}, {768, "768"}, diff --git a/src/r_segs.c b/src/r_segs.c index a52b7cb61..cde019f66 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -413,7 +413,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) #endif rlight->startheight = rlight->height; // keep starting value here to reset for each repeat rlight->lightlevel = *light->lightlevel; - rlight->extra_colormap = light->extra_colormap; + rlight->extra_colormap = *light->extra_colormap; rlight->flags = light->flags; if (rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog)) @@ -944,7 +944,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) } rlight->lightlevel = *light->lightlevel; - rlight->extra_colormap = light->extra_colormap; + rlight->extra_colormap = *light->extra_colormap; // Check if the current light effects the colormap/lightlevel if (pfloor->flags & FF_FOG) @@ -2808,7 +2808,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) } rlight->lightlevel = *light->lightlevel; - rlight->extra_colormap = light->extra_colormap; + rlight->extra_colormap = *light->extra_colormap; p++; } diff --git a/src/r_state.h b/src/r_state.h index ac3e1fa42..91c2092e9 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -40,11 +40,7 @@ extern sprcache_t *spritecachedinfo; extern lighttable_t *colormaps; // Boom colormaps. -// Had to put a limit on colormaps :( -#define MAXCOLORMAPS 60 - -extern size_t num_extra_colormaps; -extern extracolormap_t extra_colormaps[MAXCOLORMAPS]; +extern extracolormap_t *extra_colormaps; // for global animation extern INT32 *texturetranslation; diff --git a/src/r_things.c b/src/r_things.c index fb4664d90..a6a7d9877 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -981,7 +981,7 @@ static void R_SplitSprite(vissprite_t *sprite) else spritelights = scalelight[lightnum]; - newsprite->extra_colormap = sector->lightlist[i].extra_colormap; + newsprite->extra_colormap = *sector->lightlist[i].extra_colormap; if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) @@ -1360,7 +1360,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); vis->cut = cut; if (thing->subsector->sector->numlights) - vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap; + vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; else vis->extra_colormap = thing->subsector->sector->extra_colormap; @@ -1525,6 +1525,17 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } + // okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } + + //SoM: 3/17/2000: Disregard sprites that are out of view.. gzt = thing->z + spritecachedinfo[lump].topoffset; gz = gzt - spritecachedinfo[lump].height; @@ -1642,8 +1653,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - if (approx_dist <= limit_dist) - R_ProjectSprite(thing); + if (approx_dist > limit_dist) + continue; + + R_ProjectSprite(thing); } } else @@ -1664,8 +1677,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); - if (approx_dist <= limit_dist) - R_ProjectPrecipitationSprite(precipthing); + if (approx_dist > limit_dist) + continue; + + R_ProjectPrecipitationSprite(precipthing); } } else diff --git a/src/s_sound.c b/src/s_sound.c index af152db5f..1c7b00e2c 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -230,7 +230,7 @@ void S_RegisterSoundStuff(void) { if (dedicated) { - nosound = true; + sound_disabled = true; return; } @@ -494,7 +494,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) mobj_t *listenmobj = players[displayplayer].mo; mobj_t *listenmobj2 = NULL; - if (sound_disabled || !sound_started || nosound) + if (sound_disabled || !sound_started) return; // Don't want a sound? Okay then... @@ -626,7 +626,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) // Assigns the handle to one of the channels in the // mix/output buffer. - channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); + channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum); } dontplay: @@ -679,7 +679,7 @@ dontplay: // Assigns the handle to one of the channels in the // mix/output buffer. - channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); + channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum); } void S_StartSound(const void *origin, sfxenum_t sfx_id) @@ -824,7 +824,7 @@ void S_UpdateSounds(void) goto notinlevel; } - if (dedicated || nosound) + if (dedicated || sound_disabled) return; if (players[displayplayer].awayviewtics) @@ -1283,6 +1283,43 @@ void S_StartSoundName(void *mo, const char *soundname) S_StartSound(mo, soundnum); } +// +// Initializes sound stuff, including volume +// Sets channels, SFX volume, +// allocates channel buffer, sets S_sfx lookup. +// +void S_InitSfxChannels(INT32 sfxVolume) +{ + INT32 i; + + if (dedicated) + return; + + S_SetSfxVolume(sfxVolume); + + SetChannelsNum(); + + // Note that sounds have not been cached (yet). + for (i = 1; i < NUMSFX; i++) + { + S_sfx[i].usefulness = -1; // for I_GetSfx() + S_sfx[i].lumpnum = LUMPERROR; + } + + // precache sounds if requested by cmdline, or precachesound var true + if (!sound_disabled && (M_CheckParm("-precachesound") || precachesound.value)) + { + // Initialize external data (all sounds) at start, keep static. + CONS_Printf(M_GetText("Loading sounds... ")); + + for (i = 1; i < NUMSFX; i++) + if (S_sfx[i].name) + S_sfx[i].data = I_GetSfx(&S_sfx[i]); + + CONS_Printf(M_GetText(" pre-cached all sound data\n")); + } +} + /// ------------------------ /// Music /// ------------------------ @@ -1309,31 +1346,109 @@ const char *compat_special_music_slots[16] = }; #endif -#define music_playing (music_name[0]) // String is empty if no music is playing - static char music_name[7]; // up to 6-character name -static lumpnum_t music_lumpnum; // lump number of music (used??) -static void *music_data; // music raw data -static INT32 music_handle; // once registered, the handle for the music +static void *music_data; +static UINT16 music_flags; +static boolean music_looping; -static boolean mus_paused = 0; // whether songs are mus_paused +/// ------------------------ +/// Music Status +/// ------------------------ -static boolean S_MIDIMusic(const char *mname, boolean looping) +boolean S_DigMusicDisabled(void) +{ + return digital_disabled; +} + +boolean S_MIDIMusicDisabled(void) +{ + return midi_disabled; +} + +boolean S_MusicDisabled(void) +{ + return (midi_disabled && digital_disabled); +} + +boolean S_MusicPlaying(void) +{ + return I_SongPlaying(); +} + +boolean S_MusicPaused(void) +{ + return I_SongPaused(); +} + +musictype_t S_MusicType(void) +{ + return I_SongType(); +} + +boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping) +{ + if (!I_SongPlaying()) + return false; + + strncpy(mname, music_name, 7); + mname[6] = 0; + *mflags = music_flags; + *looping = music_looping; + + return (boolean)mname[0]; +} + +boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi) +{ + return ( + (checkDigi ? W_CheckNumForName(va("O_%s", mname)) != LUMPERROR : false) + || (checkMIDI ? W_CheckNumForName(va("D_%s", mname)) != LUMPERROR : false) + ); +} + +/// ------------------------ +/// Music Effects +/// ------------------------ + +boolean S_SpeedMusic(float speed) +{ + return I_SetSongSpeed(speed); +} + +/// ------------------------ +/// Music Playback +/// ------------------------ + +static boolean S_LoadMusic(const char *mname) { lumpnum_t mlumpnum; void *mdata; - INT32 mhandle; - if (nomidimusic || music_disabled) - return false; // didn't search. - - if (W_CheckNumForName(va("d_%s", mname)) == LUMPERROR) + if (S_MusicDisabled()) return false; - mlumpnum = W_GetNumForName(va("d_%s", mname)); + + if (!S_DigMusicDisabled() && S_DigExists(mname)) + mlumpnum = W_GetNumForName(va("o_%s", mname)); + else if (!S_MIDIMusicDisabled() && S_MIDIExists(mname)) + mlumpnum = W_GetNumForName(va("d_%s", mname)); + else if (S_DigMusicDisabled() && S_DigExists(mname)) + { + CONS_Alert(CONS_NOTICE, "Digital music is disabled!\n"); + return false; + } + else if (S_MIDIMusicDisabled() && S_MIDIExists(mname)) + { + CONS_Alert(CONS_NOTICE, "MIDI music is disabled!\n"); + return false; + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), mname); + return false; + } // load & register it mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC); - mhandle = I_RegisterSong(mdata, W_LumpLength(mlumpnum)); #ifdef MUSSERV if (msg_id != -1) @@ -1347,37 +1462,49 @@ static boolean S_MIDIMusic(const char *mname, boolean looping) } #endif - // play it - if (!I_PlaySong(mhandle, looping)) + if (I_LoadSong(mdata, W_LumpLength(mlumpnum))) + { + strncpy(music_name, mname, 7); + music_name[6] = 0; + music_data = mdata; + return true; + } + else return false; - - strncpy(music_name, mname, 7); - music_name[6] = 0; - music_lumpnum = mlumpnum; - music_data = mdata; - music_handle = mhandle; - return true; } -static boolean S_DigMusic(const char *mname, boolean looping) +static void S_UnloadMusic(void) { - if (nodigimusic || digital_disabled) - return false; // try midi + I_UnloadSong(); - if (!I_StartDigSong(mname, looping)) +#ifndef HAVE_SDL //SDL uses RWOPS + Z_ChangeTag(music_data, PU_CACHE); +#endif + music_data = NULL; + + music_name[0] = 0; + music_flags = 0; + music_looping = false; +} + +static boolean S_PlayMusic(boolean looping) +{ + if (S_MusicDisabled()) return false; - strncpy(music_name, mname, 7); - music_name[6] = 0; - music_lumpnum = LUMPERROR; - music_data = NULL; - music_handle = 0; + if (!I_PlaySong(looping)) + { + S_UnloadMusic(); + return false; + } + + S_InitMusicVolume(); // switch between digi and sequence volume return true; } void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) { - if ((nomidimusic || music_disabled) && (nodigimusic || digital_disabled)) + if (S_MusicDisabled()) return; // No Music (empty string) @@ -1387,44 +1514,39 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) return; } - if (strncmp(music_name, mmusic, 6)) + if (strnicmp(music_name, mmusic, 6)) { S_StopMusic(); // shutdown old music - if (!S_DigMusic(mmusic, looping) && !S_MIDIMusic(mmusic, looping)) + + if (!S_LoadMusic(mmusic)) { - CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), mmusic); + CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded!\n", mmusic); + return; + } + + music_flags = mflags; + music_looping = looping; + + if (!S_PlayMusic(looping)) + { + CONS_Alert(CONS_ERROR, "Music %.6s could not be played!\n", mmusic); return; } } I_SetSongTrack(mflags & MUSIC_TRACKMASK); } -boolean S_SpeedMusic(float speed) -{ - return I_SetSongSpeed(speed); -} - void S_StopMusic(void) { - if (!music_playing) + if (!I_SongPlaying()) return; - if (mus_paused) - I_ResumeSong(music_handle); - - if (!nodigimusic) - I_StopDigSong(); + if (I_SongPaused()) + I_ResumeSong(); S_SpeedMusic(1.0f); - I_StopSong(music_handle); - I_UnRegisterSong(music_handle); - -#ifndef HAVE_SDL //SDL uses RWOPS - Z_ChangeTag(music_data, PU_CACHE); -#endif - - music_data = NULL; - music_name[0] = 0; + I_StopSong(); + S_UnloadMusic(); // for now, stopping also means you unload the song if (cv_closedcaptioning.value) { @@ -1433,81 +1555,70 @@ void S_StopMusic(void) } } -void S_SetDigMusicVolume(INT32 volume) +// +// Stop and resume music, during game PAUSE. +// +void S_PauseAudio(void) { - if (volume < 0 || volume > 31) - CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n"); + if (I_SongPlaying() && !I_SongPaused()) + I_PauseSong(); - CV_SetValue(&cv_digmusicvolume, volume&31); - actualdigmusicvolume = cv_digmusicvolume.value; //check for change of var - -#ifdef DJGPPDOS - I_SetDigMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this. + // pause cd music +#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) + I_PauseCD(); +#else + I_StopCD(); #endif - I_SetDigMusicVolume(volume&31); } -void S_SetMIDIMusicVolume(INT32 volume) +void S_ResumeAudio(void) { - if (volume < 0 || volume > 31) - CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n"); + if (I_SongPlaying() && I_SongPaused()) + I_ResumeSong(); - CV_SetValue(&cv_midimusicvolume, volume&0x1f); + // resume cd music + I_ResumeCD(); +} + +void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume) +{ + if (digvolume < 0) + digvolume = cv_digmusicvolume.value; + if (seqvolume < 0) + seqvolume = cv_midimusicvolume.value; + + if (digvolume < 0 || digvolume > 31) + CONS_Alert(CONS_WARNING, "digmusicvolume should be between 0-31\n"); + CV_SetValue(&cv_digmusicvolume, digvolume&31); + actualdigmusicvolume = cv_digmusicvolume.value; //check for change of var + + if (seqvolume < 0 || seqvolume > 31) + CONS_Alert(CONS_WARNING, "midimusicvolume should be between 0-31\n"); + CV_SetValue(&cv_midimusicvolume, seqvolume&31); actualmidimusicvolume = cv_midimusicvolume.value; //check for change of var #ifdef DJGPPDOS - I_SetMIDIMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this. + digvolume = seqvolume = 31; #endif - I_SetMIDIMusicVolume(volume&0x1f); + + switch(I_SongType()) + { + case MU_MID: + //case MU_MOD: + //case MU_GME: + I_SetMusicVolume(seqvolume&31); + break; + default: + I_SetMusicVolume(digvolume&31); + break; + } } + /// ------------------------ /// Init & Others /// ------------------------ -// -// Initializes sound stuff, including volume -// Sets channels, SFX and music volume, -// allocates channel buffer, sets S_sfx lookup. -// -void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume) -{ - INT32 i; - - if (dedicated) - return; - - S_SetSfxVolume(sfxVolume); - S_SetDigMusicVolume(digMusicVolume); - S_SetMIDIMusicVolume(midiMusicVolume); - - SetChannelsNum(); - - // no sounds are playing, and they are not mus_paused - mus_paused = 0; - - // Note that sounds have not been cached (yet). - for (i = 1; i < NUMSFX; i++) - { - S_sfx[i].usefulness = -1; // for I_GetSfx() - S_sfx[i].lumpnum = LUMPERROR; - } - - // precache sounds if requested by cmdline, or precachesound var true - if (!nosound && (M_CheckParm("-precachesound") || precachesound.value)) - { - // Initialize external data (all sounds) at start, keep static. - CONS_Printf(M_GetText("Loading sounds... ")); - - for (i = 1; i < NUMSFX; i++) - if (S_sfx[i].name) - S_sfx[i].data = I_GetSfx(&S_sfx[i]); - - CONS_Printf(M_GetText(" pre-cached all sound data\n")); - } -} - - // // Per level startup code. // Kills playing sounds at start of level, @@ -1522,46 +1633,7 @@ void S_Start(void) mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); } - mus_paused = 0; - if (cv_resetmusic.value) S_StopMusic(); S_ChangeMusic(mapmusname, mapmusflags, true); } - -// -// Stop and resume music, during game PAUSE. -// -void S_PauseAudio(void) -{ - if (!nodigimusic) - I_PauseSong(0); - - if (music_playing && !mus_paused) - { - I_PauseSong(music_handle); - mus_paused = true; - } - - // pause cd music -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - I_PauseCD(); -#else - I_StopCD(); -#endif -} - -void S_ResumeAudio(void) -{ - if (!nodigimusic) - I_ResumeSong(0); - else - if (music_playing && mus_paused) - { - I_ResumeSong(music_handle); - mus_paused = false; - } - - // resume cd music - I_ResumeCD(); -} diff --git a/src/s_sound.h b/src/s_sound.h index 4b9735480..c94ae6652 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -14,6 +14,7 @@ #ifndef __S_SOUND__ #define __S_SOUND__ +#include "i_sound.h" // musictype_t #include "sounds.h" #include "m_fixed.h" #include "command.h" @@ -97,9 +98,9 @@ void S_RegisterSoundStuff(void); // // Initializes sound stuff, including volume -// Sets channels, SFX and music volume, allocates channel buffer, sets S_sfx lookup. +// Sets channels, SFX, allocates channel buffer, sets S_sfx lookup. // -void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume); +void S_InitSfxChannels(INT32 sfxVolume); // // Per level startup code. @@ -125,6 +126,33 @@ void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume); // Stop sound for thing at void S_StopSound(void *origin); +// +// Music Status +// + +boolean S_DigMusicDisabled(void); +boolean S_MIDIMusicDisabled(void); +boolean S_MusicDisabled(void); +boolean S_MusicPlaying(void); +boolean S_MusicPaused(void); +musictype_t S_MusicType(void); +boolean S_MusicInfo(char *mname, UINT16 *mflags, boolean *looping); +boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); +#define S_DigExists(a) S_MusicExists(a, false, true) +#define S_MIDIExists(a) S_MusicExists(a, true, false) + + +// +// Music Properties +// + +// Set Speed of Music +boolean S_SpeedMusic(float speed); + +// +// Music Routines +// + // Start music track, arbitrary, given its name, and set whether looping // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet @@ -132,9 +160,6 @@ void S_StopSound(void *origin); #define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b) void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping); -// Set Speed of Music -boolean S_SpeedMusic(float speed); - // Stops the music. void S_StopMusic(void); @@ -149,9 +174,11 @@ void S_UpdateSounds(void); FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2); -void S_SetDigMusicVolume(INT32 volume); -void S_SetMIDIMusicVolume(INT32 volume); void S_SetSfxVolume(INT32 volume); +void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume); +#define S_SetDigMusicVolume(a) S_SetMusicVolume(a,-1) +#define S_SetMIDIMusicVolume(a) S_SetMusicVolume(-1,a) +#define S_InitMusicVolume() S_SetMusicVolume(-1,-1) INT32 S_OriginPlaying(void *origin); INT32 S_IdPlaying(sfxenum_t id); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index c8fcd080e..eb851a619 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -124,6 +124,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include "macosx/mac_resources.h" #endif +#ifndef errno +#include +#endif + // Locations for searching the srb2.pk3 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2" @@ -1149,6 +1153,7 @@ static void I_ShutdownJoystick2(void) D_PostEvent(&event); } + joystick2_started = 0; JoyReset(&JoyInfo2); if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { @@ -1678,7 +1683,7 @@ static void I_ShutdownMouse2(void) EscapeCommFunction(mouse2filehandle, CLRRTS); PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT | - PURGE_TXCLEAR | PURGE_RXCLEAR); + PURGE_TXCLEAR | PURGE_RXCLEAR); CloseHandle(mouse2filehandle); @@ -1871,11 +1876,11 @@ void I_StartupMouse2(void) { // COM file handle mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ | GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); if (mouse2filehandle == INVALID_HANDLE_VALUE) { INT32 e = GetLastError(); @@ -1895,7 +1900,7 @@ void I_StartupMouse2(void) // purge buffers PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT - | PURGE_TXCLEAR | PURGE_RXCLEAR); + | PURGE_TXCLEAR | PURGE_RXCLEAR); // setup port to 1200 7N1 dcb.DCBlength = sizeof (DCB); @@ -2024,7 +2029,7 @@ static void I_ShutdownTimer(void) tic_t I_GetTime (void) { static Uint32 basetime = 0; - Uint32 ticks = SDL_GetTicks(); + Uint32 ticks = SDL_GetTicks(); if (!basetime) basetime = ticks; @@ -2090,7 +2095,6 @@ INT32 I_StartupSystem(void) return 0; } - // // I_Quit // @@ -2369,7 +2373,7 @@ void I_GetDiskFreeSpace(INT64 *freespace) { DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters; GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector, - &NumberOfFreeClusters, &TotalNumberOfClusters); + &NumberOfFreeClusters, &TotalNumberOfClusters); *freespace = BytesPerSector*SectorsPerCluster*NumberOfFreeClusters; } #else // Dummy for platform independent; 1GB should be enough @@ -2576,22 +2580,22 @@ static const char *locateWad(void) #ifdef CMAKECONFIG #ifndef NDEBUG - I_OutputMsg(","CMAKE_ASSETS_DIR); - strcpy(returnWadPath, CMAKE_ASSETS_DIR); - if (isWadPathOk(returnWadPath)) - { - return returnWadPath; - } + I_OutputMsg(","CMAKE_ASSETS_DIR); + strcpy(returnWadPath, CMAKE_ASSETS_DIR); + if (isWadPathOk(returnWadPath)) + { + return returnWadPath; + } #endif #endif #ifdef __APPLE__ - OSX_GetResourcesPath(returnWadPath); - I_OutputMsg(",%s", returnWadPath); - if (isWadPathOk(returnWadPath)) - { - return returnWadPath; - } + OSX_GetResourcesPath(returnWadPath); + I_OutputMsg(",%s", returnWadPath); + if (isWadPathOk(returnWadPath)) + { + return returnWadPath; + } #endif // examine default dirs @@ -2696,7 +2700,30 @@ const char *I_LocateWad(void) #ifdef __linux__ #define MEMINFO_FILE "/proc/meminfo" #define MEMTOTAL "MemTotal:" +#define MEMAVAILABLE "MemAvailable:" #define MEMFREE "MemFree:" +#define CACHED "Cached:" +#define BUFFERS "Buffers:" +#define SHMEM "Shmem:" + +/* Parse the contents of /proc/meminfo (in buf), return value of "name" + * (example: MemTotal) */ +static long get_entry(const char* name, const char* buf) +{ + long val; + char* hit = strstr(buf, name); + if (hit == NULL) { + return -1; + } + + errno = 0; + val = strtol(hit + strlen(name), NULL, 10); + if (errno != 0) { + CONS_Alert(CONS_ERROR, M_GetText("get_entry: strtol() failed: %s\n"), strerror(errno)); + return -1; + } + return val; +} #endif // quick fix for compil @@ -2758,6 +2785,11 @@ UINT32 I_GetFreeMem(UINT32 *total) UINT32 totalKBytes; INT32 n; INT32 meminfo_fd = -1; + long Cached; + long MemFree; + long Buffers; + long Shmem; + long MemAvailable = -1; meminfo_fd = open(MEMINFO_FILE, O_RDONLY); n = read(meminfo_fd, buf, 1023); @@ -2783,16 +2815,28 @@ UINT32 I_GetFreeMem(UINT32 *total) memTag += sizeof (MEMTOTAL); totalKBytes = atoi(memTag); - if ((memTag = strstr(buf, MEMFREE)) == NULL) + if ((memTag = strstr(buf, MEMAVAILABLE)) == NULL) { - // Error - if (total) - *total = 0L; - return 0; - } + Cached = get_entry(CACHED, buf); + MemFree = get_entry(MEMFREE, buf); + Buffers = get_entry(BUFFERS, buf); + Shmem = get_entry(SHMEM, buf); + MemAvailable = Cached + MemFree + Buffers - Shmem; - memTag += sizeof (MEMFREE); - freeKBytes = atoi(memTag); + if (MemAvailable == -1) + { + // Error + if (total) + *total = 0L; + return 0; + } + freeKBytes = MemAvailable; + } + else + { + memTag += sizeof (MEMAVAILABLE); + freeKBytes = atoi(memTag); + } if (total) *total = totalKBytes << 10; diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index bd3f5e60a..48bb61649 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -566,7 +566,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) // Tell game we got focus back, resume music if necessary window_notinfocus = false; if (!paused) - I_ResumeSong(0); //resume it + I_ResumeSong(); //resume it if (!firsttimeonmouse) { @@ -578,7 +578,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) { // Tell game we lost focus, pause music window_notinfocus = true; - I_PauseSong(0); + I_PauseSong(); if (!disable_mouse) { diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 5211efe0a..4d86d7a3c 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -34,14 +34,18 @@ (SDL_MIXER_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z)) #endif +// thanks alam for making the buildbots happy! +#if SDL_MIXER_VERSION_ATLEAST(2,0,2) +#define MUS_MP3_MAD MUS_MP3_MAD_UNUSED +#define MUS_MODPLUG MUS_MODPLUG_UNUSED +#endif + #ifdef HAVE_LIBGME #include "gme/gme.h" #define GME_TREBLE 5.0 #define GME_BASS 1.0 -#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng - -#define HAVE_ZLIB +#ifdef HAVE_ZLIB #ifndef _MSC_VER #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE @@ -57,14 +61,13 @@ #endif #include "zlib.h" -#endif -#endif +#endif // HAVE_ZLIB +#endif // HAVE_LIBGME UINT8 sound_started = false; -static boolean midimode; static Mix_Music *music; -static UINT8 music_volume, midi_volume, sfx_volume; +static UINT8 music_volume, sfx_volume; static float loop_point; static boolean songpaused; @@ -73,13 +76,20 @@ static Music_Emu *gme; static INT32 current_track; #endif +/// ------------------------ +/// Audio System +/// ------------------------ + void I_StartupSound(void) { I_Assert(!sound_started); // EE inits audio first so we're following along. if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO) - CONS_Printf("SDL Audio already started\n"); + { + CONS_Debug(DBG_DETAILED, "SDL Audio already started\n"); + return; + } else if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { CONS_Alert(CONS_ERROR, "Error initializing SDL Audio: %s\n", SDL_GetError()); @@ -87,9 +97,8 @@ void I_StartupSound(void) return; } - midimode = false; music = NULL; - music_volume = midi_volume = sfx_volume = 0; + music_volume = sfx_volume = 0; #if SDL_MIXER_VERSION_ATLEAST(1,2,11) Mix_Init(MIX_INIT_FLAC|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG); @@ -130,6 +139,10 @@ FUNCMATH void I_UpdateSound(void) { } +/// ------------------------ +/// SFX +/// ------------------------ + // this is as fast as I can possibly make it. // sorry. more asm needed. static Mix_Chunk *ds2chunk(void *stream) @@ -178,7 +191,7 @@ static Mix_Chunk *ds2chunk(void *stream) return NULL; // would and/or did wrap, can't store. break; } - sound = malloc(newsamples<<2); // samples * frequency shift * bytes per sample * channels + sound = Z_Malloc(newsamples<<2, PU_SOUND, NULL); // samples * frequency shift * bytes per sample * channels s = (SINT8 *)stream; d = (INT16 *)sound; @@ -246,6 +259,7 @@ void *I_GetSfx(sfxinfo_t *sfx) { void *lump; Mix_Chunk *chunk; + SDL_RWops *rw; #ifdef HAVE_LIBGME Music_Emu *emu; gme_info_t *info; @@ -361,7 +375,7 @@ void *I_GetSfx(sfxinfo_t *sfx) } Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up #else - //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); + return NULL; // No zlib support #endif } // Try to read it as a GME sound @@ -387,21 +401,43 @@ void *I_GetSfx(sfxinfo_t *sfx) #endif // Try to load it as a WAVE or OGG using Mixer. - return Mix_LoadWAV_RW(SDL_RWFromMem(lump, sfx->length), 1); + rw = SDL_RWFromMem(lump, sfx->length); + if (rw != NULL) + { + chunk = Mix_LoadWAV_RW(rw, 1); + return chunk; + } + + return NULL; // haven't been able to get anything } void I_FreeSfx(sfxinfo_t *sfx) { if (sfx->data) + { + Mix_Chunk *chunk = (Mix_Chunk*)sfx->data; + UINT8 *abufdata = NULL; + if (chunk->allocated == 0) + { + // We allocated the data in this chunk, so get the abuf from mixer, then let it free the chunk, THEN we free the data + // I believe this should ensure the sound is not playing when we free it + abufdata = chunk->abuf; + } Mix_FreeChunk(sfx->data); + if (abufdata) + { + // I'm going to assume we used Z_Malloc to allocate this data. + Z_Free(abufdata); + } + } sfx->data = NULL; sfx->lumpnum = LUMPERROR; } -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) { UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127 - INT32 handle = Mix_PlayChannel(-1, S_sfx[id].data, 0); + INT32 handle = Mix_PlayChannel(channel, S_sfx[id].data, 0); Mix_Volume(handle, volume); Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff)); (void)pitch; // Mixer can't handle pitch @@ -432,11 +468,10 @@ void I_SetSfxVolume(UINT8 volume) sfx_volume = volume; } -// -// Music -// +/// ------------------------ +/// Music Hooks +/// ------------------------ -// Music hooks static void music_loop(void) { Mix_PlayMusic(music, 0); @@ -464,78 +499,101 @@ static void mix_gme(void *udata, Uint8 *stream, int len) } #endif + +/// ------------------------ +/// Music System +/// ------------------------ + FUNCMATH void I_InitMusic(void) { } void I_ShutdownMusic(void) { - I_ShutdownDigMusic(); - I_ShutdownMIDIMusic(); + I_UnloadSong(); } -void I_PauseSong(INT32 handle) -{ - (void)handle; - Mix_PauseMusic(); - songpaused = true; -} +/// ------------------------ +/// Music Properties +/// ------------------------ -void I_ResumeSong(INT32 handle) -{ - (void)handle; - Mix_ResumeMusic(); - songpaused = false; -} - -// -// Digital Music -// - -void I_InitDigMusic(void) +musictype_t I_SongType(void) { #ifdef HAVE_LIBGME - gme = NULL; - current_track = -1; + if (gme) + return MU_GME; + else #endif + if (!music) + return MU_NONE; + else if (Mix_GetMusicType(music) == MUS_MID) + return MU_MID; + else if (Mix_GetMusicType(music) == MUS_MOD || Mix_GetMusicType(music) == MUS_MODPLUG) + return MU_MOD; + else if (Mix_GetMusicType(music) == MUS_MP3 || Mix_GetMusicType(music) == MUS_MP3_MAD) + return MU_MP3; + else + return (musictype_t)Mix_GetMusicType(music); } -void I_ShutdownDigMusic(void) +boolean I_SongPlaying(void) { - if (midimode) - return; + return ( +#ifdef HAVE_LIBGME + (I_SongType() == MU_GME && gme) || +#endif + (boolean)music + ); +} + +boolean I_SongPaused(void) +{ + return songpaused; +} + +/// ------------------------ +/// Music Effects +/// ------------------------ + +boolean I_SetSongSpeed(float speed) +{ + if (speed > 250.0f) + speed = 250.0f; //limit speed up to 250x #ifdef HAVE_LIBGME if (gme) { - Mix_HookMusic(NULL, NULL); - gme_delete(gme); - gme = NULL; + SDL_LockAudio(); + gme_set_tempo(gme, speed); + SDL_UnlockAudio(); + return true; } +#else + (void)speed; #endif - if (!music) - return; - Mix_HookMusicFinished(NULL); - Mix_FreeMusic(music); - music = NULL; + return false; } -boolean I_StartDigSong(const char *musicname, boolean looping) +/// ------------------------ +/// Music Playback +/// ------------------------ + +boolean I_LoadSong(char *data, size_t len) { - char *data; - size_t len; - lumpnum_t lumpnum = W_CheckNumForName(va("O_%s",musicname)); + const char *key1 = "LOOP"; + const char *key2 = "POINT="; + const char *key3 = "MS="; + const size_t key1len = strlen(key1); + const size_t key2len = strlen(key2); + const size_t key3len = strlen(key3); + char *p = data; + SDL_RWops *rw; - I_Assert(!music); + if (music #ifdef HAVE_LIBGME - I_Assert(!gme); + || gme #endif - - if (lumpnum == LUMPERROR) - return false; - midimode = false; - - data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC); - len = W_LumpLength(lumpnum); + ) + I_UnloadSong(); #ifdef HAVE_LIBGME if ((UINT8)data[0] == 0x1F @@ -621,66 +679,95 @@ boolean I_StartDigSong(const char *musicname, boolean looping) } Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up #else - //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); + CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); + return true; #endif } else if (!gme_open_data(data, len, &gme, 44100)) { gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; - gme_start_track(gme, 0); - current_track = 0; gme_set_equalizer(gme, &eq); - Mix_HookMusic(mix_gme, gme); return true; } #endif - music = Mix_LoadMUS_RW(SDL_RWFromMem(data, len), SDL_FALSE); + rw = SDL_RWFromMem(data, len); + if (rw != NULL) + { + music = Mix_LoadMUS_RW(rw, 1); + } if (!music) { CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError()); - return true; + return false; } // Find the OGG loop point. loop_point = 0.0f; - if (looping) + + while ((UINT32)(p - data) < len) { - const char *key1 = "LOOP"; - const char *key2 = "POINT="; - const char *key3 = "MS="; - const size_t key1len = strlen(key1); - const size_t key2len = strlen(key2); - const size_t key3len = strlen(key3); - char *p = data; - while ((UINT32)(p - data) < len) + if (strncmp(p++, key1, key1len)) + continue; + p += key1len-1; // skip OOP (the L was skipped in strncmp) + if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? { - if (strncmp(p++, key1, key1len)) - continue; - p += key1len-1; // skip OOP (the L was skipped in strncmp) - if (!strncmp(p, key2, key2len)) // is it LOOPPOINT=? - { - p += key2len; // skip POINT= - loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. - // because SDL_Mixer is USELESS and can't even tell us - // something simple like the frequency of the streaming music, - // we are unfortunately forced to assume that ALL MUSIC is 44100hz. - // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. - } - else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? - { - p += key3len; // skip MS= - loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. - // Everything that uses LOOPMS will work perfectly with SDL_Mixer. - } - // Neither?! Continue searching. + p += key2len; // skip POINT= + loop_point = (float)((44.1L+atoi(p)) / 44100.0L); // LOOPPOINT works by sample count. + // because SDL_Mixer is USELESS and can't even tell us + // something simple like the frequency of the streaming music, + // we are unfortunately forced to assume that ALL MUSIC is 44100hz. + // This means a lot of tracks that are only 22050hz for a reasonable downloadable file size will loop VERY badly. } + else if (!strncmp(p, key3, key3len)) // is it LOOPMS=? + { + p += key3len; // skip MS= + loop_point = (float)(atoi(p) / 1000.0L); // LOOPMS works by real time, as miliseconds. + // Everything that uses LOOPMS will work perfectly with SDL_Mixer. + } + // Neither?! Continue searching. } + return true; +} + +void I_UnloadSong(void) +{ + I_StopSong(); + +#ifdef HAVE_LIBGME + if (gme) + { + gme_delete(gme); + gme = NULL; + } +#endif + if (music) + { + Mix_FreeMusic(music); + music = NULL; + } +} + +boolean I_PlaySong(boolean looping) +{ +#ifdef HAVE_LIBGME + if (gme) + { + gme_start_track(gme, 0); + current_track = 0; + Mix_HookMusic(mix_gme, gme); + return true; + } + else +#endif + if (!music) + return false; + if (Mix_PlayMusic(music, looping && loop_point == 0.0f ? -1 : 0) == -1) { CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); - return true; + return false; } Mix_VolumeMusic((UINT32)music_volume*128/31); @@ -689,51 +776,49 @@ boolean I_StartDigSong(const char *musicname, boolean looping) return true; } -void I_StopDigSong(void) +void I_StopSong(void) { - if (midimode) - return; #ifdef HAVE_LIBGME if (gme) { Mix_HookMusic(NULL, NULL); - gme_delete(gme); - gme = NULL; current_track = -1; - return; } #endif - if (!music) - return; - Mix_HookMusicFinished(NULL); - Mix_FreeMusic(music); - music = NULL; -} - -void I_SetDigMusicVolume(UINT8 volume) -{ - music_volume = volume; - if (midimode || !music) - return; - Mix_VolumeMusic((UINT32)volume*128/31); -} - -boolean I_SetSongSpeed(float speed) -{ - if (speed > 250.0f) - speed = 250.0f; //limit speed up to 250x -#ifdef HAVE_LIBGME - if (gme) + if (music) { - SDL_LockAudio(); - gme_set_tempo(gme, speed); - SDL_UnlockAudio(); - return true; + Mix_HookMusicFinished(NULL); + Mix_HaltMusic(); } -#else - (void)speed; +} + +void I_PauseSong(void) +{ + Mix_PauseMusic(); + songpaused = true; +} + +void I_ResumeSong(void) +{ + Mix_ResumeMusic(); + songpaused = false; +} + +void I_SetMusicVolume(UINT8 volume) +{ + if (!I_SongPlaying()) + return; + +#ifdef _WIN32 + if (I_SongType() == MU_MID) + // HACK: Until we stop using native MIDI, + // disable volume changes + music_volume = 31; + else #endif - return false; + music_volume = volume; + + Mix_VolumeMusic((UINT32)music_volume*128/31); } boolean I_SetSongTrack(int track) @@ -767,79 +852,4 @@ boolean I_SetSongTrack(int track) return false; } -// -// MIDI Music -// - -FUNCMATH void I_InitMIDIMusic(void) -{ -} - -void I_ShutdownMIDIMusic(void) -{ - if (!midimode || !music) - return; - Mix_FreeMusic(music); - music = NULL; -} - -void I_SetMIDIMusicVolume(UINT8 volume) -{ - // HACK: Until we stop using native MIDI, - // disable volume changes - (void)volume; - midi_volume = 31; - //midi_volume = volume; - - if (!midimode || !music) - return; - Mix_VolumeMusic((UINT32)midi_volume*128/31); -} - -INT32 I_RegisterSong(void *data, size_t len) -{ - music = Mix_LoadMUS_RW(SDL_RWFromMem(data, len), SDL_FALSE); - if (!music) - { - CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError()); - return -1; - } - return 1337; -} - -boolean I_PlaySong(INT32 handle, boolean looping) -{ - (void)handle; - - midimode = true; - - if (Mix_PlayMusic(music, looping ? -1 : 0) == -1) - { - CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); - return false; - } - - Mix_VolumeMusic((UINT32)midi_volume*128/31); - return true; -} - -void I_StopSong(INT32 handle) -{ - if (!midimode || !music) - return; - - (void)handle; - Mix_HaltMusic(); -} - -void I_UnRegisterSong(INT32 handle) -{ - if (!midimode || !music) - return; - - (void)handle; - Mix_FreeMusic(music); - music = NULL; -} - -#endif +#endif \ No newline at end of file diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 63b51c625..477f798bd 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -194,8 +194,8 @@ static srb2audio_t localdata; static void Snd_LockAudio(void) //Alam: Lock audio data and uninstall audio callback { if (Snd_Mutex) SDL_LockMutex(Snd_Mutex); - else if (nosound) return; - else if (nomidimusic && nodigimusic + else if (sound_disabled) return; + else if (midi_disabled && digital_disabled #ifdef HW3SOUND && hws_mode == HWS_DEFAULT_MODE #endif @@ -208,8 +208,8 @@ static void Snd_LockAudio(void) //Alam: Lock audio data and uninstall audio call static void Snd_UnlockAudio(void) //Alam: Unlock audio data and reinstall audio callback { if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex); - else if (nosound) return; - else if (nomidimusic && nodigimusic + else if (sound_disabled) return; + else if (midi_disabled && digital_disabled #ifdef HW3SOUND && hws_mode == HWS_DEFAULT_MODE #endif @@ -493,7 +493,7 @@ static inline void I_SetChannels(void) INT32 *steptablemid = steptable + 128; - if (nosound) + if (sound_disabled) return; // This table provides step widths for pitch parameters. @@ -604,12 +604,13 @@ void I_FreeSfx(sfxinfo_t * sfx) // Pitching (that is, increased speed of playback) // is set, but currently not used by mixing. // -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) { (void)priority; (void)pitch; + (void)channel; - if (nosound) + if (sound_disabled) return 0; if (S_sfx[id].data == NULL) return -1; @@ -989,7 +990,7 @@ FUNCINLINE static ATTRINLINE void I_UpdateStream16M(Uint8 *stream, int len) if (Snd_Mutex) SDL_UnlockMutex(Snd_Mutex); } -#ifdef HAVE_LIBGME +#if 0 //#ifdef HAVE_LIBGME static void I_UpdateSteamGME(Music_Emu *emu, INT16 *stream, int len, UINT8 looping) { #define GME_BUFFER_LEN 44100*2048 @@ -1049,14 +1050,16 @@ static void SDLCALL I_UpdateStream(void *userdata, Uint8 *stream, int len) else if (audio.channels == 2 && audio.format == AUDIO_S16SYS) { I_UpdateStream16S(stream, len); -#ifdef HAVE_LIBGME - if (userdata) - { - srb2audio_t *sa_userdata = userdata; - if (!sa_userdata->gme_pause) - I_UpdateSteamGME(sa_userdata->gme_emu, (INT16 *)stream, len/4, sa_userdata->gme_loop); - } -#endif + + // Crashes! But no matter; this build doesn't play music anyway... +// #ifdef HAVE_LIBGME +// if (userdata) +// { +// srb2audio_t *sa_userdata = userdata; +// if (!sa_userdata->gme_pause) +// I_UpdateSteamGME(sa_userdata->gme_emu, (INT16 *)stream, len/4, sa_userdata->gme_loop); +// } +// #endif } } @@ -1136,7 +1139,7 @@ static INT32 Init3DSDriver(const char *soName) void I_ShutdownSound(void) { - if (nosound || !sound_started) + if (sound_disabled || !sound_started) return; CONS_Printf("I_ShutdownSound: "); @@ -1150,7 +1153,7 @@ void I_ShutdownSound(void) } #endif - if (nomidimusic && nodigimusic) + if (midi_disabled && digital_disabled) SDL_CloseAudio(); CONS_Printf("%s", M_GetText("shut down\n")); sound_started = false; @@ -1170,7 +1173,7 @@ void I_StartupSound(void) const char *sdrv_name = NULL; #endif #ifndef HAVE_MIXER - nomidimusic = nodigimusic = true; + midi_disabled = digital_disabled = true; #endif memset(channels, 0, sizeof (channels)); //Alam: Clean it @@ -1213,7 +1216,7 @@ void I_StartupSound(void) audio.samples /= 2; } - if (nosound) + if (sound_disabled) return; #ifdef HW3SOUND @@ -1261,7 +1264,7 @@ void I_StartupSound(void) { snddev_t snddev; - //nosound = true; + //sound_disabled = true; //I_AddExitFunc(I_ShutdownSound); snddev.bps = 16; snddev.sample_rate = audio.freq; @@ -1288,7 +1291,7 @@ void I_StartupSound(void) if (!musicStarted && SDL_OpenAudio(&audio, &audio) < 0) { CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n")); - nosound = true; + sound_disabled = true; return; } else @@ -1313,13 +1316,11 @@ void I_StartupSound(void) // MUSIC API. // -void I_ShutdownMIDIMusic(void) -{ - nomidimusic = false; - if (nodigimusic) I_ShutdownMusic(); -} +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ -#ifdef HAVE_LIBGME +#if 0 //#ifdef HAVE_LIBGME static void I_ShutdownGMEMusic(void) { Snd_LockAudio(); @@ -1330,390 +1331,126 @@ static void I_ShutdownGMEMusic(void) } #endif -void I_ShutdownDigMusic(void) -{ - nodigimusic = false; - if (nomidimusic) I_ShutdownMusic(); -} - -#ifdef HAVE_MIXER -static boolean LoadSong(void *data, size_t lumplength, size_t selectpos) -{ - FILE *midfile; - const char *tempname; -#ifdef USE_RWOPS - if (canuseRW) - { - SDL_RWops *SDLRW; - void *olddata = Smidi[selectpos]; //quick shortcut to set - - Z_Free(olddata); //free old memory - Smidi[selectpos] = NULL; - - if (!data) - return olddata != NULL; //was there old data? - - SDLRW = SDL_RWFromConstMem(data, (int)lumplength); //new RWops from Z_zone - if (!SDLRW) //ERROR while making RWops! - { - CONS_Printf(M_GetText("Couldn't load music lump: %s\n"), SDL_GetError()); - Z_Free(data); - return false; - } - - music[selectpos] = Mix_LoadMUS_RW(SDLRW); // new Mix_Chuck from RWops - if (music[selectpos]) - Smidi[selectpos] = data; //all done - else //ERROR while making Mix_Chuck - { - CONS_Printf(M_GetText("Couldn't load music data: %s\n"), Mix_GetError()); - Z_Free(data); - SDL_RWclose(SDLRW); - Smidi[selectpos] = NULL; - } - return true; - } -#endif - tempname = va("%s/%s", MIDI_PATH, fmidi[selectpos]); - - if (!data) - { - if (FIL_FileExists(tempname)) - return unlink(tempname)+1; -#ifdef MIDI_PATH2 - else if (FIL_FileExists(tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos]))) - return unlink(tempname)+1; -#endif - else - return false; - } - - midfile = fopen(tempname, "wb"); - -#ifdef MIDI_PATH2 - if (!midfile) - { - tempname = va("%s/%s", MIDI_PATH2, fmidi[selectpos]); - midfile = fopen(tempname, "wb"); - } -#endif - - if (!midfile) - { - CONS_Printf(M_GetText("Couldn't open file %s to write music in\n"), tempname); - Z_Free(data); - return false; - } - - if (fwrite(data, lumplength, 1, midfile) == 0) - { - CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, strerror(ferror(midfile))); - Z_Free(data); - fclose(midfile); - return false; - } - - fclose(midfile); - - Z_Free(data); - - music[selectpos] = Mix_LoadMUS(tempname); - if (!music[selectpos]) //ERROR while making Mix_Chuck - { - CONS_Printf(M_GetText("Couldn't load music file %s: %s\n"), tempname, Mix_GetError()); - return false; - } - return true; -} -#endif - - -void I_ShutdownMusic(void) -{ -#ifdef HAVE_MIXER - if ((nomidimusic && nodigimusic) || !musicStarted) - return; - - CONS_Printf("%s", M_GetText("I_ShutdownMusic: ")); - - I_UnRegisterSong(0); - I_StopDigSong(); - Mix_CloseAudio(); -#ifdef MIX_INIT - Mix_Quit(); -#endif - CONS_Printf("%s", M_GetText("shut down\n")); - musicStarted = SDL_FALSE; - if (Msc_Mutex) - SDL_DestroyMutex(Msc_Mutex); - Msc_Mutex = NULL; -#endif -} - -void I_InitMIDIMusic(void) -{ - if (nodigimusic) I_InitMusic(); -} - -void I_InitDigMusic(void) -{ - if (nomidimusic) I_InitMusic(); -} - void I_InitMusic(void) { -#ifdef HAVE_MIXER - char ad[100]; - SDL_version MIXcompiled; - const SDL_version *MIXlinked; -#ifdef MIXER_INIT - const int mixstart = MIX_INIT_OGG; - int mixflags; -#endif -#endif -#ifdef HAVE_LIBGME +#if 0 //#ifdef HAVE_LIBGME I_AddExitFunc(I_ShutdownGMEMusic); #endif - -#ifdef HAVE_MIXER - MIX_VERSION(&MIXcompiled) - MIXlinked = Mix_Linked_Version(); - I_OutputMsg("Compiled for SDL_mixer version: %d.%d.%d\n", - MIXcompiled.major, MIXcompiled.minor, MIXcompiled.patch); -#ifdef MIXER_POS - if (MIXlinked->major == 1 && MIXlinked->minor == 2 && MIXlinked->patch < 7) - canlooping = SDL_FALSE; -#endif -#ifdef USE_RWOPS - if (M_CheckParm("-noRW")) - canuseRW = SDL_FALSE; -#endif - I_OutputMsg("Linked with SDL_mixer version: %d.%d.%d\n", - MIXlinked->major, MIXlinked->minor, MIXlinked->patch); - if (audio.freq < 44100 && !M_CheckParm ("-freq")) //I want atleast 44Khz - { - audio.samples = (Uint16)(audio.samples*(INT32)(44100/audio.freq)); - audio.freq = 44100; //Alam: to keep it around the same XX ms - } - - if (sound_started -#ifdef HW3SOUND - && hws_mode == HWS_DEFAULT_MODE -#endif - ) - { - I_OutputMsg("Temp Shutdown of SDL Audio System"); - SDL_CloseAudio(); - I_OutputMsg(" Done\n"); - } - - CONS_Printf("%s", M_GetText("I_InitMusic:")); - -#ifdef MIXER_INIT - mixflags = Mix_Init(mixstart); - if ((mixstart & MIX_INIT_FLAC) != (mixflags & MIX_INIT_FLAC)) - { - CONS_Printf("%s", M_GetText(" Unable to load FLAC support\n")); - } - if ((mixstart & MIX_INIT_MOD ) != (mixflags & MIX_INIT_MOD )) - { - CONS_Printf("%s", M_GetText(" Unable to load MOD support\n")); - } - if ((mixstart & MIX_INIT_MP3 ) != (mixflags & MIX_INIT_MP3 )) - { - CONS_Printf("%s", M_GetText(" Unable to load MP3 support\n")); - } - if ((mixstart & MIX_INIT_OGG ) != (mixflags & MIX_INIT_OGG )) - { - CONS_Printf("%s", M_GetText(" Unable to load OGG support\n")); - } -#endif - - if (Mix_OpenAudio(audio.freq, audio.format, audio.channels, audio.samples) < 0) //open_music(&audio) - { - CONS_Printf(M_GetText(" Unable to open music: %s\n"), Mix_GetError()); - nomidimusic = nodigimusic = true; - if (sound_started -#ifdef HW3SOUND - && hws_mode == HWS_DEFAULT_MODE -#endif - ) - { - if (SDL_OpenAudio(&audio, NULL) < 0) //retry - { - CONS_Printf("%s", M_GetText(" couldn't open audio with desired format\n")); - nosound = true; - sound_started = false; - } - else - { - CONS_Printf(M_GetText(" Starting with audio driver : %s\n"), SDL_AudioDriverName(ad, (int)sizeof ad)); - } - } - return; - } - else - CONS_Printf(M_GetText(" Starting up with audio driver : %s with SDL_Mixer\n"), SDL_AudioDriverName(ad, (int)sizeof ad)); - - samplecount = audio.samples; - CV_SetValue(&cv_samplerate, audio.freq); - if (sound_started -#ifdef HW3SOUND - && hws_mode == HWS_DEFAULT_MODE -#endif - ) - I_OutputMsg(" Reconfigured SDL Audio System"); - else I_OutputMsg(" Configured SDL_Mixer System"); - I_OutputMsg(" with %d samples/slice at %ikhz(%dms buffer)\n", samplecount, audio.freq/1000, (INT32) ((audio.samples * 1000.0f) / audio.freq)); - Mix_SetPostMix(audio.callback, audio.userdata); // after mixing music, add sound effects - Mix_Resume(-1); - CONS_Printf("%s", M_GetText("Music initialized\n")); - musicStarted = SDL_TRUE; - Msc_Mutex = SDL_CreateMutex(); -#endif } -boolean I_PlaySong(INT32 handle, boolean looping) +void I_ShutdownMusic(void) { } + +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ + +musictype_t I_SongType(void) { - (void)handle; -#ifdef HAVE_MIXER - if (nomidimusic || !musicStarted || !music[handle]) - return false; + return MU_NONE; +} -#ifdef MIXER_POS - if (canlooping) - Mix_HookMusicFinished(NULL); -#endif - - if (Mix_FadeInMusic(music[handle], looping ? -1 : 0, MIDIfade) == -1) - CONS_Printf(M_GetText("Couldn't play song because %s\n"), Mix_GetError()); - else - { - Mix_VolumeMusic(musicvol); - return true; - } -#else - (void)looping; -#endif +boolean I_SongPlaying(void) +{ return false; } +boolean I_SongPaused(void) +{ + return false; +} + +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ + +boolean I_SetSongSpeed(float speed) +{ + (void)speed; + return false; +} + +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ + +#if 0 //#ifdef HAVE_LIBGME +static void I_StopGME(void) +{ + Snd_LockAudio(); + gme_seek(localdata.gme_emu, 0); + Snd_UnlockAudio(); +} + static void I_PauseGME(void) { -#ifdef HAVE_LIBGME localdata.gme_pause = true; -#endif -} - -void I_PauseSong(INT32 handle) -{ - (void)handle; - I_PauseGME(); -#ifdef HAVE_MIXER - if ((nomidimusic && nodigimusic) || !musicStarted) - return; - - Mix_PauseMusic(); - //I_StopSong(handle); -#endif } static void I_ResumeGME(void) { -#ifdef HAVE_LIBGME localdata.gme_pause = false; -#endif } - -void I_ResumeSong(INT32 handle) -{ - (void)handle; - I_ResumeGME(); -#ifdef HAVE_MIXER - if ((nomidimusic && nodigimusic) || !musicStarted) - return; - - Mix_VolumeMusic(musicvol); - Mix_ResumeMusic(); - //I_PlaySong(handle, true); #endif -} -void I_StopSong(INT32 handle) +boolean I_LoadSong(char *data, size_t len) { - (void)handle; -#ifdef HAVE_MIXER - if (nomidimusic || !musicStarted) - return; - Mix_FadeOutMusic(MIDIfade); -#endif -} - -void I_UnRegisterSong(INT32 handle) -{ -#ifdef HAVE_MIXER - - if (nomidimusic || !musicStarted) - return; - - Mix_HaltMusic(); - while (Mix_PlayingMusic()) - ; - - if (music[handle]) - Mix_FreeMusic(music[handle]); - music[handle] = NULL; - LoadSong(NULL, 0, handle); -#else - (void)handle; -#endif -} - -INT32 I_RegisterSong(void *data, size_t len) -{ -#ifdef HAVE_MIXER - if (nomidimusic || !musicStarted) - return false; - - if (!LoadSong(data, len, 0)) - return false; - - if (music[0]) - return true; - - CONS_Printf(M_GetText("Couldn't load MIDI: %s\n"), Mix_GetError()); -#else - (void)len; - (void)data; -#endif return false; } -void I_SetMIDIMusicVolume(UINT8 volume) -{ -#ifdef HAVE_MIXER - if ((nomidimusic && nodigimusic) || !musicStarted) - return; +void I_UnloadSong(void) { } - if (Msc_Mutex) SDL_LockMutex(Msc_Mutex); - musicvol = volume * 2; - if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); - Mix_VolumeMusic(musicvol); -#else - (void)volume; +boolean I_PlaySong(boolean looping) +{ + (void)looping; + return false; +} + +void I_StopSong(void) +{ +#if 0 //#ifdef HAVE_LIBGME + I_StopGME(); #endif } -#ifdef HAVE_LIBGME +void I_PauseSong(void) +{ +#if 0 //#ifdef HAVE_LIBGME + I_PauseGME(); +#endif +} + +void I_ResumeSong(void) +{ +#if 0 + I_ResumeGME(); +#endif +} + +void I_SetMusicVolume(UINT8 volume) +{ + (void)volume; +} + +boolean I_SetSongTrack(int track) +{ + (void)track; + return false; +} + +/// ------------------------ +// MUSIC LOADING AND CLEANUP +// \todo Split logic between loading and playing, +// then move to Playback section +/// ------------------------ + +#if 0 //#ifdef HAVE_LIBGME static void I_CleanupGME(void *userdata) { Z_Free(userdata); } -#endif static boolean I_StartGMESong(const char *musicname, boolean looping) { -#ifdef HAVE_LIBGME char filename[9]; void *data; lumpnum_t lumpnum; @@ -1759,240 +1496,7 @@ static boolean I_StartGMESong(const char *musicname, boolean looping) Snd_UnlockAudio(); return true; -#else - (void)musicname; - (void)looping; -#endif - return false; -} - -boolean I_StartDigSong(const char *musicname, boolean looping) -{ -#ifdef HAVE_MIXER - char filename[9]; - void *data; - lumpnum_t lumpnum; - size_t lumplength; -#endif - - if(I_StartGMESong(musicname, looping)) - return true; - -#ifdef HAVE_MIXER - if (nodigimusic) - return false; - - snprintf(filename, sizeof filename, "o_%s", musicname); - - lumpnum = W_CheckNumForName(filename); - - I_StopDigSong(); - - if (lumpnum == LUMPERROR) - { - // Alam_GBC: like in win32/win_snd.c: Graue 02-29-2004: don't worry about missing music, there might still be a MIDI - //I_OutputMsg("Music lump %s not found!\n", filename); - return false; // No music found. Oh well! - } - else - lumplength = W_LumpLength(lumpnum); - - data = W_CacheLumpNum(lumpnum, PU_MUSIC); - - if (Msc_Mutex) SDL_LockMutex(Msc_Mutex); - -#ifdef MIXER_POS - if (canlooping && (loopingDig = looping) == SDL_TRUE && strcmp(data, "OggS") == 0) - looping = false; // Only on looping Ogg files, will we will do our own looping - - // Scan the Ogg Vorbis file for the COMMENT= field for a custom - // loop point - if (!looping && loopingDig) - { - size_t scan; - const char *dataum = data; - char looplength[64]; - UINT32 loopstart = 0; - UINT8 newcount = 0; - - Mix_HookMusicFinished(I_FinishMusic); - - for (scan = 0; scan < lumplength; scan++) - { - if (*dataum++ == 'C'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'E'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '='){ - if (*dataum++ == 'L'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'I'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '=') - { - - while (*dataum != 1 && newcount != 63) - looplength[newcount++] = *dataum++; - - looplength[newcount] = '\0'; - - loopstart = atoi(looplength); - - } - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - } - - if (loopstart > 0) - { - loopstartDig = (double)((44.1l+loopstart) / 44100.0l); //8 PCM chucks off and PCM to secs -//#ifdef PARANOIA - //I_OutputMsg("I_StartDigSong: setting looping point to %ul PCMs(%f seconds)\n", loopstart, loopstartDig); -//#endif - } - else - { - looping = true; // loopingDig true, but couldn't find start loop point - } - } - else - loopstartDig = 0.0l; -#else - if (looping && strcmp(data, "OggS") == 0) - I_OutputMsg("I_StartDigSong: SRB2 was not compiled with looping music support(no Mix_FadeInMusicPos)\n"); -#endif - - if (!LoadSong(data, lumplength, 1)) - { - if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); - return false; - } - - // Note: LoadSong() frees the data. Let's make sure - // we don't try to use the data again. - data = NULL; - - if (Mix_FadeInMusic(music[1], looping ? -1 : 0, Digfade) == -1) - { - if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); - I_OutputMsg("I_StartDigSong: Couldn't play song %s because %s\n", musicname, Mix_GetError()); - return false; - } - Mix_VolumeMusic(musicvol); - - if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); - return true; -#else - (void)looping; - (void)musicname; - return false; -#endif -} - -static void I_StopGME(void) -{ -#ifdef HAVE_LIBGME - Snd_LockAudio(); - gme_seek(localdata.gme_emu, 0); - Snd_UnlockAudio(); -#endif -} - -void I_StopDigSong(void) -{ - I_StopGME(); -#ifdef HAVE_MIXER - if (nodigimusic) - return; - -#ifdef MIXER_POS - if (canlooping) - Mix_HookMusicFinished(NULL); -#endif - - Mix_HaltMusic(); - while (Mix_PlayingMusic()) - ; - - if (music[1]) - Mix_FreeMusic(music[1]); - music[1] = NULL; - LoadSong(NULL, 0, 1); -#endif -} - -void I_SetDigMusicVolume(UINT8 volume) -{ - I_SetMIDIMusicVolume(volume); -} - -boolean I_SetSongSpeed(float speed) -{ - - (void)speed; - return false; -} - -boolean I_SetSongTrack(int track) -{ - (void)track; - return false; -} - -#ifdef MIXER_POS -static void SDLCALL I_FinishMusic(void) -{ - if (!music[1]) - return; - else if (Msc_Mutex) SDL_LockMutex(Msc_Mutex); -// I_OutputMsg("I_FinishMusic: Loopping song to %g seconds\n", loopstartDig); - - if (Mix_FadeInMusicPos(music[1], loopstartDig ? 0 : -1, Digfade, loopstartDig) == 0) - Mix_VolumeMusic(musicvol); - else - I_OutputMsg("I_FinishMusic: Couldn't loop song because %s\n", Mix_GetError()); - - if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); } #endif + #endif //HAVE_SDL diff --git a/src/v_video.c b/src/v_video.c index 765965ffd..2f84d4c7e 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1045,7 +1045,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ // void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor) { - if (skins[skinnum].flags & SF_HIRES) + if (skinnum < 0 || skinnum >= numskins || (skins[skinnum].flags & SF_HIRES)) V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); else { diff --git a/src/w_wad.c b/src/w_wad.c index 7babd22ef..3112e02a0 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -234,10 +234,10 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum) for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump { // shameless copy+paste of code from LUA_LoadLump - size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name - char *name = malloc(length + 1); + size_t len = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name + char *name = malloc(len+1); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); - name[length] = '\0'; + name[len] = '\0'; CONS_Printf(M_GetText("Loading SOC from %s\n"), name); DEH_LoadDehackedLumpPwad(wadnum, lump); diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c index f6c430748..2586b8440 100644 --- a/src/win32/win_cd.c +++ b/src/win32/win_cd.c @@ -471,7 +471,7 @@ void I_PlayCD(UINT8 nTrack, UINT8 bLooping) //faB: stop MIDI music, MIDI music will restart if volume is upped later cv_digmusicvolume.value = 0; cv_midimusicvolume.value = 0; - I_StopSong (0); + I_StopSong(); //faB: I don't use the notify message, I'm trying to minimize the delay mciPlay.dwCallback = (DWORD)((size_t)hWndMain); diff --git a/src/win32/win_main.c b/src/win32/win_main.c index 6c774f557..bfe620a43 100644 --- a/src/win32/win_main.c +++ b/src/win32/win_main.c @@ -110,9 +110,9 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR // pause music when alt-tab if (appActive && !paused) - I_ResumeSong(0); + I_ResumeSong(); else if (!paused) - I_PauseSong(0); + I_PauseSong(); { HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); DWORD mode; diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c index 88f34abf8..1e1b062f8 100644 --- a/src/win32/win_snd.c +++ b/src/win32/win_snd.c @@ -17,10 +17,8 @@ #include "gme/gme.h" #define GME_TREBLE 5.0 #define GME_BASS 1.0 -#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng - -#define HAVE_ZLIB +#ifdef HAVE_ZLIB #ifndef _MSC_VER #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE @@ -36,13 +34,12 @@ #endif #include "zlib.h" -#endif -#endif +#endif // HAVE_ZLIB +#endif // HAVE_LIBGME static FMOD_SYSTEM *fsys; static FMOD_SOUND *music_stream; static FMOD_CHANNEL *music_channel; -static boolean midimode; static UINT8 music_volume, midi_volume, sfx_volume; static INT32 current_track; @@ -355,12 +352,13 @@ void I_FreeSfx(sfxinfo_t *sfx) sfx->data = NULL; } -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) { FMOD_SOUND *sound; FMOD_CHANNEL *chan; INT32 i; float frequency; + (void)channel; sound = (FMOD_SOUND *)S_sfx[id].data; I_Assert(sound != NULL); @@ -440,9 +438,9 @@ void I_SetSfxVolume(UINT8 volume) sfx_volume = volume; } -// -// MUSIC -// +/// ------------------------ +// MUSIC SYSTEM +/// ------------------------ void I_InitMusic(void) { @@ -450,53 +448,111 @@ void I_InitMusic(void) void I_ShutdownMusic(void) { - I_ShutdownDigMusic(); - I_ShutdownMIDIMusic(); + I_StopSong(); } -void I_PauseSong(INT32 handle) -{ - UNREFERENCED_PARAMETER(handle); - if (music_stream) - FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, true)); -} +/// ------------------------ +// MUSIC PROPERTIES +/// ------------------------ -void I_ResumeSong(INT32 handle) +musictype_t I_SongType(void) { - UNREFERENCED_PARAMETER(handle); - if (music_stream) - FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false)); -} +#ifdef HAVE_LIBGME + if (gme) + return MU_GME; +#endif -void I_InitDigMusic(void) -{ -} + if (!music_stream) + return MU_NONE; -void I_ShutdownDigMusic(void) -{ - if (!midimode) - I_StopDigSong(); -} - -boolean I_StartDigSong(const char *musicname, boolean looping) -{ - char *data; - size_t len; - FMOD_CREATESOUNDEXINFO fmt; - lumpnum_t lumpnum = W_CheckNumForName(va("O_%s",musicname)); - - if (lumpnum == LUMPERROR) + FMOD_SOUND_TYPE type; + if (FMOD_Sound_GetFormat(music_stream, &type, NULL, NULL, NULL) == FMOD_OK) { - lumpnum = W_CheckNumForName(va("D_%s",musicname)); - if (lumpnum == LUMPERROR) - return false; - midimode = true; + switch(type) + { + case FMOD_SOUND_TYPE_WAV: + return MU_WAV; + case FMOD_SOUND_TYPE_MOD: + return MU_MOD; + case FMOD_SOUND_TYPE_MIDI: + return MU_MID; + case FMOD_SOUND_TYPE_OGGVORBIS: + return MU_OGG; + case FMOD_SOUND_TYPE_MPEG: + return MU_MP3; + case FMOD_SOUND_TYPE_FLAC: + return MU_FLAC; + default: + return MU_NONE; + } } else - midimode = false; + return MU_NONE; +} - data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC); - len = W_LumpLength(lumpnum); +boolean I_SongPlaying(void) +{ + return (boolean)music_stream; +} + +boolean I_SongPaused(void) +{ + boolean fmpaused = false; + if (music_stream) + FMOD_Channel_GetPaused(music_channel, &fmpaused); + return fmpaused; +} + +/// ------------------------ +// MUSIC EFFECTS +/// ------------------------ + +boolean I_SetSongSpeed(float speed) +{ + FMOD_RESULT e; + float frequency; + if (!music_stream) + return false; + if (speed > 250.0f) + speed = 250.0f; //limit speed up to 250x + +#ifdef HAVE_LIBGME + // Try to set GME speed + if (gme) + { + gme_set_tempo(gme, speed); + return true; + } +#endif + + // Try to set Mod/Midi speed + e = FMOD_Sound_SetMusicSpeed(music_stream, speed); + + if (e == FMOD_ERR_FORMAT) + { + // Just change pitch instead for Ogg/etc. + FMR(FMOD_Sound_GetDefaults(music_stream, &frequency, NULL, NULL, NULL)); + FMR_MUSIC(FMOD_Channel_SetFrequency(music_channel, speed*frequency)); + } + else + FMR_MUSIC(e); + + return true; +} + +/// ------------------------ +// MUSIC PLAYBACK +/// ------------------------ + +boolean I_LoadSong(char *data, size_t len) +{ + FMOD_CREATESOUNDEXINFO fmt; + FMOD_RESULT e; + FMOD_TAG tag; + unsigned int loopstart, loopend; + + if (gme || music_stream) + I_UnloadSong(); memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); @@ -531,8 +587,6 @@ boolean I_StartDigSong(const char *musicname, boolean looping) gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around Z_Free(data); // We don't need this, either. - gme_start_track(gme, 0); - current_track = 0; gme_set_equalizer(gme,&gmeq); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; @@ -541,10 +595,7 @@ boolean I_StartDigSong(const char *musicname, boolean looping) fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = gme; - FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream)); - FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); - FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); - FMR(FMOD_Channel_SetPriority(music_channel, 0)); + FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream)); return true; } } @@ -603,8 +654,6 @@ boolean I_StartDigSong(const char *musicname, boolean looping) { gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; Z_Free(data); // We don't need this anymore. - gme_start_track(gme, 0); - current_track = 0; gme_set_equalizer(gme,&gmeq); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; @@ -613,7 +662,102 @@ boolean I_StartDigSong(const char *musicname, boolean looping) fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = gme; - FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream)); + FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream)); + return true; + } +#endif + + fmt.length = len; + + e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT, &fmt, &music_stream); + if (e != FMOD_OK) + { + if (e == FMOD_ERR_FORMAT) + CONS_Alert(CONS_WARNING, "Failed to play music lump due to invalid format.\n"); + else + FMR(e); + return false; + } + + // Try to find a loop point in streaming music formats (ogg, mp3) + + // A proper LOOPPOINT is its own tag, stupid. + e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag); + if (e != FMOD_ERR_TAGNOTFOUND) + { + FMR(e); + loopstart = atoi((char *)tag.data); // assumed to be a string data tag. + FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); + if (loopstart > 0) + FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); + return true; + } + + // Use LOOPMS for time in miliseconds. + e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag); + if (e != FMOD_ERR_TAGNOTFOUND) + { + FMR(e); + loopstart = atoi((char *)tag.data); // assumed to be a string data tag. + FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM)); + if (loopstart > 0) + FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM)); + return true; + } + + // Try to fetch it from the COMMENT tag, like A.J. Freda + e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag); + if (e != FMOD_ERR_TAGNOTFOUND) + { + char *loopText; + // Handle any errors that arose, first + FMR(e); + // Figure out where the number starts + loopText = strstr((char *)tag.data,"LOOPPOINT="); + if (loopText != NULL) + { + // Skip the "LOOPPOINT=" part. + loopText += 10; + // Convert it to our looppoint + // FMOD seems to ensure the tag is properly NULL-terminated. + // atoi will stop when it reaches anything that's not a number. + loopstart = atoi(loopText); + // Now do the rest like above + FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); + if (loopstart > 0) + FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); + } + return true; + } + + // No special loop point + return true; +} + +void I_UnloadSong(void) +{ + I_StopSong(); +#ifdef HAVE_LIBGME + if (gme) + { + gme_delete(gme); + gme = NULL; + } +#endif + if (music_stream) + { + FMR(FMOD_Sound_Release(music_stream)); + music_stream = NULL; + } +} + +boolean I_PlaySong(boolean looping) +{ +#ifdef HAVE_LIBGME + if (gme) + { + gme_start_track(gme, 0); + current_track = 0; FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR(FMOD_Channel_SetPriority(music_channel, 0)); @@ -621,139 +765,48 @@ boolean I_StartDigSong(const char *musicname, boolean looping) } #endif - fmt.length = len; - { - FMOD_RESULT e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT|(looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream); - if (e != FMOD_OK) - { - if (e == FMOD_ERR_FORMAT) - CONS_Alert(CONS_WARNING, "Failed to play music lump %s due to invalid format.\n", W_CheckNameForNum(lumpnum)); - else - FMR(e); - return false; - } - } + FMR(FMOD_Sound_SetMode(music_stream, (looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF))); FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); - if (midimode) + if (I_SongType() != MU_MID) FMR(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0)); else FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR(FMOD_Channel_SetPriority(music_channel, 0)); current_track = 0; - // Try to find a loop point in streaming music formats (ogg, mp3) - if (looping) - { - FMOD_RESULT e; - FMOD_TAG tag; - unsigned int loopstart, loopend; - - // A proper LOOPPOINT is its own tag, stupid. - e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - FMR(e); - loopstart = atoi((char *)tag.data); // assumed to be a string data tag. - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); - return true; - } - - // Use LOOPMS for time in miliseconds. - e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - FMR(e); - loopstart = atoi((char *)tag.data); // assumed to be a string data tag. - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM)); - return true; - } - - // Try to fetch it from the COMMENT tag, like A.J. Freda - e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - char *loopText; - // Handle any errors that arose, first - FMR(e); - // Figure out where the number starts - loopText = strstr((char *)tag.data,"LOOPPOINT="); - if (loopText != NULL) - { - // Skip the "LOOPPOINT=" part. - loopText += 10; - // Convert it to our looppoint - // FMOD seems to ensure the tag is properly NULL-terminated. - // atoi will stop when it reaches anything that's not a number. - loopstart = atoi(loopText); - // Now do the rest like above - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); - } - return true; - } - } - - // No special loop point, but we're playing so it's all good. return true; } -void I_StopDigSong(void) +void I_StopSong(void) { - if (music_stream) - FMR(FMOD_Sound_Release(music_stream)); - music_stream = NULL; -#ifdef HAVE_LIBGME - if (gme) - gme_delete(gme); - gme = NULL; -#endif - current_track = -1; + if (music_channel) + FMR_MUSIC(FMOD_Channel_Stop(music_channel)); } -void I_SetDigMusicVolume(UINT8 volume) +void I_PauseSong(void) { + if (music_channel) + FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, true)); +} + +void I_ResumeSong(void) +{ + if (music_channel) + FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false)); +} + +void I_SetMusicVolume(UINT8 volume) +{ + if (!music_channel) + return; + // volume is 0 to 31. - music_volume = volume; - if (!midimode && music_stream) - FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, volume / 31.0)); -} - -boolean I_SetSongSpeed(float speed) -{ - FMOD_RESULT e; - float frequency; - if (!music_stream) - return false; - if (speed > 250.0f) - speed = 250.0f; //limit speed up to 250x - -#ifdef HAVE_LIBGME - // Try to set GME speed - if (gme) - { - gme_set_tempo(gme, speed); - return true; - } -#endif - - // Try to set Mod/Midi speed - e = FMOD_Sound_SetMusicSpeed(music_stream, speed); - - if (e == FMOD_ERR_FORMAT) - { - // Just change pitch instead for Ogg/etc. - FMR(FMOD_Sound_GetDefaults(music_stream, &frequency, NULL, NULL, NULL)); - FMR_MUSIC(FMOD_Channel_SetFrequency(music_channel, speed*frequency)); - } + if (I_SongType() == MU_MID) + music_volume = 31; // windows bug hack else - FMR_MUSIC(e); + music_volume = volume; - return true; + FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); } boolean I_SetSongTrack(INT32 track) @@ -800,62 +853,3 @@ boolean I_SetSongTrack(INT32 track) } return false; } - -// -// Fuck MIDI. ... Okay fine, you can have your silly D_-only mode. -// - -void I_InitMIDIMusic(void) -{ -} - -void I_ShutdownMIDIMusic(void) -{ - if (midimode) - I_StopSong(0); -} - -void I_SetMIDIMusicVolume(UINT8 volume) -{ - // volume is 0 to 31. - midi_volume = volume; - if (midimode && music_stream) - FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, volume / 31.0)); -} - -INT32 I_RegisterSong(void *data, size_t len) -{ - FMOD_CREATESOUNDEXINFO fmt; - memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); - fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); - fmt.length = len; - FMR(FMOD_System_CreateStream(fsys, (char *)data, FMOD_OPENMEMORY_POINT, &fmt, &music_stream)); - return 1337; -} - -boolean I_PlaySong(INT32 handle, boolean looping) -{ - if (1337 == handle) - { - midimode = true; - if (looping) - FMR(FMOD_Sound_SetMode(music_stream, FMOD_LOOP_NORMAL)); - FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); - FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0)); - FMR_MUSIC(FMOD_Channel_SetPriority(music_channel, 0)); - } - return true; -} - -void I_StopSong(INT32 handle) -{ - I_UnRegisterSong(handle); -} - -void I_UnRegisterSong(INT32 handle) -{ - UNREFERENCED_PARAMETER(handle); - if (music_stream) - FMR(FMOD_Sound_Release(music_stream)); - music_stream = NULL; -} diff --git a/src/y_inter.c b/src/y_inter.c index 598f3c8ab..ec7aa30ca 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1750,6 +1750,26 @@ static void Y_SetRingBonus(player_t *player, y_bonus_t *bstruct) bstruct->points = max(0, (player->rings) * 100); } +// +// Y_SetNightsBonus +// +static void Y_SetNightsBonus(player_t *player, y_bonus_t *bstruct) +{ + strncpy(bstruct->patch, "YB_NIGHT", sizeof(bstruct->patch)); + bstruct->display = true; + bstruct->points = player->totalmarescore; +} + +// +// Y_SetLapBonus +// +static void Y_SetLapBonus(player_t *player, y_bonus_t *bstruct) +{ + strncpy(bstruct->patch, "YB_LAP", sizeof(bstruct->patch)); + bstruct->display = true; + bstruct->points = max(0, player->totalmarebonuslap * 1000); +} + // // Y_SetLinkBonus // @@ -1811,7 +1831,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) // This list can be extended in the future with SOC/Lua, perhaps. typedef void (*bonus_f)(player_t *, y_bonus_t *); -bonus_f bonuses_list[4][4] = { +bonus_f bonuses_list[6][4] = { { Y_SetNullBonus, Y_SetNullBonus, @@ -1836,6 +1856,18 @@ bonus_f bonuses_list[4][4] = { Y_SetRingBonus, Y_SetPerfectBonus, }, + { + Y_SetNullBonus, + Y_SetNightsBonus, + Y_SetLapBonus, + Y_SetNullBonus, + }, + { + Y_SetNullBonus, + Y_SetLinkBonus, + Y_SetLapBonus, + Y_SetNullBonus, + }, }; @@ -1911,8 +1943,8 @@ static void Y_AwardSpecialStageBonus(void) if (!playeringame[i] || players[i].lives < 1) // not active or game over Y_SetNullBonus(&players[i], &localbonus); - else if (maptol & TOL_NIGHTS) // Link instead of Rings - Y_SetLinkBonus(&players[i], &localbonus); + else if (maptol & TOL_NIGHTS) // Mare score instead of Rings + Y_SetNightsBonus(&players[i], &localbonus); else Y_SetRingBonus(&players[i], &localbonus); players[i].score += localbonus.points;