From 7bd741a6446a678660c4d310c546bbc3fa6ea8cc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 4 Apr 2010 17:48:26 +0000 Subject: [PATCH 001/251] - Fixed compiling with FMOD Ex 4.30.00. I get no 3D sound effects, and it's crashing on me, too. Am I doing something wrong? SVN r2271 (trunk) --- src/sound/fmodsound.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 671b73d21..e167d389f 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -167,7 +167,10 @@ static const FEnumList OutputNames[] = { "SDL", 666 }, // Mac +#if FMOD_VERSION < 0x43000 + // Sound Manager support was removed sometime in the 4.29 line. { "Sound Manager", FMOD_OUTPUTTYPE_SOUNDMANAGER }, +#endif { "Core Audio", FMOD_OUTPUTTYPE_COREAUDIO }, { NULL, 0 } From d875a0c67476bcbfbe2f0c8615968bcf561b131a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 5 Apr 2010 09:17:34 +0000 Subject: [PATCH 002/251] - fixed: Loading a savegame with music switched off forced a restart of the map's default music because starting an empty music was considered an error. SVN r2272 (trunk) --- src/s_playlist.cpp | 7 ++++++- src/s_sound.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index e92a5ceea..e7170eaa8 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -122,7 +122,12 @@ bool FPlayList::ChangeList (const char *path) // Path is relative; append it to the playlist directory. song = playlistdir + song; } - Songs.Push(song); + + // Just to make sure + if (song.IsNotEmpty()) + { + Songs.Push(song); + } } fclose (file); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index f31f1c2da..db0f0f21d 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2327,7 +2327,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) // Don't choke if the map doesn't have a song attached S_StopMusic (true); mus_playing.name = ""; - return false; + return true; } FString DEH_Music; From 114412d5a2ed274839ac3eb68a19898c4b00b4bb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Apr 2010 03:12:32 +0000 Subject: [PATCH 003/251] - Search for the MUS header within the first 32 bytes of the song so that the music in diescum.wad works. SVN r2273 (trunk) --- src/sound/fmodsound.cpp | 2 +- src/sound/i_music.cpp | 78 ++++++++++++++++----------------- src/sound/music_mus_midiout.cpp | 77 +++++++++++++++++++++++++------- zdoom.vcproj | 2 +- 4 files changed, 103 insertions(+), 56 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e167d389f..b9c2f8bc2 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1671,10 +1671,10 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * chan->setReverbProperties(&reverb); } } - chan->setPaused(false); chan->getPriority(&def_priority); FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan); schan->Rolloff = *rolloff; + chan->setPaused(false); return schan; } diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 38e820c8b..6e996bbad 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -84,6 +84,8 @@ extern void ChildSigHandler (int signum); #define GZIP_FNAME 8 #define GZIP_FCOMMENT 16 +extern int MUSHeaderSearch(const BYTE *head, int len); + EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Int, snd_mididevice) @@ -295,9 +297,14 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { FILE *file; MusInfo *info = NULL; - DWORD id; + union + { + DWORD id[32/4]; + BYTE idstr[32]; + }; const char *fmt; BYTE *ungzipped; + int i; if (nomusic) { @@ -322,22 +329,32 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { fseek (file, offset, SEEK_SET); } - - if (fread (&id, 4, 1, file) != 1) + if (len < 32) + { + return 0; + } + if (fread (id, 4, 32/4, file) != 32/4) { fclose (file); return 0; } - fseek (file, -4, SEEK_CUR); + fseek (file, -32, SEEK_CUR); } else { file = NULL; - id = *(DWORD *)musiccache; + if (len < 32) + { + return 0; + } + for (i = 0; i < 32/4; ++i) + { + id[i] = ((DWORD *)musiccache)[i]; + } } #ifndef _WIN32 - // non-windows platforms don't support MDEV_MIDI so map to MDEV_FMOD + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD if (device == MDEV_MMAPI) device = MDEV_FMOD; #endif @@ -346,7 +363,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // that can handle it, so it simplifies things if we make all songs // gzippable. ungzipped = NULL; - if ((id & MAKE_ID(255,255,255,0)) == GZIP_ID) + if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID) { if (offset != -1) { @@ -370,11 +387,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int return NULL; } musiccache = ungzipped; - id = *(DWORD *)ungzipped; + for (i = 0; i < 32/4; ++i) + { + id[i] = ((DWORD *)musiccache)[i]; + } } // Check for MUS format - if (id == MAKE_ID('M','U','S',0x1a)) + // Tolerate sloppy wads by searching up to 32 bytes for the header + if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0) { /* MUS are played as: - OPL: @@ -453,7 +474,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // Check for MIDI format else { - if (id == MAKE_ID('M','T','h','d')) + if (id[0] == MAKE_ID('M','T','h','d')) { // This is a midi file @@ -502,36 +523,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int #endif // _WIN32 } // Check for various raw OPL formats - else if (len >= 12 && - (id == MAKE_ID('R','A','W','A') || // Rdos Raw OPL - id == MAKE_ID('D','B','R','A') || // DosBox Raw OPL - id == MAKE_ID('A','D','L','I'))) // Martin Fernandez's modified IMF + else if ( + (id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL + (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL + (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - DWORD fullsig[2]; - - if (file != NULL) - { - if (fread (fullsig, 4, 2, file) != 2) - { - fclose (file); - return 0; - } - fseek (file, -8, SEEK_CUR); - } - else - { - memcpy(fullsig, musiccache, 8); - } - - if ((fullsig[0] == MAKE_ID('R','A','W','A') && fullsig[1] == MAKE_ID('D','A','T','A')) || - (fullsig[0] == MAKE_ID('D','B','R','A') && fullsig[1] == MAKE_ID('W','O','P','L')) || - (fullsig[0] == MAKE_ID('A','D','L','I') && (fullsig[1] & MAKE_ID(255,255,0,0)) == MAKE_ID('B',1,0,0))) - { - info = new OPLMUSSong (file, musiccache, len); - } + info = new OPLMUSSong (file, musiccache, len); } // Check for game music - else if ((fmt = GME_CheckFormat(id)) != NULL && fmt[0] != '\0') + else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') { info = GME_OpenSong(file, musiccache, len, fmt); } @@ -545,7 +545,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int if (info == NULL) { // Check for CDDA "format" - if (id == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) + if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) { if (file != NULL) { @@ -572,7 +572,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int // smaller than this can't possibly be a valid music file if it hasn't // been identified already, so don't even bother trying to load it. // Of course MIDIs shorter than 1024 bytes should pass. - if (info == NULL && (len >= 1024 || id == MAKE_ID('M','T','h','d'))) + if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d'))) { // Let FMOD figure out what it is. if (file != NULL) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index fcdf704bd..ef6cba16d 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -51,6 +51,8 @@ // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- +int MUSHeaderSearch(const BYTE *head, int len); + // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -99,32 +101,55 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) } #endif - MusHeader = (MUSHeader *)new BYTE[len]; - if (file != NULL) + BYTE front[32]; + int start; + + if (file == NULL) { - if (fread(MusHeader, 1, len, file) != (size_t)len) + memcpy(front, musiccache, len); + } + else if (fread(front, 1, 32, file) != 32) + { + return; + } + + // To tolerate sloppy wads (diescum.wad, I'm looking at you), we search + // the first 32 bytes of the file for a signature. My guess is that DMX + // does no validation whatsoever and just assumes it was passed a valid + // MUS file, since where the header is offset affects how it plays. + start = MUSHeaderSearch(front, sizeof(front)); + if (start < 0) + { + return; + } + + // Read the remainder of the song. + len = int(len - start); + if (len < sizeof(MusHeader)) + { // It's too short. + return; + } + MusHeader = (MUSHeader *)new BYTE[len]; + if (file == NULL) + { + memcpy(MusHeader, musiccache + start, len); + } + else + { + memcpy(MusHeader, front + start, 32 - start); + if (fread((BYTE *)MusHeader + 32 - start, 1, len - (32 - start), file) != (size_t)(len - (32 - start))) { return; } } - else - { - memcpy(MusHeader, musiccache, len); - } - // Do some validation of the MUS file - if (MusHeader->Magic != MAKE_ID('M','U','S','\x1a')) - { - return; - } - + // Do some validation of the MUS file. if (LittleShort(MusHeader->NumChans) > 15) { return; } - MusBuffer = (BYTE *)MusHeader + LittleShort(MusHeader->SongStart); - MaxMusP = MIN (LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart)); + MaxMusP = MIN(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart)); Division = 140; InitialTempo = 1000000; } @@ -376,3 +401,25 @@ MUSSong2::MUSSong2(const MUSSong2 *original, const char *filename, EMIDIDevice t Division = 140; InitialTempo = 1000000; } + +//========================================================================== +// +// MUSHeaderSearch +// +// Searches for the MUS header within the given memory block, returning +// the offset it was found at, or -1 if not present. +// +//========================================================================== + +int MUSHeaderSearch(const BYTE *head, int len) +{ + len -= 4; + for (int i = 0; i <= len; ++i) + { + if (head[i+0] == 'M' && head[i+1] == 'U' && head[i+2] == 'S' && head[i+3] == 0x1A) + { + return i; + } + } + return -1; +} diff --git a/zdoom.vcproj b/zdoom.vcproj index 2cee5d413..74ab3a9e3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -318,7 +318,7 @@ Date: Wed, 7 Apr 2010 02:02:53 +0000 Subject: [PATCH 004/251] - Added MUS header scan to mus2midi. - Fixed buffer overflow when reading a MUS song from a compressed file. SVN r2274 (trunk) --- src/mus2midi.cpp | 29 ++++++++++++++++++++--------- src/mus2midi.h | 4 ++-- src/sound/i_music.cpp | 4 ++-- src/sound/music_midi_timidity.cpp | 2 +- src/sound/music_mus_midiout.cpp | 9 +++++---- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/mus2midi.cpp b/src/mus2midi.cpp index beef4ffa4..63e59e755 100644 --- a/src/mus2midi.cpp +++ b/src/mus2midi.cpp @@ -53,7 +53,7 @@ static const BYTE StaticMIDIhead[] = 0, 255, 81, 3, 0x07, 0xa1, 0x20 }; -static const DWORD MUSMagic = MAKE_ID('M','U','S',0x1a); +extern int MUSHeaderSearch(const BYTE *head, int len); static const BYTE CtrlTranslate[15] = { @@ -110,23 +110,30 @@ static size_t WriteVarLen (TArray &file, int time) return ofs; } -bool ProduceMIDI (const BYTE *musBuf, TArray &outFile) +bool ProduceMIDI (const BYTE *musBuf, int len, TArray &outFile) { BYTE midStatus, midArgs, mid1, mid2; size_t mus_p, maxmus_p; BYTE event; int deltaTime; - const MUSHeader *musHead = (const MUSHeader *)musBuf; + const MUSHeader *musHead; BYTE status; BYTE chanUsed[16]; BYTE lastVel[16]; long trackLen; bool no_op; - // Do some validation of the MUS file - if (MUSMagic != musHead->Magic) + // Find the header + int offset = MUSHeaderSearch(musBuf, len); + + if (offset < 0 || offset + (int)sizeof(MUSHeader) >= len) return false; - + + musBuf += offset; + len -= offset; + musHead = (const MUSHeader *)musBuf; + + // Do some validation of the MUS file if (LittleShort(musHead->NumChans) > 15) return false; @@ -136,8 +143,12 @@ bool ProduceMIDI (const BYTE *musBuf, TArray &outFile) memcpy(&outFile[0], StaticMIDIhead, sizeof(StaticMIDIhead)); musBuf += LittleShort(musHead->SongStart); - maxmus_p = LittleShort(musHead->SongLen); mus_p = 0; + maxmus_p = LittleShort(musHead->SongLen); + if ((size_t)len - LittleShort(musHead->SongStart) < maxmus_p) + { + maxmus_p = len - LittleShort(musHead->SongStart); + } memset (lastVel, 100, 16); memset (chanUsed, 0, 16); @@ -287,10 +298,10 @@ bool ProduceMIDI (const BYTE *musBuf, TArray &outFile) return true; } -bool ProduceMIDI(const BYTE *musBuf, FILE *outFile) +bool ProduceMIDI(const BYTE *musBuf, int len, FILE *outFile) { TArray work; - if (ProduceMIDI(musBuf, work)) + if (ProduceMIDI(musBuf, len, work)) { return fwrite(&work[0], 1, work.Size(), outFile) == work.Size(); } diff --git a/src/mus2midi.h b/src/mus2midi.h index 6780bdf47..6dc75dc03 100644 --- a/src/mus2midi.h +++ b/src/mus2midi.h @@ -75,7 +75,7 @@ typedef struct // WORD UsedInstruments[NumInstruments]; } MUSHeader; -bool ProduceMIDI (const BYTE *musBuf, TArray &outFile); -bool ProduceMIDI (const BYTE *musBuf, FILE *outFile); +bool ProduceMIDI (const BYTE *musBuf, int len, TArray &outFile); +bool ProduceMIDI (const BYTE *musBuf, int len, FILE *outFile); #endif //__MUS2MIDI_H__ diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 6e996bbad..e25d4b5d6 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -441,7 +441,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int if (file == NULL) { - midi_made = ProduceMIDI((BYTE *)musiccache, midi); + midi_made = ProduceMIDI((BYTE *)musiccache, len, midi); } else { @@ -449,7 +449,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int size_t did_read = fread(mus, 1, len, file); if (did_read == (size_t)len) { - midi_made = ProduceMIDI(mus, midi); + midi_made = ProduceMIDI(mus, len, midi); } fseek(file, -(long)did_read, SEEK_CUR); delete[] mus; diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 15e69c8a6..ea725d0da 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -227,7 +227,7 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len) } else { - success = ProduceMIDI (buf, f); + success = ProduceMIDI (buf, len, f); } fclose (f); if (file != NULL) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index ef6cba16d..68558bdad 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -106,9 +106,9 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) if (file == NULL) { - memcpy(front, musiccache, len); + memcpy(front, musiccache, sizeof(front)); } - else if (fread(front, 1, 32, file) != 32) + else if (fread(front, 1, sizeof(front), file) != sizeof(front)) { return; } @@ -136,8 +136,8 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) } else { - memcpy(MusHeader, front + start, 32 - start); - if (fread((BYTE *)MusHeader + 32 - start, 1, len - (32 - start), file) != (size_t)(len - (32 - start))) + memcpy(MusHeader, front + start, sizeof(front) - start); + if (fread((BYTE *)MusHeader + sizeof(front) - start, 1, len - (sizeof(front) - start), file) != (size_t)(len - (32 - start))) { return; } @@ -148,6 +148,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) { return; } + MusBuffer = (BYTE *)MusHeader + LittleShort(MusHeader->SongStart); MaxMusP = MIN(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart)); Division = 140; From d6d2ce6b2400acb77f931e68dfb6511704e75d91 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 7 Apr 2010 02:16:51 +0000 Subject: [PATCH 005/251] - Fixed: maxitems calculation for MKEY_Up in M_OptButtonHandler() used the unscaled text height instead of the scaled text height to calculate the bottom-most usable row. SVN r2275 (trunk) --- src/m_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index 9c8199757..e87fa87a2 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -2319,7 +2319,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) } ytop *= CleanYfac_1; rowheight *= CleanYfac_1; - maxitems = (screen->GetHeight() - SmallFont->GetHeight() - ytop) / rowheight + 1; + maxitems = (screen->GetHeight() - rowheight - ytop) / rowheight + 1; CurrentMenu->scrollpos = MAX (0,CurrentMenu->numitems - maxitems + CurrentMenu->scrolltop); CurrentItem = CurrentMenu->numitems - 1; From f101b45d9a5ac11c9fa527e80e5bdc949bddc9fc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 7 Apr 2010 03:37:07 +0000 Subject: [PATCH 006/251] - Changed P_SeekerMissile() to compute a proper 3D trajectory. SVN r2276 (trunk) --- src/p_mobj.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a3d739bea..613054652 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1546,9 +1546,8 @@ bool AActor::CanSeek(AActor *target) const bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) { int dir; - int dist; angle_t delta; - angle_t angle; + angle_t angle, pitch; AActor *target; target = actor->tracer; @@ -1578,25 +1577,26 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) { // Turn counter clockwise actor->angle -= delta; } - angle = actor->angle>>ANGLETOFINESHIFT; - actor->velx = FixedMul (actor->Speed, finecosine[angle]); - actor->vely = FixedMul (actor->Speed, finesine[angle]); + angle = actor->angle >> ANGLETOFINESHIFT; + pitch = 0; if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) - { - if (actor->z + actor->height < target->z || - target->z + target->height < actor->z) - { // Need to seek vertically - dist = P_AproxDistance (target->x - actor->x, target->y - actor->y); - dist = dist / actor->Speed; - if (dist < 1) - { - dist = 1; - } - actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist; + { // Need to seek vertically + double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length()); + // Aim at a player's eyes and at the middle of the actor for everything else. + fixed_t aimheight = target->height/2; + if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + aimheight = static_cast(target)->ViewHeight; } + pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight); + pitch >>= ANGLETOFINESHIFT; } + fixed_t xyscale = FixedMul(actor->Speed, finecosine[pitch]); + actor->velz = FixedMul(actor->Speed, finesine[pitch]); + actor->velx = FixedMul(xyscale, finecosine[angle]); + actor->vely = FixedMul(xyscale, finesine[angle]); return true; } From a5e422020ee2a3a6695581698b361222fb4ae0e9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 9 Apr 2010 20:03:18 +0000 Subject: [PATCH 007/251] - fixed: Two stage texture compositing did not clear the intermediate buffer before using it. SVN r2277 (trunk) --- src/textures/multipatchtexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index faaa5db6c..0e4b9bc8f 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -614,6 +614,7 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota FBitmap bmp1; if (bmp1.Create(Parts[i].Texture->GetWidth(), Parts[i].Texture->GetHeight())) { + bmp1.Zero(); Parts[i].Texture->CopyTrueColorPixels(&bmp1, 0, 0); bmp->CopyPixelDataRGB(x+Parts[i].OriginX, y+Parts[i].OriginY, bmp1.GetPixels(), bmp1.GetWidth(), bmp1.GetHeight(), 4, bmp1.GetPitch(), Parts[i].Rotate, CF_BGRA, inf); From d916127ecf35495b033ff5b5ae9861ee9c6c9587 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Apr 2010 11:12:29 +0000 Subject: [PATCH 008/251] - made the recent change to P_SeekerMissile an option because it affected critical gameplay behavior and may not be used for existing actors. SVN r2278 (trunk) --- src/p_local.h | 2 +- src/p_mobj.cpp | 60 +++++++++++++++++++++--------- src/thingdef/thingdef_codeptr.cpp | 3 +- wadsrc/static/actors/constants.txt | 1 + 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 3aff45bf0..e42dc960d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -94,7 +94,7 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer=false); void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); -bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax); +bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false); enum EPuffFlags { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 613054652..dbb3f38b7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1543,11 +1543,12 @@ bool AActor::CanSeek(AActor *target) const // //---------------------------------------------------------------------------- -bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) +bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise) { int dir; + int dist; angle_t delta; - angle_t angle, pitch; + angle_t angle; AActor *target; target = actor->tracer; @@ -1577,30 +1578,55 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) { // Turn counter clockwise actor->angle -= delta; } - angle = actor->angle >> ANGLETOFINESHIFT; - pitch = 0; + angle = actor->angle>>ANGLETOFINESHIFT; + + if (!precise) + { + actor->velx = FixedMul (actor->Speed, finecosine[angle]); + actor->vely = FixedMul (actor->Speed, finesine[angle]); - if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) - { // Need to seek vertically - double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length()); - // Aim at a player's eyes and at the middle of the actor for everything else. - fixed_t aimheight = target->height/2; - if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { - aimheight = static_cast(target)->ViewHeight; + if (actor->z + actor->height < target->z || + target->z + target->height < actor->z) + { // Need to seek vertically + dist = P_AproxDistance (target->x - actor->x, target->y - actor->y); + dist = dist / actor->Speed; + if (dist < 1) + { + dist = 1; + } + actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist; + } } - pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight); - pitch >>= ANGLETOFINESHIFT; + } + else + { + angle_t pitch; + if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) + { // Need to seek vertically + double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length()); + // Aim at a player's eyes and at the middle of the actor for everything else. + fixed_t aimheight = target->height/2; + if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + aimheight = static_cast(target)->ViewHeight; + } + pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight); + pitch >>= ANGLETOFINESHIFT; + } + + fixed_t xyscale = FixedMul(actor->Speed, finecosine[pitch]); + actor->velz = FixedMul(actor->Speed, finesine[pitch]); + actor->velx = FixedMul(xyscale, finecosine[angle]); + actor->vely = FixedMul(xyscale, finesine[angle]); } - fixed_t xyscale = FixedMul(actor->Speed, finecosine[pitch]); - actor->velz = FixedMul(actor->Speed, finesine[pitch]); - actor->velx = FixedMul(xyscale, finecosine[angle]); - actor->vely = FixedMul(xyscale, finesine[angle]); return true; } + // // P_XYMovement // diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 45038d83f..6d066684b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -346,6 +346,7 @@ static FRandom pr_seekermissile ("SeekerMissile"); enum { SMF_LOOK = 1, + SMF_PRECISE = 2, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { @@ -360,7 +361,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { self->tracer = P_RoughMonsterSearch (self, distance); } - P_SeekerMissile(self, clamp(ang1, 0, 90) * ANGLE_1, clamp(ang2, 0, 90) * ANGLE_1); + P_SeekerMissile(self, clamp(ang1, 0, 90) * ANGLE_1, clamp(ang2, 0, 90) * ANGLE_1, !!(flags & SMF_PRECISE)); } //========================================================================== diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 0e1f8f903..0fd613a72 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -79,6 +79,7 @@ const int BF_AFFECTBOSSES = 4; // Flags for A_SeekerMissile const int SMF_LOOK = 1; +const int SMF_PRECISE = 2; // Activation flags enum From c7272075d3c873b7e5d9583d4789a6fa1d7b562b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Apr 2010 06:43:42 +0000 Subject: [PATCH 009/251] - added a few NULL pointer checks to protect against problems caused by actors being spawned during engine shutdown. SVN r2279 (trunk) --- src/p_mobj.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index dbb3f38b7..37276c949 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -593,7 +593,10 @@ bool AActor::SetState (FState *newstate) newstate = newstate->GetNextState(); } while (tics == 0); - screen->StateChanged(this); + if (screen != NULL) + { + screen->StateChanged(this); + } return true; } @@ -653,7 +656,10 @@ bool AActor::SetStateNF (FState *newstate) newstate = newstate->GetNextState(); } while (tics == 0); - screen->StateChanged(this); + if (screen != NULL) + { + screen->StateChanged(this); + } return true; } @@ -3693,7 +3699,10 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t { level.total_items++; } - screen->StateChanged(actor); + if (screen != NULL) + { + screen->StateChanged(actor); + } return actor; } From e4d0d6bcdbec7f211fa88c23c635d032fcc69747 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Apr 2010 11:18:33 +0000 Subject: [PATCH 010/251] - added a Sector_CopyScroller special to allow setting scrollers to sectors with special tags. - extended compatibility text to allow changing line flags and setting line specials on specific linedefs. - removed Strain MAP07 hack and replaced it by a clean 'clearlineflags' option. - Added Doomo format translations for Sector_CopyScroller because this looks like something that might be useful for making some Boom maps work without having to resort to compatibility.txt. - added a compatibility setting for UAC Ultra MAP07 which exploited some undefined scrolling behavior in Boom. (What lengths are we going to make sloppily created maps work? This entire commit was just to address this particular problem...) SVN r2280 (trunk) --- src/actionspecials.h | 1 + src/compatibility.cpp | 126 ++++++++++++++++++++++++++++++-- src/compatibility.h | 2 + src/doomdef.h | 3 +- src/p_setup.cpp | 10 +-- src/p_spec.cpp | 47 ++++++++++++ src/statnums.h | 6 +- wadsrc/static/compatibility.txt | 8 +- wadsrc/static/xlat/base.txt | 4 + 9 files changed, 187 insertions(+), 20 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index cd49504c3..de2d86bfb 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -56,6 +56,7 @@ DEFINE_SPECIAL(Sector_ChangeFlags, 54, 3, 3, 3) DEFINE_SPECIAL(Line_SetBlocking, 55, 3, 3, 3) DEFINE_SPECIAL(Line_SetTextureScale, 56, 5, 5, 5) DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5) +DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2) DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3) DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index f4fbaa529..caaaaf871 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -43,10 +43,13 @@ #include "sc_man.h" #include "cmdlib.h" #include "doomdef.h" +#include "doomdata.h" #include "doomstat.h" #include "c_dispatch.h" #include "gi.h" #include "g_level.h" +#include "p_lnspec.h" +#include "r_state.h" // MACROS ------------------------------------------------------------------ @@ -59,6 +62,14 @@ struct FCompatOption int BCompatFlags; }; +enum +{ + CP_END, + CP_CLEARFLAGS, + CP_SETFLAGS, + CP_SETSPECIAL +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -77,7 +88,6 @@ static FCompatOption Options[] = { { "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW }, { "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED }, - { "spechitoverflow", 0, BCOMPATF_SPECHITOVERFLOW }, { "vileghosts", 0, BCOMPATF_VILEGHOSTS }, // list copied from g_mapinfo.cpp @@ -109,6 +119,9 @@ static FCompatOption Options[] = { NULL, 0, 0 } }; +static TArray CompatParams; +static int ii_compatparams; + // CODE -------------------------------------------------------------------- //========================================================================== @@ -170,12 +183,57 @@ void ParseCompatibility() } while (!sc.Compare("{")); flags.CompatFlags = 0; flags.BCompatFlags = 0; - while (sc.MustGetString(), (i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) + flags.ExtCommandIndex = -1; + while (sc.GetString()) { - flags.CompatFlags |= Options[i].CompatFlags; - flags.BCompatFlags |= Options[i].BCompatFlags; + if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) + { + flags.CompatFlags |= Options[i].CompatFlags; + flags.BCompatFlags |= Options[i].BCompatFlags; + } + else if (sc.Compare("clearlineflags")) + { + if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_CLEARFLAGS); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + } + else if (sc.Compare("setlineflags")) + { + if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SETFLAGS); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + } + else if (sc.Compare("setlinespecial")) + { + if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SETSPECIAL); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + + sc.MustGetString(); + CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL)); + for(int i=0;i<5;i++) + { + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + } + } + else + { + sc.UnGet(); + break; + } + } + if (flags.ExtCommandIndex != -1) + { + CompatParams.Push(CP_END); } - sc.UnGet(); sc.MustGetStringName("}"); for (j = 0; j < md5array.Size(); ++j) { @@ -201,6 +259,7 @@ void CheckCompatibility(MapData *map) { ii_compatflags = COMPATF_SHORTTEX; ib_compatflags = 0; + ii_compatparams = -1; } else { @@ -223,17 +282,74 @@ void CheckCompatibility(MapData *map) { ii_compatflags = flags->CompatFlags; ib_compatflags = flags->BCompatFlags; + ii_compatparams = flags->ExtCommandIndex; } else { ii_compatflags = 0; ib_compatflags = 0; + ii_compatparams = -1; } } // Reset i_compatflags compatflags.Callback(); } +//========================================================================== +// +// SetCompatibilityParams +// +//========================================================================== + +void SetCompatibilityParams() +{ + if (ii_compatparams != -1) + { + unsigned i = ii_compatparams; + + while (CompatParams[i] != CP_END && i < CompatParams.Size()) + { + switch (CompatParams[i]) + { + case CP_CLEARFLAGS: + { + if (CompatParams[i+1] < numlines) + { + line_t *line = &lines[CompatParams[i+1]]; + line->flags &= ~CompatParams[i+2]; + } + i+=3; + break; + } + case CP_SETFLAGS: + { + if (CompatParams[i+1] < numlines) + { + line_t *line = &lines[CompatParams[i+1]]; + line->flags |= CompatParams[i+2]; + } + i+=3; + break; + } + case CP_SETSPECIAL: + { + if (CompatParams[i+1] < numlines) + { + line_t *line = &lines[CompatParams[i+1]]; + line->special = CompatParams[i+2]; + for(int ii=0;ii<5;ii++) + { + line->args[ii] = CompatParams[i+ii+3]; + } + } + i+=8; + break; + } + } + } + } +} + //========================================================================== // // CCMD mapchecksum diff --git a/src/compatibility.h b/src/compatibility.h index f80314cbd..5726955b5 100644 --- a/src/compatibility.h +++ b/src/compatibility.h @@ -16,6 +16,7 @@ struct FCompatValues { int CompatFlags; int BCompatFlags; + unsigned int ExtCommandIndex; }; struct FMD5HashTraits @@ -37,5 +38,6 @@ extern TMap BCompatMap; void ParseCompatibility(); void CheckCompatibility(MapData *map); +void SetCompatibilityParams(); #endif diff --git a/src/doomdef.h b/src/doomdef.h index 485f15a5e..42636f9cb 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -333,8 +333,7 @@ enum { BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps - BCOMPATF_SPECHITOVERFLOW = 1 << 2, // Emulate spechit overflow (e.g. Strain MAP07) - BCOMPATF_VILEGHOSTS = 1 << 3, // Monsters' radius and height aren't restored properly when resurrected. + BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected. }; // phares 3/20/98: diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c27da8e56..d9b285c03 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3516,15 +3516,7 @@ void P_SetupLevel (char *lumpname, int position) else P_LoadThings2 (map); // [RH] Load Hexen-style things - if (ib_compatflags & BCOMPATF_SPECHITOVERFLOW) - { - // restoring the original behavior doesn't work so we have to patch the levels in other ways. - // Fortunately the only known level depending on this bug is Strain's MAP07 and that's easy to fix. - if (numlines == 1022) - { - lines[1021].flags &= ~ML_BLOCKING; - } - } + SetCompatibilityParams(); } else { diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 737ccc226..9f634ab56 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1501,6 +1501,20 @@ static void P_SpawnScrollers(void) { int i; line_t *l = lines; + TArray copyscrollers; + + for (i = 0; i < numlines; i++) + { + if (lines[i].special == Sector_CopyScroller) + { + // don't allow copying the scroller if the sector has the same tag as it would just duplicate it. + if (lines[i].args[0] != lines[i].frontsector->tag) + { + copyscrollers.Push(i); + } + lines[i].special = 0; + } + } for (i = 0; i < numlines; i++, l++) { @@ -1571,20 +1585,53 @@ static void P_SpawnScrollers(void) case Scroll_Ceiling: for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) + { new DScroller (DScroller::sc_ceiling, -dx, dy, control, s, accel); + } + for(unsigned j = 0;j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 1)) + { + new DScroller (DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector-sectors), accel); + } + } break; case Scroll_Floor: if (l->args[2] != 1) { // scroll the floor texture for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) + { new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel); + } + for(unsigned j = 0;j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 2)) + { + new DScroller (DScroller::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel); + } + } } if (l->args[2] > 0) { // carry objects on the floor for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;) + { new DScroller (DScroller::sc_carry, dx, dy, control, s, accel); + } + for(unsigned j = 0;j < copyscrollers.Size(); j++) + { + line_t *line = &lines[copyscrollers[j]]; + + if (line->args[0] == l->args[0] && (line->args[1] & 4)) + { + new DScroller (DScroller::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel); + } + } } break; diff --git a/src/statnums.h b/src/statnums.h index f699b9c39..344a328c8 100644 --- a/src/statnums.h +++ b/src/statnums.h @@ -35,7 +35,7 @@ ** lists for different types of thinkers is taken from Build. Every thinker ** is ticked by statnum, so a thinker with a low statnum will always tick ** before a thinker with a high statnum. If a thinker is not explicitly -** created with a statnum, it will be given MAX_STATNUM. +** created with a statnum, it will be given STAT_DEFAULT */ enum @@ -59,10 +59,10 @@ enum STAT_EARTHQUAKE, // Earthquake actors STAT_MAPMARKER, // Map marker actors - STAT_DEFAULT = 100, + STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise. STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement STAT_ACTORMOVER, // actor movers - STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors calles PostBeginPlay + STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay }; #endif \ No newline at end of file diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 685fda086..09f38a80b 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -58,7 +58,7 @@ F84AB4557464A383E93F37CD3A82AC48 // MM2 map03 9D50EBE17CEC78938C7A668DB0768611 // Strain map07: Make the exit accessible { - spechitoverflow + clearlineflags 1021 1 } 71C2E6D9CFA3D8750C6A9599FB2453BD // Hacx map03: There are some switches behind @@ -128,3 +128,9 @@ CA267398C9B3A8F79349D3394F8B2106 // map20 { spritesort } + +DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller depending on Boom side effects +{ + setlinespecial 391 Sector_CopyScroller 99 6 0 0 0 +} + diff --git a/wadsrc/static/xlat/base.txt b/wadsrc/static/xlat/base.txt index a7aa69f1c..45b23e52f 100644 --- a/wadsrc/static/xlat/base.txt +++ b/wadsrc/static/xlat/base.txt @@ -321,6 +321,10 @@ include "xlat/defines.i" 350 = 0, Transfer_Heights (tag, 2) // Just fake the floor 351 = 0, Transfer_Heights (tag, 6) // Just fake the floor and clip it too +352 = 0, Sector_CopyScroller(tag, 1) // copy ceiling scroller +353 = 0, Sector_CopyScroller(tag, 2) // copy floor scroller +354 = 0, Sector_CopyScroller(tag, 6) // copy carrying floor scroller + /****** EDGE linetypes ******/ 400 = 0, ExtraFloor_LightOnly (tag, 0) // thick From 08b931006fb048d0aba1f08a5e2d56579e1a445d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 17 Apr 2010 01:55:33 +0000 Subject: [PATCH 011/251] - Reverted accidental change to fmodsound.cpp from revision 2273. SVN r2282 (trunk) --- src/sound/fmodsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index b9c2f8bc2..e167d389f 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1671,10 +1671,10 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * chan->setReverbProperties(&reverb); } } + chan->setPaused(false); chan->getPriority(&def_priority); FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan); schan->Rolloff = *rolloff; - chan->setPaused(false); return schan; } From 87a7ff7b6dd8129caeab9ba086ce3413919e4f55 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 17 Apr 2010 02:06:26 +0000 Subject: [PATCH 012/251] - Add blzut3's morphed status bar patch. SVN r2283 (trunk) --- src/d_netinfo.cpp | 4 -- src/d_player.h | 2 +- src/g_shared/a_morph.cpp | 26 +----------- src/g_shared/sbar.h | 10 ++--- src/g_shared/sbar_mugshot.cpp | 8 ++-- src/g_shared/sbarinfo.cpp | 4 -- src/g_shared/shared_sbar.cpp | 75 ----------------------------------- src/p_mobj.cpp | 1 - 8 files changed, 9 insertions(+), 121 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index c415ebe4a..51467369c 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -774,10 +774,6 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) // Rebuild translation in case the new skin uses a different range // than the old one. R_BuildPlayerTranslation (i); - if (StatusBar != NULL && i == StatusBar->GetPlayer()) - { - StatusBar->SetFace (&skins[info->skin]); - } break; case INFO_Gender: diff --git a/src/d_player.h b/src/d_player.h index 2c77872e8..28b240c10 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -312,7 +312,7 @@ public: short fixedlightlevel; pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) int morphTics; // player is a chicken/pig if > 0 - BYTE MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed + const PClass *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed int MorphStyle; // which effects to apply for this player instance when morphed const PClass *MorphExitFlash; // flash to apply when demorphing (cache of value given to P_MorphPlayer) TObjPtr PremorphWeapon; // ready weapon before morphing diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index a807ad70b..2fa69b03e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -99,15 +99,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i p->morphTics = (duration) ? duration : MORPHTICS; // [MH] Used by SBARINFO to speed up face drawing - p->MorphedPlayerClass = 0; - for (unsigned int i = 1; i < PlayerClasses.Size(); i++) - { - if (PlayerClasses[i].Type == spawntype) - { - p->MorphedPlayerClass = i; - break; - } - } + p->MorphedPlayerClass = spawntype; p->MorphStyle = style; p->MorphExitFlash = (exit_flash) ? exit_flash : RUNTIME_CLASS(ATeleportFog); @@ -149,21 +141,6 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i p->camera = morphed; } morphed->ScoreIcon = actor->ScoreIcon; // [GRB] - - // [MH] - // If the player that was morphed is the one - // taking events, set up the face, if any; - // this is only needed for old-skool skins - // and for the original DOOM status bar. - if (p == &players[consoleplayer]) - { - const char *face = spawntype->Meta.GetMetaString (APMETA_Face); - - if (face != NULL && strcmp(face, "None") != 0) - { - StatusBar->SetFace(&skins[p->MorphedPlayerClass]); - } - } return true; } @@ -309,7 +286,6 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } } } - StatusBar->SetFace(&skins[skinindex]); } } diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index d3e72c79e..cf677771a 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -165,7 +165,7 @@ struct FMugShotFrame FMugShotFrame(); ~FMugShotFrame(); - FTexture *GetTexture(const char *default_face, FPlayerSkin *skin, int random, int level=0, + FTexture *GetTexture(const char *default_face, const char *skin_face, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false); }; @@ -189,9 +189,9 @@ struct FMugShotState void Tick(); void Reset(); FMugShotFrame &GetCurrentFrame() { return Frames[Position]; } - FTexture *GetCurrentFrameTexture(const char *default_face, FPlayerSkin *skin, int level=0, int direction=0) + FTexture *GetCurrentFrameTexture(const char *default_face, const char *skin_face, int level=0, int direction=0) { - return GetCurrentFrame().GetTexture(default_face, skin, Random, level, direction, bUsesLevels, bHealth2, bHealthSpecial, bDirectional); + return GetCurrentFrame().GetTexture(default_face, skin_face, Random, level, direction, bUsesLevels, bHealth2, bHealthSpecial, bDirectional); } private: FMugShotState(); @@ -300,8 +300,6 @@ public: virtual void AttachToPlayer (player_t *player); virtual void FlashCrosshair (); virtual void BlendView (float blend[4]); - virtual void SetFace (void *skn); // Takes a FPlayerSkin as input - virtual void AddFaceToImageCollection (void *skn, FImageCollection *images); // Takes a FPlayerSkin as input virtual void NewGame (); virtual void ScreenSizeChanged (); virtual void MultiplayerChanged (); @@ -334,8 +332,6 @@ protected: void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const; - void AddFaceToImageCollectionActual (void *skn, FImageCollection *images, bool isDoom); - public: AInventory *ValidateInvFirst (int numVisible) const; void DrawCrosshair (); diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index a41476576..73d469eac 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -76,7 +76,7 @@ FMugShotFrame::~FMugShotFrame() // //=========================================================================== -FTexture *FMugShotFrame::GetTexture(const char *default_face, FPlayerSkin *skin, int random, int level, +FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_face, int random, int level, int direction, bool uses_levels, bool health2, bool healthspecial, bool directional) { int index = !directional ? random % Graphic.Size() : direction; @@ -84,7 +84,7 @@ FTexture *FMugShotFrame::GetTexture(const char *default_face, FPlayerSkin *skin, { index = Graphic.Size() - 1; } - FString sprite(skin->face[0] != 0 ? skin->face : default_face, 3); + FString sprite(skin_face[0] != 0 ? skin_face : default_face, 3); sprite += Graphic[index]; if (uses_levels) //change the last character to the level { @@ -492,8 +492,8 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu } if (CurrentState != NULL) { - FPlayerSkin *skin = &skins[player->morphTics ? player->MorphedPlayerClass : player->userinfo.skin]; - return CurrentState->GetCurrentFrameTexture(default_face, skin, level, angle); + const char *skin_face = player->morphTics ? player->MorphedPlayerClass->Meta.GetMetaString(APMETA_Face) : skins[player->userinfo.skin].face; + return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; } diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index e020d4258..8ec68982d 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -861,10 +861,6 @@ public: { patchnames[i+script->Images.Size()] = InventoryBarLumps[i]; } - for (i = 0;i < numskins;i++) - { - AddFaceToImageCollection (&skins[i], &Images); - } invBarOffset = script->Images.Size(); Images.Init(&patchnames[0], patchnames.Size()); } diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 1bbe490ca..96074390c 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1591,15 +1591,6 @@ void DBaseStatusBar::FlashItem (const PClass *itemtype) { } -void DBaseStatusBar::SetFace (void *skn) -{ -} - -void DBaseStatusBar::AddFaceToImageCollection (void *skn, FImageCollection *images) -{ - AddFaceToImageCollectionActual (skn, images, false); -} - void DBaseStatusBar::NewGame () { } @@ -1635,72 +1626,6 @@ void DBaseStatusBar::ScreenSizeChanged () } } -//--------------------------------------------------------------------------- -// -// AddFaceToImageCollectionActual -// -// Adds face graphics for specified skin to the specified image collection. -// If not in DOOM statusbar and no face in current skin, do NOT default STF* -// -//--------------------------------------------------------------------------- - -void DBaseStatusBar::AddFaceToImageCollectionActual (void *skn, FImageCollection *images, bool isDoom) -{ - const char *nameptrs[ST_NUMFACES]; - char names[ST_NUMFACES][9]; - char prefix[4]; - int i, j; - int namespc; - int facenum; - FPlayerSkin *skin = (FPlayerSkin *)skn; - - if ((skin->face[0] == 0) && !isDoom) - { - return; - } - - for (i = 0; i < ST_NUMFACES; i++) - { - nameptrs[i] = names[i]; - } - - if (skin->face[0] != 0) - { - prefix[0] = skin->face[0]; - prefix[1] = skin->face[1]; - prefix[2] = skin->face[2]; - prefix[3] = 0; - namespc = skin->namespc; - } - else - { - prefix[0] = 'S'; - prefix[1] = 'T'; - prefix[2] = 'F'; - prefix[3] = 0; - namespc = ns_global; - } - - facenum = 0; - - for (i = 0; i < ST_NUMPAINFACES; i++) - { - for (j = 0; j < ST_NUMSTRAIGHTFACES; j++) - { - mysnprintf (names[facenum++], countof(names[0]), "%sST%d%d", prefix, i, j); - } - mysnprintf (names[facenum++], countof(names[0]), "%sTR%d0", prefix, i); // turn right - mysnprintf (names[facenum++], countof(names[0]), "%sTL%d0", prefix, i); // turn left - mysnprintf (names[facenum++], countof(names[0]), "%sOUCH%d", prefix, i); // ouch! - mysnprintf (names[facenum++], countof(names[0]), "%sEVL%d", prefix, i); // evil grin ;) - mysnprintf (names[facenum++], countof(names[0]), "%sKILL%d", prefix, i); // pissed off - } - mysnprintf (names[facenum++], countof(names[0]), "%sGOD0", prefix); - mysnprintf (names[facenum++], countof(names[0]), "%sDEAD0", prefix); - - images->Add (nameptrs, ST_NUMFACES, namespc); -} - //--------------------------------------------------------------------------- // // ValidateInvFirst diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 37276c949..278fd27a7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4020,7 +4020,6 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer) // [GRB] Reset skin p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass); - StatusBar->SetFace (&skins[p->userinfo.skin]); if (!(mobj->flags2 & MF2_DONTTRANSLATE)) From 64fe29bf0ee1a447f652aefc51f7dd8be3993324 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 17 Apr 2010 02:42:50 +0000 Subject: [PATCH 013/251] - Fixed crash when parsing invalid DECALDEF lumps. SVN r2284 (trunk) --- src/decallib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decallib.cpp b/src/decallib.cpp index d20adc921..bfcc1ac14 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -403,7 +403,7 @@ void FDecalLib::ReadDecals(FScanner &sc) } else { - sc.MustGetStringName(NULL); + sc.ScriptError("Unknown decaldef keyword '%s'", sc.String); } } } From da99577cbf7158a42591c288c2d6f60948929fbe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2010 08:53:32 +0000 Subject: [PATCH 014/251] - added support for loading DeepBSP's V4 nodes. - disabled writing the nodes with the dumpmap command. ZDoom doesn't need the nodes to load a map and this only worked if the original map had standard nodes but trying to write out nodes loaded from any other format would have caused broken data. SVN r2285 (trunk) --- src/doomdata.h | 48 ++++++++++++++++++++++- src/p_setup.cpp | 94 ++++++++++++++++++++++++++++++++-------------- src/p_writemap.cpp | 15 +++++++- 3 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/doomdata.h b/src/doomdata.h index d066277a7..6b3002cdb 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -29,6 +29,7 @@ // Some global defines, that configure the game. #include "doomdef.h" +#include "m_swap.h" // // Map level types. @@ -220,6 +221,13 @@ struct mapsubsector_t WORD firstseg; // index of first one, segs are stored sequentially }; +#pragma pack(1) +struct mapsubsector4_t +{ + WORD numsegs; + DWORD firstseg; // index of first one, segs are stored sequentially +}; +#pragma pack() // LineSeg, generated by splitting LineDefs // using partition lines selected by BSP builder. @@ -231,6 +239,22 @@ struct mapseg_t WORD linedef; SWORD side; SWORD offset; + + int V1() { return LittleShort(v1); } + int V2() { return LittleShort(v2); } +}; + +struct mapseg4_t +{ + SDWORD v1; + SDWORD v2; + SWORD angle; + WORD linedef; + SWORD side; + SWORD offset; + + int V1() { return LittleLong(v1); } + int V2() { return LittleLong(v2); } }; @@ -238,18 +262,40 @@ struct mapseg_t // BSP node structure. // Indicate a leaf. -#define NF_SUBSECTOR 0x8000 struct mapnode_t { + enum + { + NF_SUBSECTOR = 0x8000, + NF_LUMPOFFSET = 0 + }; SWORD x,y,dx,dy; // partition line SWORD bbox[2][4]; // bounding box for each child // If NF_SUBSECTOR is or'ed in, it's a subsector, // else it's a node of another subtree. WORD children[2]; + + DWORD Child(int num) { return LittleShort(children[num]); } }; +struct mapnode4_t +{ + enum + { + NF_SUBSECTOR = 0x80000000, + NF_LUMPOFFSET = 8 + }; + SWORD x,y,dx,dy; // partition line + SWORD bbox[2][4]; // bounding box for each child + // If NF_SUBSECTOR is or'ed in, it's a subsector, + // else it's a node of another subtree. + DWORD children[2]; + + DWORD Child(int num) { return LittleLong(children[num]); } +}; + // Thing definition, position, orientation and type, diff --git a/src/p_setup.cpp b/src/p_setup.cpp index d9b285c03..5a6cc671f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1029,6 +1029,22 @@ static void P_LoadZNodes (FileReader &dalump, DWORD id) } +//=========================================================================== +// +// P_CheckV4Nodes +// http://www.sbsoftware.com/files/DeePBSPV4specs.txt +// +//=========================================================================== + +static bool P_CheckV4Nodes(MapData *map) +{ + char header[8]; + + map->Read(ML_NODES, header, 8); + return !memcmp(header, "xNd4\0\0\0\0", 8); +} + + //=========================================================================== // // P_LoadSegs @@ -1037,6 +1053,7 @@ static void P_LoadZNodes (FileReader &dalump, DWORD id) // //=========================================================================== +template void P_LoadSegs (MapData * map) { int i; @@ -1053,7 +1070,7 @@ void P_LoadSegs (MapData * map) memset (vertchanged,0,numvertexes); // phares 10/4/98 - numsegs = lumplen / sizeof(mapseg_t); + numsegs = lumplen / sizeof(segtype); if (numsegs == 0) { @@ -1085,14 +1102,14 @@ void P_LoadSegs (MapData * map) { for (i = 0; i < numsegs; i++) { - seg_t *li = segs+i; - mapseg_t *ml = (mapseg_t *) data + i; + seg_t *li = segs + i; + segtype *ml = ((segtype *) data) + i; int side, linedef; line_t *ldef; - vnum1 = LittleShort(ml->v1); - vnum2 = LittleShort(ml->v2); + vnum1 = ml->V1(); + vnum2 = ml->V2(); if (vnum1 >= numvertexes || vnum2 >= numvertexes) { @@ -1222,12 +1239,13 @@ void P_LoadSegs (MapData * map) // //=========================================================================== +template void P_LoadSubsectors (MapData * map) { int i; - DWORD maxseg = map->Size(ML_SEGS) / sizeof(mapseg_t); + DWORD maxseg = map->Size(ML_SEGS) / sizeof(segtype); - numsubsectors = map->MapLumps[ML_SSECTORS].Size / sizeof(mapsubsector_t); + numsubsectors = map->MapLumps[ML_SSECTORS].Size / sizeof(subsectortype); if (numsubsectors == 0 || maxseg == 0 ) { @@ -1244,11 +1262,11 @@ void P_LoadSubsectors (MapData * map) for (i = 0; i < numsubsectors; i++) { - WORD numsegs, firstseg; + subsectortype subd; - (*map->file) >> numsegs >> firstseg; + (*map->file) >> subd.numsegs >> subd.firstseg; - if (numsegs == 0) + if (subd.numsegs == 0) { Printf ("Subsector %i is empty.\n", i); delete[] subsectors; @@ -1257,8 +1275,8 @@ void P_LoadSubsectors (MapData * map) return; } - subsectors[i].numlines = numsegs; - subsectors[i].firstline = firstseg; + subsectors[i].numlines = subd.numsegs; + subsectors[i].firstline = subd.firstseg; if (subsectors[i].firstline >= maxseg) { @@ -1390,6 +1408,7 @@ void P_LoadSectors (MapData * map) // //=========================================================================== +template void P_LoadNodes (MapData * map) { FMemLump data; @@ -1397,13 +1416,13 @@ void P_LoadNodes (MapData * map) int j; int k; char *mnp; - mapnode_t *mn; + nodetype *mn; node_t* no; WORD* used; int lumplen = map->Size(ML_NODES); - int maxss = map->Size(ML_SSECTORS) / sizeof(mapsubsector_t); + int maxss = map->Size(ML_SSECTORS) / sizeof(subsectortype); - numnodes = lumplen / sizeof(mapnode_t); + numnodes = (lumplen - nodetype::NF_LUMPOFFSET) / sizeof(nodetype); if ((numnodes == 0 && maxss != 1) || maxss == 0) { @@ -1416,8 +1435,8 @@ void P_LoadNodes (MapData * map) memset (used, 0, sizeof(WORD)*numnodes); mnp = new char[lumplen]; - mn = (mapnode_t*)mnp; - map->Read(ML_NODES, mn); + mn = (nodetype*)(mnp + nodetype::NF_LUMPOFFSET); + map->Read(ML_NODES, mnp); no = nodes; for (i = 0; i < numnodes; i++, no++, mn++) @@ -1428,10 +1447,10 @@ void P_LoadNodes (MapData * map) no->dy = LittleShort(mn->dy)<children[j]); - if (child & NF_SUBSECTOR) + int child = mn->Child(j); + if (child & nodetype::NF_SUBSECTOR) { - child &= ~NF_SUBSECTOR; + child &= ~nodetype::NF_SUBSECTOR; if (child >= maxss) { Printf ("BSP node %d references invalid subsector %d.\n" @@ -3590,17 +3609,34 @@ void P_SetupLevel (char *lumpname, int position) // This just means that the map has no nodes and the engine is supposed to build them. if (map->Size(ML_SEGS) != 0 || map->Size(ML_SSECTORS) != 0 || map->Size(ML_NODES) != 0) { - times[7].Clock(); - P_LoadSubsectors (map); - times[7].Unclock(); + if (!P_CheckV4Nodes(map)) + { + times[7].Clock(); + P_LoadSubsectors (map); + times[7].Unclock(); - times[8].Clock(); - if (!ForceNodeBuild) P_LoadNodes (map); - times[8].Unclock(); + times[8].Clock(); + if (!ForceNodeBuild) P_LoadNodes (map); + times[8].Unclock(); - times[9].Clock(); - if (!ForceNodeBuild) P_LoadSegs (map); - times[9].Unclock(); + times[9].Clock(); + if (!ForceNodeBuild) P_LoadSegs (map); + times[9].Unclock(); + } + else + { + times[7].Clock(); + P_LoadSubsectors (map); + times[7].Unclock(); + + times[8].Clock(); + if (!ForceNodeBuild) P_LoadNodes (map); + times[8].Unclock(); + + times[9].Clock(); + if (!ForceNodeBuild) P_LoadSegs (map); + times[9].Unclock(); + } } else ForceNodeBuild = true; } diff --git a/src/p_writemap.cpp b/src/p_writemap.cpp index db758631f..7a052cb3b 100644 --- a/src/p_writemap.cpp +++ b/src/p_writemap.cpp @@ -172,8 +172,10 @@ static int WriteVERTEXES (FILE *file) return numvertexes * sizeof(mv); } + static int WriteSEGS (FILE *file) { +#if 0 mapseg_t ms; ms.offset = 0; // unused by ZDoom, so just leave it 0 @@ -190,10 +192,14 @@ static int WriteSEGS (FILE *file) } } return numsegs * sizeof(ms); +#else + return 0; +#endif } static int WriteSSECTORS (FILE *file) { +#if 0 mapsubsector_t mss; for (int i = 0; i < numsubsectors; ++i) @@ -203,10 +209,14 @@ static int WriteSSECTORS (FILE *file) fwrite (&mss, sizeof(mss), 1, file); } return numsubsectors * sizeof(mss); +#else + return 0; +#endif } static int WriteNODES (FILE *file) { +#if 0 mapnode_t mn; for (int i = 0; i < numnodes; ++i) @@ -224,7 +234,7 @@ static int WriteNODES (FILE *file) WORD child; if ((size_t)nodes[i].children[j] & 1) { - child = NF_SUBSECTOR | WORD((subsector_t *)((BYTE *)nodes[i].children[j] - 1) - subsectors); + child = mapnode_t::NF_SUBSECTOR | WORD((subsector_t *)((BYTE *)nodes[i].children[j] - 1) - subsectors); } else { @@ -235,6 +245,9 @@ static int WriteNODES (FILE *file) fwrite (&mn, sizeof(mn), 1, file); } return numnodes * sizeof(mn); +#else + return 0; +#endif } static int WriteSECTORS (FILE *file) From c85a602546c59f5bfc939d609445f51a9b22036e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2010 20:49:18 +0000 Subject: [PATCH 015/251] - allow loading uncompressed version of compressed nodes. - extended FileReader hierarchy so that FileReader, FileReaderZ etc. all inherit from one base class so that the same code can be used to read from both uncompressed and compressed streams. SVN r2287 (trunk) --- src/files.h | 59 +++++++++++++++++++++++++++++++++---- src/p_setup.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 120 insertions(+), 16 deletions(-) diff --git a/src/files.h b/src/files.h index 5ee70e3fd..ebe9665a4 100644 --- a/src/files.h +++ b/src/files.h @@ -8,7 +8,56 @@ #include "doomtype.h" #include "m_swap.h" -class FileReader +class FileReaderBase +{ +public: + virtual ~FileReaderBase() {} + virtual long Read (void *buffer, long len) = 0; + + FileReaderBase &operator>> (BYTE &v) + { + Read (&v, 1); + return *this; + } + + FileReaderBase &operator>> (SBYTE &v) + { + Read (&v, 1); + return *this; + } + + FileReaderBase &operator>> (WORD &v) + { + Read (&v, 2); + v = LittleShort(v); + return *this; + } + + FileReaderBase &operator>> (SWORD &v) + { + Read (&v, 2); + v = LittleShort(v); + return *this; + } + + FileReaderBase &operator>> (DWORD &v) + { + Read (&v, 4); + v = LittleLong(v); + return *this; + } + + FileReaderBase &operator>> (fixed_t &v) + { + Read (&v, 4); + v = LittleLong(v); + return *this; + } + +}; + + +class FileReader : public FileReaderBase { public: FileReader (); @@ -82,13 +131,13 @@ protected: }; // Wraps around a FileReader to decompress a zlib stream -class FileReaderZ +class FileReaderZ : public FileReaderBase { public: FileReaderZ (FileReader &file, bool zip=false); ~FileReaderZ (); - long Read (void *buffer, long len); + virtual long Read (void *buffer, long len); FileReaderZ &operator>> (BYTE &v) { @@ -144,7 +193,7 @@ private: }; // Wraps around a FileReader to decompress a bzip2 stream -class FileReaderBZ2 +class FileReaderBZ2 : public FileReaderBase { public: FileReaderBZ2 (FileReader &file); @@ -206,7 +255,7 @@ private: }; // Wraps around a FileReader to decompress a lzma stream -class FileReaderLZMA +class FileReaderLZMA : public FileReaderBase { public: FileReaderLZMA (FileReader &file, size_t uncompressed_size, bool zip); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5a6cc671f..45f50c64e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -793,7 +793,7 @@ void P_LoadVertexes (MapData * map) // //=========================================================================== -void P_LoadZSegs (FileReaderZ &data) +void P_LoadZSegs (FileReaderBase &data) { for (int i = 0; i < numsegs; ++i) { @@ -830,7 +830,7 @@ void P_LoadZSegs (FileReaderZ &data) // //=========================================================================== -void P_LoadGLZSegs (FileReaderZ &data, DWORD id) +void P_LoadGLZSegs (FileReaderBase &data, int type) { for (int i = 0; i < numsubsectors; ++i) { @@ -843,7 +843,7 @@ void P_LoadGLZSegs (FileReaderZ &data, DWORD id) BYTE side; data >> v1 >> partner; - if (id == MAKE_ID('Z','G','L','2')) + if (type == 2) { data >> line; } @@ -905,14 +905,12 @@ void P_LoadGLZSegs (FileReaderZ &data, DWORD id) // //=========================================================================== -static void P_LoadZNodes (FileReader &dalump, DWORD id) +static void LoadZNodes(FileReaderBase &data, int glnodes) { - FileReaderZ data (dalump); - DWORD i; - // Read extra vertices added during node building DWORD orgVerts, newVerts; vertex_t *newvertarray; + unsigned int i; data >> orgVerts >> newVerts; if (orgVerts + newVerts == (DWORD)numvertexes) @@ -977,13 +975,13 @@ static void P_LoadZNodes (FileReader &dalump, DWORD id) segs = new seg_t[numsegs]; memset (segs, 0, numsegs*sizeof(seg_t)); - if (id == MAKE_ID('Z','N','O','D')) + if (glnodes == 0) { P_LoadZSegs (data); } else { - P_LoadGLZSegs (data, id); + P_LoadGLZSegs (data, glnodes); } // Read nodes @@ -1029,6 +1027,60 @@ static void P_LoadZNodes (FileReader &dalump, DWORD id) } +static void P_LoadZNodes (FileReader &dalump, DWORD id) +{ + int type; + bool compressed; + + switch (id) + { + case MAKE_ID('Z','N','O','D'): + type = 0; + compressed = true; + break; + + case MAKE_ID('Z','G','L','N'): + type = 1; + compressed = true; + break; + + case MAKE_ID('Z','G','L','2'): + type = 2; + compressed = true; + break; + + case MAKE_ID('X','N','O','D'): + type = 0; + compressed = false; + break; + + case MAKE_ID('X','G','L','N'): + type = 1; + compressed = false; + break; + + case MAKE_ID('X','G','L','2'): + type = 2; + compressed = false; + break; + + default: + return; + } + + if (compressed) + { + FileReaderZ data (dalump); + LoadZNodes(data, type); + } + else + { + LoadZNodes(dalump, type); + } +} + + + //=========================================================================== // // P_CheckV4Nodes @@ -3559,12 +3611,13 @@ void P_SetupLevel (char *lumpname, int position) { // Check for compressed nodes first, then uncompressed nodes FWadLump test; - DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0; + DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0; if (map->MapLumps[ML_ZNODES].Size != 0 && !UsingGLNodes) { map->Seek(ML_ZNODES); idcheck = MAKE_ID('Z','N','O','D'); + idcheck2 = MAKE_ID('X','N','O','D'); } else if (map->MapLumps[ML_GLZNODES].Size != 0) { @@ -3572,10 +3625,12 @@ void P_SetupLevel (char *lumpname, int position) map->Seek(ML_GLZNODES); idcheck = MAKE_ID('Z','G','L','N'); idcheck2 = MAKE_ID('Z','G','L','2'); + idcheck3 = MAKE_ID('X','G','L','N'); + idcheck4 = MAKE_ID('X','G','L','2'); } map->file->Read (&id, 4); - if (id == idcheck || id == idcheck2) + if (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4) { try { From 768bdabbb6ba5c2c52aa3197207da5595e6ecaee Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2010 20:56:41 +0000 Subject: [PATCH 016/251] - UDMF node format specification change for portability reasons. SVN r2288 (trunk) --- specs/udmf_zdoom.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 15512d9fb..7db91f302 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format ZDoom extensions v1.8 - 16.07.2009 +Universal Doom Map Format ZDoom extensions v1.9 - 17.04.2010 Copyright (c) 2008 Christoph Oelckers. @@ -38,7 +38,8 @@ between the TEXTMAP and ENDMAP lumps: BEHAVIOR = contains compiled ACS code DIALOGUE = contains compiled Strife conversation scripts. - ZNODES = Nodes (must be stored as compressed GL nodes) + ZNODES = Nodes (must be stored as extended GL nodes. Compression is allowed + but deprecated for portability reasons.) BLOCKMAP = blockmap. It is recommended not to include this lump in UDMF maps. REJECT = reject table. Recommended use is for special effects only. @@ -255,6 +256,9 @@ Added sidedef scaling properties and side specific clipmidtex and wrapmidtex. Added NoDecals sidedef option Fixed conversion specifications for TranslucentLine special. +1.9 17.04.2010 +Changed node specifications to deprecate compression of node lump. + =============================================================================== EOF =============================================================================== From 178587fff2ce2fe67c57b3ffcc94cf350500568c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 19 Apr 2010 02:46:50 +0000 Subject: [PATCH 017/251] - Merged SetState and SetStateNF into a single function. - Added new sprite #### and frame character # to specify the behavior of sprite ---- on a per-sprite and per-frame basis respectively. SVN r2291 (trunk) --- src/actor.h | 3 +- src/d_dehacked.cpp | 4 +- src/g_hexen/a_fog.cpp | 2 +- src/g_hexen/a_spike.cpp | 8 +-- src/g_raven/a_minotaur.cpp | 6 +- src/info.cpp | 4 ++ src/info.h | 28 +++++--- src/p_mobj.cpp | 117 ++++++++----------------------- src/p_pspr.cpp | 43 ++---------- src/p_pspr.h | 3 +- src/p_states.cpp | 19 +++-- src/r_main.cpp | 2 +- src/thingdef/olddecorations.cpp | 2 +- src/thingdef/thingdef_states.cpp | 2 +- wadsrc/static/actors/actor.txt | 2 +- 15 files changed, 85 insertions(+), 160 deletions(-) diff --git a/src/actor.h b/src/actor.h index ad622b3b4..243c57c90 100644 --- a/src/actor.h +++ b/src/actor.h @@ -912,8 +912,7 @@ public: void SetOrigin (fixed_t x, fixed_t y, fixed_t z); bool InStateSequence(FState * newstate, FState * basestate); int GetTics(FState * newstate); - bool SetState (FState *newstate); - bool SetStateNF (FState *newstate); + bool SetState (FState *newstate, bool nofunction=false); virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); bool isFast(); void SetIdle(); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index a1ed9262f..2578f1a60 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1354,8 +1354,8 @@ static int PatchFrame (int frameNum) } info->Tics = tics; info->Misc1 = misc1; - info->Frame = (frame & 0x3f) | - (frame & 0x8000 ? SF_FULLBRIGHT : 0); + info->Frame = frame & 0x3f; + info->Fullbright = frame & 0x8000 ? true : false; } return result; diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp index 34b1537ea..3361deb65 100644 --- a/src/g_hexen/a_fog.cpp +++ b/src/g_hexen/a_fog.cpp @@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FogMove) if (self->args[3]-- <= 0) { - self->SetStateNF (self->FindState(NAME_Death)); + self->SetState (self->FindState(NAME_Death), true); return; } diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index ea9d7c3d2..f7269c40c 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -107,9 +107,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) { // Reached it's target height actor->args[0] = 1; if (actor->args[1]) - actor->SetStateNF (actor->FindState ("BloodThrustInit2")); + actor->SetState (actor->FindState ("BloodThrustInit2"), true); else - actor->SetStateNF (actor->FindState ("ThrustInit2")); + actor->SetState (actor->FindState ("ThrustInit2"), true); } // Lose the dirt clump @@ -131,9 +131,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower) { self->args[0] = 0; if (self->args[1]) - self->SetStateNF (self->FindState ("BloodThrustInit1")); + self->SetState (self->FindState ("BloodThrustInit1"), true); else - self->SetStateNF (self->FindState ("ThrustInit1")); + self->SetState (self->FindState ("ThrustInit1"), true); } } diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 0958edb83..a614d3b41 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -192,7 +192,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) && pr_minotaurdecide() < 150) { // Charge attack // Don't call the state function right away - self->SetStateNF (self->FindState ("Charge")); + self->SetState (self->FindState ("Charge"), true); self->flags |= MF_SKULLFLY; if (!friendly) { // Heretic's Minotaur is invulnerable during charge attack @@ -524,11 +524,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) if (self->target) { - self->SetStateNF (self->SeeState); + self->SetState (self->SeeState, true); } else { - self->SetStateNF (self->FindState ("Roam")); + self->SetState (self->FindState ("Roam"), true); } } diff --git a/src/info.cpp b/src/info.cpp index 1006f2b9c..62556b1e9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -113,6 +113,10 @@ void FActorInfo::StaticInit () // Sprite 1 is always ---- memcpy (temp.name, "----", 5); sprites.Push (temp); + + // Sprite 2 is always #### + memcpy (temp.name, "####", 5); + sprites.Push (temp); } Printf ("LoadActors: Load actor definitions.\n"); diff --git a/src/info.h b/src/info.h index 034c63196..9480f5f59 100644 --- a/src/info.h +++ b/src/info.h @@ -44,20 +44,28 @@ #include "dobject.h" #include "doomdef.h" -const BYTE SF_FULLBRIGHT = 0x40; - struct Baggage; class FScanner; struct FActorInfo; class FArchive; +// Sprites that are fixed in position because they can have special meanings. +enum +{ + SPR_TNT1, // The empty sprite + SPR_FIXED, // Do not change sprite or frame + SPR_NOCHANGE, // Do not change sprite (frame change is okay) +}; + struct FState { WORD sprite; SWORD Tics; - long Misc1; // Was changed to SBYTE, reverted to long for MBF compat - long Misc2; // Was changed to BYTE, reverted to long for MBF compat - BYTE Frame; + int Misc1; // Was changed to SBYTE, reverted to long for MBF compat + int Misc2; // Was changed to BYTE, reverted to long for MBF compat + BYTE Frame:6; + BYTE Fullbright:1; // State is fullbright + BYTE SameFrame:1; // Ignore Frame (except when spawning actor) BYTE DefineFlags; // Unused byte so let's use it during state creation. short Light; FState *NextState; @@ -66,11 +74,15 @@ struct FState inline int GetFrame() const { - return Frame & ~(SF_FULLBRIGHT); + return Frame; + } + inline bool GetSameFrame() const + { + return SameFrame; } inline int GetFullbright() const { - return Frame & SF_FULLBRIGHT ? 0x10 /*RF_FULLBRIGHT*/ : 0; + return Fullbright ? 0x10 /*RF_FULLBRIGHT*/ : 0; } inline int GetTics() const { @@ -90,7 +102,7 @@ struct FState } inline void SetFrame(BYTE frame) { - Frame = (Frame & SF_FULLBRIGHT) | (frame-'A'); + Frame = frame - 'A'; } void SetAction(PSymbolActionFunction *func, bool setdefaultparams = true) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 278fd27a7..2e85dfc68 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -528,7 +528,7 @@ int AActor::GetTics(FState * newstate) // //========================================================================== -bool AActor::SetState (FState *newstate) +bool AActor::SetState (FState *newstate, bool nofunction) { if (debugfile && player && (player->cheats & CF_PREDICTING)) fprintf (debugfile, "for pl %td: SetState while predicting!\n", player-players); @@ -554,37 +554,41 @@ bool AActor::SetState (FState *newstate) tics = GetTics(newstate); renderflags = (renderflags & ~RF_FULLBRIGHT) | newstate->GetFullbright(); newsprite = newstate->sprite; - if (newsprite != 1) - { - // Sprite 1 is ----, which means "do not change the sprite" - frame = newstate->GetFrame(); - - if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite) - { // [RH] If the new sprite is the same as the original sprite, and - // this actor is attached to a player, use the player's skin's - // sprite. If a player is not attached, do not change the sprite - // unless it is different from the previous state's sprite; a - // player may have been attached, died, and respawned elsewhere, - // and we do not want to lose the skin on the body. If it wasn't - // for Dehacked, I would move sprite changing out of the states - // altogether, since actors rarely change their sprites after - // spawning. - if (player != NULL) - { - sprite = skins[player->userinfo.skin].sprite; + if (newsprite != SPR_FIXED) + { // okay to change sprite and/or frame + if (!newstate->GetSameFrame()) + { // okay to change frame + frame = newstate->GetFrame(); + } + if (newsprite != SPR_NOCHANGE) + { // okay to change sprite + if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite) + { // [RH] If the new sprite is the same as the original sprite, and + // this actor is attached to a player, use the player's skin's + // sprite. If a player is not attached, do not change the sprite + // unless it is different from the previous state's sprite; a + // player may have been attached, died, and respawned elsewhere, + // and we do not want to lose the skin on the body. If it wasn't + // for Dehacked, I would move sprite changing out of the states + // altogether, since actors rarely change their sprites after + // spawning. + if (player != NULL) + { + sprite = skins[player->userinfo.skin].sprite; + } + else if (newsprite != prevsprite) + { + sprite = newsprite; + } } - else if (newsprite != prevsprite) + else { sprite = newsprite; } } - else - { - sprite = newsprite; - } } - if (newstate->CallAction(this, this)) + if (!nofunction && newstate->CallAction(this, this)) { // Check whether the called action function resulted in destroying the actor if (ObjectFlags & OF_EuthanizeMe) @@ -600,69 +604,6 @@ bool AActor::SetState (FState *newstate) return true; } -//---------------------------------------------------------------------------- -// -// FUNC AActor::SetStateNF -// -// Same as SetState, but does not call the state function. -// -//---------------------------------------------------------------------------- - -bool AActor::SetStateNF (FState *newstate) -{ - do - { - if (newstate == NULL) - { - state = NULL; - Destroy (); - return false; - } - int prevsprite, newsprite; - - if (state != NULL) - { - prevsprite = state->sprite; - } - else - { - prevsprite = -1; - } - state = newstate; - tics = GetTics(newstate); - renderflags = (renderflags & ~RF_FULLBRIGHT) | newstate->GetFullbright(); - newsprite = newstate->sprite; - if (newsprite != 1) - { - // Sprite 1 is ----, which means "do not change the sprite" - - frame = newstate->GetFrame(); - if (!(flags4 & MF4_NOSKIN) && newsprite == SpawnState->sprite) - { - if (player != NULL && gameinfo.gametype != GAME_Hexen) - { - sprite = skins[player->userinfo.skin].sprite; - } - else if (newsprite != prevsprite) - { - sprite = newsprite; - } - } - else - { - sprite = newsprite; - } - } - newstate = newstate->GetNextState(); - } while (tics == 0); - - if (screen != NULL) - { - screen->StateChanged(this); - } - return true; -} - //============================================================================ // // AActor :: AddInventory diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index e8751c1f0..7606b43a4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -61,13 +61,12 @@ static FRandom pr_gunshot ("GunShot"); // //--------------------------------------------------------------------------- -void P_SetPsprite (player_t *player, int position, FState *state) +void P_SetPsprite (player_t *player, int position, FState *state, bool nofunction) { pspdef_t *psp; - if (position == ps_weapon) - { - // A_WeaponReady will re-set these as needed + if (position == ps_weapon && !nofunction) + { // A_WeaponReady will re-set these as needed player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK); } @@ -97,7 +96,7 @@ void P_SetPsprite (player_t *player, int position, FState *state) psp->sy = state->GetMisc2()<mo != NULL) + if (!nofunction && player->mo != NULL) { if (state->CallAction(player->mo, player->ReadyWeapon)) { @@ -112,40 +111,6 @@ void P_SetPsprite (player_t *player, int position, FState *state) } while (!psp->tics); // An initial state of 0 could cycle through. } -//--------------------------------------------------------------------------- -// -// PROC P_SetPspriteNF -// -// Identical to P_SetPsprite, without calling the action function -//--------------------------------------------------------------------------- - -void P_SetPspriteNF (player_t *player, int position, FState *state) -{ - pspdef_t *psp; - - psp = &player->psprites[position]; - do - { - if (state == NULL) - { // Object removed itself. - psp->state = NULL; - break; - } - psp->state = state; - psp->tics = state->GetTics(); // could be 0 - - if (state->GetMisc1()) - { // Set coordinates. - psp->sx = state->GetMisc1()<GetMisc2()) - { - psp->sy = state->GetMisc2()<state->GetNextState(); - } while (!psp->tics); // An initial state of 0 could cycle through. -} - //--------------------------------------------------------------------------- // // PROC P_BringUpWeapon diff --git a/src/p_pspr.h b/src/p_pspr.h index 90a57b555..99eee7883 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -79,8 +79,7 @@ class player_t; class AActor; struct FState; -void P_SetPsprite (player_t *player, int position, FState *state); -void P_SetPspriteNF (player_t *player, int position, FState *state); +void P_SetPsprite (player_t *player, int position, FState *state, bool nofunction=false); void P_CalcSwing (player_t *player); void P_BringUpWeapon (player_t *player); void P_FireWeapon (player_t *player); diff --git a/src/p_states.cpp b/src/p_states.cpp index f3a99798f..15ff37117 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -824,23 +824,28 @@ bool FStateDefinitions::SetLoop() bool FStateDefinitions::AddStates(FState *state, const char *framechars) { bool error = false; + int frame = 0; + while (*framechars) { - int frame; - - if (*framechars == '^') - frame = '\\'-'A'; + bool noframe = false; + + if (*framechars == '#') + noframe = true; + else if (*framechars == '^') + frame = '\\' - 'A'; else - frame = ((*framechars)&223)-'A'; + frame = (*framechars & 223) - 'A'; framechars++; - if (frame<0 || frame>28) + if (frame < 0 || frame > 28) { frame = 0; error = true; } - state->Frame=(state->Frame&(SF_FULLBRIGHT))|frame; + state->Frame = frame; + state->SameFrame = noframe; StateArray.Push(*state); } laststate = &StateArray[StateArray.Size() - 1]; diff --git a/src/r_main.cpp b/src/r_main.cpp index 68a017986..ebc6720dd 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1054,7 +1054,7 @@ void R_SetupFrame (AActor *actor) ((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) && (camera->RenderStyle.BlendOp != STYLEOP_None) && !(camera->renderflags & RF_INVISIBLE) && - camera->sprite != 0) // Sprite 0 is always TNT1 + camera->sprite != SPR_TNT1) { // [RH] Use chasecam view P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector); diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 5948bc55d..795cbc541 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -684,7 +684,7 @@ static void ParseSpriteFrames (FActorInfo *info, TArray &states, FScanne { sc.ScriptError ("* must come after a frame"); } - state.Frame |= SF_FULLBRIGHT; + state.Fullbright = true; } else if (*token < 'A' || *token > ']') { diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index c04193718..7e2c11259 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -244,7 +244,7 @@ do_stop: { if (sc.Compare("BRIGHT")) { - state.Frame |= SF_FULLBRIGHT; + state.Fullbright = true; continue; } if (sc.Compare("OFFSET")) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 1b8be9933..5037968e2 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -282,7 +282,7 @@ ACTOR Actor native //: Thinker Stop GenericFreezeDeath: // Generic freeze death frames. Woo! - "----" A 5 A_GenericFreezeDeath + "####" "#" 5 A_GenericFreezeDeath "----" A 1 A_FreezeDeathChunks Wait GenericCrush: From d7196715793d2f63c928cc234296c96670268594 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 20 Apr 2010 02:16:06 +0000 Subject: [PATCH 018/251] - Added levelname to drawstring. SVN r2292 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 45 ++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index ebc6dad46..71444a811 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -514,7 +514,8 @@ class CommandDrawString : public SBarInfoCommand { public: CommandDrawString(SBarInfo *script) : SBarInfoCommand(script), - shadow(false), spacing(0), font(NULL), translation(CR_UNTRANSLATED) + shadow(false), spacing(0), font(NULL), translation(CR_UNTRANSLATED), + value(CONSTANT), valueArg(0) { } @@ -531,8 +532,22 @@ class CommandDrawString : public SBarInfoCommand sc.MustGetToken(','); translation = GetTranslation(sc); sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - str = sc.String; + if(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("levelname")) + { + value = LEVELNAME; + valueArg = -1; + } + else + sc.ScriptError("Unknown string '%s'.", sc.String); + } + else + { + value = CONSTANT; + sc.MustGetToken(TK_StringConst); + str = sc.String; + } sc.MustGetToken(','); GetCoordinates(sc, fullScreenOffsets, x, y); if(sc.CheckToken(',')) //spacing @@ -547,13 +562,37 @@ class CommandDrawString : public SBarInfoCommand else //monospaced, so just multiplay the character size x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + switch(value) + { + case LEVELNAME: + if(level.lumpnum != valueArg) + { + valueArg = level.lumpnum; + str = level.LevelName; + } + break; + default: + break; + } + } protected: + enum ValueType + { + LEVELNAME, + + CONSTANT + }; + bool shadow; int spacing; FFont *font; EColorRange translation; SBarInfoCoordinate x; SBarInfoCoordinate y; + ValueType value; + int valueArg; FString str; }; From 14fc5516a840f051337ae6fb7e0a39cf0fffd8f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 20 Apr 2010 11:03:31 +0000 Subject: [PATCH 019/251] - Extended ACS's 'n' print format specifier to allow printing some other info than the player's name. It will use negative indices for this. Currently supported strings are level name, level lump name and skill name. - Extended skill definitions so that printable name and image lump name are separate fields so that a printable name can be specified for Doom, too. SVN r2294 (trunk) --- src/g_level.h | 3 ++- src/g_skill.cpp | 32 ++++++++++++++++++++++----- src/m_menu.cpp | 13 ++++++++--- src/p_acs.cpp | 33 +++++++++++++++++++++++++++- wadsrc/static/language.enu | 19 ++++++++++++++++ wadsrc/static/mapinfo/chex.txt | 5 +++++ wadsrc/static/mapinfo/doomcommon.txt | 5 +++++ wadsrc/static/mapinfo/strife.txt | 5 +++++ 8 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 58ddf9d5c..d23536383 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -538,6 +538,7 @@ enum ESkillProperty SKILLP_NoPain }; int G_SkillProperty(ESkillProperty prop); +const char * G_SkillName(); typedef TMap SkillMenuNames; @@ -558,8 +559,8 @@ struct FSkillInfo int SpawnFilter; int ACSReturn; FString MenuName; + FString PicName; SkillMenuNames MenuNamesForPlayerClass; - bool MenuNameIsLump; bool MustConfirm; FString MustConfirmText; char Shortcut; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index a91e38264..424b69a47 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -35,12 +35,14 @@ #include #include "doomstat.h" +#include "d_player.h" #include "g_level.h" #include "g_game.h" #include "gi.h" #include "templates.h" #include "v_font.h" #include "m_fixed.h" +#include "gstrings.h" TArray AllSkills; int DefaultSkill = -1; @@ -70,7 +72,6 @@ void FMapInfoParser::ParseSkill () skill.Aggressiveness = FRACUNIT; skill.SpawnFilter = 0; skill.ACSReturn = 0; - skill.MenuNameIsLump = false; skill.MustConfirm = false; skill.Shortcut = 0; skill.TextColor = ""; @@ -185,7 +186,6 @@ void FMapInfoParser::ParseSkill () ParseAssign(); sc.MustGetString (); skill.MenuName = sc.String; - skill.MenuNameIsLump = false; } else if (sc.Compare("PlayerClassName")) { @@ -200,8 +200,7 @@ void FMapInfoParser::ParseSkill () { ParseAssign(); sc.MustGetString (); - skill.MenuName = sc.String; - skill.MenuNameIsLump = true; + skill.PicName = sc.String; } else if (sc.Compare("MustConfirm")) { @@ -364,6 +363,29 @@ int G_SkillProperty(ESkillProperty prop) return 0; } +//========================================================================== +// +// +// +//========================================================================== + +const char * G_SkillName() +{ + const char *name = AllSkills[gameskill].MenuName; + + player_t *player = &players[consoleplayer]; + const char *playerclass = player->mo->GetClass()->Meta.GetMetaString(APMETA_DisplayName); + + if (playerclass != NULL) + { + FString * pmnm = AllSkills[gameskill].MenuNamesForPlayerClass.CheckKey(playerclass); + if (pmnm != NULL) name = *pmnm; + } + + if (*name == '$') name = GStrings(name+1); + return name; +} + //========================================================================== // @@ -402,8 +424,8 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) SpawnFilter = other.SpawnFilter; ACSReturn = other.ACSReturn; MenuName = other.MenuName; + PicName = other.PicName; MenuNamesForPlayerClass = other.MenuNamesForPlayerClass; - MenuNameIsLump = other.MenuNameIsLump; MustConfirm = other.MustConfirm; MustConfirmText = other.MustConfirmText; Shortcut = other.Shortcut; diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 802477a3d..dfa04cd30 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -477,9 +477,16 @@ void M_StartupSkillMenu(const char *playerclass) { FSkillInfo &skill = AllSkills[i]; - SkillSelectMenu[i].name = skill.MenuName; - SkillSelectMenu[i].fulltext = !skill.MenuNameIsLump; - SkillSelectMenu[i].alphaKey = skill.MenuNameIsLump? skill.Shortcut : tolower(SkillSelectMenu[i].name[0]); + if (skill.PicName.Len() != 0) + { + SkillSelectMenu[i].name = skill.PicName; + SkillSelectMenu[i].fulltext = false; + } + else + { + SkillSelectMenu[i].name = skill.MenuName; + SkillSelectMenu[i].fulltext = true; + } SkillSelectMenu[i].textcolor = skill.GetTextColor(); SkillSelectMenu[i].alphaKey = skill.Shortcut; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5c681a4d2..c8afb1f26 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3351,6 +3351,13 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) return 0; } +enum +{ + PRINTNAME_LEVELNAME = -1, + PRINTNAME_LEVEL = -2, + PRINTNAME_SKILL = -3, +}; + #define NEXTWORD (LittleLong(*pc++)) #define NEXTBYTE (fmt==ACS_LittleEnhanced?getbyte(pc):NEXTWORD) @@ -4804,7 +4811,31 @@ int DLevelScript::RunScript () { player_t *player = NULL; - if (STACK(1) == 0 || (unsigned)STACK(1) > MAXPLAYERS) + if (STACK(1) < 0) + { + switch (STACK(1)) + { + case PRINTNAME_LEVELNAME: + work += level.LevelName; + break; + + case PRINTNAME_LEVEL: + work += level.mapname; + break; + + case PRINTNAME_SKILL: + work += G_SkillName(); + break; + + default: + work += ' '; + break; + } + sp--; + break; + + } + else if (STACK(1) == 0 || (unsigned)STACK(1) > MAXPLAYERS) { if (activator) { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 53d74a483..2f23edc2e 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1232,6 +1232,25 @@ TXT_RANDOMGOODBYE_1 = "Bye!"; TXT_RANDOMGOODBYE_2 = "Thanks, bye!"; TXT_RANDOMGOODBYE_3 = "See you later!"; +// Skills: + +SKILL_BABY = "I'm too young to die"; +SKILL_EASY = "Hey, not too rough"; +SKILL_NORMAL = "Hurt me plenty"; +SKILL_HARD = "Ultra-Violence"; +SKILL_NIGHTMARE = "NIGHTMARE!"; + +CSKILL_BABY = "Easy does it"; +CSKILL_EASY = "Not so sticky"; +CSKILL_NORMAL = "Gobs of goo"; +CSKILL_HARD = "Extreme Ooze"; +CSKILL_NIGHTMARE = "Super Slimey!"; + +SSKILL_BABY = "Training"; +SSKILL_EASY = "Rookie"; +SSKILL_NORMAL = "Veteran"; +SSKILL_HARD = "Elite"; +SSKILL_NIGHTMARE = "Bloodbath"; // Menu MNU_NEWGAME = "NEW GAME"; diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index edfbc8a46..036d2af89 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -51,6 +51,7 @@ skill baby EasyBossBrain SpawnFilter = Baby PicName = "M_JKILL" + Name = "$CSKILL_BABY" Key = "i" } @@ -59,6 +60,7 @@ skill easy EasyBossBrain SpawnFilter = Easy PicName = "M_ROUGH" + Name = "$CSKILL_EASY" Key = "h" } @@ -66,6 +68,7 @@ skill normal { SpawnFilter = Normal PicName = "M_HURT" + Name = "$CSKILL_NORMAL" Key = "h" } @@ -73,6 +76,7 @@ skill hard { SpawnFilter = Hard PicName = "M_ULTRA" + Name = "$CSKILL_HARD" Key = "u" } @@ -85,6 +89,7 @@ skill nightmare SpawnFilter = Nightmare PicName = "M_NMARE" MustConfirm = "$CNIGHTMARE" + Name = "$CSKILL_NIGHTMARE" Key = "n" } diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 4aeee99ad..3de271756 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -50,6 +50,7 @@ skill baby EasyBossBrain SpawnFilter = Baby PicName = "M_JKILL" + Name = "$SKILL_BABY" Key = "i" } @@ -58,6 +59,7 @@ skill easy EasyBossBrain SpawnFilter = Easy PicName = "M_ROUGH" + Name = "$SKILL_EASY" Key = "h" } @@ -66,6 +68,7 @@ skill normal SpawnFilter = Normal PicName = "M_HURT" Key = "h" + Name = "$SKILL_NORMAL" DefaultSkill } @@ -73,6 +76,7 @@ skill hard { SpawnFilter = Hard PicName = "M_ULTRA" + Name = "$SKILL_HARD" Key = "u" } @@ -84,6 +88,7 @@ skill nightmare RespawnTime = 12 SpawnFilter = Nightmare PicName = "M_NMARE" + Name = "$SKILL_NIGHTMARE" MustConfirm Key = "n" } diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index 7495c860b..6c213d81e 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -52,6 +52,7 @@ skill baby EasyBossBrain SpawnFilter = Baby PicName = "M_JKILL" + Name = "$SSKILL_BABY" Key = "t" } @@ -59,6 +60,7 @@ skill easy { SpawnFilter = Easy PicName = "M_ROUGH" + Name = "$SSKILL_EASY" Key = "r" } @@ -66,6 +68,7 @@ skill normal { SpawnFilter = Normal PicName = "M_HURT" + Name = "$SSKILL_NORMAL" Key = "v" DefaultSkill } @@ -74,6 +77,7 @@ skill hard { SpawnFilter = Hard PicName = "M_ULTRA" + Name = "$SSKILL_HARD" Key = "e" } @@ -85,6 +89,7 @@ skill nightmare RespawnTime = 16 SpawnFilter = Nightmare PicName = "M_NMARE" + Name = "$SSKILL_NIGHTMARE" Key = "b" } From f6cd776e2d8ca749bfc6e413d161c1df1fce0216 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 21 Apr 2010 01:40:03 +0000 Subject: [PATCH 020/251] - Extended state sprite/frame repetition to psprites. SVN r2295 (trunk) --- src/p_pspr.cpp | 25 ++++++++++++++++++++++++- src/p_pspr.h | 3 ++- src/r_things.cpp | 12 ++++++------ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 7606b43a4..a30e2d736 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -80,6 +80,19 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio } psp->state = state; + if (state->sprite != SPR_FIXED) + { // okay to change sprite and/or frame + if (!state->GetSameFrame()) + { // okay to change frame + psp->frame = state->GetFrame(); + } + if (state->sprite != SPR_NOCHANGE) + { // okay to change sprite + psp->sprite = state->sprite; + } + } + + if (sv_fastweapons >= 2 && position == ps_weapon) psp->tics = state->ActionFunc == NULL? 0 : 1; else if (sv_fastweapons) @@ -848,5 +861,15 @@ void P_MovePsprites (player_t *player) FArchive &operator<< (FArchive &arc, pspdef_t &def) { - return arc << def.state << def.tics << def.sx << def.sy; + arc << def.state << def.tics << def.sx << def.sy; + if (SaveVersion >= 2295) + { + arc << def.sprite << def.frame; + } + else + { + def.sprite = def.state->sprite; + def.frame = def.state->Frame; + } + return arc; } diff --git a/src/p_pspr.h b/src/p_pspr.h index 99eee7883..d7011714c 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -68,7 +68,8 @@ struct pspdef_t int tics; fixed_t sx; fixed_t sy; - + int sprite; + int frame; }; class FArchive; diff --git a/src/r_things.cpp b/src/r_things.cpp index 5815ca484..1750b3095 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1530,18 +1530,18 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, fixed_t sx, fixed_ assert(pspnum >= 0 && pspnum < NUMPSPRITES); // decide which patch to use - if ( (unsigned)psp->state->sprite >= (unsigned)sprites.Size ()) + if ( (unsigned)psp->sprite >= (unsigned)sprites.Size ()) { - DPrintf ("R_DrawPSprite: invalid sprite number %i\n", psp->state->sprite); + DPrintf ("R_DrawPSprite: invalid sprite number %i\n", psp->sprite); return; } - sprdef = &sprites[psp->state->sprite]; - if (psp->state->GetFrame() >= sprdef->numframes) + sprdef = &sprites[psp->sprite]; + if (psp->frame >= sprdef->numframes) { - DPrintf ("R_DrawPSprite: invalid sprite frame %i : %i\n", psp->state->sprite, psp->state->GetFrame()); + DPrintf ("R_DrawPSprite: invalid sprite frame %i : %i\n", psp->sprite, psp->frame); return; } - sprframe = &SpriteFrames[sprdef->spriteframes + psp->state->GetFrame()]; + sprframe = &SpriteFrames[sprdef->spriteframes + psp->frame]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; From e0419dde15245e7733b36bf1f8ff8eb8685e044a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Apr 2010 06:42:48 +0000 Subject: [PATCH 021/251] - fixed: Camera textures may not be used as patch. SVN r2296 (trunk) --- src/textures/multipatchtexture.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 0e4b9bc8f..90c52dd63 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -499,6 +499,8 @@ void FMultiPatchTexture::MakeTexture () { for (int i = 0; i < NumParts; ++i) { + if (Parts[i].Texture->bHasCanvas) continue; // cannot use camera textures as patch. + BYTE *trans = Parts[i].Translation ? Parts[i].Translation->Remap : NULL; { if (Parts[i].Blend != 0) @@ -561,6 +563,8 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota for(int i = 0; i < NumParts; i++) { int ret = -1; + + if (Parts[i].Texture->bHasCanvas) continue; // cannot use camera textures as patch. // rotated multipatch parts cannot be composited directly bool rotatedmulti = Parts[i].Rotate != 0 && Parts[i].Texture->bMultiPatch; From 82af1640fdd98734288bf1f167e3046e36bc28d4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Apr 2010 17:39:52 +0000 Subject: [PATCH 022/251] - fixed: HI_START/HI_END must be checked after parsing the TEXTURES lump, not before it. SVN r2297 (trunk) --- src/textures/texture.cpp | 4 ++-- src/textures/texturemanager.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 97f393cb2..234d447c4 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -549,8 +549,8 @@ FTexture *FTexture::GetRedirect(bool wantwarped) void FTexture::SetScaledSize(int fitwidth, int fitheight) { - xScale = DivScale16(Width, fitwidth); - yScale = DivScale16(Height,fitheight); + xScale = FLOAT2FIXED(float(Width) / fitwidth); + yScale = FLOAT2FIXED(float(Height) / fitheight); // compensate for roundoff errors if (MulScale16(xScale, fitwidth) != Width) xScale++; if (MulScale16(yScale, fitheight) != Height) yScale++; diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 34e2f4ae6..e562923db 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -822,10 +822,13 @@ void FTextureManager::AddTexturesForWad(int wadnum) } } - // Seventh step: Check for hires replacements. - AddHiresTextures(wadnum); + // Check for text based texture definitions LoadTextureDefs(wadnum, "TEXTURES"); LoadTextureDefs(wadnum, "HIRESTEX"); + + // Seventh step: Check for hires replacements. + AddHiresTextures(wadnum); + SortTexturesByType(firsttexture, Textures.Size()); } From bd40bba37c5d2d80d704de8acddc299dc22723e0 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 22 Apr 2010 23:38:11 +0000 Subject: [PATCH 023/251] - Added levellump, skillname, playerclass, playername, ammo1tag, ammo2tag, weapontag, inventorytag, globalvar , and globalarray to drawstring. - String constants starting in '$' will cause drawstring to reference the language lump. - Added pushup transition for strife popups. This elulates the stats screen from hexen 2. This behaves identical to slideinbottom if the primary statusbar has fullscreenoffsets set. SVN r2299 (trunk) --- src/g_shared/sbarinfo.cpp | 136 ++++++++++++++----------- src/g_shared/sbarinfo.h | 5 + src/g_shared/sbarinfo_commands.cpp | 153 ++++++++++++++++++++++++++--- 3 files changed, 225 insertions(+), 69 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 8ec68982d..7262ba8be 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -57,6 +57,7 @@ #include "g_level.h" #include "v_palette.h" #include "p_acs.h" +#include "gstrings.h" #define ADJUST_RELCENTER(x, y, outX, outY) \ if(x.RelCenter()) \ @@ -615,6 +616,13 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(TK_IntConst); popup.speed = sc.Number; } + else if(sc.Compare("pushup")) + { + popup.transition = Popup::TRANSITION_PUSHUP; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + popup.speed = sc.Number; + } else if(sc.Compare("fade")) { popup.transition = Popup::TRANSITION_FADE; @@ -722,78 +730,79 @@ SBarInfo::~SBarInfo() } //Popup -Popup::Popup() +Popup::Popup() : transition(TRANSITION_NONE), opened(false), moving(false), + height(320), width(200), speed(0), speed2(0), alpha(FRACUNIT), x(320), + y(200), displacementX(0), displacementY(0) { - transition = TRANSITION_NONE; - height = 320; - width = 200; - speed = 0; - x = 320; - y = 200; - alpha = FRACUNIT; - opened = false; - moving = false; } void Popup::init() { x = width; y = height; - if(transition == TRANSITION_SLIDEINBOTTOM) + switch(transition) { - x = 0; - } - else if(transition == TRANSITION_FADE) - { - alpha = 0; - x = 0; - y = 0; + case TRANSITION_SLIDEINBOTTOM: + case TRANSITION_PUSHUP: + x = 0; + break; + case TRANSITION_FADE: + alpha = 0; + x = 0; + y = 0; + break; + default: + break; } } void Popup::tick() { - if(transition == TRANSITION_SLIDEINBOTTOM) + switch(transition) { - if(moving) - { - if(opened) - y -= clamp(height + (y - height), 1, speed); + case TRANSITION_SLIDEINBOTTOM: + case TRANSITION_PUSHUP: + if(moving) + { + int oldY = y; + if(opened) + y -= clamp(height + (y - height), 1, speed); + else + y += clamp(height - y, 1, speed); + if(transition == TRANSITION_PUSHUP) + displacementY += y - oldY; + } + if(y != 0 && y != height) + moving = true; else - y += clamp(height - y, 1, speed); - } - if(y != 0 && y != height) - moving = true; - else - moving = false; - } - else if(transition == TRANSITION_FADE) - { - if(moving) - { - if(opened) - alpha = clamp(alpha + speed, 0, FRACUNIT); + moving = false; + break; + case TRANSITION_FADE: + if(moving) + { + if(opened) + alpha = clamp(alpha + speed, 0, FRACUNIT); + else + alpha = clamp(alpha - speed2, 0, FRACUNIT); + } + if(alpha == 0 || alpha == FRACUNIT) + moving = false; else - alpha = clamp(alpha - speed2, 0, FRACUNIT); - } - if(alpha == 0 || alpha == FRACUNIT) + moving = true; + break; + default: + if(opened) + { + y = 0; + x = 0; + } + else + { + y = height; + x = width; + } moving = false; - else - moving = true; - } - else - { - if(opened) - { - y = 0; - x = 0; - } - else - { - y = height; - x = width; - } - moving = false; + break; } } @@ -819,6 +828,16 @@ int Popup::getAlpha(int maxAlpha) return fixed_t((a * b) * FRACUNIT); } +int Popup::getXDisplacement() +{ + return displacementX; +} + +int Popup::getYDisplacement() +{ + return displacementY; +} + void Popup::open() { opened = true; @@ -914,8 +933,13 @@ public: armor = CPlayer->mo->FindInventory(); if(hud != lastHud) script->huds[hud]->Tick(NULL, this, true); - script->huds[hud]->Draw(NULL, this, 0, 0, FRACUNIT); + + if(currentPopup != POP_None && !script->huds[hud]->FullScreenOffsets()) + script->huds[hud]->Draw(NULL, this, script->popups[currentPopup-1].getXDisplacement(), script->popups[currentPopup-1].getYDisplacement(), FRACUNIT); + else + script->huds[hud]->Draw(NULL, this, 0, 0, FRACUNIT); lastHud = hud; + if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR) && (state == HUD_StatusBar || state == HUD_Fullscreen)) { SBarInfoMainBlock *inventoryBar = state == HUD_StatusBar ? script->huds[STBAR_INVENTORY] : script->huds[STBAR_INVENTORYFULLSCREEN]; diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index 6fd7b1f0c..03aae3434 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -52,6 +52,7 @@ struct Popup { TRANSITION_NONE, TRANSITION_SLIDEINBOTTOM, + TRANSITION_PUSHUP, TRANSITION_FADE, }; @@ -65,6 +66,8 @@ struct Popup int alpha; int x; int y; + int displacementX; + int displacementY; Popup(); void init(); @@ -75,6 +78,8 @@ struct Popup int getXOffset(); int getYOffset(); int getAlpha(int maxAlpha=FRACUNIT); + int getXDisplacement(); + int getYDisplacement(); }; struct SBarInfo diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 71444a811..5123dfaac 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -515,7 +515,7 @@ class CommandDrawString : public SBarInfoCommand public: CommandDrawString(SBarInfo *script) : SBarInfoCommand(script), shadow(false), spacing(0), font(NULL), translation(CR_UNTRANSLATED), - value(CONSTANT), valueArg(0) + cache(-1), strValue(CONSTANT), valueArgument(0) { } @@ -535,18 +535,50 @@ class CommandDrawString : public SBarInfoCommand if(sc.CheckToken(TK_Identifier)) { if(sc.Compare("levelname")) + strValue = LEVELNAME; + else if(sc.Compare("levellump")) + strValue = LEVELLUMP; + else if(sc.Compare("skillname")) + strValue = SKILLNAME; + else if(sc.Compare("playerclass")) + strValue = PLAYERCLASS; + else if(sc.Compare("playername")) + strValue = PLAYERNAME; + else if(sc.Compare("ammo1tag")) + strValue = AMMO1TAG; + else if(sc.Compare("ammo2tag")) + strValue = AMMO2TAG; + else if(sc.Compare("weapontag")) + strValue = WEAPONTAG; + else if(sc.Compare("inventorytag")) + strValue = INVENTORYTAG; + else if(sc.Compare("globalvar")) { - value = LEVELNAME; - valueArg = -1; + strValue = GLOBALVAR; + sc.MustGetToken(TK_IntConst); + if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) + sc.ScriptError("Global variable number out of range: %d", sc.Number); + valueArgument = sc.Number; + } + else if(sc.Compare("globalarray")) + { + strValue = GLOBALARRAY; + sc.MustGetToken(TK_IntConst); + if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) + sc.ScriptError("Global variable number out of range: %d", sc.Number); + valueArgument = sc.Number; } else sc.ScriptError("Unknown string '%s'.", sc.String); } else { - value = CONSTANT; + strValue = CONSTANT; sc.MustGetToken(TK_StringConst); - str = sc.String; + if(sc.String[0] == '$') + str = GStrings[sc.String+1]; + else + str = sc.String; } sc.MustGetToken(','); GetCoordinates(sc, fullScreenOffsets, x, y); @@ -562,25 +594,102 @@ class CommandDrawString : public SBarInfoCommand else //monospaced, so just multiplay the character size x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); } + void Reset() + { + switch(strValue) + { + case PLAYERCLASS: + // userinfo changes before the actual class change. + case SKILLNAME: + // Although it's not possible for the skill level to change + // midlevel, it is possible the level was restarted. + cache = -1; + break; + default: + break; + } + } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { - switch(value) + switch(strValue) { case LEVELNAME: - if(level.lumpnum != valueArg) + if(level.lumpnum != cache) { - valueArg = level.lumpnum; + cache = level.lumpnum; str = level.LevelName; } break; + case LEVELLUMP: + if(level.lumpnum != cache) + { + cache = level.lumpnum; + str = level.mapname; + } + break; + case SKILLNAME: + if(level.lumpnum != cache) // Can only change skill between level. + { + cache = level.lumpnum; + str = G_SkillName(); + } + break; + case PLAYERCLASS: + if(statusBar->CPlayer->userinfo.PlayerClass != cache) + { + cache = statusBar->CPlayer->userinfo.PlayerClass; + str = statusBar->CPlayer->cls->Meta.GetMetaString(APMETA_DisplayName); + } + break; + case AMMO1TAG: + SetStringToTag(statusBar->ammo1); + break; + case AMMO2TAG: + SetStringToTag(statusBar->ammo2); + break; + case WEAPONTAG: + SetStringToTag(statusBar->CPlayer->ReadyWeapon); + break; + case INVENTORYTAG: + SetStringToTag(statusBar->CPlayer->mo->InvSel); + break; + case PLAYERNAME: + // Can't think of a good way to detect changes to this, so + // I guess copying it every tick will have to do. + str = statusBar->CPlayer->userinfo.netname; + break; + case GLOBALVAR: + if(ACS_GlobalVars[valueArgument] != cache) + { + cache = ACS_GlobalVars[valueArgument]; + str = FBehavior::StaticLookupString(ACS_GlobalVars[valueArgument]); + } + break; + case GLOBALARRAY: + if(ACS_GlobalArrays[valueArgument][consoleplayer] != cache) + { + cache = ACS_GlobalArrays[valueArgument][consoleplayer]; + str = FBehavior::StaticLookupString(ACS_GlobalArrays[valueArgument][consoleplayer]); + } + break; default: break; } } protected: - enum ValueType + enum StringValueType { LEVELNAME, + LEVELLUMP, + SKILLNAME, + PLAYERCLASS, + PLAYERNAME, + AMMO1TAG, + AMMO2TAG, + WEAPONTAG, + INVENTORYTAG, + GLOBALVAR, + GLOBALARRAY, CONSTANT }; @@ -591,9 +700,28 @@ class CommandDrawString : public SBarInfoCommand EColorRange translation; SBarInfoCoordinate x; SBarInfoCoordinate y; - ValueType value; - int valueArg; + int cache; /// General purpose cache. + StringValueType strValue; + int valueArgument; FString str; + + private: + void SetStringToTag(AActor *actor) + { + if(actor != NULL) + { + if(actor->GetClass()->ClassIndex != cache) + { + cache = actor->GetClass()->ClassIndex; + str = actor->GetTag(); + } + } + else + { + cache = -1; + str = ""; + } + } }; //////////////////////////////////////////////////////////////////////////////// @@ -604,7 +732,7 @@ class CommandDrawNumber : public CommandDrawString CommandDrawNumber(SBarInfo *script) : CommandDrawString(script), fillZeros(false), whenNotZero(false), interpolationSpeed(0), drawValue(0), length(3), lowValue(-1), lowTranslation(CR_UNTRANSLATED), highValue(-1), - highTranslation(CR_UNTRANSLATED), value(CONSTANT), valueArgument(0), + highTranslation(CR_UNTRANSLATED), value(CONSTANT), inventoryItem(NULL) { } @@ -987,7 +1115,6 @@ class CommandDrawNumber : public CommandDrawString EColorRange highTranslation; EColorRange normalTranslation; ValueType value; - int valueArgument; const PClass *inventoryItem; SBarInfoCoordinate startX; From 674c63d66c255ae5fc6f0c795ef19c327dafb2db Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Apr 2010 08:12:47 +0000 Subject: [PATCH 024/251] - fixed: A_KeenDie should not drop items. SVN r2300 (trunk) --- src/g_doom/a_keen.cpp | 2 +- src/g_doom/a_painelemental.cpp | 2 +- src/g_shared/a_action.cpp | 15 ++++--- src/g_strife/a_alienspectres.cpp | 2 +- src/p_enemy.cpp | 4 +- src/p_enemy.h | 1 + src/thingdef/thingdef_codeptr.cpp | 68 +++++++++++++++---------------- 7 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/g_doom/a_keen.cpp b/src/g_doom/a_keen.cpp index 42231a915..1504bdf38 100644 --- a/src/g_doom/a_keen.cpp +++ b/src/g_doom/a_keen.cpp @@ -15,7 +15,7 @@ // DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie) { - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, false); // scan the remaining thinkers to see if all Keens are dead AActor *other; diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index c52137919..0f4ec4741 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -162,7 +162,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainDie) self->flags &= ~MF_FRIENDLY; } const PClass *spawntype = GetSpawnType(PUSH_PARAMINFO); - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, true); A_PainShootSkull (self, self->angle + ANG90, spawntype); A_PainShootSkull (self, self->angle + ANG180, spawntype); A_PainShootSkull (self, self->angle + ANG270, spawntype); diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 571b7bf1f..3697bcba8 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -57,7 +57,7 @@ IMPLEMENT_CLASS (ASwitchingDecoration) // //---------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) +void A_Unblock(AActor *self, bool drop) { // [RH] Andy Baker's stealth monsters if (self->flags & MF_STEALTH) @@ -78,8 +78,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) self->Conversation = NULL; - // If the self has attached metadata for items to drop, drop those. - if (!self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] + // If the actor has attached metadata for items to drop, drop those. + if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { FDropItem *di = self->GetDropItems(); @@ -98,9 +98,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) } } +DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) +{ + A_Unblock(self, true); +} + DEFINE_ACTION_FUNCTION(AActor, A_Fall) { - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, true); } //========================================================================== @@ -301,7 +306,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) { CALL_ACTION(A_BossDeath, self); } - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, true); self->SetState(self->FindState(NAME_Null)); } diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp index 6506cdb1c..169889b2e 100644 --- a/src/g_strife/a_alienspectres.cpp +++ b/src/g_strife/a_alienspectres.cpp @@ -85,7 +85,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) int log; int i; - CALL_ACTION(A_NoBlocking, self); // [RH] Need this for Sigil rewarding + A_Unblock(self, true); // [RH] Need this for Sigil rewarding if (!CheckBossDeath (self)) { return; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 558533742..3701a7b91 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2784,7 +2784,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_XScream) DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) { CALL_ACTION(A_Scream, self); - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, true); } //=========================================================================== @@ -2810,7 +2810,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) DEFINE_ACTION_FUNCTION(AActor, A_ActiveAndUnblock) { CALL_ACTION(A_ActiveSound, self); - CALL_ACTION(A_NoBlocking, self); + A_Unblock(self, true); } //--------------------------------------------------------------------------- diff --git a/src/p_enemy.h b/src/p_enemy.h index ce5703e73..86261dd45 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -55,6 +55,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int special, int cha void P_TossItem (AActor *item); bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params); void A_Weave(AActor *self, int xyspeed, int zspeed, fixed_t xydist, fixed_t zdist); +void A_Unblock(AActor *self, bool drop); DECLARE_ACTION(A_Look) DECLARE_ACTION(A_Wander) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6d066684b..df4861f72 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2119,47 +2119,47 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) ACTION_PARAM_START(1); ACTION_PARAM_CLASS(chunk, 0); - int i, numChunks; - AActor * mo; + int i, numChunks; + AActor * mo; - if (chunk == NULL) return; + if (chunk == NULL) return; - self->velx = self->vely = self->velz = 0; - self->height = self->GetDefault()->height; + self->velx = self->vely = self->velz = 0; + self->height = self->GetDefault()->height; - // [RH] In Hexen, this creates a random number of shards (range [24,56]) - // with no relation to the size of the self shattering. I think it should - // base the number of shards on the size of the dead thing, so bigger - // things break up into more shards than smaller things. - // An self with radius 20 and height 64 creates ~40 chunks. - numChunks = MAX (4, (self->radius>>FRACBITS)*(self->height>>FRACBITS)/32); - i = (pr_burst.Random2()) % (numChunks/4); - for (i = MAX (24, numChunks + i); i >= 0; i--) - { - mo = Spawn(chunk, - self->x + (((pr_burst()-128)*self->radius)>>7), - self->y + (((pr_burst()-128)*self->radius)>>7), - self->z + (pr_burst()*self->height/255), ALLOW_REPLACE); + // [RH] In Hexen, this creates a random number of shards (range [24,56]) + // with no relation to the size of the self shattering. I think it should + // base the number of shards on the size of the dead thing, so bigger + // things break up into more shards than smaller things. + // An self with radius 20 and height 64 creates ~40 chunks. + numChunks = MAX (4, (self->radius>>FRACBITS)*(self->height>>FRACBITS)/32); + i = (pr_burst.Random2()) % (numChunks/4); + for (i = MAX (24, numChunks + i); i >= 0; i--) + { + mo = Spawn(chunk, + self->x + (((pr_burst()-128)*self->radius)>>7), + self->y + (((pr_burst()-128)*self->radius)>>7), + self->z + (pr_burst()*self->height/255), ALLOW_REPLACE); - if (mo) - { - mo->velz = FixedDiv(mo->z - self->z, self->height)<<2; - mo->velx = pr_burst.Random2 () << (FRACBITS-7); - mo->vely = pr_burst.Random2 () << (FRACBITS-7); - mo->RenderStyle = self->RenderStyle; - mo->alpha = self->alpha; - mo->CopyFriendliness(self, true); - } - } + if (mo) + { + mo->velz = FixedDiv(mo->z - self->z, self->height)<<2; + mo->velx = pr_burst.Random2 () << (FRACBITS-7); + mo->vely = pr_burst.Random2 () << (FRACBITS-7); + mo->RenderStyle = self->RenderStyle; + mo->alpha = self->alpha; + mo->CopyFriendliness(self, true); + } + } - // [RH] Do some stuff to make this more useful outside Hexen - if (self->flags4 & MF4_BOSSDEATH) - { + // [RH] Do some stuff to make this more useful outside Hexen + if (self->flags4 & MF4_BOSSDEATH) + { CALL_ACTION(A_BossDeath, self); - } - CALL_ACTION(A_NoBlocking, self); + } + A_Unblock(self, true); - self->Destroy (); + self->Destroy (); } //=========================================================================== From bdc5d941c238307ae1be9a42818bd1cd3b3dc6e3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Apr 2010 07:21:35 +0000 Subject: [PATCH 025/251] - added a new 'playeruseback' linedef trigger type that allows using lines from the bxck side. SVN r2302 (trunk) --- specs/udmf_zdoom.txt | 6 ++++- src/doomdata.h | 3 ++- src/namedef.h | 1 + src/p_map.cpp | 59 +++++++++++++++++++++++++++++--------------- src/p_spec.cpp | 2 +- src/p_udmf.cpp | 4 +++ 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 7db91f302..e0ec43925 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format ZDoom extensions v1.9 - 17.04.2010 +Universal Doom Map Format ZDoom extensions v1.10 - 25.04.2010 Copyright (c) 2008 Christoph Oelckers. @@ -89,6 +89,7 @@ Note: All fields default to false unless mentioned otherwise. alpha = ; // Translucency of this line, default is 1.0 renderstyle = ; // Render style, can be "translucent" or "add", // default is "translucent". + playeruseback = ; // New SPAC flag, true = player can use from back side. anycross = ; // New SPAC flag, true = any non-projectile // crossing will trigger this line monsteractivate = ; // Monsters can trigger this line. @@ -259,6 +260,9 @@ Fixed conversion specifications for TranslucentLine special. 1.9 17.04.2010 Changed node specifications to deprecate compression of node lump. +1.10 25.04.2010 +Added 'playeruseback' line trigger flag. + =============================================================================== EOF =============================================================================== diff --git a/src/doomdata.h b/src/doomdata.h index 6b3002cdb..028ae5512 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -169,8 +169,9 @@ enum SPAC SPAC_AnyCross = 1<<7, // when anything without the MF2_TELEPORT flag crosses the line SPAC_MUse = 1<<8, // monsters can use SPAC_MPush = 1<<9, // monsters can push + SPAC_UseBack = 1<<10, // Can be used from the backside - SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough), + SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack), }; enum EMapLineFlags // These are flags that use different values internally diff --git a/src/namedef.h b/src/namedef.h index a95b4b5a0..4ee1e7c0f 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -386,6 +386,7 @@ xx(Repeatspecial) xx(Playercross) xx(Playeruse) +xx(Playeruseback) xx(Monstercross) xx(Impact) xx(Playerpush) diff --git a/src/p_map.cpp b/src/p_map.cpp index 6e5807066..9ff863e2b 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3983,7 +3983,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline } FLineOpening open; - if (in->d.line->special == 0 || !(in->d.line->activation & (SPAC_Use|SPAC_UseThrough))) + if (in->d.line->special == 0 || !(in->d.line->activation & (SPAC_Use|SPAC_UseThrough|SPAC_UseBack))) { blocked: if (in->d.line->flags & (ML_BLOCKEVERYTHING|ML_BLOCKUSE)) @@ -4029,27 +4029,46 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline } if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1) - // [RH] continue traversal for two-sided lines - //return in->d.line->backsector != NULL; // don't use back side - goto blocked; // do a proper check for back sides of triggers - - P_ActivateLine (in->d.line, usething, 0, SPAC_Use); + { + if (!(in->d.line->activation & SPAC_UseBack)) + { + // [RH] continue traversal for two-sided lines + //return in->d.line->backsector != NULL; // don't use back side + goto blocked; // do a proper check for back sides of triggers + } + else + { + P_ActivateLine (in->d.line, usething, 1, SPAC_UseBack); + return true; + } + } + else + { + if ((in->d.line->activation & (SPAC_Use|SPAC_UseThrough|SPAC_UseBack)) == SPAC_UseBack) + { + goto blocked; // Line cannot be used from front side so treat it as a non-trigger line + } + + P_ActivateLine (in->d.line, usething, 0, SPAC_Use); + + //WAS can't use more than one special line in a row + //jff 3/21/98 NOW multiple use allowed with enabling line flag + //[RH] And now I've changed it again. If the line is of type + // SPAC_USE, then it eats the use. Everything else passes + // it through, including SPAC_USETHROUGH. + if (i_compatflags & COMPATF_USEBLOCKING) + { + if (in->d.line->activation & SPAC_UseThrough) continue; + else return true; + } + else + { + if (!(in->d.line->activation & SPAC_Use)) continue; + else return true; + } - //WAS can't use more than one special line in a row - //jff 3/21/98 NOW multiple use allowed with enabling line flag - //[RH] And now I've changed it again. If the line is of type - // SPAC_USE, then it eats the use. Everything else passes - // it through, including SPAC_USETHROUGH. - if (i_compatflags & COMPATF_USEBLOCKING) - { - if (in->d.line->activation & SPAC_UseThrough) continue; - else return true; - } - else - { - if (!(in->d.line->activation & SPAC_Use)) continue; - else return true; } + } return false; } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 9f634ab56..eb42ef61a 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -294,7 +294,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType) { lineActivation |= SPAC_Cross|SPAC_MCross; } - if (activationType == SPAC_Use) + if (activationType ==SPAC_Use || activationType == SPAC_UseBack) { if (!P_CheckSwitchRange(mo, line, side)) { diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 5dfa06dd7..33fb027a7 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -721,6 +721,10 @@ struct UDMFParser Flag(ld->activation, SPAC_Use, key); continue; + case NAME_Playeruseback: + Flag(ld->activation, SPAC_UseBack, key); + continue; + case NAME_Monstercross: Flag(ld->activation, SPAC_MCross, key); continue; From 5fc654dac29c7243ca01c1478be7c87f128c18b8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Apr 2010 20:12:50 +0000 Subject: [PATCH 026/251] - fixed: Heretic's sludge damage sector does 4 points damage, not 5 like Doom's. SVN r2303 (trunk) --- src/p_lnspec.h | 1 + src/p_spec.cpp | 5 +++++ wadsrc/static/xlat/defines.i | 1 + wadsrc/static/xlat/heretic.txt | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 2f5a67810..f0942c4fd 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -104,6 +104,7 @@ typedef enum { dDamage_LavaWimpy = 82, dDamage_LavaHefty = 83, dScroll_EastLavaDamage = 84, + hDamage_Sludge = 85, Sector_Outside = 87, // And here are some for Strife diff --git a/src/p_spec.cpp b/src/p_spec.cpp index eb42ef61a..915d4a508 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -452,6 +452,11 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); break; + case hDamage_Sludge: + if (ironfeet == NULL && !(level.time&0x1f)) + P_DamageMobj (player->mo, NULL, NULL, 4, NAME_Slime); + break; + case dDamage_SuperHellslime: // SUPER HELLSLIME DAMAGE case dLight_Strobe_Hurt: diff --git a/wadsrc/static/xlat/defines.i b/wadsrc/static/xlat/defines.i index 648679894..b72641d30 100644 --- a/wadsrc/static/xlat/defines.i +++ b/wadsrc/static/xlat/defines.i @@ -135,6 +135,7 @@ enum dDamage_LavaWimpy = 82, dDamage_LavaHefty = 83, dScroll_EastLavaDamage = 84, + hDamage_Sludge = 85, Sector_Outside = 87, // And here are some for Strife diff --git a/wadsrc/static/xlat/heretic.txt b/wadsrc/static/xlat/heretic.txt index da4d103a5..8a2b696bc 100644 --- a/wadsrc/static/xlat/heretic.txt +++ b/wadsrc/static/xlat/heretic.txt @@ -18,7 +18,7 @@ sector 2 = dLight_StrobeFast; sector 3 = dLight_StrobeSlow; sector 4 = dScroll_EastLavaDamage; sector 5 = dDamage_LavaWimpy; -sector 7 = dDamage_Nukage; +sector 7 = hDamage_Sludge; sector 8 = dLight_Glow; sector 9 = SECRET_MASK nobitmask; sector 10 = dSector_DoorCloseIn30; From 4e693e1c98bfe29a7c1c9fab9af0e1e3a08af61b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 26 Apr 2010 01:49:29 +0000 Subject: [PATCH 027/251] - Added Gez's RandomSpawner patch: If a randomspawner is given a Z-height in the map editor, and the spawned object has a spawn height flag, it is ignored by the spawned object. This little patch fixes that. SVN r2304 (trunk) --- src/g_shared/a_randomspawner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index e62128ec4..67bd4b84a 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -114,6 +114,7 @@ class ARandomSpawner : public AActor { // copy everything relevant newmobj->SpawnAngle = newmobj->angle = angle; + newmobj->SpawnPoint[2] = SpawnPoint[2]; newmobj->special = special; newmobj->args[0] = args[0]; newmobj->args[1] = args[1]; @@ -137,10 +138,10 @@ class ARandomSpawner : public AActor // a health set to -2 after spawning, for internal reasons. if (health != SpawnHealth()) newmobj->health = health; if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED; - // Handle special altitude flags + // Handle special altitude flags if (newmobj->flags & MF_SPAWNCEILING) { - newmobj->z = newmobj->ceilingz - newmobj->height; + newmobj->z = newmobj->ceilingz - newmobj->height - SpawnPoint[2]; } else if (newmobj->flags2 & MF2_SPAWNFLOAT) { @@ -150,6 +151,7 @@ class ARandomSpawner : public AActor space -= 40*FRACUNIT; newmobj->z = MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT; } + newmobj->z += SpawnPoint[2]; } if (newmobj->flags & MF_MISSILE) P_CheckMissileSpawn(newmobj); From 36c4b396885e154ad7cf3c817306b2f84667316a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 26 Apr 2010 01:56:25 +0000 Subject: [PATCH 028/251] - Added DavidPH's A_FadeTo patch: A_FadeTo(float target, float amount = 0.10, bool remove = false) Alters transparency towards target by amount. If remove is true, the actor is destroyed if it reaches target. SVN r2305 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 60 +++++++++++++++++++++++++++---- wadsrc/static/actors/actor.txt | 1 + 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index df4861f72..7d22f11d7 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1810,11 +1810,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) ACTION_PARAM_START(1); ACTION_PARAM_FIXED(reduce, 0); - if (reduce == 0) reduce = FRACUNIT/10; - + if (reduce == 0) + { + reduce = FRACUNIT/10; + } self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha += reduce; - //if (self->alpha<=0) self->Destroy(); + // Should this clamp alpha to 1.0? } //=========================================================================== @@ -1830,11 +1832,57 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) ACTION_PARAM_FIXED(reduce, 0); ACTION_PARAM_BOOL(remove, 1); - if (reduce == 0) reduce = FRACUNIT/10; - + if (reduce == 0) + { + reduce = FRACUNIT/10; + } self->RenderStyle.Flags &= ~STYLEF_Alpha1; self->alpha -= reduce; - if (self->alpha<=0 && remove) self->Destroy(); + if (self->alpha <= 0 && remove) + { + self->Destroy(); + } +} + +//=========================================================================== +// +// A_FadeTo +// +// fades the actor to a specified transparency by a specified amount and +// destroys it if so desired +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) +{ + ACTION_PARAM_START(3); + ACTION_PARAM_FIXED(target, 0); + ACTION_PARAM_FIXED(amount, 1); + ACTION_PARAM_BOOL(remove, 2); + + self->RenderStyle.Flags &= ~STYLEF_Alpha1; + + if (self->alpha > target) + { + self->alpha -= amount; + + if (self->alpha < target) + { + self->alpha = target; + } + } + else if (self->alpha < target) + { + self->alpha += amount; + + if (self->alpha > target) + { + self->alpha = target; + } + } + if (self->alpha == target && remove) + { + self->Destroy(); + } } //=========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5037968e2..50d7369d2 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -201,6 +201,7 @@ ACTOR Actor native //: Thinker action native A_SetTranslucent(float alpha, int style = 0); action native A_FadeIn(float reduce = 0.1); action native A_FadeOut(float reduce = 0.1, bool remove = true); + action native A_FadeTo(float target, float amount = 0.1, bool remove = false); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); action native A_CheckSight(state label); action native A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); From d070e04ff61e7a388eab3ca4508668d92fe3c7af Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 26 Apr 2010 02:05:11 +0000 Subject: [PATCH 029/251] - Added Gez's patch for A_TakeInventory flag for taking ammo, with TIF_AMMO renamed to TIF_NOTAKEINFINITE. SVN r2306 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 18 ++++++++++++++++-- wadsrc/static/actors/actor.txt | 4 ++-- wadsrc/static/actors/constants.txt | 3 +++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7d22f11d7..8b09a2c10 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1314,11 +1314,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) // //=========================================================================== +enum +{ + TIF_NOTAKEINFINITE = 1, +}; + void DoTakeInventory(AActor * receiver, DECLARE_PARAMINFO) { - ACTION_PARAM_START(2); + ACTION_PARAM_START(3); ACTION_PARAM_CLASS(item, 0); ACTION_PARAM_INT(amount, 1); + ACTION_PARAM_INT(flags, 2); if (item == NULL || receiver == NULL) return; @@ -1332,7 +1338,15 @@ void DoTakeInventory(AActor * receiver, DECLARE_PARAMINFO) { res = true; } - if (!amount || amount>=inv->Amount) + // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set + // and infinite ammo is on + if (flags & TIF_NOTAKEINFINITE && + ((dmflags & DF_INFINITE_AMMO) || (receiver->player->cheats & CF_INFINITEAMMO)) && + inv->IsKindOf(RUNTIME_CLASS(AAmmo))) + { + // Nothing to do here, except maybe res = false;? Would it make sense? + } + else if (!amount || amount>=inv->Amount) { if (inv->ItemFlags&IF_KEEPDEPLETED) inv->Amount=0; else inv->Destroy(); diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 50d7369d2..1b9719463 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -191,7 +191,7 @@ ACTOR Actor native //: Thinker action native A_JumpIfInventory(class itemtype, int itemamount, state label); action native A_JumpIfArmorType(string Type, state label, int amount = 1); action native A_GiveInventory(class itemtype, int amount = 0); - action native A_TakeInventory(class itemtype, int amount = 0); + action native A_TakeInventory(class itemtype, int amount = 0, int flags = 0); action native A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); action native A_SpawnItemEx(class itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0); action native A_Print(string whattoprint, float time = 0, string fontname = ""); @@ -228,7 +228,7 @@ ACTOR Actor native //: Thinker action native A_Recoil(float xyvel); action native A_JumpIfInTargetInventory(class itemtype, int amount, state label); action native A_GiveToTarget(class itemtype, int amount = 0); - action native A_TakeFromTarget(class itemtype, int amount = 0); + action native A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0); action native A_CountdownArg(int argnum, state targstate = ""); action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); action native A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 0fd613a72..71fb3d511 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -105,6 +105,9 @@ const int AF_ClearSpecial = 32; const int AF_NoDeathSpecial = 64; const int AF_TriggerActs = 128; +// Flags for A_TakeInventory and A_TakeFromTarget +const int TIF_NOTAKEINFINITE = 1; + // constants for A_PlaySound enum { From 1b0756e170f7c75b4846c49e4cdc3d9343d0e497 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 May 2010 17:29:25 +0000 Subject: [PATCH 030/251] - added a am_showalllines cheat CVAR as countermeasure for maps that intentionally disable the full automap. SVN r2307 (trunk) --- src/am_map.cpp | 58 ++++++++++++++++++++++++++++++++++++++++--- src/b_bot.cpp | 2 -- src/c_cmds.cpp | 4 +-- src/c_dispatch.h | 2 ++ src/d_main.cpp | 1 - src/info.cpp | 1 - src/m_cheat.cpp | 1 - src/p_interaction.cpp | 1 - src/st_stuff.cpp | 1 - 9 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 28739c856..62af8ed67 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -177,6 +177,45 @@ CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); +// Disable the ML_DONTDRAW line flag if x% of all lines in a map are flagged with it +// (To counter annoying mappers who think they are smart by making the automap unusable) +bool am_showallenabled; + +CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it. +{ + int flagged = 0; + int total = 0; + if (self > 0) + { + for(int i=0;ifrontsector == line->backsector) continue; + + // disregard control sectors for deep water + if (line->frontsector->e->FakeFloor.Sectors.Size() > 0) continue; + + // disregard control sectors for 3D-floors + if (line->frontsector->e->XFloor.attached.Size() > 0) continue; + + total++; + if (line->flags & ML_DONTDRAW) flagged++; + } + am_showallenabled = (flagged * 100 / total >= self); + } + else if (self == 0) + { + am_showallenabled = true; + } + else + { + am_showallenabled = false; + } +} + + // drawing stuff #define AM_PANDOWNKEY KEY_DOWNARROW #define AM_PANUPKEY KEY_UPARROW @@ -946,6 +985,8 @@ void AM_LevelInit () if (scale_mtof > max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = MapDiv(MAPUNIT, scale_mtof); + + am_showalllines.Callback(); } //============================================================================= @@ -1601,7 +1642,12 @@ void AM_drawWalls (bool allmap) if (am_cheat != 0 || (lines[i].flags & ML_MAPPED)) { if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0) - continue; + { + if (!am_showallenabled || CheckCheatmode(false)) + { + continue; + } + } if (AM_CheckSecret(&lines[i])) { @@ -1680,8 +1726,14 @@ void AM_drawWalls (bool allmap) } else if (allmap) { - if (!(lines[i].flags & ML_DONTDRAW)) - AM_drawMline(&l, NotSeenColor); + if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0) + { + if (!am_showallenabled || CheckCheatmode(false)) + { + continue; + } + } + AM_drawMline(&l, NotSeenColor); } } } diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 3911264cd..cee4086ae 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -67,8 +67,6 @@ CCMD (removebots) Net_WriteByte (DEM_KILLBOTS); } -extern bool CheckCheatmode (); - CCMD (freeze) { if (CheckCheatmode ()) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 0567427cf..6d21a7922 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -80,11 +80,11 @@ CCMD (toggleconsole) C_ToggleConsole(); } -bool CheckCheatmode () +bool CheckCheatmode (bool printmsg) { if ((G_SkillProperty(SKILLP_DisableCheats) || netgame || deathmatch) && (!sv_cheats)) { - Printf ("sv_cheats must be true to enable this command.\n"); + if (printmsg) Printf ("sv_cheats must be true to enable this command.\n"); return true; } else diff --git a/src/c_dispatch.h b/src/c_dispatch.h index fb76f1aee..a19352d32 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -39,6 +39,8 @@ class FConfigFile; class APlayerPawn; +extern bool CheckCheatmode (bool printmsg = true); + void C_ExecCmdLineParams (); // Add commands to the console as if they were typed in. Can handle wait diff --git a/src/d_main.cpp b/src/d_main.cpp index 61e76da0d..65973e3c8 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -120,7 +120,6 @@ extern void M_SetDefaultMode (); extern void R_ExecuteSetViewSize (); extern void G_NewInit (); extern void SetupPlayerClasses (); -extern bool CheckCheatmode (); const IWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- diff --git a/src/info.cpp b/src/info.cpp index 62556b1e9..1b49ce7dd 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -454,7 +454,6 @@ CCMD (dumpmapthings) FDoomEdMap::DumpMapThings (); } -bool CheckCheatmode (); static void SummonActor (int command, int command2, FCommandLine argv) { diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index a79ca3ad7..45175c50a 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -1062,7 +1062,6 @@ void cht_Suicide (player_t *plyr) } } -bool CheckCheatmode (); CCMD (mdk) { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 6cdf86ab5..7dfd7398f 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1539,7 +1539,6 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, return; } -bool CheckCheatmode (); CCMD (kill) { diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index 59b65ef85..08e6f0be4 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -293,7 +293,6 @@ static cheatseq_t SpecialCheats[] = }; -extern bool CheckCheatmode (); CVAR(Bool, allcheats, false, CVAR_ARCHIVE) From 80f5a58e3419ccf4ec2e988f489cfd66acc2f17c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 May 2010 20:34:28 +0000 Subject: [PATCH 031/251] - fix automap cheat to avoid division by 0. SVN r2308 (trunk) --- src/am_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 62af8ed67..9987876a9 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -185,7 +185,7 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it. { int flagged = 0; int total = 0; - if (self > 0) + if (self > 0 && numlines > 0) { for(int i=0;i Date: Sat, 1 May 2010 21:17:11 +0000 Subject: [PATCH 032/251] - Fixed: If a weapon didn't use ammo the result of weaponammo was accidentally negated. SVN r2309 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 5123dfaac..6e9c71146 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2558,7 +2558,7 @@ class CommandWeaponAmmo : public SBarInfoCommandFlowControl const PClass *AmmoType2 = statusBar->CPlayer->ReadyWeapon->AmmoType2; bool usesammo1 = (AmmoType1 != NULL); bool usesammo2 = (AmmoType2 != NULL); - if(!negate && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. + if(negate && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. { SBarInfoCommandFlowControl::Draw(block, statusBar); return; From 5a4be4b62b4882f613f588e1281d7fca8c66d00d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 6 May 2010 20:32:03 +0000 Subject: [PATCH 033/251] - Added partial support for a signal based timer under Linux/Mac OS X in order to make cl_capfps effective at limiting CPU usage. SVN r2310 (trunk) --- src/CMakeLists.txt | 7 +++ src/sdl/i_system.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2a556629..8b81095f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -375,6 +375,13 @@ if( NOT STRNICMP_EXISTS ) add_definitions( -Dstrnicmp=strncasecmp ) endif( NOT STRNICMP_EXISTS ) +if( NOT WIN32 ) + CHECK_FUNCTION_EXISTS( sigtimedwait SIGTIMEDWAIT_EXISTS ) + if( SIGTIMEDWAIT_EXISTS ) + add_definitions( -DHAVE_SIGTIMEDWAIT ) + endif( SIGTIMEDWAIT_EXISTS ) +endif( NOT WIN32) + if( NOT MSVC ) add_definitions( -D__forceinline=inline ) endif( NOT MSVC ) diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 931b8a37d..4ed1131cb 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #ifndef NO_GTK #include #include @@ -117,6 +118,16 @@ static DWORD TicNext; static DWORD BaseTime; static int TicFrozen; +// Signal based timer. +static struct timespec SignalTimeOut = { 0, 1000000/TICRATE }; +#ifdef HAVE_SIGTIMEDWAIT +static sigset_t SignalWaitSet; +#endif +static int tics; +static DWORD sig_start, sig_next; + +void I_SelectTimer(); + // [RH] Returns time in milliseconds unsigned int I_MSTime (void) { @@ -134,6 +145,12 @@ unsigned int I_FPSTime() // I_GetTime // returns time in 1/35th second tics // +int I_GetTimeSelect (bool saveMS) +{ + I_SelectTimer(); + return I_GetTime (saveMS); +} + int I_GetTimePolled (bool saveMS) { if (TicFrozen != 0) @@ -151,6 +168,21 @@ int I_GetTimePolled (bool saveMS) return Scale(tm - BaseTime, TICRATE, 1000); } +int I_GetTimeSignaled (bool saveMS) +{ + if (TicFrozen != 0) + { + return TicFrozen; + } + + if (saveMS) + { + TicStart = sig_start; + TicNext = sig_next; + } + return tics; +} + int I_WaitForTicPolled (int prevtic) { int time; @@ -162,6 +194,27 @@ int I_WaitForTicPolled (int prevtic) return time; } +int I_WaitForTicSignaled (int prevtic) +{ + assert (TicFrozen == 0); + +#ifdef HAVE_SIGTIMEDWAIT + while(sigtimedwait(&SignalWaitSet, NULL, &SignalTimeOut) == -1 && errno == EINTR) + ; +#else + while(nanosleep(&SignalTimeOut, NULL) == -1 && errno == EINTR) + ; +#endif + + return I_GetTimePolled(false); +} + +void I_FreezeTimeSelect (bool frozen) +{ + I_SelectTimer(); + return I_FreezeTime (frozen); +} + void I_FreezeTimePolled (bool frozen) { if (frozen) @@ -179,6 +232,75 @@ void I_FreezeTimePolled (bool frozen) } } +void I_FreezeTimeSignaled (bool frozen) +{ + TicFrozen = frozen; +} + +int I_WaitForTicSelect (int prevtic) +{ + I_SelectTimer(); + return I_WaitForTic (prevtic); +} + +// +// I_HandleAlarm +// Should be called every time there is an alarm. +// +void I_HandleAlarm (int sig) +{ + if(!TicFrozen) + tics++; + sig_start = SDL_GetTicks(); + sig_next = Scale((Scale (sig_start, TICRATE, 1000) + 1), 1000, TICRATE); +} + +// +// I_SelectTimer +// Sets up the timer function based on if we can use signals for efficent CPU +// usage. +// +void I_SelectTimer() +{ + struct sigaction act; + struct itimerval itv; + + sigfillset (&act.sa_mask); + act.sa_flags = 0; + // [BL] This doesn't seem to be executed consistantly, I'm guessing the + // sleep functions are taking over the signal. So for now, lets just + // attach WaitForTic to signals in order to reduce CPU usage. + //act.sa_handler = I_HandleAlarm; + act.sa_handler = SIG_IGN; + + sigaction (SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = itv.it_value.tv_sec = 0; + itv.it_interval.tv_usec = itv.it_value.tv_usec = 1000000/TICRATE; + + // [BL] See above. + I_GetTime = I_GetTimePolled; + I_FreezeTime = I_FreezeTimePolled; + + if (setitimer(ITIMER_REAL, &itv, NULL) != 0) + { + //I_GetTime = I_GetTimePolled; + //I_FreezeTime = I_FreezeTimePolled; + I_WaitForTic = I_WaitForTicPolled; + } + else + { +#ifdef HAVE_SIGTIMEDWAIT + sigemptyset(&SignalWaitSet); + sigaddset(&SignalWaitSet, SIGALRM); +#endif + + //I_GetTime = I_GetTimeSignaled; + //I_FreezeTime = I_FreezeTimeSignaled; + I_WaitForTic = I_WaitForTicSignaled; + } +} + // Returns the fractional amount of a tic passed since the most recent tic fixed_t I_GetTimeFrac (uint32 *ms) { @@ -218,9 +340,9 @@ void I_Init (void) CheckCPUID (&CPU); DumpCPUInfo (&CPU); - I_GetTime = I_GetTimePolled; - I_WaitForTic = I_WaitForTicPolled; - I_FreezeTime = I_FreezeTimePolled; + I_GetTime = I_GetTimeSelect; + I_WaitForTic = I_WaitForTicSelect; + I_FreezeTime = I_FreezeTimeSelect; atterm (I_ShutdownSound); I_InitSound (); } From ac7c93ba5887057bf7563c51c34e4a0d9ad5c34e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 7 May 2010 08:19:12 +0000 Subject: [PATCH 034/251] Fixed: actor VolcanoBlast was missing its second frame from its Spawn state sequence. SVN r2311 (trunk) --- wadsrc/static/actors/heretic/hereticmisc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/heretic/hereticmisc.txt b/wadsrc/static/actors/heretic/hereticmisc.txt index b41a2d4f7..b6644e444 100644 --- a/wadsrc/static/actors/heretic/hereticmisc.txt +++ b/wadsrc/static/actors/heretic/hereticmisc.txt @@ -204,7 +204,7 @@ ACTOR VolcanoBlast States { Spawn: - VFBL A 4 BRIGHT A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, + VFBL AB 4 BRIGHT A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, 0,0,0,0,SXF_ABSOLUTEPOSITION, 64) Loop From 72f7e40145070877f6e40e7ea46bd54805abb789 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 May 2010 17:30:27 +0000 Subject: [PATCH 035/251] - fixed: Heretic's splashes don't alert monsters. SVN r2312 (trunk) --- wadsrc/static/terrain.txt | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/wadsrc/static/terrain.txt b/wadsrc/static/terrain.txt index 9a38a3d97..f1bfa6f4a 100644 --- a/wadsrc/static/terrain.txt +++ b/wadsrc/static/terrain.txt @@ -54,6 +54,58 @@ splash WaterSound noalert } +ifheretic + +splash Water +{ + smallclass WaterSplashBase + smallclip 12 + smallsound world/drip + + baseclass WaterSplashBase + chunkclass WaterSplash + chunkxvelshift 8 + chunkyvelshift 8 + chunkzvelshift 8 + chunkbasezvel 2 + sound world/watersplash + noalert +} + +splash Sludge +{ + smallclass SludgeSplash + smallclip 12 + smallsound world/sludgegloop + + baseclass SludgeSplash + chunkclass SludgeChunk + chunkxvelshift 8 + chunkyvelshift 8 + chunkzvelshift 8 + chunkbasezvel 1 + sound world/sludgegloop + noalert +} + +splash Lava +{ + smallclass LavaSplash + smallclip 12 + smallsound world/lavasizzle + + baseclass LavaSplash + chunkclass LavaSmoke + chunkxvelshift -1 + chunkyvelshift -1 + chunkzvelshift 7 + chunkbasezvel 1 + sound world/lavasizzle + noalert +} + +endif + // Terrain types ----------------------------------------------------------- terrain Water From 24aa1abf145c3c1006db11dfa418bab68f68b606 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 11 May 2010 22:27:50 +0000 Subject: [PATCH 036/251] - Added: else statements to SBarInfo. In addition braces are no longer required for blocks consisting of a single statement. SVN r2313 (trunk) --- src/g_shared/sbarinfo.cpp | 76 +++++-- src/g_shared/sbarinfo_commands.cpp | 320 +++++++++++++++++------------ wadsrc/static/sbarinfo/doom.txt | 7 +- 3 files changed, 246 insertions(+), 157 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 7262ba8be..9e424c098 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -214,44 +214,89 @@ class SBarInfoCommand class SBarInfoCommandFlowControl : public SBarInfoCommand { public: - SBarInfoCommandFlowControl(SBarInfo *script) : SBarInfoCommand(script) {} + SBarInfoCommandFlowControl(SBarInfo *script) : SBarInfoCommand(script), truth(false) {} ~SBarInfoCommandFlowControl() { - for(unsigned int i = 0;i < commands.Size();i++) - delete commands[i]; + for(unsigned int i = 0;i < 2;i++) + { + for(unsigned int j = 0;j < commands[i].Size();j++) + delete commands[i][j]; + } } void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - for(unsigned int i = 0;i < commands.Size();i++) - commands[i]->Draw(block, statusBar); + for(unsigned int i = 0;i < commands[truth].Size();i++) + commands[truth][i]->Draw(block, statusBar); } - int NumCommands() const { return commands.Size(); } + int NumCommands() const { return commands[truth].Size(); } void Parse(FScanner &sc, bool fullScreenOffsets) { - sc.MustGetToken('{'); + bool elseBlock = false; SBarInfoCommand *cmd = NULL; - while((cmd = NextCommand(sc)) != NULL) + // Should loop no more than twice. + while(true) { - cmd->Parse(sc, fullScreenOffsets); - commands.Push(cmd); + if(sc.CheckToken('{')) + { + while((cmd = NextCommand(sc)) != NULL) + { + cmd->Parse(sc, fullScreenOffsets); + commands[!elseBlock].Push(cmd); + } + } + else + { + if((cmd = NextCommand(sc)) != NULL) + { + cmd->Parse(sc, fullScreenOffsets); + commands[!elseBlock].Push(cmd); + } + else + sc.ScriptError("Missing command for flow control statement."); + } + + if(!elseBlock && sc.CheckToken(TK_Else)) + { + elseBlock = true; + continue; + } + break; } } void Reset() { - for(unsigned int i = 0;i < commands.Size();i++) - commands[i]->Reset(); + for(unsigned int i = 0;i < 2;i++) + { + for(unsigned int j = 0;j < commands[i].Size();j++) + commands[i][j]->Reset(); + } } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { - for(unsigned int i = 0;i < commands.Size();i++) - commands[i]->Tick(block, statusBar, hudChanged); + for(unsigned int i = 0;i < commands[truth].Size();i++) + commands[truth][i]->Tick(block, statusBar, hudChanged); + } + + protected: + void SetTruth(bool truth, const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + // If there is no change we don't need to do anything. Do note + // that this should not change more than once per tick. If it does + // there may be cosmetic problems. + if(this->truth == truth) + return; + + this->truth = truth; + if(block != NULL) + Tick(block, statusBar, true); } private: SBarInfoCommand *NextCommand(FScanner &sc); - TArray commands; + bool truth; + TArray commands[2]; }; class SBarInfoMainBlock : public SBarInfoCommandFlowControl @@ -260,6 +305,7 @@ class SBarInfoMainBlock : public SBarInfoCommandFlowControl SBarInfoMainBlock(SBarInfo *script) : SBarInfoCommandFlowControl(script), alpha(FRACUNIT), forceScaled(false), fullScreenOffsets(false) { + SetTruth(true, NULL, NULL); } int Alpha() const { return alpha; } diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 6e9c71146..6d8982c40 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1210,7 +1210,8 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private if(alwaysShowCounter || statusBar->CPlayer->mo->InvSel->Amount != 1) CommandDrawNumber::Draw(block, statusBar); } - else if(alternateOnEmpty) + + if(alternateOnEmpty) SBarInfoCommandFlowControl::Draw(block, statusBar); } void Parse(FScanner &sc, bool fullScreenOffsets) @@ -1267,9 +1268,13 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + if(artiflashTick > 0) artiflashTick--; - + + SetTruth(statusBar->CPlayer->mo->InvSel == NULL || (level.flags & LEVEL_NOINVENTORYBAR), block, statusBar); + CommandDrawImage::Tick(block, statusBar, hudChanged); CommandDrawNumber::Tick(block, statusBar, hudChanged); } @@ -1299,16 +1304,6 @@ class CommandGameMode : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if((!multiplayer && (modes & SINGLEPLAYER)) || - (deathmatch && (modes & DEATHMATCH)) || - (multiplayer && !deathmatch && (modes & COOPERATIVE)) || - (teamplay && (modes & TEAMGAME))) - { - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - } void Parse(FScanner &sc, bool fullScreenOffsets) { do @@ -1319,6 +1314,15 @@ class CommandGameMode : public SBarInfoCommandFlowControl while(sc.CheckToken(',')); SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + SetTruth((!multiplayer && (modes & SINGLEPLAYER)) || + (deathmatch && (modes & DEATHMATCH)) || + (multiplayer && !deathmatch && (modes & COOPERATIVE)) || + (teamplay && (modes & TEAMGAME)), block, statusBar); + } protected: static const char* const modeNames[]; enum GameModes @@ -1351,11 +1355,6 @@ class CommandUsesAmmo : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if((statusBar->CPlayer->ReadyWeapon != NULL && (statusBar->CPlayer->ReadyWeapon->AmmoType1 != NULL || statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL)) ^ negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } void Parse(FScanner &sc, bool fullScreenOffsets) { if(sc.CheckToken(TK_Identifier)) @@ -1367,6 +1366,12 @@ class CommandUsesAmmo : public SBarInfoCommandFlowControl } SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + SetTruth((statusBar->CPlayer->ReadyWeapon != NULL && (statusBar->CPlayer->ReadyWeapon->AmmoType1 != NULL || statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL)) ^ negate, block, statusBar); + } protected: bool negate; }; @@ -1380,10 +1385,11 @@ class CommandUsesSecondaryAmmo : public CommandUsesAmmo { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { - if((statusBar->CPlayer->ReadyWeapon != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType1 != statusBar->CPlayer->ReadyWeapon->AmmoType2) ^ negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + SetTruth((statusBar->CPlayer->ReadyWeapon != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType1 != statusBar->CPlayer->ReadyWeapon->AmmoType2) ^ negate, block, statusBar); } }; @@ -1396,10 +1402,11 @@ class CommandInventoryBarNotVisible : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { - if(statusBar->CPlayer->inventorytics <= 0 || (level.flags & LEVEL_NOINVENTORYBAR)) - SBarInfoCommandFlowControl::Draw(block, statusBar); + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + SetTruth(statusBar->CPlayer->inventorytics <= 0 || (level.flags & LEVEL_NOINVENTORYBAR), block, statusBar); } }; @@ -1413,11 +1420,6 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == ratio) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } void Parse(FScanner &sc, bool fullScreenOffsets) { sc.MustGetToken(TK_StringConst); @@ -1433,6 +1435,10 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl sc.ScriptError("Unkown aspect ratio: %s", sc.String); SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SetTruth(CheckRatio(screen->GetWidth(), screen->GetHeight()) == ratio, block, statusBar); + } protected: enum Ratio { @@ -2263,21 +2269,6 @@ class CommandIsSelected : public SBarInfoCommandFlowControl weapon[1] = NULL; } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if(statusBar->CPlayer->ReadyWeapon != NULL) - { - const PClass *readyWeapon = statusBar->CPlayer->ReadyWeapon->GetClass(); - if(((weapon[1] != NULL) && - ((negate && (weapon[0] != readyWeapon && weapon[1] != readyWeapon)) || - (!negate && (weapon[0] == readyWeapon || weapon[1] == readyWeapon)))) || - ((weapon[1] == NULL) && - ((!negate && weapon[0] == readyWeapon) || (negate && weapon[0] != readyWeapon)))) - { - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - } - } void Parse(FScanner &sc, bool fullScreenOffsets) { //Using StringConst instead of Identifieres is deperecated! @@ -2308,6 +2299,20 @@ class CommandIsSelected : public SBarInfoCommandFlowControl } SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + if(statusBar->CPlayer->ReadyWeapon != NULL) + { + const PClass *readyWeapon = statusBar->CPlayer->ReadyWeapon->GetClass(); + SetTruth(((weapon[1] != NULL) && + ((negate && (weapon[0] != readyWeapon && weapon[1] != readyWeapon)) || + (!negate && (weapon[0] == readyWeapon || weapon[1] == readyWeapon)))) || + ((weapon[1] == NULL) && + ((!negate && weapon[0] == readyWeapon) || (negate && weapon[0] != readyWeapon))), block, statusBar); + } + } protected: bool negate; const PClass *weapon[2]; @@ -2322,18 +2327,6 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if(statusBar->CPlayer->cls == NULL) - return; //No class so we can not continue - - int spawnClass = statusBar->CPlayer->cls->ClassIndex; - for(unsigned int i = 0;i < classes.Size();i++) - { - if(classes[i] == spawnClass) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - } void Parse(FScanner &sc, bool fullScreenOffsets) { sc.MustGetToken(TK_Identifier); @@ -2357,6 +2350,24 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl while(sc.CheckToken(TK_Identifier)); SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + if(statusBar->CPlayer->cls == NULL) + return; //No class so we can not continue + + int spawnClass = statusBar->CPlayer->cls->ClassIndex; + for(unsigned int i = 0;i < classes.Size();i++) + { + if(classes[i] == spawnClass) + { + SetTruth(true, block, statusBar); + return; + } + } + SetTruth(false, block, statusBar); + } protected: TArray classes; }; @@ -2371,22 +2382,6 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl { } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory) - { - if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder))) - { - AWeaponHolder *hold = static_cast(inv); - if(hold->PieceWeapon == weapon) - { - if(hold->PieceMask & (1 << (piece-1))) - SBarInfoCommandFlowControl::Draw(block, statusBar); - break; - } - } - } - } void Parse(FScanner &sc, bool fullScreenOffsets) { sc.MustGetToken(TK_Identifier); @@ -2400,6 +2395,25 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl piece = sc.Number; SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory) + { + if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder))) + { + AWeaponHolder *hold = static_cast(inv); + if(hold->PieceWeapon == weapon) + { + if(hold->PieceMask & (1 << (piece-1))) + SetTruth(true, block, statusBar); + return; + } + } + } + SetTruth(false, block, statusBar); + } protected: const PClass *weapon; unsigned int piece; @@ -2550,48 +2564,6 @@ class CommandWeaponAmmo : public SBarInfoCommandFlowControl ammo[1] = NULL; } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - if(statusBar->CPlayer->ReadyWeapon != NULL) - { - const PClass *AmmoType1 = statusBar->CPlayer->ReadyWeapon->AmmoType1; - const PClass *AmmoType2 = statusBar->CPlayer->ReadyWeapon->AmmoType2; - bool usesammo1 = (AmmoType1 != NULL); - bool usesammo2 = (AmmoType2 != NULL); - if(negate && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. - { - SBarInfoCommandFlowControl::Draw(block, statusBar); - return; - } - //Or means only 1 ammo type needs to match and means both need to match. - if(ammo[1] != NULL) - { - bool match1 = ((usesammo1 && (AmmoType1 == ammo[0] || AmmoType1 == ammo[1])) || !usesammo1); - bool match2 = ((usesammo2 && (AmmoType2 == ammo[0] || AmmoType2 == ammo[1])) || !usesammo2); - if((!conditionAnd && (match1 || match2)) || (conditionAnd && (match1 && match2))) - { - if(!negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - else if(negate) - { - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - } - else //Every thing here could probably be one long if statement but then it would be more confusing. - { - if((usesammo1 && (AmmoType1 == ammo[0])) || (usesammo2 && (AmmoType2 == ammo[0]))) - { - if(!negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - else if(negate) - { - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - } - } - } void Parse(FScanner &sc, bool fullScreenOffsets) { sc.MustGetToken(TK_Identifier); @@ -2621,6 +2593,59 @@ class CommandWeaponAmmo : public SBarInfoCommandFlowControl } SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + if(statusBar->CPlayer->ReadyWeapon != NULL) + { + const PClass *AmmoType1 = statusBar->CPlayer->ReadyWeapon->AmmoType1; + const PClass *AmmoType2 = statusBar->CPlayer->ReadyWeapon->AmmoType2; + bool usesammo1 = (AmmoType1 != NULL); + bool usesammo2 = (AmmoType2 != NULL); + if(negate && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. + { + SetTruth(true, block, statusBar); + return; + } + //Or means only 1 ammo type needs to match and means both need to match. + if(ammo[1] != NULL) + { + bool match1 = ((usesammo1 && (AmmoType1 == ammo[0] || AmmoType1 == ammo[1])) || !usesammo1); + bool match2 = ((usesammo2 && (AmmoType2 == ammo[0] || AmmoType2 == ammo[1])) || !usesammo2); + if((!conditionAnd && (match1 || match2)) || (conditionAnd && (match1 && match2))) + { + if(!negate) + { + SetTruth(true, block, statusBar); + return; + } + } + else if(negate) + { + SetTruth(true, block, statusBar); + return; + } + } + else //Every thing here could probably be one long if statement but then it would be more confusing. + { + if((usesammo1 && (AmmoType1 == ammo[0])) || (usesammo2 && (AmmoType2 == ammo[0]))) + { + if(!negate) + { + SetTruth(true, block, statusBar); + return; + } + } + else if(negate) + { + SetTruth(true, block, statusBar); + return; + } + } + } + SetTruth(false, block, statusBar); + } protected: bool conditionAnd; bool negate; @@ -2639,30 +2664,6 @@ class CommandInInventory : public SBarInfoCommandFlowControl amount[0] = amount[1] = 0; } - void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) - { - AInventory *invItem[2] = { statusBar->CPlayer->mo->FindInventory(item[0]), statusBar->CPlayer->mo->FindInventory(item[1]) }; - if (invItem[0] != NULL && amount[0] > 0 && invItem[0]->Amount < amount[0]) invItem[0] = NULL; - if (invItem[1] != NULL && amount[1] > 0 && invItem[1]->Amount < amount[1]) invItem[1] = NULL; - if(invItem[1] != NULL && conditionAnd) - { - if((invItem[0] != NULL && invItem[1] != NULL) && !negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - else if((invItem[0] == NULL || invItem[1] == NULL) && negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - else if(invItem[1] != NULL && !conditionAnd) - { - if((invItem[0] != NULL || invItem[1] != NULL) && !negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - else if((invItem[0] == NULL && invItem[1] == NULL) && negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } - else if((invItem[0] != NULL) && !negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - else if((invItem[0] == NULL) && negate) - SBarInfoCommandFlowControl::Draw(block, statusBar); - } void Parse(FScanner &sc, bool fullScreenOffsets) { sc.MustGetToken(TK_Identifier); @@ -2698,6 +2699,51 @@ class CommandInInventory : public SBarInfoCommandFlowControl } SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + AInventory *invItem[2] = { statusBar->CPlayer->mo->FindInventory(item[0]), statusBar->CPlayer->mo->FindInventory(item[1]) }; + if (invItem[0] != NULL && amount[0] > 0 && invItem[0]->Amount < amount[0]) invItem[0] = NULL; + if (invItem[1] != NULL && amount[1] > 0 && invItem[1]->Amount < amount[1]) invItem[1] = NULL; + if(invItem[1] != NULL && conditionAnd) + { + if((invItem[0] != NULL && invItem[1] != NULL) && !negate) + { + SetTruth(true, block, statusBar); + return; + } + else if((invItem[0] == NULL || invItem[1] == NULL) && negate) + { + SetTruth(true, block, statusBar); + return; + } + } + else if(invItem[1] != NULL && !conditionAnd) + { + if((invItem[0] != NULL || invItem[1] != NULL) && !negate) + { + SetTruth(true, block, statusBar); + return; + } + else if((invItem[0] == NULL && invItem[1] == NULL) && negate) + { + SetTruth(true, block, statusBar); + return; + } + } + else if((invItem[0] != NULL) && !negate) + { + SetTruth(true, block, statusBar); + return; + } + else if((invItem[0] == NULL) && negate) + { + SetTruth(true, block, statusBar); + return; + } + SetTruth(false, block, statusBar); + } protected: bool conditionAnd; bool negate; diff --git a/wadsrc/static/sbarinfo/doom.txt b/wadsrc/static/sbarinfo/doom.txt index cb7f75cb6..b46cffe3b 100644 --- a/wadsrc/static/sbarinfo/doom.txt +++ b/wadsrc/static/sbarinfo/doom.txt @@ -38,8 +38,7 @@ statusbar fullscreen, fullscreenoffsets // ZDoom HUD drawselectedinventory centerbottom, drawshadow, alwaysshowcounter, HUDFONT_DOOM, -14, -39, -26, -56, untranslated; } } - //no secondary ammo - usessecondaryammo not + else //no secondary ammo { inventorybarnotvisible { @@ -47,9 +46,7 @@ statusbar fullscreen, fullscreenoffsets // ZDoom HUD } } } - - // no ammo but inventory - usesammo not + else // no ammo but inventory { inventorybarnotvisible { From 69861688dcb2223525265abf6983033dc9fe1ff5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 06:52:03 +0000 Subject: [PATCH 037/251] - expanded r_smoothlighting into a r_fakecontrast CVAR that allows to set all 3 options: off, standard and smooth. SVN r2314 (trunk) --- src/m_options.cpp | 8 ++++++++ src/r_defs.h | 2 +- src/r_segs.cpp | 32 +++++++++++++++++++++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index e87fa87a2..2ca052521 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -437,6 +437,7 @@ EXTERN_CVAR (Int, wipetype) EXTERN_CVAR (Bool, vid_palettehack) EXTERN_CVAR (Bool, vid_attachedsurfaces) EXTERN_CVAR (Int, screenblocks) +EXTERN_CVAR (Int, r_fakecontrast) static TArray Crosshairs; @@ -476,6 +477,12 @@ static value_t Endoom[] = { { 2.0, "Only modified" } }; +static value_t Contrast[] = { + { 0.0, "Off" }, + { 1.0, "On" }, + { 2.0, "Smooth" } +}; + static menuitem_t VideoItems[] = { { more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} }, { more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} }, @@ -497,6 +504,7 @@ static menuitem_t VideoItems[] = { #endif { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Use fuzz effect", {&r_drawfuzz}, {2.0}, {0.0}, {0.0}, {YesNo} }, + { discrete, "Use fake contrast", {&r_fakecontrast}, {3.0}, {0.0}, {0.0}, {YesNo} }, { discrete, "Rocket Trails", {&cl_rockettrails}, {4.0}, {0.0}, {0.0}, {RocketTrailTypes} }, { discrete, "Blood Type", {&cl_bloodtype}, {3.0}, {0.0}, {0.0}, {BloodTypes} }, { discrete, "Bullet Puff Type", {&cl_pufftype}, {2.0}, {0.0}, {0.0}, {PuffTypes} }, diff --git a/src/r_defs.h b/src/r_defs.h index f19656afa..64d9b7614 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -763,7 +763,7 @@ struct side_t BYTE Flags; int Index; // needed to access custom UDMF fields which are stored in loading order. - int GetLightLevel (bool foggy, int baselight) const; + int GetLightLevel (bool foggy, int baselight, int *fake = NULL) const; void SetLight(SWORD l) { diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 06b793af4..88c918db2 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -53,6 +53,7 @@ #define WALLYREPEAT 8 + //CVAR (Int, ty, 8, 0) //CVAR (Int, tx, 8, 0) @@ -1453,24 +1454,33 @@ void R_NewWall (bool needlights) } } -CVAR(Bool, r_smoothlighting, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) self = 1; + else if (self > 2) self = 2; +} -int side_t::GetLightLevel (bool foggy, int baselight) const +int side_t::GetLightLevel (bool foggy, int baselight, int *pfakecontrast) const { if (Flags & WALLF_ABSLIGHTING) { baselight = (BYTE)Light; } + if (pfakecontrast != NULL) + { + *pfakecontrast = 0; + } if (!foggy) // Don't do relative lighting in foggy sectors { - if (!(Flags & WALLF_NOFAKECONTRAST)) + if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0) { - if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_smoothlighting) && + int rel; + if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) && linedef->dx != 0) { - baselight += int // OMG LEE KILLOUGH LIVES! :/ + rel = int // OMG LEE KILLOUGH LIVES! :/ ( (float(level.WallHorizLight) +abs(atan(float(linedef->dy)/float(linedef->dx))/float(1.57079)) @@ -1479,8 +1489,16 @@ int side_t::GetLightLevel (bool foggy, int baselight) const } else { - baselight += linedef->dx==0? level.WallVertLight : - linedef->dy==0? level.WallHorizLight : 0; + rel = linedef->dx==0? level.WallVertLight : + linedef->dy==0? level.WallHorizLight : 0; + } + if (pfakecontrast != NULL) + { + *pfakecontrast = rel; + } + else + { + baselight += rel; } } if (!(Flags & WALLF_ABSLIGHTING)) From 68fa08ca5279ad028d05bad5e90a7ea5d4daa982 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 06:54:59 +0000 Subject: [PATCH 038/251] - fixed: TNT MAP30 needs the stairbuilding compatibility option. SVN r2315 (trunk) --- src/compatibility.cpp | 1 + src/d_iwad.cpp | 2 +- src/gi.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index caaaaf871..af57688c0 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -258,6 +258,7 @@ void CheckCompatibility(MapData *map) if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && !(level.flags & LEVEL_HEXENFORMAT)) { ii_compatflags = COMPATF_SHORTTEX; + if (gameinfo.flags & GI_COMPATSHORTTEX) ii_compatflags |= COMPATF_STAIRINDEX; ib_compatflags = 0; ii_compatparams = -1; } diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 3cf9773ce..e5939e1a7 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -58,7 +58,7 @@ EIWADType gameiwad; const IWADInfo IWADInfos[NUM_IWAD_TYPES] = { // banner text, autoname, fg color, bg color - { "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX }, + { "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX | GI_COMPATSTAIRS }, { "Final Doom: Plutonia Experiment", "Plutonia", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/plutonia.txt", GI_MAPxx | GI_COMPATSHORTTEX }, { "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx }, { "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx }, diff --git a/src/gi.h b/src/gi.h index 0ada094c2..a87098555 100644 --- a/src/gi.h +++ b/src/gi.h @@ -43,6 +43,7 @@ #define GI_MENUHACK_EXTENDED 0x00000004 // (Heretic) #define GI_TEASER2 0x00000008 // Alternate version of the Strife Teaser #define GI_COMPATSHORTTEX 0x00000010 // always force COMPAT_SHORTTEX for IWAD maps. +#define GI_COMPATSTAIRS 0x00000010 // same for stairbuilding #include "gametype.h" From 942108f7ea4f791bba116b2617d1f7b8b629cffd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 07:02:23 +0000 Subject: [PATCH 039/251] - added DavidPH's A_FaceTarget patch but modified it so that if a turn angle is set the MF_SHADOW flag is ignored. SVN r2316 (trunk) --- src/p_enemy.cpp | 50 +++++++++++++++++++++++++++++----- src/p_enemy.h | 2 +- wadsrc/static/actors/actor.txt | 2 +- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3701a7b91..1174119d8 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2671,7 +2671,7 @@ void A_Chase(AActor *self) // A_FaceTarget // //============================================================================= -void A_FaceTarget (AActor *self) +void A_FaceTarget (AActor *self, angle_t max_turn) { if (!self->target) return; @@ -2683,18 +2683,54 @@ void A_FaceTarget (AActor *self) } self->flags &= ~MF_AMBUSH; - self->angle = R_PointToAngle2 (self->x, self->y, - self->target->x, self->target->y); - - if (self->target->flags & MF_SHADOW) + + angle_t target_angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); + + // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. + // It also means that there is no need to check for going past the target. + if (max_turn && (max_turn < abs(self->angle - target_angle))) + { + if (self->angle > target_angle) + { + if (self->angle - target_angle < ANGLE_180) + { + self->angle -= max_turn; + } + else + { + self->angle += max_turn; + } + } + else + { + if (target_angle - self->angle < ANGLE_180) + { + self->angle += max_turn; + } + else + { + self->angle -= max_turn; + } + } + } + else + { + self->angle = target_angle; + } + + // This will never work well if the turn angle is limited. + if (max_turn == 0 && (self->angle == target_angle) && self->target->flags & MF_SHADOW) { self->angle += pr_facetarget.Random2() << 21; } } -DEFINE_ACTION_FUNCTION(AActor, A_FaceTarget) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget) { - A_FaceTarget(self); + ACTION_PARAM_START(1); + ACTION_PARAM_ANGLE(max_turn, 0); + + A_FaceTarget(self, max_turn); } //=========================================================================== diff --git a/src/p_enemy.h b/src/p_enemy.h index 86261dd45..e3e83be6c 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -69,7 +69,7 @@ DECLARE_ACTION(A_FreezeDeathChunks) DECLARE_ACTION(A_BossDeath) void A_Chase(AActor *self); -void A_FaceTarget (AActor *actor); +void A_FaceTarget (AActor *actor, angle_t max_turn = 0); bool A_RaiseMobj (AActor *, fixed_t speed); bool A_SinkMobj (AActor *, fixed_t speed); diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 1b9719463..7ef500d0a 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -61,7 +61,7 @@ ACTOR Actor native //: Thinker action native A_XScream(); action native A_Look(); action native A_Chase(state melee = "*", state missile = "none", int flags = 0); - action native A_FaceTarget(); + action native A_FaceTarget(float max_turn = 0); action native A_PosAttack(); action native A_Scream(); action native A_SPosAttack(); From 6a57a43277cddaf1855eddabd753e8bf3ebfad60 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 07:08:39 +0000 Subject: [PATCH 040/251] - added DavidPH's LifeSteal patch for A_CustomPunch/A_Saw. SVN r2317 (trunk) --- src/g_doom/a_doomweaps.cpp | 12 ++++++++++-- src/thingdef/thingdef_codeptr.cpp | 4 ++++ wadsrc/static/actors/shared/inventory.txt | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index cfa5cdbae..026da4c5e 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -110,6 +110,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) ACTION_PARAM_SOUND(hitsound, 1); ACTION_PARAM_INT(damage, 2); ACTION_PARAM_CLASS(pufftype, 3); + ACTION_PARAM_FIXED(Range, 4) + ACTION_PARAM_FIXED(LifeSteal, 5); if (NULL == (player = self->player)) { @@ -131,8 +133,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) angle += pr_saw.Random2() << 18; // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) - P_LineAttack (self, angle, MELEERANGE+1, - P_AimLineAttack (self, angle, MELEERANGE+1, &linetarget), damage, + if (Range == 0) Range = MELEERANGE+1; + + P_LineAttack (self, angle, Range, + P_AimLineAttack (self, angle, Range, &linetarget), damage, NAME_None, pufftype); if (!linetarget) @@ -140,6 +144,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); return; } + + if (LifeSteal) + P_GiveBody (self, (damage * LifeSteal) >> FRACBITS); + S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); // turn to face target diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 8b09a2c10..cc3052b57 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1080,6 +1080,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) ACTION_PARAM_BOOL(UseAmmo, 2); ACTION_PARAM_CLASS(PuffType, 3); ACTION_PARAM_FIXED(Range, 4); + ACTION_PARAM_FIXED(LifeSteal, 5); if (!self->player) return; @@ -1110,6 +1111,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) // turn to face target if (linetarget) { + if (LifeSteal) + P_GiveBody (self, (Damage * LifeSteal) >> FRACBITS); + S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); self->angle = R_PointToAngle2 (self->x, diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 3e805ed05..e64012921 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -7,7 +7,7 @@ ACTOR Inventory native Inventory.PickupSound "misc/i_pkup" action native A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class pufftype = "BulletPuff", float range = 0); + action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", bool useammo = true, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff"); @@ -40,7 +40,7 @@ ACTOR Inventory native action native A_ClearReFire(); action native A_CheckReload(); action native A_GunFlash(state flash = ""); - action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff"); + action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); action native A_CheckForReload(int counter, state label, bool dontincrement = false); action native A_ResetReloadCounter(); action native A_RestoreSpecialPosition(); From b61b761e28a07a11473fd0a69d842bc67ae173e9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 07:11:56 +0000 Subject: [PATCH 041/251] - added DavidPH's randomization patch for hitscan attacks. SVN r2318 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 40 ++++++++++++++++++----- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 8 +++++ wadsrc/static/actors/shared/inventory.txt | 2 +- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index cc3052b57..02dc05b72 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -803,6 +803,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) // An even more customizable hitscan attack // //========================================================================== +enum CBA_Flags +{ + CBAF_AIMFACING = 1, + CBAF_NORANDOM = 2, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) { ACTION_PARAM_START(7); @@ -812,7 +818,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) ACTION_PARAM_INT(DamagePerBullet, 3); ACTION_PARAM_CLASS(pufftype, 4); ACTION_PARAM_FIXED(Range, 5); - ACTION_PARAM_BOOL(AimFacing, 6); + ACTION_PARAM_INT(Flags, 6); if(Range==0) Range=MISSILERANGE; @@ -820,9 +826,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) int bangle; int bslope; - if (self->target || AimFacing) + if (self->target || (Flags & CBAF_AIMFACING)) { - if (!AimFacing) A_FaceTarget (self); + if (!(Flags & CBAF_AIMFACING)) A_FaceTarget (self); bangle = self->angle; if (!pufftype) pufftype = PClass::FindClass(NAME_BulletPuff); @@ -834,7 +840,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) { int angle = bangle + pr_cabullet.Random2() * (Spread_XY / 255); int slope = bslope + pr_cabullet.Random2() * (Spread_Z / 255); - int damage = ((pr_cabullet()%3)+1) * DamagePerBullet; + int damage = DamagePerBullet; + + if (!(Flags & CBAF_NORANDOM)) + damage *= ((pr_cabullet()%3)+1); + P_LineAttack(self, angle, Range, slope, damage, NAME_None, pufftype); } } @@ -948,6 +958,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) // An even more customizable hitscan attack // //========================================================================== +enum FB_Flags +{ + FBF_USEAMMO = 1, + FBF_NORANDOM = 2, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) { ACTION_PARAM_START(7); @@ -956,7 +972,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) ACTION_PARAM_INT(NumberOfBullets, 2); ACTION_PARAM_INT(DamagePerBullet, 3); ACTION_PARAM_CLASS(PuffType, 4); - ACTION_PARAM_BOOL(UseAmmo, 5); + ACTION_PARAM_INT(Flags, 5); ACTION_PARAM_FIXED(Range, 6); if (!self->player) return; @@ -968,7 +984,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) int bangle; int bslope; - if (UseAmmo && weapon) + if ((Flags & FBF_USEAMMO) && weapon) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo } @@ -986,7 +1002,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if ((NumberOfBullets==1 && !player->refire) || NumberOfBullets==0) { - int damage = ((pr_cwbullet()%3)+1)*DamagePerBullet; + int damage = DamagePerBullet; + + if (!(Flags & FBF_NORANDOM)) + damage *= ((pr_cwbullet()%3)+1); + P_LineAttack(self, bangle, Range, bslope, damage, NAME_None, PuffType); } else @@ -996,7 +1016,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) { int angle = bangle + pr_cwbullet.Random2() * (Spread_XY / 255); int slope = bslope + pr_cwbullet.Random2() * (Spread_Z / 255); - int damage = ((pr_cwbullet()%3)+1) * DamagePerBullet; + int damage = DamagePerBullet; + + if (!(Flags & FBF_NORANDOM)) + damage *= ((pr_cwbullet()%3)+1); + P_LineAttack(self, angle, Range, slope, damage, NAME_None, PuffType); } } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 7ef500d0a..1a18d2ed4 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -184,7 +184,7 @@ ACTOR Actor native //: Thinker action native A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0); - action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, bool aimfacing = false); + action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0); action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff"); action native A_JumpIfHealthLower(int health, state label); action native A_JumpIfCloser(float distance, state label); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 71fb3d511..10d36dd65 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -5,6 +5,14 @@ const int CMF_AIMDIRECTION = 2; const int CMF_TRACKOWNER = 4; const int CMF_CHECKTARGETDEAD = 8; +// Flags for A_CustomBulletAttack +const int CBAF_AIMFACING = 1; +const int CBAF_NORANDOM = 2; + +// Flags for A_FireBullets +const int FBF_USEAMMO = 1; +const int FBF_NORANDOM = 2; + // Flags for A_SpawnItemEx const int SXF_TRANSFERTRANSLATION=1; const int SXF_ABSOLUTEPOSITION=2; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index e64012921..48a966878 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -8,7 +8,7 @@ ACTOR Inventory native action native A_JumpIfNoAmmo(state label); action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); - action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", bool useammo = true, float range = 0); + action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff"); action native A_Light(int extralight); From 3e5a32b5549272278f25c4106249e47cea6e46eb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 09:44:44 +0000 Subject: [PATCH 042/251] - copy-paste error in TNT stairs fix. SVN r2319 (trunk) --- src/compatibility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index af57688c0..994a34b44 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -258,7 +258,7 @@ void CheckCompatibility(MapData *map) if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && !(level.flags & LEVEL_HEXENFORMAT)) { ii_compatflags = COMPATF_SHORTTEX; - if (gameinfo.flags & GI_COMPATSHORTTEX) ii_compatflags |= COMPATF_STAIRINDEX; + if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX; ib_compatflags = 0; ii_compatparams = -1; } From d050973fa47750b9cdc45398d26c940f36bfecbc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 10:17:08 +0000 Subject: [PATCH 043/251] - added blockmap verification code. SVN r2320 (trunk) --- src/p_setup.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 45f50c64e..8c3f774d7 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2721,6 +2721,79 @@ static void P_CreateBlockMap () } } + + +// +// P_VerifyBlockMap +// +// haleyjd 03/04/10: do verification on validity of blockmap. +// +static bool P_VerifyBlockMap(int count) +{ + int x, y; + int *maxoffs = blockmaplump + count; + + int bmapwidth = blockmaplump[2]; + int bmapheight = blockmaplump[3]; + + for(y = 0; y < bmapheight; y++) + { + for(x = 0; x < bmapwidth; x++) + { + int offset; + int *list, *tmplist; + int *blockoffset; + + offset = y * bmapwidth + x; + blockoffset = blockmaplump + offset + 4; + + + // check that block offset is in bounds + if(blockoffset >= maxoffs) + { + Printf(PRINT_HIGH, "P_VerifyBlockMap: block offset overflow\n"); + return false; + } + + offset = *blockoffset; + + // check that list offset is in bounds + if(offset < 4 || offset >= count) + { + Printf(PRINT_HIGH, "P_VerifyBlockMap: list offset overflow\n"); + return false; + } + + list = blockmaplump + offset; + + // scan forward for a -1 terminator before maxoffs + for(tmplist = list; ; tmplist++) + { + // we have overflowed the lump? + if(tmplist >= maxoffs) + { + Printf(PRINT_HIGH, "P_VerifyBlockMap: open blocklist\n"); + return false; + } + if(*tmplist == -1) // found -1 + break; + } + + // scan the list for out-of-range linedef indicies in list + for(tmplist = list; *tmplist != -1; tmplist++) + { + if(*tmplist < 0 || *tmplist >= numlines) + { + Printf(PRINT_HIGH, "P_VerifyBlockMap: index >= numlines\n"); + return false; + } + } + } + } + + return true; +} + // // P_LoadBlockMap // @@ -2768,6 +2841,13 @@ void P_LoadBlockMap (MapData * map) blockmaplump[i] = t == -1 ? (DWORD)0xffffffff : (DWORD) t & 0xffff; } delete[] data; + + if (!P_VerifyBlockMap(count)) + { + DPrintf ("Generating BLOCKMAP\n"); + P_CreateBlockMap(); + } + } bmaporgx = blockmaplump[0]< Date: Wed, 12 May 2010 20:22:22 +0000 Subject: [PATCH 044/251] - fixed: The PoisonCloud had the CANBLAST flag set even though it shouldn't. SVN r2321 (trunk) --- wadsrc/static/actors/hexen/flechette.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/hexen/flechette.txt b/wadsrc/static/actors/hexen/flechette.txt index a0ad52268..75f83d770 100644 --- a/wadsrc/static/actors/hexen/flechette.txt +++ b/wadsrc/static/actors/hexen/flechette.txt @@ -142,7 +142,7 @@ ACTOR PoisonCloud native Mass 0x7fffffff +NOBLOCKMAP +NOGRAVITY +DROPOFF +NODAMAGETHRUST - +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT + +DONTSPLASH +FOILINVUL +BLOODLESSIMPACT RenderStyle Translucent Alpha 0.6 DeathSound "PoisonShroomDeath" From 489c3df007ef5ac519d041dd2c35a43fd4cbb291 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 May 2010 21:12:40 +0000 Subject: [PATCH 045/251] - revert last revision SVN r2322 (trunk) --- wadsrc/static/actors/hexen/flechette.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/hexen/flechette.txt b/wadsrc/static/actors/hexen/flechette.txt index 75f83d770..a0ad52268 100644 --- a/wadsrc/static/actors/hexen/flechette.txt +++ b/wadsrc/static/actors/hexen/flechette.txt @@ -142,7 +142,7 @@ ACTOR PoisonCloud native Mass 0x7fffffff +NOBLOCKMAP +NOGRAVITY +DROPOFF +NODAMAGETHRUST - +DONTSPLASH +FOILINVUL +BLOODLESSIMPACT + +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT RenderStyle Translucent Alpha 0.6 DeathSound "PoisonShroomDeath" From 2d4502018a9c6751727cb49986de340397ebd97e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 02:18:27 +0000 Subject: [PATCH 046/251] - Added DavidPH's FBF_EXPLICITANGLE extension. SVN r2323 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 17 +++++++++++++++-- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 02dc05b72..6c5729cf3 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -962,6 +962,7 @@ enum FB_Flags { FBF_USEAMMO = 1, FBF_NORANDOM = 2, + FBF_EXPLICITANGLE = 4, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) @@ -1014,8 +1015,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if (NumberOfBullets == -1) NumberOfBullets = 1; for (i=0 ; i Date: Fri, 14 May 2010 02:34:25 +0000 Subject: [PATCH 047/251] - Added A_JumpIfTracerCloser and A_JumpIfMasterCloser, based on DavidPH's A_JumpIfCloser patch. SVN r2324 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 48 ++++++++++++++++++++----------- wadsrc/static/actors/actor.txt | 2 ++ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6c5729cf3..a5fc1d08e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -470,30 +470,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) +void DoJumpIfCloser(AActor *target, DECLARE_PARAMINFO) { ACTION_PARAM_START(2); ACTION_PARAM_FIXED(dist, 0); ACTION_PARAM_STATE(jump, 1); - AActor *target; - - if (!self->player) - { - target=self->target; - } - else - { - // Does the player aim at something that can be shot? - P_BulletSlope(self, &target); - } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! // No target - no jump - if (target==NULL) return; - - if (P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + if (target != NULL && P_AproxDistance(self->x-target->x, self->y-target->y) < dist && ( (self->z > target->z && self->z - (target->z + target->height) < dist) || (self->z <=target->z && target->z - (self->z + self->height) < dist) ) @@ -503,6 +489,36 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) } } +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) +{ + AActor *target; + + if (!self->player) + { + target = self->target; + } + else + { + // Does the player aim at something that can be shot? + P_BulletSlope(self, &target); + } + DoJumpIfCloser(target, PUSH_PARAMINFO); +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser) +{ + // Is there really any reason to limit this to seeker missiles? + if (self->flags2 & MF2_SEEKERMISSILE) + { + DoJumpIfCloser(self->tracer, PUSH_PARAMINFO); + } +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) +{ + DoJumpIfCloser(self->master, PUSH_PARAMINFO); +} + //========================================================================== // // State jump function diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 1a18d2ed4..ec6e0cea0 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -188,6 +188,8 @@ ACTOR Actor native //: Thinker action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff"); action native A_JumpIfHealthLower(int health, state label); action native A_JumpIfCloser(float distance, state label); + action native A_JumpIfTracerCloser(float distance, state label); + action native A_JumpIfMasterCloser(float distance, state label); action native A_JumpIfInventory(class itemtype, int itemamount, state label); action native A_JumpIfArmorType(string Type, state label, int amount = 1); action native A_GiveInventory(class itemtype, int amount = 0); From 1c8397e86d23c0c15933a1d588b6a03fefea7053 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 03:37:44 +0000 Subject: [PATCH 048/251] - Fixed: PacketGet() can receive WSAECONNRESET after startup is complete, so it needs to check for a NULL before using NetMessage. SVN r2325 (trunk) --- src/i_net.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/i_net.cpp b/src/i_net.cpp index 633c75d1a..ae28bb779 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -269,8 +269,16 @@ void PacketGet (void) if (err == WSAECONNRESET) { // The remote node aborted unexpectedly, so pretend it sent an exit packet - StartScreen->NetMessage ("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.netname); + if (StartScreen != NULL) + { + StartScreen->NetMessage ("The connection from %s was dropped.\n", + players[sendplayer[node]].userinfo.netname); + } + else + { + Printf("The connection from %s was dropped.\n", + players[sendplayer[node]].userinfo.netname); + } doomcom.data[0] = 0x80; // NCMD_EXIT c = 1; From b2a4ffc7184e3d97b1a01c938f5ea23f113623f8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 03:54:35 +0000 Subject: [PATCH 049/251] - Fixed: IDirect3D9::CreateDevice() can return D3DERR_DEVICELOST if you want exclusive mode and some other application already has it. While technically this is a failure, the device is still created, so we can continue using it anyway. SVN r2326 (trunk) --- src/win32/fb_d3d9.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 561891e29..58ad92455 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -322,19 +322,23 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) HRESULT hr; if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice))) + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && + hr != D3DERR_DEVICELOST) { if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice))) + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && + hr != D3DERR_DEVICELOST) { if (d3dpp.FullScreen_RefreshRateInHz != 0) { d3dpp.FullScreen_RefreshRateInHz = 0; if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice))) + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && + hr != D3DERR_DEVICELOST) { if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice))) + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && + hr != D3DERR_DEVICELOST) { D3DDevice = NULL; } @@ -360,9 +364,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) { DeviceCaps.LineCaps |= D3DLINECAPS_ANTIALIAS; } - // I don't know about ATI's drivers. The only ATI device - // I have readily available to test with (a Mobility X300) - // really doesn't support them. + // ATI's drivers apparently also lie, so screw this cap. } CreateResources(); SetInitialState(); From 30ec646ba5ec75fc0d07486dfa23a4089a23468c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 03:58:23 +0000 Subject: [PATCH 050/251] - Removed spurious log warnings when retrying in CreateFrameBuffer(). SVN r2327 (trunk) --- src/win32/win32video.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 2753c0aeb..7a2d14981 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -596,6 +596,7 @@ DFrameBuffer *Win32Video::CreateFrameBuffer (int width, int height, bool fullscr { hr = fb->GetHR (); } + fb->ObjectFlags |= OF_YesReallyDelete; delete fb; LOG1 ("fb is bad: %08lx\n", hr); From 24f23718b74a7042fe14b1da1b928b8da39eb27c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 04:06:30 +0000 Subject: [PATCH 051/251] - Added GetHR support to D3DFB for querying the error code when device creation fails. - Should still check for a NULL device when CreateDevice() returns D3DERR_DEVICELOST. SVN r2328 (trunk) --- src/win32/fb_d3d9.cpp | 13 ++++++++----- src/win32/win32iface.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 58ad92455..c5b66870b 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -242,6 +242,8 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) { D3DPRESENT_PARAMETERS d3dpp; + LastHR = 0; + D3DDevice = NULL; VertexBuffer = NULL; IndexBuffer = NULL; @@ -323,18 +325,18 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && - hr != D3DERR_DEVICELOST) + (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && - hr != D3DERR_DEVICELOST) + (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { if (d3dpp.FullScreen_RefreshRateInHz != 0) { d3dpp.FullScreen_RefreshRateInHz = 0; if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && - hr != D3DERR_DEVICELOST) + (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && @@ -346,6 +348,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) } } } + LastHR = hr; if (D3DDevice != NULL) { D3DADAPTER_IDENTIFIER9 adapter_id; @@ -364,7 +367,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) { DeviceCaps.LineCaps |= D3DLINECAPS_ANTIALIAS; } - // ATI's drivers apparently also lie, so screw this cap. + // ATI's drivers apparently also lie, so screw this caps bit. } CreateResources(); SetInitialState(); @@ -1000,7 +1003,7 @@ bool D3DFB::IsValid () HRESULT D3DFB::GetHR () { - return 0; + return LastHR; } //========================================================================== diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 9bdfd1072..d8e6af6a3 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -414,6 +414,7 @@ private: D3DPal *Palettes; D3DTex *Textures; PackingTexture *Packs; + HRESULT LastHR; IDirect3DDevice9 *D3DDevice; IDirect3DTexture9 *FBTexture; From e9bbe4f1ff56622c5b19e31781dc8b0cd0dd2acc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 14 May 2010 04:13:59 +0000 Subject: [PATCH 052/251] - Added more logging for D3DFB CreateDevice() attempts. SVN r2329 (trunk) --- src/win32/fb_d3d9.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index c5b66870b..b21c1b003 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -323,10 +323,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) HRESULT hr; + LOG("CreateDevice attempt 1 hwvp\n"); if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { + LOG2("CreateDevice returned hr %08x dev %p; attempt 2 swvp\n", hr, D3DDevice); if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) @@ -334,10 +336,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) if (d3dpp.FullScreen_RefreshRateInHz != 0) { d3dpp.FullScreen_RefreshRateInHz = 0; + LOG2("CreateDevice returned hr %08x dev %p; attempt 3 (hwvp, default Hz)\n", hr, D3DDevice); if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { + LOG2("CreateDevice returned hr %08x dev %p; attempt 4 (swvp, default Hz)\n", hr, D3DDevice); if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && hr != D3DERR_DEVICELOST) @@ -348,6 +352,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) } } } + LOG2("Final CreateDevice returned HR %08x and device %p\n", hr, D3DDevice); LastHR = hr; if (D3DDevice != NULL) { From 896a77327ab24d31e5487ffd6892b9d2c41b7fb7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 14 May 2010 20:12:21 +0000 Subject: [PATCH 053/251] - fixed fake contrast menu option. SVN r2330 (trunk) --- src/m_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index 2ca052521..50d7966cd 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -504,7 +504,7 @@ static menuitem_t VideoItems[] = { #endif { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Use fuzz effect", {&r_drawfuzz}, {2.0}, {0.0}, {0.0}, {YesNo} }, - { discrete, "Use fake contrast", {&r_fakecontrast}, {3.0}, {0.0}, {0.0}, {YesNo} }, + { discrete, "Use fake contrast", {&r_fakecontrast}, {3.0}, {0.0}, {0.0}, {Contrast} }, { discrete, "Rocket Trails", {&cl_rockettrails}, {4.0}, {0.0}, {0.0}, {RocketTrailTypes} }, { discrete, "Blood Type", {&cl_bloodtype}, {3.0}, {0.0}, {0.0}, {BloodTypes} }, { discrete, "Bullet Puff Type", {&cl_pufftype}, {2.0}, {0.0}, {0.0}, {PuffTypes} }, From c4efbeb5157418654aa46ccf066ff81135fce44f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 14 May 2010 20:27:57 +0000 Subject: [PATCH 054/251] - fixed: Both Boom and MBF compatibility mode need COMPATF_MISSILECLIP set. SVN r2331 (trunk) --- src/d_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 65973e3c8..0241ac251 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -504,7 +504,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) break; case 3: // Boom compat mode - v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL; + v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP; break; case 4: // Old ZDoom compat mode @@ -512,7 +512,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) break; case 5: // MBF compat mode - v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MUSHROOM| + v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_MUSHROOM| COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS; break; From 9611e7310a6d2549b23bc897ab0f2955f8898c49 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 21 May 2010 19:56:13 +0000 Subject: [PATCH 055/251] - Added resolution setting to SBarInfo. - Fixed: Mug shot was not reset at the start of a new game. SVN r2332 (trunk) --- src/g_shared/sbar.h | 4 +- src/g_shared/sbar_mugshot.cpp | 11 ++++ src/g_shared/sbarinfo.cpp | 92 +++++++++++++++++++++++------- src/g_shared/sbarinfo.h | 2 + src/g_shared/sbarinfo_commands.cpp | 4 ++ src/g_shared/shared_sbar.cpp | 20 ++++--- 6 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index cf677771a..440de41dd 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -215,6 +215,7 @@ class FMugShot FMugShot(); void Grin(bool grin=true) { bEvilGrin = grin; } + void Reset(); void Tick(player_t *player); bool SetState(const char *state_name, bool wait_till_done=false, bool reset=false); int UpdateState(player_t *player, StateFlags stateflags=STANDARD); @@ -275,7 +276,7 @@ public: ST_DEADFACE = ST_GODFACE + 1 }; - DBaseStatusBar (int reltop); + DBaseStatusBar (int reltop, int hres=320, int vres=200); void Destroy (); void SetScaled (bool scale, bool force=false); @@ -338,6 +339,7 @@ public: int ST_X, ST_Y; int RelTop; + int HorizontalResolution, VirticalResolution; bool Scaled; bool Centering; bool FixedOrigin; diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index 73d469eac..cecae1df3 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -221,6 +221,17 @@ int FindMugShotStateIndex(FName state) //=========================================================================== FMugShot::FMugShot() +{ + Reset(); +} + +//=========================================================================== +// +// FMugShot :: Reset +// +//=========================================================================== + +void FMugShot::Reset() { FaceHealth = -1; bEvilGrin = false; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 9e424c098..a359fb3cb 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -190,8 +190,8 @@ class SBarInfoCommand } } - if(!fullScreenOffsets) - y.SetCoord((negative ? -sc.Number : sc.Number) - (200 - script->height)); + //if(!fullScreenOffsets) + // y.SetCoord((negative ? -sc.Number : sc.Number) - (200 - script->height)); } EColorRange GetTranslation(FScanner &sc) { @@ -367,6 +367,7 @@ enum //Key words SBARINFO_COMPLETEBORDER, SBARINFO_MONOSPACEFONTS, SBARINFO_LOWERHEALTHCAP, + SBARINFO_RESOLUTION, SBARINFO_STATUSBAR, SBARINFO_MUGSHOT, SBARINFO_CREATEPOPUP, @@ -394,6 +395,7 @@ static const char *SBarInfoTopLevel[] = "completeborder", "monospacefonts", "lowerhealthcap", + "resolution", "statusbar", "mugshot", "createpopup", @@ -579,6 +581,14 @@ void SBarInfo::ParseSBarInfo(int lump) } sc.MustGetToken(';'); break; + case SBARINFO_RESOLUTION: + sc.MustGetToken(TK_IntConst); + resW = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + resH = sc.Number; + sc.MustGetToken(';'); + break; case SBARINFO_STATUSBAR: { if(!baseSet) //If the user didn't explicitly define a base, do so now. @@ -761,6 +771,8 @@ void SBarInfo::Init() armorInterpolationSpeed = 8; height = 0; spacingCharacter = '\0'; + resW = 320; + resH = 200; for(unsigned int i = 0;i < NUMHUDS;i++) huds[i] = new SBarInfoMainBlock(this); @@ -902,7 +914,7 @@ class DSBarInfo : public DBaseStatusBar { DECLARE_CLASS(DSBarInfo, DBaseStatusBar) public: - DSBarInfo (SBarInfo *script=NULL) : DBaseStatusBar(script->height), + DSBarInfo (SBarInfo *script=NULL) : DBaseStatusBar(script->height, script->resW, script->resH), ammo1(NULL), ammo2(NULL), ammocount1(0), ammocount2(0), armor(NULL), pendingPopup(POP_None), currentPopup(POP_None), lastHud(-1), lastInventoryBar(NULL), lastPopup(NULL) @@ -1110,7 +1122,7 @@ public: fixed_t tmp = 0; // I'll handle the conversion from fixed to int myself for more control fixed_t fx = (x + ST_X).Coordinate() << FRACBITS; - fixed_t fy = (y + ST_Y).Coordinate() << FRACBITS; + fixed_t fy = (y + ST_Y - (Scaled ? script->resH : 200) + script->height).Coordinate() << FRACBITS; fixed_t fw = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth) << FRACBITS; fixed_t fh = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight) << FRACBITS; fixed_t fcx = cx == 0 ? 0 : fx + cx - (texture->GetScaledLeftOffset() << FRACBITS); @@ -1120,10 +1132,16 @@ public: if(Scaled) { if(cx != 0 || cy != 0) - screen->VirtualToRealCoordsFixed(fcx, fcy, tmp, tmp, 320, 200, true); + screen->VirtualToRealCoordsFixed(fcx, fcy, tmp, tmp, script->resW, script->resH, true); if(cr != 0 || cb != 0 || clearDontDraw) - screen->VirtualToRealCoordsFixed(fcr, fcb, tmp, tmp, 320, 200, true); - screen->VirtualToRealCoordsFixed(fx, fy, fw, fh, 320, 200, true); + screen->VirtualToRealCoordsFixed(fcr, fcb, tmp, tmp, script->resW, script->resH, true); + screen->VirtualToRealCoordsFixed(fx, fy, fw, fh, script->resW, script->resH, true); + } + else + { + fy += (200 - script->resH)<resH)<resH)<>1)) >> FRACBITS; @@ -1173,10 +1191,26 @@ public: int rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; ADJUST_RELCENTER(x,y,rx,ry) + // We can't use DTA_HUDRules since it forces a width and height. + // Translation: No high res. + bool xright = rx < 0; + bool ybot = ry < 0; + w = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth); h = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight); if(vid_fps && rx < 0 && ry >= 0) ry += 10; + if(hud_scale) + { + rx *= CleanXfac * 320.0/script->resW; + ry *= CleanYfac * 200.0/script->resH; + w *= CleanXfac * 320.0/script->resW; + h *= CleanYfac * 200.0/script->resH; + } + if(xright) + rx = SCREENWIDTH + rx; + if(ybot) + ry = SCREENHEIGHT + ry; // Check for clipping if(cx != 0 || cy != 0 || cr != 0 || cb != 0) @@ -1189,34 +1223,34 @@ public: if(ry < 0) { if(rcy != 0) - rcy = hud_scale ? SCREENHEIGHT + (rcy*CleanYfac) : SCREENHEIGHT + rcy; + rcy = hud_scale ? SCREENHEIGHT + (rcy*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcy; if(rcb != INT_MAX) - rcb = hud_scale ? SCREENHEIGHT + (rcb*CleanYfac) : SCREENHEIGHT + rcb; + rcb = hud_scale ? SCREENHEIGHT + (rcb*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcb; } else if(hud_scale) { - rcy *= CleanYfac; + rcy *= CleanYfac*200.0/script->resH; if(rcb != INT_MAX) - rcb *= CleanYfac; + rcb *= CleanYfac*200.0/script->resH; } if(rx < 0) { if(rcx != 0) - rcx = hud_scale ? SCREENWIDTH + (rcx*CleanXfac) : SCREENWIDTH + rcx; + rcx = hud_scale ? SCREENWIDTH + (rcx*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcx; if(rcr != INT_MAX) - rcr = hud_scale ? SCREENWIDTH + (rcr*CleanXfac) : SCREENWIDTH + rcr; + rcr = hud_scale ? SCREENWIDTH + (rcr*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcr; } else if(hud_scale) { - rcx *= CleanXfac; + rcx *= CleanXfac*320.0/script->resW; if(rcr != INT_MAX) - rcr *= CleanXfac; + rcr *= CleanXfac*320.0/script->resW; } } if(clearDontDraw) { - screen->Clear(rcx, rcy, MIN(rcr, w*(hud_scale ? CleanXfac : 1)), MIN(rcb, h*(hud_scale ? CleanYfac : 1)), GPalette.BlackIndex, 0); + screen->Clear(rcx, rcy, MIN(rcr, w), MIN(rcb, h), GPalette.BlackIndex, 0); } else { @@ -1232,7 +1266,6 @@ public: DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, - DTA_HUDRules, HUD_Normal, DTA_Alpha, alpha, DTA_AlphaChannel, alphaMap, DTA_FillColor, 0, @@ -1250,7 +1283,6 @@ public: DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, - DTA_HUDRules, HUD_Normal, DTA_Alpha, alpha, TAG_DONE); } @@ -1297,9 +1329,13 @@ public: if(!fullScreenOffsets) { rx += ST_X; - ry += ST_Y; + ry += ST_Y - (Scaled ? script->resH : 200) + script->height; if(Scaled) - screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true); + screen->VirtualToRealCoordsInt(rx, ry, rw, rh, script->resW, script->resH, true); + else + { + ry += (200 - script->resH); + } } else { @@ -1340,12 +1376,26 @@ public: } else { + bool xright = rx < 0; + bool ybot = ry < 0; + + if(hud_scale) + { + rx *= CleanXfac * 320.0/script->resW; + ry *= CleanYfac * 200.0/script->resH; + rw *= CleanXfac * 320.0/script->resW; + rh *= CleanYfac * 200.0/script->resH; + } + if(xright) + rx = SCREENWIDTH + rx; + if(ybot) + ry = SCREENHEIGHT + ry; + screen->DrawTexture(character, rx, ry, DTA_DestWidth, rw, DTA_DestHeight, rh, DTA_Translation, font->GetColorTranslation(translation), DTA_Alpha, alpha, - DTA_HUDRules, HUD_Normal, TAG_DONE); } if(script->spacingCharacter == '\0') diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index 03aae3434..9952e21a8 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -98,6 +98,8 @@ struct SBarInfo int height; int gameType; FMugShot MugShot; + int resW; + int resH; int GetGameType() { return gameType; } void ParseSBarInfo(int lump); diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 6d8982c40..f5dcf198e 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1175,6 +1175,10 @@ class CommandDrawMugShot : public SBarInfoCommand GetCoordinates(sc, fullScreenOffsets, x, y); sc.MustGetToken(';'); } + void Reset() + { + script->MugShot.Reset(); + } protected: FString defaultFace; //Deprecated diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 96074390c..8c0473832 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -175,7 +175,7 @@ void ST_LoadCrosshair(bool alwaysload) // //--------------------------------------------------------------------------- -DBaseStatusBar::DBaseStatusBar (int reltop) +DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) { Centering = false; FixedOrigin = false; @@ -185,6 +185,8 @@ DBaseStatusBar::DBaseStatusBar (int reltop) Displacement = 0; CPlayer = NULL; ShowLog = false; + HorizontalResolution = hres; + VirticalResolution = vres; SetScaled (st_scale); } @@ -216,18 +218,20 @@ void DBaseStatusBar::Destroy () //--------------------------------------------------------------------------- //[BL] Added force argument to have forcescaled mean forcescaled. +// - Also, if the VirticalResolution is something other than the default (200) +// We should always obey the value of scale. void DBaseStatusBar::SetScaled (bool scale, bool force) { - Scaled = (RelTop != 0 || force) && (SCREENWIDTH != 320 && scale); + Scaled = (RelTop != 0 || force) && ((SCREENWIDTH != 320 || HorizontalResolution != 320) && scale); if (!Scaled) { - ST_X = (SCREENWIDTH - 320) / 2; + ST_X = (SCREENWIDTH - HorizontalResolution) / 2; ST_Y = SCREENHEIGHT - RelTop; ::ST_Y = ST_Y; if (RelTop > 0) { - Displacement = ((ST_Y * 200 / SCREENHEIGHT) - (200 - RelTop))*FRACUNIT/RelTop; + Displacement = ((ST_Y * VirticalResolution / SCREENHEIGHT) - (VirticalResolution - RelTop))*FRACUNIT/RelTop; } else { @@ -237,14 +241,14 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) else { ST_X = 0; - ST_Y = 200 - RelTop; + ST_Y = VirticalResolution - RelTop; if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) != 4) { // Normal resolution - ::ST_Y = Scale (ST_Y, SCREENHEIGHT, 200); + ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution); } else { // 5:4 resolution - ::ST_Y = Scale(ST_Y - 100, SCREENHEIGHT*3, BaseRatioSizes[4][1]) + SCREENHEIGHT/2 + ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, BaseRatioSizes[4][1], 200)) + SCREENHEIGHT/2 + (SCREENHEIGHT - SCREENHEIGHT * BaseRatioSizes[4][3] / 48) / 2; } Displacement = 0; @@ -1000,7 +1004,7 @@ void DBaseStatusBar::RefreshBackground () const if (x > 0) { y = x == ST_X ? ST_Y : ::ST_Y; - x2 = !(ratio & 3) || !Scaled ? ST_X+320 : + x2 = !(ratio & 3) || !Scaled ? ST_X+HorizontalResolution : SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2); R_DrawBorder (0, y, x, SCREENHEIGHT); R_DrawBorder (x2, y, SCREENWIDTH, SCREENHEIGHT); From adcf26d2b5db73d8de48668f2ee23c41b005ce85 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 22 May 2010 14:00:36 +0000 Subject: [PATCH 056/251] - Fixed MSVC compiler warnings in sbarinfo.cpp SVN r2333 (trunk) --- src/g_shared/sbarinfo.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index a359fb3cb..1d5f5ed34 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1202,10 +1202,10 @@ public: ry += 10; if(hud_scale) { - rx *= CleanXfac * 320.0/script->resW; - ry *= CleanYfac * 200.0/script->resH; - w *= CleanXfac * 320.0/script->resW; - h *= CleanYfac * 200.0/script->resH; + rx *= (int) (CleanXfac * 320.0/script->resW); + ry *= (int) (CleanYfac * 200.0/script->resH); + w *= (int) (CleanXfac * 320.0/script->resW); + h *= (int) (CleanYfac * 200.0/script->resH); } if(xright) rx = SCREENWIDTH + rx; @@ -1223,28 +1223,28 @@ public: if(ry < 0) { if(rcy != 0) - rcy = hud_scale ? SCREENHEIGHT + (rcy*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcy; + rcy = hud_scale ? SCREENHEIGHT + (int) (rcy*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcy; if(rcb != INT_MAX) - rcb = hud_scale ? SCREENHEIGHT + (rcb*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcb; + rcb = hud_scale ? SCREENHEIGHT + (int) (rcb*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcb; } else if(hud_scale) { - rcy *= CleanYfac*200.0/script->resH; + rcy *= (int) (CleanYfac*200.0/script->resH); if(rcb != INT_MAX) - rcb *= CleanYfac*200.0/script->resH; + rcb *= (int) (CleanYfac*200.0/script->resH); } if(rx < 0) { if(rcx != 0) - rcx = hud_scale ? SCREENWIDTH + (rcx*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcx; + rcx = hud_scale ? SCREENWIDTH + (int) (rcx*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcx; if(rcr != INT_MAX) - rcr = hud_scale ? SCREENWIDTH + (rcr*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcr; + rcr = hud_scale ? SCREENWIDTH + (int) (rcr*CleanXfac*320.0/script->resW) : SCREENWIDTH + rcr; } else if(hud_scale) { - rcx *= CleanXfac*320.0/script->resW; + rcx *= (int) (CleanXfac*320.0/script->resW); if(rcr != INT_MAX) - rcr *= CleanXfac*320.0/script->resW; + rcr *= (int) (CleanXfac*320.0/script->resW); } } @@ -1381,10 +1381,10 @@ public: if(hud_scale) { - rx *= CleanXfac * 320.0/script->resW; - ry *= CleanYfac * 200.0/script->resH; - rw *= CleanXfac * 320.0/script->resW; - rh *= CleanYfac * 200.0/script->resH; + rx *= (int) (CleanXfac * 320.0/script->resW); + ry *= (int) (CleanYfac * 200.0/script->resH); + rw *= (int) (CleanXfac * 320.0/script->resW); + rh *= (int) (CleanYfac * 200.0/script->resH); } if(xright) rx = SCREENWIDTH + rx; From 61d2a808d7d045b83fa68cee876751bb49c1d6b0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 25 May 2010 02:30:05 +0000 Subject: [PATCH 057/251] - Response file improvements: * Fixed: Trying to use a response file would result in infinite looping until memory was exhausted. * Fixed: Response files were read after coalescing file parameters, which would lead to non-coalesced parameters if the original command line and response file both had them. * You can now use more than one response file. * Response files can include other response files. SVN r2334 (trunk) --- src/d_main.cpp | 6 ++-- src/m_argv.cpp | 13 +++++++ src/m_argv.h | 1 + src/m_misc.cpp | 96 ++++++++++++++++++++++++++++++++------------------ src/tarray.h | 7 ++-- 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 0241ac251..fe560c3c3 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1753,12 +1753,15 @@ void D_DoomMain (void) #endif #endif + // Check response files before coalescing file parameters. + M_FindResponseFile (); + // Combine different file parameters with their pre-switch bits. Args->CollectFiles("-deh", ".deh"); Args->CollectFiles("-bex", ".bex"); Args->CollectFiles("-exec", ".cfg"); Args->CollectFiles("-playdemo", ".lmp"); - Args->CollectFiles("-file", NULL); // anythnig left goes after -file + Args->CollectFiles("-file", NULL); // anything left goes after -file PClass::StaticInit (); atterm (C_DeinitConsole); @@ -1769,7 +1772,6 @@ void D_DoomMain (void) rngseed = I_MakeRNGSeed(); FRandom::StaticClearRandom (); - M_FindResponseFile (); Printf ("M_LoadDefaults: Load system defaults.\n"); M_LoadDefaults (); // load before initing other systems diff --git a/src/m_argv.cpp b/src/m_argv.cpp index 5dbdc4d3d..e414ca367 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -302,6 +302,19 @@ void DArgs::AppendArgs(int argc, const FString *argv) } } +//=========================================================================== +// +// DArgs :: RemoveArg +// +// Removes a single argument from argv. +// +//=========================================================================== + +void DArgs::RemoveArg(int argindex) +{ + Argv.Delete(argindex); +} + //=========================================================================== // // DArgs :: CollectFiles diff --git a/src/m_argv.h b/src/m_argv.h index b2a432edb..8b4fbf2dc 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -53,6 +53,7 @@ public: void AppendArg(FString arg); void AppendArgs(int argc, const FString *argv); + void RemoveArg(int argindex); void SetArgs(int argc, char **argv); void CollectFiles(const char *param, const char *extension); DArgs *GatherFiles(const char *param) const; diff --git a/src/m_misc.cpp b/src/m_misc.cpp index c828a965a..1f8b9f3e6 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -150,40 +150,54 @@ int M_ReadFile (char const *name, BYTE **buffer) void M_FindResponseFile (void) { - int i; + const int limit = 100; // avoid infinite recursion + int added_stuff = 0; + int i = 1; - for (i = 1; i < Args->NumArgs(); i++) + while (i < Args->NumArgs()) { - if (Args->GetArg(i)[0] == '@') + if (Args->GetArg(i)[0] != '@') + { + i++; + } + else { char **argv; - char *file; - int argc; + char *file = NULL; + int argc = 0; FILE *handle; int size; long argsize; - int k; int index; - // READ THE RESPONSE FILE INTO MEMORY - handle = fopen (Args->GetArg(i) + 1,"rb"); - if (!handle) - { // [RH] Make this a warning, not an error. - Printf ("No such response file (%s)!", Args->GetArg(i) + 1); - continue; + // Any more response files after the limit will be removed from the + // command line. + if (added_stuff < limit) + { + // READ THE RESPONSE FILE INTO MEMORY + handle = fopen (Args->GetArg(i) + 1,"rb"); + if (!handle) + { // [RH] Make this a warning, not an error. + Printf ("No such response file (%s)!\n", Args->GetArg(i) + 1); + } + else + { + Printf ("Found response file %s!\n", Args->GetArg(i) + 1); + fseek (handle, 0, SEEK_END); + size = ftell (handle); + fseek (handle, 0, SEEK_SET); + file = new char[size+1]; + fread (file, size, 1, handle); + file[size] = 0; + fclose (handle); + + argsize = ParseCommandLine (file, &argc, NULL); + } + } + else + { + Printf ("Ignored response file %s.\n", Args->GetArg(i) + 1); } - - Printf ("Found response file %s!\n", Args->GetArg(i) + 1); - fseek (handle, 0, SEEK_END); - size = ftell (handle); - fseek (handle, 0, SEEK_SET); - file = new char[size+1]; - fread (file, size, 1, handle); - file[size] = 0; - fclose (handle); - - argsize = ParseCommandLine (file, &argc, NULL); - argc = Args->NumArgs() - 1; if (argc != 0) { @@ -199,27 +213,39 @@ void M_FindResponseFile (void) newargs->AppendArg(Args->GetArg(index)); // Copy parameters from response file. - for (index = 0; index < argc; ++i) + for (index = 0; index < argc; ++index) newargs->AppendArg(argv[index]); // Copy parameters after response file. - for (index = i + 1, i = newargs->NumArgs(); index < Args->NumArgs(); ++index) + for (index = i + 1; index < Args->NumArgs(); ++index) newargs->AppendArg(Args->GetArg(index)); // Use the new argument vector as the global Args object. Args = newargs; + if (++added_stuff == limit) + { + Printf("Response file limit of %d hit.\n", limit); + } + } + else + { + // Remove the response file from the Args object + Args->RemoveArg(i); + } + if (file != NULL) + { + delete[] file; } - - delete[] file; - - // DISPLAY ARGS - Printf ("%d command-line args:\n", Args->NumArgs ()); - for (k = 1; k < Args->NumArgs (); k++) - Printf ("%s\n", Args->GetArg (k)); - - break; } } + if (added_stuff > 0) + { + // DISPLAY ARGS + Printf ("Added %d response file%s, now have %d command-line args:\n", + added_stuff, added_stuff > 1 ? "s" : "", Args->NumArgs ()); + for (int k = 1; k < Args->NumArgs (); k++) + Printf ("%s\n", Args->GetArg (k)); + } } // ParseCommandLine diff --git a/src/tarray.h b/src/tarray.h index f93636f99..09d092e00 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -159,10 +159,13 @@ public: void Delete (unsigned int index, int deletecount) { - if (index + deletecount > Count) deletecount = Count - index; + if (index + deletecount > Count) + { + deletecount = Count - index; + } if (deletecount > 0) { - for(int i = 0; i < deletecount; i++) + for (int i = 0; i < deletecount; i++) { Array[index + i].~T(); } From 709414e6066c4e3512de9d0fa40089a1db9cfb13 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 25 May 2010 03:40:37 +0000 Subject: [PATCH 058/251] - Fixed: Animated doors should only leave ML_BLOCKING set if the door was created with it set. Otherwise, monsters will be unable to open it after it has been used once if it isn't set for push activation. SVN r2336 (trunk) --- src/doomdata.h | 2 +- src/p_doors.cpp | 21 +++++++++++++++++++++ src/p_map.cpp | 19 ++++++++++--------- src/p_spec.h | 1 + 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/doomdata.h b/src/doomdata.h index 028ae5512..859246261 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -139,7 +139,7 @@ enum ELineFlags ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally) // Extended flags - ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can active the line + ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line ML_BLOCK_PLAYERS = 0x00004000, ML_BLOCKEVERYTHING = 0x00008000, // [RH] Line blocks everything ML_ZONEBOUNDARY = 0x00010000, diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 29ec1fc6b..ccfd61c5d 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -626,6 +626,17 @@ void DAnimatedDoor::Tick () MoveCeiling (2048*FRACUNIT, m_BotDist, -1); m_Sector->ceilingdata = NULL; Destroy (); + // Unset blocking flags on lines that didn't start with them. Since the + // ceiling is down now, we shouldn't need this flag anymore to keep things + // from getting through. + if (!m_SetBlocking1) + { + m_Line1->flags &= ~ML_BLOCKING; + } + if (!m_SetBlocking2) + { + m_Line2->flags &= ~ML_BLOCKING; + } break; } else @@ -668,6 +679,14 @@ void DAnimatedDoor::Serialize (FArchive &arc) << m_Speed << m_Delay << basetex; + if (SaveVersion < 2336) + { + m_SetBlocking1 = m_SetBlocking2 = true; + } + else + { + arc << m_SetBlocking1 << m_SetBlocking2; + } if (arc.IsLoading()) { @@ -727,6 +746,8 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay) m_Delay = delay; m_Timer = m_Speed; m_Frame = 0; + m_SetBlocking1 = !!(m_Line1->flags & ML_BLOCKING); + m_SetBlocking2 = !!(m_Line2->flags & ML_BLOCKING); m_Line1->flags |= ML_BLOCKING; m_Line2->flags |= ML_BLOCKING; m_BotDist = m_Sector->ceilingplane.d; diff --git a/src/p_map.cpp b/src/p_map.cpp index 9ff863e2b..09d1f944a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -620,16 +620,17 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm) return false; } - // MBF bouncers are treated as missiles here. - bool Projectile = (tm.thing->flags & MF_MISSILE || tm.thing->BounceFlags & BOUNCE_MBF); - // MBF considers that friendly monsters are not blocked by monster-blocking lines. - // This is added here as a compatibility option. Note that monsters that are dehacked - // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this - // just optionally generalizes the behavior to other friendly monsters. - bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) - || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); + // MBF bouncers are treated as missiles here. + bool Projectile = (tm.thing->flags & MF_MISSILE || tm.thing->BounceFlags & BOUNCE_MBF); + // MBF considers that friendly monsters are not blocked by monster-blocking lines. + // This is added here as a compatibility option. Note that monsters that are dehacked + // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this + // just optionally generalizes the behavior to other friendly monsters. + bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) + || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); - if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING|ML_BLOCKPROJECTILE))) { + if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING|ML_BLOCKPROJECTILE))) + { if (ld->flags & ML_RAILING) { rail = true; diff --git a/src/p_spec.h b/src/p_spec.h index ca0d9492c..ca3694c09 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -640,6 +640,7 @@ protected: }; int m_Speed; int m_Delay; + bool m_SetBlocking1, m_SetBlocking2; friend bool EV_SlidingDoor (line_t *line, AActor *thing, int tag, int speed, int delay); private: From 4480a508b316644ad9f4c55a68b8b81a3665b3c5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 25 May 2010 03:53:13 +0000 Subject: [PATCH 059/251] - Changed AActor::GetTag() to use language lookups for strings that start with $. SVN r2337 (trunk) --- src/p_mobj.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2e85dfc68..f12180ff8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -60,6 +60,7 @@ #include "colormatcher.h" #include "v_palette.h" #include "p_enemy.h" +#include "gstrings.h" // MACROS ------------------------------------------------------------------ @@ -5561,9 +5562,26 @@ bool AActor::IsSentient() const const char *AActor::GetTag(const char *def) const { - if (Tag != NAME_None) return Tag.GetChars(); - else if (def) return def; - else return GetClass()->TypeName.GetChars(); + if (Tag != NAME_None) + { + const char *tag = Tag.GetChars(); + if (tag[0] == '$') + { + return GStrings(tag + 1); + } + else + { + return tag; + } + } + else if (def) + { + return def; + } + else + { + return GetClass()->TypeName.GetChars(); + } } From 2b211f99a8c670684cdb0477149c4b29782125f5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 25 May 2010 20:19:09 +0000 Subject: [PATCH 060/251] - fixed: The intermission text screen background should not animate SVN r2338 (trunk) --- src/f_finale.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.cpp b/src/f_finale.cpp index 2b9fc8773..b0c806b67 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -1226,7 +1226,7 @@ void F_Drawer (void) FTextureID picnum = TexMan.CheckForTexture (FinaleFlat, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); if (picnum.isValid()) { - screen->FlatFill (0,0, SCREENWIDTH, SCREENHEIGHT, TexMan(picnum)); + screen->FlatFill (0,0, SCREENWIDTH, SCREENHEIGHT, TexMan[picnum]); } else { From 9dfdf2ecddc4af875abfd147217fec2ac693038a Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 26 May 2010 00:51:06 +0000 Subject: [PATCH 061/251] - Fixed some issues with high resolution status bars. SVN r2339 (trunk) --- src/g_shared/sbarinfo.cpp | 121 ++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 1d5f5ed34..db1ddb387 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -59,16 +59,6 @@ #include "p_acs.h" #include "gstrings.h" -#define ADJUST_RELCENTER(x, y, outX, outY) \ - if(x.RelCenter()) \ - outX = *x + SCREENWIDTH/(hud_scale ? CleanXfac*2 : 2); \ - else \ - outX = *x; \ - if(y.RelCenter()) \ - outY = *y + SCREENHEIGHT/(hud_scale ? CleanYfac*2 : 2); \ - else \ - outY = *y; - #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum { @@ -910,6 +900,18 @@ void Popup::close() //////////////////////////////////////////////////////////////////////////////// +inline void adjustRelCenter(const SBarInfoCoordinate &x, const SBarInfoCoordinate &y, int &outX, int &outY, const double &xScale, const double &yScale) +{ + if(x.RelCenter()) + outX = *x + (int) (SCREENWIDTH/(hud_scale ? xScale*2 : 2)); + else + outX = *x; + if(y.RelCenter()) + outY = *y + (int) (SCREENHEIGHT/(hud_scale ? yScale*2 : 2)); + else + outY = *y; +} + class DSBarInfo : public DBaseStatusBar { DECLARE_CLASS(DSBarInfo, DBaseStatusBar) @@ -1189,7 +1191,11 @@ public: else { int rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; - ADJUST_RELCENTER(x,y,rx,ry) + + double xScale = !hud_scale ? 1.0 : (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; + double yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH; + + adjustRelCenter(x, y, rx, ry, xScale, yScale); // We can't use DTA_HUDRules since it forces a width and height. // Translation: No high res. @@ -1202,10 +1208,10 @@ public: ry += 10; if(hud_scale) { - rx *= (int) (CleanXfac * 320.0/script->resW); - ry *= (int) (CleanYfac * 200.0/script->resH); - w *= (int) (CleanXfac * 320.0/script->resW); - h *= (int) (CleanYfac * 200.0/script->resH); + rx = (int) (rx*xScale); + ry = (int) (ry*yScale); + w = (int) (w*xScale); + h = (int) (h*yScale); } if(xright) rx = SCREENWIDTH + rx; @@ -1215,12 +1221,13 @@ public: // Check for clipping if(cx != 0 || cy != 0 || cr != 0 || cb != 0) { - rcx = cx == 0 ? 0 : rx+(cx>>FRACBITS); - rcy = cy == 0 ? 0 : ry+(cy>>FRACBITS); - rcr = cr == 0 ? INT_MAX : rx+w-(cr>>FRACBITS); - rcb = cb == 0 ? INT_MAX : ry+h-(cb>>FRACBITS); + rcx = cx == 0 ? 0 : rx+(int) ((cx>>FRACBITS)*xScale); + rcy = cy == 0 ? 0 : ry+(int) ((cy>>FRACBITS)*yScale); + rcr = cr == 0 ? INT_MAX : rx+w-(int) ((cr>>FRACBITS)*xScale); + rcb = cb == 0 ? INT_MAX : ry+h-(int) ((cb>>FRACBITS)*yScale); + // Fix the clipping for fullscreenoffsets. - if(ry < 0) + /*if(ry < 0) { if(rcy != 0) rcy = hud_scale ? SCREENHEIGHT + (int) (rcy*CleanYfac*200.0/script->resH) : SCREENHEIGHT + rcy; @@ -1245,7 +1252,7 @@ public: rcx *= (int) (CleanXfac*320.0/script->resW); if(rcr != INT_MAX) rcr *= (int) (CleanXfac*320.0/script->resW); - } + }*/ } if(clearDontDraw) @@ -1295,9 +1302,18 @@ public: x += spacing; int ax = *x; int ay = *y; + + double xScale = 1.0; + double yScale = 1.0; + if(fullScreenOffsets) { - ADJUST_RELCENTER(x,y,ax,ay) + if(hud_scale) + { + xScale = (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; + yScale = (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENWIDTH/(double) script->resW; + } + adjustRelCenter(x, y, ax, ay, xScale, yScale); } while(*str != '\0') { @@ -1341,63 +1357,38 @@ public: { if(vid_fps && ax < 0 && ay >= 0) ry += 10; - } - if(drawshadow) - { - int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); - if(!fullScreenOffsets) - { - screen->DrawTexture(character, rx+2, ry+2, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Alpha, salpha, - DTA_FillColor, 0, - TAG_DONE); - } - else - { - screen->DrawTexture(character, rx+2, ry+2, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Alpha, salpha, - DTA_HUDRules, HUD_Normal, - DTA_FillColor, 0, - TAG_DONE); - } - } - if(!fullScreenOffsets) - { - screen->DrawTexture(character, rx, ry, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Translation, font->GetColorTranslation(translation), - DTA_Alpha, alpha, - TAG_DONE); - } - else - { + bool xright = rx < 0; bool ybot = ry < 0; if(hud_scale) { - rx *= (int) (CleanXfac * 320.0/script->resW); - ry *= (int) (CleanYfac * 200.0/script->resH); - rw *= (int) (CleanXfac * 320.0/script->resW); - rh *= (int) (CleanYfac * 200.0/script->resH); + rx = (int) (rx*xScale); + ry = (int) (ry*yScale); + rw = (int) (rw*xScale); + rh = (int) (rh*yScale); } if(xright) rx = SCREENWIDTH + rx; if(ybot) ry = SCREENHEIGHT + ry; - - screen->DrawTexture(character, rx, ry, + } + if(drawshadow) + { + int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); + screen->DrawTexture(character, rx+2, ry+2, DTA_DestWidth, rw, DTA_DestHeight, rh, - DTA_Translation, font->GetColorTranslation(translation), - DTA_Alpha, alpha, + DTA_Alpha, salpha, + DTA_FillColor, 0, TAG_DONE); } + screen->DrawTexture(character, rx, ry, + DTA_DestWidth, rw, + DTA_DestHeight, rh, + DTA_Translation, font->GetColorTranslation(translation), + DTA_Alpha, alpha, + TAG_DONE); if(script->spacingCharacter == '\0') ax += width + spacing - (character->LeftOffset+1); else //width gets changed at the call to GetChar() From 8f881be0fb18dad093eb803ff2fcf25f86bcabba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 28 May 2010 11:15:05 +0000 Subject: [PATCH 062/251] - added a Boom (strict) compatibility mode. - Restored some original Doom behavior that received complaints from users: * reactivated the old sliding against diagonal walls code and compatibility optioned it with COMPATF_WALLRUN. * re-added the original hitscan checking code using a cross-section of the actor instead of the bounding box, compatibility optioned with COMPATF_HITSCAN. SVN r2340 (trunk) --- src/compatibility.cpp | 1 + src/d_main.cpp | 9 ++- src/doomdef.h | 1 + src/m_options.cpp | 8 +- src/p_map.cpp | 79 ++++++++++--------- src/p_maputl.cpp | 173 ++++++++++++++++++++++++++++-------------- 6 files changed, 171 insertions(+), 100 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 994a34b44..75729ff61 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -116,6 +116,7 @@ static FCompatOption Options[] = { "corpsegibs", COMPATF_CORPSEGIBS, 0 }, { "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 }, { "spritesort", COMPATF_SPRITESORT, 0 }, + { "hitscan", COMPATF_HITSCAN, 0 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index fe560c3c3..ceba6cfff 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -500,7 +500,8 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set) v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT| COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN| - COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS; + COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS|COMPATF_HITSCAN| + COMPATF_WALLRUN|COMPATF_NOTOSSDROPS; break; case 3: // Boom compat mode @@ -516,6 +517,11 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS; break; + case 6: // Boom with some added settings to reenable spme 'broken' behavior + v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_NO_PASSMOBJ| + COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS; + break; + } compatflags = v; } @@ -548,6 +554,7 @@ CVAR (Flag, compat_mbfmonstermove,compatflags, COMPATF_MBFMONSTERMOVE); CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS); CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS); CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT); +CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 42636f9cb..bfba79a2d 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -325,6 +325,7 @@ enum COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs. COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines. COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance + COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/m_options.cpp b/src/m_options.cpp index 50d7966cd..a71b58025 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -149,13 +149,14 @@ value_t OffOn[2] = { { 1.0, "Off" } }; -value_t CompatModes[6] = { +value_t CompatModes[] = { { 0.0, "Default" }, { 1.0, "Doom" }, { 2.0, "Doom (strict)" }, { 3.0, "Boom" }, - { 4.0, "ZDoom 2.0.63" }, + { 6.0, "Boom (strict)" }, { 5.0, "MBF" }, + { 4.0, "ZDoom 2.0.63" }, }; menu_t *CurrentMenu; @@ -1092,7 +1093,7 @@ static menu_t DMFlagsMenu = *=======================================*/ static menuitem_t CompatibilityItems[] = { - { discrete, "Compatibility mode", {&compatmode}, {6.0}, {1.0}, {0.0}, {CompatModes} }, + { discrete, "Compatibility mode", {&compatmode}, {7.0}, {1.0}, {0.0}, {CompatModes} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} }, { bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} }, @@ -1122,6 +1123,7 @@ static menuitem_t CompatibilityItems[] = { { bitflag, "Crushed monsters can be resurrected", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_CORPSEGIBS} }, { bitflag, "Friendly monsters aren't blocked", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOBLOCKFRIENDS} }, { bitflag, "Invert sprite sorting", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SPRITESORT} }, + { bitflag, "Use Doom code for hitscan checks", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_HITSCAN} }, { discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} }, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 09d1f944a..4e78227f5 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2183,48 +2183,53 @@ void FSlide::HitSlideLine (line_t* ld) } // ^ else // | { // phares -#if 0 - fixed_t newlen; - - if (deltaangle > ANG180) - deltaangle += ANG180; - // I_Error ("SlideLine: ang>ANG180"); - - lineangle >>= ANGLETOFINESHIFT; - deltaangle >>= ANGLETOFINESHIFT; - - newlen = FixedMul (movelen, finecosine[deltaangle]); - - tmxmove = FixedMul (newlen, finecosine[lineangle]); - tmymove = FixedMul (newlen, finesine[lineangle]); -#else - divline_t dll, dlv; - fixed_t inter1, inter2, inter3; - - P_MakeDivline (ld, &dll); - - dlv.x = slidemo->x; - dlv.y = slidemo->y; - dlv.dx = dll.dy; - dlv.dy = -dll.dx; - - inter1 = P_InterceptVector(&dll, &dlv); - - dlv.dx = tmxmove; - dlv.dy = tmymove; - inter2 = P_InterceptVector (&dll, &dlv); - inter3 = P_InterceptVector (&dlv, &dll); - - if (inter3 != 0) + // Doom's original algorithm here does not work well due to imprecisions of the sine table. + // However, keep it active if the wallrunning compatibility flag is on + if (i_compatflags & COMPATF_WALLRUN) { - tmxmove = Scale (inter2-inter1, dll.dx, inter3); - tmymove = Scale (inter2-inter1, dll.dy, inter3); + fixed_t newlen; + + if (deltaangle > ANG180) + deltaangle += ANG180; + // I_Error ("SlideLine: ang>ANG180"); + + lineangle >>= ANGLETOFINESHIFT; + deltaangle >>= ANGLETOFINESHIFT; + + newlen = FixedMul (movelen, finecosine[deltaangle]); + + tmxmove = FixedMul (newlen, finecosine[lineangle]); + tmymove = FixedMul (newlen, finesine[lineangle]); } else { - tmxmove = tmymove = 0; + divline_t dll, dlv; + fixed_t inter1, inter2, inter3; + + P_MakeDivline (ld, &dll); + + dlv.x = slidemo->x; + dlv.y = slidemo->y; + dlv.dx = dll.dy; + dlv.dy = -dll.dx; + + inter1 = P_InterceptVector(&dll, &dlv); + + dlv.dx = tmxmove; + dlv.dy = tmymove; + inter2 = P_InterceptVector (&dll, &dlv); + inter3 = P_InterceptVector (&dlv, &dll); + + if (inter3 != 0) + { + tmxmove = Scale (inter2-inter1, dll.dx, inter3); + tmymove = Scale (inter2-inter1, dll.dy, inter3); + } + else + { + tmxmove = tmymove = 0; + } } -#endif } // phares } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index d4ea1bdf9..fc0197183 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -970,81 +970,136 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it divline_t line; int i; - // [RH] Don't check a corner to corner crossection for hit. - // Instead, check against the actual bounding box. - // There's probably a smarter way to determine which two sides - // of the thing face the trace than by trying all four sides... - for (i = 0; i < 4; ++i) + if (!(i_compatflags & COMPATF_HITSCAN)) { - switch (i) + // [RH] Don't check a corner to corner crossection for hit. + // Instead, check against the actual bounding box (but not if compatibility optioned.) + + // There's probably a smarter way to determine which two sides + // of the thing face the trace than by trying all four sides... + for (i = 0; i < 4; ++i) { - case 0: // Top edge - line.x = thing->x + thing->radius; - line.y = thing->y + thing->radius; - line.dx = -thing->radius * 2; - line.dy = 0; - break; - - case 1: // Right edge - line.x = thing->x + thing->radius; - line.y = thing->y - thing->radius; - line.dx = 0; - line.dy = thing->radius * 2; - break; - - case 2: // Bottom edge - line.x = thing->x - thing->radius; - line.y = thing->y - thing->radius; - line.dx = thing->radius * 2; - line.dy = 0; - break; - - case 3: // Left edge - line.x = thing->x - thing->radius; - line.y = thing->y + thing->radius; - line.dx = 0; - line.dy = thing->radius * -2; - break; - } - // Check if this side is facing the trace origin - if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) - { - numfronts++; - - // If it is, see if the trace crosses it - if (P_PointOnDivlineSide (line.x, line.y, &trace) != - P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + switch (i) { - // It's a hit - fixed_t frac = P_InterceptVector (&trace, &line); - if (frac < 0) - { // behind source + case 0: // Top edge + line.x = thing->x + thing->radius; + line.y = thing->y + thing->radius; + line.dx = -thing->radius * 2; + line.dy = 0; + break; + + case 1: // Right edge + line.x = thing->x + thing->radius; + line.y = thing->y - thing->radius; + line.dx = 0; + line.dy = thing->radius * 2; + break; + + case 2: // Bottom edge + line.x = thing->x - thing->radius; + line.y = thing->y - thing->radius; + line.dx = thing->radius * 2; + line.dy = 0; + break; + + case 3: // Left edge + line.x = thing->x - thing->radius; + line.y = thing->y + thing->radius; + line.dx = 0; + line.dy = thing->radius * -2; + break; + } + // Check if this side is facing the trace origin + if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0) + { + numfronts++; + + // If it is, see if the trace crosses it + if (P_PointOnDivlineSide (line.x, line.y, &trace) != + P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace)) + { + // It's a hit + fixed_t frac = P_InterceptVector (&trace, &line); + if (frac < 0) + { // behind source + continue; + } + + intercept_t newintercept; + newintercept.frac = frac; + newintercept.isaline = false; + newintercept.done = false; + newintercept.d.thing = thing; + intercepts.Push (newintercept); continue; } + } + } + // If none of the sides was facing the trace, then the trace + // must have started inside the box, so add it as an intercept. + if (numfronts == 0) + { + intercept_t newintercept; + newintercept.frac = 0; + newintercept.isaline = false; + newintercept.done = false; + newintercept.d.thing = thing; + intercepts.Push (newintercept); + } + } + else + { + // Old code for compatibility purposes + fixed_t x1, y1, x2, y2; + int s1, s2; + divline_t dl; + fixed_t frac; + + bool tracepositive = (trace.dx ^ trace.dy)>0; + + // check a corner to corner crossection for hit + if (tracepositive) + { + x1 = thing->x - thing->radius; + y1 = thing->y + thing->radius; + + x2 = thing->x + thing->radius; + y2 = thing->y - thing->radius; + } + else + { + x1 = thing->x - thing->radius; + y1 = thing->y - thing->radius; + + x2 = thing->x + thing->radius; + y2 = thing->y + thing->radius; + } + + s1 = P_PointOnDivlineSide (x1, y1, &trace); + s2 = P_PointOnDivlineSide (x2, y2, &trace); + + if (s1 != s2) + { + dl.x = x1; + dl.y = y1; + dl.dx = x2-x1; + dl.dy = y2-y1; + + frac = P_InterceptVector (&trace, &dl); + + if (frac >= 0) + { intercept_t newintercept; newintercept.frac = frac; newintercept.isaline = false; newintercept.done = false; newintercept.d.thing = thing; intercepts.Push (newintercept); - continue; } } } - - // If none of the sides was facing the trace, then the trace - // must have started inside the box, so add it as an intercept. - if (numfronts == 0) - { - intercept_t newintercept; - newintercept.frac = 0; - newintercept.isaline = false; - newintercept.done = false; - newintercept.d.thing = thing; - intercepts.Push (newintercept); - } } } From 6c4d070095c3dfef557c081d0c34c4b307dae42f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 28 May 2010 21:07:45 +0000 Subject: [PATCH 063/251] - restored original Doom behavior for hitscans to only check actors which have their center in the blockmap cells being checked, compatibility optioned by COMPATF_HITSCAN. SVN r2341 (trunk) --- src/p_local.h | 5 ++- src/p_map.cpp | 15 +++---- src/p_maputl.cpp | 109 +++++++++++++++++++++++++++++------------------ src/p_setup.cpp | 20 --------- src/p_trace.cpp | 2 +- src/po_man.cpp | 8 ++-- 6 files changed, 83 insertions(+), 76 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index e42dc960d..fc9068cd0 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -292,7 +292,7 @@ class FBlockThingsIterator public: FBlockThingsIterator(int minx, int miny, int maxx, int maxy); FBlockThingsIterator(const FBoundingBox &box); - AActor *Next(); + AActor *Next(bool centeronly = false); void Reset() { StartBlock(minx, miny); } }; @@ -307,7 +307,7 @@ class FPathTraverse unsigned int count; void AddLineIntercepts(int bx, int by); - void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it); + void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); public: intercept_t *Next(); @@ -320,6 +320,7 @@ public: #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 +#define PT_COMPATIBLE 4 AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); AActor *P_RoughMonsterSearch (AActor *mo, int distance); diff --git a/src/p_map.cpp b/src/p_map.cpp index 4e78227f5..d13a12c3f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1276,10 +1276,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm) return true; // Check things first, possibly picking things up. - // The bounding box is extended by MAXRADIUS - // because DActors are grouped into mapblocks - // based on their origin point, and can overlap - // into adjacent blocks by up to MAXRADIUS units. thing->BlockingMobj = NULL; thingblocker = NULL; fakedblocker = NULL; @@ -2943,7 +2939,7 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in) void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target) { - FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS); + FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE); intercept_t *in; while ((in = it.Next())) @@ -3426,9 +3422,12 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, (t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD)); // Hit a thing, so it could be either a puff or blood - hitx = t1->x + FixedMul (vx, trace.Distance); - hity = t1->y + FixedMul (vy, trace.Distance); - hitz = shootz + FixedMul (vz, trace.Distance); + fixed_t dist = trace.Distance; + // position a bit closer for puffs/blood if using compatibility mode. + if (i_compatflags & COMPATF_HITSCAN) dist -= 10*FRACUNIT; + hitx = t1->x + FixedMul (vx, dist); + hity = t1->y + FixedMul (vy, dist); + hitz = shootz + FixedMul (vz, dist); // Spawn bullet puffs or blood spots, depending on target type. if ((puffDefaults->flags3 & MF3_PUFFONACTORS) || diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index fc0197183..14421fc50 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -825,7 +825,7 @@ void FBlockThingsIterator::SwitchBlock(int x, int y) // //=========================================================================== -AActor *FBlockThingsIterator::Next() +AActor *FBlockThingsIterator::Next(bool centeronly) { for (;;) { @@ -842,37 +842,55 @@ AActor *FBlockThingsIterator::Next() { // This actor doesn't span blocks, so we know it can only ever be checked once. return me; } - size_t hash = ((size_t)me >> 3) % countof(Buckets); - for (i = Buckets[hash]; i >= 0; ) + if (centeronly) { - entry = GetHashEntry(i); - if (entry->Actor == me) - { // I've already been checked. Skip to the next actor. - break; + // Block boundaries for compatibility mode + fixed_t blockleft = (curx << MAPBLOCKSHIFT) + bmaporgx; + fixed_t blockright = blockleft + MAPBLOCKSIZE; + fixed_t blockbottom = (cury << MAPBLOCKSHIFT) + bmaporgy; + fixed_t blocktop = blockbottom + MAPBLOCKSIZE; + + // only return actors with the center in this block + if (me->x >= blockleft && me->x < blockright && + me->y >= blockbottom && me->y < blocktop) + { + return me; } - i = entry->Next; } - if (i < 0) - { // Add me to the hash table and return me. - if (NumFixedHash < (int)countof(FixedHash)) + else + { + size_t hash = ((size_t)me >> 3) % countof(Buckets); + for (i = Buckets[hash]; i >= 0; ) { - entry = &FixedHash[NumFixedHash]; - entry->Next = Buckets[hash]; - Buckets[hash] = NumFixedHash++; - } - else - { - if (DynHash.Size() == 0) - { - DynHash.Grow(50); + entry = GetHashEntry(i); + if (entry->Actor == me) + { // I've already been checked. Skip to the next actor. + break; } - i = DynHash.Reserve(1); - entry = &DynHash[i]; - entry->Next = Buckets[hash]; - Buckets[hash] = i + countof(FixedHash); + i = entry->Next; + } + if (i < 0) + { // Add me to the hash table and return me. + if (NumFixedHash < (int)countof(FixedHash)) + { + entry = &FixedHash[NumFixedHash]; + entry->Next = Buckets[hash]; + Buckets[hash] = NumFixedHash++; + } + else + { + if (DynHash.Size() == 0) + { + DynHash.Grow(50); + } + i = DynHash.Reserve(1); + entry = &DynHash[i]; + entry->Next = Buckets[hash]; + Buckets[hash] = i + countof(FixedHash); + } + entry->Actor = me; + return me; } - entry->Actor = me; - return me; } } @@ -959,19 +977,19 @@ void FPathTraverse::AddLineIntercepts(int bx, int by) // //=========================================================================== -void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it) +void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it, bool compatible) { AActor *thing; it.SwitchBlock(bx, by); - while ((thing = it.Next())) + while ((thing = it.Next(compatible))) { int numfronts = 0; divline_t line; int i; - if (!(i_compatflags & COMPATF_HITSCAN)) + if (!compatible) { // [RH] Don't check a corner to corner crossection for hit. // Instead, check against the actual bounding box (but not if compatibility optioned.) @@ -1251,6 +1269,8 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in // from skipping the break statement. mapx = xt1; mapy = yt1; + + bool compatible = (flags & PT_COMPATIBLE) && (i_compatflags & COMPATF_HITSCAN); // we want to use one list of checked actors for the entire operation FBlockThingsIterator btit; @@ -1263,7 +1283,7 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in if (flags & PT_ADDTHINGS) { - AddThingIntercepts(mapx, mapy, btit); + AddThingIntercepts(mapx, mapy, btit, compatible); } if (mapx == xt2 && mapy == yt2) @@ -1293,21 +1313,28 @@ FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, in // being entered need to be checked (which will happen when this loop // continues), but the other two blocks adjacent to the corner also need to // be checked. - if (flags & PT_ADDLINES) + if (!compatible) { - AddLineIntercepts(mapx + mapxstep, mapy); - AddLineIntercepts(mapx, mapy + mapystep); + if (flags & PT_ADDLINES) + { + AddLineIntercepts(mapx + mapxstep, mapy); + AddLineIntercepts(mapx, mapy + mapystep); + } + + if (flags & PT_ADDTHINGS) + { + AddThingIntercepts(mapx + mapxstep, mapy, btit, false); + AddThingIntercepts(mapx, mapy + mapystep, btit, false); + } + xintercept += xstep; + yintercept += ystep; + mapx += mapxstep; + mapy += mapystep; } - - if (flags & PT_ADDTHINGS) + else { - AddThingIntercepts(mapx + mapxstep, mapy, btit); - AddThingIntercepts(mapx, mapy + mapystep, btit); + count = 100; // Doom originally did not handle this case so do the same in compatibility mode. } - xintercept += xstep; - yintercept += ystep; - mapx += mapxstep; - mapy += mapystep; break; } } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8c3f774d7..5efdac413 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3077,26 +3077,6 @@ static void P_GroupLines (bool buildmap) } } } -#if 0 - int block; - - // adjust bounding box to map blocks - block = (bbox.Top()-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; - block = block >= bmapheight ? bmapheight-1 : block; - //sector->blockbox.Top()=block; - - block = (bbox.Bottom()-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; - block = block < 0 ? 0 : block; - //sector->blockbox.Bottom()=block; - - block = (bbox.Right()-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; - block = block >= bmapwidth ? bmapwidth-1 : block; - //sector->blockbox.Right()=block; - - block = (bbox.Left()-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; - block = block < 0 ? 0 : block; - //sector->blockbox.Left()=block; -#endif } delete[] linesDoneInEachSector; times[3].Unclock(); diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 1f38cc694..bd00da36f 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -74,7 +74,7 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, int ptflags; FTraceInfo inf; - ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES; + ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES; inf.StartX = x; inf.StartY = y; diff --git a/src/po_man.cpp b/src/po_man.cpp index 13a5bda91..12e3f57ca 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1156,10 +1156,10 @@ static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po) ld = seg->linedef; - top = (ld->bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; - bottom = (ld->bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; - left = (ld->bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; - right = (ld->bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; + top = (ld->bbox[BOXTOP]-bmaporgy) >> MAPBLOCKSHIFT; + bottom = (ld->bbox[BOXBOTTOM]-bmaporgy) >> MAPBLOCKSHIFT; + left = (ld->bbox[BOXLEFT]-bmaporgx) >> MAPBLOCKSHIFT; + right = (ld->bbox[BOXRIGHT]-bmaporgx) >> MAPBLOCKSHIFT; blocked = false; checker.Clear(); From 862d6551bc01859ec56a60973cf97a505710c661 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 28 May 2010 21:29:28 +0000 Subject: [PATCH 064/251] - fixed: Heretic's 666 lower floor must be of type LowerToHighest unlike Doom which is LowerToLowest. SVN r2342 (trunk) --- src/g_level.h | 1 + src/g_mapinfo.cpp | 1 + src/p_enemy.cpp | 4 ++++ wadsrc/static/mapinfo/heretic.txt | 10 +++++----- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index d23536383..016e256c3 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -129,6 +129,7 @@ enum ELevelFlags LEVEL_SPECLOWERFLOOR = 0x00000100, LEVEL_SPECOPENDOOR = 0x00000200, + LEVEL_SPECLOWERFLOORTOHIGHEST= 0x00000300, LEVEL_SPECACTIONSMASK = 0x00000300, LEVEL_MONSTERSTELEFRAG = 0x00000400, diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index f8c087459..1014d1770 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1324,6 +1324,7 @@ MapFlagHandlers[] = { "specialaction_exitlevel", MITYPE_SCFLAGS, 0, ~LEVEL_SPECACTIONSMASK }, { "specialaction_opendoor", MITYPE_SCFLAGS, LEVEL_SPECOPENDOOR, ~LEVEL_SPECACTIONSMASK }, { "specialaction_lowerfloor", MITYPE_SCFLAGS, LEVEL_SPECLOWERFLOOR, ~LEVEL_SPECACTIONSMASK }, + { "specialaction_lowerfloortohighest",MITYPE_SCFLAGS,LEVEL_SPECLOWERFLOORTOHIGHEST, ~LEVEL_SPECACTIONSMASK }, { "specialaction_killmonsters", MITYPE_SETFLAG, LEVEL_SPECKILLMONSTERS, 0 }, { "lightning", MITYPE_SETFLAG, LEVEL_STARTLIGHTNING, 0 }, { "smoothlighting", MITYPE_SETFLAG2, LEVEL2_SMOOTHLIGHTING, 0 }, diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 1174119d8..d3ddd8ddd 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3160,6 +3160,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false); return; + case LEVEL_SPECLOWERFLOORTOHIGHEST: + EV_DoFloor (DFloor::floorLowerToHighest, NULL, 666, FRACUNIT, 0, 0, 0, false); + return; + case LEVEL_SPECOPENDOOR: EV_DoDoor (DDoor::doorOpen, NULL, NULL, 666, 8*FRACUNIT, 0, 0, 0); return; diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 955574891..1d3d63fd2 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -193,7 +193,7 @@ map E1M8 lookup "HHUSTR_E1M8" cluster = 1 nointermission ironlichspecial - specialaction_lowerfloor + specialaction_lowerfloortohighest music = "MUS_E1M8" } @@ -279,7 +279,7 @@ map E2M8 lookup "HHUSTR_E2M8" cluster = 2 nointermission minotaurspecial - specialaction_lowerfloor + specialaction_lowerfloortohighest specialaction_killmonsters music = "MUS_E2M8" } @@ -366,7 +366,7 @@ map E3M8 lookup "HHUSTR_E3M8" cluster = 3 nointermission dsparilspecial - specialaction_lowerfloor + specialaction_lowerfloortohighest specialaction_killmonsters music = "MUS_E1M9" } @@ -453,7 +453,7 @@ map E4M8 lookup "HHUSTR_E4M8" cluster = 4 nointermission ironlichspecial - specialaction_lowerfloor + specialaction_lowerfloortohighest specialaction_killmonsters music = "MUS_E1M8" } @@ -541,7 +541,7 @@ map E5M8 lookup "HHUSTR_E5M8" nointermission minotaurspecial specialaction_killmonsters - specialaction_lowerfloor + specialaction_lowerfloortohighest music = "MUS_E2M8" } From 042e913022e581093e7a7495de4c286f5fc0fbd4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 29 May 2010 07:07:39 +0000 Subject: [PATCH 065/251] - added Boom's fix for finding the highest neighboring light level per sector (compatibility optioned by COMPATF_LIGHT.) SVN r2343 (trunk) --- src/compatibility.cpp | 7 +- src/d_main.cpp | 8 ++- src/doomdef.h | 1 + src/g_mapinfo.cpp | 1 + src/m_options.cpp | 3 +- src/p_lights.cpp | 146 ++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 155 insertions(+), 11 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 75729ff61..b93cb68f2 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -117,6 +117,7 @@ static FCompatOption Options[] = { "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 }, { "spritesort", COMPATF_SPRITESORT, 0 }, { "hitscan", COMPATF_HITSCAN, 0 }, + { "lightlevel", COMPATF_LIGHT, 0 }, { NULL, 0, 0 } }; @@ -255,10 +256,12 @@ void CheckCompatibility(MapData *map) FMD5Holder md5; FCompatValues *flags; - // When playing Doom IWAD levels force COMPAT_SHORTTEX. + // When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT. + // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. + // TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD. if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && !(level.flags & LEVEL_HEXENFORMAT)) { - ii_compatflags = COMPATF_SHORTTEX; + ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT; if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX; ib_compatflags = 0; ii_compatparams = -1; diff --git a/src/d_main.cpp b/src/d_main.cpp index ceba6cfff..3b4341b28 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -494,14 +494,15 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 1: // Doom2.exe compatible with a few relaxed settings v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT| - COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_DEHHEALTH|COMPATF_CROSSDROPOFF; + COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_DEHHEALTH|COMPATF_CROSSDROPOFF| + COMPATF_LIGHT; break; case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set) v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT| COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN| COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS|COMPATF_HITSCAN| - COMPATF_WALLRUN|COMPATF_NOTOSSDROPS; + COMPATF_WALLRUN|COMPATF_NOTOSSDROPS|COMPATF_LIGHT; break; case 3: // Boom compat mode @@ -509,7 +510,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) break; case 4: // Old ZDoom compat mode - v = COMPATF_SOUNDTARGET; + v = COMPATF_SOUNDTARGET|COMPATF_LIGHT; break; case 5: // MBF compat mode @@ -555,6 +556,7 @@ CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS); CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS); CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT); CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN); +CVAR (Flag, compat_light, compatflags,COMPATF_LIGHT); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index bfba79a2d..061e2b2c4 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -326,6 +326,7 @@ enum COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines. COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. + COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 1014d1770..53cd9ee5c 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1400,6 +1400,7 @@ MapFlagHandlers[] = { "compat_corpsegibs", MITYPE_COMPATFLAG, COMPATF_CORPSEGIBS}, { "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS}, { "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT}, + { "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT}, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/m_options.cpp b/src/m_options.cpp index a71b58025..db09257aa 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1097,10 +1097,10 @@ static menuitem_t CompatibilityItems[] = { { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} }, { bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} }, + { bitflag, "Find neighboring light like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_LIGHT} }, { bitflag, "Limit Pain Elementals' Lost Souls", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_LIMITPAIN} }, { bitflag, "Don't let others hear your pickups", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SILENTPICKUP} }, { bitflag, "Actors are infinitely tall", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NO_PASSMOBJ} }, - { bitflag, "Cripple sound for silent BFG trick", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MAGICSILENCE} }, { bitflag, "Enable wall running", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_WALLRUN} }, { bitflag, "Spawn item drops on the floor", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOTOSSDROPS} }, { bitflag, "All special lines can block ", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_USEBLOCKING} }, @@ -1124,6 +1124,7 @@ static menuitem_t CompatibilityItems[] = { { bitflag, "Friendly monsters aren't blocked", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOBLOCKFRIENDS} }, { bitflag, "Invert sprite sorting", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SPRITESORT} }, { bitflag, "Use Doom code for hitscan checks", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_HITSCAN} }, + { bitflag, "Cripple sound for silent BFG trick", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MAGICSILENCE} }, { discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} }, }; diff --git a/src/p_lights.cpp b/src/p_lights.cpp index c33e27466..f437f4c7b 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -39,6 +39,12 @@ static FRandom pr_lightflash ("LightFlash"); static FRandom pr_strobeflash ("StrobeFlash"); static FRandom pr_fireflicker ("FireFlicker"); +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + IMPLEMENT_CLASS (DLighting) DLighting::DLighting () @@ -51,9 +57,11 @@ DLighting::DLighting (sector_t *sector) ChangeStatNum (STAT_LIGHT); } +//----------------------------------------------------------------------------- // // FIRELIGHT FLICKER // +//----------------------------------------------------------------------------- IMPLEMENT_CLASS (DFireFlicker) @@ -68,9 +76,12 @@ void DFireFlicker::Serialize (FArchive &arc) } +//----------------------------------------------------------------------------- // // T_FireFlicker // +//----------------------------------------------------------------------------- + void DFireFlicker::Tick () { int amount; @@ -89,9 +100,12 @@ void DFireFlicker::Tick () } } +//----------------------------------------------------------------------------- // // P_SpawnFireFlicker // +//----------------------------------------------------------------------------- + DFireFlicker::DFireFlicker (sector_t *sector) : DLighting (sector) { @@ -108,9 +122,12 @@ DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower) m_Count = 4; } +//----------------------------------------------------------------------------- // // [RH] flickering light like Hexen's // +//----------------------------------------------------------------------------- + IMPLEMENT_CLASS (DFlicker) DFlicker::DFlicker () @@ -123,6 +140,11 @@ void DFlicker::Serialize (FArchive &arc) arc << m_Count << m_MaxLight << m_MinLight; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- void DFlicker::Tick () { @@ -142,6 +164,12 @@ void DFlicker::Tick () } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + DFlicker::DFlicker (sector_t *sector, int upper, int lower) : DLighting (sector) { @@ -151,6 +179,12 @@ DFlicker::DFlicker (sector_t *sector, int upper, int lower) m_Count = (pr_flicker()&64)+1; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void EV_StartLightFlickering (int tag, int upper, int lower) { int secnum; @@ -163,9 +197,11 @@ void EV_StartLightFlickering (int tag, int upper, int lower) } +//----------------------------------------------------------------------------- // // BROKEN LIGHT FLASHING // +//----------------------------------------------------------------------------- IMPLEMENT_CLASS (DLightFlash) @@ -179,10 +215,13 @@ void DLightFlash::Serialize (FArchive &arc) arc << m_Count << m_MaxLight << m_MaxTime << m_MinLight << m_MinTime; } +//----------------------------------------------------------------------------- // // T_LightFlash // Do flashing lights. // +//----------------------------------------------------------------------------- + void DLightFlash::Tick () { if (--m_Count == 0) @@ -200,9 +239,12 @@ void DLightFlash::Tick () } } +//----------------------------------------------------------------------------- // // P_SpawnLightFlash // +//----------------------------------------------------------------------------- + DLightFlash::DLightFlash (sector_t *sector) : DLighting (sector) { @@ -226,9 +268,11 @@ DLightFlash::DLightFlash (sector_t *sector, int min, int max) } +//----------------------------------------------------------------------------- // // STROBE LIGHT FLASHING // +//----------------------------------------------------------------------------- IMPLEMENT_CLASS (DStrobe) @@ -242,9 +286,12 @@ void DStrobe::Serialize (FArchive &arc) arc << m_Count << m_MaxLight << m_MinLight << m_DarkTime << m_BrightTime; } +//----------------------------------------------------------------------------- // // T_StrobeFlash // +//----------------------------------------------------------------------------- + void DStrobe::Tick () { if (--m_Count == 0) @@ -262,9 +309,12 @@ void DStrobe::Tick () } } +//----------------------------------------------------------------------------- // // Hexen-style constructor // +//----------------------------------------------------------------------------- + DStrobe::DStrobe (sector_t *sector, int upper, int lower, int utics, int ltics) : DLighting (sector) { @@ -275,9 +325,12 @@ DStrobe::DStrobe (sector_t *sector, int upper, int lower, int utics, int ltics) m_Count = 1; // Hexen-style is always in sync } +//----------------------------------------------------------------------------- // // Doom-style constructor // +//----------------------------------------------------------------------------- + DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync) : DLighting (sector) { @@ -295,10 +348,13 @@ DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync) +//----------------------------------------------------------------------------- // // Start strobing lights (usually from a trigger) // [RH] Made it more configurable. // +//----------------------------------------------------------------------------- + void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics) { int secnum; @@ -330,10 +386,13 @@ void EV_StartLightStrobing (int tag, int utics, int ltics) } +//----------------------------------------------------------------------------- // // TURN LINE'S TAG LIGHTS OFF // [RH] Takes a tag instead of a line // +//----------------------------------------------------------------------------- + void EV_TurnTagLightsOff (int tag) { int i; @@ -358,10 +417,13 @@ void EV_TurnTagLightsOff (int tag) } +//----------------------------------------------------------------------------- // // TURN LINE'S TAG LIGHTS ON // [RH] Takes a tag instead of a line // +//----------------------------------------------------------------------------- + void EV_LightTurnOn (int tag, int bright) { int secnum = -1; @@ -370,6 +432,7 @@ void EV_LightTurnOn (int tag, int bright) while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) { sector_t *sector = sectors + secnum; + int tbright = bright; //jff 5/17/98 search for maximum PER sector // bright = -1 means to search ([RH] Not 0) // for highest light level @@ -378,7 +441,6 @@ void EV_LightTurnOn (int tag, int bright) { int j; - bright = 0; for (j = 0; j < sector->linecount; j++) { sector_t *temp = getNextSector (sector->lines[j], sector); @@ -386,14 +448,23 @@ void EV_LightTurnOn (int tag, int bright) if (!temp) continue; - if (temp->lightlevel > bright) - bright = temp->lightlevel; + if (temp->lightlevel > tbright) + tbright = temp->lightlevel; } } - sector->SetLightLevel(bright); + sector->SetLightLevel(tbright); + + //jff 5/17/98 unless compatibility optioned + //then maximum near ANY tagged sector + if (i_compatflags & COMPATF_LIGHT) + { + bright = tbright; + } } } +//----------------------------------------------------------------------------- +// // killough 10/98 // // EV_LightTurnOnPartway @@ -404,7 +475,7 @@ void EV_LightTurnOn (int tag, int bright) // Sets the light to min on 0, max on 1, and interpolates in-between. // Used for doors with gradual lighting effects. // -// Returns true +//----------------------------------------------------------------------------- void EV_LightTurnOnPartway (int tag, fixed_t frac) { @@ -438,11 +509,14 @@ void EV_LightTurnOnPartway (int tag, fixed_t frac) } +//----------------------------------------------------------------------------- // // [RH] New function to adjust tagged sectors' light levels // by a relative amount. Light levels are clipped to // within the range 0-255 inclusive. // +//----------------------------------------------------------------------------- + void EV_LightChange (int tag, int value) { int secnum = -1; @@ -455,9 +529,12 @@ void EV_LightChange (int tag, int value) } +//----------------------------------------------------------------------------- // // Spawn glowing light // +//----------------------------------------------------------------------------- + IMPLEMENT_CLASS (DGlow) DGlow::DGlow () @@ -470,6 +547,12 @@ void DGlow::Serialize (FArchive &arc) arc << m_Direction << m_MaxLight << m_MinLight; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void DGlow::Tick () { int newlight = m_Sector->lightlevel; @@ -499,6 +582,11 @@ void DGlow::Tick () m_Sector->SetLightLevel(newlight); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- DGlow::DGlow (sector_t *sector) : DLighting (sector) @@ -508,9 +596,11 @@ DGlow::DGlow (sector_t *sector) m_Direction = -1; } +//----------------------------------------------------------------------------- // // [RH] More glowing light, this time appropriate for Hexen-ish uses. // +//----------------------------------------------------------------------------- IMPLEMENT_CLASS (DGlow2) @@ -524,6 +614,12 @@ void DGlow2::Serialize (FArchive &arc) arc << m_End << m_MaxTics << m_OneShot << m_Start << m_Tics; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void DGlow2::Tick () { if (m_Tics++ >= m_MaxTics) @@ -546,6 +642,12 @@ void DGlow2::Tick () m_Sector->SetLightLevel(((m_End - m_Start) * m_Tics) / m_MaxTics + m_Start); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + DGlow2::DGlow2 (sector_t *sector, int start, int end, int tics, bool oneshot) : DLighting (sector) { @@ -556,6 +658,12 @@ DGlow2::DGlow2 (sector_t *sector, int start, int end, int tics, bool oneshot) m_OneShot = oneshot; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void EV_StartLightGlowing (int tag, int upper, int lower, int tics) { int secnum; @@ -584,6 +692,12 @@ void EV_StartLightGlowing (int tag, int upper, int lower, int tics) } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void EV_StartLightFading (int tag, int value, int tics) { int secnum; @@ -611,8 +725,12 @@ void EV_StartLightFading (int tag, int value, int tics) } +//----------------------------------------------------------------------------- +// // [RH] Phased lighting ala Hexen, but implemented without the help of the Hexen source // The effect is a little different, but close enough, I feel. +// +//----------------------------------------------------------------------------- IMPLEMENT_CLASS (DPhased) @@ -626,6 +744,12 @@ void DPhased::Serialize (FArchive &arc) arc << m_BaseLevel << m_Phase; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void DPhased::Tick () { const int steps = 12; @@ -644,6 +768,12 @@ void DPhased::Tick () m_Phase--; } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev) { if (!sector) @@ -675,6 +805,12 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + DPhased::DPhased (sector_t *sector, int baselevel) : DLighting (sector) { From cd1104e80c00b8ceb3889e8c83c5d7a3b99ea378 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 29 May 2010 09:11:12 +0000 Subject: [PATCH 066/251] - changed: Maps with missing first sidedefs no longer abort. THey now print a console warning and use the first sidedef in the map. SVN r2344 (trunk) --- src/p_setup.cpp | 20 ++++++++++++++++---- src/p_udmf.cpp | 5 +++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5efdac413..b19b64240 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1967,8 +1967,14 @@ void P_LoadLineDefs (MapData * map) } else { - if (LittleShort(mld->sidenum[0]) != NO_INDEX) - sidecount++; + // patch missing first sides instead of crashing out. + // Visual glitches are better than not being able to play. + if (LittleShort(mld->sidenum[0]) == NO_INDEX) + { + Printf("Line %d has no first side.\n", i); + mld->sidenum[0] = 0; + } + sidecount++; if (LittleShort(mld->sidenum[1]) != NO_INDEX) sidecount++; linemap[i] = i+skipped; @@ -2037,8 +2043,14 @@ void P_LoadLineDefs2 (MapData * map) } else { - if (LittleShort(mld->sidenum[0]) != NO_INDEX) - sidecount++; + // patch missing first sides instead of crashing out. + // Visual glitches are better than not being able to play. + if (LittleShort(mld->sidenum[0]) == NO_INDEX) + { + Printf("Line %d has no first side.\n", i); + mld->sidenum[0] = 0; + } + sidecount++; if (LittleShort(mld->sidenum[1]) != NO_INDEX) sidecount++; linemap[i] = i+skipped; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 33fb027a7..6cbfccbef 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -850,6 +850,11 @@ struct UDMFParser { ld->Alpha = FRACUNIT * 3/4; } + if (ld->sidedef[0] == NULL) + { + ld->sidedef[0] = (side_t*)(intptr_t)(1); + Printf("Line %d has no first side.\n", index); + } } //=========================================================================== From e848fa3c4c3e68de7e8aeb1d378dd8ef54c818e5 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 30 May 2010 00:12:46 +0000 Subject: [PATCH 067/251] - Switched SBarInfo to floating point math. SVN r2345 (trunk) --- src/g_shared/sbarinfo.cpp | 160 +++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 82 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index db1ddb387..72389c628 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -900,14 +900,14 @@ void Popup::close() //////////////////////////////////////////////////////////////////////////////// -inline void adjustRelCenter(const SBarInfoCoordinate &x, const SBarInfoCoordinate &y, int &outX, int &outY, const double &xScale, const double &yScale) +inline void adjustRelCenter(const SBarInfoCoordinate &x, const SBarInfoCoordinate &y, double &outX, double &outY, const double &xScale, const double &yScale) { if(x.RelCenter()) - outX = *x + (int) (SCREENWIDTH/(hud_scale ? xScale*2 : 2)); + outX = *x + (SCREENWIDTH/(hud_scale ? xScale*2 : 2)); else outX = *x; if(y.RelCenter()) - outY = *y + (int) (SCREENHEIGHT/(hud_scale ? yScale*2 : 2)); + outY = *y + (SCREENHEIGHT/(hud_scale ? yScale*2 : 2)); else outY = *y; } @@ -1110,59 +1110,57 @@ public: if (texture == NULL) return; + double dx = *x; + double dy = *y; + if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - x -= (texture->GetScaledWidth()/2)-texture->LeftOffset; - y -= (texture->GetScaledHeight()/2)-texture->TopOffset; + x -= (texture->GetScaledWidthDouble()/2.0)-texture->LeftOffset; + y -= (texture->GetScaledHeightDouble()/2.0)-texture->TopOffset; } x += xOffset; y += yOffset; - int w, h; + double w, h; if(!fullScreenOffsets) { - fixed_t tmp = 0; - // I'll handle the conversion from fixed to int myself for more control - fixed_t fx = (x + ST_X).Coordinate() << FRACBITS; - fixed_t fy = (y + ST_Y - (Scaled ? script->resH : 200) + script->height).Coordinate() << FRACBITS; - fixed_t fw = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth) << FRACBITS; - fixed_t fh = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight) << FRACBITS; - fixed_t fcx = cx == 0 ? 0 : fx + cx - (texture->GetScaledLeftOffset() << FRACBITS); - fixed_t fcy = cy == 0 ? 0 : fy + cy - (texture->GetScaledTopOffset() << FRACBITS); - fixed_t fcr = fx + fw - cr; - fixed_t fcb = fy + fh - cb; + double tmp = 0; + dx += ST_X; + dy += ST_Y - (Scaled ? script->resH : 200) + script->height; + w = forceWidth < 0 ? texture->GetScaledWidth() : forceWidth; + h = forceHeight < 0 ? texture->GetScaledHeight() : forceHeight; + double dcx = cx == 0 ? 0 : dx + ((double) cx / FRACUNIT) - texture->GetScaledLeftOffsetDouble(); + double dcy = cy == 0 ? 0 : dy + ((double) cy / FRACUNIT) - texture->GetScaledTopOffsetDouble(); + double dcr = cr == 0 ? INT_MAX : dx + w - ((double) cr / FRACUNIT); + double dcb = cb == 0 ? INT_MAX : dy + h - ((double) cb / FRACUNIT); + if(Scaled) { if(cx != 0 || cy != 0) - screen->VirtualToRealCoordsFixed(fcx, fcy, tmp, tmp, script->resW, script->resH, true); + screen->VirtualToRealCoords(dcx, dcy, tmp, tmp, script->resW, script->resH, true); if(cr != 0 || cb != 0 || clearDontDraw) - screen->VirtualToRealCoordsFixed(fcr, fcb, tmp, tmp, script->resW, script->resH, true); - screen->VirtualToRealCoordsFixed(fx, fy, fw, fh, script->resW, script->resH, true); + screen->VirtualToRealCoords(dcr, dcb, tmp, tmp, script->resW, script->resH, true); + screen->VirtualToRealCoords(dx, dy, w, h, script->resW, script->resH, true); } else { - fy += (200 - script->resH)<resH)<resH)<resH; + dcy += 200 - script->resH; + dcb += 200 - script->resH; } - // Round to nearest - w = (fw + (FRACUNIT>>1)) >> FRACBITS; - h = (fh + (FRACUNIT>>1)) >> FRACBITS; - cr = cr != 0 ? fcr >> FRACBITS : INT_MAX; - cb = cb != 0 ? fcb >> FRACBITS : INT_MAX; if(clearDontDraw) - screen->Clear(MAX(fx, fcx)>>FRACBITS, MAX(fy, fcy)>>FRACBITS, fcr>>FRACBITS, fcb>>FRACBITS, GPalette.BlackIndex, 0); + screen->Clear(static_cast(MAX(dx, dcx)), static_cast(MAX(dy, dcy)), static_cast(dcr), static_cast(dcb), GPalette.BlackIndex, 0); else { if(alphaMap) { - screen->DrawTexture(texture, (fx >> FRACBITS), (fy >> FRACBITS), - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, fcx>>FRACBITS, - DTA_ClipTop, fcy>>FRACBITS, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, + screen->DrawTexture(texture, dx, dy, + DTA_DestWidthF, w, + DTA_DestHeightF, h, + DTA_ClipLeft, static_cast(dcx), + DTA_ClipTop, static_cast(dcy), + DTA_ClipRight, static_cast(dcr), + DTA_ClipBottom, static_cast(dcb), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, @@ -1173,13 +1171,13 @@ public: } else { - screen->DrawTexture(texture, (fx >> FRACBITS), (fy >> FRACBITS), - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, fcx>>FRACBITS, - DTA_ClipTop, fcy>>FRACBITS, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, + screen->DrawTexture(texture, dx, dy, + DTA_DestWidthF, w, + DTA_DestHeightF, h, + DTA_ClipLeft, static_cast(dcx), + DTA_ClipTop, static_cast(dcy), + DTA_ClipRight, static_cast(dcr), + DTA_ClipBottom, static_cast(dcb), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, @@ -1190,7 +1188,7 @@ public: } else { - int rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; + double rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; double xScale = !hud_scale ? 1.0 : (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; double yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH; @@ -1202,16 +1200,16 @@ public: bool xright = rx < 0; bool ybot = ry < 0; - w = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth); - h = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight); + w = (forceWidth < 0 ? texture->GetScaledWidthDouble() : forceWidth); + h = (forceHeight < 0 ? texture->GetScaledHeightDouble() : forceHeight); if(vid_fps && rx < 0 && ry >= 0) ry += 10; if(hud_scale) { - rx = (int) (rx*xScale); - ry = (int) (ry*yScale); - w = (int) (w*xScale); - h = (int) (h*yScale); + rx *= xScale; + ry *= yScale; + w *= xScale; + h *= yScale; } if(xright) rx = SCREENWIDTH + rx; @@ -1221,10 +1219,10 @@ public: // Check for clipping if(cx != 0 || cy != 0 || cr != 0 || cb != 0) { - rcx = cx == 0 ? 0 : rx+(int) ((cx>>FRACBITS)*xScale); - rcy = cy == 0 ? 0 : ry+(int) ((cy>>FRACBITS)*yScale); - rcr = cr == 0 ? INT_MAX : rx+w-(int) ((cr>>FRACBITS)*xScale); - rcb = cb == 0 ? INT_MAX : ry+h-(int) ((cb>>FRACBITS)*yScale); + rcx = cx == 0 ? 0 : rx+(((double) cx/FRACUNIT)*xScale); + rcy = cy == 0 ? 0 : ry+(((double) cy/FRACUNIT)*yScale); + rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale); + rcb = cb == 0 ? INT_MAX : ry+h-(((double) cb/FRACUNIT)*yScale); // Fix the clipping for fullscreenoffsets. /*if(ry < 0) @@ -1256,20 +1254,18 @@ public: } if(clearDontDraw) - { - screen->Clear(rcx, rcy, MIN(rcr, w), MIN(rcb, h), GPalette.BlackIndex, 0); - } + screen->Clear(static_cast(rcx), static_cast(rcy), static_cast(MIN(rcr, w)), static_cast(MIN(rcb, h)), GPalette.BlackIndex, 0); else { if(alphaMap) { screen->DrawTexture(texture, rx, ry, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, rcx, - DTA_ClipTop, rcy, - DTA_ClipRight, rcr, - DTA_ClipBottom, rcb, + DTA_DestWidthF, w, + DTA_DestHeightF, h, + DTA_ClipLeft, static_cast(rcx), + DTA_ClipTop, static_cast(rcy), + DTA_ClipRight, static_cast(rcr), + DTA_ClipBottom, static_cast(rcb), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, @@ -1281,12 +1277,12 @@ public: else { screen->DrawTexture(texture, rx, ry, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, rcx, - DTA_ClipTop, rcy, - DTA_ClipRight, rcr, - DTA_ClipBottom, rcb, + DTA_DestWidthF, w, + DTA_DestHeightF, h, + DTA_ClipLeft, static_cast(rcx), + DTA_ClipTop, static_cast(rcy), + DTA_ClipRight, static_cast(rcr), + DTA_ClipBottom, static_cast(rcb), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, @@ -1300,8 +1296,8 @@ public: void DrawString(FFont *font, const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool drawshadow=false) const { x += spacing; - int ax = *x; - int ay = *y; + double ax = *x; + double ay = *y; double xScale = 1.0; double yScale = 1.0; @@ -1337,17 +1333,17 @@ public: if(script->spacingCharacter == '\0') //If we are monospaced lets use the offset ax += (character->LeftOffset+1); //ignore x offsets since we adapt to character size - int rx, ry, rw, rh; + double rx, ry, rw, rh; rx = ax + xOffset; ry = ay + yOffset; - rw = character->GetScaledWidth(); - rh = character->GetScaledHeight(); + rw = character->GetScaledWidthDouble(); + rh = character->GetScaledHeightDouble(); if(!fullScreenOffsets) { rx += ST_X; ry += ST_Y - (Scaled ? script->resH : 200) + script->height; if(Scaled) - screen->VirtualToRealCoordsInt(rx, ry, rw, rh, script->resW, script->resH, true); + screen->VirtualToRealCoords(rx, ry, rw, rh, script->resW, script->resH, true); else { ry += (200 - script->resH); @@ -1363,10 +1359,10 @@ public: if(hud_scale) { - rx = (int) (rx*xScale); - ry = (int) (ry*yScale); - rw = (int) (rw*xScale); - rh = (int) (rh*yScale); + rx *= xScale; + ry *= yScale; + rw *= xScale; + rh *= yScale; } if(xright) rx = SCREENWIDTH + rx; @@ -1377,15 +1373,15 @@ public: { int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); screen->DrawTexture(character, rx+2, ry+2, - DTA_DestWidth, rw, - DTA_DestHeight, rh, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, DTA_Alpha, salpha, DTA_FillColor, 0, TAG_DONE); } screen->DrawTexture(character, rx, ry, - DTA_DestWidth, rw, - DTA_DestHeight, rh, + DTA_DestWidthF, rw, + DTA_DestHeightF, rh, DTA_Translation, font->GetColorTranslation(translation), DTA_Alpha, alpha, TAG_DONE); From bdd2ebfe149a31013a437e4b350a5f50d682d598 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 30 May 2010 07:47:08 +0000 Subject: [PATCH 068/251] - added a new dmflag for allowing switching to weapons without ammo. SVN r2346 (trunk) --- src/d_main.cpp | 1 + src/doomdef.h | 1 + src/g_game.cpp | 3 ++- src/g_shared/a_pickups.h | 2 +- src/g_shared/a_weapons.cpp | 16 +++++++++++----- src/m_options.cpp | 1 + 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b4341b28..1fecffab9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -458,6 +458,7 @@ CVAR (Flag, sv_disallowspying, dmflags2, DF2_DISALLOW_SPYING); CVAR (Flag, sv_chasecam, dmflags2, DF2_CHASECAM); CVAR (Flag, sv_disallowsuicide, dmflags2, DF2_NOSUICIDE); CVAR (Flag, sv_noautoaim, dmflags2, DF2_NOAUTOAIM); +CVAR (Flag, sv_dontcheckammo, dmflags2, DF2_DONTCHECKAMMO); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 061e2b2c4..87216ae6b 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -292,6 +292,7 @@ enum DF2_CHASECAM = 1 << 21, // Players can use the chasecam cheat. DF2_NOSUICIDE = 1 << 22, // Players are allowed to suicide. DF2_NOAUTOAIM = 1 << 23, // Players cannot use autoaim. + DF2_DONTCHECKAMMO = 1 << 24, // Don't Check ammo when switching weapons. }; // [RH] Compatibility flags. diff --git a/src/g_game.cpp b/src/g_game.cpp index e9a4d4f1e..fc4a21772 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -288,7 +288,8 @@ CCMD (slot) if (slot < NUM_WEAPON_SLOTS) { - SendItemUse = players[consoleplayer].weapons.Slots[slot].PickWeapon (&players[consoleplayer]); + SendItemUse = players[consoleplayer].weapons.Slots[slot].PickWeapon (&players[consoleplayer], + !(dmflags2 & DF2_DONTCHECKAMMO)); } } } diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index b402fcf59..3afcbf5b7 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -21,7 +21,7 @@ public: bool AddWeapon (const char *type); bool AddWeapon (const PClass *type); void AddWeaponList (const char *list, bool clear); - AWeapon *PickWeapon (player_t *player); + AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } int LocateWeapon (const PClass *type); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index e02391640..e2aaab1c4 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -753,7 +753,7 @@ int FWeaponSlot::LocateWeapon(const PClass *type) // //=========================================================================== -AWeapon *FWeaponSlot::PickWeapon(player_t *player) +AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { int i, j; @@ -777,9 +777,12 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { - return weap; + if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) + { + return weap; + } } } } @@ -789,9 +792,12 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon)) && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { - return weap; + if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) + { + return weap; + } } } return player->ReadyWeapon; diff --git a/src/m_options.cpp b/src/m_options.cpp index db09257aa..7fcd0bdcf 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1047,6 +1047,7 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Automap allies", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_AUTOMAP_ALLIES} }, { bitflag, "Allow spying", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DISALLOW_SPYING} }, { bitflag, "Chasecam cheat", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_CHASECAM} }, + { bitflag, "Check ammo for weapon switch", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DONTCHECKAMMO} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, { whitetext,"Deathmatch Settings", {NULL}, {0}, {0}, {0}, {NULL} }, From 5535f98218ea00fe9a035a2e26c83ffa9681a3c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 30 May 2010 08:00:27 +0000 Subject: [PATCH 069/251] - fixed: The code drawing the chess pieces for Hexen's finale used floating point paeameters with integer fields for drawing the texture. SVN r2347 (trunk) --- src/f_finale.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/f_finale.cpp b/src/f_finale.cpp index b0c806b67..c37d1f459 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -1322,15 +1322,15 @@ void F_Drawer (void) if (multiplayer) { screen->DrawTexture (TexMan["CHESSALL"], 20, 0, - DTA_VirtualWidth, w, - DTA_VirtualHeight, h, TAG_DONE); + DTA_VirtualWidthF, w, + DTA_VirtualHeightF, h, TAG_DONE); } else if (players[consoleplayer].CurrentPlayerClass > 0) { picname = players[consoleplayer].CurrentPlayerClass == 1 ? "CHESSC" : "CHESSM"; screen->DrawTexture (TexMan[picname], 60, 0, - DTA_VirtualWidth, w, - DTA_VirtualHeight, h, TAG_DONE); + DTA_VirtualWidthF, w, + DTA_VirtualHeightF, h, TAG_DONE); } } } From 9716e1aea78a4f5b34f0cb87b689f53a18ff2c74 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 30 May 2010 18:34:59 +0000 Subject: [PATCH 070/251] - Changed DrawSelectedInventory's alternateonempty flag to draw the subblock before itself. This allows an else statement to be more useful in practice. - Fixed: Added offsets to the wrong variable in SBarInfo. SVN r2348 (trunk) --- src/g_shared/sbarinfo.cpp | 8 ++++---- src/g_shared/sbarinfo_commands.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 72389c628..1808308be 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1115,12 +1115,12 @@ public: if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - x -= (texture->GetScaledWidthDouble()/2.0)-texture->LeftOffset; - y -= (texture->GetScaledHeightDouble()/2.0)-texture->TopOffset; + dx -= (texture->GetScaledWidthDouble()/2.0)-texture->LeftOffset; + dy -= (texture->GetScaledHeightDouble()/2.0)-texture->TopOffset; } - x += xOffset; - y += yOffset; + dx += xOffset; + dy += yOffset; double w, h; if(!fullScreenOffsets) { diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index f5dcf198e..c107de090 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1202,6 +1202,9 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { + if(alternateOnEmpty) + SBarInfoCommandFlowControl::Draw(block, statusBar); + if(statusBar->CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) { if(artiflash && artiflashTick) @@ -1214,9 +1217,6 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private if(alwaysShowCounter || statusBar->CPlayer->mo->InvSel->Amount != 1) CommandDrawNumber::Draw(block, statusBar); } - - if(alternateOnEmpty) - SBarInfoCommandFlowControl::Draw(block, statusBar); } void Parse(FScanner &sc, bool fullScreenOffsets) { From 14b71ede1195684fa9a807d3200c0c7484ee63b1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 30 May 2010 19:23:53 +0000 Subject: [PATCH 071/251] - Added support for DRO version 2 files. SVN r2349 (trunk) --- src/oplsynth/opl_mus_player.cpp | 114 +++++++++++++++++++++++++------- src/oplsynth/opl_mus_player.h | 2 +- 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index befbaf535..31eef55fd 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -66,7 +66,7 @@ OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len) { if (fread (scoredata, 1, len, file) != (size_t)len) { - delete[] scoredata; +fail: delete[] scoredata; scoredata = NULL; return; } @@ -78,9 +78,7 @@ OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len) if (io->OPLinit (TwoChips + 1)) { - delete[] scoredata; - scoredata = NULL; - return; + goto fail; } // Check for RDosPlay raw OPL format @@ -96,12 +94,36 @@ OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len) } // Check for DosBox OPL dump else if (((DWORD *)scoredata)[0] == MAKE_ID('D','B','R','A') && - ((DWORD *)scoredata)[1] == MAKE_ID('W','O','P','L') && - ((DWORD *)scoredata)[2] == MAKE_ID(0,0,1,0)) + ((DWORD *)scoredata)[1] == MAKE_ID('W','O','P','L')) { - RawPlayer = DosBox; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - ScoreLen = MIN(len - 24, LittleLong(((DWORD *)scoredata)[4])); + if (((DWORD *)scoredata)[2] == MAKE_ID(0,0,1,0)) + { + RawPlayer = DosBox1; + SamplesPerTick = OPL_SAMPLE_RATE / 1000; + ScoreLen = MIN(len - 24, LittleLong(((DWORD *)scoredata)[4])) + 24; + } + else if (((DWORD *)scoredata)[2] == MAKE_ID(2,0,0,0)) + { + if (scoredata[20] != 0) + { + Printf("Unsupported DOSBox Raw OPL format %d\n", scoredata[20]); + goto fail; + } + if (scoredata[21] != 0) + { + Printf("Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]); + goto fail; + } + RawPlayer = DosBox2; + SamplesPerTick = OPL_SAMPLE_RATE / 1000; + int headersize = 0x1A + scoredata[0x19]; + ScoreLen = MIN(len - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize; + } + else + { + Printf("Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((WORD *)scoredata)[4]), LittleShort(((WORD *)scoredata)[5])); + goto fail; + } } // Check for modified IMF format (includes a header) else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') && @@ -131,6 +153,10 @@ OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len) ScoreLen = songlen + int(score - scoredata); } } + else + { + goto fail; + } Restart (); } @@ -159,18 +185,24 @@ void OPLmusicFile::Restart () { OPLmusicBlock::Restart(); WhichChip = 0; - if (RawPlayer == RDosPlay) + switch (RawPlayer) { + case RDosPlay: score = scoredata + 10; SamplesPerTick = LittleShort(*(WORD *)(scoredata + 8)) / ADLIB_CLOCK_MUL; - } - else if (RawPlayer == DosBox) - { + break; + + case DosBox1: score = scoredata + 24; SamplesPerTick = OPL_SAMPLE_RATE / 1000; - } - else if (RawPlayer == IMF) - { + break; + + case DosBox2: + score = scoredata + 0x1A + scoredata[0x19]; + SamplesPerTick = OPL_SAMPLE_RATE / 1000; + break; + + case IMF: score = scoredata + 6; // Skip track and game name @@ -183,6 +215,7 @@ void OPLmusicFile::Restart () { score += 4; // Skip song length } + break; } io->SetClockRate(SamplesPerTick); } @@ -331,9 +364,11 @@ void OPLmusicBlock::OffsetSamples(float *buff, int count) int OPLmusicFile::PlayTick () { BYTE reg, data; + WORD delay; - if (RawPlayer == RDosPlay) + switch (RawPlayer) { + case RDosPlay: while (score < scoredata + ScoreLen) { data = *score++; @@ -379,9 +414,9 @@ int OPLmusicFile::PlayTick () break; } } - } - else if (RawPlayer == DosBox) - { + break; + + case DosBox1: while (score < scoredata + ScoreLen) { reg = *score++; @@ -420,11 +455,42 @@ int OPLmusicFile::PlayTick () io->OPLwriteReg(WhichChip, reg, data); } } - } - else if (RawPlayer == IMF) - { - WORD delay = 0; + break; + case DosBox2: + { + BYTE *to_reg = scoredata + 0x1A; + BYTE to_reg_size = scoredata[0x19]; + BYTE short_delay_code = scoredata[0x17]; + BYTE long_delay_code = scoredata[0x18]; + + while (score < scoredata + ScoreLen) + { + BYTE code = *score++; + data = *score++; + + // Which OPL chip to write to is encoded in the high bit of the code value. + int which = !!(code & 0x80); + code &= 0x7F; + + if (code == short_delay_code) + { + return data + 1; + } + else if (code == long_delay_code) + { + return (data + 1) << 8; + } + else if (code < to_reg_size && (which = 0 || TwoChips)) + { + io->OPLwriteReg(which, to_reg[code], data); + } + } + } + break; + + case IMF: + delay = 0; while (delay == 0 && score + 4 - scoredata <= ScoreLen) { if (*(DWORD *)score == 0xFFFFFFFF) diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index 58cadc8b6..d1357e0e0 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -41,7 +41,7 @@ protected: OPLmusicFile() {} int PlayTick(); - enum { RDosPlay, IMF, DosBox } RawPlayer; + enum { RDosPlay, IMF, DosBox1, DosBox2 } RawPlayer; int ScoreLen; int WhichChip; }; From eadc539bc6b7b0090b7d0d0de0fcb70d4f51fdc3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 30 May 2010 20:12:32 +0000 Subject: [PATCH 072/251] - fixed: Poison clouds spawned by the PoisonShroom should not be pushable by the Disc of Repulsion. SVN r2350 (trunk) --- src/actor.h | 1 + src/p_map.cpp | 3 ++- src/thingdef/thingdef_data.cpp | 1 + wadsrc/static/actors/hexen/flechette.txt | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/actor.h b/src/actor.h index 243c57c90..9621ab733 100644 --- a/src/actor.h +++ b/src/actor.h @@ -319,6 +319,7 @@ enum MF6_NOTRIGGER = 0x00010000, // actor cannot trigger any line actions MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) + MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself // --- mobj.renderflags --- diff --git a/src/p_map.cpp b/src/p_map.cpp index d13a12c3f..4888f8479 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1149,7 +1149,8 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) } solid = (thing->flags & MF_SOLID) && !(thing->flags & MF_NOCLIP) && - (tm.thing->flags & MF_SOLID); + ((tm.thing->flags & MF_SOLID) || (tm.thing->flags6 & MF6_BLOCKEDBYSOLIDACTORS)); + // Check for special pickup if ((thing->flags & MF_SPECIAL) && (tm.thing->flags & MF_PICKUP) // [RH] The next condition is to compensate for the extra height diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 87ac4f198..7ebb680d8 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -224,6 +224,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF6, JUMPDOWN, AActor, flags6), DEFINE_FLAG(MF6, VULNERABLE, AActor, flags6), DEFINE_FLAG(MF6, NOTRIGGER, AActor, flags6), + DEFINE_FLAG(MF6, BLOCKEDBYSOLIDACTORS, AActor, flags6), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/wadsrc/static/actors/hexen/flechette.txt b/wadsrc/static/actors/hexen/flechette.txt index a0ad52268..4820a706d 100644 --- a/wadsrc/static/actors/hexen/flechette.txt +++ b/wadsrc/static/actors/hexen/flechette.txt @@ -142,7 +142,7 @@ ACTOR PoisonCloud native Mass 0x7fffffff +NOBLOCKMAP +NOGRAVITY +DROPOFF +NODAMAGETHRUST - +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT + +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT +BLOCKEDBYSOLIDACTORS RenderStyle Translucent Alpha 0.6 DeathSound "PoisonShroomDeath" From b8cb1f0cfbf68917bf922a1bcef0a9a62cf699b2 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 31 May 2010 07:01:04 +0000 Subject: [PATCH 073/251] - Fixed: The alpha property of status bars didn't work anymore. - Added: alpha command to SBarInfo which allows you to increase the translucency for certain parts of the status bar. - Added: reverse flag for drawkeybar which reverses the order in which rows are filled with keys. - Changed a gamemode statement to an else in the Doom hud since the frag count and keys should never be shown at the same time. SVN r2351 (trunk) --- src/g_shared/sbarinfo.cpp | 10 ++++--- src/g_shared/sbarinfo_commands.cpp | 46 +++++++++++++++++++++++++----- wadsrc/static/sbarinfo/doom.txt | 2 +- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 1808308be..bbd1f6c57 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -293,17 +293,18 @@ class SBarInfoMainBlock : public SBarInfoCommandFlowControl { public: SBarInfoMainBlock(SBarInfo *script) : SBarInfoCommandFlowControl(script), - alpha(FRACUNIT), forceScaled(false), fullScreenOffsets(false) + alpha(FRACUNIT), currentAlpha(FRACUNIT), forceScaled(false), + fullScreenOffsets(false) { SetTruth(true, NULL, NULL); } - int Alpha() const { return alpha; } + int Alpha() const { return currentAlpha; } void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, int xOffset, int yOffset, int alpha) { this->xOffset = xOffset; this->yOffset = yOffset; - this->alpha = alpha; + this->currentAlpha = fixed_t((((double) this->alpha / (double) FRACUNIT) * ((double) alpha / (double) FRACUNIT)) * FRACUNIT); SBarInfoCommandFlowControl::Draw(this, statusBar); } bool ForceScaled() const { return forceScaled; } @@ -336,8 +337,9 @@ class SBarInfoMainBlock : public SBarInfoCommandFlowControl int XOffset() const { return xOffset; } int YOffset() const { return yOffset; } - private: + protected: int alpha; + int currentAlpha; bool forceScaled; bool fullScreenOffsets; int xOffset; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index c107de090..ce68e6c6f 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1795,8 +1795,8 @@ class CommandDrawKeyBar : public SBarInfoCommand { public: CommandDrawKeyBar(SBarInfo *script) : SBarInfoCommand(script), - number(3), vertical(false), reverseRows(false), iconSize(-1), - rowIconSize(-1), keyOffset(0), rowSize(0) + number(3), vertical(false), reverse(false), reverseRows(false), + iconSize(-1), rowIconSize(-1), keyOffset(0), rowSize(0) { } @@ -1833,12 +1833,12 @@ class CommandDrawKeyBar : public SBarInfoCommand if(iconSize == -1) { if(!vertical) - slotOffset += TexMan[item->Icon]->GetScaledWidth() + 2; + slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledWidth() + 2); else - slotOffset += TexMan[item->Icon]->GetScaledHeight() + 2; + slotOffset += (reverse ? -1 : 1) * (TexMan[item->Icon]->GetScaledHeight() + 2); } else - slotOffset += iconSize; + slotOffset += (reverse ? -iconSize : iconSize); if(rowSize > 0 && (i % rowSize == rowSize-1)) { @@ -1871,6 +1871,8 @@ class CommandDrawKeyBar : public SBarInfoCommand { if(sc.Compare("reverserows")) reverseRows = true; + else if(sc.Compare("reverse")) + reverse = true; else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|')) @@ -1911,6 +1913,7 @@ class CommandDrawKeyBar : public SBarInfoCommand protected: unsigned int number; bool vertical; + bool reverse; bool reverseRows; int iconSize; int rowIconSize; @@ -2757,6 +2760,34 @@ class CommandInInventory : public SBarInfoCommandFlowControl //////////////////////////////////////////////////////////////////////////////// +class CommandAlpha : public SBarInfoMainBlock +{ + public: + CommandAlpha(SBarInfo *script) : SBarInfoMainBlock(script) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + forceScaled = block->ForceScaled(); + fullScreenOffsets = block->FullScreenOffsets(); + + SBarInfoMainBlock::Draw(block, statusBar, block->XOffset(), block->YOffset(), block->Alpha()); + } + + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_FloatConst); + alpha = fixed_t(FRACUNIT * sc.Float); + + // We don't want to allow all the options of a regular main block + // so skip to the SBarInfoCommandFlowControl. + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + static const char *SBarInfoCommandNames[] = { "drawimage", "drawnumber", "drawswitchableimage", @@ -2766,7 +2797,7 @@ static const char *SBarInfoCommandNames[] = "gamemode", "playerclass", "aspectratio", "isselected", "usesammo", "usessecondaryammo", "hasweaponpiece", "inventorybarnotvisible", - "weaponammo", "ininventory", + "weaponammo", "ininventory", "alpha", NULL }; @@ -2779,7 +2810,7 @@ enum SBarInfoCommands SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_ASPECTRATIO, SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO, SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE, - SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, + SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, }; SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) @@ -2810,6 +2841,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script); case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script); case SBARINFO_ININVENTORY: return new CommandInInventory(script); + case SBARINFO_ALPHA: return new CommandAlpha(script); } sc.ScriptError("Unknown command '%s'.\n", sc.String); diff --git a/wadsrc/static/sbarinfo/doom.txt b/wadsrc/static/sbarinfo/doom.txt index b46cffe3b..d80d0390b 100644 --- a/wadsrc/static/sbarinfo/doom.txt +++ b/wadsrc/static/sbarinfo/doom.txt @@ -58,7 +58,7 @@ statusbar fullscreen, fullscreenoffsets // ZDoom HUD { drawnumber 2147483647, HUDFONT_DOOM, untranslated, frags, drawshadow, -3, 1; } - gamemode singleplayer, cooperative, teamgame + else { // let's hope no mod ever uses 100 keys... drawkeybar 100, vertical, reverserows, auto, -10, 2, 0, 3, auto; From d29123c511f1f4b0d8dc79e61d9365e6f5680693 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 31 May 2010 20:04:49 +0000 Subject: [PATCH 074/251] - Added a HexenStrict DrawInventoryBar style due to some alignment errors I noticed with the Hexen style. SVN r2352 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 55 +++++++++++++++++++----------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index ce68e6c6f..13263a831 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1596,7 +1596,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand { public: CommandDrawInventoryBar(SBarInfo *script) : SBarInfoCommand(script), - style(GAME_Doom), size(7), alwaysShow(false), noArtibox(false), + style(STYLE_Doom), size(7), alwaysShow(false), noArtibox(false), noArrows(false), alwaysShowCounter(false), translucent(false), vertical(false), counters(NULL), font(NULL), translation(CR_GOLD), fontSpacing(0) @@ -1616,9 +1616,9 @@ class CommandDrawInventoryBar : public SBarInfoCommand { int spacing = 0; if(!vertical) - spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; + spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; else - spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; int bgalpha = block->Alpha(); if(translucent) @@ -1637,20 +1637,22 @@ class CommandDrawInventoryBar : public SBarInfoCommand if(!noArtibox) statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgARTIBOX], rx, ry, block->XOffset(), block->YOffset(), bgalpha, block->FullScreenOffsets()); - if(style != GAME_Strife) //Strife draws the cursor before the icons - statusBar->DrawGraphic(TexMan(item->Icon), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->Amount <= 0); + if(style != STYLE_Strife) //Strife draws the cursor before the icons + statusBar->DrawGraphic(TexMan(item->Icon), rx - (style == STYLE_HexenStrict ? 2 : 0), ry - (style == STYLE_HexenStrict ? 1 : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->Amount <= 0); if(item == statusBar->CPlayer->mo->InvSel) { - if(style == GAME_Heretic) + if(style == STYLE_Heretic) statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry+29, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - else if(style == GAME_Hexen) + else if(style == STYLE_Hexen) statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry-1, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - else if(style == GAME_Strife) + else if(style == STYLE_HexenStrict) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx-1, ry-1, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + else if(style == STYLE_Strife) statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgCURSOR], rx-6, ry-2, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); else statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } - if(style == GAME_Strife) + if(style == STYLE_Strife) statusBar->DrawGraphic(TexMan(item->Icon), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->Amount <= 0); if(counters != NULL && (alwaysShowCounter || item->Amount != 1)) { @@ -1664,16 +1666,18 @@ class CommandDrawInventoryBar : public SBarInfoCommand // Is there something to the left? if (!noArrows && statusBar->CPlayer->mo->FirstInv() != statusBar->CPlayer->mo->InvFirst) { - int offset = style != GAME_Strife ? -12 : 14; + int offset = (style != STYLE_Strife ? (style != STYLE_HexenStrict ? -12 : -10) : 14); + int yOffset = style != STYLE_HexenStrict ? 0 : -1; statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? - statusBar->invBarOffset + imgINVLFGEM1 : statusBar->invBarOffset + imgINVLFGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + statusBar->invBarOffset + imgINVLFGEM1 : statusBar->invBarOffset + imgINVLFGEM2], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } // Is there something to the right? if (!noArrows && item != NULL) { - int offset = style != GAME_Strife ? size*31+2 : size*35-4; + int offset = (style != STYLE_Strife ? (style != STYLE_HexenStrict ? size*31+2 : size*31) : size*35-4); + int yOffset = style != STYLE_HexenStrict ? 0 : -1; statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? - statusBar->invBarOffset + imgINVRTGEM1 : statusBar->invBarOffset + imgINVRTGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + statusBar->invBarOffset + imgINVRTGEM1 : statusBar->invBarOffset + imgINVRTGEM2], x + (!vertical ? offset : yOffset), y + (vertical ? offset : yOffset), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } } } @@ -1681,13 +1685,15 @@ class CommandDrawInventoryBar : public SBarInfoCommand { sc.MustGetToken(TK_Identifier); if(sc.Compare("Doom")) - style = GAME_Doom; + style = STYLE_Doom; else if(sc.Compare("Heretic")) - style = GAME_Heretic; + style = STYLE_Heretic; else if(sc.Compare("Hexen")) - style = GAME_Hexen; + style = STYLE_Hexen; + else if(sc.Compare("HexenStrict")) + style = STYLE_HexenStrict; else if(sc.Compare("Strife")) - style = GAME_Strife; + style = STYLE_Strife; else sc.ScriptError("Unknown style '%s'.", sc.String); @@ -1745,9 +1751,9 @@ class CommandDrawInventoryBar : public SBarInfoCommand { int spacing = 0; if(!vertical) - spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; + spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; else - spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; counters = new CommandDrawNumber*[size]; for(unsigned int i = 0;i < size;i++) @@ -1769,7 +1775,16 @@ class CommandDrawInventoryBar : public SBarInfoCommand counters[i]->Tick(block, statusBar, hudChanged); } protected: - int style; + enum Styles + { + STYLE_Doom, + STYLE_Heretic, + STYLE_Hexen, + STYLE_HexenStrict, + STYLE_Strife + }; + + Styles style; unsigned int size; bool alwaysShow; bool noArtibox; From d7686d0c26204497f32cc1f3920db6d7bca1c768 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 2 Jun 2010 20:26:27 +0000 Subject: [PATCH 075/251] - Added optional offset parameters to the drawshadow flag. - Added character alignment parameter to font monospacing. - Fixed: character shadows were not scaled. - Heretic keys now have an icon associated with them so that they can be drawn through drawkeybar. - Replaced the built in Heretic and Hexen status bars with SBarInfo equivalents. SVN r2353 (trunk) --- src/CMakeLists.txt | 2 - src/g_heretic/heretic_sbar.cpp | 795 ------------ src/g_hexen/hexen_sbar.cpp | 1194 ------------------ src/g_level.cpp | 20 +- src/g_shared/sbar.h | 2 - src/g_shared/sbarinfo.cpp | 51 +- src/g_shared/sbarinfo.h | 8 + src/g_shared/sbarinfo_commands.cpp | 31 +- wadsrc/static/actors/heretic/heretickeys.txt | 3 + wadsrc/static/animdefs.txt | 6 + wadsrc/static/mapinfo/heretic.txt | 2 +- wadsrc/static/mapinfo/hexen.txt | 2 +- wadsrc/static/sbarinfo/heretic.txt | 123 ++ wadsrc/static/sbarinfo/hexen.txt | 259 ++++ 14 files changed, 478 insertions(+), 2020 deletions(-) delete mode 100644 src/g_heretic/heretic_sbar.cpp delete mode 100644 src/g_hexen/hexen_sbar.cpp create mode 100755 wadsrc/static/sbarinfo/heretic.txt create mode 100755 wadsrc/static/sbarinfo/hexen.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b81095f3..31b3e1414 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -664,9 +664,7 @@ add_executable( zdoom WIN32 zstring.cpp g_doom/a_doommisc.cpp g_heretic/a_hereticmisc.cpp - g_heretic/heretic_sbar.cpp g_hexen/a_hexenmisc.cpp - g_hexen/hexen_sbar.cpp g_raven/a_artitele.cpp g_raven/a_minotaur.cpp g_strife/a_strifestuff.cpp diff --git a/src/g_heretic/heretic_sbar.cpp b/src/g_heretic/heretic_sbar.cpp deleted file mode 100644 index d9cabf2d5..000000000 --- a/src/g_heretic/heretic_sbar.cpp +++ /dev/null @@ -1,795 +0,0 @@ -#include - -#include "doomtype.h" -#include "doomstat.h" -#include "v_font.h" -#include "sbar.h" -#include "r_defs.h" -#include "w_wad.h" -#include "m_random.h" -#include "d_player.h" -#include "st_stuff.h" -#include "v_video.h" -#include "r_draw.h" -#include "templates.h" -#include "a_keys.h" -#include "r_translate.h" -#include "g_level.h" -#include "v_palette.h" - - -static FRandom pr_chainwiggle; - -// This texture is used to shade each end of the health chain -class FHereticShader : public FTexture -{ -public: - FHereticShader (); - - const BYTE *GetColumn (unsigned int column, const Span **spans_out); - const BYTE *GetPixels (); - void Unload (); - -private: - static const BYTE Pixels[10*16]; - static const Span DummySpan[2]; -}; - -static FHereticShader ChainShade; - -const FTexture::Span FHereticShader::DummySpan[2] = { { 0, 10 }, { 0, 0 } }; -const BYTE FHereticShader::Pixels[10*16] = -{ - 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, - 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -}; - -FHereticShader::FHereticShader () -{ - Width = 16; - Height = 10; - WidthBits = 4; - HeightBits = 4; - WidthMask = 15; -} - -void FHereticShader::Unload () -{ -} - -const BYTE *FHereticShader::GetColumn (unsigned int column, const Span **spans_out) -{ - if (spans_out != NULL) - { - *spans_out = DummySpan; - } - return Pixels + 10*(column & 15); -} - -const BYTE *FHereticShader::GetPixels () -{ - return Pixels; -} - - -class DHereticStatusBar : public DBaseStatusBar -{ - DECLARE_CLASS(DHereticStatusBar, DBaseStatusBar) - HAS_OBJECT_POINTERS -public: - DHereticStatusBar () : DBaseStatusBar (42) - { - static const char *hereticLumpNames[NUM_HERETICSB_IMAGES] = - { - "LTFACE", "RTFACE", "BARBACK", "INVBAR", "CHAIN", - NULL, "LIFEGEM2", "LTFCTOP", "RTFCTOP", "SELECTBO", - "INVGEML1", "INVGEML2", "INVGEMR1", "INVGEMR2", "BLACKSQ", - "ARMCLEAR", "CHAINBACK","GOD1", "GOD2", "USEARTIA", - "USEARTIB", "USEARTIC", "USEARTID", "YKEYICON", "GKEYICON", - "BKEYICON", "ARTIBOX", "PTN1A0", "PTN1B0", "PTN1C0" - }; - static const char *sharedLumpNames[] = - { - "LAME", "NEGNUM", "IN0", "IN1", "IN2", - "IN3", "IN4", "IN5", "IN6", "IN7", - "IN8", "IN9", "FONTB13", "FONTB16", "FONTB17", - "FONTB18", "FONTB19", "FONTB20", "FONTB21", "FONTB22", - "FONTB23", "FONTB24", "FONTB25", "SMALLIN0", "SMALLIN1", - "SMALLIN2", "SMALLIN3", "SMALLIN4", "SMALLIN5", "SMALLIN6", - "SMALLIN7", "SMALLIN8", "SMALLIN9" - }; - - if (deathmatch) - { - hereticLumpNames[5] = "STATBAR"; - } - else - { - hereticLumpNames[5] = "LIFEBAR"; - } - - DBaseStatusBar::Images.Init (sharedLumpNames, NUM_BASESB_IMAGES); - Images.Init (hereticLumpNames, NUM_HERETICSB_IMAGES); - - oldarti = NULL; - oldammo1 = oldammo2 = NULL; - oldammocount1 = oldammocount2 = -1; - oldartiCount = 0; - oldfrags = -9999; - oldarmor = -1; - oldhealth = -1; - oldlife = -1; - oldkeys = -1; - - HealthMarker = 0; - ChainWiggle = 0; - ArtifactFlash = 0; - } - - ~DHereticStatusBar () - { - } - - void Tick () - { - int curHealth; - - DBaseStatusBar::Tick (); - if (level.time & 1) - { - ChainWiggle = pr_chainwiggle() & 1; - } - curHealth = CPlayer->health; - if (curHealth < 0) - { - curHealth = 0; - } - if (curHealth < HealthMarker) - { - HealthMarker -= clamp ((HealthMarker - curHealth) >> 2, 1, 8); - } - else if (curHealth > HealthMarker) - { - HealthMarker += clamp ((curHealth - HealthMarker) >> 2, 1, 8); - } - - if (ArtifactFlash > 0) - { - if (--ArtifactFlash == 0) - { - ArtiRefresh = screen->GetPageCount (); - } - } - } - - void Draw (EHudState state) - { - DBaseStatusBar::Draw (state); - - if (state == HUD_Fullscreen) - { - DrawFullScreenStuff (); - SB_state = screen->GetPageCount (); - } - else if (state == HUD_StatusBar) - { - if (SB_state > 0) - { - DrawImage (Images[imgBARBACK], 0, 0); - if (CPlayer->cheats&CF_GODMODE) - { - DrawImage (Images[imgGOD1], 16, 9); - DrawImage (Images[imgGOD2], 287, 9); - } - oldhealth = -1; - } - DrawCommonBar (); - if (CPlayer->inventorytics == 0) - { - if (SB_state < 0) - { - SB_state = screen->GetPageCount (); - } - if (SB_state != 0) - { - // Main interface - SB_state--; - DrawImage (Images[imgSTATBAR], 34, 2); - oldarti = NULL; - oldammo1 = oldammo2 = NULL; - oldammocount1 = oldammocount2 = -1; - oldarmor = -1; - oldfrags = -9999; //can't use -1, 'cuz of negative frags - oldlife = -1; - oldkeys = -1; - oldhealth = -1; - ArtiRefresh = 0; - } - DrawMainBar (); - } - else - { - if (SB_state > -1) - { - SB_state = -screen->GetPageCount () - 1; - } - if (SB_state < -1) - { - SB_state++; - DrawImage (Images[imgINVBAR], 34, 2); - } - DrawInventoryBar (); - } - } - } - -private: -//--------------------------------------------------------------------------- -// -// PROC DrawCommonBar -// -//--------------------------------------------------------------------------- - - void DrawCommonBar () - { - int chainY; - int healthPos; - - DrawImage (Images[imgLTFCTOP], 0, -10); - //DrawImage (Images[imgRTFCTOP], 290, -10); - screen->DrawTexture (Images[imgRTFCTOP], ST_X+290, ST_Y, - DTA_Bottom320x200, Scaled, - DTA_TopOffset, Images[imgRTFCTOP]->GetHeight(), - TAG_DONE); - - if (oldhealth != HealthMarker) - { - oldhealth = HealthMarker; - HealthRefresh = screen->GetPageCount (); - } - if (HealthRefresh) - { - HealthRefresh--; - healthPos = HealthMarker; - if (healthPos < 0) - { - healthPos = 0; - } - if (healthPos > 100) - { - healthPos = 100; - } - healthPos = (healthPos * 256) / 100; - chainY = (HealthMarker == (CPlayer->health > 0 ? CPlayer->health : 0)) ? 33 : 33 + ChainWiggle; - DrawImage (Images[imgCHAINBACK], 0, 32); - DrawImage (Images[imgCHAIN], 2+(healthPos%17), chainY); - DrawImage (Images[imgLIFEGEM], 17+healthPos, chainY, multiplayer ? - translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)] : NULL); - DrawImage (Images[imgLTFACE], 0, 32); - DrawImage (Images[imgRTFACE], 276, 32); - screen->DrawTexture (&ChainShade, ST_X+19, ST_Y+32, - DTA_Bottom320x200, Scaled, - DTA_AlphaChannel, true, - DTA_FillColor, 0, - TAG_DONE); - screen->DrawTexture (&ChainShade, ST_X+277, ST_Y+32, - DTA_Bottom320x200, Scaled, - DTA_AlphaChannel, true, - DTA_FillColor, 0, - DTA_FlipX, true, - TAG_DONE); - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawMainBar -// -//--------------------------------------------------------------------------- - - void DrawMainBar () - { - AInventory *item; - AAmmo *ammo1, *ammo2; - int ammocount1, ammocount2; - int temp; - int playerkeys; - - // Ready artifact - if (ArtifactFlash) - { - DrawImage (Images[imgBLACKSQ], 180, 3); - DrawImage (Images[imgUSEARTIA + ArtifactFlash], 182, 3); - oldarti = NULL; // so that the correct artifact fills in after the flash - } - else if (oldarti != CPlayer->mo->InvSel - || (oldarti != NULL && oldartiCount != oldarti->Amount)) - { - oldarti = CPlayer->mo->InvSel; - GC::WriteBarrier(this, oldarti); - oldartiCount = oldarti != NULL ? oldarti->Amount : 0; - ArtiRefresh = screen->GetPageCount (); - } - if (ArtiRefresh) - { - ArtiRefresh--; - DrawImage (Images[imgBLACKSQ], 180, 3); - if (oldarti != NULL) - { - DrawDimImage (TexMan(oldarti->Icon), 179, 2, oldarti->Amount <= 0); - if (oldartiCount != 1) - { - DrSmallNumber (oldartiCount, 197, 24); - } - } - } - - // Frags - if (deathmatch) - { - temp = CPlayer->fragcount; - if (temp != oldfrags) - { - oldfrags = temp; - FragHealthRefresh = screen->GetPageCount (); - } - if (FragHealthRefresh) - { - FragHealthRefresh--; - DrawImage (Images[imgARMCLEAR], 57, 13); - DrINumber (temp, 61, 12); - } - } - else - { - temp = MAX(0, HealthMarker); - if (oldlife != temp) - { - oldlife = temp; - FragHealthRefresh = screen->GetPageCount (); - } - if (FragHealthRefresh) - { - FragHealthRefresh--; - DrawImage (Images[imgARMCLEAR], 57, 13); - DrINumber (temp, 61, 12); - } - } - - // Keys - playerkeys = 0; - - for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) - { - if (item->IsKindOf (RUNTIME_CLASS(AKey))) - { - int keynum = static_cast(item)->KeyNumber; - if (keynum >= 1 && keynum <= 3) - { - playerkeys |= 1 << (keynum-1); - } - } - } - if (oldkeys != playerkeys) - { - oldkeys = playerkeys; - KeysRefresh = screen->GetPageCount (); - } - if (KeysRefresh) - { - KeysRefresh--; - // [RH] Erase the key images so the player can drop keys - // and see the status update. - screen->DrawTexture (Images[imgSTATBAR], ST_X+34, ST_Y+2, - DTA_WindowLeft, 119, - DTA_WindowRight, 129, - DTA_Bottom320x200, Scaled, - TAG_DONE); - if (playerkeys & 4) - { - DrawImage (Images[imgYKEYICON], 153, 6); - } - if (playerkeys & 1) - { - DrawImage (Images[imgGKEYICON], 153, 14); - } - if (playerkeys & 2) - { - DrawImage (Images[imgBKEYICON], 153, 22); - } - } - - // Ammo - GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); - if (ammo1 == ammo2) - { - // Don't show the same ammo twice. - ammo2 = NULL; - } - if (oldammo1 != ammo1 || oldammo2 != ammo2 || - oldammocount1 != ammocount1 || oldammocount2 != ammocount2) - { - oldammo1 = ammo1; - oldammo2 = ammo2; - oldammocount1 = ammocount1; - oldammocount2 = ammocount2; - GC::WriteBarrier(this, ammo1); - GC::WriteBarrier(this, ammo2); - AmmoRefresh = screen->GetPageCount (); - } - if (AmmoRefresh) - { - AmmoRefresh--; - DrawImage (Images[imgBLACKSQ], 108, 3); - if (ammo2 != NULL) - { // Draw both ammos - screen->DrawTexture (TexMan[ammo1->Icon], 115+ST_X, 11+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, Scaled, - TAG_DONE); - DrSmallNumber (ammo1->Amount, 124, 7); - screen->DrawTexture (TexMan[ammo2->Icon], 115+ST_X, 22+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, Scaled, - TAG_DONE); - DrSmallNumber (ammo2->Amount, 124, 19); - } - else if (ammo1 != NULL) - { // Draw just one ammo - DrINumber (ammo1->Amount, 109, 4); - screen->DrawTexture (TexMan[ammo1->Icon], 123+ST_X, 22+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, Scaled, - TAG_DONE); - } - } - - // Armor - AInventory *armor = CPlayer->mo->FindInventory(); - int armorpoints = armor != NULL ? armor->Amount : 0; - if (oldarmor != armorpoints) - { - oldarmor = armorpoints; - ArmorRefresh = screen->GetPageCount (); - } - if (ArmorRefresh) - { - ArmorRefresh--; - DrawImage (Images[imgARMCLEAR], 224, 13); - DrINumber (armorpoints, 228, 12); - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawInventoryBar -// -//--------------------------------------------------------------------------- - - void DrawInventoryBar () - { - AInventory *item; - int i; - - DrawImage (Images[imgINVBAR], 34, 2); - CPlayer->mo->InvFirst = ValidateInvFirst (7); - if (CPlayer->mo->InvFirst != NULL) - { - for (item = CPlayer->mo->InvFirst, i = 0; item != NULL && i < 7; item = item->NextInv(), ++i) - { - DrawDimImage (TexMan(item->Icon), 50+i*31, 2, item->Amount <= 0); - if (item->Amount != 1) - { - DrSmallNumber (item->Amount, 65+i*31, 24); - } - if (item == CPlayer->mo->InvSel) - { - DrawImage (Images[imgSELECTBOX], 50+i*31, 31); - } - } - // Is there something to the left? - if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - DrawImage (Images[!(gametic & 4) ? - imgINVLFGEM1 : imgINVLFGEM2], 38, 1); - } - // Is there something to the right? - if (item != NULL) - { - DrawImage (Images[!(gametic & 4) ? - imgINVRTGEM1 : imgINVRTGEM2], 269, 1); - } - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawFullScreenStuff -// -//--------------------------------------------------------------------------- - - void DrawFullScreenStuff () - { - AInventory *item; - FTexture *pic; - int i; - - // Draw health - if (CPlayer->mo->health > 0) - { - pic = Images[imgPTN1 + gametic/3%3]; - screen->DrawTexture (pic, 48, -3, - DTA_HUDRules, HUD_Normal, - DTA_LeftOffset, pic->GetWidth()/2, - DTA_TopOffset, pic->GetHeight(), - TAG_DONE); - DrBNumberOuter (CPlayer->mo->health, 5, -21); - } - else - { - DrBNumberOuter (0, 5, -20); - } - - // Draw armor - ABasicArmor *armor = CPlayer->mo->FindInventory(); - if (armor != NULL && armor->Amount != 0) - { - pic = TexMan(armor->Icon); - if (pic != NULL) - { - screen->DrawTexture (pic, 56, -24, - DTA_HUDRules, HUD_Normal, - DTA_LeftOffset, pic->GetWidth()/2, - DTA_TopOffset, pic->GetHeight(), - TAG_DONE); - } - DrBNumberOuter (armor->Amount, 5, -43); - } - - if (deathmatch) - { - // Draw frag count - DrINumberOuter (CPlayer->fragcount, 45, -16); - } - else - { - // Draw keys - int playerkeys = 0; - - for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) - { - if (item->IsKindOf (RUNTIME_CLASS(AKey))) - { - int keynum = static_cast(item)->KeyNumber; - if (keynum >= 1 && keynum <= 3) - { - playerkeys |= 1 << (keynum-1); - } - } - } - i = -7; - if (playerkeys & 2) - { - screen->DrawTexture (Images[imgBKEYICON], 54, i, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - i -= 8; - } - if (playerkeys & 1) - { - screen->DrawTexture (Images[imgGKEYICON], 54, i, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - i -= 8; - } - if (playerkeys & 4) - { - screen->DrawTexture (Images[imgYKEYICON], 54, i, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - } - - // Draw ammo - AAmmo *ammo1, *ammo2; - int ammocount1, ammocount2; - - GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); - if (ammo1 != NULL) - { - // Draw primary ammo in the bottom-right corner - DrINumberOuter (ammo1->Amount, -29, -15); - screen->DrawTexture (TexMan(ammo1->Icon), -14, -22, - DTA_HUDRules, HUD_Normal, - DTA_CenterBottomOffset, true, - TAG_DONE); - if (ammo2 != NULL && ammo2!=ammo1) - { - // Draw secondary ammo just above the primary ammo - DrINumberOuter (ammo2->Amount, -29, -56); - screen->DrawTexture (TexMan(ammo2->Icon), -14, -63, - DTA_HUDRules, HUD_Normal, - DTA_CenterBottomOffset, true, - TAG_DONE); - } - } - - // Draw inventory - if (CPlayer->inventorytics == 0) - { - if (ArtifactFlash) - { - screen->DrawTexture (Images[imgARTIBOX], -61, -31, - DTA_HUDRules, HUD_Normal, - DTA_Alpha, TRANSLUC50, - TAG_DONE); - screen->DrawTexture (Images[imgUSEARTIA + ArtifactFlash], -61, -31, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - else if (CPlayer->mo->InvSel != NULL) - { - screen->DrawTexture (Images[imgARTIBOX], -61, -31, - DTA_HUDRules, HUD_Normal, - DTA_Alpha, TRANSLUC50, - TAG_DONE); - screen->DrawTexture (TexMan(CPlayer->mo->InvSel->Icon), -61, -31, - DTA_HUDRules, HUD_Normal, - DTA_ColorOverlay, CPlayer->mo->InvSel->Amount > 0 ? 0 : DIM_OVERLAY, - TAG_DONE); - if (CPlayer->mo->InvSel->Amount != 1) - { - DrSmallNumberOuter (CPlayer->mo->InvSel->Amount, -46, -9, false); - } - } - } - else - { - CPlayer->mo->InvFirst = ValidateInvFirst (7); - i = 0; - if (CPlayer->mo->InvFirst != NULL) - { - for (item = CPlayer->mo->InvFirst; item != NULL && i < 7; item = item->NextInv(), ++i) - { - screen->DrawTexture (Images[imgARTIBOX], -100+i*31, -32, - DTA_HUDRules, HUD_HorizCenter, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - screen->DrawTexture (TexMan(item->Icon), -100+i*31, -32, - DTA_HUDRules, HUD_HorizCenter, - DTA_ColorOverlay, item->Amount > 0 ? 0 : DIM_OVERLAY, - TAG_DONE); - if (item->Amount != 1) - { - DrSmallNumberOuter (item->Amount, -84+i*31, -10, true); - } - if (item == CPlayer->mo->InvSel) - { - screen->DrawTexture (Images[imgSELECTBOX], -100+i*31, -3, - DTA_HUDRules, HUD_HorizCenter, - TAG_DONE); - } - } - // Is there something to the left? - if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - screen->DrawTexture (Images[!(gametic & 4) ? - imgINVLFGEM1 : imgINVLFGEM2], -112, -33, - DTA_HUDRules, HUD_HorizCenter, TAG_DONE); - } - // Is there something to the right? - if (item != NULL) - { - screen->DrawTexture (Images[!(gametic & 4) ? - imgINVRTGEM1 : imgINVRTGEM2], 119, -33, - DTA_HUDRules, HUD_HorizCenter, TAG_DONE); - } - } - for (; i < 7; i++) - { - screen->DrawTexture (Images[imgARTIBOX], -100+i*31, -32, - DTA_HUDRules, HUD_HorizCenter, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - } - } - } - -//--------------------------------------------------------------------------- -// -// PROC FlashItem -// -//--------------------------------------------------------------------------- - - void FlashItem (const PClass *itemtype) - { - ArtifactFlash = 4; - } - - static const char patcharti[][10]; - static const char ammopic[][10]; - - TObjPtr oldarti; - TObjPtr oldammo1, oldammo2; - int oldammocount1, oldammocount2; - int oldartiCount; - int oldfrags; - int oldarmor; - int oldhealth; - int oldlife; - int oldkeys; - - enum - { - imgLTFACE, - imgRTFACE, - imgBARBACK, - imgINVBAR, - imgCHAIN, - imgSTATBAR, - imgLIFEGEM, - imgLTFCTOP, - imgRTFCTOP, - imgSELECTBOX, - imgINVLFGEM1, - imgINVLFGEM2, - imgINVRTGEM1, - imgINVRTGEM2, - imgBLACKSQ, - imgARMCLEAR, - imgCHAINBACK, - imgGOD1, - imgGOD2, - imgUSEARTIA, - imgUSEARTIB, - imgUSEARTIC, - imgUSEARTID, - imgYKEYICON, - imgGKEYICON, - imgBKEYICON, - imgARTIBOX, - imgPTN1, - imgPTN2, - imgPTN3, - - NUM_HERETICSB_IMAGES - }; - - FImageCollection Images; - - int HealthMarker; - int ChainWiggle; - int ArtifactFlash; - - char HealthRefresh; - char ArtiRefresh; - char FragHealthRefresh; - char KeysRefresh; - char AmmoRefresh; - char ArmorRefresh; -}; - -IMPLEMENT_POINTY_CLASS(DHereticStatusBar) - DECLARE_POINTER(oldarti) - DECLARE_POINTER(oldammo1) - DECLARE_POINTER(oldammo2) -END_POINTERS - -DBaseStatusBar *CreateHereticStatusBar () -{ - return new DHereticStatusBar; -} diff --git a/src/g_hexen/hexen_sbar.cpp b/src/g_hexen/hexen_sbar.cpp deleted file mode 100644 index 787b8f8d9..000000000 --- a/src/g_hexen/hexen_sbar.cpp +++ /dev/null @@ -1,1194 +0,0 @@ -#include - -#include "doomtype.h" -#include "doomstat.h" -#include "v_font.h" -#include "sbar.h" -#include "r_defs.h" -#include "w_wad.h" -#include "m_random.h" -#include "d_player.h" -#include "st_stuff.h" -#include "v_video.h" -#include "r_draw.h" -#include "templates.h" -#include "a_hexenglobal.h" -#include "a_keys.h" -#include "r_translate.h" -#include "a_weaponpiece.h" -#include "v_palette.h" - - -class FManaBar : public FTexture -{ -public: - FManaBar (); - - const BYTE *GetColumn (unsigned int column, const Span **spans_out); - const BYTE *GetPixels (); - void Unload (); - bool CheckModified (); - - void SetVial (FTexture *pic, AActor *actor, const PClass *manaType); - -protected: - BYTE Pixels[5*24]; - static const Span DummySpan[2]; - - FTexture *VialPic; - int VialLevel; - bool NeedRefresh; - - void MakeTexture (); -}; - -const FTexture::Span FManaBar::DummySpan[2] = { { 0, 24 }, { 0, 0 } }; - -FManaBar::FManaBar () -: VialPic(0), VialLevel(0), NeedRefresh(false) -{ - Width = 5; - Height = 24; - WidthBits = 2; - HeightBits = 5; - WidthMask = 3; -} - -void FManaBar::Unload () -{ - if (VialPic != 0) - { - VialPic->Unload (); - } -} - -bool FManaBar::CheckModified () -{ - return NeedRefresh; -} - -const BYTE *FManaBar::GetColumn (unsigned int column, const Span **spans_out) -{ - if (NeedRefresh) - { - MakeTexture (); - } - if (column > 4) - { - column = 4; - } - if (spans_out != NULL) - { - *spans_out = DummySpan; - } - return Pixels + column*24; -} - -const BYTE *FManaBar::GetPixels () -{ - if (NeedRefresh) - { - MakeTexture (); - } - return Pixels; -} - -void FManaBar::SetVial (FTexture *pic, AActor *actor, const PClass *manaType) -{ - int level, max; - AInventory *ammo; - - ammo = actor->FindInventory (manaType); - level = 0; max = 200; - if (ammo != NULL) - { - level = ammo->Amount; - max = ammo->MaxAmount; - if (!max) max = 1; - } - level = MIN (22*level/max, 22); - if (VialPic != pic || VialLevel != level) - { - VialPic = pic; - VialLevel = level; - NeedRefresh = true; - } -} - -void FManaBar::MakeTexture () -{ - int run = 22 - VialLevel; - BYTE color0 = GPalette.Remap[0]; - - NeedRefresh = false; - VialPic->CopyToBlock (Pixels, 5, 24, 0, 0); - memset (Pixels + 25, color0, run); - memset (Pixels + 25+24, color0, run); - memset (Pixels + 25+24+24, color0, run); -} - -class DHexenStatusBar : public DBaseStatusBar -{ - DECLARE_CLASS(DHexenStatusBar, DBaseStatusBar) - HAS_OBJECT_POINTERS -public: - DHexenStatusBar () : DBaseStatusBar (38) - { - static const char *hexenLumpNames[NUM_HEXENSB_IMAGES] = - { - "H2BAR", "H2TOP", "INVBAR", "LFEDGE", "RTEDGE", - "STATBAR", "KEYBAR", "SELECTBO", "ARTICLS", "ARMCLS", - "MANACLS", "MANAVL1", "MANAVL2", "MANAVL1D", "MANAVL2D", - "MANADIM1", "MANADIM2", "MANABRT1", "MANABRT2", "INVGEML1", - "INVGEML2", "INVGEMR1", "INVGEMR2", "KILLS", "USEARTIA", - "USEARTIB", "USEARTIC", "USEARTID", "USEARTIE", "KEYSLOT1", - "KEYSLOT2", "KEYSLOT3", "KEYSLOT4", "KEYSLOT5", "KEYSLOT6", - "KEYSLOT7", "KEYSLOT8", "KEYSLOT9", "KEYSLOTA", "KEYSLOTB", - "ARMSLOT1", "ARMSLOT2", "ARMSLOT3", "ARMSLOT4", "ARTIBOX", - "HAMOBACK" - }; - static const char *classLumpNames[3][NUM_HEXENCLASSSB_IMAGES] = - { - { - "WPSLOT0", "WPFULL0", "WPIECEF1", "WPIECEF2", - "WPIECEF3", "CHAIN", "LIFEGMF2" - }, - { - "WPSLOT1", "WPFULL1", "WPIECEC1", "WPIECEC2", - "WPIECEC3", "CHAIN2", "LIFEGMC2" - }, - { - "WPSLOT2", "WPFULL2", "WPIECEM1", "WPIECEM2", - "WPIECEM3", "CHAIN3", "LIFEGMM2" - } - }; - static const char *sharedLumpNames[] = - { - "LAME", "NEGNUM", "IN0", "IN1", "IN2", - "IN3", "IN4", "IN5", "IN6", "IN7", - "IN8", "IN9", "FONTB13", "FONTB16", "FONTB17", - "FONTB18", "FONTB19", "FONTB20", "FONTB21", "FONTB22", - "FONTB23", "FONTB24", "FONTB25", "SMALLIN0", "SMALLIN1", - "SMALLIN2", "SMALLIN3", "SMALLIN4", "SMALLIN5", "SMALLIN6", - "SMALLIN7", "SMALLIN8", "SMALLIN9", - - "INRED0", "INRED1", "INRED2", "INRED3", "INRED4", - "INRED5", "INRED6", "INRED7", "INRED8", "INRED9" - }; - - DBaseStatusBar::Images.Init (sharedLumpNames, NUM_BASESB_IMAGES + 10); - Images.Init (hexenLumpNames, NUM_HEXENSB_IMAGES); - ClassImages[0].Init (classLumpNames[0], NUM_HEXENCLASSSB_IMAGES); - ClassImages[1].Init (classLumpNames[1], NUM_HEXENCLASSSB_IMAGES); - ClassImages[2].Init (classLumpNames[2], NUM_HEXENCLASSSB_IMAGES); - - oldarti = NULL; - oldartiCount = 0; - oldammo1 = oldammo2 = NULL; - oldammocount1 = oldammocount2 = -1; - oldfrags = -9999; - oldmana1 = -1; - oldmana2 = -1; - oldusemana1 = -1; - oldusemana2 = -1; - olddrawbars = -1; - oldarmor = -1; - oldhealth = -1; - oldlife = -1; - oldpieces = -1; - oldkeys[0] = oldkeys[1] = oldkeys[2] = oldkeys[3] = oldkeys[4] = NULL; - - HealthMarker = 0; - ArtifactFlash = 0; - - ArtiRefresh = 0; - FragHealthRefresh = 0; - KeysRefresh = 0; - ArmorRefresh = 0; - HealthRefresh = 0; - Mana1Refresh = 0; - Mana2Refresh = 0; - AmmoRefresh = 0; - } - - ~DHexenStatusBar () - { - } - - void Tick () - { - int curHealth; - - DBaseStatusBar::Tick (); - if (CPlayer->mo == NULL) - { - curHealth = 0; - } - else - { - curHealth = CPlayer->mo->health; - } - if (curHealth < 0) - { - curHealth = 0; - } - if (curHealth < HealthMarker) - { - HealthMarker -= clamp ((HealthMarker - curHealth) >> 2, 1, 6); - } - else if (curHealth > HealthMarker) - { - HealthMarker += clamp ((curHealth - HealthMarker) >> 2, 1, 6); - } - - if (ArtifactFlash > 0) - { - if (--ArtifactFlash == 0) - { - ArtiRefresh = screen->GetPageCount (); - } - } - } - - void Draw (EHudState state) - { - DBaseStatusBar::Draw (state); - - if (state == HUD_Fullscreen) - { - DrawFullScreenStuff (); - SB_state = screen->GetPageCount (); - } - else if (state == HUD_StatusBar) - { - if (SB_state > 0) - { - DrawImage (Images[imgH2BAR], 0, -27); - oldhealth = -1; - } - DrawCommonBar (); - if (CPlayer->inventorytics == 0) - { - if (SB_state < 0) - { - SB_state = screen->GetPageCount (); - } - if (SB_state != 0) - { - // Main interface - SB_state--; - DrawImage (Images[!automapactive ? imgSTATBAR : imgKEYBAR], 38, 0); - oldarti = NULL; - oldammo1 = oldammo2 = NULL; - oldmana1 = -1; - oldmana2 = -1; - oldusemana1 = -1; - oldusemana2 = -1; - olddrawbars = -1; - oldarmor = -1; - oldpieces = -1; - oldfrags = -9999; //can't use -1, 'cuz of negative frags - oldlife = -1; - oldkeys[0] = oldkeys[1] = oldkeys[2] = oldkeys[3] = oldkeys[4] = NULL; - ArtiRefresh = 0; - //oldhealth = -1; - } - if (!automapactive) - { - DrawMainBar (); - } - else - { - DrawKeyBar (); - } - } - else - { - if (SB_state > -1) - { - SB_state = -screen->GetPageCount () - 1; - } - if (SB_state < -1) - { - SB_state++; - } - DrawInventoryBar (); - } - } - } - - void AttachToPlayer (player_t *player) - { - DBaseStatusBar::AttachToPlayer (player); - if (player->mo != NULL) - { - if (player->mo->IsKindOf (PClass::FindClass(NAME_MagePlayer))) - { - FourthWeaponClass = 2; - LifeBarClass = 2; - } - else if (player->mo->IsKindOf (PClass::FindClass(NAME_ClericPlayer))) - { - FourthWeaponClass = 1; - LifeBarClass = 1; - } - else - { - FourthWeaponClass = 0; - LifeBarClass = 0; - } - } - } - -private: -//--------------------------------------------------------------------------- -// -// PROC DrawCommonBar -// -//--------------------------------------------------------------------------- - - void DrawCommonBar () - { - int healthPos; - - DrawImage (Images[imgH2TOP], 0, -27); - - if (oldhealth != HealthMarker) - { - oldhealth = HealthMarker; - HealthRefresh = screen->GetPageCount (); - } - if (HealthRefresh) - { - int lifeClass = LifeBarClass; - - HealthRefresh--; - healthPos = clamp (HealthMarker, 0, 100); - DrawImage (ClassImages[lifeClass][imgCHAIN], 35+((healthPos*196/100)%9), 31); - DrawImage (ClassImages[lifeClass][imgLIFEGEM], 7+(healthPos*11/5), 31, multiplayer ? - translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)] : NULL); - DrawImage (Images[imgLFEDGE], 0, 31); - DrawImage (Images[imgRTEDGE], 277, 31); - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawMainBar -// -//--------------------------------------------------------------------------- - - void DrawMainBar () - { - int temp; - - // Ready artifact - if (ArtifactFlash) - { - DrawImage (Images[imgARTICLEAR], 144, -1); - DrawImage (Images[imgUSEARTIA + ArtifactFlash], 148, 2); - oldarti = NULL; // so that the correct artifact fills in after the flash - } - else if (oldarti != CPlayer->mo->InvSel - || (oldarti != NULL && oldartiCount != oldarti->Amount)) - { - oldarti = CPlayer->mo->InvSel; - GC::WriteBarrier(this, oldarti); - oldartiCount = oldarti != NULL ? oldarti->Amount : 0; - ArtiRefresh = screen->GetPageCount (); - } - if (ArtiRefresh) - { - ArtiRefresh--; - DrawImage (Images[imgARTICLEAR], 144, -1); - if (oldarti != NULL) - { - DrawDimImage (TexMan(oldarti->Icon), 143, 2, oldarti->Amount <= 0); - if (oldartiCount != 1) - { - DrSmallNumber (oldartiCount, 162, 23); - } - } - } - - // Frags - if (deathmatch) - { - temp = CPlayer->fragcount; - if (temp != oldfrags) - { - oldfrags = temp; - FragHealthRefresh = screen->GetPageCount (); - } - if (FragHealthRefresh) - { - FragHealthRefresh--; - DrawImage (Images[imgKILLS], 38, 1); - DrINumber (temp, 40, 15); - } - } - else - { - temp = MAX (0, HealthMarker); - if (oldlife != temp) - { - oldlife = temp; - FragHealthRefresh = screen->GetPageCount (); - } - if (FragHealthRefresh) - { - FragHealthRefresh--; - DrawImage (Images[imgARMCLEAR], 41, 16); - DrINumber (temp, 40, 14, temp >= 25 ? imgINumbers : NUM_BASESB_IMAGES); - } - } - - // Mana - AAmmo *ammo1, *ammo2; - int ammocount1, ammocount2; - int drawbar; - - GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); - if (ammo1==ammo2) - { - // Don't show the same ammo twice. - ammo2=NULL; - } - - // If the weapon uses some ammo that is not mana, do not draw - // the mana bars; draw the specific used ammo instead. - const PClass *mana1 = PClass::FindClass(NAME_Mana1); - const PClass *mana2 = PClass::FindClass(NAME_Mana2); - - drawbar = !((ammo1 != NULL && ammo1->GetClass() != mana1 && ammo1->GetClass() != mana2) || - (ammo2 != NULL && ammo2->GetClass() != mana1 && ammo2->GetClass() != mana2)); - - if (drawbar != olddrawbars) - { - AmmoRefresh = screen->GetPageCount (); - olddrawbars = drawbar; - oldmana1 = -1; - oldmana2 = -1; - } - if (drawbar && oldammo2 != ammo2) - { - AmmoRefresh = screen->GetPageCount (); - } - if (drawbar) - { - DrawManaBars (ammo1, ammo2, mana1, mana2); - } - else - { - DrawMainAltAmmo (ammo1, ammo2, ammocount1, ammocount2); - } - - // Armor - temp = GetArmorPercent (NULL); - if (oldarmor != temp) - { - oldarmor = temp; - ArmorRefresh = screen->GetPageCount (); - } - if (ArmorRefresh) - { - ArmorRefresh--; - DrawImage (Images[imgARMCLEAR], 255, 16); - DrINumber (temp / (5*FRACUNIT), 250, 14); - } - - // Weapon Pieces - DrawWeaponPieces(); - } - -//--------------------------------------------------------------------------- -// -// PROC DrawMainAltAmmo -// -// Draw a generic ammo readout on the main bar, instead of the mana bars. -// -//--------------------------------------------------------------------------- - - void DrawMainAltAmmo (AAmmo *ammo1, AAmmo *ammo2, int ammocount1, int ammocount2) - { - if (ammo1 != oldammo1 || ammocount1 != oldammocount1) - { - AmmoRefresh = screen->GetPageCount (); - oldammo1 = ammo1; - oldammocount1 = ammocount1; - GC::WriteBarrier(this, ammo1); - } - if (ammo2 != oldammo2 || ammocount2 != oldammocount2) - { - AmmoRefresh = screen->GetPageCount (); - oldammo2 = ammo2; - oldammocount2 = ammocount2; - GC::WriteBarrier(this, ammo2); - } - - if (AmmoRefresh) - { - AmmoRefresh--; - DrawImage (Images[imgAMMOBACK], 77, 2); - if (ammo2 != NULL) - { // Draw both ammos - AmmoRefresh--; - screen->DrawTexture (TexMan[ammo1->Icon], 89+ST_X, 10+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, true, - TAG_DONE); - DrSmallNumber (ammo1->Amount, 86, 20); - - screen->DrawTexture (TexMan[ammo2->Icon], 113+ST_X, 10+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, true, - TAG_DONE); - DrSmallNumber (ammo2->Amount, 110, 20); - } - else - { // Draw one ammo - screen->DrawTexture (TexMan[ammo1->Icon], 100+ST_X, 10+ST_Y, - DTA_CenterOffset, true, - DTA_Bottom320x200, true, - TAG_DONE); - DrSmallNumber (ammo1->Amount, 97, 20); - } - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawManaBars -// -// Draws the mana bars on the main status bar -// -//--------------------------------------------------------------------------- - - void DrawManaBars (AAmmo *ammo1, AAmmo *ammo2, const PClass *manatype1, const PClass *manatype2) - { - AAmmo *mana1 = NULL, *mana2 = NULL; - int usemana1 = false, usemana2 = false; - int manacount1, manacount2; - int manaPatch1, manaPatch2; - int manaVialPatch1, manaVialPatch2; - - manaPatch1 = 0; - manaPatch2 = 0; - manaVialPatch1 = 0; - manaVialPatch2 = 0; - - if (AmmoRefresh) - { - Mana1Refresh = MAX(AmmoRefresh, Mana1Refresh); - Mana2Refresh = MAX(AmmoRefresh, Mana2Refresh); - AmmoRefresh--; - screen->DrawTexture (Images[imgSTATBAR], ST_X+38, ST_Y, - DTA_WindowLeft, 39, - DTA_WindowRight, 87, - DTA_Bottom320x200, Scaled, - TAG_DONE); - } - - // Locate Mana1 and Mana2 in the inventory, and decide which ones are used. - if (ammo1 == NULL) - { - } - else if (ammo1->GetClass() == manatype1) - { - mana1 = ammo1; - usemana1 = true; - } - else if (ammo1->GetClass() == manatype2) - { - mana2 = ammo1; - usemana2 = true; - } - if (ammo2 == NULL) - { - } - else if (ammo2->GetClass() == manatype1) - { - mana1 = ammo2; - usemana1 = true; - } - else if (ammo2->GetClass() == manatype2) - { - mana2 = ammo2; - usemana2 = true; - } - if (mana1 == NULL) - { - mana1 = static_cast(CPlayer->mo->FindInventory(manatype1)); - } - if (mana2 == NULL) - { - mana2 = static_cast(CPlayer->mo->FindInventory(manatype2)); - } - manacount1 = mana1 != NULL ? mana1->Amount : 0; - manacount2 = mana2 != NULL ? mana2->Amount : 0; - - // Has Mana1 changed since last time? - if (oldmana1 != manacount1 || oldusemana1 != usemana1) - { - oldmana1 = manacount1; - oldusemana1 = usemana1; - Mana1Refresh = screen->GetPageCount (); - } - - // Has Mana2 changed since last time? - if (oldmana2 != manacount2 || oldusemana2 != usemana2) - { - oldmana2 = manacount2; - oldusemana2 = usemana2; - Mana2Refresh = screen->GetPageCount (); - } - // Decide what to draw for vial 1 - if (Mana1Refresh) - { - Mana1Refresh--; - DrawImage (Images[imgMANACLEAR], 77, 16); - DrSmallNumber (manacount1, 79, 19); - if (!usemana1) - { // Draw Dim Mana icon - manaPatch1 = imgMANADIM1; - manaVialPatch1 = imgMANAVIALDIM1; - } - else - { - manaPatch1 = imgMANABRIGHT1; - manaVialPatch1 = manacount1 ? imgMANAVIAL1 : imgMANAVIALDIM1; - } - } - // Decide what to draw for vial 2 - if (Mana2Refresh) - { - Mana2Refresh--; - DrawImage (Images[imgMANACLEAR], 109, 16); - DrSmallNumber (manacount2, 111, 19); - if (!usemana2) - { // Draw Dim Mana icon - manaPatch2 = imgMANADIM2; - manaVialPatch2 = imgMANAVIALDIM2; - } - else - { - manaPatch2 = imgMANABRIGHT2; - manaVialPatch2 = manacount2 ? imgMANAVIAL2 : imgMANAVIALDIM2; - } - } - // Update mana graphics - if (manaPatch1 || manaPatch2 || manaVialPatch1) - { - if (manaVialPatch1) - { - DrawImage (Images[manaPatch1], 77, 2); - ManaVial1Pic.SetVial (Images[manaVialPatch1], CPlayer->mo, manatype1); - DrawImage (&ManaVial1Pic, 94, 2); - } - if (manaVialPatch2) - { - DrawImage (Images[manaPatch2], 110, 2); - ManaVial2Pic.SetVial (Images[manaVialPatch2], CPlayer->mo, manatype2); - DrawImage (&ManaVial2Pic, 102, 2); - } - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawInventoryBar -// -//--------------------------------------------------------------------------- - - void DrawInventoryBar () - { - AInventory *item; - int i; - - DrawImage (Images[imgINVBAR], 38, 0); - CPlayer->mo->InvFirst = ValidateInvFirst (7); - if (CPlayer->mo->InvFirst != NULL) - { - for (item = CPlayer->mo->InvFirst, i = 0; item != NULL && i < 7; item = item->NextInv(), ++i) - { - DrawDimImage (TexMan(item->Icon), 50+i*31, 1, item->Amount <= 0); - if (item->Amount != 1) - { - DrSmallNumber (item->Amount, 68+i*31, 23); - } - if (item == CPlayer->mo->InvSel) - { - DrawImage (Images[imgSELECTBOX], 51+i*31, 1); - } - } - // Is there something to the left? - if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - DrawImage (Images[!(gametic & 4) ? - imgINVLFGEM1 : imgINVLFGEM2], 42, 1); - } - // Is there something to the right? - if (item != NULL) - { - DrawImage (Images[!(gametic & 4) ? - imgINVRTGEM1 : imgINVRTGEM2], 269, 1); - } - } - } - -//========================================================================== -// -// DrawKeyBar -// -//========================================================================== - - void DrawKeyBar () - { - AInventory *item; - AHexenArmor *armor; - AKey *keys[5]; - int i; - int temp; - bool different; - - keys[0] = keys[1] = keys[2] = keys[3] = keys[4] = NULL; - for (item = CPlayer->mo->Inventory, i = 0; - item != NULL && i < 5; - item = item->Inventory) - { - if (item->Icon.isValid() && - item->IsKindOf (RUNTIME_CLASS(AKey)) && - item->GetClass() != RUNTIME_CLASS(AKey)) - { - keys[i++] = static_cast(item); - } - } - different = false; - for (i = 0; i < 5; ++i) - { - if (keys[i] != oldkeys[i]) - { - oldkeys[i] = keys[i]; - GC::WriteBarrier(this, keys[i]); - different = true; - } - } - if (different) - { - KeysRefresh = screen->GetPageCount (); - } - if (KeysRefresh) - { - KeysRefresh--; - for (i = 0; i < 5 && keys[i] != NULL; i++) - { - DrawImage (TexMan[keys[i]->Icon], 46 + i*20, 2); - } - } - - temp = GetArmorPercent (&armor); - if (oldarmor != temp && armor != NULL) - { - for (i = 0; i < 4; i++) - { - if (armor->Slots[i] > 0 && armor->SlotsIncrement[i] > 0) - { - DrawFadedImage (Images[imgARMSLOT1+i], 150+31*i, 2, - MIN (OPAQUE, Scale (armor->Slots[i], OPAQUE, - armor->SlotsIncrement[i]))); - } - } - oldarmor = temp; - } - } - -//========================================================================== -// -// GetArmorPercent -// -//========================================================================== - - fixed_t GetArmorPercent (AHexenArmor **armorp) - { - AHexenArmor *harmor = CPlayer->mo->FindInventory(); - fixed_t amount = 0; - if (harmor != NULL) - { - amount = harmor->Slots[0] - + harmor->Slots[1] - + harmor->Slots[2] - + harmor->Slots[3] - + harmor->Slots[4]; - } - // [RH] Count basic armor too. - ABasicArmor *barmor = CPlayer->mo->FindInventory(); - if (barmor != NULL) - { - amount += barmor->SavePercent; - } - if (armorp != NULL) - { - *armorp = harmor; - } - return amount; - } - -//========================================================================== -// -// DrawWeaponPieces -// -//========================================================================== - - void DrawWeaponPieces () - { - static ENamedName FourthWeaponNames[] = { NAME_FWeapQuietus, NAME_CWeapWraithverge, NAME_MWeapBloodscourge }; - - for(AInventory *inv = CPlayer->mo->Inventory; inv != NULL; inv = inv->Inventory) - { - if (inv->IsA(RUNTIME_CLASS(AWeaponHolder))) - { - AWeaponHolder *hold = static_cast(inv); - - if (hold->PieceWeapon->TypeName == FourthWeaponNames[(int)FourthWeaponClass]) - { - // Weapon Pieces - if (oldpieces != hold->PieceMask) - { - oldpieces = hold->PieceMask; - - static int PieceX[3][3] = - { - { 190, 225, 234 }, - { 190, 212, 225 }, - { 190, 205, 224 }, - }; - int pieces = oldpieces; - int weapClass = FourthWeaponClass; - - if (pieces == 7) - { - DrawImage (ClassImages[weapClass][imgWEAPONFULL], 190, 0); - return; - } - DrawImage (ClassImages[weapClass][imgWEAPONSLOT], 190, 0); - if (pieces & WPIECE1) - { - DrawImage (ClassImages[weapClass][imgPIECE1], PieceX[weapClass][0], 0); - } - if (pieces & WPIECE2) - { - DrawImage (ClassImages[weapClass][imgPIECE2], PieceX[weapClass][1], 0); - } - if (pieces & WPIECE3) - { - DrawImage (ClassImages[weapClass][imgPIECE3], PieceX[weapClass][2], 0); - } - } - return; - } - } - } - if (oldpieces != 0) - { - DrawImage (ClassImages[(int)FourthWeaponClass][imgWEAPONSLOT], 190, 0); - oldpieces = 0; - } - } - -//--------------------------------------------------------------------------- -// -// PROC DrawFullScreenStuff -// -//--------------------------------------------------------------------------- - - void DrawFullScreenStuff () - { - AInventory *item; - int i; - - // Health - DrBNumberOuter (MAX (0, CPlayer->mo->health), 5, -20); - - // Frags - if (deathmatch) - { - DrINumberOuter (CPlayer->fragcount, 45, -15); - } - - // Inventory - if (CPlayer->inventorytics == 0) - { - if (ArtifactFlash) - { - screen->DrawTexture (Images[imgARTIBOX], -80, -30, - DTA_HUDRules, HUD_Normal, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - screen->DrawTexture (Images[imgUSEARTIA + ArtifactFlash], -76, -26, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - else if (CPlayer->mo->InvSel != NULL) - { - screen->DrawTexture (Images[imgARTIBOX], -80, -30, - DTA_HUDRules, HUD_Normal, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - screen->DrawTexture (TexMan(CPlayer->mo->InvSel->Icon), -82, -31, - DTA_HUDRules, HUD_Normal, - DTA_ColorOverlay, CPlayer->mo->InvSel->Amount > 0 ? 0 : DIM_OVERLAY, - TAG_DONE); - if (CPlayer->mo->InvSel->Amount != 1) - { - DrSmallNumberOuter (CPlayer->mo->InvSel->Amount, -64, -8, false); - } - } - } - else - { - CPlayer->mo->InvFirst = ValidateInvFirst (7); - i = 0; - if (CPlayer->mo->InvFirst != NULL) - { - for (item = CPlayer->mo->InvFirst; item != NULL && i < 7; item = item->NextInv(), ++i) - { - screen->DrawTexture (Images[imgARTIBOX], -106+i*31, -32, - DTA_HUDRules, HUD_HorizCenter, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - screen->DrawTexture (TexMan(item->Icon), -108+i*31, -33, - DTA_HUDRules, HUD_HorizCenter, - DTA_ColorOverlay, item->Amount > 0 ? 0 : DIM_OVERLAY, - TAG_DONE); - if (item->Amount != 1) - { - DrSmallNumberOuter (item->Amount, -90+i*31, -11, true); - } - if (item == CPlayer->mo->InvSel) - { - screen->DrawTexture (Images[imgSELECTBOX], -107+i*31, -33, - DTA_HUDRules, HUD_HorizCenter, - TAG_DONE); - } - } - // Is there something to the left? - if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - screen->DrawTexture (Images[!(gametic & 4) ? - imgINVLFGEM1 : imgINVLFGEM2], -118, -33, - DTA_HUDRules, HUD_HorizCenter, TAG_DONE); - } - // Is there something to the right? - if (item != NULL) - { - screen->DrawTexture (Images[!(gametic & 4) ? - imgINVRTGEM1 : imgINVRTGEM2], 113, -33, - DTA_HUDRules, HUD_HorizCenter, TAG_DONE); - } - } - for (; i < 7; i++) - { - screen->DrawTexture (Images[imgARTIBOX], -106+i*31, -32, - DTA_HUDRules, HUD_HorizCenter, - DTA_Alpha, HX_SHADOW, - TAG_DONE); - } - } - - // Mana - AAmmo *ammo1, *ammo2; - int ammocount1, ammocount2; - bool drawmana; - - GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2); - - // If the weapon uses some ammo that is not mana, do not draw - // the mana blocks; draw the specific used ammo instead. - const PClass *mana1 = PClass::FindClass(NAME_Mana1); - const PClass *mana2 = PClass::FindClass(NAME_Mana2); - - drawmana = !((ammo1 != NULL && ammo1->GetClass() != mana1 && ammo1->GetClass() != mana2) || - (ammo2 != NULL && ammo2->GetClass() != mana1 && ammo2->GetClass() != mana2)); - - if (drawmana) - { - int manaImage; - int ammo = 0; - - if (CPlayer->ReadyWeapon != NULL) - { - if (CPlayer->ReadyWeapon->Ammo1 != NULL) - { - if (CPlayer->ReadyWeapon->Ammo1->GetClass() == mana1) - { - ammo |= 1; - } - else if (CPlayer->ReadyWeapon->Ammo1->GetClass() == mana2) - { - ammo |= 2; - } - } - if (CPlayer->ReadyWeapon->Ammo2 != NULL) - { - if (CPlayer->ReadyWeapon->Ammo2->GetClass() == mana1) - { - ammo |= 1; - } - else if (CPlayer->ReadyWeapon->Ammo2->GetClass() == mana2) - { - ammo |= 2; - } - } - } - - item = CPlayer->mo->FindInventory (mana1); - i = item != NULL ? item->Amount : 0; - manaImage = ((ammo & 1) && i > 0) ? imgMANABRIGHT1 : imgMANADIM1; - screen->DrawTexture (Images[manaImage], -17, -30, - DTA_HUDRules, HUD_Normal, TAG_DONE); - DrINumberOuter (i, -47, -30); - - item = CPlayer->mo->FindInventory (mana2); - i = item != NULL ? item->Amount : 0; - manaImage = ((ammo & 2) && i > 0) ? imgMANABRIGHT2 : imgMANADIM2; - screen->DrawTexture (Images[manaImage], -17, -15, - DTA_HUDRules, HUD_Normal, TAG_DONE); - DrINumberOuter (i, -47, -15); - } - else - { - } - } - -//--------------------------------------------------------------------------- -// -// PROC FlashItem -// -//--------------------------------------------------------------------------- - - void FlashItem (const PClass *itemtype) - { - ArtifactFlash = 4; - } - - static const char patcharti[][10]; - static const char ammopic[][10]; - - TObjPtr oldarti; - TObjPtr oldammo1, oldammo2; - TObjPtr oldkeys[5]; - int oldammocount1, oldammocount2; - int oldartiCount; - int oldfrags; - int oldmana1; - int oldmana2; - int oldusemana1; - int oldusemana2; - int olddrawbars; - int oldarmor; - int oldhealth; - int oldlife; - int oldpieces; - - enum - { - imgH2BAR, - imgH2TOP, - imgINVBAR, - imgLFEDGE, - imgRTEDGE, - imgSTATBAR, - imgKEYBAR, - imgSELECTBOX, - imgARTICLEAR, - imgARMCLEAR, - imgMANACLEAR, - imgMANAVIAL1, - imgMANAVIAL2, - imgMANAVIALDIM1, - imgMANAVIALDIM2, - imgMANADIM1, - imgMANADIM2, - imgMANABRIGHT1, - imgMANABRIGHT2, - imgINVLFGEM1, - imgINVLFGEM2, - imgINVRTGEM1, - imgINVRTGEM2, - imgKILLS, - imgUSEARTIA, - imgUSEARTIB, - imgUSEARTIC, - imgUSEARTID, - imgUSEARTIE, - imgKEYSLOT1, - imgKEYSLOT2, - imgKEYSLOT3, - imgKEYSLOT4, - imgKEYSLOT5, - imgKEYSLOT6, - imgKEYSLOT7, - imgKEYSLOT8, - imgKEYSLOT9, - imgKEYSLOTA, - imgKEYSLOTB, - imgARMSLOT1, - imgARMSLOT2, - imgARMSLOT3, - imgARMSLOT4, - imgARTIBOX, - imgAMMOBACK, - - NUM_HEXENSB_IMAGES - }; - - enum - { - imgWEAPONSLOT, - imgWEAPONFULL, - imgPIECE1, - imgPIECE2, - imgPIECE3, - imgCHAIN, - imgLIFEGEM, - - NUM_HEXENCLASSSB_IMAGES - }; - - FImageCollection Images; - FImageCollection ClassImages[3]; - - int HealthMarker; - char ArtifactFlash; - - char FourthWeaponClass; - char LifeBarClass; - - char ArtiRefresh; - char FragHealthRefresh; - char KeysRefresh; - char ArmorRefresh; - char HealthRefresh; - char Mana1Refresh; - char Mana2Refresh; - char AmmoRefresh; - - FManaBar ManaVial1Pic; - FManaBar ManaVial2Pic; -}; - -IMPLEMENT_POINTY_CLASS(DHexenStatusBar) - DECLARE_POINTER(oldarti) - DECLARE_POINTER(oldammo1) - DECLARE_POINTER(oldammo2) - DECLARE_POINTER(oldkeys[0]) - DECLARE_POINTER(oldkeys[1]) - DECLARE_POINTER(oldkeys[2]) - DECLARE_POINTER(oldkeys[3]) - DECLARE_POINTER(oldkeys[4]) -END_POINTERS - -DBaseStatusBar *CreateHexenStatusBar () -{ - return new DHexenStatusBar; -} diff --git a/src/g_level.cpp b/src/g_level.cpp index 1fd0130dc..fbefb011d 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -419,15 +419,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) int cstype = SBarInfoScript[SCRIPT_CUSTOM]->GetGameType(); //Did the user specify a "base" - if(cstype == GAME_Heretic) - { - StatusBar = CreateHereticStatusBar(); - } - else if(cstype == GAME_Hexen) - { - StatusBar = CreateHexenStatusBar(); - } - else if(cstype == GAME_Strife) + if(cstype == GAME_Strife) { StatusBar = CreateStrifeStatusBar(); } @@ -442,18 +434,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel) } if (StatusBar == NULL) { - if (gameinfo.gametype & GAME_DoomChex) + if (gameinfo.gametype & (GAME_DoomChex|GAME_Heretic|GAME_Hexen)) { StatusBar = CreateCustomStatusBar (SCRIPT_DEFAULT); } - else if (gameinfo.gametype == GAME_Heretic) - { - StatusBar = CreateHereticStatusBar (); - } - else if (gameinfo.gametype == GAME_Hexen) - { - StatusBar = CreateHexenStatusBar (); - } else if (gameinfo.gametype == GAME_Strife) { StatusBar = CreateStrifeStatusBar (); diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 440de41dd..295e0e4e1 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -376,8 +376,6 @@ extern DBaseStatusBar *StatusBar; // Status bar factories ----------------------------------------------------- -DBaseStatusBar *CreateHereticStatusBar(); -DBaseStatusBar *CreateHexenStatusBar(); DBaseStatusBar *CreateStrifeStatusBar(); DBaseStatusBar *CreateCustomStatusBar(int script=0); diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index bbd1f6c57..3a1462eb0 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -483,9 +483,19 @@ void SBarInfo::ParseSBarInfo(int lump) ParseSBarInfo(lump); } else if(sc.Compare("Heretic")) - gameType = GAME_Heretic; + { + int lump = Wads.CheckNumForFullName("sbarinfo/heretic.txt", true); + if(lump == -1) + sc.ScriptError("Standard Heretic Status Bar not found."); + ParseSBarInfo(lump); + } else if(sc.Compare("Hexen")) - gameType = GAME_Hexen; + { + int lump = Wads.CheckNumForFullName("sbarinfo/hexen.txt", true); + if(lump == -1) + sc.ScriptError("Standard Hexen Status Bar not found."); + ParseSBarInfo(lump); + } else if(sc.Compare("Strife")) gameType = GAME_Strife; else if(sc.Compare("None")) @@ -559,6 +569,19 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(','); sc.MustGetToken(TK_StringConst); //Don't tell anyone we're just ignoring this ;) } + if(sc.CheckToken(',')) + { + // Character alignment + sc.MustGetToken(TK_Identifier); + if(sc.Compare("left")) + spacingAlignment = ALIGN_LEFT; + else if(sc.Compare("center")) + spacingAlignment = ALIGN_CENTER; + else if(sc.Compare("right")) + spacingAlignment = ALIGN_RIGHT; + else + sc.ScriptError("Unknown alignment '%s'.", sc.String); + } sc.MustGetToken(';'); break; case SBARINFO_LOWERHEALTHCAP: @@ -763,6 +786,7 @@ void SBarInfo::Init() armorInterpolationSpeed = 8; height = 0; spacingCharacter = '\0'; + spacingAlignment = ALIGN_CENTER; resW = 320; resH = 200; @@ -1295,7 +1319,7 @@ public: } } - void DrawString(FFont *font, const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool drawshadow=false) const + void DrawString(FFont *font, const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool drawshadow=false, int shadowX=2, int shadowY=2) const { x += spacing; double ax = *x; @@ -1340,6 +1364,23 @@ public: ry = ay + yOffset; rw = character->GetScaledWidthDouble(); rh = character->GetScaledHeightDouble(); + + if(script->spacingCharacter != '\0') + { + double spacingSize = font->GetCharWidth((int) script->spacingCharacter); + switch(script->spacingAlignment) + { + default: + break; + case SBarInfo::ALIGN_CENTER: + rx += (spacingSize/2)-(rw/2); + break; + case SBarInfo::ALIGN_RIGHT: + rx += spacingSize-rw; + break; + } + } + if(!fullScreenOffsets) { rx += ST_X; @@ -1374,7 +1415,9 @@ public: if(drawshadow) { int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); - screen->DrawTexture(character, rx+2, ry+2, + double srx = rx + (shadowX*xScale); + double sry = ry + (shadowY*yScale); + screen->DrawTexture(character, srx, sry, DTA_DestWidthF, rw, DTA_DestHeightF, rh, DTA_Alpha, salpha, diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index 9952e21a8..d2d81f1f7 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -84,6 +84,13 @@ struct Popup struct SBarInfo { + enum MonospaceAlignment + { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT + }; + TArray Images; SBarInfoMainBlock *huds[NUMHUDS]; Popup popups[NUMPOPUPS]; @@ -93,6 +100,7 @@ struct SBarInfo bool completeBorder; bool lowerHealthCap; char spacingCharacter; + MonospaceAlignment spacingAlignment; int interpolationSpeed; int armorInterpolationSpeed; int height; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 13263a831..91e7aa06c 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -514,14 +514,15 @@ class CommandDrawString : public SBarInfoCommand { public: CommandDrawString(SBarInfo *script) : SBarInfoCommand(script), - shadow(false), spacing(0), font(NULL), translation(CR_UNTRANSLATED), - cache(-1), strValue(CONSTANT), valueArgument(0) + shadow(false), shadowX(2), shadowY(2), spacing(0), font(NULL), + translation(CR_UNTRANSLATED), cache(-1), strValue(CONSTANT), + valueArgument(0) { } void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - statusBar->DrawString(font, str.GetChars(), x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translation, spacing, shadow); + statusBar->DrawString(font, str.GetChars(), x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translation, spacing, shadow, shadowX, shadowY); } void Parse(FScanner &sc, bool fullScreenOffsets) { @@ -695,6 +696,8 @@ class CommandDrawString : public SBarInfoCommand }; bool shadow; + int shadowX; + int shadowY; int spacing; FFont *font; EColorRange translation; @@ -850,7 +853,18 @@ class CommandDrawNumber : public CommandDrawString else if(sc.Compare("whennotzero")) whenNotZero = true; else if(sc.Compare("drawshadow")) + { + if(sc.CheckToken('(')) + { + sc.MustGetToken(TK_IntConst); + shadowX = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + shadowY = sc.Number; + sc.MustGetToken(')'); + } shadow = true; + } else if(sc.Compare("interpolate")) { sc.MustGetToken('('); @@ -1236,7 +1250,18 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private else if(sc.Compare("centerbottom")) offset = static_cast (HMIDDLE|BOTTOM); else if(sc.Compare("drawshadow")) + { + if(sc.CheckToken('(')) + { + sc.MustGetToken(TK_IntConst); + shadowX = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + shadowY = sc.Number; + sc.MustGetToken(')'); + } shadow = true; + } else { font = V_GetFont(sc.String); diff --git a/wadsrc/static/actors/heretic/heretickeys.txt b/wadsrc/static/actors/heretic/heretickeys.txt index 774629866..71beab253 100644 --- a/wadsrc/static/actors/heretic/heretickeys.txt +++ b/wadsrc/static/actors/heretic/heretickeys.txt @@ -13,6 +13,7 @@ ACTOR KeyGreen : HereticKey 73 Game Heretic SpawnID 86 Inventory.PickupMessage "$TXT_GOTGREENKEY" + Inventory.Icon "GKEYICON" States { Spawn: @@ -28,6 +29,7 @@ ACTOR KeyBlue : HereticKey 79 Game Heretic SpawnID 85 Inventory.PickupMessage "$TXT_GOTBLUEKEY" + Inventory.Icon "BKEYICON" States { Spawn: @@ -43,6 +45,7 @@ ACTOR KeyYellow : HereticKey 80 Game Heretic SpawnID 87 Inventory.PickupMessage "$TXT_GOTYELLOWKEY" + Inventory.Icon "YKEYICON" States { Spawn: diff --git a/wadsrc/static/animdefs.txt b/wadsrc/static/animdefs.txt index f4b33eaab..a2a4498e2 100644 --- a/wadsrc/static/animdefs.txt +++ b/wadsrc/static/animdefs.txt @@ -95,6 +95,12 @@ pic SPMINO13 tics 3 pic SPMINO14 tics 3 pic SPMINO15 tics 3 +// Animate health vial for Heretic fullscreen HUD +texture optional PTN1A0 +pic PTN1A0 tics 3 +pic PTN1B0 tics 3 +pic PTN1C0 tics 3 + // The Wings of Wrath are not included, because they stop spinning when // you stop flying, so they can't be a simple animation. diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 1d3d63fd2..0c78f1184 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -24,7 +24,7 @@ gameinfo defaultbloodparticlecolor = "ff 00 00" backpacktype = "BagOfHolding" armoricons = "SHLDA0", 0.75, "SHD2A0" - statusbar = "" + statusbar = "sbarinfo/heretic.txt" intermissionmusic = "mus_intr" intermissioncounter = false weaponslot = 1, "Staff", "Gauntlets" diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index cdababe39..344f4eb41 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -26,7 +26,7 @@ gameinfo defaultbloodcolor = "68 00 00" defaultbloodparticlecolor = "ff 00 00" backpacktype = "BagOfHolding" // Hexen doesn't have a backpack so use Heretic's. - statusbar = "" + statusbar = "sbarinfo/hexen.txt" intermissionmusic = "hub" intermissioncounter = false weaponslot = 1, "FWeapFist", "CWeapMace", "MWeapWand" diff --git a/wadsrc/static/sbarinfo/heretic.txt b/wadsrc/static/sbarinfo/heretic.txt new file mode 100755 index 000000000..c5b22f6b3 --- /dev/null +++ b/wadsrc/static/sbarinfo/heretic.txt @@ -0,0 +1,123 @@ +/******************************************************************************* + * DEFAULT HERETIC STATUS BAR + ******************************************************************************* + * If you wish to include this file into a custom status bar please use the + * following command: + * + * base Heretic; + * + * Using #include "sbarinfo/heretic.txt" will not be supported. + ******************************************************************************/ + +height 42; +monospacefonts true, "0", center; + +statusbar fullscreen, fullscreenoffsets +{ + //health + drawimage "PTN1A0", 48, -3, centerbottom; + drawnumber 2147483647, BIGFONT, untranslated, health, drawshadow, interpolate(8), 41, -21, 1; + + //armor + drawimage armoricon, 56, -24, centerbottom; + drawnumber 2147483647, BIGFONT, untranslated, armor, drawshadow, whennotzero, 41, -43, 1; + + //frags/keys + gamemode deathmatch + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, frags, drawshadow, 70, -16, 1; + else + drawkeybar 100, vertical, reverse, 8, 54, -7, 0, 3, auto; + + //ammo + drawimage ammoicon1, -14, -22, centerbottom; + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, ammo1, drawshadow(1, 1), -3, -15, 1; + //secondary ammo + usessecondaryammo + { + drawimage ammoicon2, -14, -63, centerbottom; + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, ammo2, drawshadow(1, 1), -3, -56, 1; + } + + inventorybarnotvisible + { + drawselectedinventory alternateonempty, artiflash, INDEXFONT_RAVEN, -61, -31, -34, -9, untranslated + { + } + else + { + alpha 0.6 + drawimage "ARTIBOX", -61, -31; + } + } +} + +statusbar normal +{ + drawimage "BARBACK", 0, 158; + drawimage "LTFCTOP", 0, 148; + drawimage "RTFCTOP", 290, 148; + + //god mode + drawswitchableimage invulnerable, "GOD1", "nullimage", 16, 167; + drawswitchableimage invulnerable, "GOD2", "nullimage", 287, 167; + + //health + drawimage "CHAINBAC", 0, 190; + gamemode singleplayer + drawgem wiggle, interpolate(8), "CHAIN", "LIFEGEM2", 15, 25, 16, 2, 191; + else + drawgem wiggle, interpolate(8), translatable, "CHAIN", "LIFEGEM2", 15, 25, 16, 2, 191; + drawimage "LTFACE", 0, 190; + drawimage "RTFACE", 276, 190; + drawshader 16, 10, horizontal, 19, 190; + drawshader 16, 10, horizontal, reverse, 278, 190; + + //statbar + gamemode singleplayer, cooperative + { + drawimage "LIFEBAR", 34, 160; + drawimage "ARMCLEAR", 57, 171; + drawnumber 3, HUDFONT_RAVEN, untranslated, health, interpolate(8), 87, 170, 1; + } + else + { + drawimage "STATBAR", 34, 160; + drawimage "ARMCLEAR", 57, 171; + drawnumber 3, HUDFONT_RAVEN, untranslated, frags, 87, 170, 1; + } + drawimage "ARMCLEAR", 224, 171; + drawnumber 3, HUDFONT_RAVEN, untranslated, armor, 254, 170, 1; + + //ammo + usessecondaryammo not + { + drawnumber 3, HUDFONT_RAVEN, untranslated, ammo1, 135, 162, 1; + drawimage ammoicon1, 123, 180, center; + } + else + { + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo1, 137, 165; + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo2, 137, 177; + drawimage ammoicon1, 115, 169, center; + drawimage ammoicon2, 115, 180, center; + } + + //keys + drawswitchableimage keyslot 3, "nullimage", "YKEYICON", 153, 164; + drawswitchableimage keyslot 1, "nullimage", "GKEYICON", 153, 172; + drawswitchableimage keyslot 2, "nullimage", "BKEYICON", 153, 180; + + //inventory box + drawselectedinventory artiflash, INDEXFONT_RAVEN, 179, 160, 209, 182, untranslated; +} + +statusbar inventory +{ + drawimage "INVBAR", 34, 160; + drawinventorybar Heretic, noartibox, 7, INDEXFONT_RAVEN, 50, 160, 77, 182, untranslated; +} + +statusbar inventoryfullscreen, fullscreenoffsets // ZDoom HUD overlay. +{ + drawinventorybar Heretic, translucent, 7, INDEXFONT_RAVEN, -106+center, -31, -78+center, -9, untranslated; +} diff --git a/wadsrc/static/sbarinfo/hexen.txt b/wadsrc/static/sbarinfo/hexen.txt new file mode 100755 index 000000000..3dc900e98 --- /dev/null +++ b/wadsrc/static/sbarinfo/hexen.txt @@ -0,0 +1,259 @@ +/******************************************************************************* + * DEFAULT HEXEN STATUS BAR + ******************************************************************************* + * If you wish to include this file into a custom status bar please use the + * following command: + * + * base Hexen; + * + * Using #include "sbarinfo/hexen.txt" will not be supported. + ******************************************************************************/ + +height 38; +monospacefonts true, "0", center; + +statusbar fullscreen, fullscreenoffsets +{ + //health + drawnumber 2147483647, BIGFONT, untranslated, health, drawshadow, interpolate(8), 40, -20, 1; + + //frags + gamemode deathmatch + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, frags, drawshadow(1, 1), 70, -15, 1; + + inventorybarnotvisible + { + drawselectedinventory alternateonempty, artiflash, INDEXFONT_RAVEN, -82, -31, -52, -8, untranslated + { + } + else + { + alpha 0.6 + drawimage "ARTIBOX", -80, -30; + } + } + + // Mana + weaponammo Mana1 && Mana2 + { + weaponammo Mana1 + drawimage "MANABRT1", -17, -30; + else + drawimage "MANADIM1", -17, -30; + weaponammo Mana2 + drawimage "MANABRT2", -17, -15; + else + drawimage "MANADIM2", -17, -15; + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, ammo Mana1, drawshadow(1, 1), -21, -30, 1; + drawnumber 2147483647, HUDFONT_RAVEN, untranslated, ammo Mana2, drawshadow(1, 1), -21, -15, 1; + } +} + +statusbar Normal +{ + drawimage "H2BAR", 0, 135; + drawimage "STATBAR", 38, 162; + + drawselectedinventory artiflash, INDEXFONT_RAVEN, 143, 163, 174, 184, untranslated; + + gamemode deathmatch, teamgame + { + drawimage "KILLS", 38, 163; + drawnumber 3, HUDFONT_RAVEN, untranslated, frags, 58, 163, 1; + } + else + { + drawimage "ARMCLS", 41, 178; + drawnumber 3, HUDFONT_RAVEN, untranslated, health, interpolate(6), 65, 176, 1, red, 25; + } + + //mana bars + weaponammo Mana1 && Mana2 + { + weaponammo Mana1 + { + drawimage "MANABRT1", 77, 164; + drawbar "MANAVL1", "nullimage", ammo Mana1, vertical, 94, 164, 1; + } + else + { + drawimage "MANADIM1", 77, 164; + drawbar "MANAVL1D", "nullimage", ammo Mana1, vertical, 94, 164, 1; + } + weaponammo Mana2 + { + drawimage "MANABRT2", 110, 164; + drawbar "MANAVL2", "nullimage", ammo Mana2, vertical, 102, 164, 1; + } + else + { + drawimage "MANADIM2", 110, 164; + drawbar "MANAVL2D", "nullimage", ammo Mana2, vertical, 102, 164, 1; + } + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo Mana1, 91, 181; + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo Mana2, 123, 181; + } + else //Weapon doesn't use ammo draw an alternative + { + drawimage "HAMOBACK", 77, 164; + usessecondaryammo + { + drawimage ammoicon1, 89, 172, center; + drawimage ammoicon2, 113, 172, center; + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo1, 98, 182; + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo2, 122, 182; + } + else + { + drawimage ammoicon1, 100, 172, center; + drawnumber 3, INDEXFONT_RAVEN, untranslated, ammo1, 109, 182; + } + } + + //armor + drawimage "ARMCLS", 255, 178; + drawnumber 2, HUDFONT_RAVEN, untranslated, armorclass, 275, 176, 1; + + playerclass Fighter + { + drawimage "WPSLOT0", 190, 162; + hasweaponpiece FWeapQuietus, 1 + { + drawimage "WPIECEF1", 190, 162; + } + hasweaponpiece FWeapQuietus, 2 + { + drawimage "WPIECEF2", 225, 162; + } + hasweaponpiece FWeapQuietus, 3 + { + drawimage "WPIECEF3", 234, 162; + } + hasweaponpiece FWeapQuietus, 1 + { + hasweaponpiece FWeapQuietus, 2 + { + hasweaponpiece FWeapQuietus, 3 + { + drawimage "WPFULL0", 190, 162; + } + } + } + + gamemode singleplayer + drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + } + else playerclass Cleric + { + drawimage "WPSLOT1", 190, 162; + hasweaponpiece CWeapWraithverge, 1 + { + drawimage "WPIECEC1", 190, 162; + } + hasweaponpiece CWeapWraithverge, 2 + { + drawimage "WPIECEC2", 212, 162; + } + hasweaponpiece CWeapWraithverge, 3 + { + drawimage "WPIECEC3", 225, 162; + } + hasweaponpiece CWeapWraithverge, 1 + { + hasweaponpiece CWeapWraithverge, 2 + { + hasweaponpiece CWeapWraithverge, 3 + { + drawimage "WPFULL1", 190, 162; + } + } + } + + gamemode singleplayer + drawgem interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; + } + else playerclass Mage + { + drawimage "WPSLOT2", 190, 162; + hasweaponpiece MWeapBloodscourge, 1 + { + drawimage "WPIECEM1", 190, 162; + } + hasweaponpiece MWeapBloodscourge, 2 + { + drawimage "WPIECEM2", 205, 162; + } + hasweaponpiece MWeapBloodscourge, 3 + { + drawimage "WPIECEM3", 224, 162; + } + hasweaponpiece MWeapBloodscourge, 1 + { + hasweaponpiece MWeapBloodscourge, 2 + { + hasweaponpiece MWeapBloodscourge, 3 + { + drawimage "WPFULL2", 190, 162; + } + } + } + + gamemode singleplayer + drawgem interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; + } + drawimage "LFEDGE", 0, 193; + drawimage "RTEDGE", 277, 193; +} + +statusbar Automap +{ + drawimage "H2BAR", 0, 135; + drawimage "KEYBAR", 38, 162; + drawkeybar 5, horizontal, 20, 46, 164; + drawimage hexenarmor armor, "ARMSLOT1", 150, 164; + drawimage hexenarmor shield, "ARMSLOT2", 181, 164; + drawimage hexenarmor helm, "ARMSLOT3", 212, 164; + drawimage hexenarmor amulet, "ARMSLOT4", 243, 164; + + // Also draw the life gem here + playerclass Fighter + { + gamemode singleplayer + drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + } + else playerclass Cleric + { + gamemode singleplayer + drawgem interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; + } + else playerclass Mage + { + gamemode singleplayer + drawgem interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; + } + drawimage "LFEDGE", 0, 193; + drawimage "RTEDGE", 277, 193; +} + +statusbar inventory +{ + drawimage "INVBAR", 38, 162; + drawinventorybar HexenStrict, noartibox, 7, INDEXFONT_RAVEN, 52, 164, 80, 185, untranslated; +} + +statusbar inventoryfullscreen, fullscreenoffsets // ZDoom HUD overlay. +{ + drawinventorybar HexenStrict, translucent, 7, INDEXFONT_RAVEN, -106+center, -31, -78+center, -10, untranslated; +} From 2090c03d88298c9cbd04e696089b7816561fb5a0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jun 2010 04:53:19 +0000 Subject: [PATCH 076/251] - Fixed: D3DFB::GetScreenshotBuffer() must not offset the buffer pointer for letterboxed modes, since the screenwipe speedup fixes also mean that this function no longer operates directly with the front buffer, but rather with a copy that is not letterboxed. SVN r2355 (trunk) --- src/win32/fb_d3d9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index b21c1b003..ea96a79cf 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1726,7 +1726,7 @@ void D3DFB::GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_ } else { - buffer = (const BYTE *)lrect.pBits + lrect.Pitch * LBOffsetI; + buffer = (const BYTE *)lrect.pBits; pitch = lrect.Pitch; color_type = SS_BGRA; } From 41bd0f536970c1b9e22190c4554bcb8e7e41f26f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jun 2010 05:00:30 +0000 Subject: [PATCH 077/251] - Fixed: "Disallow Suicide" gameplay menu option should be labeled as "Allow Suicide". SVN r2356 (trunk) --- src/doomdef.h | 2 +- src/m_options.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 87216ae6b..716b2e105 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -290,7 +290,7 @@ enum DF2_NO_AUTOMAP_ALLIES = 1 << 19, // Allies can been seen on the automap. DF2_DISALLOW_SPYING = 1 << 20, // You can spy on your allies. DF2_CHASECAM = 1 << 21, // Players can use the chasecam cheat. - DF2_NOSUICIDE = 1 << 22, // Players are allowed to suicide. + DF2_NOSUICIDE = 1 << 22, // Players are not allowed to suicide. DF2_NOAUTOAIM = 1 << 23, // Players cannot use autoaim. DF2_DONTCHECKAMMO = 1 << 24, // Don't Check ammo when switching weapons. }; diff --git a/src/m_options.cpp b/src/m_options.cpp index 7fcd0bdcf..67aab6d62 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1037,7 +1037,7 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Fast monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FAST_MONSTERS} }, { bitflag, "Degeneration", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_DEGENERATION} }, { bitflag, "Allow Autoaim", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NOAUTOAIM} }, - { bitflag, "Disallow Suicide", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NOSUICIDE} }, + { bitflag, "Allow Suicide", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NOSUICIDE} }, { bitmask, "Allow jump", {&dmflags}, {3.0}, {DF_NO_JUMP|DF_YES_JUMP}, {0}, {DF_Jump} }, { bitmask, "Allow crouch", {&dmflags}, {3.0}, {DF_NO_CROUCH|DF_YES_CROUCH}, {0}, {DF_Crouch} }, { bitflag, "Allow freelook", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FREELOOK} }, From 185e5ad8449c293963bf36d15fcc9a64798c99e8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jun 2010 05:07:54 +0000 Subject: [PATCH 078/251] - Need to remove heretic_sbar.cpp and hexen_sbar.cpp from the VC project to complete r2353. SVN r2357 (trunk) --- zdoom.vcproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/zdoom.vcproj b/zdoom.vcproj index 74ab3a9e3..0f82621ab 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -3236,10 +3236,6 @@ /> - - - - Date: Sun, 6 Jun 2010 05:41:09 +0000 Subject: [PATCH 079/251] - Revert r2235 so that all DECORATE member accesses are consistent. It didn't work as intended anyway. SVN r2358 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a5fc1d08e..e2726e3f9 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3129,7 +3129,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) ACTION_PARAM_NAME(varname, 0); ACTION_PARAM_INT(value, 1); - PSymbol *sym = stateowner->GetClass()->Symbols.FindSymbol(varname, true); + PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); PSymbolVariable *var; if (sym == NULL || sym->SymbolType != SYM_Variable || @@ -3137,11 +3137,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) var->ValueType.Type != VAL_Int) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), - stateowner->GetClass()->TypeName.GetChars()); + self->GetClass()->TypeName.GetChars()); return; } // Set the value of the specified user variable. - *(int *)(reinterpret_cast(stateowner) + var->offset) = value; + *(int *)(reinterpret_cast(self) + var->offset) = value; } //=========================================================================== @@ -3157,7 +3157,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) ACTION_PARAM_INT(pos, 1); ACTION_PARAM_INT(value, 2); - PSymbol *sym = stateowner->GetClass()->Symbols.FindSymbol(varname, true); + PSymbol *sym = self->GetClass()->Symbols.FindSymbol(varname, true); PSymbolVariable *var; if (sym == NULL || sym->SymbolType != SYM_Variable || @@ -3165,17 +3165,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) { Printf("%s is not a user array in class %s\n", varname.GetChars(), - stateowner->GetClass()->TypeName.GetChars()); + self->GetClass()->TypeName.GetChars()); return; } if (pos < 0 || pos >= var->ValueType.size) { Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), - stateowner->GetClass()->TypeName.GetChars()); + self->GetClass()->TypeName.GetChars()); return; } // Set the value of the specified user array at index pos. - ((int *)(reinterpret_cast(stateowner) + var->offset))[pos] = value; + ((int *)(reinterpret_cast(self) + var->offset))[pos] = value; } //=========================================================================== From afd9bcb59ac4fb23549aca01e771caed8d07b4ec Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 7 Jun 2010 15:45:09 +0000 Subject: [PATCH 080/251] - Fixed: drawstring didn't properly align itself when variable strings were used. SVN r2360 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 37 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 91e7aa06c..65be83f7d 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -582,7 +582,7 @@ class CommandDrawString : public SBarInfoCommand str = sc.String; } sc.MustGetToken(','); - GetCoordinates(sc, fullScreenOffsets, x, y); + GetCoordinates(sc, fullScreenOffsets, startX, y); if(sc.CheckToken(',')) //spacing { sc.MustGetToken(TK_IntConst); @@ -590,10 +590,7 @@ class CommandDrawString : public SBarInfoCommand } sc.MustGetToken(';'); - if(script->spacingCharacter == '\0') - x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); - else //monospaced, so just multiplay the character size - x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + RealignString(); } void Reset() { @@ -619,6 +616,7 @@ class CommandDrawString : public SBarInfoCommand { cache = level.lumpnum; str = level.LevelName; + RealignString(); } break; case LEVELLUMP: @@ -626,6 +624,7 @@ class CommandDrawString : public SBarInfoCommand { cache = level.lumpnum; str = level.mapname; + RealignString(); } break; case SKILLNAME: @@ -633,6 +632,7 @@ class CommandDrawString : public SBarInfoCommand { cache = level.lumpnum; str = G_SkillName(); + RealignString(); } break; case PLAYERCLASS: @@ -640,6 +640,7 @@ class CommandDrawString : public SBarInfoCommand { cache = statusBar->CPlayer->userinfo.PlayerClass; str = statusBar->CPlayer->cls->Meta.GetMetaString(APMETA_DisplayName); + RealignString(); } break; case AMMO1TAG: @@ -658,12 +659,14 @@ class CommandDrawString : public SBarInfoCommand // Can't think of a good way to detect changes to this, so // I guess copying it every tick will have to do. str = statusBar->CPlayer->userinfo.netname; + RealignString(); break; case GLOBALVAR: if(ACS_GlobalVars[valueArgument] != cache) { cache = ACS_GlobalVars[valueArgument]; str = FBehavior::StaticLookupString(ACS_GlobalVars[valueArgument]); + RealignString(); } break; case GLOBALARRAY: @@ -671,6 +674,7 @@ class CommandDrawString : public SBarInfoCommand { cache = ACS_GlobalArrays[valueArgument][consoleplayer]; str = FBehavior::StaticLookupString(ACS_GlobalArrays[valueArgument][consoleplayer]); + RealignString(); } break; default: @@ -678,6 +682,15 @@ class CommandDrawString : public SBarInfoCommand } } protected: + void RealignString() + { + x = startX; + if(script->spacingCharacter == '\0') + x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); + else //monospaced, so just multiplay the character size + x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + } + enum StringValueType { LEVELNAME, @@ -701,6 +714,7 @@ class CommandDrawString : public SBarInfoCommand int spacing; FFont *font; EColorRange translation; + SBarInfoCoordinate startX; SBarInfoCoordinate x; SBarInfoCoordinate y; int cache; /// General purpose cache. @@ -717,6 +731,7 @@ class CommandDrawString : public SBarInfoCommand { cache = actor->GetClass()->ClassIndex; str = actor->GetTag(); + RealignString(); } } else @@ -1061,9 +1076,7 @@ class CommandDrawNumber : public CommandDrawString translation = lowTranslation; else if(highValue != -1 && drawValue >= highValue) //high translation = highTranslation; - - x = startX; - + // 10^9 is a largest we can hold in a 32-bit int. So if we go any larger we have to toss out the positions limit. int maxval = length <= 9 ? (int) ceil(pow(10., length))-1 : INT_MAX; if(!fillZeros || length == 1) @@ -1083,10 +1096,8 @@ class CommandDrawNumber : public CommandDrawString str.Insert(0, "0"); } } - if(script->spacingCharacter == '\0') - x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); - else //monospaced, so just multiplay the character size - x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + + RealignString(); } protected: enum ValueType @@ -1131,8 +1142,6 @@ class CommandDrawNumber : public CommandDrawString ValueType value; const PClass *inventoryItem; - SBarInfoCoordinate startX; - friend class CommandDrawInventoryBar; }; From 2aa7cdc5a81e07abf701d67c5a6ae8fe10b80fe7 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 8 Jun 2010 23:32:01 +0000 Subject: [PATCH 081/251] - Fixed: drawbar didn't work right when scaled. SVN r2361 (trunk) --- src/g_shared/sbarinfo.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 3a1462eb0..1966b58f6 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1153,8 +1153,8 @@ public: double tmp = 0; dx += ST_X; dy += ST_Y - (Scaled ? script->resH : 200) + script->height; - w = forceWidth < 0 ? texture->GetScaledWidth() : forceWidth; - h = forceHeight < 0 ? texture->GetScaledHeight() : forceHeight; + w = forceWidth < 0 ? texture->GetScaledWidthDouble() : forceWidth; + h = forceHeight < 0 ? texture->GetScaledHeightDouble() : forceHeight; double dcx = cx == 0 ? 0 : dx + ((double) cx / FRACUNIT) - texture->GetScaledLeftOffsetDouble(); double dcy = cy == 0 ? 0 : dy + ((double) cy / FRACUNIT) - texture->GetScaledTopOffsetDouble(); double dcr = cr == 0 ? INT_MAX : dx + w - ((double) cr / FRACUNIT); @@ -1174,6 +1174,7 @@ public: dcy += 200 - script->resH; dcb += 200 - script->resH; } + if(clearDontDraw) screen->Clear(static_cast(MAX(dx, dcx)), static_cast(MAX(dy, dcy)), static_cast(dcr), static_cast(dcb), GPalette.BlackIndex, 0); else @@ -1185,8 +1186,8 @@ public: DTA_DestHeightF, h, DTA_ClipLeft, static_cast(dcx), DTA_ClipTop, static_cast(dcy), - DTA_ClipRight, static_cast(dcr), - DTA_ClipBottom, static_cast(dcb), + DTA_ClipRight, static_cast(MIN(INT_MAX, dcr)), + DTA_ClipBottom, static_cast(MIN(INT_MAX, dcb)), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, @@ -1202,8 +1203,8 @@ public: DTA_DestHeightF, h, DTA_ClipLeft, static_cast(dcx), DTA_ClipTop, static_cast(dcy), - DTA_ClipRight, static_cast(dcr), - DTA_ClipBottom, static_cast(dcb), + DTA_ClipRight, static_cast(MIN(INT_MAX, dcr)), + DTA_ClipBottom, static_cast(MIN(INT_MAX, dcb)), DTA_Translation, translate ? GetTranslation() : 0, DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, From 4d86ebddf9369c8579c147be342549e9b2e8edeb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 08:47:38 +0000 Subject: [PATCH 082/251] - Added support for Risen3D/PrBoom+'s MUSINFO lump. SVN r2366 (trunk) --- src/g_level.h | 2 + src/p_mobj.cpp | 5 ++ src/s_advsound.cpp | 79 ++++++++++++++++++++ src/s_sound.cpp | 1 + src/s_sound.h | 7 +- wadsrc/static/actors/shared/sectoraction.txt | 6 ++ 6 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 016e256c3..4edf4409e 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -239,6 +239,7 @@ struct FOptionalMapinfoDataPtr }; typedef TMap FOptData; +typedef TMap FMusicMap; struct level_info_t { @@ -298,6 +299,7 @@ struct level_info_t float teamdamage; FOptData optdata; + FMusicMap MusicMap; TArray specialactions; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f12180ff8..ff896a0f1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4290,6 +4290,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mthing->args[0] = mthing->type - 14000; mthing->type = 14065; } + else if (mthing->type >= 14101 && mthing->type <= 14164) + { + mthing->args[0] = mthing->type - 14100; + mthing->type = 14165; + } // find which type to spawn i = DoomEdMap.FindType (mthing->type); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index b5cfc1d82..7f9cd8592 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -2111,3 +2111,82 @@ void AAmbientSound::Deactivate (AActor *activator) } } } + + +//========================================================================== +// +// S_ParseMusInfo +// Parses MUSINFO lump. +// +//========================================================================== + +void S_ParseMusInfo() +{ + int lastlump = 0, lump; + + while ((lump = Wads.FindLump ("MUSINFO", &lastlump)) != -1) + { + FScanner sc(lump); + + while (sc.GetString()) + { + level_info_t *map = FindLevelInfo(sc.String); + + if (map == NULL) + { + // Don't abort for invalid maps + sc.ScriptMessage("Unknown map '%s'", sc.String); + } + while (sc.CheckNumber()) + { + int index = sc.Number; + sc.MustGetString(); + if (index > 0) + { + FName music = sc.String; + if (map != NULL) + { + map->MusicMap[index] = music; + } + } + } + } + } +} + + +//========================================================================== +// +// Music changer. Uses the sector action class to do its job +// +//========================================================================== + +class AMusicChanger : public ASectorAction +{ + DECLARE_CLASS (AMusicChanger, ASectorAction) +public: + virtual bool TriggerAction (AActor *triggerer, int activationType); +}; + +IMPLEMENT_CLASS(AMusicChanger) + +bool AMusicChanger::TriggerAction (AActor *triggerer, int activationType) +{ + if (activationType & SECSPAC_Enter) + { + if (args[0] != 0) + { + FName *music = level.info->MusicMap.CheckKey(args[0]); + + if (music != NULL) + { + S_ChangeMusic(music->GetChars(), args[1]); + } + } + else + { + S_ChangeMusic("*"); + } + } + return Super::TriggerAction (triggerer, activationType); +} diff --git a/src/s_sound.cpp b/src/s_sound.cpp index db0f0f21d..b7a63e51b 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -323,6 +323,7 @@ void S_InitData () LastLocalSndInfo = LastLocalSndSeq = ""; S_ParseSndInfo (); S_ParseSndSeq (-1); + S_ParseMusInfo(); } //========================================================================== diff --git a/src/s_sound.h b/src/s_sound.h index b616b9137..41820bec7 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -353,6 +353,7 @@ void S_ShrinkPlayerSoundLists (); void S_UnloadSound (sfxinfo_t *sfx); sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); unsigned int S_GetMSLength(FSoundID sound); +void S_ParseMusInfo(); // [RH] Prints sound debug info to the screen. // Modelled after Hexen's noise cheat. @@ -373,9 +374,9 @@ enum EMidiDevice { MDEV_DEFAULT = -1, MDEV_MMAPI = 0, - MDEV_TIMIDITY = 1, - MDEV_OPL = 2, - MDEV_FMOD = 3, + MDEV_OPL = 1, + MDEV_FMOD = 2, + MDEV_TIMIDITY = 3, }; typedef TMap MidiDeviceMap; diff --git a/wadsrc/static/actors/shared/sectoraction.txt b/wadsrc/static/actors/shared/sectoraction.txt index 24b81bc39..2d7fe2a80 100644 --- a/wadsrc/static/actors/shared/sectoraction.txt +++ b/wadsrc/static/actors/shared/sectoraction.txt @@ -73,3 +73,9 @@ ACTOR SecActHitFakeFloor : SectorAction 9989 native { } +// Music changer ---------------------------------- + +ACTOR MusicChanger : SectorAction 14165 native +{ +} + From ec443978814299bcc1b9aa07b8d037ea6a8679f9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 09:06:12 +0000 Subject: [PATCH 083/251] - added some options to A_CustomPunch, including calling Strife's dagger alert function. SVN r2367 (trunk) --- src/p_enemy.h | 1 + src/thingdef/thingdef_codeptr.cpp | 16 ++++++++++++++-- wadsrc/static/actors/constants.txt | 5 +++++ wadsrc/static/actors/shared/inventory.txt | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/p_enemy.h b/src/p_enemy.h index e3e83be6c..1d80e08e3 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -44,6 +44,7 @@ struct FLookExParams FState *seestate; }; +void P_DaggerAlert (AActor *target, AActor *emitter); void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks); bool P_HitFriend (AActor *self); void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash=false); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e2726e3f9..df1a9c23e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1125,12 +1125,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) // Berserk is not handled here. That can be done with A_CheckIfInventory // //========================================================================== + +enum +{ + CPF_USEAMMO = 1, + CPF_DAGGER = 2, + CPF_PULLIN = 4, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { ACTION_PARAM_START(5); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_BOOL(norandom, 1); - ACTION_PARAM_BOOL(UseAmmo, 2); + ACTION_PARAM_INT(flags, 2); ACTION_PARAM_CLASS(PuffType, 3); ACTION_PARAM_FIXED(Range, 4); ACTION_PARAM_FIXED(LifeSteal, 5); @@ -1152,7 +1160,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) pitch = P_AimLineAttack (self, angle, Range, &linetarget); // only use ammo when actually hitting something! - if (UseAmmo && linetarget && weapon) + if ((flags & CPF_USEAMMO) && linetarget && weapon) { if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo } @@ -1173,6 +1181,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) self->y, linetarget->x, linetarget->y); + + if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; + if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget); + } } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index dfed8f5c0..6c027d82a 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -90,6 +90,11 @@ const int BF_AFFECTBOSSES = 4; const int SMF_LOOK = 1; const int SMF_PRECISE = 2; +// Flags for A_CustomPunch +const int CPF_USEAMMO = 1; +const int CPF_DAGGER = 2; +const int CPF_PULLIN = 4; + // Activation flags enum { diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 48a966878..3a4dd20d9 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -7,7 +7,7 @@ ACTOR Inventory native Inventory.PickupSound "misc/i_pkup" action native A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); + action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff"); From b2cef54d7291cf92c3f153a39f70507d3fe63bf8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 10:11:50 +0000 Subject: [PATCH 084/251] - fixed: Classes inherited from PowerScanner didn't work anymore. SVN r2368 (trunk) --- src/actor.h | 2 +- src/am_map.cpp | 2 +- src/p_mobj.cpp | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/actor.h b/src/actor.h index 9621ab733..db4d07dbb 100644 --- a/src/actor.h +++ b/src/actor.h @@ -646,7 +646,7 @@ public: bool CheckLocalView (int playernum) const; // Finds the first item of a particular type. - AInventory *FindInventory (const PClass *type); + AInventory *FindInventory (const PClass *type, bool subclass = false); AInventory *FindInventory (FName type); template T *FindInventory () { diff --git a/src/am_map.cpp b/src/am_map.cpp index 9987876a9..36d31a00e 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2127,7 +2127,7 @@ void AM_Drawer () return; bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0; - bool allthings = allmap && players[consoleplayer].mo->FindInventory() != NULL; + bool allthings = allmap && players[consoleplayer].mo->FindInventory(RUNTIME_CLASS(APowerScanner), true) != NULL; AM_initColors (viewactive); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ff896a0f1..6fd05c040 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -772,7 +772,7 @@ AInventory *AActor::DropInventory (AInventory *item) // //============================================================================ -AInventory *AActor::FindInventory (const PClass *type) +AInventory *AActor::FindInventory (const PClass *type, bool subclass) { AInventory *item; @@ -781,9 +781,19 @@ AInventory *AActor::FindInventory (const PClass *type) assert (type->ActorInfo != NULL); for (item = Inventory; item != NULL; item = item->Inventory) { - if (item->GetClass() == type) + if (!subclass) { - break; + if (item->GetClass() == type) + { + break; + } + } + else + { + if (item->IsKindOf(type)) + { + break; + } } } return item; From 32f3d0051483bfb63214ac88f37a532f4c4df992 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 10:24:56 +0000 Subject: [PATCH 085/251] - fixed: Stopping music did not clear the variable used to restart the last played song. SVN r2369 (trunk) --- src/s_sound.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index b7a63e51b..c31e2f7ac 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2328,6 +2328,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) // Don't choke if the map doesn't have a song attached S_StopMusic (true); mus_playing.name = ""; + LastSong = ""; return true; } From e2ce20a445ba87c4fb4e4f7bcc60c363790794aa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 10:38:38 +0000 Subject: [PATCH 086/251] - fixed: A_Print and related functions should not make a use state chain succeed. - fixed: APowerIronFeet must continuously reset the player's air supply. SVN r2370 (trunk) --- src/g_shared/a_artifacts.cpp | 19 +++++++++++++++---- src/g_shared/a_artifacts.h | 1 + src/thingdef/thingdef_codeptr.cpp | 4 ++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 304c9059e..088e480c5 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -750,10 +750,6 @@ void APowerIronFeet::AbsorbDamage (int damage, FName damageType, int &newdamage) if (damageType == NAME_Drowning) { newdamage = 0; - if (Owner->player != NULL) - { - Owner->player->mo->ResetAirSupply (); - } } else if (Inventory != NULL) { @@ -761,6 +757,21 @@ void APowerIronFeet::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +//=========================================================================== +// +// APowerIronFeet :: DoEffect +// +//=========================================================================== + +void APowerIronFeet::DoEffect () +{ + if (Owner->player != NULL) + { + Owner->player->mo->ResetAirSupply (); + } +} + + // Strife Environment Suit Powerup ------------------------------------------- IMPLEMENT_CLASS (APowerMask) diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 00e39247e..13ff0f1d4 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -86,6 +86,7 @@ class APowerIronFeet : public APowerup DECLARE_CLASS (APowerIronFeet, APowerup) public: void AbsorbDamage (int damage, FName damageType, int &newdamage); + void DoEffect (); }; class APowerMask : public APowerIronFeet diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index df1a9c23e..c76c5842d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1805,6 +1805,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) C_MidPrint(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; } + ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! } //=========================================================================== @@ -1835,6 +1836,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) FString formatted = strbin1(text); C_MidPrintBold(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; + ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! } //=========================================================================== @@ -1848,6 +1850,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) ACTION_PARAM_START(1); ACTION_PARAM_STRING(text, 0); Printf("%s\n", text); + ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! } //=========================================================================== @@ -1861,6 +1864,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) ACTION_PARAM_START(1); ACTION_PARAM_INT(num, 0); Printf("%d\n", num); + ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! } //=========================================================================== From 6ff2abc53d3acb3f5b23acf811635b68d974adf3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 10:44:06 +0000 Subject: [PATCH 087/251] - fixed: Setting +NOCLIP for a player class did not work. SVN r2371 (trunk) --- src/p_user.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index ec80954b4..a350babab 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2041,7 +2041,7 @@ void P_PlayerThink (player_t *player) player->inventorytics--; } // No-clip cheat - if (player->cheats & CF_NOCLIP) + if (player->cheats & CF_NOCLIP || (player->mo->GetDefault()->flags & MF_NOCLIP)) { player->mo->flags |= MF_NOCLIP; } From f73fe072f6f14361fa829aa8bf5edc3e53724d10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 10:50:43 +0000 Subject: [PATCH 088/251] - Set +NEVERRESPAWN flag for several Strife monsters that should not respawn in Bloodbath skill. SVN r2372 (trunk) --- wadsrc/static/actors/strife/acolyte.txt | 1 + wadsrc/static/actors/strife/loremaster.txt | 1 + wadsrc/static/actors/strife/macil.txt | 1 + wadsrc/static/actors/strife/oracle.txt | 1 + wadsrc/static/actors/strife/sentinel.txt | 1 + wadsrc/static/actors/strife/strifebishop.txt | 1 + 6 files changed, 6 insertions(+) diff --git a/wadsrc/static/actors/strife/acolyte.txt b/wadsrc/static/actors/strife/acolyte.txt index 139b13056..73b27864b 100644 --- a/wadsrc/static/actors/strife/acolyte.txt +++ b/wadsrc/static/actors/strife/acolyte.txt @@ -13,6 +13,7 @@ ACTOR Acolyte : StrifeHumanoid +SEESDAGGERS +NOSPLASHALERT +FLOORCLIP + +NEVERRESPAWN MinMissileChance 150 Tag "ACOLYTE" SeeSound "acolyte/sight" diff --git a/wadsrc/static/actors/strife/loremaster.txt b/wadsrc/static/actors/strife/loremaster.txt index 39ffcea4c..dd79c0f19 100644 --- a/wadsrc/static/actors/strife/loremaster.txt +++ b/wadsrc/static/actors/strife/loremaster.txt @@ -20,6 +20,7 @@ ACTOR Loremaster 12 +INCOMBAT +LOOKALLAROUND +NOICEDEATH + +NEVERRESPAWN DamageFactor "Fire", 0.5 MinMissileChance 150 Tag "PRIEST" diff --git a/wadsrc/static/actors/strife/macil.txt b/wadsrc/static/actors/strife/macil.txt index ba99be435..3666728e0 100644 --- a/wadsrc/static/actors/strife/macil.txt +++ b/wadsrc/static/actors/strife/macil.txt @@ -16,6 +16,7 @@ ACTOR Macil1 64 +NOICEDEATH +NOSPLASHALERT +NODAMAGE + +NEVERRESPAWN DamageFactor "Fire", 0.5 MinMissileChance 150 SeeSound "macil/sight" diff --git a/wadsrc/static/actors/strife/oracle.txt b/wadsrc/static/actors/strife/oracle.txt index ca25f2526..03b80c894 100644 --- a/wadsrc/static/actors/strife/oracle.txt +++ b/wadsrc/static/actors/strife/oracle.txt @@ -11,6 +11,7 @@ ACTOR Oracle 199 Monster +NOTDMATCH +NOBLOOD + +NEVERRESPAWN DamageFactor "Fire", 0.5 DamageFactor "SpectralLow", 0 MaxDropoffHeight 32 diff --git a/wadsrc/static/actors/strife/sentinel.txt b/wadsrc/static/actors/strife/sentinel.txt index 8128063c4..14bbaf8e1 100644 --- a/wadsrc/static/actors/strife/sentinel.txt +++ b/wadsrc/static/actors/strife/sentinel.txt @@ -20,6 +20,7 @@ ACTOR Sentinel 3006 +INCOMBAT +MISSILEMORE +LOOKALLAROUND + +NEVERRESPAWN MinMissileChance 150 SeeSound "sentinel/sight" DeathSound "sentinel/death" diff --git a/wadsrc/static/actors/strife/strifebishop.txt b/wadsrc/static/actors/strife/strifebishop.txt index 303129271..dcedf7f58 100644 --- a/wadsrc/static/actors/strife/strifebishop.txt +++ b/wadsrc/static/actors/strife/strifebishop.txt @@ -17,6 +17,7 @@ ACTOR StrifeBishop 187 +FLOORCLIP +INCOMBAT +NOICEDEATH + +NEVERRESPAWN DamageFactor "Fire", 0.5 MinMissileChance 150 MaxDropoffHeight 32 From e535b40a9e1f8415d3fdf3ecebe81c859817fe66 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 13 Jun 2010 11:14:01 +0000 Subject: [PATCH 089/251] - fixed: All melee attack functions only used the target acquired by P_AimLineAttack for all subsequent calculations, not the actual victim of the attack. SVN r2373 (trunk) --- src/g_doom/a_doomweaps.cpp | 3 ++- src/g_doom/a_scriptedmarine.cpp | 4 ++-- src/g_heretic/a_chicken.cpp | 4 ++-- src/g_heretic/a_hereticweaps.cpp | 4 ++-- src/g_hexen/a_clericmace.cpp | 4 ++-- src/g_hexen/a_clericstaff.cpp | 4 ++-- src/g_hexen/a_fighteraxe.cpp | 4 ++-- src/g_hexen/a_fighterhammer.cpp | 4 ++-- src/g_hexen/a_fighterplayer.cpp | 4 ++-- src/g_hexen/a_pig.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 2 +- src/p_local.h | 4 ++-- src/p_map.cpp | 19 ++++++++++++++++--- src/thingdef/thingdef_codeptr.cpp | 2 +- 14 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 026da4c5e..7cd53b49c 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -52,7 +52,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) angle += pr_punch.Random2() << 18; pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true); + + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget); // turn to face target if (linetarget) diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 150b7eb79..a6dd7f7b9 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -264,7 +264,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw) P_LineAttack (self, angle, MELEERANGE+1, P_AimLineAttack (self, angle, MELEERANGE+1, &linetarget), damage, - NAME_Melee, pufftype); + NAME_Melee, pufftype, false, &linetarget); if (!linetarget) { @@ -318,7 +318,7 @@ static void MarinePunch(AActor *self, int damagemul) A_FaceTarget (self); angle = self->angle + (pr_m_punch.Random2() << 18); pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true); + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget); // turn to face target if (linetarget) diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 86e71774f..a8b8c98d3 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -175,7 +175,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) damage = 1 + (pr_beakatkpl1()&3); angle = player->mo->angle; slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { player->mo->angle = R_PointToAngle2 (player->mo->x, @@ -208,7 +208,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) damage = pr_beakatkpl2.HitDice (4); angle = player->mo->angle; slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true); + P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget); if (linetarget) { player->mo->angle = R_PointToAngle2 (player->mo->x, diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index f17e72545..ad0115089 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -85,7 +85,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) angle = self->angle; angle += pr_sap.Random2() << 18; slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true); + P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &linetarget); if (linetarget) { //S_StartSound(player->mo, sfx_stfhit); @@ -273,7 +273,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) pufftype = PClass::FindClass("GauntletPuff1"); } slope = P_AimLineAttack (self, angle, dist, &linetarget); - P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype); + P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &linetarget); if (!linetarget) { if (pr_gatk() > 64) diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index d834dcd1b..9cb512286 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -36,7 +36,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); AdjustPlayerAngle (player->mo, linetarget); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); @@ -46,7 +46,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { - P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); AdjustPlayerAngle (player->mo, linetarget); // player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->y, linetarget->x, linetarget->y); diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 03b8c7518..8dc8c0916 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -70,7 +70,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff")); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); if (((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0))|| linetarget->flags3&MF3_ISMONSTER) @@ -94,7 +94,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { - P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff")); + P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindClass ("CStaffPuff"), false, &linetarget); pmo->angle = R_PointToAngle2 (pmo->x, pmo->y, linetarget->x, linetarget->y); if ((linetarget->player && (!linetarget->IsTeammate (pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER) diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 281d20c2c..7dd5ac06e 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -225,7 +225,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget); if (linetarget) { - P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true); + P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { P_ThrustMobj (linetarget, angle, power); @@ -238,7 +238,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget); if (linetarget) { - P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true); + P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); if (linetarget->flags3&MF3_ISMONSTER) { P_ThrustMobj (linetarget, angle, power); diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 2c457c035..ddfab12d4 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -49,7 +49,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if (linetarget) { - P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); AdjustPlayerAngle(pmo, linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { @@ -62,7 +62,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if(linetarget) { - P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true); + P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); AdjustPlayerAngle(pmo, linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index ba1bc9e82..078a063e0 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -165,7 +165,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) power = 6*FRACUNIT; pufftype = PClass::FindClass ("HammerPuff"); } - P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true); + P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { P_ThrustMobj (linetarget, angle, power); @@ -184,7 +184,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) power = 6*FRACUNIT; pufftype = PClass::FindClass ("HammerPuff"); } - P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true); + P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) { P_ThrustMobj (linetarget, angle, power); diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index 21d2ab936..437a336a3 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -75,7 +75,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) damage = 3+(pr_snoutattack()&3); angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE, &linetarget); - puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true); + puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &linetarget); S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); if(linetarget) { diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 97526bf67..bf5cb124e 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -110,7 +110,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) angle = self->angle + (pr_jabdagger.Random2() << 18); pitch = P_AimLineAttack (self, angle, 80*FRACUNIT, &linetarget); - P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true); + P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true, &linetarget); // turn to face target if (linetarget) diff --git a/src/p_local.h b/src/p_local.h index fc9068cd0..2092f8f4f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -418,8 +418,8 @@ enum ALF_CHECKCONVERSATION = 8, }; -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, bool ismelee = false); -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, bool ismelee = false, AActor **victim = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false, AActor **victim = NULL); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version diff --git a/src/p_map.cpp b/src/p_map.cpp index 4888f8479..40344db83 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3297,7 +3297,7 @@ static bool CheckForSpectral (FTraceResults &res) //========================================================================== AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, const PClass *pufftype, bool ismeleeattack) + int pitch, int damage, FName damageType, const PClass *pufftype, bool ismeleeattack, AActor **victim) { fixed_t vx, vy, vz, shootz; FTraceResults trace; @@ -3308,6 +3308,11 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor *puff = NULL; int flags = ismeleeattack? PF_MELEERANGE : 0; + if (victim != NULL) + { + *victim = NULL; + } + angle >>= ANGLETOFINESHIFT; pitch = (angle_t)(pitch) >> ANGLETOFINESHIFT; @@ -3490,6 +3495,10 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, flags); } + if (victim != NULL) + { + *victim = trace.Actor; + } } if (trace.CrossedWater) { @@ -3511,16 +3520,20 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, - int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack) + int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack, AActor **victim) { const PClass * type = PClass::FindClass(pufftype); + if (victim != NULL) + { + *victim = NULL; + } if (type == NULL) { Printf("Attempt to spawn unknown actor type '%s'\n", pufftype.GetChars()); } else { - return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack); + return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack, victim); } return NULL; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c76c5842d..a4977eaa6 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1167,7 +1167,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); - P_LineAttack (self, angle, Range, pitch, Damage, NAME_None, PuffType, true); + P_LineAttack (self, angle, Range, pitch, Damage, NAME_None, PuffType, true, &linetarget); // turn to face target if (linetarget) From 1bbae4a8f2a00db5d13f8fd6425ada85bc96e38c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 13 Jun 2010 16:50:54 +0000 Subject: [PATCH 090/251] - Fixed: PClass::InitializeActors() did not initialize the ActorInfo's ColorSets. Why this only caused problems on PPC Macs, I do not know. SVN r2374 (trunk) --- src/dobjtype.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b2622d1db..3e733ce36 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -410,6 +410,7 @@ void PClass::InitializeActorInfo () info->StateList = NULL; info->DamageFactors = NULL; info->PainChances = NULL; + info->ColorSets = NULL; m_RuntimeActors.Push (this); } From 34d8212d648b3bcfe0edef89ed328986f4c121d3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 18 Jun 2010 03:35:41 +0000 Subject: [PATCH 091/251] - Changed G_ChangeLevel()'s parameter list to match the ACS version's. - Added resethealth to complement resetinventory. SVN r2377 (trunk) --- src/d_net.cpp | 2 +- src/g_game.cpp | 12 ++++++++++-- src/g_game.h | 2 +- src/g_level.cpp | 36 ++++++++++++++++++++---------------- src/g_level.h | 14 ++++++++++++-- src/g_mapinfo.cpp | 1 + src/p_acs.cpp | 7 +------ src/p_acs.h | 10 ---------- src/p_lnspec.cpp | 2 +- 9 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 264aed1df..997919963 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2021,7 +2021,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) // Using LEVEL_NOINTERMISSION tends to throw the game out of sync. // That was a long time ago. Maybe it works now? level.flags |= LEVEL_CHANGEMAPCHEAT; - G_ChangeLevel(s, pos, false); + G_ChangeLevel(s, pos, 0); break; case DEM_SUICIDE: diff --git a/src/g_game.cpp b/src/g_game.cpp index fc4a21772..d68ead9ef 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1163,7 +1163,9 @@ void G_Ticker () // G_PlayerFinishLevel // Called when a player completes a level. // -void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory) +// flags is checked for RESETINVENTORY and RESETHEALTH only. + +void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags) { AInventory *item, *next; player_t *p; @@ -1235,8 +1237,14 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory P_UndoPlayerMorph (p, p, 0, true); } + // Resets player health to default + if (flags & CHANGELEVEL_RESETHEALTH) + { + p->health = p->mo->health = p->mo->SpawnHealth(); + } + // Clears the entire inventory and gives back the defaults for starting a game - if (resetinventory) + if (flags & CHANGELEVEL_RESETINVENTORY) { AInventory *inv = p->mo->Inventory; diff --git a/src/g_game.h b/src/g_game.h index 56f16081b..20fdae892 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -71,7 +71,7 @@ enum EFinishLevelType FINISH_NoHub }; -void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory); +void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags); void G_DoReborn (int playernum, bool freshbot); diff --git a/src/g_level.cpp b/src/g_level.cpp index fbefb011d..b14959efe 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -529,10 +529,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel) static FString nextlevel; static int startpos; // [RH] Support for multiple starts per level extern int NoWipe; // [RH] Don't wipe when travelling in hubs -static bool startkeepfacing; // [RH] Support for keeping your facing angle -static bool resetinventory; // Reset the inventory to the player's default for the next level +static int changeflags; static bool unloading; -static bool g_nomonsters; //========================================================================== // @@ -543,8 +541,7 @@ static bool g_nomonsters; //========================================================================== -void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nextSkill, - bool nointermission, bool resetinv, bool nomonsters) +void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill) { level_info_t *nextinfo = NULL; @@ -573,25 +570,32 @@ void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nex if (nextSkill != -1) NextSkill = nextSkill; - g_nomonsters = nomonsters; - - if (nointermission) level.flags |= LEVEL_NOINTERMISSION; + if (flags & CHANGELEVEL_NOINTERMISSION) + { + level.flags |= LEVEL_NOINTERMISSION; + } cluster_info_t *thiscluster = FindClusterInfo (level.cluster); cluster_info_t *nextcluster = nextinfo? FindClusterInfo (nextinfo->cluster) : NULL; startpos = position; - startkeepfacing = keepFacing; gameaction = ga_completed; - resetinventory = resetinv; if (nextinfo != NULL) { if (thiscluster != nextcluster || (thiscluster && !(thiscluster->flags & CLUSTER_HUB))) { - resetinventory |= !!(nextinfo->flags2 & LEVEL2_RESETINVENTORY); + if (nextinfo->flags2 & LEVEL2_RESETINVENTORY) + { + flags |= CHANGELEVEL_RESETINVENTORY; + } + if (nextinfo->flags2 & LEVEL2_RESETHEALTH) + { + flags |= CHANGELEVEL_RESETHEALTH; + } } } + changeflags = flags; bglobal.End(); //Added by MC: @@ -667,12 +671,12 @@ const char *G_GetSecretExitMap() void G_ExitLevel (int position, bool keepFacing) { - G_ChangeLevel(G_GetExitMap(), position, keepFacing); + G_ChangeLevel(G_GetExitMap(), position, keepFacing ? CHANGELEVEL_KEEPFACING : 0); } void G_SecretExitLevel (int position) { - G_ChangeLevel(G_GetSecretExitMap(), position, false); + G_ChangeLevel(G_GetSecretExitMap(), position, 0); } //========================================================================== @@ -786,7 +790,7 @@ void G_DoCompleted (void) { if (playeringame[i]) { // take away appropriate inventory - G_PlayerFinishLevel (i, mode, resetinventory); + G_PlayerFinishLevel (i, mode, changeflags); } } @@ -927,7 +931,7 @@ void G_DoLoadLevel (int position, bool autosave) players[i].fragcount = 0; } - if (g_nomonsters) + if (changeflags & CHANGELEVEL_NOMONSTERS) { level.flags2 |= LEVEL2_NOMONSTERS; } @@ -1164,7 +1168,7 @@ void G_FinishTravel () // The player being spawned here is a short lived dummy and // must not start any ENTER script or big problems will happen. pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], true); - if (!startkeepfacing) + if (!changeflags & CHANGELEVEL_KEEPFACING) { pawn->angle = pawndup->angle; pawn->pitch = pawndup->pitch; diff --git a/src/g_level.h b/src/g_level.h index 4edf4409e..701437452 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -201,6 +201,7 @@ enum ELevelFlags LEVEL2_SMOOTHLIGHTING = 0x01000000, // Level uses the smooth lighting feature. LEVEL2_POLYGRIND = 0x02000000, // Polyobjects grind corpses to gibs. LEVEL2_RESETINVENTORY = 0x04000000, // Resets player inventory when starting this level (unless in a hub) + LEVEL2_RESETHEALTH = 0x08000000, // Resets player health when starting this level (unless in a hub) }; @@ -491,8 +492,17 @@ void G_SecretExitLevel (int position); const char *G_GetExitMap(); const char *G_GetSecretExitMap(); -void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int nextSkill=-1, - bool nointermission=false, bool resetinventory=false, bool nomonsters=false); +enum +{ + CHANGELEVEL_KEEPFACING = 1, + CHANGELEVEL_RESETINVENTORY = 2, + CHANGELEVEL_NOMONSTERS = 4, + CHANGELEVEL_CHANGESKILL = 8, + CHANGELEVEL_NOINTERMISSION = 16, + CHANGELEVEL_RESETHEALTH = 32, +}; + +void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1); void G_SetForEndGame (char *nextmap); diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 53cd9ee5c..004b47a2f 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1373,6 +1373,7 @@ MapFlagHandlers[] = { "grinding_polyobj", MITYPE_SETFLAG2, LEVEL2_POLYGRIND, 0 }, { "no_grinding_polyobj", MITYPE_CLRFLAG2, LEVEL2_POLYGRIND, 0 }, { "resetinventory", MITYPE_SETFLAG2, LEVEL2_RESETINVENTORY, 0 }, + { "resethealth", MITYPE_SETFLAG2, LEVEL2_RESETHEALTH, 0 }, { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX}, diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c8afb1f26..eb69c60be 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6250,12 +6250,7 @@ int DLevelScript::RunScript () case PCD_CHANGELEVEL: { - int flags = STACK(2); - G_ChangeLevel(FBehavior::StaticLookupString(STACK(4)), STACK(3), - !!(flags & CHANGELEVEL_KEEPFACING), STACK(1), - !!(flags & CHANGELEVEL_NOINTERMISSION), - !!(flags & CHANGELEVEL_RESETINVENTORY), - !!(flags & CHANGELEVEL_NOMONSTERS)); + G_ChangeLevel(FBehavior::StaticLookupString(STACK(4)), STACK(3), STACK(2), STACK(1)); sp -= 4; } break; diff --git a/src/p_acs.h b/src/p_acs.h index c57af5793..8e193d41e 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -667,16 +667,6 @@ public: SCRIPT_ModulusBy0, }; - enum - { - CHANGELEVEL_KEEPFACING = 1, - CHANGELEVEL_RESETINVENTORY = 2, - CHANGELEVEL_NOMONSTERS = 4, - CHANGELEVEL_CHANGESKILL = 8, - CHANGELEVEL_NOINTERMISSION = 16 - }; - - DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module, bool backSide, int arg0, int arg1, int arg2, int always); ~DLevelScript (); diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index cf79e376b..fb0bd31ab 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -792,7 +792,7 @@ FUNC(LS_Teleport_NewMap) if (info && CheckIfExitIsGood (it, info)) { - G_ChangeLevel(info->mapname, arg1, !!arg2); + G_ChangeLevel(info->mapname, arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0); return true; } } From 141cf825cf1c3d6db9f0a375b9ed1f5edffef477 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 18 Jun 2010 03:52:04 +0000 Subject: [PATCH 092/251] - Fixed: iCopyColors() should not invert the grayscale value for special colormaps, since this is already handled by the GrayscaleToColor array for the one colormap that needs it. SVN r2379 (trunk) --- src/textures/bitmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textures/bitmap.cpp b/src/textures/bitmap.cpp index 20dfd38bd..b552f9797 100644 --- a/src/textures/bitmap.cpp +++ b/src/textures/bitmap.cpp @@ -101,7 +101,7 @@ void iCopyColors(BYTE *pout, const BYTE *pin, int count, int step, FCopyInfo *in a = TSrc::A(pin); if (TBlend::ProcessAlpha0() || a) { - gray = clamp(255 - TSrc::Gray(pin),0,255); + gray = clamp(TSrc::Gray(pin),0,255); PalEntry pe = cm->GrayscaleToColor[gray]; TBlend::OpC(pout[TDest::RED], pe.r , a, inf); From e379d243884f5e2ebace91d0543dd479e3b2b113 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 18 Jun 2010 04:10:05 +0000 Subject: [PATCH 093/251] - Fixed: The intensity scalar for building DesaturateColormaps was off by one. SVN r2380 (trunk) --- src/v_palette.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v_palette.cpp b/src/v_palette.cpp index c47f75370..231e160c0 100644 --- a/src/v_palette.cpp +++ b/src/v_palette.cpp @@ -483,12 +483,12 @@ void InitPalette () { int intensity = (GPalette.BaseColors[c].r * 77 + GPalette.BaseColors[c].g * 143 + - GPalette.BaseColors[c].b * 37) / 255; + GPalette.BaseColors[c].b * 37) / 256; int r = (GPalette.BaseColors[c].r * (31-m) + intensity *m) / 31; int g = (GPalette.BaseColors[c].g * (31-m) + intensity *m) / 31; int b = (GPalette.BaseColors[c].b * (31-m) + intensity *m) / 31; - shade[c] = ColorMatcher.Pick (r, g, b); + shade[c] = ColorMatcher.Pick(r, g, b); } } From 503b9349382ca1578e15162e5d7b71e72dbaee1c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 20 Jun 2010 04:41:23 +0000 Subject: [PATCH 094/251] - Added better error messages for MIDI playback failure than just "MIDI playback failure". SVN r2383 (trunk) --- src/sound/i_musicinterns.h | 2 +- src/sound/music_midistream.cpp | 88 +++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index a715e844c..e5c4771eb 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -288,7 +288,7 @@ protected: void OutputVolume (DWORD volume); int FillBuffer(int buffer_num, int max_events, DWORD max_time); - bool ServiceEvent(); + int ServiceEvent(); int VolumeControllerChange(int channel, int volume); static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2); diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 6771906a0..5ed94c34c 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -518,9 +518,59 @@ void MIDIStreamer::Update() if (PlayerThread != NULL && WaitForSingleObject(PlayerThread, 0) == WAIT_OBJECT_0) { + static const char *const MMErrorCodes[] = + { + "No error", + "Unspecified error", + "Device ID out of range", + "Driver failed enable", + "Device already allocated", + "Device handle is invalid", + "No device driver present", + "Memory allocation error", + "Function isn't supported", + "Error value out of range", + "Invalid flag passed", + "Invalid parameter passed", + "Handle being used simultaneously on another thread", + "Specified alias not found", + "Bad registry database", + "Registry key not found", + "Registry read error", + "Registry write error", + "Registry delete error", + "Registry value not found", + "Driver does not call DriverCallback", + "More data to be returned", + }; + static const char *const MidiErrorCodes[] = + { + "MIDI header not prepared", + "MIDI still playing something", + "MIDI no configured instruments", + "MIDI hardware is still busy", + "MIDI port no longer connected", + "MIDI invalid MIF", + "MIDI operation unsupported with open mode", + "MIDI through device 'eating' a message", + }; + DWORD code = 0xABADCAFE; + GetExitCodeThread(PlayerThread, &code); CloseHandle(PlayerThread); PlayerThread = NULL; - Printf ("MIDI playback failure\n"); + Printf ("MIDI playback failure: "); + if (code >= 0 && code < countof(MMErrorCodes)) + { + Printf("%s\n", MMErrorCodes[code]); + } + else if (code >= MIDIERR_BASE && code < MIDIERR_BASE + countof(MidiErrorCodes)) + { + Printf("%s\n", MidiErrorCodes[code - MIDIERR_BASE]); + } + else + { + Printf("%08x\n", code); + } Stop(); } #endif @@ -553,6 +603,7 @@ DWORD WINAPI MIDIStreamer::PlayerProc (LPVOID lpParameter) DWORD MIDIStreamer::PlayerLoop() { HANDLE events[2] = { BufferDoneEvent, ExitEvent }; + int res; SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); @@ -561,9 +612,9 @@ DWORD MIDIStreamer::PlayerLoop() switch (WaitForMultipleObjects(2, events, FALSE, INFINITE)) { case WAIT_OBJECT_0: - if (ServiceEvent()) + if (0 != (res = ServiceEvent())) { - return 1; + return res; } break; @@ -572,7 +623,7 @@ DWORD MIDIStreamer::PlayerLoop() default: // Should not happen. - return 1; + return MMSYSERR_ERROR; } } } @@ -584,28 +635,31 @@ DWORD MIDIStreamer::PlayerLoop() // // Fills the buffer that just finished playing with new events and appends // it to the MIDI stream queue. Stops the song if playback is over. Returns -// true if a problem occured and playback should stop. +// non-zero if a problem occured and playback should stop. // //========================================================================== -bool MIDIStreamer::ServiceEvent() +int MIDIStreamer::ServiceEvent() { + int res; + if (EndQueued == 1) { - return false; + return 0; } - if (0 != MIDI->UnprepareHeader(&Buffer[BufferNum])) + if (0 != (res = MIDI->UnprepareHeader(&Buffer[BufferNum]))) { - return true; + return res; } fill: - switch (FillBuffer(BufferNum, MAX_EVENTS, MAX_TIME)) + res = FillBuffer(BufferNum, MAX_EVENTS, MAX_TIME); + switch (res & 3) { case SONG_MORE: - if ((MIDI->NeedThreadedCallback() && 0 != MIDI->StreamOutSync(&Buffer[BufferNum])) || - (!MIDI->NeedThreadedCallback() && 0 != MIDI->StreamOut(&Buffer[BufferNum]))) + if ((MIDI->NeedThreadedCallback() && 0 != (res = MIDI->StreamOutSync(&Buffer[BufferNum]))) || + (!MIDI->NeedThreadedCallback() && 0 != (res = MIDI->StreamOut(&Buffer[BufferNum])))) { - return true; + return res; } else { @@ -623,9 +677,9 @@ fill: break; default: - return true; + return res >> 2; } - return false; + return 0; } //========================================================================== @@ -720,9 +774,9 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time) Buffer[buffer_num].lpData = (LPSTR)Events[buffer_num]; Buffer[buffer_num].dwBufferLength = DWORD((LPSTR)events - Buffer[buffer_num].lpData); Buffer[buffer_num].dwBytesRecorded = Buffer[buffer_num].dwBufferLength; - if (0 != MIDI->PrepareHeader(&Buffer[buffer_num])) + if (0 != (i = MIDI->PrepareHeader(&Buffer[buffer_num]))) { - return SONG_ERROR; + return SONG_ERROR | (i << 2); } return SONG_MORE; } From b8db84b6bc493775317efb02458f0cef584aa494 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 Jun 2010 17:57:32 +0000 Subject: [PATCH 095/251] - added a new dmflag to allow killing all monsters spawned by a boss brain's cubes after killing the brain (for those who like clean level statistics.) SVN r2385 (trunk) --- src/actor.h | 2 +- src/d_main.cpp | 1 + src/doomdef.h | 1 + src/g_doom/a_bossbrain.cpp | 16 ++++++++++++++++ src/m_options.cpp | 1 + 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index db4d07dbb..6e0c625f1 100644 --- a/src/actor.h +++ b/src/actor.h @@ -260,7 +260,7 @@ enum MF4_NOEXTREMEDEATH = 0x10000000, // this projectile or weapon never gibs its victim MF4_EXTREMEDEATH = 0x20000000, // this projectile or weapon always gibs its victim MF4_FRIGHTENED = 0x40000000, // Monster runs away from player - /* = 0x80000000, */ + MF4_BOSSSPAWNED = 0x80000000, // Spawned by a boss spawn cube // --- mobj.flags5 --- diff --git a/src/d_main.cpp b/src/d_main.cpp index 1fecffab9..c24b18480 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -459,6 +459,7 @@ CVAR (Flag, sv_chasecam, dmflags2, DF2_CHASECAM); CVAR (Flag, sv_disallowsuicide, dmflags2, DF2_NOSUICIDE); CVAR (Flag, sv_noautoaim, dmflags2, DF2_NOAUTOAIM); CVAR (Flag, sv_dontcheckammo, dmflags2, DF2_DONTCHECKAMMO); +CVAR (Flag, sv_killbossmonst, dmflags2, DF2_KILLBOSSMONST); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 716b2e105..3aa527523 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -293,6 +293,7 @@ enum DF2_NOSUICIDE = 1 << 22, // Players are not allowed to suicide. DF2_NOAUTOAIM = 1 << 23, // Players cannot use autoaim. DF2_DONTCHECKAMMO = 1 << 24, // Don't Check ammo when switching weapons. + DF2_KILLBOSSMONST = 1 << 25, // Kills all monsters spawned by a boss cube when the boss dies }; // [RH] Compatibility flags. diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 47374e617..0110b0ae5 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -76,6 +76,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) return; + // New dmflag: Kill all boss spawned monsters before ending the level. + if (dmflags2 & DF2_KILLBOSSMONST) + { + TThinkerIterator it; + AActor *mo; + while ((mo = it.Next())) + { + if (mo->flags4 & MF4_BOSSSPAWNED) + { + P_DamageMobj(mo, self, self, mo->health, NAME_None, + DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR); + } + } + } + G_ExitLevel (0, false); } @@ -250,6 +265,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) // telefrag anything in this spot P_TeleportMove (newmobj, newmobj->x, newmobj->y, newmobj->z, true); } + newmobj->flags4 |= MF4_BOSSSPAWNED; } } diff --git a/src/m_options.cpp b/src/m_options.cpp index 67aab6d62..324b45cc6 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1048,6 +1048,7 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Allow spying", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DISALLOW_SPYING} }, { bitflag, "Chasecam cheat", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_CHASECAM} }, { bitflag, "Check ammo for weapon switch", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DONTCHECKAMMO} }, + { bitflag, "Killing boss brain kills all its monsters", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_KILLBOSSMONST} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, { whitetext,"Deathmatch Settings", {NULL}, {0}, {0}, {0}, {NULL} }, From 7069ea88bb65e1c359d9b772635aca3071064540 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 21 Jun 2010 01:49:35 +0000 Subject: [PATCH 096/251] - Fixed erroneous allocation of class defaults using new to M_Malloc to match the rest of them. SVN r2386 (trunk) --- src/dobjtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 3e733ce36..a51e8ad0c 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -384,7 +384,7 @@ const PClass *PClass::FindClassTentative (FName name) void PClass::InitializeActorInfo () { Symbols.SetParentTable (&ParentClass->Symbols); - Defaults = new BYTE[Size]; + Defaults = (BYTE *)M_Malloc(Size); if (ParentClass->Defaults != NULL) { memcpy (Defaults, ParentClass->Defaults, ParentClass->Size); From 86b17d6d9f54f1f6757d013d0b16ae946d9b6ed8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Jun 2010 20:21:07 +0000 Subject: [PATCH 097/251] - Sync debugging output between ZDBSP and ZDoom's internal node builder. SVN r2389 (trunk) --- src/nodebuild.cpp | 14 ++++++++-- src/nodebuild_extract.cpp | 54 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 83393f7c3..63a736e6a 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -198,8 +198,15 @@ void FNodeBuilder::CreateSubsectorsForReal () qsort (&SegList[sub.firstline], sub.numlines, sizeof(USegPtr), SortSegs); // Convert seg pointers into indices + D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size())); for (unsigned int i = sub.firstline; i < SegList.Size(); ++i) { + D(Printf (PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", SegList[i].SegPtr - &Segs[0], + SegList[i].SegPtr->linedef == -1 ? '+' : ' ', + Vertices[SegList[i].SegPtr->v1].x>>16, + Vertices[SegList[i].SegPtr->v1].y>>16, + Vertices[SegList[i].SegPtr->v2].x>>16, + Vertices[SegList[i].SegPtr->v2].y>>16)); SegList[i].SegNum = DWORD(SegList[i].SegPtr - &Segs[0]); } Subsectors.Push (sub); @@ -296,7 +303,9 @@ bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int D(Printf (PRINT_LOG, " - seg %d(%d,%d)-(%d,%d) line %d front %d back %d\n", seg, Vertices[Segs[seg].v1].x>>16, Vertices[Segs[seg].v1].y>>16, Vertices[Segs[seg].v2].x>>16, Vertices[Segs[seg].v2].y>>16, - Segs[seg].linedef, Segs[seg].frontsector, Segs[seg].backsector)); + Segs[seg].linedef, + Segs[seg].frontsector == NULL ? -1 : Segs[seg].frontsector - sectors, + Segs[seg].backsector == NULL ? -1 : Segs[seg].backsector - sectors)); if (Segs[seg].linedef != -1 && Segs[seg].frontsector != sec // Segs with the same front and back sectors are allowed to reside @@ -1020,7 +1029,8 @@ void FNodeBuilder::PrintSet (int l, DWORD set) Printf (PRINT_LOG, "set %d:\n", l); for (; set != DWORD_MAX; set = Segs[set].next) { - Printf (PRINT_LOG, "\t%u(%td):%d(%d,%d)-%d(%d,%d) ", set, Segs[set].frontsector-sectors, + Printf (PRINT_LOG, "\t%u(%td)%c%d(%d,%d)-%d(%d,%d)\n", set, Segs[set].frontsector-sectors, + Segs[set].linedef == -1 ? '+' : ':', Segs[set].v1, Vertices[Segs[set].v1].x>>16, Vertices[Segs[set].v1].y>>16, Segs[set].v2, diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index ffa69f705..f363cc4ec 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -45,6 +45,14 @@ #include "templates.h" #include "r_main.h" +#if 0 +#define D(x) x +#define DD 1 +#else +#define D(x) do{}while(0) +#undef DD +#endif + void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, seg_t *&outSegs, int &segCount, subsector_t *&outSubs, int &subCount, @@ -63,7 +71,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, subCount = Subsectors.Size(); outSubs = new subsector_t[subCount]; - memset(outSubs,0,subCount * sizeof(subsector_t)); + memset(outSubs, 0, subCount * sizeof(subsector_t)); nodeCount = Nodes.Size (); outNodes = new node_t[nodeCount]; @@ -71,16 +79,19 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, memcpy (outNodes, &Nodes[0], nodeCount*sizeof(node_t)); for (i = 0; i < nodeCount; ++i) { + D(Printf(PRINT_LOG, "Node %d:\n", i)); // Go backwards because on 64-bit systems, both of the intchildren are // inside the first in-game child. for (int j = 1; j >= 0; --j) { if (outNodes[i].intchildren[j] & 0x80000000) { + D(Printf(PRINT_LOG, " subsector %d\n", outNodes[i].intchildren[j] & 0x7FFFFFFF)); outNodes[i].children[j] = (BYTE *)(outSubs + (outNodes[i].intchildren[j] & 0x7fffffff)) + 1; } else { + D(Printf(PRINT_LOG, " node %d\n", outNodes[i].intchildren[j])); outNodes[i].children[j] = outNodes + outNodes[i].intchildren[j]; } } @@ -120,6 +131,8 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, const FPrivSeg *org = &Segs[SegList[i].SegNum]; seg_t *out = &outSegs[i]; + D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2)); + out->v1 = outVerts + org->v1; out->v2 = outVerts + org->v2; out->backsector = org->backsector; @@ -131,7 +144,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, } } - //Printf ("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount); + D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount)); for (i = 0; i < Level.NumLines; ++i) { @@ -185,10 +198,26 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * prev = seg; firstVert = seg->v1; +#ifdef DD + Printf(PRINT_LOG, "--%d--\n", subsector); + for (j = first; j < max; ++j) + { + seg = &Segs[SegList[j].SegNum]; + angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); + Printf(PRINT_LOG, "%d%c %5d(%5d,%5d)->%5d(%5d,%5d) - %3.3f %d,%d\n", j, + seg->linedef == -1 ? '+' : ':', + seg->v1, Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16, + seg->v2, Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16, + double(ang/2)*180/(1<<30), + seg->planenum, seg->planefront); + } +#endif + if (diffplanes) { // A well-behaved subsector. Output the segs sorted by the angle formed by connecting // the subsector's center to their first vertex. + D(Printf(PRINT_LOG, "Well behaved subsector\n")); for (i = first + 1; i < max; ++i) { angle_t bestdiff = ANGLE_MAX; @@ -226,7 +255,9 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[seg->v1]); count++; } - +#ifdef DD + Printf(PRINT_LOG, "+%d\n", bestj); +#endif prevAngle -= bestdiff; seg->storedseg = PushGLSeg (segs, seg, outVerts); count++; @@ -237,6 +268,9 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * break; } } +#ifdef DD + Printf(PRINT_LOG, "\n"); +#endif } else { // A degenerate subsector. These are handled in three stages: @@ -248,6 +282,8 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * // to the start seg. // A dot product serves to determine distance from the start seg. + D(Printf(PRINT_LOG, "degenerate subsector\n")); + // Stage 1. Go forward. count += OutputDegenerateSubsector (segs, subsector, true, 0, prev, outVerts); @@ -263,6 +299,18 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[firstVert]); count++; } +#ifdef DD + Printf(PRINT_LOG, "Output GL subsector %d:\n", subsector); + for (i = segs.Size() - count; i < (int)segs.Size(); ++i) + { + Printf(PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", i, + segs[i].linedef == NULL ? '+' : ' ', + segs[i].v1->x>>16, + segs[i].v1->y>>16, + segs[i].v2->x>>16, + segs[i].v2->y>>16); + } +#endif return count; } From 551f0d31482b153271a205d9f38691eb6b2f8632 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Jun 2010 20:49:02 +0000 Subject: [PATCH 098/251] - Remove fakedblocker, since it was unused. SVN r2391 (trunk) --- src/p_map.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 40344db83..34f396317 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1212,7 +1212,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm) { sector_t *newsec; AActor *thingblocker; - AActor *fakedblocker; fixed_t realheight = thing->height; tm.thing = thing; @@ -1279,7 +1278,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm) // Check things first, possibly picking things up. thing->BlockingMobj = NULL; thingblocker = NULL; - fakedblocker = NULL; if (thing->player) { // [RH] Fake taller height to catch stepping up into things. thing->height = realheight + thing->MaxStepHeight; @@ -1326,7 +1324,6 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm) } // Nothing is blocking us, but this actor potentially could // if there is something else to step on. - fakedblocker = BlockingMobj; thing->BlockingMobj = NULL; } else From 9bf543af992ed0715f6022853d5e0a3a81d4162d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 30 Jun 2010 06:09:49 +0000 Subject: [PATCH 099/251] - Fixed: Episodes starting on a map with 8 characters in its lump name would not work. SVN r2394 (trunk) --- src/g_mapinfo.cpp | 1 + src/m_menu.cpp | 2 +- src/m_menu.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 004b47a2f..2b31f50f8 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1802,6 +1802,7 @@ void FMapInfoParser::ParseEpisodeInfo () EpisodeMenu[i].fulltext = !picisgfx; EpisodeNoSkill[i] = noskill; strncpy (EpisodeMaps[i], map, 8); + EpisodeMaps[i][8] = 0; } } diff --git a/src/m_menu.cpp b/src/m_menu.cpp index dfa04cd30..9bc25284e 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -391,7 +391,7 @@ oldmenuitem_t EpisodeMenu[MAX_EPISODES] = {1,0,0, NULL, M_Episode, CR_UNTRANSLATED}, }; -char EpisodeMaps[MAX_EPISODES][8]; +char EpisodeMaps[MAX_EPISODES][9]; bool EpisodeNoSkill[MAX_EPISODES]; oldmenu_t EpiDef = diff --git a/src/m_menu.h b/src/m_menu.h index f46b6a9e9..4f45cbed2 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -273,7 +273,7 @@ extern int CurrentItem; extern oldmenuitem_t EpisodeMenu[MAX_EPISODES]; extern bool EpisodeNoSkill[MAX_EPISODES]; -extern char EpisodeMaps[MAX_EPISODES][8]; +extern char EpisodeMaps[MAX_EPISODES][9]; extern oldmenu_t EpiDef; #endif From 853b8f8963f3697ee7ffc42c5902e993111d0d6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 30 Jun 2010 15:20:18 +0000 Subject: [PATCH 100/251] - did some profiling of P_InterceptVector. Here's the results I got: * the unaltered floating point version is 10% faster than the 64 bit integer version. * using doubles instead of floats increases performance by another 25%. * another 15% can be gained by manually optimizing the code. - P_InterceptVector now uses the optimized floating point version which is almost twice as fast as the 64bit integer version. SVN r2395 (trunk) --- src/p_maputl.cpp | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 14421fc50..f7874c345 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -63,21 +63,20 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy) // P_InterceptVector // // Returns the fractional intercept point along the first divline. -// This is only called by the addthings and addlines traversers. // //========================================================================== fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1) { -#if 1 // [RH] Use 64 bit ints, so long divlines don't overflow +#if 0 // [RH] Use 64 bit ints, so long divlines don't overflow - SQWORD den = ((SQWORD)v1->dy*v2->dx - (SQWORD)v1->dx*v2->dy) >> FRACBITS; + SQWORD den = ( ((SQWORD)v1->dy*v2->dx - (SQWORD)v1->dx*v2->dy) >> FRACBITS ); if (den == 0) return 0; // parallel SQWORD num = ((SQWORD)(v1->x - v2->x)*v1->dy + (SQWORD)(v2->y - v1->y)*v1->dx); return (fixed_t)(num / den); -#elif 1 // This is the original Doom version +#elif 0 // This is the original Doom version fixed_t frac; fixed_t num; @@ -97,19 +96,24 @@ fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1) return frac; -#else // UNUSED, float debug. +#else // optimized version of the float debug version. A lot faster on modern systens. - float frac; - float num; - float den; - float v1x = (float)v1->x/FRACUNIT; - float v1y = (float)v1->y/FRACUNIT; - float v1dx = (float)v1->dx/FRACUNIT; - float v1dy = (float)v1->dy/FRACUNIT; - float v2x = (float)v2->x/FRACUNIT; - float v2y = (float)v2->y/FRACUNIT; - float v2dx = (float)v2->dx/FRACUNIT; - float v2dy = (float)v2->dy/FRACUNIT; + + double frac; + double num; + double den; + + // There's no need to divide by FRACUNIT here. + // At the end both num and den will contain a factor + // 1/(FRACUNIT*FRACUNIT) so they'll cancel each other out. + double v1x = (double)v1->x; + double v1y = (double)v1->y; + double v1dx = (double)v1->dx; + double v1dy = (double)v1->dy; + double v2x = (double)v2->x; + double v2y = (double)v2->y; + double v2dx = (double)v2->dx; + double v2dy = (double)v2->dy; den = v1dy*v2dx - v1dx*v2dy; @@ -119,10 +123,11 @@ fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1) num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; frac = num / den; - return frac*FRACUNIT; + return FLOAT2FIXED(frac); #endif } + //========================================================================== // // P_LineOpening From 6df5e6f9cb7635bb31fb37bbd33277ee42b8a2b3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Jul 2010 09:35:39 +0000 Subject: [PATCH 101/251] - added Gez's anti-crossinclude submission but made some changes. Cross-includes overriding core files will produce fatal errors but cross-includes between PWADs will be tolerated. For DECORATE a command line override switch exists so that for testing the error can be disabled. SVN r2400 (trunk) --- src/d_main.cpp | 7 +++++-- src/g_mapinfo.cpp | 21 +++++++++++++++++++-- src/g_shared/sbarinfo.cpp | 31 +++++++++++++++++++------------ src/m_menu.cpp | 3 +++ src/thingdef/thingdef_parse.cpp | 13 +++++++++++++ 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index c24b18480..3b1e841a5 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1209,8 +1209,11 @@ void D_DoAdvanceDemo (void) case 2: pagetic = (int)(gameinfo.pageTime * TICRATE); gamestate = GS_DEMOSCREEN; - pagename = gameinfo.creditPages[pagecount]; - pagecount = (pagecount+1) % gameinfo.creditPages.Size(); + if (gameinfo.creditPages.Size() > 0) + { + pagename = gameinfo.creditPages[pagecount]; + pagecount = (pagecount+1) % gameinfo.creditPages.Size(); + } demosequence = 1; break; } diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 2b31f50f8..1eb6363fd 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -51,6 +51,8 @@ #include "doomstat.h" #include "d_player.h" #include "autosegs.h" +#include "version.h" +#include "v_text.h" int FindEndSequence (int type, const char *picname); @@ -1865,6 +1867,15 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i { sc.ScriptError("include file '%s' not found", sc.String); } + if (Wads.GetLumpFile(sc.LumpNum) != Wads.GetLumpFile(inclump)) + { + // Do not allow overriding includes from the default MAPINFO + if (Wads.GetLumpFile(sc.LumpNum) == 0) + { + I_FatalError("File %s is overriding core lump %s.", + Wads.GetWadFullName(Wads.GetLumpFile(inclump)), sc.String); + } + } FScanner saved_sc = sc; ParseMapInfo(inclump, gamedefaults, defaultinfo); sc = saved_sc; @@ -1956,12 +1967,18 @@ void G_ParseMapInfo (const char *basemapinfo) atterm(ClearEpisodes); - // Parse the default MAPINFO for the current game. + // Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3. if (basemapinfo != NULL) { FMapInfoParser parse; level_info_t defaultinfo; - parse.ParseMapInfo(Wads.GetNumForFullName(basemapinfo), gamedefaults, defaultinfo); + int baselump = Wads.GetNumForFullName(basemapinfo); + if (Wads.GetLumpFile(baselump) > 0) + { + I_FatalError("File %s is overriding core lump %s.", + Wads.GetWadFullName(Wads.GetLumpFile(baselump)), basemapinfo); + } + parse.ParseMapInfo(baselump, gamedefaults, defaultinfo); } static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", NULL }; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 1966b58f6..6895ce321 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -58,6 +58,7 @@ #include "v_palette.h" #include "p_acs.h" #include "gstrings.h" +#include "version.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum @@ -469,6 +470,7 @@ void SBarInfo::ParseSBarInfo(int lump) ParseSBarInfo(lump); continue; } + int baselump = -2; switch(sc.MustMatchString(SBarInfoTopLevel)) { case SBARINFO_BASE: @@ -477,24 +479,15 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(TK_Identifier); if(sc.Compare("Doom")) { - int lump = Wads.CheckNumForFullName("sbarinfo/doom.txt", true); - if(lump == -1) - sc.ScriptError("Standard Doom Status Bar not found."); - ParseSBarInfo(lump); + baselump = Wads.CheckNumForFullName("sbarinfo/doom.txt", true); } else if(sc.Compare("Heretic")) { - int lump = Wads.CheckNumForFullName("sbarinfo/heretic.txt", true); - if(lump == -1) - sc.ScriptError("Standard Heretic Status Bar not found."); - ParseSBarInfo(lump); + baselump = Wads.CheckNumForFullName("sbarinfo/heretic.txt", true); } else if(sc.Compare("Hexen")) { - int lump = Wads.CheckNumForFullName("sbarinfo/hexen.txt", true); - if(lump == -1) - sc.ScriptError("Standard Hexen Status Bar not found."); - ParseSBarInfo(lump); + baselump = Wads.CheckNumForFullName("sbarinfo/hexen.txt", true); } else if(sc.Compare("Strife")) gameType = GAME_Strife; @@ -502,6 +495,20 @@ void SBarInfo::ParseSBarInfo(int lump) gameType = GAME_Any; else sc.ScriptError("Bad game name: %s", sc.String); + // If one of the standard status bar should be loaded, baselump has been set to a different value. + if (baselump != -2) + { + if(baselump == -1) + { + sc.ScriptError("Standard %s status bar not found.", sc.String); + } + else if (Wads.GetLumpFile(baselump) > 0) + { + I_FatalError("File %s is overriding core lump sbarinfo/%s.txt.", + Wads.GetWadFullName(Wads.GetLumpFile(baselump)), sc.String); + } + ParseSBarInfo(baselump); + } sc.MustGetToken(';'); break; case SBARINFO_HEIGHT: diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 9bc25284e..49d5638ef 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -1293,6 +1293,9 @@ void M_DrawFrame (int left, int top, int width, int height) { FTexture *p; const gameborder_t *border = gameinfo.border; + // Sanity check for incomplete gameinfo + if (border == NULL) + return; int offset = border->offset; int right = left + width; int bottom = top + height; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 7712fe43b..07f4ca4e2 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -52,6 +52,9 @@ #include "thingdef_exp.h" #include "w_wad.h" #include "v_video.h" +#include "version.h" +#include "v_text.h" +#include "m_argv.h" void ParseOldDecoration(FScanner &sc, EDefinitionType def); @@ -1199,6 +1202,16 @@ void ParseDecorate (FScanner &sc) case TK_Include: { sc.MustGetString(); + // This check needs to remain overridable for testing purposes. + if (Wads.GetLumpFile(sc.LumpNum) == 0 && !Args->CheckParm("-allowdecoratecrossincludes")) + { + int includefile = Wads.GetLumpFile(Wads.CheckNumForFullName(sc.String, true)); + if (includefile != 0) + { + I_FatalError("File %s is overriding core lump %s.", + Wads.GetWadFullName(includefile), sc.String); + } + } FScanner newscanner; newscanner.Open(sc.String); ParseDecorate(newscanner); From e1e7cebd01bbec0e505e2f24b3bd80f15bf52f0c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Jul 2010 20:57:11 +0000 Subject: [PATCH 102/251] - fixed: The SBARINFO parser insisted that all player classes being specified have to exist. This, however, made it impossible to redefine the player classes in Hexen. SVN r2401 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 65be83f7d..9016c2427 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2398,8 +2398,10 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl break; } } + /* if(!foundClass) sc.ScriptError("Unkown PlayerClass '%s'.", sc.String); + */ if(!sc.CheckToken(',')) break; } From ccd4dc31896eb5ad6d64c9ebfba94e344144c7b8 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 1 Jul 2010 21:03:29 +0000 Subject: [PATCH 103/251] - Fixed: the hexen statusbar should assume you are the fighter if you are not one of the known classes. SVN r2402 (trunk) --- wadsrc/static/sbarinfo/hexen.txt | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/wadsrc/static/sbarinfo/hexen.txt b/wadsrc/static/sbarinfo/hexen.txt index 3dc900e98..f1c294525 100755 --- a/wadsrc/static/sbarinfo/hexen.txt +++ b/wadsrc/static/sbarinfo/hexen.txt @@ -114,38 +114,7 @@ statusbar Normal drawimage "ARMCLS", 255, 178; drawnumber 2, HUDFONT_RAVEN, untranslated, armorclass, 275, 176, 1; - playerclass Fighter - { - drawimage "WPSLOT0", 190, 162; - hasweaponpiece FWeapQuietus, 1 - { - drawimage "WPIECEF1", 190, 162; - } - hasweaponpiece FWeapQuietus, 2 - { - drawimage "WPIECEF2", 225, 162; - } - hasweaponpiece FWeapQuietus, 3 - { - drawimage "WPIECEF3", 234, 162; - } - hasweaponpiece FWeapQuietus, 1 - { - hasweaponpiece FWeapQuietus, 2 - { - hasweaponpiece FWeapQuietus, 3 - { - drawimage "WPFULL0", 190, 162; - } - } - } - - gamemode singleplayer - drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; - else - drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; - } - else playerclass Cleric + playerclass Cleric { drawimage "WPSLOT1", 190, 162; hasweaponpiece CWeapWraithverge, 1 @@ -207,6 +176,37 @@ statusbar Normal else drawgem translatable, interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; } + else + { + drawimage "WPSLOT0", 190, 162; + hasweaponpiece FWeapQuietus, 1 + { + drawimage "WPIECEF1", 190, 162; + } + hasweaponpiece FWeapQuietus, 2 + { + drawimage "WPIECEF2", 225, 162; + } + hasweaponpiece FWeapQuietus, 3 + { + drawimage "WPIECEF3", 234, 162; + } + hasweaponpiece FWeapQuietus, 1 + { + hasweaponpiece FWeapQuietus, 2 + { + hasweaponpiece FWeapQuietus, 3 + { + drawimage "WPFULL0", 190, 162; + } + } + } + + gamemode singleplayer + drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + else + drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; + } drawimage "LFEDGE", 0, 193; drawimage "RTEDGE", 277, 193; } From ea04d2bbdf3c39103adcaedc96a48f5065e974d9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 6 Jul 2010 20:32:24 +0000 Subject: [PATCH 104/251] - fixed: ZDoom aborted on old WADs containing a binary LANGUAGE lump. SVN r2414 (trunk) --- src/sc_man.cpp | 18 ++++++++++++++++++ src/sc_man.h | 2 ++ src/stringtable.cpp | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 298676dc6..a725c2703 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -331,6 +331,24 @@ void FScanner::RestorePos (const FScanner::SavedPos &pos) Crossed = false; } +//========================================================================== +// +// FScanner :: isText +// +// Checks if this is a text file. +// +//========================================================================== + +bool FScanner::isText() +{ + for(unsigned int i=0;i Date: Thu, 8 Jul 2010 21:16:01 +0000 Subject: [PATCH 105/251] - fixed: Hexen's melee weapons were missing some NULL pointer checks in the code that determines whether they hit something or not. SVN r2415 (trunk) --- src/g_hexen/a_clericmace.cpp | 18 ++++++++++-------- src/g_hexen/a_fighteraxe.cpp | 26 ++++++++++++++++---------- src/g_hexen/a_fighterhammer.cpp | 26 ++++++++++++++++---------- src/g_hexen/a_fighterplayer.cpp | 22 ++++++++++++++-------- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index 9cb512286..0e43f3df9 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -37,20 +37,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack) if (linetarget) { P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); - AdjustPlayerAngle (player->mo, linetarget); -// player->mo->angle = R_PointToAngle2(player->mo->x, -// player->mo->y, linetarget->x, linetarget->y); - goto macedone; + if (linetarget != NULL) + { + AdjustPlayerAngle (player->mo, linetarget); + goto macedone; + } } angle = player->mo->angle-i*(ANG45/16); slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget); if (linetarget) { P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); - AdjustPlayerAngle (player->mo, linetarget); -// player->mo->angle = R_PointToAngle2(player->mo->x, -// player->mo->y, linetarget->x, linetarget->y); - goto macedone; + if (linetarget != NULL) + { + AdjustPlayerAngle (player->mo, linetarget); + goto macedone; + } } } // didn't find any creatures, so try to strike any walls diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 7dd5ac06e..4223552b9 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -226,26 +226,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack) if (linetarget) { P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + { + P_ThrustMobj (linetarget, angle, power); + } + AdjustPlayerAngle (pmo, linetarget); + useMana++; + goto axedone; } - AdjustPlayerAngle (pmo, linetarget); - useMana++; - goto axedone; } angle = pmo->angle-i*(ANG45/16); slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget); if (linetarget) { P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget->flags3&MF3_ISMONSTER) + if (linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + if (linetarget->flags3&MF3_ISMONSTER) + { + P_ThrustMobj (linetarget, angle, power); + } + AdjustPlayerAngle (pmo, linetarget); + useMana++; + goto axedone; } - AdjustPlayerAngle (pmo, linetarget); - useMana++; - goto axedone; } } // didn't find any creatures, so try to strike any walls diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index ddfab12d4..85bbb3aae 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -50,26 +50,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) if (linetarget) { P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); - AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + AdjustPlayerAngle(pmo, linetarget); + if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + { + P_ThrustMobj (linetarget, angle, power); + } + pmo->special1 = false; // Don't throw a hammer + goto hammerdone; } - pmo->special1 = false; // Don't throw a hammer - goto hammerdone; } angle = pmo->angle-i*(ANG45/32); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if(linetarget) { P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, PClass::FindClass ("HammerPuff"), true, &linetarget); - AdjustPlayerAngle(pmo, linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget != NULL) { - P_ThrustMobj(linetarget, angle, power); + AdjustPlayerAngle(pmo, linetarget); + if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + { + P_ThrustMobj(linetarget, angle, power); + } + pmo->special1 = false; // Don't throw a hammer + goto hammerdone; } - pmo->special1 = false; // Don't throw a hammer - goto hammerdone; } } // didn't find any targets in meleerange, so set to throw out a hammer diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 078a063e0..0867a86e4 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -166,12 +166,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) pufftype = PClass::FindClass ("HammerPuff"); } P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + { + P_ThrustMobj (linetarget, angle, power); + } + AdjustPlayerAngle (pmo, linetarget); + goto punchdone; } - AdjustPlayerAngle (pmo, linetarget); - goto punchdone; } angle = pmo->angle-i * (ANG45/16); slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &linetarget); @@ -185,12 +188,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack) pufftype = PClass::FindClass ("HammerPuff"); } P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget); - if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + if (linetarget != NULL) { - P_ThrustMobj (linetarget, angle, power); + if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) + { + P_ThrustMobj (linetarget, angle, power); + } + AdjustPlayerAngle (pmo, linetarget); + goto punchdone; } - AdjustPlayerAngle (pmo, linetarget); - goto punchdone; } } // didn't find any creatures, so try to strike any walls From e379658143a42efc78978d8f3a5383cc57e4ae57 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 8 Jul 2010 23:59:45 +0000 Subject: [PATCH 106/251] - Added multimonitor support, as per Tom Seddon's code. vid_adapter controls which one to use, and vid_listadapters prints them. SVN r2417 (trunk) --- src/win32/fb_d3d9.cpp | 11 ++--- src/win32/win32iface.h | 8 +++- src/win32/win32video.cpp | 87 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index ea96a79cf..02da9910f 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -237,13 +237,14 @@ CVAR(Bool, vid_hwaalines, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -D3DFB::D3DFB (int width, int height, bool fullscreen) +D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen) : BaseWinFB (width, height) { D3DPRESENT_PARAMETERS d3dpp; LastHR = 0; + Adapter = adapter; D3DDevice = NULL; VertexBuffer = NULL; IndexBuffer = NULL; @@ -324,12 +325,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) HRESULT hr; LOG("CreateDevice attempt 1 hwvp\n"); - if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, + if (FAILED(hr = D3D->CreateDevice(Adapter, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { LOG2("CreateDevice returned hr %08x dev %p; attempt 2 swvp\n", hr, D3DDevice); - if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, + if (FAILED(D3D->CreateDevice(Adapter, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { @@ -337,12 +338,12 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) { d3dpp.FullScreen_RefreshRateInHz = 0; LOG2("CreateDevice returned hr %08x dev %p; attempt 3 (hwvp, default Hz)\n", hr, D3DDevice); - if (FAILED(hr = D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, + if (FAILED(hr = D3D->CreateDevice(Adapter, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && (hr != D3DERR_DEVICELOST || D3DDevice == NULL)) { LOG2("CreateDevice returned hr %08x dev %p; attempt 4 (swvp, default Hz)\n", hr, D3DDevice); - if (FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, + if (FAILED(D3D->CreateDevice(Adapter, D3DDEVTYPE_HAL, Window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &d3dpp, &D3DDevice)) && hr != D3DERR_DEVICELOST) { diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index d8e6af6a3..e46c392c3 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -75,6 +75,8 @@ class Win32Video : public IVideo bool GoFullscreen (bool yes); void BlankForGDI (); + void DumpAdapters (); + private: struct ModeInfo { @@ -97,12 +99,13 @@ class Win32Video : public IVideo int m_IteratorBits; bool m_IteratorFS; bool m_IsFullscreen; + UINT m_Adapter; void AddMode (int x, int y, int bits, int baseHeight, int doubling); void FreeModes (); static HRESULT WINAPI EnumDDModesCB (LPDDSURFACEDESC desc, void *modes); - void AddD3DModes (D3DFORMAT format); + void AddD3DModes (UINT adapter, D3DFORMAT format); void AddLowResModes (); void AddLetterboxModes (); void ScaleModes (int doubling); @@ -218,7 +221,7 @@ class D3DFB : public BaseWinFB { DECLARE_CLASS(D3DFB, BaseWinFB) public: - D3DFB (int width, int height, bool fullscreen); + D3DFB (UINT adapter, int width, int height, bool fullscreen); ~D3DFB (); bool IsValid (); @@ -416,6 +419,7 @@ private: PackingTexture *Packs; HRESULT LastHR; + UINT Adapter; IDirect3DDevice9 *D3DDevice; IDirect3DTexture9 *FBTexture; IDirect3DTexture9 *TempRenderTexture, *RenderTexture[2]; diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 7a2d14981..a610fd409 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -65,6 +65,7 @@ #include "doomerrors.h" #include "m_argv.h" #include "r_defs.h" +#include "v_text.h" #include "win32iface.h" @@ -107,12 +108,14 @@ IDirect3D9 *D3D; IDirect3DDevice9 *D3Device; CVAR (Bool, vid_forceddraw, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR (Int, vid_adapter, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // CODE -------------------------------------------------------------------- Win32Video::Win32Video (int parm) : m_Modes (NULL), - m_IsFullscreen (false) + m_IsFullscreen (false), + m_Adapter (D3DADAPTER_DEFAULT) { I_SetWndProc(); if (!InitD3D9()) @@ -168,9 +171,13 @@ bool Win32Video::InitD3D9 () goto closelib; } + // Select adapter. + m_Adapter = (vid_adapter < 1 || (UINT)vid_adapter > D3D->GetAdapterCount()) + ? D3DADAPTER_DEFAULT : (UINT)vid_adapter - 1u; + // Check that we have at least PS 1.4 available. D3DCAPS9 devcaps; - if (FAILED(D3D->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &devcaps))) + if (FAILED(D3D->GetDeviceCaps (m_Adapter, D3DDEVTYPE_HAL, &devcaps))) { goto d3drelease; } @@ -185,8 +192,8 @@ bool Win32Video::InitD3D9 () // Enumerate available display modes. FreeModes (); - AddD3DModes (D3DFMT_X8R8G8B8); - AddD3DModes (D3DFMT_R5G6B5); + AddD3DModes (m_Adapter, D3DFMT_X8R8G8B8); + AddD3DModes (m_Adapter, D3DFMT_R5G6B5); if (Args->CheckParm ("-2")) { // Force all modes to be pixel-doubled. ScaleModes (1); @@ -340,6 +347,70 @@ void Win32Video::BlankForGDI () static_cast (screen)->Blank (); } +//========================================================================== +// +// Win32Video :: DumpAdapters +// +// Dumps the list of display adapters to the console. Only meaningful for +// Direct3D. +// +//========================================================================== + +void Win32Video::DumpAdapters() +{ + if (D3D == NULL) + { + Printf("Multi-monitor support requires Direct3D.\n"); + return; + } + + UINT num_adapters = D3D->GetAdapterCount(); + + for (UINT i = 0; i < num_adapters; ++i) + { + D3DADAPTER_IDENTIFIER9 ai; + char moreinfo[64] = ""; + + if (FAILED(D3D->GetAdapterIdentifier(i, 0, &ai))) + { + continue; + } + // Strip trailing whitespace from adapter description. + for (char *p = ai.Description + strlen(ai.Description) - 1; + p >= ai.Description && isspace(*p); + --p) + { + *p = '\0'; + } + // Get monitor info from GDI for more details. Windows 95 apparently does not have + // the GetMonitorInfo function. I will leave this like this for now instead of using + // GetProcAddress to see if it's still worth worrying about Windows 95 support. + // (e.g. Will anybody complain that they can't run ZDoom anymore?) + HMONITOR hm = D3D->GetAdapterMonitor(i); + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hm, &mi)) + { + mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s", + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + mi.rcMonitor.left, mi.rcMonitor.top, + mi.dwFlags & MONITORINFOF_PRIMARY ? " (Primary)" : ""); + } + Printf("%s%u. %s%s\n", + i == m_Adapter ? TEXTCOLOR_BOLD : "", + i + 1, ai.Description, moreinfo); + } +} + +CCMD(vid_listadapters) +{ + if (Video != NULL) + { + static_cast(Video)->DumpAdapters(); + } +} + // Mode enumeration -------------------------------------------------------- HRESULT WINAPI Win32Video::EnumDDModesCB (LPDDSURFACEDESC desc, void *data) @@ -348,15 +419,15 @@ HRESULT WINAPI Win32Video::EnumDDModesCB (LPDDSURFACEDESC desc, void *data) return DDENUMRET_OK; } -void Win32Video::AddD3DModes (D3DFORMAT format) +void Win32Video::AddD3DModes (UINT adapter, D3DFORMAT format) { UINT modecount, i; D3DDISPLAYMODE mode; - modecount = D3D->GetAdapterModeCount (D3DADAPTER_DEFAULT, format); + modecount = D3D->GetAdapterModeCount (adapter, format); for (i = 0; i < modecount; ++i) { - if (D3D_OK == D3D->EnumAdapterModes (D3DADAPTER_DEFAULT, format, i, &mode)) + if (D3D_OK == D3D->EnumAdapterModes (adapter, format, i, &mode)) { AddMode (mode.Width, mode.Height, 8, mode.Height, 0); } @@ -571,7 +642,7 @@ DFrameBuffer *Win32Video::CreateFrameBuffer (int width, int height, bool fullscr if (D3D != NULL) { - fb = new D3DFB (width, height, fullscreen); + fb = new D3DFB (m_Adapter, width, height, fullscreen); } else { From 5a4dad12056defcf9e0a58f47264e418f726ea1e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Jul 2010 01:57:46 +0000 Subject: [PATCH 107/251] - Don't give health for "give all". - "Give artifacts" and "give puzzlepieces" now use the amount value to decide how much of each item to give you. 0 means to give you the max. The old behavior can be obtained by explicitly stating 1. (Since "give all" encompasses these as well, this also applies to that.) - Added "give everything" cheat to give everything. This is like "give all" but ignores the WIF_CHEATNOTWEAPON flag. (Note that this flag has valid uses, but that doesn't stop people from abusing it anyway.) SVN r2418 (trunk) --- src/m_cheat.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 45175c50a..b50c908e8 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -604,7 +604,7 @@ void GiveSpawner (player_t *player, const PClass *type, int amount) void cht_Give (player_t *player, const char *name, int amount) { - bool giveall; + enum { ALL_NO, ALL_YES, ALL_YESYES } giveall; int i; const PClass *type; @@ -616,9 +616,17 @@ void cht_Give (player_t *player, const char *name, int amount) return; } - giveall = (stricmp (name, "all") == 0); + giveall = ALL_NO; + if (stricmp (name, "all") == 0) + { + giveall = ALL_YES; + } + else if (stricmp (name, "everything") == 0) + { + giveall = ALL_YES; + } - if (giveall || stricmp (name, "health") == 0) + if (stricmp (name, "health") == 0) { if (amount > 0) { @@ -643,9 +651,6 @@ void cht_Give (player_t *player, const char *name, int amount) player->health = deh.GodHealth; } } - - if (!giveall) - return; } if (giveall || stricmp (name, "backpack") == 0) @@ -760,7 +765,7 @@ void cht_Give (player_t *player, const char *name, int amount) player->weapons.LocateWeapon(type, NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); - if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) + if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { GiveSpawner (player, type, 1); } @@ -786,7 +791,7 @@ void cht_Give (player_t *player, const char *name, int amount) !type->IsDescendantOf (RUNTIME_CLASS(APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS(AArmor))) { - GiveSpawner (player, type, 1); + GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); } } } @@ -804,7 +809,7 @@ void cht_Give (player_t *player, const char *name, int amount) AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid()) { - GiveSpawner (player, type, 1); + GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); } } } From a4017797155cbfb13441849986ece8675de29d06 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Jul 2010 03:04:43 +0000 Subject: [PATCH 108/251] - Fixed: FMugShotFrame::GetTexture() needs to NULL-check skin_face. (default_face might also be empty. I don't know if that deserves special handling, but it doesn't crash, so I'll let blzut3 worry about it.) SVN r2419 (trunk) --- src/g_shared/sbar_mugshot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index cecae1df3..e48a047bb 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -84,7 +84,7 @@ FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_f { index = Graphic.Size() - 1; } - FString sprite(skin_face[0] != 0 ? skin_face : default_face, 3); + FString sprite(skin_face != NULL && skin_face[0] != 0 ? skin_face : default_face, 3); sprite += Graphic[index]; if (uses_levels) //change the last character to the level { From 305a03d7c8080544051295d529e3bb5cee43f1ad Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Jul 2010 00:51:38 +0000 Subject: [PATCH 109/251] - Fixed copy-pasta error for "give everything". SVN r2420 (trunk) --- src/m_cheat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index b50c908e8..0a7928a91 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -623,7 +623,7 @@ void cht_Give (player_t *player, const char *name, int amount) } else if (stricmp (name, "everything") == 0) { - giveall = ALL_YES; + giveall = ALL_YESYES; } if (stricmp (name, "health") == 0) From 99a2014ead2d065ec90c175937d222d9c7d7fa93 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Jul 2010 02:59:34 +0000 Subject: [PATCH 110/251] - Added support for custom loop points for songs. This does not work with MP3 because of the way MP3 obfuscates custom tags. Vorbis and FLAC are fine. (I could make it work with MP3, but you should be using Vorbis instead.) They are: * LOOP_START: Start time for the loop. If omitted, the song repeats from the beginning. * LOOP_END: End time for the loop. If omitted, the song loops at the end. (If you need to specify this, why aren't you using a shorter song.) You only need to specify one of these tags to set the custom loop. Naturally, you can set them both, as well. The format for each tag is the same: * If it contains a colon (:), it specifies by time. This may be of the form 00:00:00.00 (HH:MM:SS.ss) to specify by play. Various parts may be left off. e.g. To start the loop at 20 seconds in, you can use ":20", 0:20", "00:00:20", ":20.0", etc. Values after the decimal are fractions of a second and accurate to one millisecond. * If you don't include a colon but just have a raw number, then it's the number of PCM samples at which to loop. * Any characters other than digits (0-9), colons (:), or a single decimal point for the seconds portion will result in the tag being ignored. SVN r2424 (trunk) --- src/s_advsound.cpp | 94 +++++++++++++++++++++++++++++++++++++++++ src/s_sound.h | 1 + src/sound/fmodsound.cpp | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 7f9cd8592..e121bc2ee 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1772,6 +1772,100 @@ int S_FindSkinnedSoundEx (AActor *actor, const char *name, const char *extendedn return S_FindSkinnedSound (actor, id); } +//========================================================================== +// +// S_ParseTimeTag +// +// Passed the value of a loop point tag, converts it to numbers. +// +// This may be of the form 00:00:00.00 (HH:MM:SS.ss) to specify by play +// time. Various parts may be left off. The only requirement is that it +// contain a colon. e.g. To start the loop at 20 seconds in, you can use +// ":20", "0:20", "00:00:20", ":20.0", etc. Values after the decimal are +// fractions of a second. +// +// If you don't include a colon but just have a raw number, then it's +// the number of PCM samples at which to loop. +// +// Returns true if the tag made sense, false if not. +// +//========================================================================== + +bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time) +{ + const char *bit = tag; + char ms[3] = { 0 }; + unsigned int times[3] = { 0 }; + int ms_pos = 0, time_pos = 0; + bool pcm = true, in_ms = false; + + for (bit = tag; *bit != '\0'; ++bit) + { + if (*bit >= '0' && *bit <= '9') + { + if (in_ms) + { + // Ignore anything past three fractional digits. + if (ms_pos < 3) + { + ms[ms_pos++] = *bit - '0'; + } + } + else + { + times[time_pos] = times[time_pos] * 10 + *bit - '0'; + } + } + else if (*bit == ':') + { + if (in_ms) + { // If we already specified milliseconds, we can't take any more parts. + return false; + } + pcm = false; + if (++time_pos == countof(times)) + { // Time too long. (Seriously, starting the loop days in?) + return false; + } + } + else if (*bit == '.') + { + if (pcm || in_ms) + { // It doesn't make sense to have fractional PCM values. + // It also doesn't make sense to have more than one dot. + return false; + } + in_ms = true; + } + else + { // Anything else: We don't understand this. + return false; + } + } + if (pcm) + { + *as_samples = true; + *time = times[0]; + } + else + { + unsigned int mytime = 0; + + // Add in hours, minutes, and seconds + for (int i = 0; i <= time_pos; ++i) + { + mytime = mytime * 60 + times[i]; + } + + // Add in milliseconds + mytime = mytime * 1000 + ms[0] * 100 + ms[1] * 10 + ms[2]; + + *as_samples = false; + *time = mytime; + } + return true; +} + //========================================================================== // // CCMD soundlist diff --git a/src/s_sound.h b/src/s_sound.h index 41820bec7..8d89d1a0d 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -354,6 +354,7 @@ void S_UnloadSound (sfxinfo_t *sfx); sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); unsigned int S_GetMSLength(FSoundID sound); void S_ParseMusInfo(); +bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time); // [RH] Prints sound debug info to the screen. // Modelled after Hexen's noise cheat. diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e167d389f..e94ec04b7 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -61,6 +61,7 @@ extern HWND Window; #include "v_video.h" #include "v_palette.h" #include "cmdlib.h" +#include "s_sound.h" // MACROS ------------------------------------------------------------------ @@ -1435,6 +1436,26 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int return capsule; } +//========================================================================== +// +// GetTagData +// +// Checks for a string-type tag, and returns its data. +// +//========================================================================== + +const char *GetTagData(FMOD::Sound *sound, const char *tag_name) +{ + FMOD_TAG tag; + + if (FMOD_OK == sound->getTag(tag_name, 0, &tag) && + (tag.datatype == FMOD_TAGDATATYPE_STRING || tag.datatype == FMOD_TAGDATATYPE_STRING_UTF8)) + { + return (const char *)tag.data; + } + return NULL; +} + //========================================================================== // // FMODSoundRenderer :: OpenStream @@ -1496,6 +1517,61 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla } if (result == FMOD_OK) { + // Handle custom loop starts by checking for a "loop_start" tag. +#if 0 + FMOD_TAG tag; + int numtags; + if (FMOD_OK == stream->getNumTags(&numtags, NULL)) + { + for (int i = 0; i < numtags; ++i) + { + if (FMOD_OK == stream->getTag(NULL, i, &tag)) + { + Printf("Tag %2d. %d %s = %s\n", i, tag.datatype, tag.name, tag.data); + } + } + } +#endif + const char *tag_data; + unsigned int looppt[2]; + bool looppt_as_samples[2], have_looppt[2] = { false }; + static const char *const loop_tags[2] = { "LOOP_START", "LOOP_END" }; + + for (int i = 0; i < 2; ++i) + { + if (NULL != (tag_data = GetTagData(stream, loop_tags[i]))) + { + if (S_ParseTimeTag(tag_data, &looppt_as_samples[i], &looppt[i])) + { + have_looppt[i] = true; + } + else + { + Printf("Invalid %s tag: '%s'\n", loop_tags[i], tag_data); + } + } + } + if (have_looppt[0] && !have_looppt[1]) + { // Have a start tag, but not an end tag: End at the end of the song. + have_looppt[1] = (FMOD_OK == stream->getLength(&looppt[1], FMOD_TIMEUNIT_PCM)); + looppt_as_samples[1] = true; + } + else if (!have_looppt[0] && have_looppt[1]) + { // Have an end tag, but no start tag: Start at beginning of the song. + looppt[0] = 0; + looppt_as_samples[0] = true; + have_looppt[0] = true; + } + if (have_looppt[0] && have_looppt[1]) + { // Have both loop points: Try to set the loop. + FMOD_RESULT res = stream->setLoopPoints( + looppt[0], looppt_as_samples[0] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS, + looppt[1] - 1, looppt_as_samples[1] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS); + if (res != FMOD_OK) + { + Printf("Setting custom song loop points for song failed. Error %d\n", res); + } + } return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL); } return NULL; From c29639426fa67c304d616bcc441ec26903911848 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 15 Jul 2010 23:07:41 +0000 Subject: [PATCH 111/251] - Sounds that define a loop no longer play looped by default. They must be started with CHAN_LOOP so that the higher level sound code knows they loop and can handle them accordingly. - Added support for a LOOP_BIDI tag. Set it to "1", "On", "True", or "Yes" to use a bidirectional loop. This only works with sounds and not music, because music is streamed so does not support them. - Extended custom loop support to work with samples as well as music. SVN r2434 (trunk) --- src/sound/fmodsound.cpp | 163 ++++++++++++++++++++++++++-------------- 1 file changed, 105 insertions(+), 58 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e94ec04b7..a31665803 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1456,6 +1456,88 @@ const char *GetTagData(FMOD::Sound *sound, const char *tag_name) return NULL; } +//========================================================================== +// +// SetCustomLoopPts +// +// Sets up custom sound loops by checking for these tags: +// LOOP_START +// LOOP_END +// LOOP_BIDI +// +//========================================================================== + +static void SetCustomLoopPts(FMOD::Sound *sound) +{ +#if 0 + FMOD_TAG tag; + int numtags; + if (FMOD_OK == stream->getNumTags(&numtags, NULL)) + { + for (int i = 0; i < numtags; ++i) + { + if (FMOD_OK == sound->getTag(NULL, i, &tag)) + { + Printf("Tag %2d. %d %s = %s\n", i, tag.datatype, tag.name, tag.data); + } + } + } +#endif + const char *tag_data; + unsigned int looppt[2]; + bool looppt_as_samples[2], have_looppt[2] = { false }; + static const char *const loop_tags[2] = { "LOOP_START", "LOOP_END" }; + + for (int i = 0; i < 2; ++i) + { + if (NULL != (tag_data = GetTagData(sound, loop_tags[i]))) + { + if (S_ParseTimeTag(tag_data, &looppt_as_samples[i], &looppt[i])) + { + have_looppt[i] = true; + } + else + { + Printf("Invalid %s tag: '%s'\n", loop_tags[i], tag_data); + } + } + } + if (have_looppt[0] && !have_looppt[1]) + { // Have a start tag, but not an end tag: End at the end of the song. + have_looppt[1] = (FMOD_OK == sound->getLength(&looppt[1], FMOD_TIMEUNIT_PCM)); + looppt_as_samples[1] = true; + } + else if (!have_looppt[0] && have_looppt[1]) + { // Have an end tag, but no start tag: Start at beginning of the song. + looppt[0] = 0; + looppt_as_samples[0] = true; + have_looppt[0] = true; + } + if (have_looppt[0] && have_looppt[1]) + { // Have both loop points: Try to set the loop. + FMOD_RESULT res = sound->setLoopPoints( + looppt[0], looppt_as_samples[0] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS, + looppt[1] - 1, looppt_as_samples[1] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS); + if (res != FMOD_OK) + { + Printf("Setting custom loop points failed. Error %d\n", res); + } + } + // Check for a bi-directional loop. + if (NULL != (tag_data = GetTagData(sound, "LOOP_BIDI")) && + (stricmp(tag_data, "on") == 0 || + stricmp(tag_data, "true") == 0 || + stricmp(tag_data, "yes") == 0 || + stricmp(tag_data, "1") == 0)) + { + FMOD_MODE mode; + if (FMOD_OK == (sound->getMode(&mode))) + { + sound->setMode(mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL) | FMOD_LOOP_BIDI); + } + } +} + //========================================================================== // // FMODSoundRenderer :: OpenStream @@ -1517,61 +1599,7 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla } if (result == FMOD_OK) { - // Handle custom loop starts by checking for a "loop_start" tag. -#if 0 - FMOD_TAG tag; - int numtags; - if (FMOD_OK == stream->getNumTags(&numtags, NULL)) - { - for (int i = 0; i < numtags; ++i) - { - if (FMOD_OK == stream->getTag(NULL, i, &tag)) - { - Printf("Tag %2d. %d %s = %s\n", i, tag.datatype, tag.name, tag.data); - } - } - } -#endif - const char *tag_data; - unsigned int looppt[2]; - bool looppt_as_samples[2], have_looppt[2] = { false }; - static const char *const loop_tags[2] = { "LOOP_START", "LOOP_END" }; - - for (int i = 0; i < 2; ++i) - { - if (NULL != (tag_data = GetTagData(stream, loop_tags[i]))) - { - if (S_ParseTimeTag(tag_data, &looppt_as_samples[i], &looppt[i])) - { - have_looppt[i] = true; - } - else - { - Printf("Invalid %s tag: '%s'\n", loop_tags[i], tag_data); - } - } - } - if (have_looppt[0] && !have_looppt[1]) - { // Have a start tag, but not an end tag: End at the end of the song. - have_looppt[1] = (FMOD_OK == stream->getLength(&looppt[1], FMOD_TIMEUNIT_PCM)); - looppt_as_samples[1] = true; - } - else if (!have_looppt[0] && have_looppt[1]) - { // Have an end tag, but no start tag: Start at beginning of the song. - looppt[0] = 0; - looppt_as_samples[0] = true; - have_looppt[0] = true; - } - if (have_looppt[0] && have_looppt[1]) - { // Have both loop points: Try to set the loop. - FMOD_RESULT res = stream->setLoopPoints( - looppt[0], looppt_as_samples[0] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS, - looppt[1] - 1, looppt_as_samples[1] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS); - if (res != FMOD_OK) - { - Printf("Setting custom song loop points for song failed. Error %d\n", res); - } - } + SetCustomLoopPts(stream); return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL); } return NULL; @@ -1613,7 +1641,15 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi mode = (mode & ~FMOD_3D) | FMOD_2D; if (flags & SNDF_LOOP) { - mode = (mode & ~FMOD_LOOP_OFF) | FMOD_LOOP_NORMAL; + mode &= ~FMOD_LOOP_OFF; + if (!(mode & (FMOD_LOOP_NORMAL | FMOD_LOOP_BIDI))) + { + mode |= FMOD_LOOP_NORMAL; + } + } + else + { + mode |= FMOD_LOOP_OFF; } chan->setMode(mode); chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx); @@ -1713,7 +1749,16 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * } if (flags & SNDF_LOOP) { - mode = (mode & ~FMOD_LOOP_OFF) | FMOD_LOOP_NORMAL; + mode &= ~FMOD_LOOP_OFF; + if (!(mode & (FMOD_LOOP_NORMAL | FMOD_LOOP_BIDI))) + { + mode |= FMOD_LOOP_NORMAL; + } + } + else + { + // FMOD_LOOP_OFF overrides FMOD_LOOP_NORMAL and FMOD_LOOP_BIDI + mode |= FMOD_LOOP_OFF; } mode = SetChanHeadSettings(listener, chan, pos, !!(flags & SNDF_AREA), mode); chan->setMode(mode); @@ -1810,13 +1855,14 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel * // Clamp the position of looping sounds to be within the sound. // If we try to start it several minutes past its normal end, // FMOD doesn't like that. + // FIXME: Clamp this right for loops that don't cover the whole sound. if (flags & SNDF_LOOP) { FMOD::Sound *sound; if (FMOD_OK == chan->getCurrentSound(&sound)) { unsigned int len; - if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len) + if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len != 0) { difftime %= len; } @@ -2358,6 +2404,7 @@ SoundHandle FMODSoundRenderer::LoadSound(BYTE *sfxdata, int length) DPrintf("Failed to allocate sample: Error %d\n", result); return retval; } + SetCustomLoopPts(sample); retval.data = sample; return retval; } From 5b63fd067573f16808c810c1bcd5fc98dc3a02e4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 16 Jul 2010 03:46:20 +0000 Subject: [PATCH 112/251] - Added an optional parameter to DamageScreenColor to scale the amount of damage for pain flash calculations. This can range from 0.0 to 1.0. SVN r2435 (trunk) --- src/g_shared/shared_sbar.cpp | 17 ++++++++++------- src/p_user.cpp | 4 ++++ src/thingdef/thingdef_properties.cpp | 11 ++++++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 8c0473832..ef48d211a 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1507,15 +1507,18 @@ void DBaseStatusBar::BlendView (float blend[4]) AddBlend (0.8431f, 0.7333f, 0.2706f, cnt > 128 ? 0.5f : cnt / 255.f, blend); } - cnt = DamageToAlpha[MIN (113, CPlayer->damagecount)]; - - if (cnt) + if (CPlayer->mo->DamageFade.a != 0) { - if (cnt > 228) - cnt = 228; + cnt = DamageToAlpha[MIN (113, CPlayer->damagecount * CPlayer->mo->DamageFade.a / 255)]; + + if (cnt) + { + if (cnt > 228) + cnt = 228; - APlayerPawn *mo = players[consoleplayer].mo; - AddBlend (mo->DamageFade.r / 255.f, mo->DamageFade.g / 255.f, mo->DamageFade.b / 255.f, cnt / 255.f, blend); + APlayerPawn *mo = CPlayer->mo; + AddBlend (mo->DamageFade.r / 255.f, mo->DamageFade.g / 255.f, mo->DamageFade.b / 255.f, cnt / 255.f, blend); + } } // Unlike Doom, I did not have any utility source to look at to find the diff --git a/src/p_user.cpp b/src/p_user.cpp index a350babab..65909b3d3 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -426,6 +426,10 @@ void APlayerPawn::Serialize (FArchive &arc) << MorphWeapon << DamageFade << PlayerFlags; + if (SaveVersion < 2435) + { + DamageFade.a = 255; + } } //=========================================================================== diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index f58eb6500..db620c5c7 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2094,10 +2094,19 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, crouchsprite, S, PlayerPawn) //========================================================================== // //========================================================================== -DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, C, PlayerPawn) +DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cf, PlayerPawn) { PROP_COLOR_PARM(c, 0); defaults->DamageFade = c; + if (PROP_PARM_COUNT < 3) // Because colors count as 2 parms + { + defaults->DamageFade.a = 255; + } + else + { + PROP_FLOAT_PARM(a, 2); + defaults->DamageFade.a = BYTE(255 * clamp(a, 0.f, 1.f)); + } } //========================================================================== From 1cf12693ba01997111d2b5f7c726f1539b20cc5e Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 18 Jul 2010 08:00:12 +0000 Subject: [PATCH 113/251] - Added Cocoa IWAD picker for Mac OS X. SVN r2440 (trunk) --- src/CMakeLists.txt | 2 +- src/sdl/i_system.cpp | 4 + src/sdl/iwadpicker_cocoa.mm | 212 ++++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/sdl/iwadpicker_cocoa.mm diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31b3e1414..ea4f153a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -473,7 +473,7 @@ else( WIN32 ) sdl/sdlvideo.cpp sdl/st_start.cpp ) if( APPLE ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m ) + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm ) endif( APPLE ) endif( WIN32 ) diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 4ed1131cb..c05ed2027 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -78,6 +78,8 @@ extern "C" #ifndef NO_GTK extern bool GtkAvailable; +#elif defined(__APPLE__) +int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad); #endif DWORD LanguageIDs[4] = @@ -611,6 +613,8 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad); } +#elif defined(__APPLE__) + return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad); #endif printf ("Please select a game wad (or 0 to exit):\n"); diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm new file mode 100644 index 000000000..48ce26fe1 --- /dev/null +++ b/src/sdl/iwadpicker_cocoa.mm @@ -0,0 +1,212 @@ +/* + ** iwadpicker_cocoa.mm + ** + ** Implements Mac OS X native IWAD Picker. + ** + **--------------------------------------------------------------------------- + ** Copyright 2010 Braden Obrzut + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "d_main.h" +#include "version.h" +#include + +enum +{ + COLUMN_IWAD, + COLUMN_GAME, + + NUM_COLUMNS +}; + +static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; + +// Class to convert the IWAD data into a form that Cocoa can use. +@interface IWADTableData : NSObject +{ + NSMutableArray *data; +} + +- (IWADTableData *)init:(WadStuff *) wads:(int) numwads; + +- (int)numberOfRowsInTableView:(NSTableView *)aTableView; +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +@end + +@implementation IWADTableData + +- (IWADTableData *)init:(WadStuff *) wads:(int) numwads +{ + data = [[NSMutableArray alloc] initWithCapacity:numwads]; + + for(int i = 0;i < numwads;i++) + { + NSMutableDictionary *record = [[NSMutableDictionary alloc] initWithCapacity:NUM_COLUMNS]; + const char* filename = strrchr(wads[i].Path, '/'); + if(filename == NULL) + filename = wads[i].Path; + else + filename++; + [record setObject:[NSString stringWithCString:filename] forKey:[NSString stringWithCString:tableHeaders[COLUMN_IWAD]]]; + [record setObject:[NSString stringWithCString:IWADInfos[wads[i].Type].Name] forKey:[NSString stringWithCString:tableHeaders[COLUMN_GAME]]]; + [data addObject:record]; + } + + return self; +} + +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [data count]; +} + +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +{ + NSParameterAssert(rowIndex >= 0 && (unsigned int) rowIndex < [data count]); + NSMutableDictionary *record = [data objectAtIndex:rowIndex]; + return [record objectForKey:[aTableColumn identifier]]; +} + +@end + +// So we can listen for button actions and such we need to have an Obj-C class. +@interface IWADPicker : NSResponder +{ + NSApplication *app; + NSWindow *window; + NSButton *okButton; + NSButton *cancelButton; + bool cancelled; +} + +- (void)buttonPressed:(id) sender; +- (void)makeLabel:(NSTextField *)label:(const char*) str; +- (int)pickIWad:(WadStuff *)wads:(int) numwads:(bool) showwin:(int) defaultiwad; +@end + +@implementation IWADPicker + +- (void)buttonPressed:(id) sender; +{ + if(sender == cancelButton) + cancelled = true; + + [window orderOut:self]; + [app stopModal]; +} + +// Apparently labels in Cocoa are uneditable text fields, so lets make this a +// little more automated. +- (void)makeLabel:(NSTextField *)label:(const char*) str +{ + [label setStringValue:[NSString stringWithCString:str]]; + [label setBezeled:NO]; + [label setDrawsBackground:NO]; + [label setEditable:NO]; + [label setSelectable:NO]; +} + +- (int)pickIWad:(WadStuff *)wads:(int) numwads:(bool) showwin:(int) defaultiwad +{ + cancelled = false; + + app = [NSApplication sharedApplication]; + id windowTitle = [NSString stringWithCString:GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"]; + + NSRect frame = NSMakeRect(0, 0, 400, 450); + window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; + [window setTitle:windowTitle]; + + NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(22, 379, 372, 50)]; + [self makeLabel:description:"ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"]; + [[window contentView] addSubview:description]; + + // Commented out version would account for an additional parameters box. + //NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 103, 362, 288)]; + NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 50, 362, 341)]; + NSTableView *iwadTable = [[NSTableView alloc] initWithFrame:[iwadScroller bounds]]; + IWADTableData *tableData = [[IWADTableData alloc] init:wads:numwads]; + for(int i = 0;i < NUM_COLUMNS;i++) + { + NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[NSString stringWithCString:tableHeaders[i]]]; + [[column headerCell] setStringValue:[column identifier]]; + if(i == 0) + [column setMaxWidth:110]; + [column setEditable:NO]; + [column setResizingMask:NSTableColumnAutoresizingMask]; + [iwadTable addTableColumn:column]; + } + [iwadScroller setDocumentView:iwadTable]; + [iwadScroller setHasVerticalScroller:YES]; + [iwadTable setDataSource:tableData]; + [iwadTable sizeToFit]; + [iwadTable selectRowIndexes:[[NSIndexSet alloc] initWithIndex:defaultiwad] byExtendingSelection:NO]; + [iwadTable scrollRowToVisible:defaultiwad]; + [[window contentView] addSubview:iwadScroller]; + + /*NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(17, 78, 144, 17)]; + [self makeLabel:additionalParametersLabel:"Additional Parameters"]; + [[window contentView] addSubview:additionalParametersLabel]; + NSTextField *additionalParameters = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 48, 360, 22)]; + [[window contentView] addSubview:additionalParameters];*/ + + // Doesn't look like the SDL version implements this so lets not show it. + /*NSButton *dontAsk = [[NSButton alloc] initWithFrame:NSMakeRect(18, 18, 178, 18)]; + [dontAsk setTitle:[NSString stringWithCString:"Don't ask me this again"]]; + [dontAsk setButtonType:NSSwitchButton]; + [dontAsk setState:(showwin ? NSOffState : NSOnState)]; + [[window contentView] addSubview:dontAsk];*/ + + okButton = [[NSButton alloc] initWithFrame:NSMakeRect(196, 12, 96, 32)]; + [okButton setTitle:[NSString stringWithCString:"OK"]]; + [okButton setBezelStyle:NSRoundedBezelStyle]; + [okButton setAction:@selector(buttonPressed:)]; + [okButton setTarget:self]; + [[window contentView] addSubview:okButton]; + + cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(292, 12, 96, 32)]; + [cancelButton setTitle:[NSString stringWithCString:"Cancel"]]; + [cancelButton setBezelStyle:NSRoundedBezelStyle]; + [cancelButton setAction:@selector(buttonPressed:)]; + [cancelButton setTarget:self]; + [[window contentView] addSubview:cancelButton]; + + [window center]; + [app runModalForWindow:window]; + + return cancelled ? -1 : [iwadTable selectedRow]; +} + +@end + +// Simple wrapper so we can call this from outside. +int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) +{ + return [[IWADPicker alloc] pickIWad:wads:numwads:showwin:defaultiwad]; +} From 921c950bada47ce5697958cc6c315ff96268784d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 18 Jul 2010 09:23:33 +0000 Subject: [PATCH 114/251] - Release Objective-C objects (since I found out the garbage collector is opt-in). SVN r2441 (trunk) --- src/sdl/iwadpicker_cocoa.mm | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm index 48ce26fe1..2768c0e41 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/sdl/iwadpicker_cocoa.mm @@ -53,6 +53,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; NSMutableArray *data; } +- (void)dealloc; - (IWADTableData *)init:(WadStuff *) wads:(int) numwads; - (int)numberOfRowsInTableView:(NSTableView *)aTableView; @@ -61,6 +62,13 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; @implementation IWADTableData +- (void)dealloc +{ + [data release]; + + [super dealloc]; +} + - (IWADTableData *)init:(WadStuff *) wads:(int) numwads { data = [[NSMutableArray alloc] initWithCapacity:numwads]; @@ -76,6 +84,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [record setObject:[NSString stringWithCString:filename] forKey:[NSString stringWithCString:tableHeaders[COLUMN_IWAD]]]; [record setObject:[NSString stringWithCString:IWADInfos[wads[i].Type].Name] forKey:[NSString stringWithCString:tableHeaders[COLUMN_GAME]]]; [data addObject:record]; + [record release]; } return self; @@ -96,7 +105,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; @end // So we can listen for button actions and such we need to have an Obj-C class. -@interface IWADPicker : NSResponder +@interface IWADPicker : NSObject { NSApplication *app; NSWindow *window; @@ -146,6 +155,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(22, 379, 372, 50)]; [self makeLabel:description:"ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"]; [[window contentView] addSubview:description]; + [description release]; // Commented out version would account for an additional parameters box. //NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 103, 362, 288)]; @@ -161,14 +171,19 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [column setEditable:NO]; [column setResizingMask:NSTableColumnAutoresizingMask]; [iwadTable addTableColumn:column]; + [column release]; } [iwadScroller setDocumentView:iwadTable]; [iwadScroller setHasVerticalScroller:YES]; [iwadTable setDataSource:tableData]; [iwadTable sizeToFit]; - [iwadTable selectRowIndexes:[[NSIndexSet alloc] initWithIndex:defaultiwad] byExtendingSelection:NO]; + NSIndexSet *selection = [[NSIndexSet alloc] initWithIndex:defaultiwad]; + [iwadTable selectRowIndexes:selection byExtendingSelection:NO]; + [selection release]; [iwadTable scrollRowToVisible:defaultiwad]; [[window contentView] addSubview:iwadScroller]; + [iwadTable release]; + [iwadScroller release]; /*NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(17, 78, 144, 17)]; [self makeLabel:additionalParametersLabel:"Additional Parameters"]; @@ -200,6 +215,10 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [window center]; [app runModalForWindow:window]; + [window release]; + [okButton release]; + [cancelButton release]; + return cancelled ? -1 : [iwadTable selectedRow]; } @@ -208,5 +227,8 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; // Simple wrapper so we can call this from outside. int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { - return [[IWADPicker alloc] pickIWad:wads:numwads:showwin:defaultiwad]; + IWADPicker *picker = [IWADPicker alloc]; + int ret = [picker pickIWad:wads:numwads:showwin:defaultiwad]; + [picker release]; + return ret; } From 3a48da2c56effcbcc3a31a0b6288fed3f3bfa938 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 19 Jul 2010 03:39:32 +0000 Subject: [PATCH 115/251] - Fixed: The x64 project configuration had not been kept synced with the Win32 configuration and did not exclude sbarinfo_commands.cpp from the build. SVN r2442 (trunk) --- zdoom.vcproj | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/zdoom.vcproj b/zdoom.vcproj index 0f82621ab..684eba0b3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2283,6 +2283,14 @@ Name="VCCLCompilerTool" /> + + + + + + Date: Fri, 23 Jul 2010 05:56:25 +0000 Subject: [PATCH 116/251] - merged polyobject branch into trunk and made some adjustments for savegame compatibility. SVN r2448 (trunk) --- src/am_map.cpp | 65 ++ src/dobjgc.cpp | 1 + src/m_bbox.cpp | 5 - src/m_bbox.h | 1 + src/nodebuild.cpp | 2 +- src/nodebuild_extract.cpp | 1 - src/p_local.h | 6 +- src/p_maputl.cpp | 5 +- src/p_saveg.cpp | 14 +- src/p_setup.cpp | 2 + src/p_sight.cpp | 7 +- src/po_man.cpp | 1840 +++++++++++++++++++++---------------- src/po_man.h | 116 +++ src/r_bsp.cpp | 52 +- src/r_defs.h | 63 +- src/r_interpolate.cpp | 51 +- src/r_main.cpp | 3 + src/r_polymost.cpp | 2 + src/s_sndseq.cpp | 1 + src/s_sound.cpp | 7 +- src/tarray.h | 6 + zdoom.vcproj | 750 +++++++-------- 22 files changed, 1757 insertions(+), 1243 deletions(-) create mode 100644 src/po_man.h diff --git a/src/am_map.cpp b/src/am_map.cpp index 36d31a00e..291a069d8 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -58,6 +58,7 @@ #include "am_map.h" #include "a_artifacts.h" +#include "po_man.h" struct AMColor { @@ -177,6 +178,10 @@ CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); + +CVAR(Int, am_showsubsector, -1, 0); + + // Disable the ML_DONTDRAW line flag if x% of all lines in a map are flagged with it // (To counter annoying mappers who think they are smart by making the automap unusable) bool am_showallenabled; @@ -1614,6 +1619,64 @@ static bool AM_CheckSecret(line_t *line) } +//============================================================================= +// +// Polyobject debug stuff +// +//============================================================================= + +void AM_drawSeg(seg_t *seg, const AMColor &color) +{ + mline_t l; + l.a.x = seg->v1->x >> FRACTOMAPBITS; + l.a.y = seg->v1->y >> FRACTOMAPBITS; + l.b.x = seg->v2->x >> FRACTOMAPBITS; + l.b.y = seg->v2->y >> FRACTOMAPBITS; + + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + AM_rotatePoint (&l.a.x, &l.a.y); + AM_rotatePoint (&l.b.x, &l.b.y); + } + AM_drawMline(&l, color); +} + +void AM_showSS() +{ + if (am_showsubsector >= 0 && am_showsubsector < numsubsectors) + { + AMColor yellow; + yellow.FromRGB(255,255,0); + AMColor red; + red.FromRGB(255,0,0); + + subsector_t *sub = &subsectors[am_showsubsector]; + for(unsigned int i=0;inumlines;i++) + { + AM_drawSeg(&segs[sub->firstline+i], yellow); + } + PO_LinkToSubsectors(); + + for(int i=0;isubsectorlinks; + + while (pnode != NULL) + { + if (pnode->subsector == sub) + { + for(unsigned j=0;jsegs.Size();j++) + { + AM_drawSeg(&pnode->segs[j], red); + } + } + pnode = pnode->snext; + } + } + } +} + //============================================================================= // // Determines visible lines, draws them. @@ -2166,6 +2229,8 @@ void AM_Drawer () AM_drawCrosshair(XHairColor); AM_drawMarks(); + + AM_showSS(); } //============================================================================= diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 1c8e618bd..4d7589e9b 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -71,6 +71,7 @@ #include "r_interpolate.h" #include "doomstat.h" #include "m_argv.h" +#include "po_man.h" // MACROS ------------------------------------------------------------------ diff --git a/src/m_bbox.cpp b/src/m_bbox.cpp index d13f790e6..6d3a5b744 100644 --- a/src/m_bbox.cpp +++ b/src/m_bbox.cpp @@ -91,8 +91,3 @@ int FBoundingBox::BoxOnLineSide (const line_t *ld) const return (p1 == p2) ? p1 : -1; } - - - - - diff --git a/src/m_bbox.h b/src/m_bbox.h index 7c7221688..febf9d2a2 100644 --- a/src/m_bbox.h +++ b/src/m_bbox.h @@ -25,6 +25,7 @@ #include "doomtype.h" struct line_t; +struct node_t; class FBoundingBox { diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 63a736e6a..345c42de8 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -173,11 +173,11 @@ void FNodeBuilder::CreateSubsectorsForReal () subsector_t sub; unsigned int i; - sub.poly = NULL; sub.validcount = 0; sub.CenterX = 0; // Code in p_setup.cpp will set these for us later. sub.CenterY = 0; sub.sector = NULL; + sub.polys = NULL; for (i = 0; i < SubsectorSets.Size(); ++i) { diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index f363cc4ec..77fa4dec7 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -106,7 +106,6 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, DWORD numsegs = CloseSubsector (segs, i, outVerts); outSubs[i].numlines = numsegs; outSubs[i].firstline = segs.Size() - numsegs; - outSubs[i].poly = NULL; } segCount = segs.Size (); diff --git a/src/p_local.h b/src/p_local.h index 2092f8f4f..387089f68 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -237,6 +237,7 @@ struct FLineOpening void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx=FIXED_MIN, fixed_t refy=0); class FBoundingBox; +struct polyblock_t; class FBlockLinesIterator { @@ -536,12 +537,9 @@ extern int po_NumPolyobjs; extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn -bool PO_MovePolyobj (int num, int x, int y, bool force=false); -bool PO_RotatePolyobj (int num, angle_t angle); void PO_Init (); bool PO_Busy (int polyobj); -void PO_ClosestPoint(const FPolyObj *poly, fixed_t ox, fixed_t oy, fixed_t &x, fixed_t &y, seg_t **seg); -struct FPolyObj *PO_GetPolyobj(int polyNum); +FPolyObj *PO_GetPolyobj(int polyNum); // // P_SPEC diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index f7874c345..91370c070 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -39,6 +39,7 @@ // State. #include "r_state.h" #include "templates.h" +#include "po_man.h" static AActor *RoughBlockCheck (AActor *mo, int index, void *); @@ -692,9 +693,9 @@ line_t *FBlockLinesIterator::Next() polyLink->polyobj->validcount = validcount; } - line_t *ld = polyLink->polyobj->lines[polyIndex]; + line_t *ld = polyLink->polyobj->Linedefs[polyIndex]; - if (++polyIndex >= polyLink->polyobj->numlines) + if (++polyIndex >= (int)polyLink->polyobj->Linedefs.Size()) { polyLink = polyLink->next; polyIndex = 0; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 5e9a18f9c..783517764 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -46,12 +46,14 @@ #include "a_sharedglobal.h" #include "r_interpolate.h" #include "g_level.h" +#include "po_man.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNow, bool skipload); static void SpawnExtraPlayers (); + // // P_ArchivePlayers // @@ -496,8 +498,8 @@ void P_SerializePolyobjs (FArchive &arc) arc << seg << po_NumPolyobjs; for(i = 0, po = polyobjs; i < po_NumPolyobjs; i++, po++) { - arc << po->tag << po->angle << po->startSpot[0] << - po->startSpot[1] << po->interpolation; + arc << po->tag << po->angle << po->StartSpot.x << + po->StartSpot.y << po->interpolation; } } else @@ -523,11 +525,11 @@ void P_SerializePolyobjs (FArchive &arc) I_Error ("UnarchivePolyobjs: Invalid polyobj tag"); } arc << angle; - PO_RotatePolyobj (po->tag, angle); + po->RotatePolyobj (angle); arc << deltaX << deltaY << po->interpolation; - deltaX -= po->startSpot[0]; - deltaY -= po->startSpot[1]; - PO_MovePolyobj (po->tag, deltaX, deltaY, true); + deltaX -= po->StartSpot.x; + deltaY -= po->StartSpot.y; + po->MovePolyobj (deltaX, deltaY, true); } } } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b19b64240..4b411fb26 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -65,6 +65,7 @@ #include "g_level.h" #include "md5.h" #include "compatibility.h" +#include "po_man.h" void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt); void P_SetSlopes (); @@ -3341,6 +3342,7 @@ extern polyblock_t **PolyBlockMap; void P_FreeLevelData () { + FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. SN_StopAllSequences (); DThinker::DestroyAllThinkers (); level.total_monsters = level.total_items = level.total_secrets = diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 55ab3f13a..4324ebc0a 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -18,6 +18,7 @@ #include "m_bbox.h" #include "p_lnspec.h" #include "g_level.h" +#include "po_man.h" // State. #include "r_state.h" @@ -305,7 +306,7 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) int *list; polyblock_t *polyLink; - int i; + unsigned int i; extern polyblock_t **PolyBlockMap; offset = y*bmapwidth+x; @@ -318,9 +319,9 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) if (polyLink->polyobj->validcount != validcount) { polyLink->polyobj->validcount = validcount; - for (i = 0; i < polyLink->polyobj->numlines; i++) + for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++) { - if (!P_SightCheckLine (polyLink->polyobj->lines[i])) + if (!P_SightCheckLine (polyLink->polyobj->Linedefs[i])) return false; } } diff --git a/src/po_man.cpp b/src/po_man.cpp index 12e3f57ca..f457629fc 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -26,6 +26,7 @@ #include "p_lnspec.h" #include "r_interpolate.h" #include "g_level.h" +#include "po_man.h" // MACROS ------------------------------------------------------------------ @@ -33,6 +34,17 @@ // TYPES ------------------------------------------------------------------- +inline vertex_t *side_t::V1() const +{ + return this == linedef->sidedef[0]? linedef->v1 : linedef->v2; +} + +inline vertex_t *side_t::V2() const +{ + return this == linedef->sidedef[0]? linedef->v2 : linedef->v1; +} + + inline FArchive &operator<< (FArchive &arc, podoortype_t &type) { BYTE val = (BYTE)type; @@ -49,6 +61,7 @@ public: DPolyAction (int polyNum); void Serialize (FArchive &arc); void Destroy(); + int GetSpeed() const { return m_Speed; } void StopInterpolation (); protected: @@ -59,8 +72,6 @@ protected: TObjPtr m_Interpolation; void SetInterpolation (); - - friend void ThrustMobj (AActor *actor, seg_t *seg, FPolyObj *po); }; class DRotatePoly : public DPolyAction @@ -115,20 +126,17 @@ private: // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -bool PO_RotatePolyobj (int num, angle_t angle); void PO_Init (void); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static int GetPolyobjMirror (int poly); -static void UpdateSegBBox (seg_t *seg); static void RotatePt (int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY); static void UnLinkPolyobj (FPolyObj *po); static void LinkPolyobj (FPolyObj *po); -static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po); +static bool CheckMobjBlocking (side_t *seg, FPolyObj *po); static void InitBlockMap (void); -static void IterFindPolySegs (vertex_t *v1, vertex_t *v2, seg_t **segList); +static void IterFindPolySides (vertex_t *v1, vertex_t *v2, seg_t **segList); static void SpawnPolyobj (int index, int tag, int type); static void TranslateToStartSpot (int tag, int originX, int originY); static void DoMovePolyobj (FPolyObj *po, int x, int y); @@ -148,21 +156,23 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static int PolySegCount; - -static SDWORD *SegListHead; // contains numvertexes elements -static TArray KnownPolySegs; +static SDWORD *SideListHead; // contains numvertexes elements +static TArray KnownPolySides; // CODE -------------------------------------------------------------------- + + +//========================================================================== +// +// +// +//========================================================================== + IMPLEMENT_POINTY_CLASS (DPolyAction) DECLARE_POINTER(m_Interpolation) END_POINTERS -IMPLEMENT_CLASS (DRotatePoly) -IMPLEMENT_CLASS (DMovePoly) -IMPLEMENT_CLASS (DPolyDoor) - DPolyAction::DPolyAction () { } @@ -209,6 +219,14 @@ void DPolyAction::StopInterpolation () } } +//========================================================================== +// +// +// +//========================================================================== + +IMPLEMENT_CLASS (DRotatePoly) + DRotatePoly::DRotatePoly () { } @@ -218,6 +236,14 @@ DRotatePoly::DRotatePoly (int polyNum) { } +//========================================================================== +// +// +// +//========================================================================== + +IMPLEMENT_CLASS (DMovePoly) + DMovePoly::DMovePoly () { } @@ -236,6 +262,14 @@ DMovePoly::DMovePoly (int polyNum) m_ySpeed = 0; } +//========================================================================== +// +// +// +//========================================================================== + +IMPLEMENT_CLASS (DPolyDoor) + DPolyDoor::DPolyDoor () { } @@ -266,7 +300,10 @@ DPolyDoor::DPolyDoor (int polyNum, podoortype_t type) void DRotatePoly::Tick () { - if (PO_RotatePolyobj (m_PolyObj, m_Speed)) + FPolyObj *poly = PO_GetPolyobj (m_PolyObj); + if (poly == NULL) return; + + if (poly->RotatePolyobj (m_Speed)) { unsigned int absSpeed = abs (m_Speed); @@ -277,7 +314,6 @@ void DRotatePoly::Tick () m_Dist -= absSpeed; if (m_Dist == 0) { - FPolyObj *poly = PO_GetPolyobj (m_PolyObj); if (poly->specialdata == this) { poly->specialdata = NULL; @@ -315,7 +351,8 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, } else { - I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); + Printf("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); + return false; } pe = new DRotatePoly (polyNum); if (byteAngle) @@ -337,12 +374,13 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, poly->specialdata = pe; SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); - while ( (mirror = GetPolyobjMirror(polyNum)) ) + while ( (mirror = poly->GetMirror()) ) { poly = PO_GetPolyobj(mirror); if (poly == NULL) { - I_Error ("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); + Printf ("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); + break; } if (poly && poly->specialdata && !overRide) { // mirroring poly is already in motion @@ -381,27 +419,29 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, void DMovePoly::Tick () { - FPolyObj *poly; + FPolyObj *poly = PO_GetPolyobj (m_PolyObj); - if (PO_MovePolyobj (m_PolyObj, m_xSpeed, m_ySpeed)) + if (poly != NULL) { - int absSpeed = abs (m_Speed); - m_Dist -= absSpeed; - if (m_Dist <= 0) + if (poly->MovePolyobj (m_xSpeed, m_ySpeed)) { - poly = PO_GetPolyobj (m_PolyObj); - if (poly->specialdata == this) + int absSpeed = abs (m_Speed); + m_Dist -= absSpeed; + if (m_Dist <= 0) { - poly->specialdata = NULL; + if (poly->specialdata == this) + { + poly->specialdata = NULL; + } + SN_StopSequence (poly); + Destroy (); + } + else if (m_Dist < absSpeed) + { + m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); + m_xSpeed = FixedMul (m_Speed, finecosine[m_Angle]); + m_ySpeed = FixedMul (m_Speed, finesine[m_Angle]); } - SN_StopSequence (poly); - Destroy (); - } - else if (m_Dist < absSpeed) - { - m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); - m_xSpeed = FixedMul (m_Speed, finecosine[m_Angle]); - m_ySpeed = FixedMul (m_Speed, finesine[m_Angle]); } } } @@ -429,7 +469,8 @@ bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, } else { - I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); + Printf("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); + return false; } pe = new DMovePoly (polyNum); pe->m_Dist = dist; // Distance @@ -452,7 +493,7 @@ bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, pe->StopInterpolation (); } - while ( (mirror = GetPolyobjMirror(polyNum)) ) + while ( (mirror = poly->GetMirror()) ) { poly = PO_GetPolyobj(mirror); if (poly && poly->specialdata && !overRide) @@ -486,13 +527,14 @@ bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, void DPolyDoor::Tick () { int absSpeed; - FPolyObj *poly; + FPolyObj *poly = PO_GetPolyobj (m_PolyObj); + + if (poly == NULL) return; if (m_Tics) { if (!--m_Tics) { - poly = PO_GetPolyobj (m_PolyObj); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, m_Close); } return; @@ -500,21 +542,19 @@ void DPolyDoor::Tick () switch (m_Type) { case PODOOR_SLIDE: - if (m_Dist <= 0 || PO_MovePolyobj (m_PolyObj, m_xSpeed, m_ySpeed)) + if (m_Dist <= 0 || poly->MovePolyobj (m_xSpeed, m_ySpeed)) { absSpeed = abs (m_Speed); m_Dist -= absSpeed; if (m_Dist <= 0) { - poly = PO_GetPolyobj (m_PolyObj); SN_StopSequence (poly); if (!m_Close) { m_Dist = m_TotalDist; m_Close = true; m_Tics = m_WaitTics; - m_Direction = (ANGLE_MAX>>ANGLETOFINESHIFT)- - m_Direction; + m_Direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - m_Direction; m_xSpeed = -m_xSpeed; m_ySpeed = -m_ySpeed; } @@ -530,7 +570,6 @@ void DPolyDoor::Tick () } else { - poly = PO_GetPolyobj (m_PolyObj); if (poly->crush || !m_Close) { // continue moving if the poly is a crusher, or is opening return; @@ -549,7 +588,7 @@ void DPolyDoor::Tick () break; case PODOOR_SWING: - if (PO_RotatePolyobj (m_PolyObj, m_Speed)) + if (poly->RotatePolyobj (m_Speed)) { absSpeed = abs (m_Speed); if (m_Dist == -1) @@ -559,7 +598,6 @@ void DPolyDoor::Tick () m_Dist -= absSpeed; if (m_Dist <= 0) { - poly = PO_GetPolyobj (m_PolyObj); SN_StopSequence (poly); if (!m_Close) { @@ -580,7 +618,6 @@ void DPolyDoor::Tick () } else { - poly = PO_GetPolyobj (m_PolyObj); if(poly->crush || !m_Close) { // continue moving if the poly is a crusher, or is opening return; @@ -622,7 +659,8 @@ bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, } else { - I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); + Printf("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); + return false; } pd = new DPolyDoor (polyNum, type); if (type == PODOOR_SLIDE) @@ -646,7 +684,7 @@ bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, poly->specialdata = pd; - while ( (mirror = GetPolyobjMirror (polyNum)) ) + while ( (mirror = poly->GetMirror()) ) { poly = PO_GetPolyobj (mirror); if (poly && poly->specialdata) @@ -700,24 +738,39 @@ FPolyObj *PO_GetPolyobj (int polyNum) return NULL; } + +//========================================================================== +// +// +// +//========================================================================== + +FPolyObj::FPolyObj() +{ + StartSpot.x = StartSpot.y = 0; + angle = 0; + tag = 0; + memset(bbox, 0, sizeof(bbox)); + validcount = 0; + crush = 0; + bHurtOnTouch = false; + seqType = 0; + size = 0; + subsectorlinks = NULL; + specialdata = NULL; + interpolation = NULL; + SVIndex = -1; +} + //========================================================================== // // GetPolyobjMirror // //========================================================================== -static int GetPolyobjMirror(int poly) +int FPolyObj::GetMirror() { - int i; - - for (i = 0; i < po_NumPolyobjs; i++) - { - if (polyobjs[i].tag == poly) - { - return polyobjs[i].lines[0]->args[1]; - } - } - return 0; + return Linedefs[0]->args[1]; } //========================================================================== @@ -726,7 +779,7 @@ static int GetPolyobjMirror(int poly) // //========================================================================== -void ThrustMobj (AActor *actor, seg_t *seg, FPolyObj *po) +void FPolyObj::ThrustMobj (AActor *actor, side_t *side) { int thrustAngle; int thrustX; @@ -739,20 +792,20 @@ void ThrustMobj (AActor *actor, seg_t *seg, FPolyObj *po) { return; } - thrustAngle = - (R_PointToAngle2 (seg->v1->x, seg->v1->y, seg->v2->x, seg->v2->y) - - ANGLE_90) >> ANGLETOFINESHIFT; + vertex_t *v1 = side->V1(); + vertex_t *v2 = side->V2(); + thrustAngle = (R_PointToAngle2 (v1->x, v1->y, v2->x, v2->y) - ANGLE_90) >> ANGLETOFINESHIFT; - pe = static_cast(po->specialdata); + pe = static_cast(specialdata); if (pe) { if (pe->IsKindOf (RUNTIME_CLASS (DRotatePoly))) { - force = pe->m_Speed >> 8; + force = pe->GetSpeed() >> 8; } else { - force = pe->m_Speed >> 3; + force = pe->GetSpeed() >> 3; } if (force < FRACUNIT) { @@ -772,12 +825,12 @@ void ThrustMobj (AActor *actor, seg_t *seg, FPolyObj *po) thrustY = FixedMul (force, finesine[thrustAngle]); actor->velx += thrustX; actor->vely += thrustY; - if (po->crush) + if (crush) { - if (po->bHurtOnTouch || !P_CheckMove (actor, actor->x + thrustX, actor->y + thrustY)) + if (bHurtOnTouch || !P_CheckMove (actor, actor->x + thrustX, actor->y + thrustY)) { - P_DamageMobj (actor, NULL, NULL, po->crush, NAME_Crush); - P_TraceBleed (po->crush, actor); + P_DamageMobj (actor, NULL, NULL, crush, NAME_Crush); + P_TraceBleed (crush, actor); } } if (level.flags2 & LEVEL2_POLYGRIND) actor->Grind(false); // crush corpses that get caught in a polyobject's way @@ -789,48 +842,62 @@ void ThrustMobj (AActor *actor, seg_t *seg, FPolyObj *po) // //========================================================================== -static void UpdateSegBBox (seg_t *seg) +void FPolyObj::UpdateBBox () { - line_t *line; + for(unsigned i=0;ilinedef; + if (line->v1->x < line->v2->x) + { + line->bbox[BOXLEFT] = line->v1->x; + line->bbox[BOXRIGHT] = line->v2->x; + } + else + { + line->bbox[BOXLEFT] = line->v2->x; + line->bbox[BOXRIGHT] = line->v1->x; + } + if (line->v1->y < line->v2->y) + { + line->bbox[BOXBOTTOM] = line->v1->y; + line->bbox[BOXTOP] = line->v2->y; + } + else + { + line->bbox[BOXBOTTOM] = line->v2->y; + line->bbox[BOXTOP] = line->v1->y; + } - if (line->v1->x < line->v2->x) - { - line->bbox[BOXLEFT] = line->v1->x; - line->bbox[BOXRIGHT] = line->v2->x; - } - else - { - line->bbox[BOXLEFT] = line->v2->x; - line->bbox[BOXRIGHT] = line->v1->x; - } - if (line->v1->y < line->v2->y) - { - line->bbox[BOXBOTTOM] = line->v1->y; - line->bbox[BOXTOP] = line->v2->y; - } - else - { - line->bbox[BOXBOTTOM] = line->v2->y; - line->bbox[BOXTOP] = line->v1->y; + // Update the line's slopetype + line->dx = line->v2->x - line->v1->x; + line->dy = line->v2->y - line->v1->y; + if (!line->dx) + { + line->slopetype = ST_VERTICAL; + } + else if (!line->dy) + { + line->slopetype = ST_HORIZONTAL; + } + else + { + line->slopetype = ((line->dy ^ line->dx) >= 0) ? ST_POSITIVE : ST_NEGATIVE; + } } + CalcCenter(); +} - // Update the line's slopetype - line->dx = line->v2->x - line->v1->x; - line->dy = line->v2->y - line->v1->y; - if (!line->dx) +void FPolyObj::CalcCenter() +{ + SQWORD cx = 0, cy = 0; + for(unsigned i=0;islopetype = ST_VERTICAL; - } - else if (!line->dy) - { - line->slopetype = ST_HORIZONTAL; - } - else - { - line->slopetype = ((line->dy ^ line->dx) >= 0) ? ST_POSITIVE : ST_NEGATIVE; + cx += Vertices[i]->x; + cy += Vertices[i]->y; } + CenterSpot.x = (fixed_t)(cx / Vertices.Size()); + CenterSpot.y = (fixed_t)(cy / Vertices.Size()); } //========================================================================== @@ -839,41 +906,35 @@ static void UpdateSegBBox (seg_t *seg) // //========================================================================== -bool PO_MovePolyobj (int num, int x, int y, bool force) +bool FPolyObj::MovePolyobj (int x, int y, bool force) { - FPolyObj *po; - - if (!(po = PO_GetPolyobj (num))) - { - I_Error ("PO_MovePolyobj: Invalid polyobj number: %d\n", num); - } - - UnLinkPolyobj (po); - DoMovePolyobj (po, x, y); + UnLinkPolyobj (); + DoMovePolyobj (x, y); if (!force) { - seg_t **segList = po->segs; bool blocked = false; - for (int count = po->numsegs; count; count--, segList++) + for(unsigned i=0;i < Sidedefs.Size(); i++) { - if (CheckMobjBlocking(*segList, po)) + if (CheckMobjBlocking(Sidedefs[i])) { blocked = true; - break; } } if (blocked) { - DoMovePolyobj (po, -x, -y); - LinkPolyobj(po); + DoMovePolyobj (-x, -y); + LinkPolyobj(); return false; } } - po->startSpot[0] += x; - po->startSpot[1] += y; - LinkPolyobj (po); + StartSpot.x += x; + StartSpot.y += y; + CenterSpot.x += x; + CenterSpot.y += y; + LinkPolyobj (); + ClearSubsectorLinks(); return true; } @@ -883,42 +944,21 @@ bool PO_MovePolyobj (int num, int x, int y, bool force) // //========================================================================== -void DoMovePolyobj (FPolyObj *po, int x, int y) +void FPolyObj::DoMovePolyobj (int x, int y) { - int count; - seg_t **segList; - seg_t **veryTempSeg; - vertex_t *prevPts; - - segList = po->segs; - prevPts = po->prevPts; - - validcount++; - for (count = po->numsegs; count; count--, segList++, prevPts++) + for(unsigned i=0;i < Vertices.Size(); i++) { - line_t *linedef = (*segList)->linedef; - if (linedef->validcount != validcount) - { - linedef->bbox[BOXTOP] += y; - linedef->bbox[BOXBOTTOM] += y; - linedef->bbox[BOXLEFT] += x; - linedef->bbox[BOXRIGHT] += x; - linedef->validcount = validcount; - } - for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) - { - if ((*veryTempSeg)->v1 == (*segList)->v1) - { - break; - } - } - if (veryTempSeg == segList) - { - (*segList)->v1->x += x; - (*segList)->v1->y += y; - } - (*prevPts).x += x; // previous points are unique for each seg - (*prevPts).y += y; + Vertices[i]->x += x; + Vertices[i]->y += y; + PrevPts[i].x += x; + PrevPts[i].y += y; + } + for (unsigned i = 0; i < Linedefs.Size(); i++) + { + Linedefs[i]->bbox[BOXTOP] += y; + Linedefs[i]->bbox[BOXBOTTOM] += y; + Linedefs[i]->bbox[BOXLEFT] += x; + Linedefs[i]->bbox[BOXRIGHT] += x; } } @@ -943,77 +983,48 @@ static void RotatePt (int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_ // //========================================================================== -bool PO_RotatePolyobj (int num, angle_t angle) +bool FPolyObj::RotatePolyobj (angle_t angle) { - int count; - seg_t **segList; - vertex_t *originalPts; - vertex_t *prevPts; int an; - FPolyObj *po; bool blocked; - if(!(po = PO_GetPolyobj(num))) + an = (this->angle+angle)>>ANGLETOFINESHIFT; + + UnLinkPolyobj(); + + for(unsigned i=0;i < Vertices.Size(); i++) { - I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num); + PrevPts[i].x = Vertices[i]->x; + PrevPts[i].y = Vertices[i]->y; + Vertices[i]->x = OriginalPts[i].x; + Vertices[i]->y = OriginalPts[i].y; + RotatePt(an, &Vertices[i]->x, &Vertices[i]->y, StartSpot.x, StartSpot.y); } - an = (po->angle+angle)>>ANGLETOFINESHIFT; - - UnLinkPolyobj(po); - - segList = po->segs; - originalPts = po->originalPts; - prevPts = po->prevPts; - - for(count = po->numsegs; count; count--, segList++, originalPts++, - prevPts++) - { - prevPts->x = (*segList)->v1->x; - prevPts->y = (*segList)->v1->y; - (*segList)->v1->x = originalPts->x; - (*segList)->v1->y = originalPts->y; - RotatePt (an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot[0], - po->startSpot[1]); - } - segList = po->segs; blocked = false; validcount++; - for (count = po->numsegs; count; count--, segList++) + UpdateBBox(); + + for(unsigned i=0;i < Sidedefs.Size(); i++) { - if (CheckMobjBlocking(*segList, po)) + if (CheckMobjBlocking(Sidedefs[i])) { blocked = true; } - if ((*segList)->linedef->validcount != validcount) - { - UpdateSegBBox(*segList); - (*segList)->linedef->validcount = validcount; - } } if (blocked) { - segList = po->segs; - prevPts = po->prevPts; - for (count = po->numsegs; count; count--, segList++, prevPts++) + for(unsigned i=0;i < Vertices.Size(); i++) { - (*segList)->v1->x = prevPts->x; - (*segList)->v1->y = prevPts->y; + Vertices[i]->x = PrevPts[i].x; + Vertices[i]->y = PrevPts[i].y; } - segList = po->segs; - validcount++; - for (count = po->numsegs; count; count--, segList++, prevPts++) - { - if ((*segList)->linedef->validcount != validcount) - { - UpdateSegBBox(*segList); - (*segList)->linedef->validcount = validcount; - } - } - LinkPolyobj(po); + UpdateBBox(); + LinkPolyobj(); return false; } - po->angle += angle; - LinkPolyobj(po); + this->angle += angle; + LinkPolyobj(); + ClearSubsectorLinks(); return true; } @@ -1023,22 +1034,22 @@ bool PO_RotatePolyobj (int num, angle_t angle) // //========================================================================== -static void UnLinkPolyobj (FPolyObj *po) +void FPolyObj::UnLinkPolyobj () { polyblock_t *link; int i, j; int index; // remove the polyobj from each blockmap section - for(j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++) + for(j = bbox[BOXBOTTOM]; j <= bbox[BOXTOP]; j++) { index = j*bmapwidth; - for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) + for(i = bbox[BOXLEFT]; i <= bbox[BOXRIGHT]; i++) { if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight) { link = PolyBlockMap[index+i]; - while(link != NULL && link->polyobj != po) + while(link != NULL && link->polyobj != this) { link = link->next; } @@ -1052,99 +1063,13 @@ static void UnLinkPolyobj (FPolyObj *po) } } -//========================================================================== -// -// LinkPolyobj -// -//========================================================================== - -static void LinkPolyobj (FPolyObj *po) -{ - int leftX, rightX; - int topY, bottomY; - seg_t **tempSeg; - polyblock_t **link; - polyblock_t *tempLink; - int i, j; - - // calculate the polyobj bbox - tempSeg = po->segs; - rightX = leftX = (*tempSeg)->v1->x; - topY = bottomY = (*tempSeg)->v1->y; - - for(i = 0; i < po->numsegs; i++, tempSeg++) - { - if((*tempSeg)->v1->x > rightX) - { - rightX = (*tempSeg)->v1->x; - } - if((*tempSeg)->v1->x < leftX) - { - leftX = (*tempSeg)->v1->x; - } - if((*tempSeg)->v1->y > topY) - { - topY = (*tempSeg)->v1->y; - } - if((*tempSeg)->v1->y < bottomY) - { - bottomY = (*tempSeg)->v1->y; - } - } - po->bbox[BOXRIGHT] = (rightX-bmaporgx)>>MAPBLOCKSHIFT; - po->bbox[BOXLEFT] = (leftX-bmaporgx)>>MAPBLOCKSHIFT; - po->bbox[BOXTOP] = (topY-bmaporgy)>>MAPBLOCKSHIFT; - po->bbox[BOXBOTTOM] = (bottomY-bmaporgy)>>MAPBLOCKSHIFT; - // add the polyobj to each blockmap section - for(j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth; - j += bmapwidth) - { - for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) - { - if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth) - { - link = &PolyBlockMap[j+i]; - if(!(*link)) - { // Create a new link at the current block cell - *link = new polyblock_t; - (*link)->next = NULL; - (*link)->prev = NULL; - (*link)->polyobj = po; - continue; - } - else - { - tempLink = *link; - while(tempLink->next != NULL && tempLink->polyobj != NULL) - { - tempLink = tempLink->next; - } - } - if(tempLink->polyobj == NULL) - { - tempLink->polyobj = po; - continue; - } - else - { - tempLink->next = new polyblock_t; - tempLink->next->next = NULL; - tempLink->next->prev = tempLink; - tempLink->next->polyobj = po; - } - } - // else, don't link the polyobj, since it's off the map - } - } -} - //========================================================================== // // CheckMobjBlocking // //========================================================================== -static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po) +bool FPolyObj::CheckMobjBlocking (side_t *sd) { static TArray checker; FBlockNode *block; @@ -1154,8 +1079,7 @@ static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po) line_t *ld; bool blocked; - ld = seg->linedef; - + ld = sd->linedef; top = (ld->bbox[BOXTOP]-bmaporgy) >> MAPBLOCKSHIFT; bottom = (ld->bbox[BOXBOTTOM]-bmaporgy) >> MAPBLOCKSHIFT; left = (ld->bbox[BOXLEFT]-bmaporgx) >> MAPBLOCKSHIFT; @@ -1205,7 +1129,7 @@ static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po) { continue; } - ThrustMobj (mobj, seg, po); + ThrustMobj (mobj, sd); blocked = true; } } @@ -1217,461 +1141,72 @@ static bool CheckMobjBlocking (seg_t *seg, FPolyObj *po) //========================================================================== // -// InitBlockMap +// LinkPolyobj // //========================================================================== -static void InitBlockMap (void) +void FPolyObj::LinkPolyobj () { - int i; + int leftX, rightX; + int topY, bottomY; + polyblock_t **link; + polyblock_t *tempLink; - PolyBlockMap = new polyblock_t *[bmapwidth*bmapheight]; - memset (PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *)); + // calculate the polyobj bbox + vertex_t *vt = Sidedefs[0]->V1(); + rightX = leftX = vt->x; + topY = bottomY = vt->y; - for (i = 0; i < po_NumPolyobjs; i++) + Bounds.ClearBox(); + for(unsigned i = 1; i < Sidedefs.Size(); i++) { - LinkPolyobj(&polyobjs[i]); + vt = Sidedefs[i]->V1(); + Bounds.AddToBox(vt->x, vt->y); } -} - -//========================================================================== -// -// InitSegLists [RH] -// -// Group segs by vertex and collect segs that are known to belong to a -// polyobject so that they can be initialized fast. -//========================================================================== - -static void InitSegLists () -{ - SDWORD i; - - SegListHead = new SDWORD[numvertexes]; - - clearbuf (SegListHead, numvertexes, -1); - - for (i = 0; i < numsegs; ++i) + bbox[BOXRIGHT] = (Bounds.Right() - bmaporgx) >> MAPBLOCKSHIFT; + bbox[BOXLEFT] = (Bounds.Left() - bmaporgx) >> MAPBLOCKSHIFT; + bbox[BOXTOP] = (Bounds.Top() - bmaporgy) >> MAPBLOCKSHIFT; + bbox[BOXBOTTOM] = (Bounds.Bottom() - bmaporgy) >> MAPBLOCKSHIFT; + // add the polyobj to each blockmap section + for(int j = bbox[BOXBOTTOM]*bmapwidth; j <= bbox[BOXTOP]*bmapwidth; + j += bmapwidth) { - if (segs[i].linedef != NULL) + for(int i = bbox[BOXLEFT]; i <= bbox[BOXRIGHT]; i++) { - SegListHead[segs[i].v1 - vertexes] = i; - if ((segs[i].linedef->special == Polyobj_StartLine || - segs[i].linedef->special == Polyobj_ExplicitLine)) + if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth) { - KnownPolySegs.Push (i); - } - } - } -} - -//========================================================================== -// -// KilSegLists [RH] -// -//========================================================================== - -static void KillSegLists () -{ - delete[] SegListHead; - SegListHead = NULL; - KnownPolySegs.Clear (); - KnownPolySegs.ShrinkToFit (); -} - -//========================================================================== -// -// IterFindPolySegs -// -// Passing NULL for segList will cause IterFindPolySegs to count the -// number of segs in the polyobj. v1 is the vertex to stop at, and v2 -// is the vertex to start at. -//========================================================================== - -static void IterFindPolySegs (vertex_t *v1, vertex_t *v2p, seg_t **segList) -{ - SDWORD j; - int v2 = int(v2p - vertexes); - int i; - - // This for loop exists solely to avoid infinitely looping on badly - // formed polyobjects. - for (i = 0; i < numsegs; i++) - { - j = SegListHead[v2]; - - if (j < 0) - { - break; - } - - if (segs[j].v1 == v1) - { - return; - } - - if (segs[j].linedef != NULL) - { - if (segList == NULL) - { - PolySegCount++; - } - else - { - *segList++ = &segs[j]; - segs[j].bPolySeg = true; - } - } - v2 = int(segs[j].v2 - vertexes); - } - I_Error ("IterFindPolySegs: Non-closed Polyobj around (%d,%d).\n", - v1->x >> FRACBITS, v1->y >> FRACBITS); -} - - -//========================================================================== -// -// SpawnPolyobj -// -//========================================================================== - -static void SpawnPolyobj (int index, int tag, int type) -{ - unsigned int ii; - int i; - int j; - - for (ii = 0; ii < KnownPolySegs.Size(); ++ii) - { - i = KnownPolySegs[ii]; - if (i < 0) - { - continue; - } - - if (segs[i].linedef->special == Polyobj_StartLine && - segs[i].linedef->args[0] == tag) - { - if (polyobjs[index].segs) - { - I_Error ("SpawnPolyobj: Polyobj %d already spawned.\n", tag); - } - segs[i].linedef->special = 0; - segs[i].linedef->args[0] = 0; - segs[i].bPolySeg = true; - PolySegCount = 1; - IterFindPolySegs(segs[i].v1, segs[i].v2, NULL); - - polyobjs[index].numsegs = PolySegCount; - polyobjs[index].segs = new seg_t *[PolySegCount]; - polyobjs[index].segs[0] = &segs[i]; // insert the first seg - IterFindPolySegs (segs[i].v1, segs[i].v2, polyobjs[index].segs+1); - polyobjs[index].crush = (type != PO_SPAWN_TYPE) ? 3 : 0; - polyobjs[index].bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); - polyobjs[index].tag = tag; - polyobjs[index].seqType = segs[i].linedef->args[2]; - if (polyobjs[index].seqType < 0 || polyobjs[index].seqType > 63) - { - polyobjs[index].seqType = 0; - } - break; - } - } - if (!polyobjs[index].segs) - { // didn't find a polyobj through PO_LINE_START - TArray polySegList; - unsigned int psIndexOld; - polyobjs[index].numsegs = 0; - for (j = 1; j < PO_MAXPOLYSEGS; j++) - { - psIndexOld = polySegList.Size(); - for (ii = 0; ii < KnownPolySegs.Size(); ++ii) - { - i = KnownPolySegs[ii]; - - if (i >= 0 && - segs[i].linedef->special == Polyobj_ExplicitLine && - segs[i].linedef->args[0] == tag) + link = &PolyBlockMap[j+i]; + if(!(*link)) + { // Create a new link at the current block cell + *link = new polyblock_t; + (*link)->next = NULL; + (*link)->prev = NULL; + (*link)->polyobj = this; + continue; + } + else { - if (!segs[i].linedef->args[1]) + tempLink = *link; + while(tempLink->next != NULL && tempLink->polyobj != NULL) { - I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", - j+1, tag); - } - if (segs[i].linedef->args[1] == j) - { - polySegList.Push (&segs[i]); - polyobjs[index].numsegs++; + tempLink = tempLink->next; } } - } - // Clear out any specials for these segs...we cannot clear them out - // in the above loop, since we aren't guaranteed one seg per linedef. - for (ii = 0; ii < KnownPolySegs.Size(); ++ii) - { - i = KnownPolySegs[ii]; - if (i >= 0 && - segs[i].linedef->special == Polyobj_ExplicitLine && - segs[i].linedef->args[0] == tag && segs[i].linedef->args[1] == j) + if(tempLink->polyobj == NULL) { - segs[i].linedef->special = 0; - segs[i].linedef->args[0] = 0; - segs[i].bPolySeg = true; - KnownPolySegs[ii] = -1; - } - } - if (polySegList.Size() == psIndexOld) - { // Check if an explicit line order has been skipped. - // A line has been skipped if there are any more explicit - // lines with the current tag value. [RH] Can this actually happen? - for (ii = 0; ii < KnownPolySegs.Size(); ++ii) - { - i = KnownPolySegs[ii]; - if (i >= 0 && - segs[i].linedef->special == Polyobj_ExplicitLine && - segs[i].linedef->args[0] == tag) - { - I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", - j, tag); - } + tempLink->polyobj = this; + continue; + } + else + { + tempLink->next = new polyblock_t; + tempLink->next->next = NULL; + tempLink->next->prev = tempLink; + tempLink->next->polyobj = this; } } + // else, don't link the polyobj, since it's off the map } - if (polyobjs[index].numsegs) - { - PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally - polyobjs[index].crush = (type != PO_SPAWN_TYPE) ? 3 : 0; - polyobjs[index].bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); - polyobjs[index].tag = tag; - polyobjs[index].segs = new seg_t *[polyobjs[index].numsegs]; - for (i = 0; i < polyobjs[index].numsegs; i++) - { - polyobjs[index].segs[i] = polySegList[i]; - } - polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->args[3]; - // Next, change the polyobj's first line to point to a mirror - // if it exists - (*polyobjs[index].segs)->linedef->args[1] = - (*polyobjs[index].segs)->linedef->args[2]; - } - else - I_Error ("SpawnPolyobj: Poly %d does not exist\n", tag); - } - - TArray lines; - TArray vertices; - - for(int i=0; ilinedef; - int j; - - for(j = lines.Size() - 1; j >= 0; j--) - { - if (lines[j] == l) break; - } - if (j < 0) lines.Push(l); - - vertex_t *v = polyobjs[index].segs[i]->v1; - - for(j = vertices.Size() - 1; j >= 0; j--) - { - if (vertices[j] == v) break; - } - if (j < 0) vertices.Push(v); - - v = polyobjs[index].segs[i]->v2; - - for(j = vertices.Size() - 1; j >= 0; j--) - { - if (vertices[j] == v) break; - } - if (j < 0) vertices.Push(v); - } - polyobjs[index].numlines = lines.Size(); - polyobjs[index].lines = new line_t*[lines.Size()]; - memcpy(polyobjs[index].lines, &lines[0], sizeof(lines[0]) * lines.Size()); - - polyobjs[index].numvertices = vertices.Size(); - polyobjs[index].vertices = new vertex_t*[vertices.Size()]; - memcpy(polyobjs[index].vertices, &vertices[0], sizeof(vertices[0]) * vertices.Size()); -} - -//========================================================================== -// -// TranslateToStartSpot -// -//========================================================================== - -static void TranslateToStartSpot (int tag, int originX, int originY) -{ - seg_t **tempSeg; - seg_t **veryTempSeg; - vertex_t *tempPt; - subsector_t *sub; - FPolyObj *po; - int deltaX; - int deltaY; - vertex_t avg; // used to find a polyobj's center, and hence subsector - int i; - - po = NULL; - for (i = 0; i < po_NumPolyobjs; i++) - { - if (polyobjs[i].tag == tag) - { - po = &polyobjs[i]; - break; - } - } - if (po == NULL) - { // didn't match the tag with a polyobj tag - I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n", - tag); - } - if (po->segs == NULL) - { - I_Error ("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag); - } - po->originalPts = new vertex_t[po->numsegs]; - po->prevPts = new vertex_t[po->numsegs]; - deltaX = originX-po->startSpot[0]; - deltaY = originY-po->startSpot[1]; - - tempSeg = po->segs; - tempPt = po->originalPts; - avg.x = 0; - avg.y = 0; - - validcount++; - for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++) - { - (*tempSeg)->bPolySeg = true; // this is not set for all segs - (*tempSeg)->sidedef->Flags |= WALLF_POLYOBJ; - if ((*tempSeg)->linedef->validcount != validcount) - { - (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY; - (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY; - (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX; - (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX; - (*tempSeg)->linedef->validcount = validcount; - } - for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++) - { - if((*veryTempSeg)->v1 == (*tempSeg)->v1) - { - break; - } - } - if (veryTempSeg == tempSeg) - { // the point hasn't been translated, yet - (*tempSeg)->v1->x -= deltaX; - (*tempSeg)->v1->y -= deltaY; - } - avg.x += (*tempSeg)->v1->x >> FRACBITS; - avg.y += (*tempSeg)->v1->y >> FRACBITS; - // the original Pts are based off the startSpot Pt, and are - // unique to each seg, not each linedef - tempPt->x = (*tempSeg)->v1->x-po->startSpot[0]; - tempPt->y = (*tempSeg)->v1->y-po->startSpot[1]; - } - // Put polyobj in its subsector. - avg.x /= po->numsegs; - avg.y /= po->numsegs; - sub = R_PointInSubsector (avg.x << FRACBITS, avg.y << FRACBITS); - if (sub->poly != NULL) - { - I_Error ("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n"); - } - sub->poly = po; -} - -//========================================================================== -// -// PO_Init -// -//========================================================================== - -void PO_Init (void) -{ - // [RH] Hexen found the polyobject-related things by reloading the map's - // THINGS lump here and scanning through it. I have P_SpawnMapThing() - // record those things instead, so that in here we simply need to - // look at the polyspawns list. - polyspawns_t *polyspawn, **prev; - int polyIndex; - - // [RH] Make this faster - InitSegLists (); - - polyobjs = new FPolyObj[po_NumPolyobjs]; - memset (polyobjs, 0, po_NumPolyobjs*sizeof(FPolyObj)); - - polyIndex = 0; // index polyobj number - // Find the startSpot points, and spawn each polyobj - for (polyspawn = polyspawns, prev = &polyspawns; polyspawn;) - { - // 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch - if (polyspawn->type == PO_SPAWN_TYPE || - polyspawn->type == PO_SPAWNCRUSH_TYPE || - polyspawn->type == PO_SPAWNHURT_TYPE) - { // Polyobj StartSpot Pt. - polyobjs[polyIndex].startSpot[0] = polyspawn->x; - polyobjs[polyIndex].startSpot[1] = polyspawn->y; - SpawnPolyobj(polyIndex, polyspawn->angle, polyspawn->type); - polyIndex++; - *prev = polyspawn->next; - delete polyspawn; - polyspawn = *prev; - } else { - prev = &polyspawn->next; - polyspawn = polyspawn->next; - } - } - for (polyspawn = polyspawns; polyspawn;) - { - polyspawns_t *next = polyspawn->next; - if (polyspawn->type == PO_ANCHOR_TYPE) - { // Polyobj Anchor Pt. - TranslateToStartSpot (polyspawn->angle, polyspawn->x, polyspawn->y); - } - delete polyspawn; - polyspawn = next; - } - polyspawns = NULL; - - // check for a startspot without an anchor point - for (polyIndex = 0; polyIndex < po_NumPolyobjs; polyIndex++) - { - if (!polyobjs[polyIndex].originalPts) - { - I_Error ("PO_Init: StartSpot located without an Anchor point: %d\n", - polyobjs[polyIndex].tag); - } - } - InitBlockMap(); - - // [RH] Don't need the seg lists anymore - KillSegLists (); -} - -//========================================================================== -// -// PO_Busy -// -//========================================================================== - -bool PO_Busy (int polyobj) -{ - FPolyObj *poly; - - poly = PO_GetPolyobj (polyobj); - if (poly == NULL || poly->specialdata == NULL) - { - return false; - } - else - { - return true; } } @@ -1684,18 +1219,18 @@ bool PO_Busy (int polyobj) // //=========================================================================== -void PO_ClosestPoint(const FPolyObj *poly, fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, seg_t **seg) +void FPolyObj::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, side_t **side) const { - int i; + unsigned int i; double x = fx, y = fy; double bestdist = HUGE_VAL; double bestx = 0, besty = 0; - seg_t *bestseg = NULL; + side_t *bestline = NULL; - for (i = 0; i < poly->numsegs; ++i) + for (i = 0; i < Sidedefs.Size(); ++i) { - vertex_t *v1 = poly->segs[i]->v1; - vertex_t *v2 = poly->segs[i]->v2; + vertex_t *v1 = Sidedefs[i]->V1(); + vertex_t *v2 = Sidedefs[i]->V2(); double a = v2->x - v1->x; double b = v2->y - v1->y; double den = a*a + b*b; @@ -1734,42 +1269,801 @@ void PO_ClosestPoint(const FPolyObj *poly, fixed_t fx, fixed_t fy, fixed_t &ox, bestdist = dist; bestx = ix; besty = iy; - bestseg = poly->segs[i]; + bestline = Sidedefs[i]; } } ox = fixed_t(bestx); oy = fixed_t(besty); - if (seg != NULL) + if (side != NULL) { - *seg = bestseg; + *side = bestline; } } -FPolyObj::~FPolyObj() +vertex_t *FPolyObj::GetNewVertex() { - if (segs != NULL) + if (SVIndex == ~0u || SplitVertices[SVIndex]->used == 10) { - delete[] segs; - segs = NULL; + SVIndex++; + if (SVIndex >= SplitVertices.Size()) + { + SplitVertices.Push(new FPolyVertexBlock); + } + SplitVertices[SVIndex]->clear(); } - if (lines != NULL) + return &SplitVertices[SVIndex]->vertices[SplitVertices[SVIndex]->used++]; +} + +//========================================================================== +// +// InitBlockMap +// +//========================================================================== + +static void InitBlockMap (void) +{ + int i; + + PolyBlockMap = new polyblock_t *[bmapwidth*bmapheight]; + memset (PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *)); + + for (i = 0; i < po_NumPolyobjs; i++) { - delete[] lines; - lines = NULL; - } - if (vertices != NULL) - { - delete[] vertices; - vertices = NULL; - } - if (originalPts != NULL) - { - delete[] originalPts; - originalPts = NULL; - } - if (prevPts != NULL) - { - delete[] prevPts; - prevPts = NULL; + polyobjs[i].LinkPolyobj(); } } + +//========================================================================== +// +// InitSideLists [RH] +// +// Group sides by vertex and collect side that are known to belong to a +// polyobject so that they can be initialized fast. +//========================================================================== + +static void InitSideLists () +{ + SDWORD i; + + SideListHead = new SDWORD[numvertexes]; + clearbuf (SideListHead, numvertexes, -1); + + for (i = 0; i < numsides; ++i) + { + if (sides[i].linedef != NULL) + { + SideListHead[sides[i].V1() - vertexes] = i; + if ((sides[i].linedef->special == Polyobj_StartLine || + sides[i].linedef->special == Polyobj_ExplicitLine)) + { + KnownPolySides.Push (i); + } + } + } +} + +//========================================================================== +// +// KillSideLists [RH] +// +//========================================================================== + +static void KillSideLists () +{ + delete[] SideListHead; + SideListHead = NULL; + KnownPolySides.Clear (); + KnownPolySides.ShrinkToFit (); +} + +//========================================================================== +// +// IterFindPolySides +// +//========================================================================== + +static void IterFindPolySides (FPolyObj *po, side_t *side) +{ + SDWORD j; + int i; + vertex_t *v1 = side->V1(); + + po->Sidedefs.Push(side); + + // This for loop exists solely to avoid infinitely looping on badly + // formed polyobjects. + for (i = 0; i < numsides; i++) + { + int v2 = int(side->V2() - vertexes); + j = SideListHead[v2]; + + if (j < 0) + { + break; + } + side = &sides[j]; + + if (side->V1() == v1) + { + return; + } + po->Sidedefs.Push(side); + } + I_Error ("IterFindPolySides: Non-closed Polyobj at linedef %d.\n", + side->linedef-lines); +} + + +//========================================================================== +// +// SpawnPolyobj +// +//========================================================================== + +static void SpawnPolyobj (int index, int tag, int type) +{ + unsigned int ii; + int i; + int j; + FPolyObj *po = &polyobjs[index]; + + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + if (i < 0) + { + continue; + } + + side_t *sd = &sides[i]; + + if (sd->linedef->special == Polyobj_StartLine && + sd->linedef->args[0] == tag) + { + if (po->Sidedefs.Size() > 0) + { + I_Error ("SpawnPolyobj: Polyobj %d already spawned.\n", tag); + } + sd->linedef->special = 0; + sd->linedef->args[0] = 0; + IterFindPolySides(&polyobjs[index], sd); + po->crush = (type != PO_SPAWN_TYPE) ? 3 : 0; + po->bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); + po->tag = tag; + po->seqType = sd->linedef->args[2]; + if (po->seqType < 0 || po->seqType > 63) + { + po->seqType = 0; + } + break; + } + } + if (po->Sidedefs.Size() == 0) + { + // didn't find a polyobj through PO_LINE_START + TArray polySideList; + unsigned int psIndexOld; + for (j = 1; j < PO_MAXPOLYSEGS; j++) + { + psIndexOld = po->Sidedefs.Size(); + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + + if (i >= 0 && + sides[i].linedef->special == Polyobj_ExplicitLine && + sides[i].linedef->args[0] == tag) + { + if (!sides[i].linedef->args[1]) + { + I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", + j+1, tag); + } + if (sides[i].linedef->args[1] == j) + { + po->Sidedefs.Push (&sides[i]); + } + } + } + // Clear out any specials for these segs...we cannot clear them out + // in the above loop, since we aren't guaranteed one seg per linedef. + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + if (i >= 0 && + sides[i].linedef->special == Polyobj_ExplicitLine && + sides[i].linedef->args[0] == tag && sides[i].linedef->args[1] == j) + { + sides[i].linedef->special = 0; + sides[i].linedef->args[0] = 0; + KnownPolySides[ii] = -1; + } + } + if (po->Sidedefs.Size() == psIndexOld) + { // Check if an explicit line order has been skipped. + // A line has been skipped if there are any more explicit + // lines with the current tag value. [RH] Can this actually happen? + for (ii = 0; ii < KnownPolySides.Size(); ++ii) + { + i = KnownPolySides[ii]; + if (i >= 0 && + sides[i].linedef->special == Polyobj_ExplicitLine && + sides[i].linedef->args[0] == tag) + { + I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", + j, tag); + } + } + } + } + if (po->Sidedefs.Size() > 0) + { + po->crush = (type != PO_SPAWN_TYPE) ? 3 : 0; + po->bHurtOnTouch = (type == PO_SPAWNHURT_TYPE); + po->tag = tag; + po->seqType = po->Sidedefs[0]->linedef->args[3]; + // Next, change the polyobj's first line to point to a mirror + // if it exists + po->Sidedefs[0]->linedef->args[1] = + po->Sidedefs[0]->linedef->args[2]; + } + else + I_Error ("SpawnPolyobj: Poly %d does not exist\n", tag); + } + + validcount++; + for(unsigned int i=0; iSidedefs.Size(); i++) + { + line_t *l = po->Sidedefs[i]->linedef; + + if (l->validcount != validcount) + { + l->validcount = validcount; + po->Linedefs.Push(l); + + vertex_t *v = l->v1; + int j; + for(j = po->Vertices.Size() - 1; j >= 0; j--) + { + if (po->Vertices[j] == v) break; + } + if (j < 0) po->Vertices.Push(v); + + v = l->v2; + for(j = po->Vertices.Size() - 1; j >= 0; j--) + { + if (po->Vertices[j] == v) break; + } + if (j < 0) po->Vertices.Push(v); + + } + } + po->Sidedefs.ShrinkToFit(); + po->Linedefs.ShrinkToFit(); + po->Vertices.ShrinkToFit(); +} + +//========================================================================== +// +// TranslateToStartSpot +// +//========================================================================== + +static void TranslateToStartSpot (int tag, int originX, int originY) +{ + FPolyObj *po; + int deltaX; + int deltaY; + + po = NULL; + for (int i = 0; i < po_NumPolyobjs; i++) + { + if (polyobjs[i].tag == tag) + { + po = &polyobjs[i]; + break; + } + } + if (po == NULL) + { // didn't match the tag with a polyobj tag + I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag); + } + if (po->Sidedefs.Size() == 0) + { + I_Error ("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag); + } + po->OriginalPts.Resize(po->Sidedefs.Size()); + po->PrevPts.Resize(po->Sidedefs.Size()); + deltaX = originX - po->StartSpot.x; + deltaY = originY - po->StartSpot.y; + + for (unsigned i = 0; i < po->Sidedefs.Size(); i++) + { + po->Sidedefs[i]->Flags |= WALLF_POLYOBJ; + } + for (unsigned i = 0; i < po->Linedefs.Size(); i++) + { + po->Linedefs[i]->bbox[BOXTOP] -= deltaY; + po->Linedefs[i]->bbox[BOXBOTTOM] -= deltaY; + po->Linedefs[i]->bbox[BOXLEFT] -= deltaX; + po->Linedefs[i]->bbox[BOXRIGHT] -= deltaX; + } + for (unsigned i = 0; i < po->Vertices.Size(); i++) + { + po->Vertices[i]->x -= deltaX; + po->Vertices[i]->y -= deltaY; + po->OriginalPts[i].x = po->Vertices[i]->x - po->StartSpot.x; + po->OriginalPts[i].y = po->Vertices[i]->y - po->StartSpot.y; + } + po->CalcCenter(); + // subsector assignment no longer done here. + // Polyobjects will be sorted into the subsectors each frame before rendering them. +} + +//========================================================================== +// +// PO_Init +// +//========================================================================== + +void PO_Init (void) +{ + // [RH] Hexen found the polyobject-related things by reloading the map's + // THINGS lump here and scanning through it. I have P_SpawnMapThing() + // record those things instead, so that in here we simply need to + // look at the polyspawns list. + polyspawns_t *polyspawn, **prev; + int polyIndex; + + // [RH] Make this faster + InitSideLists (); + + polyobjs = new FPolyObj[po_NumPolyobjs]; + + polyIndex = 0; // index polyobj number + // Find the startSpot points, and spawn each polyobj + for (polyspawn = polyspawns, prev = &polyspawns; polyspawn;) + { + // 9301 (3001) = no crush, 9302 (3002) = crushing, 9303 = hurting touch + if (polyspawn->type == PO_SPAWN_TYPE || + polyspawn->type == PO_SPAWNCRUSH_TYPE || + polyspawn->type == PO_SPAWNHURT_TYPE) + { + // Polyobj StartSpot Pt. + polyobjs[polyIndex].StartSpot.x = polyspawn->x; + polyobjs[polyIndex].StartSpot.y = polyspawn->y; + SpawnPolyobj(polyIndex, polyspawn->angle, polyspawn->type); + polyIndex++; + *prev = polyspawn->next; + delete polyspawn; + polyspawn = *prev; + } + else + { + prev = &polyspawn->next; + polyspawn = polyspawn->next; + } + } + for (polyspawn = polyspawns; polyspawn;) + { + polyspawns_t *next = polyspawn->next; + if (polyspawn->type == PO_ANCHOR_TYPE) + { + // Polyobj Anchor Pt. + TranslateToStartSpot (polyspawn->angle, polyspawn->x, polyspawn->y); + } + delete polyspawn; + polyspawn = next; + } + polyspawns = NULL; + + // check for a startspot without an anchor point + for (polyIndex = 0; polyIndex < po_NumPolyobjs; polyIndex++) + { + if (polyobjs[polyIndex].OriginalPts.Size() == 0) + { + I_Error ("PO_Init: StartSpot located without an Anchor point: %d\n", + polyobjs[polyIndex].tag); + } + } + InitBlockMap(); + + // [RH] Don't need the seg lists anymore + KillSideLists (); + + // We still need to flag the segs of the polyobj's sidedefs so that they are excluded from rendering. + for(int i=0;iFlags & WALLF_POLYOBJ); + } + + for(int i=0;idx; + double fdy = (double)no->dy; + no->len = (float)sqrt(fdx * fdx + fdy * fdy); + } +} + +//========================================================================== +// +// PO_Busy +// +//========================================================================== + +bool PO_Busy (int polyobj) +{ + FPolyObj *poly; + + poly = PO_GetPolyobj (polyobj); + return (poly != NULL && poly->specialdata != NULL); +} + + + +//========================================================================== +// +// +// +//========================================================================== + +void FPolyObj::ClearSubsectorLinks() +{ + for(unsigned i=0; iclear(); + } + SVIndex = -1; + while (subsectorlinks != NULL) + { + assert(subsectorlinks->state == 1337); + + FPolyNode *next = subsectorlinks->snext; + + if (subsectorlinks->pnext != NULL) + { + assert(subsectorlinks->pnext->state == 1337); + subsectorlinks->pnext->pprev = subsectorlinks->pprev; + } + + if (subsectorlinks->pprev != NULL) + { + assert(subsectorlinks->pprev->state == 1337); + subsectorlinks->pprev->pnext = subsectorlinks->pnext; + } + else + { + subsectorlinks->subsector->polys = subsectorlinks->pnext; + } + subsectorlinks->state = -1; + delete subsectorlinks; + subsectorlinks = next; + } + subsectorlinks = NULL; +} + +void FPolyObj::ClearAllSubsectorLinks() +{ + for(int i=0;iv1->x; + double v2y = (double)seg->v1->y; + double v2dx = (double)(seg->v2->x - seg->v1->x); + double v2dy = (double)(seg->v2->y - seg->v1->y); + double v1x = (double)bsp->x; + double v1y = (double)bsp->y; + double v1dx = (double)bsp->dx; + double v1dy = (double)bsp->dy; + + den = v1dy*v2dx - v1dx*v2dy; + + if (den == 0) + return false; // parallel + + num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; + frac = num / den; + + if (frac < 0. || frac > 1.) return false; + + v->x = xs_RoundToInt(v2x + frac * v2dx); + v->y = xs_RoundToInt(v2y + frac * v2dy); + return true; +} + +//========================================================================== +// +// PartitionDistance +// +// Determine the distance of a vertex to a node's partition line. +// +//========================================================================== + +static double PartitionDistance(vertex_t *vt, node_t *node) +{ + return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len; +} + +//========================================================================== +// +// AddToBBox +// +//========================================================================== + +static void AddToBBox(fixed_t child[4], fixed_t parent[4]) +{ + if (child[BOXTOP] > parent[BOXTOP]) + { + parent[BOXTOP] = child[BOXTOP]; + } + if (child[BOXBOTTOM] < parent[BOXBOTTOM]) + { + parent[BOXBOTTOM] = child[BOXBOTTOM]; + } + if (child[BOXLEFT] < parent[BOXLEFT]) + { + parent[BOXLEFT] = child[BOXLEFT]; + } + if (child[BOXRIGHT] > parent[BOXRIGHT]) + { + parent[BOXRIGHT] = child[BOXRIGHT]; + } +} + +//========================================================================== +// +// AddToBBox +// +//========================================================================== + +static void AddToBBox(vertex_t *v, fixed_t bbox[4]) +{ + if (v->x < bbox[BOXLEFT]) + { + bbox[BOXLEFT] = v->x; + } + if (v->x > bbox[BOXRIGHT]) + { + bbox[BOXRIGHT] = v->x; + } + if (v->y < bbox[BOXBOTTOM]) + { + bbox[BOXBOTTOM] = v->y; + } + if (v->y > bbox[BOXTOP]) + { + bbox[BOXTOP] = v->y; + } +} + +//========================================================================== +// +// SplitPoly +// +//========================================================================== + +static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) +{ + static TArray lists[2]; + static const double POLY_EPSILON = 0.3125; + + if (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + + int centerside = R_PointOnSide(pnode->poly->CenterSpot.x, pnode->poly->CenterSpot.y, bsp); + + lists[0].Clear(); + lists[1].Clear(); + for(unsigned i=0;isegs.Size(); i++) + { + seg_t *seg = &pnode->segs[i]; + + // Parts of the following code were taken from Eternity and are + // being used with permission. + + // get distance of vertices from partition line + // If the distance is too small, we may decide to + // change our idea of sidedness. + double dist_v1 = PartitionDistance(seg->v1, bsp); + double dist_v2 = PartitionDistance(seg->v2, bsp); + + // If the distances are less than epsilon, consider the points as being + // on the same side as the polyobj origin. Why? People like to build + // polyobject doors flush with their door tracks. This breaks using the + // usual assumptions. + + + // Addition to Eternity code: We must also check any seg with only one + // vertex inside the epsilon threshold. If not, these lines will get split but + // adjoining ones with both vertices inside the threshold won't thus messing up + // the order in which they get drawn. + + if(dist_v1 <= POLY_EPSILON) + { + if (dist_v2 <= POLY_EPSILON) + { + lists[centerside].Push(*seg); + } + else + { + int side = R_PointOnSide(seg->v2->x, seg->v2->y, bsp); + lists[side].Push(*seg); + } + } + else if (dist_v2 <= POLY_EPSILON) + { + int side = R_PointOnSide(seg->v1->x, seg->v1->y, bsp); + lists[side].Push(*seg); + } + else + { + int side1 = R_PointOnSide(seg->v1->x, seg->v1->y, bsp); + int side2 = R_PointOnSide(seg->v2->x, seg->v2->y, bsp); + + if(side1 != side2) + { + // if the partition line crosses this seg, we must split it. + + vertex_t *vert = pnode->poly->GetNewVertex(); + + if (GetIntersection(seg, bsp, vert)) + { + lists[0].Push(*seg); + lists[1].Push(*seg); + lists[side1].Last().v2 = vert; + lists[side2].Last().v1 = vert; + } + else + { + // should never happen + lists[side1].Push(*seg); + } + } + else + { + // both points on the same side. + lists[side1].Push(*seg); + } + } + } + if (lists[1].Size() == 0) + { + SplitPoly(pnode, bsp->children[0], bsp->bbox[0]); + AddToBBox(bsp->bbox[0], bbox); + } + else if (lists[0].Size() == 0) + { + SplitPoly(pnode, bsp->children[1], bsp->bbox[1]); + AddToBBox(bsp->bbox[1], bbox); + } + else + { + // create the new node + FPolyNode *newnode = new FPolyNode; + newnode->state = 1337; + newnode->poly = pnode->poly; + newnode->pnext = NULL; + newnode->pprev = NULL; + newnode->subsector = NULL; + newnode->snext = NULL; + newnode->segs = lists[1]; + + // set segs for original node + pnode->segs = lists[0]; + + // recurse back side + SplitPoly(newnode, bsp->children[1], bsp->bbox[1]); + + // recurse front side + SplitPoly(pnode, bsp->children[0], bsp->bbox[0]); + + AddToBBox(bsp->bbox[0], bbox); + AddToBBox(bsp->bbox[1], bbox); + } + } + else + { + // we reached a subsector so we can link the node with this subsector + subsector_t *sub = (subsector_t *)((BYTE *)node - 1); + + // Link node to subsector + pnode->pnext = sub->polys; + if (pnode->pnext != NULL) + { + assert(pnode->pnext->state == 1337); + pnode->pnext->pprev = pnode; + } + pnode->pprev = NULL; + sub->polys = pnode; + + // link node to polyobject + pnode->snext = pnode->poly->subsectorlinks; + pnode->poly->subsectorlinks = pnode; + pnode->subsector = sub; + + // calculate bounding box for this polynode + assert(pnode->segs.Size() != 0); + fixed_t subbbox[4] = { FIXED_MIN, FIXED_MAX, FIXED_MAX, FIXED_MIN }; + + for (unsigned i = 0; i < pnode->segs.Size(); ++i) + { + AddToBBox(pnode->segs[i].v1, subbbox); + AddToBBox(pnode->segs[i].v2, subbbox); + } + // Potentially expand the parent node's bounding box to contain these bits of polyobject. + AddToBBox(subbbox, bbox); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FPolyObj::CreateSubsectorLinks() +{ + FPolyNode *node = new FPolyNode; + fixed_t dummybbox[4]; + + node->state = 1337; + node->poly = this; + node->pnext = NULL; + node->pprev = NULL; + node->snext = NULL; + node->segs.Resize(Sidedefs.Size()); + + for(unsigned i=0; isegs[i]; + side_t *side = Sidedefs[i]; + + seg->v1 = side->V1(); + seg->v2 = side->V2(); + seg->sidedef = side; + seg->linedef = side->linedef; + seg->frontsector = side->sector; + seg->backsector = side->linedef->frontsector == side->sector? + side->linedef->backsector : side->linedef->frontsector; + seg->Subsector = NULL; + seg->PartnerSeg = NULL; + seg->bPolySeg = true; + } + SplitPoly(node, nodes + numnodes - 1, dummybbox); +} + +//========================================================================== +// +// +// +//========================================================================== + +void PO_LinkToSubsectors() +{ + for (int i = 0; i < po_NumPolyobjs; i++) + { + if (polyobjs[i].subsectorlinks == NULL) + { + polyobjs[i].CreateSubsectorLinks(); + } + } +} \ No newline at end of file diff --git a/src/po_man.h b/src/po_man.h new file mode 100644 index 000000000..88565cbbf --- /dev/null +++ b/src/po_man.h @@ -0,0 +1,116 @@ +#ifndef __PO_MAN_H +#define __PO_MAN_H + +#include "tarray.h" +#include "r_defs.h" +#include "m_bbox.h" + +// +// Linked lists of polyobjects +// +struct FPolyObj; +struct FPolyNode +{ + int state; + FPolyObj *poly; // owning polyobject + FPolyNode *pnext; // next polyobj in list + FPolyNode *pprev; // previous polyobj + + subsector_t *subsector; // containimg subsector + FPolyNode *snext; // next subsector + + TArray segs; // segs for this node + fixed_t dist; // distance for sorting +}; + +struct FPolyVertex +{ + fixed_t x, y; +}; + +struct FPolyVertexBlock +{ + int used; + vertex_t vertices[10]; + + void clear() + { + used = 0; + //memset(vertices, 0, sizeof(vertices)); + } +}; + +// ===== Polyobj data ===== +struct FPolyObj +{ + TArray Sidedefs; + TArray Linedefs; + TArray Vertices; + TArray OriginalPts; + TArray PrevPts; + FPolyVertex StartSpot; + FPolyVertex CenterSpot; + FBoundingBox Bounds; // Bounds in map coordinates + TDeletingArray SplitVertices; + unsigned int SVIndex; + + angle_t angle; + int tag; // reference tag assigned in HereticEd + int bbox[4]; // bounds in blockmap coordinates + int validcount; + int crush; // should the polyobj attempt to crush mobjs? + bool bHurtOnTouch; // should the polyobj hurt anything it touches? + int seqType; + fixed_t size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) + FPolyNode *subsectorlinks; + DThinker *specialdata; // pointer to a thinker, if the poly is moving + TObjPtr interpolation; + + FPolyObj(); + DInterpolation *SetInterpolation(); + void StopInterpolation(); + + int GetMirror(); + bool MovePolyobj (int x, int y, bool force = false); + bool RotatePolyobj (angle_t angle); + void ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, side_t **side) const; + void LinkPolyobj (); + void CreateSubsectorLinks(); + void ClearSubsectorLinks(); + vertex_t *GetNewVertex(); + void CalcCenter(); + static void ClearAllSubsectorLinks(); + +private: + + void ThrustMobj (AActor *actor, side_t *side); + void UpdateBBox (); + void DoMovePolyobj (int x, int y); + void UnLinkPolyobj (); + bool CheckMobjBlocking (side_t *sd); + +}; +extern FPolyObj *polyobjs; // list of all poly-objects on the level + +inline FArchive &operator<< (FArchive &arc, FPolyObj *&poly) +{ + return arc.SerializePointer (polyobjs, (BYTE **)&poly, sizeof(FPolyObj)); +} + +inline FArchive &operator<< (FArchive &arc, const FPolyObj *&poly) +{ + return arc.SerializePointer (polyobjs, (BYTE **)&poly, sizeof(FPolyObj)); +} + +struct polyblock_t +{ + FPolyObj *polyobj; + struct polyblock_t *prev; + struct polyblock_t *next; +}; + + +void PO_LinkToSubsectors(); + + +#endif \ No newline at end of file diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index a1f6f6098..da2eee749 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -50,6 +50,7 @@ #include "r_bsp.h" #include "v_palette.h" #include "r_sky.h" +#include "po_man.h" int WallMost (short *mostbuf, const secplane_t &plane); @@ -1006,6 +1007,46 @@ void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el) } } } + + +static int STACK_ARGS polycmp(const void *a, const void *b) +{ + const FPolyNode *A = *(FPolyNode **)a; + const FPolyNode *B = *(FPolyNode **)b; + + return A->dist - B->dist; +} + + +static void R_AddPolyobjs(subsector_t *sub) +{ + static TArray sortedpolys; + + FPolyNode *pn = sub->polys; + sortedpolys.Clear(); + while (pn != NULL) + { + sortedpolys.Push(pn); + pn->dist = R_PointToDist2(pn->poly->CenterSpot.x - viewx, pn->poly->CenterSpot.y - viewy); + pn = pn->pnext; + } + if (sortedpolys.Size() > 1) + { + qsort(&sortedpolys[0], sortedpolys.Size(), sizeof (sortedpolys[0]), polycmp); + } + + for(unsigned i=0; isegs.Size(); j++) + { + R_AddLine(&pn->segs[j]); + } + } +} + + + // // R_Subsector // Determine floor/ceiling planes. @@ -1098,14 +1139,9 @@ void R_Subsector (subsector_t *sub) R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide); } - if (sub->poly) - { // Render the polyobj in the subsector first - int polyCount = sub->poly->numsegs; - seg_t **polySeg = sub->poly->segs; - while (polyCount--) - { - R_AddLine (*polySeg++); - } + if (sub->polys) + { // Render the polyobjs in the subsector first + R_AddPolyobjs(sub); } while (count--) diff --git a/src/r_defs.h b/src/r_defs.h index 64d9b7614..e6ad90448 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -75,6 +75,11 @@ struct vertex_t { return x == other.x && y == other.y; } + + void clear() + { + x = y = 0; + } }; // Forward of LineDefs, for Sectors. @@ -854,6 +859,9 @@ struct side_t DInterpolation *SetInterpolation(int position); void StopInterpolation(int position); + + vertex_t *V1() const; + vertex_t *V2() const; }; FArchive &operator<< (FArchive &arc, side_t::part &p); @@ -916,19 +924,20 @@ struct msecnode_t bool visited; // killough 4/4/98, 4/7/98: used in search algorithms }; +struct FPolyNode; + // // A SubSector. // References a Sector. // Basically, this is a list of LineSegs indicating the visible walls that // define (all or some) sides of a convex BSP leaf. // -struct FPolyObj; struct subsector_t { sector_t *sector; DWORD numlines; DWORD firstline; - FPolyObj *poly; + FPolyNode *polys; int validcount; fixed_t CenterX, CenterY; }; @@ -954,45 +963,7 @@ struct seg_t BITFIELD bPolySeg:1; }; -// ===== Polyobj data ===== -struct FPolyObj -{ - int numsegs; - seg_t **segs; - int numlines; - line_t **lines; - int numvertices; - vertex_t **vertices; - fixed_t startSpot[2]; - vertex_t *originalPts; // used as the base for the rotations - vertex_t *prevPts; // use to restore the old point values - angle_t angle; - int tag; // reference tag assigned in HereticEd - int bbox[4]; - int validcount; - int crush; // should the polyobj attempt to crush mobjs? - bool bHurtOnTouch; // should the polyobj hurt anything it touches? - int seqType; - fixed_t size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) - DThinker *specialdata; // pointer to a thinker, if the poly is moving - TObjPtr interpolation; - - ~FPolyObj(); - DInterpolation *SetInterpolation(); - void StopInterpolation(); -}; -extern FPolyObj *polyobjs; // list of all poly-objects on the level - -inline FArchive &operator<< (FArchive &arc, FPolyObj *&poly) -{ - return arc.SerializePointer (polyobjs, (BYTE **)&poly, sizeof(FPolyObj)); -} - -inline FArchive &operator<< (FArchive &arc, const FPolyObj *&poly) -{ - return arc.SerializePointer (polyobjs, (BYTE **)&poly, sizeof(FPolyObj)); -} - + // // BSP node. @@ -1005,6 +976,7 @@ struct node_t fixed_t dx; fixed_t dy; fixed_t bbox[2][4]; // Bounding box for each child. + float len; union { void *children[2]; // If bit 0 is set, it's a subsector. @@ -1013,15 +985,6 @@ struct node_t }; -struct polyblock_t -{ - FPolyObj *polyobj; - struct polyblock_t *prev; - struct polyblock_t *next; -}; - - - // posts are runs of non masked source pixels struct column_t { diff --git a/src/r_interpolate.cpp b/src/r_interpolate.cpp index 238793981..f2fba2f8c 100644 --- a/src/r_interpolate.cpp +++ b/src/r_interpolate.cpp @@ -38,6 +38,8 @@ #include "stats.h" #include "r_interpolate.h" #include "p_local.h" +#include "i_system.h" +#include "po_man.h" //========================================================================== // @@ -134,6 +136,8 @@ class DPolyobjInterpolation : public DInterpolation FPolyObj *poly; TArray oldverts, bakverts; + fixed_t oldcx, oldcy; + fixed_t bakcx, bakcy; public: @@ -728,8 +732,8 @@ void DWallScrollInterpolation::Serialize(FArchive &arc) DPolyobjInterpolation::DPolyobjInterpolation(FPolyObj *po) { poly = po; - oldverts.Resize(po->numvertices<<1); - bakverts.Resize(po->numvertices<<1); + oldverts.Resize(po->Vertices.Size() << 1); + bakverts.Resize(po->Vertices.Size() << 1); UpdateInterpolation (); interpolator.AddInterpolation(this); } @@ -755,11 +759,13 @@ void DPolyobjInterpolation::Destroy() void DPolyobjInterpolation::UpdateInterpolation() { - for(int i = 0; i < poly->numvertices; i++) + for(unsigned int i = 0; i < poly->Vertices.Size(); i++) { - oldverts[i*2 ] = poly->vertices[i]->x; - oldverts[i*2+1] = poly->vertices[i]->y; + oldverts[i*2 ] = poly->Vertices[i]->x; + oldverts[i*2+1] = poly->Vertices[i]->y; } + oldcx = poly->CenterSpot.x; + oldcy = poly->CenterSpot.y; } //========================================================================== @@ -770,12 +776,14 @@ void DPolyobjInterpolation::UpdateInterpolation() void DPolyobjInterpolation::Restore() { - for(int i = 0; i < poly->numvertices; i++) + for(unsigned int i = 0; i < poly->Vertices.Size(); i++) { - poly->vertices[i]->x = bakverts[i*2 ]; - poly->vertices[i]->y = bakverts[i*2+1]; + poly->Vertices[i]->x = bakverts[i*2 ]; + poly->Vertices[i]->y = bakverts[i*2+1]; } - //poly->Moved(); + poly->CenterSpot.x = bakcx; + poly->CenterSpot.y = bakcy; + poly->ClearSubsectorLinks(); } //========================================================================== @@ -786,10 +794,10 @@ void DPolyobjInterpolation::Restore() void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) { - for(int i = 0; i < poly->numvertices; i++) + for(unsigned int i = 0; i < poly->Vertices.Size(); i++) { - fixed_t *px = &poly->vertices[i]->x; - fixed_t *py = &poly->vertices[i]->y; + fixed_t *px = &poly->Vertices[i]->x; + fixed_t *py = &poly->Vertices[i]->y; bakverts[i*2 ] = *px; bakverts[i*2+1] = *py; @@ -797,7 +805,12 @@ void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) *px = oldverts[i*2 ] + FixedMul(bakverts[i*2 ] - oldverts[i*2 ], smoothratio); *py = oldverts[i*2+1] + FixedMul(bakverts[i*2+1] - oldverts[i*2+1], smoothratio); } - //poly->Moved(); + bakcx = poly->CenterSpot.x; + bakcy = poly->CenterSpot.y; + poly->CenterSpot.x = bakcx + FixedMul(bakcx - oldcx, smoothratio); + poly->CenterSpot.y = bakcy + FixedMul(bakcy - oldcy, smoothratio); + + poly->ClearSubsectorLinks(); } //========================================================================== @@ -808,11 +821,21 @@ void DPolyobjInterpolation::Interpolate(fixed_t smoothratio) void DPolyobjInterpolation::Serialize(FArchive &arc) { - Super::Serialize(arc); int po = int(poly - polyobjs); arc << po << oldverts; poly = polyobjs + po; + + if (SaveVersion >= 2448) + { + arc << oldcx << oldcy; + } + else + { + // This will glitch if an old savegame is loaded but at least it'll allow loading it. + oldcx = poly->CenterSpot.x; + oldcy = poly->CenterSpot.y; + } if (arc.IsLoading()) bakverts.Resize(oldverts.Size()); } diff --git a/src/r_main.cpp b/src/r_main.cpp index ebc6720dd..ccc15e477 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -50,6 +50,7 @@ #include "r_bsp.h" #include "r_plane.h" #include "v_palette.h" +#include "po_man.h" // MACROS ------------------------------------------------------------------ @@ -1488,6 +1489,8 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) { camera->renderflags |= RF_INVISIBLE; } + // Link the polyobjects right before drawing the scene to reduce the amounts of calls to this function + PO_LinkToSubsectors(); if (r_polymost < 2) { R_RenderBSPNode (nodes + numnodes - 1); // The head node is the last node output. diff --git a/src/r_polymost.cpp b/src/r_polymost.cpp index f5f82950a..3c9157d1b 100644 --- a/src/r_polymost.cpp +++ b/src/r_polymost.cpp @@ -1471,6 +1471,7 @@ void RP_Subsector (subsector_t *sub) // R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide); // } +#if 0 if (sub->poly) { // Render the polyobj in the subsector first int polyCount = sub->poly->numsegs; @@ -1480,6 +1481,7 @@ void RP_Subsector (subsector_t *sub) RP_AddLine (*polySeg++); } } +#endif while (count--) { diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 381a27866..19076055e 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -22,6 +22,7 @@ #include "i_system.h" #include "cmdlib.h" #include "p_local.h" +#include "po_man.h" #include "gi.h" #include "templates.h" #include "c_dispatch.h" diff --git a/src/s_sound.cpp b/src/s_sound.cpp index c31e2f7ac..40be1b927 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -49,6 +49,7 @@ #include "templates.h" #include "timidity/timidity.h" #include "g_level.h" +#include "po_man.h" // MACROS ------------------------------------------------------------------ @@ -795,11 +796,11 @@ static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fix static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z) { - seg_t *seg; + side_t *side; sector_t *sec; - PO_ClosestPoint(poly, *x, *y, *x, *y, &seg); - sec = seg->frontsector; + poly->ClosestPoint(*x, *y, *x, *y, &side); + sec = side->sector; *z = clamp(*z, sec->floorplane.ZatPoint(*x, *y), sec->ceilingplane.ZatPoint(*x, *y)); } diff --git a/src/tarray.h b/src/tarray.h index 09d092e00..9ee5eff2b 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -129,6 +129,12 @@ public: { return Array[index]; } + // Returns a reference to the last element + T &Last() const + { + return Array[Count-1]; + } + unsigned int Push (const T &item) { Grow (1); diff --git a/zdoom.vcproj b/zdoom.vcproj index 684eba0b3..190b09e0c 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + @@ -1626,6 +1630,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -1868,14 +1880,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -2065,14 +2069,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -2083,6 +2079,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + - - - + + + - - - @@ -5383,6 +5379,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -5661,7 +5665,7 @@ /> Date: Fri, 23 Jul 2010 21:19:59 +0000 Subject: [PATCH 117/251] - added Firebrand's patch to rename 'swap' due to naming conflicts in newer MSVC compilers. SVN r2449 (trunk) --- src/d_dehacked.cpp | 4 ++-- src/dobjtype.cpp | 2 +- src/nodebuild.cpp | 2 +- src/p_acs.cpp | 6 +++--- src/p_enemy.cpp | 4 ++-- src/p_setup.cpp | 4 ++-- src/p_switch.cpp | 2 +- src/r_anim.cpp | 4 ++-- src/r_bsp.cpp | 6 +++--- src/r_drawt.cpp | 6 +++--- src/r_main.cpp | 2 +- src/r_polymost.cpp | 2 +- src/r_segs.cpp | 10 +++++----- src/r_things.cpp | 2 +- src/r_translate.cpp | 6 +++--- src/s_playlist.cpp | 2 +- src/templates.h | 4 ++-- src/textures/texture.cpp | 6 +++--- src/thingdef/thingdef_expression.cpp | 4 ++-- src/thingdef/thingdef_properties.cpp | 2 +- src/timidity/instrum_sf2.cpp | 4 ++-- src/v_draw.cpp | 2 +- src/v_palette.cpp | 2 +- src/win32/fb_d3d9.cpp | 4 ++-- src/win32/fb_d3d9_wipe.cpp | 2 +- src/win32/fb_ddraw.cpp | 2 +- src/win32/i_dijoy.cpp | 2 +- src/win32/i_system.cpp | 2 +- 28 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 2578f1a60..f896e6988 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2109,13 +2109,13 @@ static int PatchText (int oldSize) // This must be done because the map is scanned using a binary search. while (i > 0 && strncmp (DehSpriteMappings[i-1].Sprite, newStr, 4) > 0) { - swap (DehSpriteMappings[i-1], DehSpriteMappings[i]); + swapvalues (DehSpriteMappings[i-1], DehSpriteMappings[i]); --i; } while ((size_t)i < countof(DehSpriteMappings)-1 && strncmp (DehSpriteMappings[i+1].Sprite, newStr, 4) < 0) { - swap (DehSpriteMappings[i+1], DehSpriteMappings[i]); + swapvalues (DehSpriteMappings[i+1], DehSpriteMappings[i]); ++i; } break; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index a51e8ad0c..cdac25902 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -68,7 +68,7 @@ void PClass::StaticInit () // MinGW's linker is linking the object files backwards for me now... if (head > tail) { - swap (head, tail); + swapvalues (head, tail); } qsort (head + 1, tail - head - 1, sizeof(REGINFO), cregcmp); diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 345c42de8..bbf281b95 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -371,7 +371,7 @@ bool FNodeBuilder::CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD { if (Segs[seg2].linedef == -1) { // Do not put minisegs into a new subsector. - swap (seg1, seg2); + swapvalues (seg1, seg2); } D(Printf(PRINT_LOG, "Need to synthesize a splitter for set %d on seg %d (ov)\n", set, seg2)); splitseg = DWORD_MAX; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index eb69c60be..03f3f9649 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1487,7 +1487,7 @@ void FBehavior::LoadScriptsDirectory () // Make the closed version the first one. if (Scripts[i+1].Type == SCRIPT_Closed) { - swap(Scripts[i], Scripts[i+1]); + swapvalues(Scripts[i], Scripts[i+1]); } } } @@ -2051,7 +2051,7 @@ int DLevelScript::Random (int min, int max) { if (max < min) { - swap (max, min); + swapvalues (max, min); } return min + pr_acs(max - min + 1); @@ -3550,7 +3550,7 @@ int DLevelScript::RunScript () break; case PCD_SWAP: - swap(Stack[sp-2], Stack[sp-1]); + swapvalues(Stack[sp-2], Stack[sp-1]); break; case PCD_LSPEC1: diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index d3ddd8ddd..e982ea0d0 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -679,7 +679,7 @@ void P_DoNewChaseDir (AActor *actor, fixed_t deltax, fixed_t deltay) { if ((pr_newchasedir() > 200 || abs(deltay) > abs(deltax))) { - swap (d[1], d[2]); + swapvalues (d[1], d[2]); } if (d[1] == turnaround) @@ -997,7 +997,7 @@ void P_RandomChaseDir (AActor *actor) // try other directions if (pr_newchasedir() > 200 || abs(deltay) > abs(deltax)) { - swap (d[1], d[2]); + swapvalues (d[1], d[2]); } if (d[1] == turnaround) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 4b411fb26..8ade6cb13 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2631,7 +2631,7 @@ static void P_CreateBlockMap () { if (bx > bx2) { - swap (block, endblock); + swapvalues (block, endblock); } do { @@ -2643,7 +2643,7 @@ static void P_CreateBlockMap () { if (by > by2) { - swap (block, endblock); + swapvalues (block, endblock); } do { diff --git a/src/p_switch.cpp b/src/p_switch.cpp index b7eeb784d..423633585 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -354,7 +354,7 @@ FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad) max = sc.Number & 65535; if (min > max) { - swap (min, max); + swapvalues (min, max); } thisframe.Time = ((max - min + 1) << 16) | min; } diff --git a/src/r_anim.cpp b/src/r_anim.cpp index 7daeafd83..cac361866 100644 --- a/src/r_anim.cpp +++ b/src/r_anim.cpp @@ -202,7 +202,7 @@ void R_InitPicAnims (void) // [RH] Allow for backward animations as well as forward. if (pic1 > pic2) { - swap (pic1, pic2); + swapvalues (pic1, pic2); animtype = FAnimDef::ANIM_Backward; } @@ -548,7 +548,7 @@ static void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool m { type = FAnimDef::ANIM_Backward; TexMan[framenum]->bNoDecals = TexMan[picnum]->bNoDecals; - swap (framenum, picnum); + swapvalues (framenum, picnum); } if (sc.GetString()) { diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index da2eee749..5ba65cdd6 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -574,7 +574,7 @@ void R_AddLine (seg_t *line) int t = 256-WallTX1; WallTX1 = 256-WallTX2; WallTX2 = t; - swap (WallTY1, WallTY2); + swapvalues (WallTY1, WallTY2); } if (WallTX1 >= -WallTY1) @@ -651,7 +651,7 @@ void R_AddLine (seg_t *line) { // The seg is only part of the wall. if (line->linedef->sidedef[0] != line->sidedef) { - swap (v1, v2); + swapvalues (v1, v2); } tx1 = v1->x - viewx; tx2 = v2->x - viewx; @@ -901,7 +901,7 @@ static bool R_CheckBBox (fixed_t *bspcoord) // killough 1/28/98: static int t = 256-rx1; rx1 = 256-rx2; rx2 = t; - swap (ry1, ry2); + swapvalues (ry1, ry2); } if (rx1 >= -ry1) diff --git a/src/r_drawt.cpp b/src/r_drawt.cpp index 671a977ec..fbfaf6307 100644 --- a/src/r_drawt.cpp +++ b/src/r_drawt.cpp @@ -1131,7 +1131,7 @@ void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *span) if (sprflipvert) { - swap (dc_yl, dc_yh); + swapvalues (dc_yl, dc_yh); } if (dc_yh >= mfloorclip[dc_x]) @@ -1205,8 +1205,8 @@ nextpost: // instead of bottom-to-top. while (front < back) { - swap (front[0], back[0]); - swap (front[1], back[1]); + swapvalues (front[0], back[0]); + swapvalues (front[1], back[1]); front += 2; back -= 2; } diff --git a/src/r_main.cpp b/src/r_main.cpp index ccc15e477..cbacb93a5 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -377,7 +377,7 @@ fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy) if (dy > dx) { - swap (dx, dy); + swapvalues (dx, dy); } return FixedDiv (dx, finecosine[tantoangle[FixedDiv (dy, dx) >> DBITS] >> ANGLETOFINESHIFT]); diff --git a/src/r_polymost.cpp b/src/r_polymost.cpp index 3c9157d1b..663c8ae61 100644 --- a/src/r_polymost.cpp +++ b/src/r_polymost.cpp @@ -1204,7 +1204,7 @@ void RP_AddLine (seg_t *line) { // The seg is only part of the wall. if (line->linedef->sidedef[0] != line->sidedef) { - swap (v1, v2); + swapvalues (v1, v2); } tx1 = v1->x - viewx; tx2 = v2->x - viewx; diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 88c918db2..d1983342f 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2302,7 +2302,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, int t = 256-WallTX1; WallTX1 = 256-WallTX2; WallTX2 = t; - swap (WallTY1, WallTY2); + swapvalues (WallTY1, WallTY2); } if (WallTX1 >= -WallTY1) @@ -2433,11 +2433,11 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, goto done; } - swap (x1, WallSX1); - swap (x2, WallSX2); + swapvalues (x1, WallSX1); + swapvalues (x2, WallSX2); PrepWall (swall, lwall, WallSpriteTile->GetWidth() << FRACBITS); - swap (x1, WallSX1); - swap (x2, WallSX2); + swapvalues (x1, WallSX1); + swapvalues (x2, WallSX2); if (flipx) { diff --git a/src/r_things.cpp b/src/r_things.cpp index 1750b3095..600354ced 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1020,7 +1020,7 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span) if (sprflipvert) { - swap (dc_yl, dc_yh); + swapvalues (dc_yl, dc_yh); } if (dc_yh >= mfloorclip[dc_x]) diff --git a/src/r_translate.cpp b/src/r_translate.cpp index d5ef79a1f..eef8c1c1b 100644 --- a/src/r_translate.cpp +++ b/src/r_translate.cpp @@ -312,8 +312,8 @@ void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) if (start > end) { - swap (start, end); - swap (pal1, pal2); + swapvalues (start, end); + swapvalues (pal1, pal2); } else if (start == end) { @@ -354,7 +354,7 @@ void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, in if (start > end) { - swap (start, end); + swapvalues (start, end); r = r2; g = g2; b = b2; diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index e7170eaa8..ce82a8182 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -162,7 +162,7 @@ void FPlayList::Shuffle () for (i = 0; i < numsongs; ++i) { - swap (Songs[i], Songs[(rand() % (numsongs - i)) + i]); + swapvalues (Songs[i], Songs[(rand() % (numsongs - i)) + i]); } Position = 0; } diff --git a/src/templates.h b/src/templates.h index c3037456a..002bdeb3b 100644 --- a/src/templates.h +++ b/src/templates.h @@ -195,14 +195,14 @@ T clamp (const T in, const T min, const T max) //========================================================================== // -// swap +// swapvalues // // Swaps the values of a and b. //========================================================================== template inline -void swap (T &a, T &b) +void swapvalues (T &a, T &b) { T temp = a; a = b; b = temp; } diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 234d447c4..576c30de9 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -366,12 +366,12 @@ void FTexture::FlipSquareBlock (BYTE *block, int x, int y) if (count & 1) { count--; - swap (corner[count], corner[count*x]); + swapvalues (corner[count], corner[count*x]); } for (j = 0; j < count; j += 2) { - swap (corner[j], corner[j*x]); - swap (corner[j+1], corner[(j+1)*x]); + swapvalues (corner[j], corner[j*x]); + swapvalues (corner[j+1], corner[(j+1)*x]); } } } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2511b93a8..9440a05b0 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1667,7 +1667,7 @@ ExpVal FxRandom::EvalExpression (AActor *self) if (maxval < minval) { - swap (maxval, minval); + swapvalues (maxval, minval); } val.Int = (*rng)(maxval - minval + 1) + minval; @@ -1714,7 +1714,7 @@ ExpVal FxFRandom::EvalExpression (AActor *self) if (maxval < minval) { - swap (maxval, minval); + swapvalues (maxval, minval); } val.Float = frandom * (maxval - minval) + minval; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index db620c5c7..0452cb951 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1861,7 +1861,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) PROP_INT_PARM(end, 1); if (start > end) - swap (start, end); + swapvalues (start, end); info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); } diff --git a/src/timidity/instrum_sf2.cpp b/src/timidity/instrum_sf2.cpp index 5064c9fe1..a455bbdee 100644 --- a/src/timidity/instrum_sf2.cpp +++ b/src/timidity/instrum_sf2.cpp @@ -1035,11 +1035,11 @@ void SFFile::CheckZones(int start, int stop, bool instr) // Check for swapped ranges. (Should we fix them or ignore them?) if (bag[i].KeyRange.Lo > bag[i].KeyRange.Hi) { - swap(bag[i].KeyRange.Lo, bag[i].KeyRange.Hi); + swapvalues(bag[i].KeyRange.Lo, bag[i].KeyRange.Hi); } if (bag[i].VelRange.Lo > bag[i].VelRange.Hi) { - swap(bag[i].VelRange.Lo, bag[i].VelRange.Hi); + swapvalues(bag[i].VelRange.Lo, bag[i].VelRange.Hi); } } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 42b0b5145..3c2ed74d0 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -919,7 +919,7 @@ void DCanvas::DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 real { // horizontal line if (x0 > x1) { - swap (x0, x1); + swapvalues (x0, x1); } memset (GetBuffer() + y0*GetPitch() + x0, palColor, deltaX+1); } diff --git a/src/v_palette.cpp b/src/v_palette.cpp index 231e160c0..3149f5df5 100644 --- a/src/v_palette.cpp +++ b/src/v_palette.cpp @@ -224,7 +224,7 @@ void FPalette::MakeGoodRemap () if (new0 > dup) { // Make the lower-numbered entry a copy of color 0. (Just because.) - swap (new0, dup); + swapvalues (new0, dup); } Remap[0] = new0; Remap[new0] = dup; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 02da9910f..922c63a29 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -2967,7 +2967,7 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, double x, double y, uint32 t if (parms.flipX) { - swap(u0, u1); + swapvalues(u0, u1); } if (parms.windowleft > 0 || parms.windowright < parms.texwidth) { @@ -3640,7 +3640,7 @@ bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR & if (quad.Flags & BQF_InvertSource) { quad.Flags &= ~BQF_InvertSource; - swap(start, end); + swapvalues(start, end); } quad.ShaderNum = BQS_SpecialColormap; color0 = D3DCOLOR_RGBA(DWORD(start[0]/2*255), DWORD(start[1]/2*255), DWORD(start[2]/2*255), color0 >> 24); diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp index 9a3b34412..9024fa804 100644 --- a/src/win32/fb_d3d9_wipe.cpp +++ b/src/win32/fb_d3d9_wipe.cpp @@ -231,7 +231,7 @@ void D3DFB::WipeEndScreen() // waste time copying from TempRenderTexture to FinalWipeScreen. if (FinalWipeScreen != TempRenderTexture) { - swap(RenderTexture[CurrRenderTexture], FinalWipeScreen); + swapvalues(RenderTexture[CurrRenderTexture], FinalWipeScreen); TempRenderTexture = RenderTexture[CurrRenderTexture]; } diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp index e440bd7f1..3a9b3d35e 100644 --- a/src/win32/fb_ddraw.cpp +++ b/src/win32/fb_ddraw.cpp @@ -774,7 +774,7 @@ void DDrawFB::RebuildColorTable () for (i = 0; i < 256; i++) { - swap (syspal[i].peRed, syspal[i].peBlue); + swapvalues (syspal[i].peRed, syspal[i].peBlue); } for (i = 0; i < 256; i++) { diff --git a/src/win32/i_dijoy.cpp b/src/win32/i_dijoy.cpp index e21f77e25..89ddd1600 100644 --- a/src/win32/i_dijoy.cpp +++ b/src/win32/i_dijoy.cpp @@ -629,7 +629,7 @@ bool FDInputJoystick::ReorderAxisPair(const GUID &xid, const GUID &yid, int pos) } if (x == pos + 1 && y == pos) { // Xbox 360 Controllers return them in this order. - swap(Axes[pos], Axes[pos + 1]); + swapvalues(Axes[pos], Axes[pos + 1]); } else if (x != pos || y != pos + 1) { diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 04e2694d6..c8b496656 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -997,7 +997,7 @@ void I_PrintStr(const char *cp) if (edit != NULL) { // GDI uses BGR colors, but color is RGB, so swap the R and the B. - swap(color.r, color.b); + swapvalues(color.r, color.b); // Change the color. format.cbSize = sizeof(format); format.dwMask = CFM_COLOR; From f430881a54eef2627f3024046e672b6e89a7f8b7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Jul 2010 21:36:17 +0000 Subject: [PATCH 118/251] - Added DavidPH's Poison damage extension but changed it so that the metadata can be removed. SVN r2450 (trunk) --- src/actor.h | 12 +++++++++++- src/p_interaction.cpp | 28 ++++++++++++++++++++++++++++ src/p_local.h | 1 + src/p_map.cpp | 25 +++++++++++++++++++++++++ src/p_mobj.cpp | 23 ++++++++++++++++++++--- src/thingdef/thingdef_data.cpp | 2 ++ src/thingdef/thingdef_properties.cpp | 22 +++++++++++++++++++--- 7 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/actor.h b/src/actor.h index 6e0c625f1..9ae11696b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -320,6 +320,8 @@ enum MF6_SHATTERING = 0x00020000, // marks an ice corpse for forced shattering MF6_KILLED = 0x00040000, // Something that was killed (but not necessarily a corpse) MF6_BLOCKEDBYSOLIDACTORS = 0x00080000, // Blocked by solid actors, even if not solid itself + MF6_ADDITIVEPOISONDAMAGE = 0x00100000, + MF6_ADDITIVEPOISONDURATION = 0x00200000, // --- mobj.renderflags --- @@ -505,7 +507,6 @@ enum AMETA_BloodColor, // colorized blood AMETA_GibHealth, // negative health below which this monster dies an extreme death AMETA_WoundHealth, // health needed to enter wound state - AMETA_PoisonDamage, // Amount of poison damage AMETA_FastSpeed, // Speed in fast mode AMETA_RDFactor, // Radius damage factor AMETA_CameraHeight, // Height of camera when used as such @@ -843,6 +844,15 @@ public: AActor *BlockingMobj; // Actor that blocked the last move line_t *BlockingLine; // Line that blocked the last move + int PoisonDamage; // Damage received per tic from poison. + int PoisonDuration; // Duration left for receiving poison damage. + int PoisonPeriod; // How often poison damage is applied. (Every X tics.) + + int PoisonDamageReceived; // Damage received per tic from poison. + int PoisonDurationReceived; // Duration left for receiving poison damage. + int PoisonPeriodReceived; // How often poison damage is applied. (Every X tics.) + TObjPtr Poisoner; // Last source of received poison damage. + // a linked list of sectors where this object appears struct msecnode_t *touching_sectorlist; // phares 3/14/98 diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 7dfd7398f..d4db86436 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1369,6 +1369,34 @@ dopain: target->flags |= MF_JUSTHIT; // fight back! } +void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period) +{ + int olddamage = target->PoisonDamageReceived; + int oldduration = target->PoisonDurationReceived; + + target->Poisoner = source; + + if (inflictor->flags6 & MF6_ADDITIVEPOISONDAMAGE) + { + target->PoisonDamageReceived += damage; + } + else + { + target->PoisonDamageReceived = damage; + } + + if (inflictor->flags6 & MF6_ADDITIVEPOISONDURATION) + { + target->PoisonDurationReceived += duration; + } + else + { + target->PoisonDurationReceived = duration; + } + + target->PoisonPeriodReceived = period; +} + bool AActor::OkayToSwitchTarget (AActor *other) { if (other == this) diff --git a/src/p_local.h b/src/p_local.h index 387089f68..a69f2549d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -480,6 +480,7 @@ extern FBlockNode** blocklinks; // for thing chains // void P_TouchSpecialThing (AActor *special, AActor *toucher); void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); +void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period); bool P_GiveBody (AActor *actor, int num); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); diff --git a/src/p_map.cpp b/src/p_map.cpp index 34f396317..3ee9b15f2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1088,6 +1088,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) P_RipperBlood (tm.thing, thing); } S_Sound (tm.thing, CHAN_BODY, "misc/ripslop", 1, ATTN_IDLE); + + // Do poisoning (if using new style poison) + if (tm.thing->PoisonDuration != INT_MIN) + { + P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod); + } + damage = tm.thing->GetMissileDamage (3, 2); P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) @@ -1109,6 +1116,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) return true; } } + + // Do poisoning (if using new style poison) + if (tm.thing->PoisonDuration != INT_MIN) + { + P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod); + } + // Do damage damage = tm.thing->GetMissileDamage ((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN)) @@ -3471,6 +3485,13 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, trace.Actor, srcangle, srcpitch); } } + + // Allow puffs to inflict poison damage, so that hitscans can poison, too. + if (puffDefaults->PoisonDuration != INT_MIN) + { + P_PoisonMobj(trace.Actor, puff ? puff : t1, t1, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod); + } + // [GZ] If MF6_FORCEPAIN is set, we need to call P_DamageMobj even if damage is 0! // Note: The puff may not yet be spawned here so we must check the class defaults, not the actor. if (damage || (puffDefaults->flags6 & MF6_FORCEPAIN)) @@ -3840,6 +3861,10 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color P_TraceBleed (damage, x, y, z, RailHits[i].HitActor, source->angle, pitch); } if (spawnpuff) P_SpawnPuff (source, puffclass, x, y, z, source->angle - ANG90, 1, PF_HITTHING); + + if (puffDefaults && puffDefaults->PoisonDuration != INT_MIN) + P_PoisonMobj(RailHits[i].HitActor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod); + P_DamageMobj (RailHits[i].HitActor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6fd05c040..9c1e195ee 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -346,6 +346,11 @@ void AActor::Serialize (FArchive &arc) WeaveIndexZ = 0; } } + if (SaveVersion >= 2450) + { + arc << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner; + arc << PoisonDamage << PoisonDuration << PoisonPeriod; + } // Skip past uservar array in old savegames if (SaveVersion < 1933) @@ -3314,6 +3319,18 @@ void AActor::Tick () { return; } + + // Check for poison damage, but only once per PoisonPeriod tics (or once per second if none). + if (PoisonDurationReceived && (level.time % (PoisonPeriodReceived ? PoisonPeriodReceived : TICRATE) == 0)) + { + P_DamageMobj(this, NULL, Poisoner, PoisonDamageReceived, NAME_Poison, 0); + + --PoisonDurationReceived; + + // Must clear damage when duration is done, otherwise it + // could be added to with ADDITIVEPOISONDAMAGE. + if (!PoisonDurationReceived) PoisonDamageReceived = 0; + } } // cycle through states, calling action functions at transitions @@ -5444,10 +5461,10 @@ int AActor::DoSpecialDamage (AActor *target, int damage) { if (target->player) { - int poisondamage = GetClass()->Meta.GetMetaInt(AMETA_PoisonDamage); - if (poisondamage > 0) + // Only do this for old style poison damage. + if (PoisonDamage > 0 && PoisonDuration == INT_MIN) { - P_PoisonPlayer (target->player, this, this->target, poisondamage); + P_PoisonPlayer (target->player, this, this->target, PoisonDamage); damage >>= 1; } } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 7ebb680d8..b08e48719 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -224,6 +224,8 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF6, JUMPDOWN, AActor, flags6), DEFINE_FLAG(MF6, VULNERABLE, AActor, flags6), DEFINE_FLAG(MF6, NOTRIGGER, AActor, flags6), + DEFINE_FLAG(MF6, ADDITIVEPOISONDAMAGE, AActor, flags6), + DEFINE_FLAG(MF6, ADDITIVEPOISONDURATION, AActor, flags6), DEFINE_FLAG(MF6, BLOCKEDBYSOLIDACTORS, AActor, flags6), // Effect flags diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 0452cb951..ffe287035 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -999,10 +999,26 @@ DEFINE_PROPERTY(maxdropoffheight, F, Actor) //========================================================================== // //========================================================================== -DEFINE_PROPERTY(poisondamage, I, Actor) +DEFINE_PROPERTY(poisondamage, Iii, Actor) { - PROP_INT_PARM(i, 0); - info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, i); + PROP_INT_PARM(poisondamage, 0); + PROP_INT_PARM(poisonduration, 1); + PROP_INT_PARM(poisonperiod, 2); + + defaults->PoisonDamage = poisondamage; + if (PROP_PARM_COUNT == 1) + { + defaults->PoisonDuration = INT_MIN; + } + else + { + defaults->PoisonDuration = poisonduration; + + if (PROP_PARM_COUNT > 2) + defaults->PoisonPeriod = poisonperiod; + else + defaults->PoisonPeriod = 0; + } } //========================================================================== From bc47f7133b8715b56ed505539b369c5f0bdcb1c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 23 Jul 2010 21:55:01 +0000 Subject: [PATCH 119/251] - Added DavidPH's A_Teleport submission but removed the now redundant GetSpotWithMinDistance functions. SVN r2451 (trunk) --- src/g_heretic/a_dsparil.cpp | 2 +- src/g_shared/a_specialspot.cpp | 14 +++-- src/g_shared/a_specialspot.h | 2 +- src/thingdef/thingdef_codeptr.cpp | 83 ++++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + wadsrc/static/actors/constants.txt | 4 ++ 6 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index b6a8c6a1e..aa0bd46ed 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -139,7 +139,7 @@ void P_DSparilTeleport (AActor *actor) DSpotState *state = DSpotState::GetSpotState(); if (state == NULL) return; - spot = state->GetSpotWithMinDistance(PClass::FindClass("BossSpot"), actor->x, actor->y, 128*FRACUNIT); + spot = state->GetSpotWithMinMaxDistance(PClass::FindClass("BossSpot"), actor->x, actor->y, 128*FRACUNIT, 0); if (spot == NULL) return; prevX = actor->x; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index dbf2cffca..44ee6b848 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -147,14 +147,20 @@ struct FSpotList // //---------------------------------------------------------------------------- - ASpecialSpot *GetSpotWithMinDistance(fixed_t x, fixed_t y, fixed_t distance) + ASpecialSpot *GetSpotWithMinMaxDistance(fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist) { if (Spots.Size() == 0) return NULL; int i = pr_spot() % Spots.Size(); int initial = i; - while (P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y) < distance) + fixed_t distance; + + while (true) { + distance = P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y); + + if ((distance >= mindist) && ((maxdist == 0) || (distance <= maxdist))) break; + i = (i+1) % Spots.Size(); if (i == initial) return NULL; } @@ -329,10 +335,10 @@ ASpecialSpot *DSpotState::GetNextInList(const PClass *type, int skipcounter) // //---------------------------------------------------------------------------- -ASpecialSpot *DSpotState::GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance) +ASpecialSpot *DSpotState::GetSpotWithMinMaxDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist) { FSpotList *list = FindSpotList(type); - if (list != NULL) return list->GetSpotWithMinDistance(x, y, distance); + if (list != NULL) return list->GetSpotWithMinMaxDistance(x, y, mindist, maxdist); return NULL; } diff --git a/src/g_shared/a_specialspot.h b/src/g_shared/a_specialspot.h index ffc083978..21d90f73f 100644 --- a/src/g_shared/a_specialspot.h +++ b/src/g_shared/a_specialspot.h @@ -36,7 +36,7 @@ public: bool RemoveSpot(ASpecialSpot *spot); void Serialize(FArchive &arc); ASpecialSpot *GetNextInList(const PClass *type, int skipcounter); - ASpecialSpot *GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance); + ASpecialSpot *GetSpotWithMinMaxDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t mindist, fixed_t maxdist); ASpecialSpot *GetRandomSpot(const PClass *type, bool onlyonce = false); }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a4977eaa6..406d8d759 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -66,6 +66,7 @@ #include "v_font.h" #include "doomstat.h" #include "v_palette.h" +#include "g_shared/a_specialspot.h" static FRandom pr_camissile ("CustomActorfire"); @@ -81,6 +82,7 @@ static FRandom pr_spawndebris ("SpawnDebris"); static FRandom pr_spawnitemex ("SpawnItemEx"); static FRandom pr_burst ("Burst"); static FRandom pr_monsterrefire ("MonsterRefire"); +static FRandom pr_teleport("Teleport"); //========================================================================== @@ -3194,6 +3196,87 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) ((int *)(reinterpret_cast(self) + var->offset))[pos] = value; } +//=========================================================================== +// +// A_Teleport(optional state teleportstate, optional class targettype, +// optional class fogtype, optional int flags, optional fixed mindist, +// optional fixed maxdist) +// +// Attempts to teleport to a targettype at least mindist away and at most +// maxdist away (0 means unlimited). If successful, spawn a fogtype at old +// location and place calling actor in teleportstate. +// +//=========================================================================== +enum T_Flags +{ + TF_TELEFRAG = 1, // Allow telefrag in order to teleport. + TF_RANDOMDECIDE = 2, // Randomly fail based on health. (A_Srcr2Decide) +}; + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) +{ + ACTION_PARAM_START(6); + ACTION_PARAM_STATE(TeleportState, 0); + ACTION_PARAM_CLASS(TargetType, 1); + ACTION_PARAM_CLASS(FogType, 2); + ACTION_PARAM_INT(Flags, 3); + ACTION_PARAM_FIXED(MinDist, 4); + ACTION_PARAM_FIXED(MaxDist, 5); + + // Randomly choose not to teleport like A_Srcr2Decide. + if (Flags & TF_RANDOMDECIDE) + { + static const int chance[] = + { + 192, 120, 120, 120, 64, 64, 32, 16, 0 + }; + + unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8); + + if (chanceindex >= countof(chance)) + { + chanceindex = countof(chance) - 1; + } + + if (pr_teleport() >= chance[chanceindex]) return; + } + + if (TeleportState == NULL) + { + // Default to Teleport. + TeleportState = self->FindState("Teleport"); + // If still nothing, then return. + if (!TeleportState) return; + } + + DSpotState *state = DSpotState::GetSpotState(); + if (state == NULL) return; + + if (!TargetType) TargetType = PClass::FindClass("BossSpot"); + + AActor * spot = state->GetSpotWithMinMaxDistance(TargetType, self->x, self->y, MinDist, MaxDist); + if (spot == NULL) return; + + fixed_t prevX = self->x; + fixed_t prevY = self->y; + fixed_t prevZ = self->z; + if (P_TeleportMove (self, spot->x, spot->y, spot->z, Flags & TF_TELEFRAG)) + { + ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + + if (FogType) + { + Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + } + + ACTION_JUMP(TeleportState); + + self->z = self->floorz; + self->angle = spot->angle; + self->velx = self->vely = self->velz = 0; + } +} + //=========================================================================== // // A_Turn diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index ec6e0cea0..b6ef92265 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -224,6 +224,7 @@ ACTOR Actor native //: Thinker action native A_CheckCeiling(state label); action native A_PlayerSkinCheck(state label); action native A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); + action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 128, float maxdist = 0); action native A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); action native A_Weave(int xspeed, int yspeed, float xdist, float ydist); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 6c027d82a..f03ad34a6 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -95,6 +95,10 @@ const int CPF_USEAMMO = 1; const int CPF_DAGGER = 2; const int CPF_PULLIN = 4; +// Flags for A_Teleport +const int TF_TELEFRAG = 1; +const int TF_RANDOMDECIDE = 2; + // Activation flags enum { From 58be666c9ce39df72da06902bc8d7e1efd29a0ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Jul 2010 06:15:07 +0000 Subject: [PATCH 120/251] =?UTF-8?q?-=20added=20David=C3=9CH's=20explicit?= =?UTF-8?q?=20angle=20submission=20for=20A=5FCustomBulletAttack=20function?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SVN r2452 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 17 +++++++++++++++-- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 406d8d759..69333c75f 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -825,6 +825,7 @@ enum CBA_Flags { CBAF_AIMFACING = 1, CBAF_NORANDOM = 2, + CBAF_EXPLICITANGLE = 4, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) @@ -856,8 +857,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); for (i=0 ; i Date: Sat, 24 Jul 2010 06:21:53 +0000 Subject: [PATCH 121/251] - added DavidPH's A_Saw extension submission. SVN r2453 (trunk) --- src/g_doom/a_doomweaps.cpp | 74 +++++++++++++++++------ wadsrc/static/actors/constants.txt | 8 +++ wadsrc/static/actors/shared/inventory.txt | 2 +- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 7cd53b49c..515a3015e 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -100,52 +100,88 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol) // // A_Saw // +enum SAW_Flags +{ + SF_NORANDOM = 1, + SF_RANDOMLIGHTMISS = 2, + SF_RANDOMLIGHTHIT = 4, + SF_NOUSEAMMOMISS = 8, + SF_NOUSEAMMO = 16, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) { - angle_t angle; + angle_t angle; + angle_t slope; player_t *player; AActor *linetarget; - ACTION_PARAM_START(4); + ACTION_PARAM_START(9); ACTION_PARAM_SOUND(fullsound, 0); ACTION_PARAM_SOUND(hitsound, 1); ACTION_PARAM_INT(damage, 2); ACTION_PARAM_CLASS(pufftype, 3); - ACTION_PARAM_FIXED(Range, 4) - ACTION_PARAM_FIXED(LifeSteal, 5); + ACTION_PARAM_INT(Flags, 4); + ACTION_PARAM_FIXED(Range, 5); + ACTION_PARAM_ANGLE(Spread_XY, 6); + ACTION_PARAM_ANGLE(Spread_Z, 7); + ACTION_PARAM_FIXED(LifeSteal, 8); if (NULL == (player = self->player)) { return; } + if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); + if (damage == 0) damage = 2; + + if (!(Flags & SF_NORANDOM)) + damage *= (pr_saw()%10+1); + + // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) + if (Range == 0) Range = MELEERANGE+1; + + angle = self->angle + (pr_saw.Random2() * (Spread_XY / 255)); + slope = P_AimLineAttack (self, angle, Range, &linetarget) + (pr_saw.Random2() * (Spread_Z / 255)); + + P_LineAttack (self, angle, Range, + slope, damage, + NAME_None, pufftype); + AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) + if ((weapon != NULL) && !(Flags & SF_NOUSEAMMO) && !(!linetarget && (Flags & SF_NOUSEAMMOMISS))) { if (!weapon->DepleteAmmo (weapon->bAltFire)) return; } - if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff); - if (damage == 0) damage = 2; - - damage *= (pr_saw()%10+1); - angle = self->angle; - angle += pr_saw.Random2() << 18; - - // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) - if (Range == 0) Range = MELEERANGE+1; - - P_LineAttack (self, angle, Range, - P_AimLineAttack (self, angle, Range, &linetarget), damage, - NAME_None, pufftype); - if (!linetarget) { + if ((Flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64)) + { + player->extralight = !player->extralight; + } S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM); return; } + if (Flags & SF_RANDOMLIGHTHIT) + { + int randVal = pr_saw(); + if (randVal < 64) + { + player->extralight = 0; + } + else if (randVal < 160) + { + player->extralight = 1; + } + else + { + player->extralight = 2; + } + } + if (LifeSteal) P_GiveBody (self, (damage * LifeSteal) >> FRACBITS); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index ab2630688..dcf029ca9 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -1,4 +1,12 @@ +// Flags for A_Saw +const int SF_NORANDOM = 1; +const int SF_RANDOMLIGHTMISS = 2; +const int SF_RANDOMLIGHTHIT = 4; +const int SF_RANDOMLIGHTBOTH = 6; +const int SF_NOUSEAMMOMISS = 8; +const int SF_NOUSEAMMO = 16; + // Flags for A_CustomMissile const int CMF_AIMOFFSET = 1; const int CMF_AIMDIRECTION = 2; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 3a4dd20d9..22cd69e6f 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -40,7 +40,7 @@ ACTOR Inventory native action native A_ClearReFire(); action native A_CheckReload(); action native A_GunFlash(state flash = ""); - action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); + action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float spread_xy = 2.8125, float spread_z = 0, float lifesteal = 0); action native A_CheckForReload(int counter, state label, bool dontincrement = false); action native A_ResetReloadCounter(); action native A_RestoreSpecialPosition(); From 37f55c653900ac3ad519f9ae43796e51cf2ee684 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Jul 2010 06:27:13 +0000 Subject: [PATCH 122/251] - added DavidPH's A_RailAttack extension submission. SVN r2454 (trunk) --- src/p_local.h | 2 +- src/p_map.cpp | 14 +++---- src/thingdef/thingdef_codeptr.cpp | 48 +++++++++++++++++++---- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 1 + wadsrc/static/actors/shared/inventory.txt | 2 +- 6 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index a69f2549d..eb69a23c7 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -425,7 +425,7 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version void P_TraceBleed (int damage, AActor *target); // random direction version -void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, const PClass *puff = NULL, bool pierce = true); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, bool silent = false, const PClass *puff = NULL, bool pierce = true, angle_t angleoffset = 0, angle_t pitchoffset = 0); // [RH] Shoot a railgun bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); void P_CheckSplash(AActor *self, fixed_t distance); diff --git a/src/p_map.cpp b/src/p_map.cpp index 3ee9b15f2..b19c04e7b 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3769,7 +3769,7 @@ static bool ProcessNoPierceRailHit (FTraceResults &res) // //========================================================================== -void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, const PClass *puffclass, bool pierce) +void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, bool silent, const PClass *puffclass, bool pierce, angle_t angleoffset, angle_t pitchoffset) { fixed_t vx, vy, vz; angle_t angle, pitch; @@ -3780,8 +3780,8 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color if (puffclass == NULL) puffclass = PClass::FindClass(NAME_BulletPuff); - pitch = (angle_t)(-source->pitch) >> ANGLETOFINESHIFT; - angle = source->angle >> ANGLETOFINESHIFT; + pitch = ((angle_t)(-source->pitch) + pitchoffset) >> ANGLETOFINESHIFT; + angle = (source->angle + angleoffset) >> ANGLETOFINESHIFT; vx = FixedMul (finecosine[pitch], finecosine[angle]); vy = FixedMul (finecosine[pitch], finesine[angle]); @@ -3801,7 +3801,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color shootz += 8*FRACUNIT; } - angle = (source->angle - ANG90) >> ANGLETOFINESHIFT; + angle = ((source->angle + angleoffset) - ANG90) >> ANGLETOFINESHIFT; x1 += offset*finecosine[angle]; y1 += offset*finesine[angle]; @@ -3857,10 +3857,10 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color else { spawnpuff = (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF); - P_SpawnBlood (x, y, z, source->angle - ANG180, damage, RailHits[i].HitActor); + P_SpawnBlood (x, y, z, (source->angle + angleoffset) - ANG180, damage, RailHits[i].HitActor); P_TraceBleed (damage, x, y, z, RailHits[i].HitActor, source->angle, pitch); } - if (spawnpuff) P_SpawnPuff (source, puffclass, x, y, z, source->angle - ANG90, 1, PF_HITTHING); + if (spawnpuff) P_SpawnPuff (source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, PF_HITTHING); if (puffDefaults && puffDefaults->PoisonDuration != INT_MIN) P_PoisonMobj(RailHits[i].HitActor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod); @@ -3874,7 +3874,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color SpawnShootDecal (source, trace); if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - P_SpawnPuff (source, puffclass, trace.X, trace.Y, trace.Z, source->angle - ANG90, 1, 0); + P_SpawnPuff (source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); } } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 69333c75f..d0319a992 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1207,7 +1207,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) enum { RAF_SILENT = 1, - RAF_NOPIERCE = 2 + RAF_NOPIERCE = 2, + RAF_EXPLICITANGLE = 4, }; //========================================================================== @@ -1217,7 +1218,7 @@ enum //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { - ACTION_PARAM_START(8); + ACTION_PARAM_START(10); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_BOOL(UseAmmo, 2); @@ -1225,7 +1226,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) ACTION_PARAM_COLOR(Color2, 4); ACTION_PARAM_INT(Flags, 5); ACTION_PARAM_FLOAT(MaxDiff, 6); - ACTION_PARAM_CLASS(PuffType, 7); + ACTION_PARAM_CLASS(PuffType, 7); + ACTION_PARAM_ANGLE(Spread_XY, 8); + ACTION_PARAM_ANGLE(Spread_Z, 9); if (!self->player) return; @@ -1237,7 +1240,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) if (!weapon->DepleteAmmo(weapon->bAltFire, true)) return; // out of ammo } - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE))); + angle_t angle; + angle_t slope; + + if (Flags & RAF_EXPLICITANGLE) + { + angle = Spread_XY; + slope = Spread_Z; + } + else + { + angle = pr_crailgun.Random2() * (Spread_XY / 255); + slope = pr_crailgun.Random2() * (Spread_Z / 255); + } + + P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angle, slope); } //========================================================================== @@ -1249,12 +1266,13 @@ enum { CRF_DONTAIM = 0, CRF_AIMPARALLEL = 1, - CRF_AIMDIRECT = 2 + CRF_AIMDIRECT = 2, + CRF_EXPLICITANGLE = 4, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { - ACTION_PARAM_START(8); + ACTION_PARAM_START(10); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_COLOR(Color1, 2); @@ -1263,6 +1281,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) ACTION_PARAM_INT(aim, 5); ACTION_PARAM_FLOAT(MaxDiff, 6); ACTION_PARAM_CLASS(PuffType, 7); + ACTION_PARAM_ANGLE(Spread_XY, 8); + ACTION_PARAM_ANGLE(Spread_Z, 9); AActor *linetarget; @@ -1329,7 +1349,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) angle_t angle = (self->angle - ANG90) >> ANGLETOFINESHIFT; - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE))); + angle_t angleoffset; + angle_t slopeoffset; + + if (Flags & CRF_EXPLICITANGLE) + { + angleoffset = Spread_XY; + slopeoffset = Spread_Z; + } + else + { + angleoffset = pr_crailgun.Random2() * (Spread_XY / 255); + slopeoffset = pr_crailgun.Random2() * (Spread_Z / 255); + } + + P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, (Flags & RAF_SILENT), PuffType, (!(Flags & RAF_NOPIERCE)), angleoffset, slopeoffset); self->x = saved_x; self->y = saved_y; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b6ef92265..3f8396ea1 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -185,7 +185,7 @@ ACTOR Actor native //: Thinker action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0); action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0); - action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff"); + action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, bool aim = false, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0); action native A_JumpIfHealthLower(int health, state label); action native A_JumpIfCloser(float distance, state label); action native A_JumpIfTracerCloser(float distance, state label); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index dcf029ca9..27a23fea6 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -84,6 +84,7 @@ const int MRF_UNDOBYDEATHSAVES = 2048; // Flags for A_RailAttack and A_CustomRailgun const int RGF_SILENT = 1; const int RGF_NOPIERCING = 2; +const int RGF_EXPLICITANGLE = 4; // Flags for A_Mushroom const int MSF_Standard = 0; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 22cd69e6f..a61519df0 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -10,7 +10,7 @@ ACTOR Inventory native action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); - action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff"); + action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0); action native A_Light(int extralight); action native A_Light0(); action native A_Light1(); From 2b381babed727d9a757734d3c747fe4920764958 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Jul 2010 06:30:52 +0000 Subject: [PATCH 123/251] - added DavidPH's A_JumpIfTargetInLOS extension submission. SVN r2455 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 108 +++++++++++++++++++++++++---- wadsrc/static/actors/actor.txt | 4 +- wadsrc/static/actors/constants.txt | 9 +++ 3 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d0319a992..36abb056c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2541,23 +2541,38 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) //========================================================================== // -// A_JumpIfTargetInLOS (state label, optional fixed fov, optional bool -// projectiletarget) +// A_JumpIfTargetInLOS (state label, optional fixed fov, optional int flags, +// optional fixed dist_max, optional fixed dist_close) // // Jumps if the actor can see its target, or if the player has a linetarget. // ProjectileTarget affects how projectiles are treated. If set, it will use // the target of the projectile for seekers, and ignore the target for // normal projectiles. If not set, it will use the missile's owner instead -// (the default). +// (the default). ProjectileTarget is now flag JLOSF_PROJECTILE. dist_max +// sets the maximum distance that actor can see, 0 means forever. dist_close +// uses special behavior if certain flags are set, 0 means no checks. // //========================================================================== +enum JLOS_flags +{ + JLOSF_PROJECTILE=1, + JLOSF_NOSIGHT=2, + JLOSF_CLOSENOFOV=4, + JLOSF_CLOSENOSIGHT=8, + JLOSF_CLOSENOJUMP=16, + JLOSF_DEADNOJUMP=32, + JLOSF_CHECKMASTER=64, +}; + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) { - ACTION_PARAM_START(3); + ACTION_PARAM_START(5); ACTION_PARAM_STATE(jump, 0); ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_BOOL(projtarg, 2); + ACTION_PARAM_INT(flags, 2); + ACTION_PARAM_FIXED(dist_max, 3); + ACTION_PARAM_FIXED(dist_close, 4); angle_t an; AActor *target; @@ -2566,7 +2581,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (!self->player) { - if (self->flags & MF_MISSILE && projtarg) + if (flags & JLOSF_CHECKMASTER) + { + target = self->master; + } + else if (self->flags & MF_MISSILE && (flags & JLOSF_PROJECTILE)) { if (self->flags2 & MF2_SEEKERMISSILE) target = self->tracer; @@ -2580,7 +2599,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. - if (!P_CheckSight (self, target, SF_IGNOREVISIBILITY)) + if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; + + fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); + distance = P_AproxDistance(distance, target->z - self->z); + + if (dist_max && (distance > dist_max)) return; + + bool doCheckSight = !(flags & JLOSF_NOSIGHT); + + if (dist_close && (distance < dist_close)) + { + if (flags & JLOSF_CLOSENOJUMP) + return; + + if (flags & JLOSF_CLOSENOFOV) + fov = 0; + + if (flags & JLOSF_CLOSENOSIGHT) + doCheckSight = false; + } + + if (doCheckSight && !P_CheckSight (self, target, SF_IGNOREVISIBILITY)) return; if (fov && (fov < ANGLE_MAX)) @@ -2602,9 +2642,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) { // Does the player aim at something that can be shot? P_BulletSlope(self, &target); - } - if (!target) return; + if (!target) return; + + fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); + distance = P_AproxDistance(distance, target->z - self->z); + + if (dist_max && (distance > dist_max)) return; + + if (dist_close && (distance < dist_close)) + { + if (flags & JLOSF_CLOSENOJUMP) + return; + } + } ACTION_JUMP(jump); } @@ -2612,24 +2663,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) //========================================================================== // -// A_JumpIfInTargetLOS (state label, optional fixed fov, optional bool -// projectiletarget) +// A_JumpIfInTargetLOS (state label, optional fixed fov, optional int flags +// optional fixed dist_max, optional fixed dist_close) // //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) { - ACTION_PARAM_START(3); + ACTION_PARAM_START(5); ACTION_PARAM_STATE(jump, 0); ACTION_PARAM_ANGLE(fov, 1); - ACTION_PARAM_BOOL(projtarg, 2); + ACTION_PARAM_INT(flags, 2); + ACTION_PARAM_FIXED(dist_max, 3); + ACTION_PARAM_FIXED(dist_close, 4); angle_t an; AActor *target; ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (self->flags & MF_MISSILE && projtarg) + if (flags & JLOSF_CHECKMASTER) + { + target = self->master; + } + else if (self->flags & MF_MISSILE && (flags & JLOSF_PROJECTILE)) { if (self->flags2 & MF2_SEEKERMISSILE) target = self->tracer; @@ -2643,7 +2700,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (!target) return; // [KS] Let's not call P_CheckSight unnecessarily in this case. - if (!P_CheckSight (target, self, SF_IGNOREVISIBILITY)) + if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) return; + + fixed_t distance = P_AproxDistance(target->x - self->x, target->y - self->y); + distance = P_AproxDistance(distance, target->z - self->z); + + if (dist_max && (distance > dist_max)) return; + + bool doCheckSight = !(flags & JLOSF_NOSIGHT); + + if (dist_close && (distance < dist_close)) + { + if (flags & JLOSF_CLOSENOJUMP) + return; + + if (flags & JLOSF_CLOSENOFOV) + fov = 0; + + if (flags & JLOSF_CLOSENOSIGHT) + doCheckSight = false; + } + + if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) return; if (fov && (fov < ANGLE_MAX)) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 3f8396ea1..fb0655524 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -246,8 +246,8 @@ ACTOR Actor native //: Thinker action native A_DeQueueCorpse(); action native A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = ""); action native A_ClearTarget(); - action native A_JumpIfTargetInLOS (state label, float fov = 0, bool projectiletarget = false); - action native A_JumpIfInTargetLOS (state label, float fov = 0, bool projectiletarget = false); + action native A_JumpIfTargetInLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); + action native A_JumpIfInTargetLOS (state label, float fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); action native A_DamageMaster(int amount, name damagetype = "none"); action native A_DamageChildren(int amount, name damagetype = "none"); action native A_DamageSiblings(int amount, name damagetype = "none"); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 27a23fea6..cbd91add6 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -56,6 +56,15 @@ const int RSF_FOG = 1; const int RSF_KEEPTARGET = 2; const int RSF_TELEFRAG = 4; +// Flags for A_JumpIfTargetInLOS and A_JumpIfInTargetLOS +const int JLOSF_PROJECTILE = 1; +const int JLOSF_NOSIGHT = 2; +const int JLOSF_CLOSENOFOV = 4; +const int JLOSF_CLOSENOSIGHT = 8; +const int JLOSF_CLOSENOJUMP = 16; +const int JLOSF_DEADNOJUMP = 32; +const int JLOSF_CHECKMASTER = 64; + // Flags for A_ChangeVelocity const int CVF_RELATIVE = 1; const int CVF_REPLACE = 2; From 9ca1de64352b237740979cfb9997ef2b046fae8d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Jul 2010 06:38:57 +0000 Subject: [PATCH 124/251] - added PinkSilver's APROP_MasterTid submission. SVN r2456 (trunk) --- src/p_acs.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 03f3f9649..df3ff8173 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2431,6 +2431,93 @@ void DLevelScript::DoSetFont (int fontnum) } } +int DoSetMaster (AActor *self, AActor *master) +{ + AActor *defs; + if (self->flags3&MF3_ISMONSTER) + { + if (master) + { + if (master->flags3&MF3_ISMONSTER) + { + self->FriendPlayer = 0; + self->master = master; + level.total_monsters -= self->CountsAsKill(); + self->flags = (self->flags & ~MF_FRIENDLY) | (master->flags & MF_FRIENDLY); + level.total_monsters += self->CountsAsKill(); + // Don't attack your new master + if (self->target == self->master) self->target = NULL; + if (self->lastenemy == self->master) self->lastenemy = NULL; + if (self->LastHeard == self->master) self->LastHeard = NULL; + return 1; + } + else if (master->player) + { + // [KS] Be friendly to this player + self->master = NULL; + level.total_monsters -= self->CountsAsKill(); + self->flags|=MF_FRIENDLY; + self->FriendPlayer = int(master->player-players+1); + + AActor * attacker=master->player->attacker; + if (attacker) + { + if (!(attacker->flags&MF_FRIENDLY) || + (deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=self->FriendPlayer)) + { + self->LastHeard = self->target = attacker; + } + } + // And stop attacking him if necessary. + if (self->target == master) self->target = NULL; + if (self->lastenemy == master) self->lastenemy = NULL; + if (self->LastHeard == master) self->LastHeard = NULL; + return 1; + } + } + else + { + self->master = NULL; + self->FriendPlayer = 0; + // Go back to whatever friendliness we usually have... + defs = self->GetDefault(); + level.total_monsters -= self->CountsAsKill(); + self->flags = (self->flags & ~MF_FRIENDLY) | (defs->flags & MF_FRIENDLY); + level.total_monsters += self->CountsAsKill(); + // ...And re-side with our friends. + if (self->target && !self->IsHostile (self->target)) self->target = NULL; + if (self->lastenemy && !self->IsHostile (self->lastenemy)) self->lastenemy = NULL; + if (self->LastHeard && !self->IsHostile (self->LastHeard)) self->LastHeard = NULL; + return 1; + } + } + return 0; +} + +int DoGetMasterTID (AActor *self) +{ + if (self->master) return self->master->tid; + else if (self->FriendPlayer) + { + player_t *player = &players[(self->FriendPlayer)-1]; + return player->mo->tid; + } + else return 0; +} + +static AActor *SingleActorFromTID (int tid, AActor *defactor) +{ + if (tid == 0) + { + return defactor; + } + else + { + FActorIterator iterator (tid); + return iterator.Next(); + } +} + enum { APROP_Health = 0, @@ -2458,6 +2545,7 @@ enum APROP_Score = 22, APROP_Notrigger = 23, APROP_DamageFactor = 24, + APROP_MasterTID = 25, }; // These are needed for ACS's APROP_RenderStyle @@ -2626,25 +2714,18 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) actor->DamageFactor = value; break; + case APROP_MasterTID: + AActor *other; + other = SingleActorFromTID (value, NULL); + DoSetMaster (actor, other); + break; + default: // do nothing. break; } } -static AActor *SingleActorFromTID (int tid, AActor *defactor) -{ - if (tid == 0) - { - return defactor; - } - else - { - FActorIterator iterator (tid); - return iterator.Next(); - } -} - int DLevelScript::GetActorProperty (int tid, int property) { AActor *actor = SingleActorFromTID (tid, activator); @@ -2696,6 +2777,7 @@ int DLevelScript::GetActorProperty (int tid, int property) return 0; } case APROP_Score: return actor->Score; + case APROP_MasterTID: return DoGetMasterTID (actor); default: return 0; } } @@ -2726,6 +2808,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_SpawnHealth: case APROP_JumpZ: case APROP_Score: + case APROP_MasterTID: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value From a373c3858e5ddf5e7da6750c8b6cb63931622a12 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Jul 2010 10:17:16 +0000 Subject: [PATCH 125/251] - fixed: A_Teleport's RNG had the same name as the one used by SelectTeleDest. SVN r2458 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 36abb056c..4330c204c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -82,7 +82,7 @@ static FRandom pr_spawndebris ("SpawnDebris"); static FRandom pr_spawnitemex ("SpawnItemEx"); static FRandom pr_burst ("Burst"); static FRandom pr_monsterrefire ("MonsterRefire"); -static FRandom pr_teleport("Teleport"); +static FRandom pr_teleport("A_Teleport"); //========================================================================== From 006fb343b0e18026fd4f6bce6e407b396ef23445 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 25 Jul 2010 20:46:14 +0000 Subject: [PATCH 126/251] - Added Pink Silver's DrawString/Number alignment patch (with one minor change). SVN r2460 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 68 +++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 9016c2427..a40b8d2a0 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -516,7 +516,7 @@ class CommandDrawString : public SBarInfoCommand CommandDrawString(SBarInfo *script) : SBarInfoCommand(script), shadow(false), shadowX(2), shadowY(2), spacing(0), font(NULL), translation(CR_UNTRANSLATED), cache(-1), strValue(CONSTANT), - valueArgument(0) + valueArgument(0), alignment (ALIGN_RIGHT) { } @@ -587,6 +587,29 @@ class CommandDrawString : public SBarInfoCommand { sc.MustGetToken(TK_IntConst); spacing = sc.Number; + if(sc.CheckToken(',')) //[KS] flags? flags! SIX FLAGS! + { + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("alignment")) + { + sc.MustGetToken('('); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("right")) + alignment = ALIGN_RIGHT; + else if(sc.Compare("left")) + alignment = ALIGN_LEFT; + else if(sc.Compare("center")) + alignment = ALIGN_CENTER; + else + sc.ScriptError("Unknown alignment '%s'.", sc.String); + sc.MustGetToken(')'); + } + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|') && !sc.CheckToken(',')) break; + } + } } sc.MustGetToken(';'); @@ -682,13 +705,33 @@ class CommandDrawString : public SBarInfoCommand } } protected: + enum StringAlignment + { + ALIGN_RIGHT, + ALIGN_LEFT, + ALIGN_CENTER, + }; + void RealignString() { x = startX; - if(script->spacingCharacter == '\0') - x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); - else //monospaced, so just multiplay the character size - x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + switch (alignment) + { + case ALIGN_LEFT: + break; + case ALIGN_RIGHT: + if(script->spacingCharacter == '\0') + x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); + else //monospaced, so just multiplay the character size + x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + break; + case ALIGN_CENTER: + if(script->spacingCharacter == '\0') + x -= static_cast (font->StringWidth(str)+(spacing * str.Len()) / 2); + else + x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len() / 2); + break; + } } enum StringValueType @@ -721,6 +764,7 @@ class CommandDrawString : public SBarInfoCommand StringValueType strValue; int valueArgument; FString str; + StringAlignment alignment; private: void SetStringToTag(AActor *actor) @@ -887,6 +931,20 @@ class CommandDrawNumber : public CommandDrawString interpolationSpeed = sc.Number; sc.MustGetToken(')'); } + else if(sc.Compare("alignment")) + { + sc.MustGetToken('('); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("right")) + alignment = ALIGN_RIGHT; + else if(sc.Compare("left")) + alignment = ALIGN_LEFT; + else if(sc.Compare("center")) + alignment = ALIGN_CENTER; + else + sc.ScriptError("Unknown alignment '%s'.", sc.String); + sc.MustGetToken(')'); + } else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|')) From 1bda16cc454cf1e413583808c73a9ebd716a9cb2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 25 Jul 2010 21:38:34 +0000 Subject: [PATCH 127/251] - Use side_t::RightSide in IterFindPolySides() instead of the SideListHead array. SVN r2461 (trunk) --- src/po_man.cpp | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index f457629fc..6b208825d 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -136,7 +136,7 @@ static void UnLinkPolyobj (FPolyObj *po); static void LinkPolyobj (FPolyObj *po); static bool CheckMobjBlocking (side_t *seg, FPolyObj *po); static void InitBlockMap (void); -static void IterFindPolySides (vertex_t *v1, vertex_t *v2, seg_t **segList); +static void IterFindPolySides (FPolyObj *po, side_t *side); static void SpawnPolyobj (int index, int tag, int type); static void TranslateToStartSpot (int tag, int originX, int originY); static void DoMovePolyobj (FPolyObj *po, int x, int y); @@ -156,7 +156,6 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static SDWORD *SideListHead; // contains numvertexes elements static TArray KnownPolySides; // CODE -------------------------------------------------------------------- @@ -1323,21 +1322,13 @@ static void InitBlockMap (void) static void InitSideLists () { - SDWORD i; - - SideListHead = new SDWORD[numvertexes]; - clearbuf (SideListHead, numvertexes, -1); - - for (i = 0; i < numsides; ++i) + for (int i = 0; i < numsides; ++i) { - if (sides[i].linedef != NULL) + if (sides[i].linedef != NULL && + (sides[i].linedef->special == Polyobj_StartLine || + sides[i].linedef->special == Polyobj_ExplicitLine)) { - SideListHead[sides[i].V1() - vertexes] = i; - if ((sides[i].linedef->special == Polyobj_StartLine || - sides[i].linedef->special == Polyobj_ExplicitLine)) - { - KnownPolySides.Push (i); - } + KnownPolySides.Push (i); } } } @@ -1350,8 +1341,6 @@ static void InitSideLists () static void KillSideLists () { - delete[] SideListHead; - SideListHead = NULL; KnownPolySides.Clear (); KnownPolySides.ShrinkToFit (); } @@ -1375,9 +1364,9 @@ static void IterFindPolySides (FPolyObj *po, side_t *side) for (i = 0; i < numsides; i++) { int v2 = int(side->V2() - vertexes); - j = SideListHead[v2]; + j = side->RightSide; - if (j < 0) + if (j == NO_SIDE) { break; } From 35ba99ed31efc173d2229d2ec4e22249a6d17967 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Jul 2010 21:46:51 +0000 Subject: [PATCH 128/251] - Added Gez's automap enhancements but made the new key icon optional. SVN r2462 (trunk) --- src/am_map.cpp | 104 +++++++++++++++++++++++++++++++--------- src/d_dehacked.cpp | 2 +- src/g_shared/a_keys.cpp | 7 ++- src/m_options.cpp | 6 +++ 4 files changed, 95 insertions(+), 24 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 291a069d8..5883b9472 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -59,6 +59,7 @@ #include "am_map.h" #include "a_artifacts.h" #include "po_man.h" +#include "a_keys.h" struct AMColor { @@ -80,7 +81,7 @@ struct AMColor static AMColor Background, YourColor, WallColor, TSWallColor, FDWallColor, CDWallColor, ThingColor, - ThingColor_Item, ThingColor_Monster, ThingColor_Friend, + ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend, SecretWallColor, GridColor, XHairColor, NotSeenColor, LockedColor, @@ -171,12 +172,15 @@ CVAR (Color, am_secretsectorcolor, 0xff00ff, CVAR_ARCHIVE); CVAR (Color, am_ovsecretsectorcolor,0x00ffff, CVAR_ARCHIVE); CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE); CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE); +CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE); +CVAR (Color, am_thingcolor_citem, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); +CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE); CVAR(Int, am_showsubsector, -1, 0); @@ -297,25 +301,22 @@ mline_t player_arrow[] = { { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; +#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) mline_t player_arrow_raven[] = { - { { -R+R/4, 0 }, { 0, 0} }, // center line. - { { -R+R/4, R/8 }, { R, 0} }, // blade - { { -R+R/4, -R/8 }, { R, 0 } }, - { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece - { { -R+R/8, -R/4 }, { -R+R/8, R/4 } }, - { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors - { { -R+R/8, R/4 }, { -R+R/4, R/4} }, - { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel - { { -R-R/4, R/8 }, { -R+R/8, R/8 } }, - { { -R-R/4, -R/8}, { -R+R/8, -R/8 } } - }; - -#undef R -#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) + { { -R+R/4, 0 }, { 0, 0} }, // center line. + { { -R+R/4, R/8 }, { R, 0} }, // blade + { { -R+R/4, -R/8 }, { R, 0 } }, + { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece + { { -R+R/8, -R/4 }, { -R+R/8, R/4 } }, + { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors + { { -R+R/8, R/4 }, { -R+R/4, R/4} }, + { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel + { { -R-R/4, R/8 }, { -R+R/8, R/8 } }, + { { -R-R/4, -R/8}, { -R+R/8, -R/8 } } +}; #define NUMPLYRLINES_RAVEN (sizeof(player_arrow_raven)/sizeof(mline_t)) -#define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/6 } }, // -----> @@ -334,9 +335,9 @@ mline_t cheat_player_arrow[] = { { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } }; +#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #undef R -#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #define R (MAPUNIT) // [RH] Avoid lots of warnings without compiler-specific #pragmas @@ -353,9 +354,37 @@ mline_t thintriangle_guy[] = { L (1,0, -.5,.7), L (-.5,.7, -.5,-.7) }; +#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) + +mline_t square_guy[] = { + L (0,1,1,0), + L (1,0,0,-1), + L (0,-1,-1,0), + L (-1,0,0,1) +}; +#define NUMSQUAREGUYLINES (sizeof(square_guy)/sizeof(mline_t)) + +#undef R +#define R (MAPUNIT) + +mline_t key_guy[] = { + L (-2, 0, -1.7, -0.5), + L (-1.7, -0.5, -1.5, -0.7), + L (-1.5, -0.7, -0.8, -0.5), + L (-0.8, -0.5, -0.6, 0), + L (-0.6, 0, -0.8, 0.5), + L (-1.5, 0.7, -0.8, 0.5), + L (-1.7, 0.5, -1.5, 0.7), + L (-2, 0, -1.7, 0.5), + L (-0.6, 0, 2, 0), + L (1.7, 0, 1.7, -1), + L (1.5, 0, 1.5, -1), + L (1.3, 0, 1.3, -1) +}; +#define NUMKEYGUYLINES (sizeof(key_guy)/sizeof(mline_t)) + #undef L #undef R -#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) @@ -818,6 +847,7 @@ static void AM_initColors (bool overlayed) SecretWallColor = WallColor; SecretSectorColor.FromCVar (am_ovsecretsectorcolor); ThingColor_Item.FromCVar (am_ovthingcolor_item); + ThingColor_CountItem.FromCVar (am_ovthingcolor_citem); ThingColor_Friend.FromCVar (am_ovthingcolor_friend); ThingColor_Monster.FromCVar (am_ovthingcolor_monster); ThingColor.FromCVar (am_ovthingcolor); @@ -841,6 +871,7 @@ static void AM_initColors (bool overlayed) FDWallColor.FromCVar (am_fdwallcolor); CDWallColor.FromCVar (am_cdwallcolor); ThingColor_Item.FromCVar (am_thingcolor_item); + ThingColor_CountItem.FromCVar (am_thingcolor_citem); ThingColor_Friend.FromCVar (am_thingcolor_friend); ThingColor_Monster.FromCVar (am_thingcolor_monster); ThingColor.FromCVar (am_thingcolor); @@ -2027,11 +2058,40 @@ void AM_drawThings () if (t->flags & MF_FRIENDLY || !(t->flags & MF_COUNTKILL)) color = ThingColor_Friend; else color = ThingColor_Monster; } - else if (t->flags&MF_SPECIAL) color = ThingColor_Item; + else if (t->flags&MF_SPECIAL) + { + // Find the key's own color. + // Only works correctly if single-key locks have lower numbers than any-key locks. + // That is the case for all default keys, however. + if (t->IsKindOf(RUNTIME_CLASS(AKey))) + { + if (am_showkeys) + { + int P_GetMapColorForKey (AInventory * key); + int c = P_GetMapColorForKey(static_cast(t)); - AM_drawLineCharacter - (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, - 16<= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); + else color = ThingColor_CountItem; + AM_drawLineCharacter(key_guy, NUMKEYGUYLINES, 16<flags&MF_COUNTITEM) + color = ThingColor_CountItem; + else + color = ThingColor_Item; + } + + if (color.Index != -1) + { + AM_drawLineCharacter + (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, + 16<= 3) { diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index f896e6988..97c8296a4 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -952,7 +952,7 @@ static int PatchThing (int thingy) // compatibility, the upper bits are freed, but we have conflicts between the ZDoom bits // and the MBF bits. The only such flag exposed to DEHSUPP, though, is STEALTH -- the others // are not available through mnemonics, and aren't available either through their bit value. - // So if we find the STEALTH keyword, it's a ZDoom mod, otherwise assume assume FRIEND. + // So if we find the STEALTH keyword, it's a ZDoom mod, otherwise assume FRIEND. bool zdoomflags = false; char *strval; diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 575d13592..c9139f76b 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -19,7 +19,12 @@ struct OneKey bool check(AActor * owner) { - return !!owner->FindInventory(key); + // P_GetMapColorForKey() checks the key directly + if (owner->IsKindOf (RUNTIME_CLASS(AKey))) + return owner->IsA(key); + // Other calls check an actor that may have a key in its inventory. + else + return !!owner->FindInventory(key); } }; diff --git a/src/m_options.cpp b/src/m_options.cpp index 324b45cc6..ddfd0f897 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -112,6 +112,7 @@ EXTERN_CVAR (Int, crosshair) EXTERN_CVAR (Bool, freelook) EXTERN_CVAR (Int, sv_smartaim) EXTERN_CVAR (Int, am_colorset) +EXTERN_CVAR (Bool, am_showkeys) EXTERN_CVAR (Int, vid_aspect) static void CalcIndent (menu_t *menu); @@ -579,6 +580,7 @@ static menuitem_t AutomapItems[] = { { discrete, "Show total time elapsed", {&am_showtotaltime}, {2.0}, {0.0}, {0.0}, {OnOff} }, { discrete, "Show secrets on map", {&am_map_secrets}, {3.0}, {0.0}, {0.0}, {SecretTypes} }, { discrete, "Draw map background", {&am_drawmapback}, {2.0}, {0.0}, {0.0}, {OnOff} }, + { discrete, "Show keys (cheat)", {&am_showkeys}, {2.0}, {0.0}, {0.0}, {OnOff} }, }; menu_t AutomapMenu = @@ -622,9 +624,11 @@ EXTERN_CVAR (Color, am_ovsecretsectorcolor) EXTERN_CVAR (Color, am_thingcolor_friend) EXTERN_CVAR (Color, am_thingcolor_monster) EXTERN_CVAR (Color, am_thingcolor_item) +EXTERN_CVAR (Color, am_thingcolor_citem) EXTERN_CVAR (Color, am_ovthingcolor_friend) EXTERN_CVAR (Color, am_ovthingcolor_monster) EXTERN_CVAR (Color, am_ovthingcolor_item) +EXTERN_CVAR (Color, am_ovthingcolor_citem) static menuitem_t MapColorsItems[] = { { rsafemore, "Restore default custom colors", {NULL}, {0}, {0}, {0}, {(value_t*)DefaultCustomColors} }, @@ -648,6 +652,7 @@ static menuitem_t MapColorsItems[] = { { colorpicker, "Monsters (for cheat)", {&am_thingcolor_monster}, {0}, {0}, {0}, {0} }, { colorpicker, "Friends (for cheat)", {&am_thingcolor_friend}, {0}, {0}, {0}, {0} }, { colorpicker, "Items (for cheat)", {&am_thingcolor_item}, {0}, {0}, {0}, {0} }, + { colorpicker, "Count Items (for cheat)", {&am_thingcolor_citem}, {0}, {0}, {0}, {0} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {0} }, { colorpicker, "You (overlay)", {&am_ovyourcolor}, {0}, {0}, {0}, {0} }, { colorpicker, "1-sided walls (overlay)", {&am_ovwallcolor}, {0}, {0}, {0}, {0} }, @@ -659,6 +664,7 @@ static menuitem_t MapColorsItems[] = { { colorpicker, "Monsters (overlay) (for cheat)", {&am_ovthingcolor_monster}, {0}, {0}, {0}, {0} }, { colorpicker, "Friends (overlay) (for cheat)", {&am_ovthingcolor_friend}, {0}, {0}, {0}, {0} }, { colorpicker, "Items (overlay) (for cheat)", {&am_ovthingcolor_item}, {0}, {0}, {0}, {0} }, + { colorpicker, "Count Items (overlay) (for cheat)", {&am_ovthingcolor_citem}, {0}, {0}, {0}, {0} }, }; menu_t MapColorsMenu = From 2cf19f436ab8f2cc56d54ddc2771a847b5e81e35 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 26 Jul 2010 17:10:43 +0000 Subject: [PATCH 129/251] - added Gez's dumpactors patch. SVN r2463 (trunk) --- src/dobject.cpp | 27 +++++++++++++++++++++++++++ src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_parse.cpp | 2 ++ 3 files changed, 30 insertions(+) diff --git a/src/dobject.cpp b/src/dobject.cpp index 0ccdd130b..073be864f 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -188,6 +188,33 @@ const char *FMetaTable::GetMetaString (DWORD id) const return meta != NULL ? meta->Value.String : NULL; } +CCMD (dumpactors) +{ + char * filters[32] = + { + "0:All", "1:Doom", "2:Heretic", "3:DoomHeretic", "4:Hexen", "5:DoomHexen", "6:Raven", "7:IdRaven", + "8:Strife", "9:DoomStrife", "10:HereticStrife", "11:DoomHereticStrife", "12:HexenStrife", + "13:DoomHexenStrife", "14:RavenStrife", "15:NotChex", "16:Chex", "17:DoomChex", "18:HereticChex", + "19:DoomHereticChex", "20:HexenChex", "21:DoomHexenChex", "22:RavenChex", "23:NotStrife", "24:StrifeChex", + "25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic", + "30:NotDoom", "31:All", + }; + Printf("%i object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::m_Types.Size()); + for (unsigned int i = 0; i < PClass::m_Types.Size(); i++) + { + PClass *cls = PClass::m_Types[i]; + if (cls != NULL && cls->ActorInfo != NULL) + Printf("%s\t%i\t%i\t%s\t%s\n", + cls->TypeName.GetChars(), cls->ActorInfo->DoomEdNum, + cls->ActorInfo->SpawnID, filters[cls->ActorInfo->GameFilter & 31], + cls->Meta.GetMetaString (ACMETA_Lump)); + else if (cls != NULL) + Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\n", cls->TypeName.GetChars()); + else + Printf("Type %i is not an object class\n", i); + } +} + CCMD (dumpclasses) { // This is by no means speed-optimized. But it's an informational console diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index df4bc78ab..6b2124149 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -230,6 +230,7 @@ enum ACMETA_MeleeDamage, ACMETA_MissileName, ACMETA_MissileHeight, + ACMETA_Lump, }; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 07f4ca4e2..ae236a58c 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -1106,6 +1106,8 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) { FActorInfo *info = CreateNewActor(sc, typeName, parentName, native); info->DoomEdNum = DoomEdNum > 0? DoomEdNum : -1; + info->Class->Meta.SetMetaString (ACMETA_Lump, Wads.GetLumpFullPath(sc.LumpNum)); + SetReplacement(info, replaceName); ResetBaggage (bag, info->Class->ParentClass); From 6f4ed40496afd89778f81234b32131014dff6610 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Jul 2010 18:32:10 +0000 Subject: [PATCH 130/251] - added TIHan's ArmorFactor submission. SVN r2465 (trunk) --- src/g_level.h | 4 +++- src/g_shared/a_armor.cpp | 24 ++++++++++++++++++++++++ src/g_skill.cpp | 13 ++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 701437452..f316491d5 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -548,7 +548,8 @@ enum ESkillProperty SKILLP_ACSReturn, SKILLP_MonsterHealth, SKILLP_FriendlyHealth, - SKILLP_NoPain + SKILLP_NoPain, + SKILLP_ArmorFactor }; int G_SkillProperty(ESkillProperty prop); const char * G_SkillName(); @@ -583,6 +584,7 @@ struct FSkillInfo fixed_t MonsterHealth; fixed_t FriendlyHealth; bool NoPain; + fixed_t ArmorFactor; FSkillInfo() {} FSkillInfo(const FSkillInfo &other) diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 9e43ccfb6..6dd39885d 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -5,6 +5,7 @@ #include "r_data.h" #include "a_pickups.h" #include "templates.h" +#include "g_level.h" IMPLEMENT_CLASS (AArmor) @@ -84,6 +85,18 @@ bool ABasicArmor::HandlePickup (AInventory *item) // You shouldn't be picking up BasicArmor anyway. return true; } + if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorBonus)) && !(item->ItemFlags & IF_IGNORESKILL)) + { + ABasicArmorBonus *armor = static_cast(item); + + armor->SaveAmount = FixedMul(armor->SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); + } + else if (item->IsKindOf(RUNTIME_CLASS(ABasicArmorPickup)) && !(item->ItemFlags & IF_IGNORESKILL)) + { + ABasicArmorPickup *armor = static_cast(item); + + armor->SaveAmount = FixedMul(armor->SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); + } if (Inventory != NULL) { return Inventory->HandlePickup (item); @@ -202,6 +215,12 @@ AInventory *ABasicArmorPickup::CreateCopy (AActor *other) copy->SaveAmount = SaveAmount; copy->MaxAbsorb = MaxAbsorb; copy->MaxFullAbsorb = MaxFullAbsorb; + + if (!(ItemFlags & IF_IGNORESKILL)) + { // extra ammo in baby mode and nightmare mode + SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); + } + return copy; } @@ -279,6 +298,11 @@ AInventory *ABasicArmorBonus::CreateCopy (AActor *other) copy->BonusMax = BonusMax; copy->MaxAbsorb = MaxAbsorb; copy->MaxFullAbsorb = MaxFullAbsorb; + + if (!(ItemFlags & IF_IGNORESKILL)) + { // extra ammo in baby mode and nightmare mode + SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); + } return copy; } diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 424b69a47..cac38563a 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -80,6 +80,7 @@ void FMapInfoParser::ParseSkill () skill.MonsterHealth = FRACUNIT; skill.FriendlyHealth = FRACUNIT; skill.NoPain = false; + skill.ArmorFactor = FRACUNIT; sc.MustGetString(); skill.Name = sc.String; @@ -249,6 +250,12 @@ void FMapInfoParser::ParseSkill () { skill.NoPain = true; } + else if (sc.Compare("ArmorFactor")) + { + ParseAssign(); + sc.MustGetFloat(); + skill.ArmorFactor = FLOAT2FIXED(sc.Float); + } else if (sc.Compare("DefaultSkill")) { if (DefaultSkill >= 0) @@ -357,7 +364,10 @@ int G_SkillProperty(ESkillProperty prop) return AllSkills[gameskill].FriendlyHealth; case SKILLP_NoPain: - return AllSkills[gameskill].NoPain; + return AllSkills[gameskill].NoPain; + + case SKILLP_ArmorFactor: + return AllSkills[gameskill].ArmorFactor; } } return 0; @@ -435,6 +445,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) MonsterHealth = other.MonsterHealth; FriendlyHealth = other.FriendlyHealth; NoPain = other.NoPain; + ArmorFactor = other.ArmorFactor; return *this; } From e1f06da5e31d7f11e9b70b00b3b1606baaac696e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Jul 2010 21:48:24 +0000 Subject: [PATCH 131/251] - separated hitlist generation for texture precaching into a virtual function of DFrameBuffer. SVN r2466 (trunk) --- src/r_data.cpp | 71 +++----------------------------------------- src/v_video.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ src/v_video.h | 1 + 3 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/r_data.cpp b/src/r_data.cpp index 0be54a8ad..ee40e29ca 100644 --- a/src/r_data.cpp +++ b/src/r_data.cpp @@ -421,80 +421,15 @@ void R_DeinitData () void R_PrecacheLevel (void) { BYTE *hitlist; - BYTE *spritelist; - int i; if (demoplayback) return; hitlist = new BYTE[TexMan.NumTextures()]; - spritelist = new BYTE[sprites.Size()]; - - // Precache textures (and sprites). memset (hitlist, 0, TexMan.NumTextures()); - memset (spritelist, 0, sprites.Size()); - { - AActor *actor; - TThinkerIterator iterator; - - while ( (actor = iterator.Next ()) ) - spritelist[actor->sprite] = 1; - } - - for (i = (int)(sprites.Size () - 1); i >= 0; i--) - { - if (spritelist[i]) - { - int j, k; - for (j = 0; j < sprites[i].numframes; j++) - { - const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; - - for (k = 0; k < 16; k++) - { - FTextureID pic = frame->Texture[k]; - if (pic.isValid()) - { - hitlist[pic.GetIndex()] = 1; - } - } - } - } - } - - delete[] spritelist; - - for (i = numsectors - 1; i >= 0; i--) - { - hitlist[sectors[i].GetTexture(sector_t::floor).GetIndex()] = - hitlist[sectors[i].GetTexture(sector_t::ceiling).GetIndex()] |= 2; - } - - for (i = numsides - 1; i >= 0; i--) - { - hitlist[sides[i].GetTexture(side_t::top).GetIndex()] = - hitlist[sides[i].GetTexture(side_t::mid).GetIndex()] = - hitlist[sides[i].GetTexture(side_t::bottom).GetIndex()] |= 1; - } - - // Sky texture is always present. - // Note that F_SKY1 is the name used to - // indicate a sky floor/ceiling as a flat, - // while the sky texture is stored like - // a wall texture, with an episode dependant - // name. - - if (sky1texture.isValid()) - { - hitlist[sky1texture.GetIndex()] |= 1; - } - if (sky2texture.isValid()) - { - hitlist[sky2texture.GetIndex()] |= 1; - } - - for (i = TexMan.NumTextures() - 1; i >= 0; i--) + screen->GetHitlist(hitlist); + for (int i = TexMan.NumTextures() - 1; i >= 0; i--) { screen->PrecacheTexture(TexMan.ByIndex(i), hitlist[i]); } @@ -502,6 +437,8 @@ void R_PrecacheLevel (void) delete[] hitlist; } + + //========================================================================== // // R_GetColumn diff --git a/src/v_video.cpp b/src/v_video.cpp index 24ed1a562..2327529be 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -62,6 +62,7 @@ #include "m_png.h" #include "colormatcher.h" #include "v_palette.h" +#include "r_sky.h" IMPLEMENT_ABSTRACT_CLASS (DCanvas) @@ -1196,6 +1197,83 @@ void DFrameBuffer::WipeCleanup() wipe_Cleanup(); } +//=========================================================================== +// +// Create texture hitlist +// +//=========================================================================== + +void DFrameBuffer::GetHitlist(BYTE *hitlist) +{ + BYTE *spritelist; + int i; + + spritelist = new BYTE[sprites.Size()]; + + // Precache textures (and sprites). + memset (spritelist, 0, sprites.Size()); + + { + AActor *actor; + TThinkerIterator iterator; + + while ( (actor = iterator.Next ()) ) + spritelist[actor->sprite] = 1; + } + + for (i = (int)(sprites.Size () - 1); i >= 0; i--) + { + if (spritelist[i]) + { + int j, k; + for (j = 0; j < sprites[i].numframes; j++) + { + const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j]; + + for (k = 0; k < 16; k++) + { + FTextureID pic = frame->Texture[k]; + if (pic.isValid()) + { + hitlist[pic.GetIndex()] = 1; + } + } + } + } + } + + delete[] spritelist; + + for (i = numsectors - 1; i >= 0; i--) + { + hitlist[sectors[i].GetTexture(sector_t::floor).GetIndex()] = + hitlist[sectors[i].GetTexture(sector_t::ceiling).GetIndex()] |= 2; + } + + for (i = numsides - 1; i >= 0; i--) + { + hitlist[sides[i].GetTexture(side_t::top).GetIndex()] = + hitlist[sides[i].GetTexture(side_t::mid).GetIndex()] = + hitlist[sides[i].GetTexture(side_t::bottom).GetIndex()] |= 1; + } + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependant + // name. + + if (sky1texture.isValid()) + { + hitlist[sky1texture.GetIndex()] |= 1; + } + if (sky2texture.isValid()) + { + hitlist[sky2texture.GetIndex()] |= 1; + } +} + //=========================================================================== // // Texture precaching diff --git a/src/v_video.h b/src/v_video.h index 6beaeea7b..77a3f8a65 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -398,6 +398,7 @@ public: virtual FNativePalette *CreatePalette(FRemapTable *remap); // Precaches or unloads a texture + virtual void GetHitlist(BYTE *hitlist); virtual void PrecacheTexture(FTexture *tex, int cache); // Screen wiping From 30ffffd904021581fc430cdf9ee873110f4b1028 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 29 Jul 2010 06:53:20 +0000 Subject: [PATCH 132/251] - fixed: Checks for poison damage were not correct. SVN r2469 (trunk) --- src/p_map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index b19c04e7b..f8c267070 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1090,7 +1090,7 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) S_Sound (tm.thing, CHAN_BODY, "misc/ripslop", 1, ATTN_IDLE); // Do poisoning (if using new style poison) - if (tm.thing->PoisonDuration != INT_MIN) + if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN) { P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod); } @@ -1118,7 +1118,7 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) } // Do poisoning (if using new style poison) - if (tm.thing->PoisonDuration != INT_MIN) + if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN) { P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod); } @@ -3487,7 +3487,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } // Allow puffs to inflict poison damage, so that hitscans can poison, too. - if (puffDefaults->PoisonDuration != INT_MIN) + if (puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { P_PoisonMobj(trace.Actor, puff ? puff : t1, t1, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod); } @@ -3862,7 +3862,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color } if (spawnpuff) P_SpawnPuff (source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, PF_HITTHING); - if (puffDefaults && puffDefaults->PoisonDuration != INT_MIN) + if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) P_PoisonMobj(RailHits[i].HitActor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod); P_DamageMobj (RailHits[i].HitActor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); From 1b531f0ffcbecb5d81542693f8a737fe9658d026 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 29 Jul 2010 06:54:00 +0000 Subject: [PATCH 133/251] - missed this one... SVN r2470 (trunk) --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9c1e195ee..390bbbb47 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -172,6 +172,7 @@ IMPLEMENT_POINTY_CLASS (AActor) DECLARE_POINTER (Inventory) DECLARE_POINTER (LastHeard) DECLARE_POINTER (master) + DECLARE_POINTER (Poisoner) END_POINTERS AActor::~AActor () From 6e6640ef07d2f25d8cf4b698375e32a7ea54c631 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 29 Jul 2010 12:00:33 +0000 Subject: [PATCH 134/251] - fixed: Chex Quest should have a 'Read This' menu option. SVN r2471 (trunk) --- wadsrc/static/mapinfo/chex.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 036d2af89..9e313cf1e 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -41,6 +41,7 @@ gameinfo defaultdropstyle = 1 endoom = "ENDOOM" player5start = 4001 + drawreadthis = true } skill baby From 8d5ca6501abaa4645d24de6598e6811ca55a1d94 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 30 Jul 2010 03:21:13 +0000 Subject: [PATCH 135/251] - Add a NULL FrontCopySurface check to D3DFB::GetCurrentScreen, because this can apparently be NULL when starting with -timedemo or -playdemo. (But it never happened for me in the debugger.) SVN r2474 (trunk) --- src/win32/fb_d3d9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 922c63a29..b2c8e1bfa 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1772,7 +1772,7 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) assert(pool == D3DPOOL_SYSTEMMEM || pool == D3DPOOL_DEFAULT); - if (FAILED(FrontCopySurface->GetDesc(&desc))) + if (FrontCopySurface == NULL || FAILED(FrontCopySurface->GetDesc(&desc))) { return NULL; } From 677d07f837fc1a08fcbd41eebda84e71a95ca071 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 02:41:56 +0000 Subject: [PATCH 136/251] - Merge BSP-able polyobjects back into the trunk. SVN r2480 (trunk) --- CMakeLists.txt | 7 - src/CMakeLists.txt | 7 + src/am_map.cpp | 26 +- src/nodebuild.cpp | 209 +++++++-- src/nodebuild.h | 115 +++-- src/nodebuild_classify_nosse2.cpp | 39 +- src/nodebuild_classify_sse2.cpp | 50 +- src/nodebuild_extract.cpp | 92 +++- src/nodebuild_utility.cpp | 155 +++++++ src/p_setup.cpp | 46 +- src/po_man.cpp | 160 ++++--- src/po_man.h | 45 +- src/r_bsp.cpp | 110 +++-- src/r_defs.h | 50 +- src/r_polymost.cpp | 2 +- src/r_segs.cpp | 191 ++------ zdoom.vcproj | 748 +++++++++++++++--------------- 17 files changed, 1242 insertions(+), 810 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78264488d..215858b14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,13 +64,6 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" ) -if( CMAKE_COMPILER_IS_GNUCXX AND PROFILE ) - set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) - set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) - set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) -endif( CMAKE_COMPILER_IS_GNUCXX AND PROFILE ) - if( ZLIB_FOUND ) message( STATUS "Using system zlib" ) else( ZLIB_FOUND ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ea4f153a2..67e06cf3b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -330,6 +330,13 @@ endif( NOT NO_ASM ) # Set up flags for GCC if( CMAKE_COMPILER_IS_GNUCXX ) + if( PROFILE ) + set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) + set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) + set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) + endif( PROFILE ) + set( REL_CXX_FLAGS "-fno-rtti" ) if( NOT PROFILE ) set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" ) diff --git a/src/am_map.cpp b/src/am_map.cpp index 5883b9472..9dccdf2c0 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1672,6 +1672,22 @@ void AM_drawSeg(seg_t *seg, const AMColor &color) AM_drawMline(&l, color); } +void AM_drawPolySeg(FPolySeg *seg, const AMColor &color) +{ + mline_t l; + l.a.x = seg->v1.x >> FRACTOMAPBITS; + l.a.y = seg->v1.y >> FRACTOMAPBITS; + l.b.x = seg->v2.x >> FRACTOMAPBITS; + l.b.y = seg->v2.y >> FRACTOMAPBITS; + + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + AM_rotatePoint (&l.a.x, &l.a.y); + AM_rotatePoint (&l.b.x, &l.b.y); + } + AM_drawMline(&l, color); +} + void AM_showSS() { if (am_showsubsector >= 0 && am_showsubsector < numsubsectors) @@ -1682,13 +1698,13 @@ void AM_showSS() red.FromRGB(255,0,0); subsector_t *sub = &subsectors[am_showsubsector]; - for(unsigned int i=0;inumlines;i++) + for (unsigned int i = 0; i < sub->numlines; i++) { - AM_drawSeg(&segs[sub->firstline+i], yellow); + AM_drawSeg(sub->firstline + i, yellow); } PO_LinkToSubsectors(); - for(int i=0;isubsectorlinks; @@ -1697,9 +1713,9 @@ void AM_showSS() { if (pnode->subsector == sub) { - for(unsigned j=0;jsegs.Size();j++) + for (unsigned j = 0; j < pnode->segs.Size(); j++) { - AM_drawSeg(&pnode->segs[j], red); + AM_drawPolySeg(&pnode->segs[j], red); } } pnode = pnode->snext; diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index bbf281b95..804190fee 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -62,10 +62,17 @@ const int AAPreference = 16; #define D(x) do{}while(0) #endif +FNodeBuilder::FNodeBuilder(FLevel &level) +: Level(level), GLNodes(false), SegsStuffed(0) +{ + + VertexMap = NULL; +} + FNodeBuilder::FNodeBuilder (FLevel &level, TArray &polyspots, TArray &anchors, - bool makeGLNodes, bool enableSSE2) - : Level(level), GLNodes(makeGLNodes), EnableSSE2(enableSSE2), SegsStuffed(0) + bool makeGLNodes) + : Level(level), GLNodes(makeGLNodes), SegsStuffed(0) { VertexMap = new FVertexMap (*this, Level.MinX, Level.MinY, Level.MaxX, Level.MaxY); FindUsedVertices (Level.Vertices, Level.NumVertices); @@ -83,6 +90,33 @@ FNodeBuilder::~FNodeBuilder() } } +void FNodeBuilder::BuildMini(bool makeGLNodes) +{ + GLNodes = makeGLNodes; + GroupSegPlanesSimple(); + BuildTree(); +} + +void FNodeBuilder::Clear() +{ + SegsStuffed = 0; + Nodes.Clear(); + Subsectors.Clear(); + SubsectorSets.Clear(); + Segs.Clear(); + Vertices.Clear(); + SegList.Clear(); + PlaneChecked.Clear(); + Planes.Clear(); + Touched.Clear(); + Colinear.Clear(); + SplitSharers.Clear(); + if (VertexMap == NULL) + { + VertexMap = new FVertexMapSimple(*this); + } +} + void FNodeBuilder::BuildTree () { fixed_t bbox[4]; @@ -90,35 +124,38 @@ void FNodeBuilder::BuildTree () C_InitTicker ("Building BSP", FRACUNIT); HackSeg = DWORD_MAX; HackMate = DWORD_MAX; - CreateNode (0, bbox); + CreateNode (0, Segs.Size(), bbox); CreateSubsectorsForReal (); C_InitTicker (NULL, 0); } -int FNodeBuilder::CreateNode (DWORD set, fixed_t bbox[4]) +int FNodeBuilder::CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]) { node_t node; - int skip, count, selstat; + int skip, selstat; DWORD splitseg; - count = CountSegs (set); - skip = count / MaxSegs; + skip = int(count / MaxSegs); + // When building GL nodes, count may not be an exact count of the number of segs + // in the set. That's okay, because we just use it to get a skip count, so an + // estimate is fine. if ((selstat = SelectSplitter (set, node, splitseg, skip, true)) > 0 || (skip > 0 && (selstat = SelectSplitter (set, node, splitseg, 1, true)) > 0) || (selstat < 0 && (SelectSplitter (set, node, splitseg, skip, false) > 0 || (skip > 0 && SelectSplitter (set, node, splitseg, 1, false)))) || - CheckSubsector (set, node, splitseg, count)) + CheckSubsector (set, node, splitseg)) { // Create a normal node DWORD set1, set2; + unsigned int count1, count2; - SplitSegs (set, node, splitseg, set1, set2); + SplitSegs (set, node, splitseg, set1, set2, count1, count2); D(PrintSet (1, set1)); D(Printf (PRINT_LOG, "(%d,%d) delta (%d,%d) from seg %d\n", node.x>>16, node.y>>16, node.dx>>16, node.dy>>16, splitseg)); D(PrintSet (2, set2)); - node.intchildren[0] = CreateNode (set1, node.bbox[0]); - node.intchildren[1] = CreateNode (set2, node.bbox[1]); + node.intchildren[0] = CreateNode (set1, count1, node.bbox[0]); + node.intchildren[1] = CreateNode (set2, count2, node.bbox[1]); bbox[BOXTOP] = MAX (node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]); bbox[BOXBOTTOM] = MIN (node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]); bbox[BOXLEFT] = MIN (node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]); @@ -173,17 +210,15 @@ void FNodeBuilder::CreateSubsectorsForReal () subsector_t sub; unsigned int i; - sub.validcount = 0; - sub.CenterX = 0; // Code in p_setup.cpp will set these for us later. - sub.CenterY = 0; sub.sector = NULL; sub.polys = NULL; + sub.BSP = NULL; for (i = 0; i < SubsectorSets.Size(); ++i) { DWORD set = SubsectorSets[i]; + DWORD firstline = (DWORD)SegList.Size(); - sub.firstline = (DWORD)SegList.Size(); while (set != DWORD_MAX) { USegPtr ptr; @@ -192,14 +227,15 @@ void FNodeBuilder::CreateSubsectorsForReal () SegList.Push (ptr); set = ptr.SegPtr->next; } - sub.numlines = (DWORD)(SegList.Size() - sub.firstline); + sub.numlines = (DWORD)(SegList.Size() - firstline); + sub.firstline = (seg_t *)firstline; // Sort segs by linedef for special effects - qsort (&SegList[sub.firstline], sub.numlines, sizeof(USegPtr), SortSegs); + qsort (&SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs); // Convert seg pointers into indices D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size())); - for (unsigned int i = sub.firstline; i < SegList.Size(); ++i) + for (unsigned int i = firstline; i < SegList.Size(); ++i) { D(Printf (PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d)\n", SegList[i].SegPtr - &Segs[0], SegList[i].SegPtr->linedef == -1 ? '+' : ' ', @@ -273,24 +309,12 @@ int STACK_ARGS FNodeBuilder::SortSegs (const void *a, const void *b) } } -int FNodeBuilder::CountSegs (DWORD set) const -{ - int count = 0; - - while (set != DWORD_MAX) - { - count++; - set = Segs[set].next; - } - return count; -} - // Given a set of segs, checks to make sure they all belong to a single // sector. If so, false is returned, and they become a subsector. If not, // a splitter is synthesized, and true is returned to continue processing // down this branch of the tree. -bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize) +bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg) { sector_t *sec; DWORD seg; @@ -506,7 +530,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit) int realSegs[2] = { 0, 0 }; int specialSegs[2] = { 0, 0 }; DWORD i = set; - int sidev1, sidev2; + int sidev[2]; int side; bool splitter = false; unsigned int max, m2, p, q; @@ -525,7 +549,7 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit) } else { - side = ClassifyLine (node, test, sidev1, sidev2); + side = ClassifyLine (node, &Vertices[test->v1], &Vertices[test->v2], sidev); } switch (side) { @@ -535,9 +559,9 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit) // The "right" thing to do in this case is to only reject it if there is // another nosplit seg from the same sector at this vertex. Note that a line // that lies exactly on top of the splitter is okay. - if (test->loopnum && honorNoSplit && (sidev1 == 0 || sidev2 == 0)) + if (test->loopnum && honorNoSplit && (sidev[0] == 0 || sidev[1] == 0)) { - if ((sidev1 | sidev2) != 0) + if ((sidev[0] | sidev[1]) != 0) { max = Touched.Size(); for (p = 0; p < max; ++p) @@ -735,8 +759,10 @@ int FNodeBuilder::Heuristic (node_t &node, DWORD set, bool honorNoSplit) return score; } -void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1) +void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1) { + unsigned int _count0 = 0; + unsigned int _count1 = 0; outset0 = DWORD_MAX; outset1 = DWORD_MAX; @@ -749,18 +775,18 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou FPrivSeg *seg = &Segs[set]; int next = seg->next; - int sidev1, sidev2, side; + int sidev[2], side; if (HackSeg == set) { HackSeg = DWORD_MAX; side = 1; - sidev1 = sidev2 = 0; + sidev[0] = sidev[1] = 0; hack = true; } else { - side = ClassifyLine (node, seg, sidev1, sidev2); + side = ClassifyLine (node, &Vertices[seg->v1], &Vertices[seg->v2], sidev); hack = false; } @@ -769,11 +795,13 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou case 0: // seg is entirely in front seg->next = outset0; outset0 = set; + _count0++; break; case 1: // seg is entirely in back seg->next = outset1; outset1 = set; + _count1++; break; default: // seg needs to be split @@ -803,18 +831,20 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou Printf("SelectVertexClose selected endpoint of seg %u\n", set); } - seg2 = SplitSeg (set, vertnum, sidev1); + seg2 = SplitSeg (set, vertnum, sidev[0]); Segs[seg2].next = outset0; outset0 = seg2; Segs[set].next = outset1; outset1 = set; + _count0++; + _count1++; // Also split the seg on the back side if (Segs[set].partner != DWORD_MAX) { int partner1 = Segs[set].partner; - int partner2 = SplitSeg (partner1, vertnum, sidev2); + int partner2 = SplitSeg (partner1, vertnum, sidev[1]); // The newly created seg stays in the same set as the // back seg because it has not been considered for splitting // yet. If it had been, then the front seg would have already @@ -835,17 +865,17 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou } if (side >= 0 && GLNodes) { - if (sidev1 == 0) + if (sidev[0] == 0) { double dist1 = AddIntersection (node, seg->v1); - if (sidev2 == 0) + if (sidev[1] == 0) { double dist2 = AddIntersection (node, seg->v2); FSplitSharer share = { dist1, set, dist2 > dist1 }; SplitSharers.Push (share); } } - else if (sidev2 == 0) + else if (sidev[1] == 0) { AddIntersection (node, seg->v2); } @@ -881,6 +911,8 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou { AddMinisegs (node, splitseg, outset0, outset1); } + count0 = _count0; + count1 = _count1; } void FNodeBuilder::SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const @@ -1038,3 +1070,92 @@ void FNodeBuilder::PrintSet (int l, DWORD set) } Printf (PRINT_LOG, "*\n"); } + + + +#ifdef BACKPATCH +#ifdef _WIN32 +extern "C" { +__declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsigned long, unsigned long *); +} +#define PAGE_EXECUTE_READWRITE 64 +#else +#include +#include +#endif + +#ifdef __GNUC__ +extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) +#else +static int *CallerOffset; +int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) +#endif +{ + // Select the routine based on SSE2 availability and patch the caller so that + // they call that routine directly next time instead of going through here. + int *calleroffset; + int diff; + int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]); + +#ifdef __GNUC__ + calleroffset = (int *)__builtin_return_address(0); +#else + calleroffset = CallerOffset; +#endif +// printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset); + + if (CPU.bSSE2) + { + func = ClassifyLineSSE2; + diff = (char *)ClassifyLineSSE2 - (char *)calleroffset; + } + else + { + func = ClassifyLine2; + diff = (char *)ClassifyLine2 - (char *)calleroffset; + } + + calleroffset--; + // Patch the caller. +#ifdef _WIN32 + unsigned long oldprotect; + if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) +#else + // must make this page-aligned for mprotect + long pagesize = sysconf(_SC_PAGESIZE); + char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1)); + size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage; + int ptect; + if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC))) +#endif + { + *calleroffset = diff; +#ifdef _WIN32 + VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect); +#else + mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC); +#endif + } + + // And return by calling the real function. + return func (node, v1, v2, sidev); +} + +#ifndef __GNUC__ +// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness +// to retrieve the return address of the stack before sending control to the real +// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds, +// we're okay that VC++ can't do inline assembly on that target. + +extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) +{ + // We store the return address in a global, so as not to need to mess with the parameter list. + __asm + { + mov eax, [esp] + mov CallerOffset, eax + jmp ClassifyLineBackpatchC + } +} +#endif +#endif diff --git a/src/nodebuild.h b/src/nodebuild.h index d0d59e706..d1ed2cb15 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -1,6 +1,10 @@ #include "doomdata.h" #include "tarray.h" #include "r_defs.h" +#include "x86.h" + +struct FPolySeg; +struct FMiniBSP; struct FEventInfo { @@ -40,6 +44,27 @@ private: FEvent *Predecessor (FEvent *event) const; }; +struct FSimpleVert +{ + fixed_t x, y; +}; + +extern "C" +{ + int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); +#ifndef DISABLE_SSE + int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); + int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); +#ifdef BACKPATCH +#ifdef __GNUC__ + int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline)); +#else + int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); +#endif +#endif +#endif +} + class FNodeBuilder { struct FPrivSeg @@ -60,9 +85,8 @@ class FNodeBuilder bool planefront; FPrivSeg *hashnext; }; - struct FPrivVert + struct FPrivVert : FSimpleVert { - fixed_t x, y; DWORD segs; // segs that use this vertex as v1 DWORD segs2; // segs that use this vertex as v2 @@ -88,7 +112,17 @@ class FNodeBuilder }; // Like a blockmap, but for vertices instead of lines - class FVertexMap + class IVertexMap + { + public: + virtual ~IVertexMap(); + virtual int SelectVertexExact(FPrivVert &vert) = 0; + virtual int SelectVertexClose(FPrivVert &vert) = 0; + private: + IVertexMap &operator=(const IVertexMap &); + }; + + class FVertexMap : public IVertexMap { public: FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy); @@ -116,12 +150,23 @@ class FNodeBuilder assert (y <= MaxY); return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide; } + }; - FVertexMap &operator= (const FVertexMap &) { return *this; } + class FVertexMapSimple : public IVertexMap + { + public: + FVertexMapSimple(FNodeBuilder &builder); + + int SelectVertexExact(FPrivVert &vert); + int SelectVertexClose(FPrivVert &vert); + private: + int InsertVertex(FPrivVert &vert); + + FNodeBuilder &MyBuilder; }; friend class FVertexMap; - + friend class FVertexMapSimple; public: struct FLevel @@ -132,7 +177,14 @@ public: fixed_t MinX, MinY, MaxX, MaxY; - void FindMapBounds (); + void FindMapBounds(); + void ResetMapBounds() + { + MinX = FIXED_MAX; + MinY = FIXED_MAX; + MaxX = FIXED_MIN; + MaxY = FIXED_MIN; + } }; struct FPolyStart @@ -141,9 +193,10 @@ public: fixed_t x, y; }; + FNodeBuilder (FLevel &level); FNodeBuilder (FLevel &level, TArray &polyspots, TArray &anchors, - bool makeGLNodes, bool enableSSE2); + bool makeGLNodes); ~FNodeBuilder (); void Extract (node_t *&nodes, int &nodeCount, @@ -151,6 +204,13 @@ public: subsector_t *&ssecs, int &subCount, vertex_t *&verts, int &vertCount); + // These are used for building sub-BSP trees for polyobjects. + void Clear(); + void AddPolySegs(FPolySeg *segs, int numsegs); + void AddSegs(seg_t *segs, int numsegs); + void BuildMini(bool makeGLNodes); + void ExtractMini(FMiniBSP *bsp); + static angle_t PointToAngle (fixed_t dx, fixed_t dy); // < 0 : in front of line @@ -160,7 +220,7 @@ public: static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy); private: - FVertexMap *VertexMap; + IVertexMap *VertexMap; TArray Nodes; TArray Subsectors; @@ -181,7 +241,6 @@ private: DWORD HackMate; // Seg to use in front of hack seg FLevel &Level; bool GLNodes; // Add minisegs to make GL nodes? - bool EnableSSE2; // Progress meter stuff int SegsStuffed; @@ -191,29 +250,27 @@ private: void MakeSegsFromSides (); int CreateSeg (int linenum, int sidenum); void GroupSegPlanes (); + void GroupSegPlanesSimple (); void FindPolyContainers (TArray &spots, TArray &anchors); bool GetPolyExtents (int polynum, fixed_t bbox[4]); int MarkLoop (DWORD firstseg, int loopnum); void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg); - int CreateNode (DWORD set, fixed_t bbox[4]); + int CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]); int CreateSubsector (DWORD set, fixed_t bbox[4]); void CreateSubsectorsForReal (); - bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize); + bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg); bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg); bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate); int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit); - void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1); + void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1); DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront); int Heuristic (node_t &node, DWORD set, bool honorNoSplit); - int CountSegs (DWORD set) const; // Returns: // 0 = seg is in front // 1 = seg is in back // -1 = seg cuts the node - inline int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2); - int ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2); - int ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2); + inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]); void FixSplitSharers (const node_t &node); double AddIntersection (const node_t &node, int vertex); @@ -273,21 +330,27 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int return s_num > 0.0 ? -1 : 1; } -inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) +inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]) { -#if !defined(_M_IX86) && !defined(_M_X64) && !defined(__i386__) && !defined(__amd64__) - return ClassifyLine2 (node, seg, sidev1, sidev2); -#elif defined(__SSE2__) +#ifdef DISABLE_SSE + return ClassifyLine2 (node, v1, v2, sidev); +#else +#if defined(__SSE2__) || defined(_M_IX64) // If compiling with SSE2 support everywhere, just use the SSE2 version. - return ClassifyLineSSE2 (node, seg, sidev1, sidev2); + return ClassifyLineSSE2 (node, v1, v2, sidev); #elif defined(_MSC_VER) && _MSC_VER < 1300 - // VC 6 does not support SSE2 optimizations. - return ClassifyLine2 (node, seg, sidev1, sidev2); + // VC 6 does not support SSE optimizations. + return ClassifyLine2 (node, v1, v2, sidev); #else // Select the routine based on our flag. - if (EnableSSE2) - return ClassifyLineSSE2 (node, seg, sidev1, sidev2); +#ifdef BACKPATCH + return ClassifyLineBackpatch (node, v1, v2, sidev); +#else + if (CPU.bSSE2) + return ClassifyLineSSE2 (node, v1, v2, sidev); else - return ClassifyLine2 (node, seg, sidev1, sidev2); + return ClassifyLine2 (node, v1, v2, sidev); +#endif +#endif #endif } diff --git a/src/nodebuild_classify_nosse2.cpp b/src/nodebuild_classify_nosse2.cpp index 2b7f6bec6..3fd1da272 100644 --- a/src/nodebuild_classify_nosse2.cpp +++ b/src/nodebuild_classify_nosse2.cpp @@ -3,11 +3,8 @@ #define FAR_ENOUGH 17179869184.f // 4<<32 -int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) +extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) { - const FPrivVert *v1 = &Vertices[seg->v1]; - const FPrivVert *v2 = &Vertices[seg->v2]; - double d_x1 = double(node.x); double d_y1 = double(node.y); double d_dx = double(node.dx); @@ -26,13 +23,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, { if (s_num2 <= -FAR_ENOUGH) { - sidev1 = sidev2 = 1; + sidev[0] = sidev[1] = 1; return 1; } if (s_num2 >= FAR_ENOUGH) { - sidev1 = 1; - sidev2 = -1; + sidev[0] = 1; + sidev[1] = -1; return -1; } nears = 1; @@ -41,13 +38,13 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, { if (s_num2 >= FAR_ENOUGH) { - sidev1 = sidev2 = -1; + sidev[0] = sidev[1] = -1; return 0; } if (s_num2 <= -FAR_ENOUGH) { - sidev1 = -1; - sidev2 = 1; + sidev[0] = -1; + sidev[1] = 1; return -1; } nears = 1; @@ -65,41 +62,41 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, double dist = s_num1 * s_num1 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { - sidev1 = 0; + sidev[0] = 0; } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; } } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; } if (nears & 1) { double dist = s_num2 * s_num2 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { - sidev2 = 0; + sidev[1] = 0; } else { - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } } else { - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } - if ((sidev1 | sidev2) == 0) + if ((sidev[0] | sidev[1]) == 0) { // seg is coplanar with the splitter, so use its orientation to determine // which child it ends up in. If it faces the same direction as the splitter, // it goes in front. Otherwise, it goes in back. @@ -127,11 +124,11 @@ int FNodeBuilder::ClassifyLine2 (node_t &node, const FPrivSeg *seg, int &sidev1, } } } - else if (sidev1 <= 0 && sidev2 <= 0) + else if (sidev[0] <= 0 && sidev[1] <= 0) { return 0; } - else if (sidev1 >= 0 && sidev2 >= 0) + else if (sidev[0] >= 0 && sidev[1] >= 0) { return 1; } diff --git a/src/nodebuild_classify_sse2.cpp b/src/nodebuild_classify_sse2.cpp index 05e4684a8..01c469093 100644 --- a/src/nodebuild_classify_sse2.cpp +++ b/src/nodebuild_classify_sse2.cpp @@ -1,18 +1,16 @@ +#ifndef DISABLE_SSE + #include "doomtype.h" #include "nodebuild.h" #define FAR_ENOUGH 17179869184.f // 4<<32 -// This function is identical to the ClassifyLine2 version. So how does it use SSE2? -// Easy! By explicitly enabling SSE2 in the configuration properties for this one -// file, we can build it with SSE2 enabled without forcing SSE2 on the rest of the -// project. +// You may notice that this function is identical to ClassifyLine2. +// The reason it is SSE2 is because this file is explicitly compiled +// with SSE2 math enabled, but the other files are not. -int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2) +extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) { - const FPrivVert *v1 = &Vertices[seg->v1]; - const FPrivVert *v2 = &Vertices[seg->v2]; - double d_x1 = double(node.x); double d_y1 = double(node.y); double d_dx = double(node.dx); @@ -31,13 +29,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side { if (s_num2 <= -FAR_ENOUGH) { - sidev1 = sidev2 = 1; + sidev[0] = sidev[1] = 1; return 1; } if (s_num2 >= FAR_ENOUGH) { - sidev1 = 1; - sidev2 = -1; + sidev[0] = 1; + sidev[1] = -1; return -1; } nears = 1; @@ -46,13 +44,13 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side { if (s_num2 >= FAR_ENOUGH) { - sidev1 = sidev2 = -1; + sidev[0] = sidev[1] = -1; return 0; } if (s_num2 <= -FAR_ENOUGH) { - sidev1 = -1; - sidev2 = 1; + sidev[0] = -1; + sidev[1] = 1; return -1; } nears = 1; @@ -70,41 +68,41 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side double dist = s_num1 * s_num1 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { - sidev1 = 0; + sidev[0] = 0; } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; } } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; } if (nears & 1) { double dist = s_num2 * s_num2 * l; if (dist < SIDE_EPSILON*SIDE_EPSILON) { - sidev2 = 0; + sidev[1] = 0; } else { - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } } else { - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } } else { - sidev1 = s_num1 > 0.0 ? -1 : 1; - sidev2 = s_num2 > 0.0 ? -1 : 1; + sidev[0] = s_num1 > 0.0 ? -1 : 1; + sidev[1] = s_num2 > 0.0 ? -1 : 1; } - if ((sidev1 | sidev2) == 0) + if ((sidev[0] | sidev[1]) == 0) { // seg is coplanar with the splitter, so use its orientation to determine // which child it ends up in. If it faces the same direction as the splitter, // it goes in front. Otherwise, it goes in back. @@ -132,13 +130,15 @@ int FNodeBuilder::ClassifyLineSSE2 (node_t &node, const FPrivSeg *seg, int &side } } } - else if (sidev1 <= 0 && sidev2 <= 0) + else if (sidev[0] <= 0 && sidev[1] <= 0) { return 0; } - else if (sidev1 >= 0 && sidev2 >= 0) + else if (sidev[0] >= 0 && sidev[1] >= 0) { return 1; } return -1; } + +#endif diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index 77fa4dec7..24fadcf3b 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -105,7 +105,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, { DWORD numsegs = CloseSubsector (segs, i, outVerts); outSubs[i].numlines = numsegs; - outSubs[i].firstline = segs.Size() - numsegs; + outSubs[i].firstline = (seg_t *)(size_t)(segs.Size() - numsegs); } segCount = segs.Size (); @@ -142,6 +142,10 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, out->bPolySeg = false; } } + for (i = 0; i < subCount; ++i) + { + outSubs[i].firstline = &outSegs[(size_t)outSubs[i].firstline]; + } D(Printf("%i segs, %i nodes, %i subsectors\n", segCount, nodeCount, subCount)); @@ -152,6 +156,86 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, } } +void FNodeBuilder::ExtractMini (FMiniBSP *bsp) +{ + unsigned int i; + + bsp->Verts.Resize(Vertices.Size()); + for (i = 0; i < Vertices.Size(); ++i) + { + bsp->Verts[i].x = Vertices[i].x; + bsp->Verts[i].y = Vertices[i].y; + } + + bsp->Subsectors.Resize(Subsectors.Size()); + memset(&bsp->Subsectors[0], 0, Subsectors.Size() * sizeof(subsector_t)); + + bsp->Nodes.Resize(Nodes.Size()); + memcpy(&bsp->Nodes[0], &Nodes[0], Nodes.Size()*sizeof(node_t)); + for (i = 0; i < Nodes.Size(); ++i) + { + D(Printf(PRINT_LOG, "Node %d:\n", i)); + // Go backwards because on 64-bit systems, both of the intchildren are + // inside the first in-game child. + for (int j = 1; j >= 0; --j) + { + if (bsp->Nodes[i].intchildren[j] & 0x80000000) + { + D(Printf(PRINT_LOG, " subsector %d\n", bsp->Nodes[i].intchildren[j] & 0x7FFFFFFF)); + bsp->Nodes[i].children[j] = (BYTE *)&bsp->Subsectors[bsp->Nodes[i].intchildren[j] & 0x7fffffff] + 1; + } + else + { + D(Printf(PRINT_LOG, " node %d\n", bsp->Nodes[i].intchildren[j])); + bsp->Nodes[i].children[j] = &bsp->Nodes[bsp->Nodes[i].intchildren[j]]; + } + } + } + + if (GLNodes) + { + for (i = 0; i < Subsectors.Size(); ++i) + { + DWORD numsegs = CloseSubsector (bsp->Segs, i, &bsp->Verts[0]); + bsp->Subsectors[i].numlines = numsegs; + bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs]; + } + + for (i = 0; i < Segs.Size(); ++i) + { + if (bsp->Segs[i].PartnerSeg != NULL) + { + bsp->Segs[i].PartnerSeg = &bsp->Segs[Segs[(unsigned int)(size_t)bsp->Segs[i].PartnerSeg-1].storedseg]; + } + } + } + else + { + memcpy(&bsp->Subsectors[0], &Subsectors[0], Subsectors.Size()*sizeof(subsector_t)); + bsp->Segs.Resize(Segs.Size()); + for (i = 0; i < Segs.Size(); ++i) + { + const FPrivSeg *org = &Segs[SegList[i].SegNum]; + seg_t *out = &bsp->Segs[i]; + + D(Printf(PRINT_LOG, "Seg %d: v1(%d) -> v2(%d)\n", i, org->v1, org->v2)); + + out->v1 = &bsp->Verts[org->v1]; + out->v2 = &bsp->Verts[org->v2]; + out->backsector = org->backsector; + out->frontsector = org->frontsector; + out->linedef = Level.Lines + org->linedef; + out->sidedef = Level.Sides + org->sidedef; + out->PartnerSeg = NULL; + out->bPolySeg = false; + } + for (i = 0; i < bsp->Subsectors.Size(); ++i) + { + bsp->Subsectors[i].firstline = &bsp->Segs[(size_t)bsp->Subsectors[i].firstline]; + } + } +} + int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t *outVerts) { FPrivSeg *seg, *prev; @@ -163,7 +247,7 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * bool diffplanes; int firstplane; - first = Subsectors[subsector].firstline; + first = (DWORD)(size_t)Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; @@ -322,7 +406,7 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray &segs, int subsector, double dot, x1, y1, dx, dy, dx2, dy2; bool wantside; - first = Subsectors[subsector].firstline; + first = (DWORD)(size_t)Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; @@ -401,7 +485,6 @@ DWORD FNodeBuilder::PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_ } newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1); newseg.bPolySeg = false; - newseg.Subsector = NULL; return (DWORD)segs.Push (newseg); } @@ -417,6 +500,5 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray &segs, vert newseg.sidedef = NULL; newseg.PartnerSeg = NULL; newseg.bPolySeg = false; - newseg.Subsector = NULL; segs.Push (newseg); } diff --git a/src/nodebuild_utility.cpp b/src/nodebuild_utility.cpp index a8a618b9f..ef79ac4d9 100644 --- a/src/nodebuild_utility.cpp +++ b/src/nodebuild_utility.cpp @@ -49,6 +49,7 @@ #include "m_bbox.h" #include "r_main.h" #include "i_system.h" +#include "po_man.h" static const int PO_LINE_START = 1; static const int PO_LINE_EXPLICIT = 5; @@ -177,6 +178,86 @@ int FNodeBuilder::CreateSeg (int linenum, int sidenum) return segnum; } +// For every seg, create FPrivSegs and FPrivVerts. + +void FNodeBuilder::AddSegs(seg_t *segs, int numsegs) +{ + assert(numsegs > 0); + + for (int i = 0; i < numsegs; ++i) + { + FPrivSeg seg; + FPrivVert vert; + int segnum; + + seg.next = DWORD_MAX; + seg.loopnum = 0; + seg.partner = DWORD_MAX; + seg.hashnext = NULL; + seg.planefront = false; + seg.planenum = DWORD_MAX; + seg.storedseg = DWORD_MAX; + + seg.frontsector = segs[i].frontsector; + seg.backsector = segs[i].backsector; + vert.x = segs[i].v1->x; + vert.y = segs[i].v1->y; + seg.v1 = VertexMap->SelectVertexExact(vert); + vert.x = segs[i].v2->x; + vert.y = segs[i].v2->y; + seg.v2 = VertexMap->SelectVertexExact(vert); + seg.linedef = int(segs[i].linedef - Level.Lines); + seg.sidedef = segs[i].sidedef != NULL ? int(segs[i].sidedef - Level.Sides) : int(NO_SIDE); + seg.nextforvert = Vertices[seg.v1].segs; + seg.nextforvert2 = Vertices[seg.v2].segs2; + + segnum = (int)Segs.Push(seg); + Vertices[seg.v1].segs = segnum; + Vertices[seg.v2].segs2 = segnum; + } +} + +void FNodeBuilder::AddPolySegs(FPolySeg *segs, int numsegs) +{ + assert(numsegs > 0); + + for (int i = 0; i < numsegs; ++i) + { + FPrivSeg seg; + FPrivVert vert; + int segnum; + + seg.next = DWORD_MAX; + seg.loopnum = 0; + seg.partner = DWORD_MAX; + seg.hashnext = NULL; + seg.planefront = false; + seg.planenum = DWORD_MAX; + seg.storedseg = DWORD_MAX; + + side_t *side = segs[i].wall; + assert(side != NULL); + + seg.frontsector = side->sector; + seg.backsector = side->linedef->frontsector == side->sector ? side->linedef->backsector : side->linedef->frontsector; + vert.x = segs[i].v1.x; + vert.y = segs[i].v1.y; + seg.v1 = VertexMap->SelectVertexExact(vert); + vert.x = segs[i].v2.x; + vert.y = segs[i].v2.y; + seg.v2 = VertexMap->SelectVertexExact(vert); + seg.linedef = int(side->linedef - Level.Lines); + seg.sidedef = int(side - Level.Sides); + seg.nextforvert = Vertices[seg.v1].segs; + seg.nextforvert2 = Vertices[seg.v2].segs2; + + segnum = (int)Segs.Push(seg); + Vertices[seg.v1].segs = segnum; + Vertices[seg.v2].segs2 = segnum; + } +} + + // Group colinear segs together so that only one seg per line needs to be checked // by SelectSplitter(). @@ -269,6 +350,27 @@ void FNodeBuilder::GroupSegPlanes () PlaneChecked.Reserve ((planenum + 7) / 8); } +// Just create one plane per seg. Should be good enough for mini BSPs. +void FNodeBuilder::GroupSegPlanesSimple() +{ + Planes.Resize(Segs.Size()); + for (int i = 0; i < (int)Segs.Size(); ++i) + { + FPrivSeg *seg = &Segs[i]; + FSimpleLine *pline = &Planes[i]; + seg->next = i+1; + seg->hashnext = NULL; + seg->planenum = i; + seg->planefront = true; + pline->x = Vertices[seg->v1].x; + pline->y = Vertices[seg->v1].y; + pline->dx = Vertices[seg->v2].x - Vertices[seg->v1].x; + pline->dy = Vertices[seg->v2].y - Vertices[seg->v1].y; + } + Segs.Last().next = DWORD_MAX; + PlaneChecked.Reserve((Segs.Size() + 7) / 8); +} + // Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin // is not solely defined by the polyobject's anchor, but also by the polyobject itself. // For the split avoidance to work properly, you must have a convex, complete loop of @@ -507,6 +609,10 @@ void FNodeBuilder::FLevel::FindMapBounds () MaxY = maxy; } +FNodeBuilder::IVertexMap::~IVertexMap() +{ +} + FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy) : MyBuilder(builder) @@ -606,3 +712,52 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert) return vertnum; } + +FNodeBuilder::FVertexMapSimple::FVertexMapSimple(FNodeBuilder &builder) + : MyBuilder(builder) +{ +} + +int FNodeBuilder::FVertexMapSimple::SelectVertexExact(FNodeBuilder::FPrivVert &vert) +{ + FPrivVert *verts = &MyBuilder.Vertices[0]; + unsigned int stop = MyBuilder.Vertices.Size(); + + for (unsigned int i = 0; i < stop; ++i) + { + if (verts[i].x == vert.x && verts[i].y == vert.y) + { + return i; + } + } + // Not present: add it! + return InsertVertex(vert); +} + +int FNodeBuilder::FVertexMapSimple::SelectVertexClose(FNodeBuilder::FPrivVert &vert) +{ + FPrivVert *verts = &MyBuilder.Vertices[0]; + unsigned int stop = MyBuilder.Vertices.Size(); + + for (unsigned int i = 0; i < stop; ++i) + { +#if VERTEX_EPSILON <= 1 + if (verts[i].x == vert.x && verts[i].y == y) +#else + if (abs(verts[i].x - vert.x) < VERTEX_EPSILON && + abs(verts[i].y - vert.y) < VERTEX_EPSILON) +#endif + { + return i; + } + } + // Not present: add it! + return InsertVertex (vert); +} + +int FNodeBuilder::FVertexMapSimple::InsertVertex (FNodeBuilder::FPrivVert &vert) +{ + vert.segs = DWORD_MAX; + vert.segs2 = DWORD_MAX; + return (int)MyBuilder.Vertices.Push (vert); +} diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8ade6cb13..452cb0dcf 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -855,7 +855,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type) } data >> side; - seg = &segs[subsectors[i].firstline + j]; + seg = subsectors[i].firstline + j; seg->v1 = &vertexes[v1]; if (j == 0) { @@ -894,7 +894,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type) { seg->linedef = NULL; seg->sidedef = NULL; - seg->frontsector = seg->backsector = segs[subsectors[i].firstline].frontsector; + seg->frontsector = seg->backsector = subsectors[i].firstline->frontsector; } } } @@ -952,7 +952,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes) DWORD numsegs; data >> numsegs; - subsectors[i].firstline = currSeg; + subsectors[i].firstline = (seg_t *)(size_t)currSeg; // Oh damn. I should have stored the seg count sooner. subsectors[i].numlines = numsegs; currSeg += numsegs; } @@ -976,6 +976,11 @@ static void LoadZNodes(FileReaderBase &data, int glnodes) segs = new seg_t[numsegs]; memset (segs, 0, numsegs*sizeof(seg_t)); + for (i = 0; i < numSubs; ++i) + { + subsectors[i].firstline = &segs[(size_t)subsectors[i].firstline]; + } + if (glnodes == 0) { P_LoadZSegs (data); @@ -1141,6 +1146,11 @@ void P_LoadSegs (MapData * map) data = new BYTE[lumplen]; map->Read(ML_SEGS, data); + for (i = 0; i < numsubsectors; ++i) + { + subsectors[i].firstline = &segs[(size_t)subsectors[i].firstline]; + } + // phares: 10/4/98: Vertchanged is an array that represents the vertices. // Mark those used by linedefs. A marked vertex is one that is not a // candidate for movement further down. @@ -1329,9 +1339,9 @@ void P_LoadSubsectors (MapData * map) } subsectors[i].numlines = subd.numsegs; - subsectors[i].firstline = subd.firstseg; + subsectors[i].firstline = (seg_t *)(size_t)subd.firstseg; - if (subsectors[i].firstline >= maxseg) + if ((size_t)subsectors[i].firstline >= maxseg) { Printf ("Subsector %d contains invalid segs %u-%u\n" "The BSP will be rebuilt.\n", i, subsectors[i].firstline, @@ -1341,7 +1351,7 @@ void P_LoadSubsectors (MapData * map) delete[] subsectors; break; } - else if (subsectors[i].firstline + subsectors[i].numlines > maxseg) + else if ((size_t)subsectors[i].firstline + subsectors[i].numlines > maxseg) { Printf ("Subsector %d contains invalid segs %u-%u\n" "The BSP will be rebuilt.\n", i, maxseg, @@ -2910,20 +2920,7 @@ static void P_GroupLines (bool buildmap) times[0].Clock(); for (i = 0; i < numsubsectors; i++) { - subsectors[i].sector = segs[subsectors[i].firstline].sidedef->sector; - subsectors[i].validcount = validcount; - - double accumx = 0.0, accumy = 0.0; - - for (jj = 0; jj < subsectors[i].numlines; ++jj) - { - seg_t *seg = &segs[subsectors[i].firstline + jj]; - seg->Subsector = &subsectors[i]; - accumx += seg->v1->x + seg->v2->x; - accumy += seg->v1->y + seg->v2->y; - } - subsectors[i].CenterX = fixed_t(accumx * 0.5 / subsectors[i].numlines); - subsectors[i].CenterY = fixed_t(accumy * 0.5 / subsectors[i].numlines); + subsectors[i].sector = subsectors[i].firstline->sidedef->sector; } times[0].Unclock(); @@ -3369,6 +3366,13 @@ void P_FreeLevelData () } if (subsectors != NULL) { + for (int i = 0; i < numsubsectors; ++i) + { + if (subsectors[i].BSP != NULL) + { + delete subsectors[i].BSP; + } + } delete[] subsectors; subsectors = NULL; } @@ -3786,7 +3790,7 @@ void P_SetupLevel (char *lumpname, int position) }; leveldata.FindMapBounds (); UsingGLNodes |= genglnodes; - FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes, CPU.bSSE2); + FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes); delete[] vertexes; builder.Extract (nodes, numnodes, segs, numsegs, diff --git a/src/po_man.cpp b/src/po_man.cpp index 6b208825d..c240e28fa 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -142,6 +142,9 @@ static void TranslateToStartSpot (int tag, int originX, int originY); static void DoMovePolyobj (FPolyObj *po, int x, int y); static void InitSegLists (); static void KillSegLists (); +static FPolyNode *NewPolyNode(); +static void FreePolyNode(); +static void ReleaseAllPolyNodes(); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -157,6 +160,7 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u // PRIVATE DATA DEFINITIONS ------------------------------------------------ static TArray KnownPolySides; +static FPolyNode *FreePolyNodes; // CODE -------------------------------------------------------------------- @@ -758,7 +762,6 @@ FPolyObj::FPolyObj() subsectorlinks = NULL; specialdata = NULL; interpolation = NULL; - SVIndex = -1; } //========================================================================== @@ -1279,20 +1282,6 @@ void FPolyObj::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, si } } -vertex_t *FPolyObj::GetNewVertex() -{ - if (SVIndex == ~0u || SplitVertices[SVIndex]->used == 10) - { - SVIndex++; - if (SVIndex >= SplitVertices.Size()) - { - SplitVertices.Push(new FPolyVertexBlock); - } - SplitVertices[SVIndex]->clear(); - } - return &SplitVertices[SVIndex]->vertices[SplitVertices[SVIndex]->used++]; -} - //========================================================================== // // InitBlockMap @@ -1699,11 +1688,6 @@ bool PO_Busy (int polyobj) void FPolyObj::ClearSubsectorLinks() { - for(unsigned i=0; iclear(); - } - SVIndex = -1; while (subsectorlinks != NULL) { assert(subsectorlinks->state == 1337); @@ -1725,6 +1709,12 @@ void FPolyObj::ClearSubsectorLinks() { subsectorlinks->subsector->polys = subsectorlinks->pnext; } + + if (subsectorlinks->subsector->BSP != NULL) + { + subsectorlinks->subsector->BSP->bDirty = true; + } + subsectorlinks->state = -1; delete subsectorlinks; subsectorlinks = next; @@ -1734,10 +1724,11 @@ void FPolyObj::ClearSubsectorLinks() void FPolyObj::ClearAllSubsectorLinks() { - for(int i=0;iv1->x; - double v2y = (double)seg->v1->y; - double v2dx = (double)(seg->v2->x - seg->v1->x); - double v2dy = (double)(seg->v2->y - seg->v1->y); + double v2x = (double)seg->v1.x; + double v2y = (double)seg->v1.y; + double v2dx = (double)(seg->v2.x - seg->v1.x); + double v2dy = (double)(seg->v2.y - seg->v1.y); double v1x = (double)bsp->x; double v1y = (double)bsp->y; double v1dx = (double)bsp->dx; @@ -1786,7 +1777,7 @@ static bool GetIntersection(seg_t *seg, node_t *bsp, vertex_t *v) // //========================================================================== -static double PartitionDistance(vertex_t *vt, node_t *node) +static double PartitionDistance(FPolyVertex *vt, node_t *node) { return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len; } @@ -1823,7 +1814,7 @@ static void AddToBBox(fixed_t child[4], fixed_t parent[4]) // //========================================================================== -static void AddToBBox(vertex_t *v, fixed_t bbox[4]) +static void AddToBBox(FPolyVertex *v, fixed_t bbox[4]) { if (v->x < bbox[BOXLEFT]) { @@ -1851,7 +1842,7 @@ static void AddToBBox(vertex_t *v, fixed_t bbox[4]) static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) { - static TArray lists[2]; + static TArray lists[2]; static const double POLY_EPSILON = 0.3125; if (!((size_t)node & 1)) // Keep going until found a subsector @@ -1864,7 +1855,7 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) lists[1].Clear(); for(unsigned i=0;isegs.Size(); i++) { - seg_t *seg = &pnode->segs[i]; + FPolySeg *seg = &pnode->segs[i]; // Parts of the following code were taken from Eternity and are // being used with permission. @@ -1872,8 +1863,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) // get distance of vertices from partition line // If the distance is too small, we may decide to // change our idea of sidedness. - double dist_v1 = PartitionDistance(seg->v1, bsp); - double dist_v2 = PartitionDistance(seg->v2, bsp); + double dist_v1 = PartitionDistance(&seg->v1, bsp); + double dist_v2 = PartitionDistance(&seg->v2, bsp); // If the distances are less than epsilon, consider the points as being // on the same side as the polyobj origin. Why? People like to build @@ -1894,27 +1885,27 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) } else { - int side = R_PointOnSide(seg->v2->x, seg->v2->y, bsp); + int side = R_PointOnSide(seg->v2.x, seg->v2.y, bsp); lists[side].Push(*seg); } } else if (dist_v2 <= POLY_EPSILON) { - int side = R_PointOnSide(seg->v1->x, seg->v1->y, bsp); + int side = R_PointOnSide(seg->v1.x, seg->v1.y, bsp); lists[side].Push(*seg); } else { - int side1 = R_PointOnSide(seg->v1->x, seg->v1->y, bsp); - int side2 = R_PointOnSide(seg->v2->x, seg->v2->y, bsp); + int side1 = R_PointOnSide(seg->v1.x, seg->v1.y, bsp); + int side2 = R_PointOnSide(seg->v2.x, seg->v2.y, bsp); if(side1 != side2) { // if the partition line crosses this seg, we must split it. - vertex_t *vert = pnode->poly->GetNewVertex(); + FPolyVertex vert; - if (GetIntersection(seg, bsp, vert)) + if (GetIntersection(seg, bsp, &vert)) { lists[0].Push(*seg); lists[1].Push(*seg); @@ -1947,13 +1938,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) else { // create the new node - FPolyNode *newnode = new FPolyNode; - newnode->state = 1337; + FPolyNode *newnode = NewPolyNode(); newnode->poly = pnode->poly; - newnode->pnext = NULL; - newnode->pprev = NULL; - newnode->subsector = NULL; - newnode->snext = NULL; newnode->segs = lists[1]; // set segs for original node @@ -1995,8 +1981,8 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) for (unsigned i = 0; i < pnode->segs.Size(); ++i) { - AddToBBox(pnode->segs[i].v1, subbbox); - AddToBBox(pnode->segs[i].v2, subbbox); + AddToBBox(&pnode->segs[i].v1, subbbox); + AddToBBox(&pnode->segs[i].v2, subbbox); } // Potentially expand the parent node's bounding box to contain these bits of polyobject. AddToBBox(subbbox, bbox); @@ -2011,31 +1997,23 @@ static void SplitPoly(FPolyNode *pnode, void *node, fixed_t bbox[4]) void FPolyObj::CreateSubsectorLinks() { - FPolyNode *node = new FPolyNode; - fixed_t dummybbox[4]; + FPolyNode *node = NewPolyNode(); + // Even though we don't care about it, we need to initialize this + // bounding box to something so that Valgrind won't complain about it + // when SplitPoly modifies it. + fixed_t dummybbox[4] = { 0 }; - node->state = 1337; node->poly = this; - node->pnext = NULL; - node->pprev = NULL; - node->snext = NULL; node->segs.Resize(Sidedefs.Size()); for(unsigned i=0; isegs[i]; + FPolySeg *seg = &node->segs[i]; side_t *side = Sidedefs[i]; seg->v1 = side->V1(); seg->v2 = side->V2(); - seg->sidedef = side; - seg->linedef = side->linedef; - seg->frontsector = side->sector; - seg->backsector = side->linedef->frontsector == side->sector? - side->linedef->backsector : side->linedef->frontsector; - seg->Subsector = NULL; - seg->PartnerSeg = NULL; - seg->bPolySeg = true; + seg->wall = side; } SplitPoly(node, nodes + numnodes - 1, dummybbox); } @@ -2055,4 +2033,62 @@ void PO_LinkToSubsectors() polyobjs[i].CreateSubsectorLinks(); } } -} \ No newline at end of file +} + +//========================================================================== +// +// NewPolyNode +// +//========================================================================== + +static FPolyNode *NewPolyNode() +{ + FPolyNode *node; + + if (FreePolyNodes != NULL) + { + node = FreePolyNodes; + FreePolyNodes = node->pnext; + } + else + { + node = new FPolyNode; + } + node->state = 1337; + node->poly = NULL; + node->pnext = NULL; + node->pprev = NULL; + node->subsector = NULL; + node->snext = NULL; + return node; +} + +//========================================================================== +// +// FreePolyNode +// +//========================================================================== + +void FreePolyNode(FPolyNode *node) +{ + node->segs.Clear(); + node->pnext = FreePolyNodes; + FreePolyNodes = node; +} + +//========================================================================== +// +// ReleaseAllPolyNodes +// +//========================================================================== + +void ReleaseAllPolyNodes() +{ + FPolyNode *node, *next; + + for (node = FreePolyNodes; node != NULL; node = next) + { + next = node->pnext; + delete node; + } +} diff --git a/src/po_man.h b/src/po_man.h index 88565cbbf..3d963f33b 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -5,13 +5,32 @@ #include "r_defs.h" #include "m_bbox.h" + +struct FPolyVertex +{ + fixed_t x, y; + + FPolyVertex &operator=(vertex_t *v) + { + x = v->x; + y = v->y; + return *this; + } +}; + +struct FPolySeg +{ + FPolyVertex v1; + FPolyVertex v2; + side_t *wall; +}; + // // Linked lists of polyobjects // struct FPolyObj; struct FPolyNode { - int state; FPolyObj *poly; // owning polyobject FPolyNode *pnext; // next polyobj in list FPolyNode *pprev; // previous polyobj @@ -19,25 +38,8 @@ struct FPolyNode subsector_t *subsector; // containimg subsector FPolyNode *snext; // next subsector - TArray segs; // segs for this node - fixed_t dist; // distance for sorting -}; - -struct FPolyVertex -{ - fixed_t x, y; -}; - -struct FPolyVertexBlock -{ - int used; - vertex_t vertices[10]; - - void clear() - { - used = 0; - //memset(vertices, 0, sizeof(vertices)); - } + TArray segs; // segs for this node + int state; }; // ===== Polyobj data ===== @@ -51,8 +53,6 @@ struct FPolyObj FPolyVertex StartSpot; FPolyVertex CenterSpot; FBoundingBox Bounds; // Bounds in map coordinates - TDeletingArray SplitVertices; - unsigned int SVIndex; angle_t angle; int tag; // reference tag assigned in HereticEd @@ -77,7 +77,6 @@ struct FPolyObj void LinkPolyobj (); void CreateSubsectorLinks(); void ClearSubsectorLinks(); - vertex_t *GetNewVertex(); void CalcCenter(); static void ClearAllSubsectorLinks(); diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 5ba65cdd6..8eebac3d5 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -43,6 +43,7 @@ #include "r_things.h" #include "a_sharedglobal.h" #include "g_level.h" +#include "nodebuild.h" // State. #include "doomstat.h" @@ -108,6 +109,9 @@ WORD MirrorFlags; seg_t *ActiveWallMirror; TArray WallMirrors; +static FNodeBuilder::FLevel PolyNodeLevel; +static FNodeBuilder PolyNodeBuilder(PolyNodeLevel); + CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? @@ -1009,44 +1013,76 @@ void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el) } -static int STACK_ARGS polycmp(const void *a, const void *b) -{ - const FPolyNode *A = *(FPolyNode **)a; - const FPolyNode *B = *(FPolyNode **)b; - return A->dist - B->dist; + +//========================================================================== +// +// FMiniBSP Constructor +// +//========================================================================== + +FMiniBSP::FMiniBSP() +{ + bDirty = false; } +//========================================================================== +// +// P_BuildPolyBSP +// +//========================================================================== +static void R_BuildPolyBSP(subsector_t *sub) +{ + assert((sub->BSP == NULL || sub->BSP->bDirty) && "BSP computed more than once"); + + // Set up level information for the node builder. + PolyNodeLevel.Sides = sides; + PolyNodeLevel.NumSides = numsides; + PolyNodeLevel.Lines = lines; + PolyNodeLevel.NumLines = numlines; + + // Feed segs to the nodebuilder and build the nodes. + PolyNodeBuilder.Clear(); + PolyNodeBuilder.AddSegs(sub->firstline, sub->numlines); + for (FPolyNode *pn = sub->polys; pn != NULL; pn = pn->pnext) + { + PolyNodeBuilder.AddPolySegs(&pn->segs[0], (int)pn->segs.Size()); + } + PolyNodeBuilder.BuildMini(false); + if (sub->BSP == NULL) + { + sub->BSP = new FMiniBSP; + } + else + { + sub->BSP->bDirty = false; + } + PolyNodeBuilder.ExtractMini(sub->BSP); + for (unsigned int i = 0; i < sub->BSP->Subsectors.Size(); ++i) + { + sub->BSP->Subsectors[i].sector = sub->sector; + } +} + +void R_Subsector (subsector_t *sub); static void R_AddPolyobjs(subsector_t *sub) { - static TArray sortedpolys; - - FPolyNode *pn = sub->polys; - sortedpolys.Clear(); - while (pn != NULL) + if (sub->BSP == NULL || sub->BSP->bDirty) { - sortedpolys.Push(pn); - pn->dist = R_PointToDist2(pn->poly->CenterSpot.x - viewx, pn->poly->CenterSpot.y - viewy); - pn = pn->pnext; + R_BuildPolyBSP(sub); } - if (sortedpolys.Size() > 1) + if (sub->BSP->Nodes.Size() == 0) { - qsort(&sortedpolys[0], sortedpolys.Size(), sizeof (sortedpolys[0]), polycmp); + R_Subsector(&sub->BSP->Subsectors[0]); } - - for(unsigned i=0; isegs.Size(); j++) - { - R_AddLine(&pn->segs[j]); - } + R_RenderBSPNode(&sub->BSP->Nodes.Last()); } } - // // R_Subsector // Determine floor/ceiling planes. @@ -1061,15 +1097,25 @@ void R_Subsector (subsector_t *sub) int floorlightlevel; // killough 3/16/98: set floor lightlevel int ceilinglightlevel; // killough 4/11/98 +#if 0 #ifdef RANGECHECK if (sub - subsectors >= (ptrdiff_t)numsubsectors) I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors); #endif +#endif + + assert(sub->sector != NULL); + + if (sub->polys) + { // Render the polyobjs in the subsector first + R_AddPolyobjs(sub); + return; + } frontsector = sub->sector; frontsector->MoreFlags |= SECF_DRAWN; count = sub->numlines; - line = &segs[sub->firstline]; + line = sub->firstline; // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, @@ -1133,15 +1179,13 @@ void R_Subsector (subsector_t *sub) ceilinglightlevel : floorlightlevel, FakeSide); // [RH] Add particles - int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight); - for (WORD i = ParticlesInSubsec[(unsigned int)(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext) - { - R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide); - } - - if (sub->polys) - { // Render the polyobjs in the subsector first - R_AddPolyobjs(sub); + if ((unsigned int)(sub - subsectors) < (unsigned int)numsubsectors) + { // Only do it for the main BSP. + int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight); + for (WORD i = ParticlesInSubsec[(unsigned int)(sub-subsectors)]; i != NO_PARTICLE; i = Particles[i].snext) + { + R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide); + } } while (count--) diff --git a/src/r_defs.h b/src/r_defs.h index e6ad90448..8e0d779d2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -925,22 +925,7 @@ struct msecnode_t }; struct FPolyNode; - -// -// A SubSector. -// References a Sector. -// Basically, this is a list of LineSegs indicating the visible walls that -// define (all or some) sides of a convex BSP leaf. -// -struct subsector_t -{ - sector_t *sector; - DWORD numlines; - DWORD firstline; - FPolyNode *polys; - int validcount; - fixed_t CenterX, CenterY; -}; +struct FMiniBSP; // // The LineSeg. @@ -957,12 +942,27 @@ struct seg_t sector_t* frontsector; sector_t* backsector; // NULL for one-sided lines - subsector_t* Subsector; seg_t* PartnerSeg; BITFIELD bPolySeg:1; }; +// +// A SubSector. +// References a Sector. +// Basically, this is a list of LineSegs indicating the visible walls that +// define (all or some) sides of a convex BSP leaf. +// +struct subsector_t +{ + sector_t *sector; + FPolyNode *polys; + FMiniBSP *BSP; + seg_t *firstline; + DWORD numlines; +}; + + // @@ -985,6 +985,22 @@ struct node_t }; +// An entire BSP tree. + +struct FMiniBSP +{ + FMiniBSP(); + + bool bDirty; + + TArray Nodes; + TArray Segs; + TArray Subsectors; + TArray Verts; +}; + + + // posts are runs of non masked source pixels struct column_t { diff --git a/src/r_polymost.cpp b/src/r_polymost.cpp index 663c8ae61..2cb3e2225 100644 --- a/src/r_polymost.cpp +++ b/src/r_polymost.cpp @@ -1401,7 +1401,7 @@ void RP_Subsector (subsector_t *sub) frontsector = sub->sector; count = sub->numlines; - line = &segs[sub->firstline]; + line = sub->firstline; // killough 3/8/98, 4/4/98: Deep water / fake ceiling effect frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, diff --git a/src/r_segs.cpp b/src/r_segs.cpp index d1983342f..5bb3a09fc 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1480,17 +1480,17 @@ int side_t::GetLightLevel (bool foggy, int baselight, int *pfakecontrast) const if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) && linedef->dx != 0) { - rel = int // OMG LEE KILLOUGH LIVES! :/ + rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/ ( - (float(level.WallHorizLight) - +abs(atan(float(linedef->dy)/float(linedef->dx))/float(1.57079)) - *float(level.WallVertLight - level.WallHorizLight)) + level.WallHorizLight + + fabs(atan(double(linedef->dy) / linedef->dx) / 1.57079) + * (level.WallVertLight - level.WallHorizLight) ); } else { - rel = linedef->dx==0? level.WallVertLight : - linedef->dy==0? level.WallHorizLight : 0; + rel = linedef->dx == 0 ? level.WallVertLight : + linedef->dy == 0 ? level.WallHorizLight : 0; } if (pfakecontrast != NULL) { @@ -2008,80 +2008,12 @@ int WallMost (short *mostbuf, const secplane_t &plane) return bad; } -void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat) -{ // swall = scale, lwall = texturecolumn - int x; - float top, bot, i; - float xrepeat = (float)walxrepeat; - float ol, l, topinc, botinc; - - i = (float)(WallSX1 - centerx); - top = WallUoverZorg + WallUoverZstep * i; - bot = WallInvZorg + WallInvZstep * i; - topinc = WallUoverZstep * 4.f; - botinc = WallInvZstep * 4.f; - - x = WallSX1; - - l = top / bot; - swall[x] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg); - lwall[x] = xs_RoundToInt(l * xrepeat); - // As long as l is invalid, step one column at a time so that - // we can get as many correct texture columns as possible. - while (l > 1.0 && x+1 < WallSX2) - { - l = (top += WallUoverZstep) / (bot += WallInvZstep); - x++; - swall[x] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg); - lwall[x] = xs_RoundToInt(l * xrepeat); - } - l *= xrepeat; - while (x+4 < WallSX2) - { - top += topinc; bot += botinc; - ol = l; l = top / bot; - swall[x+4] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg); - lwall[x+4] = xs_RoundToInt(l *= xrepeat); - - i = (ol+l) * 0.5f; - lwall[x+2] = xs_RoundToInt(i); - lwall[x+1] = xs_RoundToInt((ol+i) * 0.5f); - lwall[x+3] = xs_RoundToInt((l+i) * 0.5f); - swall[x+2] = ((swall[x]+swall[x+4])>>1); - swall[x+1] = ((swall[x]+swall[x+2])>>1); - swall[x+3] = ((swall[x+4]+swall[x+2])>>1); - x += 4; - } - if (x+2 < WallSX2) - { - top += topinc * 0.5f; bot += botinc * 0.5f; - ol = l; l = top / bot; - swall[x+2] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg); - lwall[x+2] = xs_RoundToInt(l *= xrepeat); - - lwall[x+1] = xs_RoundToInt((l+ol)*0.5f); - swall[x+1] = (swall[x]+swall[x+2])>>1; - x += 2; - } - if (x+1 < WallSX2) - { - l = (top + WallUoverZstep) / (bot + WallInvZstep); - swall[x+1] = xs_RoundToInt(l * WallDepthScale + WallDepthOrg); - lwall[x+1] = xs_RoundToInt(l * xrepeat); - } - /* - for (x = WallSX1; x < WallSX2; x++) - { - frac = top / bot; - lwall[x] = xs_RoundToInt(frac * xrepeat); - swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg); - top += WallUoverZstep; - bot += WallInvZstep; - } - */ - +static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat) +{ // fix for rounding errors fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0; + int x; + if (WallSX1 > 0) { for (x = WallSX1; x < WallSX2; x++) @@ -2110,85 +2042,52 @@ void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat) } } -void PrepLWall (fixed_t *lwall, fixed_t walxrepeat) -{ // lwall = texturecolumn - int x; - float top, bot, i; - float xrepeat = (float)walxrepeat; - float ol, l, topinc, botinc; +void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat) +{ // swall = scale, lwall = texturecolumn + double top, bot, i; + double xrepeat = walxrepeat; + double topinc, botinc; - i = (float)(WallSX1 - centerx); + i = WallSX1 - centerx; top = WallUoverZorg + WallUoverZstep * i; bot = WallInvZorg + WallInvZstep * i; topinc = WallUoverZstep * 4.f; botinc = WallInvZstep * 4.f; - x = WallSX1; + for (int x = WallSX1; x < WallSX2; x++) + { + double frac = top / bot; + lwall[x] = xs_RoundToInt(frac * xrepeat); + swall[x] = xs_RoundToInt(frac * WallDepthScale + WallDepthOrg); + top += WallUoverZstep; + bot += WallInvZstep; + } + PrepWallRoundFix(lwall, walxrepeat); +} - l = top / bot; - lwall[x] = xs_RoundToInt(l * xrepeat); - // As long as l is invalid, step one column at a time so that - // we can get as many correct texture columns as possible. - while (l > 1.0 && x+1 < WallSX2) - { - l = (top += WallUoverZstep) / (bot += WallInvZstep); - lwall[++x] = xs_RoundToInt(l * xrepeat); - } - l *= xrepeat; - while (x+4 < WallSX2) - { - top += topinc; bot += botinc; - ol = l; l = top / bot; - lwall[x+4] = xs_RoundToInt(l *= xrepeat); +void PrepLWall (fixed_t *lwall, fixed_t walxrepeat) +{ // lwall = texturecolumn + double top, bot, i; + double xrepeat = walxrepeat; + double topinc, botinc; + double topstep; - i = (ol+l) * 0.5f; - lwall[x+2] = xs_RoundToInt(i); - lwall[x+1] = xs_RoundToInt((ol+i) * 0.5f); - lwall[x+3] = xs_RoundToInt((l+i) * 0.5f); - x += 4; - } - if (x+2 < WallSX2) - { - top += topinc * 0.5f; bot += botinc * 0.5f; - ol = l; l = top / bot; - lwall[x+2] = xs_RoundToInt(l *= xrepeat); - lwall[x+1] = xs_RoundToInt((l+ol)*0.5f); - x += 2; - } - if (x+1 < WallSX2) - { - l = (top + WallUoverZstep) / (bot + WallInvZstep); - lwall[x+1] = xs_RoundToInt(l * xrepeat); - } + i = WallSX1 - centerx; + top = WallUoverZorg + WallUoverZstep * i; + bot = WallInvZorg + WallInvZstep * i; + topinc = WallUoverZstep * 4.f; + botinc = WallInvZstep * 4.f; - // fix for rounding errors - fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0; - if (WallSX1 > 0) + top *= xrepeat; + topstep = WallUoverZstep * xrepeat; + + for (int x = WallSX1; x < WallSX2; x++) { - for (x = WallSX1; x < WallSX2; x++) - { - if ((unsigned)lwall[x] >= (unsigned)walxrepeat) - { - lwall[x] = fix; - } - else - { - break; - } - } - } - fix = walxrepeat - 1 - fix; - for (x = WallSX2-1; x >= WallSX1; x--) - { - if ((unsigned)lwall[x] >= (unsigned)walxrepeat) - { - lwall[x] = fix; - } - else - { - break; - } + lwall[x] = xs_RoundToInt(top / bot); + top += topstep; + bot += WallInvZstep; } + PrepWallRoundFix(lwall, walxrepeat); } // pass = 0: when seg is first drawn diff --git a/zdoom.vcproj b/zdoom.vcproj index 190b09e0c..913cff4a9 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - @@ -1880,6 +1872,14 @@ Outputs="$(IntDir)/$(InputName).obj" /> + + + @@ -2069,6 +2069,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -2079,14 +2087,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - + + + - - - + + + @@ -5379,14 +5387,6 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> - - - @@ -5665,7 +5665,7 @@ /> Date: Sun, 1 Aug 2010 04:31:18 +0000 Subject: [PATCH 137/251] - Changed the four-byte fillers in asm_x86_64/tmap3.s from 0x88888888 to 0x44444444 because newer version of gas complained about it. SVN r2481 (trunk) --- src/asm_x86_64/tmap3.s | 84 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/asm_x86_64/tmap3.s b/src/asm_x86_64/tmap3.s index 8a9b52e48..867d11c75 100644 --- a/src/asm_x86_64/tmap3.s +++ b/src/asm_x86_64/tmap3.s @@ -1,28 +1,28 @@ -#%include "valgrind.inc" +#%include "valgrind.inc" - .section .text + .section .text -.globl ASM_PatchPitch -ASM_PatchPitch: +.globl ASM_PatchPitch +ASM_PatchPitch: movl dc_pitch(%rip), %ecx movl %ecx, pm+3(%rip) - movl %ecx, vltpitch+3(%rip) -# selfmod pm, vltpitch+6 - ret - .align 16 + movl %ecx, vltpitch+3(%rip) +# selfmod pm, vltpitch+6 + ret + .align 16 -.globl setupvlinetallasm +.globl setupvlinetallasm setupvlinetallasm: movb %dil, shifter1+2(%rip) movb %dil, shifter2+2(%rip) movb %dil, shifter3+2(%rip) - movb %dil, shifter4+2(%rip) -# selfmod shifter1, shifter4+3 + movb %dil, shifter4+2(%rip) +# selfmod shifter1, shifter4+3 ret - .align 16 - - .section .rtext,"awx" - + .align 16 + + .section .rtext,"awx" + .globl vlinetallasm4 .type vlinetallasm4,@function vlinetallasm4: @@ -38,18 +38,18 @@ vlinetallasm4: subq $8, %rsp # Does the stack need to be 16-byte aligned for Linux? .cfi_adjust_cfa_offset 8 -# rax = bufplce base address -# rbx = -# rcx = offset from rdi/count (negative) -# edx/rdx = scratch -# rdi = bottom of columns to write to -# r8d-r11d = column offsets -# r12-r15 = palookupoffse[0] - palookupoffse[4] +# rax = bufplce base address +# rbx = +# rcx = offset from rdi/count (negative) +# edx/rdx = scratch +# rdi = bottom of columns to write to +# r8d-r11d = column offsets +# r12-r15 = palookupoffse[0] - palookupoffse[4] movl dc_count(%rip), %ecx movq dc_dest(%rip), %rdi testl %ecx, %ecx - jle vltepilog # count must be positive + jle vltepilog # count must be positive movq bufplce(%rip), %rax movq bufplce+8(%rip), %r8 @@ -60,14 +60,14 @@ vlinetallasm4: subq %rax, %r10 movl %r8d, source2+4(%rip) movl %r9d, source3+4(%rip) - movl %r10d, source4+4(%rip) + movl %r10d, source4+4(%rip) -pm: imulq $320, %rcx +pm: imulq $320, %rcx movq palookupoffse(%rip), %r12 movq palookupoffse+8(%rip), %r13 movq palookupoffse+16(%rip), %r14 - movq palookupoffse+24(%rip), %r15 + movq palookupoffse+24(%rip), %r15 movl vince(%rip), %r8d movl vince+4(%rip), %r9d @@ -76,53 +76,53 @@ pm: imulq $320, %rcx movl %r8d, step1+3(%rip) movl %r9d, step2+3(%rip) movl %r10d, step3+3(%rip) - movl %r11d, step4+3(%rip) + movl %r11d, step4+3(%rip) addq %rcx, %rdi - negq %rcx + negq %rcx movl vplce(%rip), %r8d movl vplce+4(%rip), %r9d movl vplce+8(%rip), %r10d movl vplce+12(%rip), %r11d # selfmod loopit, vltepilog - jmp loopit + jmp loopit - .align 16 + .align 16 loopit: movl %r8d, %edx shifter1: shrl $24, %edx -step1: addl $0x88888888, %r8d +step1: addl $0x44444444, %r8d movzbl (%rax,%rdx), %edx movl %r9d, %ebx movb (%r12,%rdx), %dl shifter2: shrl $24, %ebx -step2: addl $0x88888888, %r9d -source2: movzbl 0x88888888(%rax,%rbx), %ebx +step2: addl $0x44444444, %r9d +source2: movzbl 0x44444444(%rax,%rbx), %ebx movl %r10d, %ebp movb (%r13,%rbx), %bl shifter3: shr $24, %ebp -step3: addl $0x88888888, %r10d -source3: movzbl 0x88888888(%rax,%rbp), %ebp +step3: addl $0x44444444, %r10d +source3: movzbl 0x44444444(%rax,%rbp), %ebp movl %r11d, %esi movb (%r14,%rbp), %bpl shifter4: shr $24, %esi -step4: add $0x88888888, %r11d -source4: movzbl 0x88888888(%rax,%rsi), %esi +step4: add $0x44444444, %r11d +source4: movzbl 0x44444444(%rax,%rsi), %esi movb %dl, (%rdi,%rcx) movb %bl, 1(%rdi,%rcx) movb (%r15,%rsi), %sil movb %bpl, 2(%rdi,%rcx) movb %sil, 3(%rdi,%rcx) -vltpitch: addq $320, %rcx - jl loopit +vltpitch: addq $320, %rcx + jl loopit movl %r8d, vplce(%rip) movl %r9d, vplce+4(%rip) movl %r10d, vplce+8(%rip) - movl %r11d, vplce+12(%rip) - + movl %r11d, vplce+12(%rip) + vltepilog: addq $8, %rsp .cfi_adjust_cfa_offset -8 @@ -137,5 +137,5 @@ vltepilog: ret .cfi_endproc .align 16 - + From 58269a18f0359da2f0ba3ab4da80ca87c6be1f8d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 05:16:09 +0000 Subject: [PATCH 138/251] - Use a flood-fill algorithm to define polyobjects with PolyObj_StartLine instead of a simple loop-following algorithm. This fixes the polyobjects in http://www.doomworld.com/idgames/index.php?id=6291 SVN r2482 (trunk) --- src/p_setup.cpp | 30 ++++++------------------- src/p_setup.h | 23 +++++++++++++++++++ src/po_man.cpp | 60 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 69 insertions(+), 44 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 452cb0dcf..4df7a367e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -128,27 +128,8 @@ FLightStack* LightStacks; TArray MapThingsConverted; int sidecount; -struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init -{ - union - { - // Used when unpacking sidedefs and assigning - // properties based on linedefs. - struct - { - short tag, special; - short alpha; - DWORD map; - } a; +sidei_t *sidetemp; - // Used when grouping sidedefs into loops. - struct - { - DWORD first, next; - char lineside; - } b; - }; -} *sidetemp; TArray linemap; bool UsingGLNodes; @@ -2261,9 +2242,8 @@ static void P_LoopSidedefs () sides[right].LeftSide = i; } - // Throw away sidedef init info now that we're done with it - delete[] sidetemp; - sidetemp = NULL; + // We keep the sidedef init info around until after polyobjects are initialized, + // so don't delete just yet. } int P_DetermineTranslucency (int lumpnum) @@ -3866,6 +3846,10 @@ void P_SetupLevel (char *lumpname, int position) PO_Init (); // Initialize the polyobjs times[16].Unclock(); + assert(sidetemp != NULL); + delete[] sidetemp; + sidetemp = NULL; + // if deathmatch, randomly spawn the active players if (deathmatch) { diff --git a/src/p_setup.h b/src/p_setup.h index c751c989c..80196e317 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -111,4 +111,27 @@ int P_TranslateSectorSpecial (int); int GetUDMFInt(int type, int index, const char *key); fixed_t GetUDMFFixed(int type, int index, const char *key); +struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init +{ + union + { + // Used when unpacking sidedefs and assigning + // properties based on linedefs. + struct + { + short tag, special; + short alpha; + DWORD map; + } a; + + // Used when grouping sidedefs into loops. + struct + { + DWORD first, next; + char lineside; + } b; + }; +}; +extern sidei_t *sidetemp; + #endif diff --git a/src/po_man.cpp b/src/po_man.cpp index c240e28fa..93662f64e 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -27,6 +27,7 @@ #include "r_interpolate.h" #include "g_level.h" #include "po_man.h" +#include "p_setup.h" // MACROS ------------------------------------------------------------------ @@ -1334,41 +1335,58 @@ static void KillSideLists () KnownPolySides.ShrinkToFit (); } +//========================================================================== +// +// AddPolyVert +// +// Helper function for IterFindPolySides() +// +//========================================================================== + +static void AddPolyVert(TArray &vnum, DWORD vert) +{ + for (unsigned int i = vnum.Size() - 1; i-- != 0; ) + { + if (vnum[i] == vert) + { // Already in the set. No need to add it. + return; + } + } + vnum.Push(vert); +} + //========================================================================== // // IterFindPolySides // +// Beginning with the first vertex of the starting side, for each vertex +// in vnum, add all the sides that use it as a first vertex to the polyobj, +// and add all their second vertices to vnum. This continues until there +// are no new vertices in vnum. +// //========================================================================== static void IterFindPolySides (FPolyObj *po, side_t *side) { - SDWORD j; - int i; - vertex_t *v1 = side->V1(); + static TArray vnum; + unsigned int vnumat; - po->Sidedefs.Push(side); + assert(sidetemp != NULL); - // This for loop exists solely to avoid infinitely looping on badly - // formed polyobjects. - for (i = 0; i < numsides; i++) + vnum.Clear(); + vnum.Push(DWORD(side->V1() - vertexes)); + vnumat = 0; + + while (vnum.Size() != vnumat) { - int v2 = int(side->V2() - vertexes); - j = side->RightSide; - - if (j == NO_SIDE) + DWORD sidenum = sidetemp[vnum[vnumat++]].b.first; + while (sidenum != NO_SIDE) { - break; + po->Sidedefs.Push(&sides[sidenum]); + AddPolyVert(vnum, DWORD(sides[sidenum].V2() - vertexes)); + sidenum = sidetemp[sidenum].b.next; } - side = &sides[j]; - - if (side->V1() == v1) - { - return; - } - po->Sidedefs.Push(side); } - I_Error ("IterFindPolySides: Non-closed Polyobj at linedef %d.\n", - side->linedef-lines); } From b9ea9a415e4568d1b79d1df451fc8a3afde0b0ba Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 19:14:10 +0000 Subject: [PATCH 139/251] - Added Polyobj_MoveTo, Polyobj_OR_MoveTo, and Polyobj_Stop. - Cleaned up a couple of warnings. SVN r2483 (trunk) --- src/actionspecials.h | 3 + src/nodebuild.cpp | 6 +- src/p_lnspec.cpp | 24 +++++- src/p_local.h | 3 +- src/po_man.cpp | 200 +++++++++++++++++++++++++++++++++++++++---- src/po_man.h | 2 +- src/vectors.h | 12 +-- 7 files changed, 219 insertions(+), 31 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index de2d86bfb..392efecb4 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -85,6 +85,9 @@ DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5, 5) DEFINE_SPECIAL(ACS_ExecuteWithResult, 84, 1, 4, 4) DEFINE_SPECIAL(ACS_LockedExecuteDoor, 85, 5, 5, 5) +DEFINE_SPECIAL(Polyobj_Stop, 87, 1, 1, 1) +DEFINE_SPECIAL(Polyobj_MoveTo, 88, 4, 4, 4) +DEFINE_SPECIAL(Polyobj_OR_MoveTo, 89, 4, 4, 4) DEFINE_SPECIAL(Polyobj_OR_RotateLeft, 90, 3, 3, 3) DEFINE_SPECIAL(Polyobj_OR_RotateRight, 91, 3, 3, 3) DEFINE_SPECIAL(Polyobj_OR_Move, 92, 4, 4, 4) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 804190fee..8298e9017 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -228,7 +228,7 @@ void FNodeBuilder::CreateSubsectorsForReal () set = ptr.SegPtr->next; } sub.numlines = (DWORD)(SegList.Size() - firstline); - sub.firstline = (seg_t *)firstline; + sub.firstline = (seg_t *)(size_t)firstline; // Sort segs by linedef for special effects qsort (&SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs); @@ -1107,12 +1107,12 @@ int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVe if (CPU.bSSE2) { func = ClassifyLineSSE2; - diff = (char *)ClassifyLineSSE2 - (char *)calleroffset; + diff = int((char *)ClassifyLineSSE2 - (char *)calleroffset); } else { func = ClassifyLine2; - diff = (char *)ClassifyLine2 - (char *)calleroffset; + diff = int((char *)ClassifyLine2 - (char *)calleroffset); } calleroffset--; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index fb0bd31ab..61df5806d 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -121,6 +121,12 @@ FUNC(LS_Polyobj_MoveTimes8) return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT * 8, false); } +FUNC(LS_Polyobj_MoveTo) +// Polyobj_MoveTo (po, speed, x, y) +{ + return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2, arg3, false); +} + FUNC(LS_Polyobj_DoorSwing) // Polyobj_DoorSwing (po, speed, angle, delay) { @@ -157,6 +163,18 @@ FUNC(LS_Polyobj_OR_MoveTimes8) return EV_MovePoly (ln, arg0, SPEED(arg1), BYTEANGLE(arg2), arg3 * FRACUNIT * 8, true); } +FUNC(LS_Polyobj_OR_MoveTo) +// Polyobj_OR_MoveTo (po, speed, x, y) +{ + return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2, arg3, true); +} + +FUNC(LS_Polyobj_Stop) +// Polyobj_Stop (po) +{ + return EV_StopPoly (arg0); +} + FUNC(LS_Door_Close) // Door_Close (tag, speed, lighttag) { @@ -3060,9 +3078,9 @@ lnSpecFunc LineSpecials[256] = /* 84 */ LS_ACS_ExecuteWithResult, /* 85 */ LS_ACS_LockedExecuteDoor, /* 86 */ LS_NOP, - /* 87 */ LS_NOP, - /* 88 */ LS_NOP, - /* 89 */ LS_NOP, + /* 87 */ LS_Polyobj_Stop, + /* 88 */ LS_Polyobj_MoveTo, + /* 89 */ LS_Polyobj_OR_MoveTo, /* 90 */ LS_Polyobj_OR_RotateLeft, /* 91 */ LS_Polyobj_OR_RotateRight, /* 92 */ LS_Polyobj_OR_Move, diff --git a/src/p_local.h b/src/p_local.h index eb69a23c7..6978be19d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -506,8 +506,9 @@ typedef enum bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); +bool EV_MovePolyTo (line_t *line, int polyNum, int speed, int x, int y, bool overRide); bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); - +bool EV_StopPoly (int polyNum); // [RH] Data structure for P_SpawnMapThing() to keep track diff --git a/src/po_man.cpp b/src/po_man.cpp index 93662f64e..535d1f2dc 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -28,6 +28,7 @@ #include "g_level.h" #include "po_man.h" #include "p_setup.h" +#include "vectors.h" // MACROS ------------------------------------------------------------------ @@ -62,6 +63,7 @@ public: DPolyAction (int polyNum); void Serialize (FArchive &arc); void Destroy(); + void Stop(); int GetSpeed() const { return m_Speed; } void StopInterpolation (); @@ -104,6 +106,23 @@ protected: friend bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); }; +class DMovePolyTo : public DPolyAction +{ + DECLARE_CLASS(DMovePolyTo, DPolyAction) +public: + DMovePolyTo(int polyNum); + void Serialize(FArchive &arc); + void Tick(); +protected: + DMovePolyTo(); + fixed_t m_xSpeed; + fixed_t m_ySpeed; + fixed_t m_xTarget; + fixed_t m_yTarget; + + friend bool EV_MovePolyTo(line_t *line, int polyNum, int speed, int x, int y, bool overRide); +}; + class DPolyDoor : public DMovePoly { @@ -199,7 +218,7 @@ void DPolyAction::Destroy() { FPolyObj *poly = PO_GetPolyobj (m_PolyObj); - if (poly->specialdata == NULL || poly->specialdata == this) + if (poly->specialdata == this) { poly->specialdata = NULL; } @@ -208,6 +227,13 @@ void DPolyAction::Destroy() Super::Destroy(); } +void DPolyAction::Stop() +{ + FPolyObj *poly = PO_GetPolyobj(m_PolyObj); + SN_StopSequence(poly); + Destroy(); +} + void DPolyAction::SetInterpolation () { FPolyObj *poly = PO_GetPolyobj (m_PolyObj); @@ -266,6 +292,34 @@ DMovePoly::DMovePoly (int polyNum) m_ySpeed = 0; } +//========================================================================== +// +// +// +// +//========================================================================== + +IMPLEMENT_CLASS(DMovePolyTo) + +DMovePolyTo::DMovePolyTo() +{ +} + +void DMovePolyTo::Serialize(FArchive &arc) +{ + Super::Serialize(arc); + arc << m_xSpeed << m_ySpeed << m_xTarget << m_yTarget; +} + +DMovePolyTo::DMovePolyTo(int polyNum) + : Super(polyNum) +{ + m_xSpeed = 0; + m_ySpeed = 0; + m_xTarget = 0; + m_yTarget = 0; +} + //========================================================================== // // @@ -318,10 +372,6 @@ void DRotatePoly::Tick () m_Dist -= absSpeed; if (m_Dist == 0) { - if (poly->specialdata == this) - { - poly->specialdata = NULL; - } SN_StopSequence (poly); Destroy (); } @@ -433,10 +483,6 @@ void DMovePoly::Tick () m_Dist -= absSpeed; if (m_Dist <= 0) { - if (poly->specialdata == this) - { - poly->specialdata = NULL; - } SN_StopSequence (poly); Destroy (); } @@ -522,6 +568,111 @@ bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, return true; } +//========================================================================== +// +// DMovePolyTo :: Tick +// +//========================================================================== + +void DMovePolyTo::Tick () +{ + FPolyObj *poly = PO_GetPolyobj (m_PolyObj); + + if (poly != NULL) + { + if (poly->MovePolyobj (m_xSpeed, m_ySpeed)) + { + int absSpeed = abs (m_Speed); + m_Dist -= absSpeed; + if (m_Dist <= 0) + { + SN_StopSequence (poly); + Destroy (); + } + else if (m_Dist < absSpeed) + { + m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); + m_xSpeed = m_xTarget - poly->StartSpot.x; + m_ySpeed = m_yTarget - poly->StartSpot.y; + } + } + } +} + +//========================================================================== +// +// EV_MovePolyTo +// +//========================================================================== + +bool EV_MovePolyTo(line_t *line, int polyNum, int speed, int ix, int iy, bool overRide) +{ + fixed_t targx = ix << FRACBITS; + fixed_t targy = iy << FRACBITS; + int mirror; + DMovePolyTo *pe; + FPolyObj *poly; + TVector2 dist; + double distlen; + bool nointerp; + + if ( (poly = PO_GetPolyobj(polyNum)) ) + { + if (poly->specialdata && !overRide) + { // poly is already moving + return false; + } + } + else + { + Printf("EV_MovePolyTo: Invalid polyobj num: %d\n", polyNum); + return false; + } + dist.X = targx - poly->StartSpot.x; + dist.Y = targy - poly->StartSpot.y; + pe = new DMovePolyTo(polyNum); + poly->specialdata = pe; + pe->m_Dist = xs_RoundToInt(distlen = dist.MakeUnit()); + pe->m_Speed = speed; + pe->m_xSpeed = xs_RoundToInt(speed * dist.X); + pe->m_ySpeed = xs_RoundToInt(speed * dist.Y); + pe->m_xTarget = targx; + pe->m_yTarget = targy; + + nointerp = (pe->m_Dist / pe->m_Speed) <= 2; + if (nointerp) + { + pe->StopInterpolation(); + } + + while ( (mirror = poly->GetMirror()) ) + { + poly = PO_GetPolyobj(mirror); + if (poly && poly->specialdata && !overRide) + { // mirroring poly is already in motion + break; + } + // reverse the direction + dist.X = -dist.X; + dist.Y = -dist.Y; + pe = new DMovePolyTo(mirror); + poly->specialdata = pe; + pe->m_Dist = xs_RoundToInt(distlen); + pe->m_Speed = speed; + pe->m_xSpeed = xs_RoundToInt(speed * dist.X); + pe->m_ySpeed = xs_RoundToInt(speed * dist.Y); + pe->m_xTarget = xs_RoundToInt(poly->StartSpot.x + distlen * dist.X); + pe->m_yTarget = xs_RoundToInt(poly->StartSpot.y + distlen * dist.Y); + polyNum = mirror; + SN_StartSequence(poly, poly->seqType, SEQ_DOOR, 0); + if (nointerp) + { + pe->StopInterpolation(); + } + } + return true; +} + //========================================================================== // // T_PolyDoor @@ -564,10 +715,6 @@ void DPolyDoor::Tick () } else { - if (poly->specialdata == this) - { - poly->specialdata = NULL; - } Destroy (); } } @@ -612,10 +759,6 @@ void DPolyDoor::Tick () } else { - if (poly->specialdata == this) - { - poly->specialdata = NULL; - } Destroy (); } } @@ -719,7 +862,28 @@ bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, } return true; } - + +//========================================================================== +// +// EV_StopPoly +// +//========================================================================== + +bool EV_StopPoly(int polynum) +{ + FPolyObj *poly; + + if (NULL != (poly = PO_GetPolyobj(polynum))) + { + if (poly->specialdata != NULL) + { + poly->specialdata->Stop(); + } + return true; + } + return false; +} + // ===== Higher Level Poly Interface code ===== //========================================================================== diff --git a/src/po_man.h b/src/po_man.h index 3d963f33b..d76dff55f 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -63,7 +63,7 @@ struct FPolyObj int seqType; fixed_t size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) FPolyNode *subsectorlinks; - DThinker *specialdata; // pointer to a thinker, if the poly is moving + DPolyAction *specialdata; // pointer to a thinker, if the poly is moving TObjPtr interpolation; FPolyObj(); diff --git a/src/vectors.h b/src/vectors.h index 013077042..c0783e250 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -242,12 +242,14 @@ struct TVector2 return *this * len; } - // Scales this vector into a unit vector - void MakeUnit() + // Scales this vector into a unit vector. Returns the old length + double MakeUnit() { - double len = Length(); - if (len != 0) len = 1 / len; - *this *= len; + double len, ilen; + len = ilen = Length(); + if (ilen != 0) ilen = 1 / ilen; + *this *= ilen; + return len; } // Dot product From fc6e48dd3f61dd4f473c6d0e9b9495dd56edf90b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 19:50:41 +0000 Subject: [PATCH 140/251] - Fixed: FPolyObj::LinkPolyobj() did not add the polyobject's first side to the polyobject's bounding box. It should also add both vertices from each side, since non-closed polyobjects are possible with PolyObj_ExplicitLine. SVN r2485 (trunk) --- src/po_man.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index 535d1f2dc..e0597190c 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1314,20 +1314,18 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) void FPolyObj::LinkPolyobj () { - int leftX, rightX; - int topY, bottomY; polyblock_t **link; polyblock_t *tempLink; // calculate the polyobj bbox - vertex_t *vt = Sidedefs[0]->V1(); - rightX = leftX = vt->x; - topY = bottomY = vt->y; - Bounds.ClearBox(); - for(unsigned i = 1; i < Sidedefs.Size(); i++) + for(unsigned i = 0; i < Sidedefs.Size(); i++) { - vt = Sidedefs[i]->V1(); + vertex_t *vt; + + vt = Sidedefs[i]->linedef->v1; + Bounds.AddToBox(vt->x, vt->y); + vt = Sidedefs[i]->linedef->v2; Bounds.AddToBox(vt->x, vt->y); } bbox[BOXRIGHT] = (Bounds.Right() - bmaporgx) >> MAPBLOCKSHIFT; From b2d018eccd83bd9e54041d90aca5d120555bd669 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 20:05:52 +0000 Subject: [PATCH 141/251] - Made SBARINFO more tolerant of certain error conditions. (Why is there so much duplication of code? It felt like I was changing the same lines over and over and over.) SVN r2486 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 95 ++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 26 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index a40b8d2a0..8339a3592 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -93,7 +93,10 @@ class CommandDrawImage : public SBarInfoCommand else if(sc.Compare("amulet")) type = HEXENARMOR_AMULET; else - sc.ScriptError("Unkown armor type: '%s'", sc.String); + { + sc.ScriptMessage("Unkown armor type: '%s'", sc.String); + type = HEXENARMOR_ARMOR; + } sc.MustGetToken(','); getImage = true; } @@ -108,9 +111,12 @@ class CommandDrawImage : public SBarInfoCommand const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + } + else + { + sprite = ((AInventory *)GetDefaultByType(item))->Icon; } - sprite = ((AInventory *)GetDefaultByType(item))->Icon; image = -1; } } @@ -324,7 +330,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } GetOperation(sc, conditionalOperator[0], conditionalValue[0]); } @@ -349,7 +355,7 @@ class CommandDrawSwitchableImage : public CommandDrawImage const PClass* item = PClass::FindClass(sc.String); if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); } GetOperation(sc, conditionalOperator[1], conditionalValue[1]); } @@ -529,7 +535,10 @@ class CommandDrawString : public SBarInfoCommand sc.MustGetToken(TK_Identifier); font = V_GetFont(sc.String); if(font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); + { + sc.ScriptMessage("Unknown font '%s'.", sc.String); + font = SmallFont; + } sc.MustGetToken(','); translation = GetTranslation(sc); sc.MustGetToken(','); @@ -807,7 +816,10 @@ class CommandDrawNumber : public CommandDrawString sc.MustGetToken(TK_Identifier); font = V_GetFont(sc.String); if(font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); + { + sc.ScriptMessage("Unknown font '%s'.", sc.String); + font = SmallFont; + } sc.MustGetToken(','); normalTranslation = GetTranslation(sc); sc.MustGetToken(','); @@ -837,7 +849,8 @@ class CommandDrawNumber : public CommandDrawString inventoryItem = PClass::FindClass(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); + sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); + inventoryItem = RUNTIME_CLASS(AAmmo); } } else if(sc.Compare("ammocapacity")) @@ -847,7 +860,8 @@ class CommandDrawNumber : public CommandDrawString inventoryItem = PClass::FindClass(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); + sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); + inventoryItem = RUNTIME_CLASS(AAmmo); } } else if(sc.Compare("frags")) @@ -889,18 +903,20 @@ class CommandDrawNumber : public CommandDrawString value = POWERUPTIME; sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) { - sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); + sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); + inventoryItem = RUNTIME_CLASS(APowerupGiver); } } else { value = INVENTORY; inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of ammo + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + inventoryItem = RUNTIME_CLASS(AInventory); } } sc.MustGetToken(','); @@ -1333,7 +1349,10 @@ class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private { font = V_GetFont(sc.String); if(font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); + { + sc.ScriptMessage("Unknown font '%s'.", sc.String); + font = SmallFont; + } sc.MustGetToken(','); break; } @@ -1815,7 +1834,10 @@ class CommandDrawInventoryBar : public SBarInfoCommand sc.MustGetToken(TK_Identifier); font = V_GetFont(sc.String); if(font == NULL) + { sc.ScriptError("Unknown font '%s'.", sc.String); + font = SmallFont; + } sc.MustGetToken(','); GetCoordinates(sc, fullScreenOffsets, x, y); @@ -2098,8 +2120,11 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier)) //comparing reference { inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory + { + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + inventoryItem = RUNTIME_CLASS(AInventory); + } } } else if(sc.Compare("armor")) @@ -2108,8 +2133,11 @@ class CommandDrawBar : public SBarInfoCommand if(sc.CheckToken(TK_Identifier)) { inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory + { + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + inventoryItem = RUNTIME_CLASS(AInventory); + } } } else if(sc.Compare("ammo1")) @@ -2123,7 +2151,8 @@ class CommandDrawBar : public SBarInfoCommand inventoryItem = PClass::FindClass(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); + sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); + inventoryItem = RUNTIME_CLASS(AAmmo); } } else if(sc.Compare("frags")) @@ -2141,9 +2170,10 @@ class CommandDrawBar : public SBarInfoCommand type = POWERUPTIME; sc.MustGetToken(TK_Identifier); inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) { - sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); + sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); + inventoryItem = RUNTIME_CLASS(APowerupGiver); } } else @@ -2152,7 +2182,8 @@ class CommandDrawBar : public SBarInfoCommand inventoryItem = PClass::FindClass(sc.String); if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + inventoryItem = RUNTIME_CLASS(AInventory); } } sc.MustGetToken(','); @@ -2401,7 +2432,10 @@ class CommandIsSelected : public SBarInfoCommandFlowControl { weapon[i] = PClass::FindClass(sc.String); if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i])) - sc.ScriptError("'%s' is not a type of weapon.", sc.String); + { + sc.ScriptMessage("'%s' is not a type of weapon.", sc.String); + weapon[i] = RUNTIME_CLASS(AWeapon); + } if(sc.CheckToken(',')) { @@ -2503,7 +2537,10 @@ class CommandHasWeaponPiece : public SBarInfoCommandFlowControl sc.MustGetToken(TK_Identifier); weapon = PClass::FindClass(sc.String); if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon - sc.ScriptError("%s is not a kind of weapon.", sc.String); + { + sc.ScriptMessage("%s is not a kind of weapon.", sc.String); + weapon = RUNTIME_CLASS(AWeapon); + } sc.MustGetToken(','); sc.MustGetToken(TK_IntConst); if(sc.Number < 1) @@ -2692,7 +2729,10 @@ class CommandWeaponAmmo : public SBarInfoCommandFlowControl { ammo[i] = PClass::FindClass(sc.String); if(ammo[i] == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo[i])) //must be a kind of ammo - sc.ScriptError("'%s' is not a type of ammo.", sc.String); + { + sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); + ammo[i] = RUNTIME_CLASS(AAmmo); + } if(sc.CheckToken(TK_OrOr)) { @@ -2792,7 +2832,10 @@ class CommandInInventory : public SBarInfoCommandFlowControl { item[i] = PClass::FindClass(sc.String); if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + { + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + item[i] = RUNTIME_CLASS(AInventory); + } if (sc.CheckToken(',')) { From 9a025fbb2399e0124a8f06034c18c3437b18ecef Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Aug 2010 20:21:04 +0000 Subject: [PATCH 142/251] - Changed xtoviewangle[] calculation so that when it mirrors the array to the left half, it does not include xtoviewangle[centerx] in the mirroring so that the two columns at the center of the screen do not map to the same angle. (BTW, this array is only used for the sky drawing.) SVN r2487 (trunk) --- src/r_main.cpp | 2 +- src/r_plane.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index cbacb93a5..93131b149 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -472,7 +472,7 @@ void R_InitTextureMapping () } for (i = 0; i < centerx; i++) { - xtoviewangle[i] = (angle_t)(-(signed)xtoviewangle[viewwidth-i-1]); + xtoviewangle[i] = (angle_t)(-(signed)xtoviewangle[viewwidth-i]); } } diff --git a/src/r_plane.cpp b/src/r_plane.cpp index aae870fbe..b89a2979e 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -740,6 +740,10 @@ inline void R_MakeSpans (int x, int t1, int b1, int t2, int b2, void (*mapfunc)( // in the normal convention for patches, but uses color 0 as a transparent // color instead. // +// Note that since ZDoom now uses color 0 as transparent for other purposes, +// you can use normal texture transparency, so the distinction isn't so +// important anymore, but you should still be aware of it. +// //========================================================================== static FTexture *frontskytex, *backskytex; From b59162a33a811d6811ece840ff8017b5168c5da8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 7 Aug 2010 03:36:56 +0000 Subject: [PATCH 143/251] - Fixed: Floor_RaiseAndCrush did not subtract 8 from the lowest ceiling's height when determining a destination height. (It did subtract 8, but in the wrong place.) SVN r2490 (trunk) --- src/p_floor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 00407a36c..fa3a01e09 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -358,7 +358,7 @@ manual_floor: floor->m_Direction = 1; newheight = sec->FindLowestCeilingSurrounding (&spot); if (floortype == DFloor::floorRaiseAndCrush) - floor->m_FloorDestDist -= 8 * FRACUNIT; + newheight -= 8 * FRACUNIT; ceilingheight = sec->FindLowestCeilingPoint (&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); if (sec->floorplane.ZatPointDist (spot2, floor->m_FloorDestDist) > ceilingheight) From cb6e9b90fb99eb1bca219d9b7e70a0e5fecfac95 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 7 Aug 2010 03:57:22 +0000 Subject: [PATCH 144/251] - Added r_clearbuffer cvar. Valid values are: * 0. Do not clear. This is the standard behavior. * 1. Clear to black. * 2. Clear to white. * 3. Alternate between black and white every 128 ms. * 4. Step through the palette one color at a time every 32 ms. * 5. Epileptic seizure inducing random colors every frame. SVN r2491 (trunk) --- src/r_main.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/r_main.cpp b/src/r_main.cpp index 93131b149..e3008862f 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -100,6 +100,7 @@ static float CurrentVisibility = 8.f; static fixed_t MaxVisForWall; static fixed_t MaxVisForFloor; static FRandom pr_torchflicker ("TorchFlicker"); +static FRandom pr_hom ("HOM-Flasher"); static TArray PastViewers; static int centerxwide; static bool polyclipped; @@ -111,6 +112,7 @@ bool r_dontmaplines; CVAR (String, r_viewsize, "", CVAR_NOSET) CVAR (Int, r_polymost, 0, 0) CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE) +CVAR (Int, r_clearbuffer, 0, 0) fixed_t r_BaseVisibility; fixed_t r_WallVisibility; @@ -1270,6 +1272,34 @@ void R_SetupFrame (AActor *actor) { polyclipped = RP_SetupFrame (false); } + + if (RenderTarget == screen && r_clearbuffer != 0) + { + int color; + int hom = r_clearbuffer; + + if (hom == 3) + { + hom = ((I_FPSTime() / 128) & 1) + 1; + } + if (hom == 1) + { + color = GPalette.BlackIndex; + } + else if (hom == 2) + { + color = GPalette.WhiteIndex; + } + else if (hom == 4) + { + color = (I_FPSTime() / 32) & 255; + } + else + { + color = pr_hom(); + } + memset(RenderTarget->GetBuffer(), color, RenderTarget->GetPitch() * RenderTarget->GetHeight()); + } } //========================================================================== From 9137ef04f6c7b3195accfa6c2b0db6c592c9fad7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 7 Aug 2010 04:32:18 +0000 Subject: [PATCH 145/251] - Added "SoundSequence" UDMF sector property. This is the name of the sound sequence to play for the sector. Note that this contrasts with sound sequence things in that it takes a name and not a number. Also, placing a sound sequence thing in a sector will override this property. SVN r2492 (trunk) --- src/namedef.h | 1 + src/p_buildmap.cpp | 1 + src/p_ceiling.cpp | 4 ++++ src/p_doors.cpp | 6 +++++- src/p_floor.cpp | 4 ++++ src/p_pillar.cpp | 8 ++++++++ src/p_plats.cpp | 8 ++++++++ src/p_saveg.cpp | 9 +++++++++ src/p_setup.cpp | 1 + src/p_udmf.cpp | 7 ++++++- src/r_defs.h | 1 + 11 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index 4ee1e7c0f..94e0c97bd 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -417,6 +417,7 @@ xx(Gravity) xx(Lightcolor) xx(Fadecolor) xx(Desaturation) +xx(SoundSequence) xx(Silent) xx(Nofallingdamage) xx(Dropactors) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 86d7575ad..afc6d5277 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -432,6 +432,7 @@ static void LoadSectors (sectortype *bsec) sec->lightlevel = (sec->GetPlaneLight(sector_t::floor) + sec->GetPlaneLight(sector_t::ceiling)) / 2; sec->seqType = -1; + sec->SeqName = NAME_None; sec->nextsec = -1; sec->prevsec = -1; sec->gravity = 1.f; diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 4dd072a06..c9aec4f37 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -65,6 +65,10 @@ void DCeiling::PlayCeilingSound () { SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false); } + else if (m_Sector->SeqName != NAME_None) + { + SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->SeqName, 0); + } else { if (m_Silent == 2) diff --git a/src/p_doors.cpp b/src/p_doors.cpp index ccfd61c5d..e82adbe4c 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -237,6 +237,10 @@ void DDoor::DoorSound (bool raise) const { SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_DOOR, choice); } + else if (m_Sector->SeqName != NAME_None) + { + SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->SeqName, choice); + } else { const char *snd; @@ -424,7 +428,7 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, // Otherwise, just let the current one continue. // FIXME: This should be check if the sound sequence has separate up/down // paths, not if it was manually set. - if (sec->seqType == -1 || SN_CheckSequence(sec, CHAN_CEILING) == NULL) + if ((sec->seqType < 0 && sec->SeqName == NAME_None) || SN_CheckSequence(sec, CHAN_CEILING) == NULL) { door->DoorSound (false); } diff --git a/src/p_floor.cpp b/src/p_floor.cpp index fa3a01e09..3fff563f8 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -44,6 +44,10 @@ static void StartFloorSound (sector_t *sec) { SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0); } + else if (sec->SeqName != NAME_None) + { + SN_StartSequence (sec, CHAN_FLOOR, sec->SeqName, 0); + } else { SN_StartSequence (sec, CHAN_FLOOR, "Floor", 0); diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 1d2d5ba81..4faed647f 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -190,9 +190,17 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed, } if (sector->seqType >= 0) + { SN_StartSequence (sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); + } + else if (sector->SeqName != NAME_None) + { + SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0); + } else + { SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0); + } } bool EV_DoPillar (DPillar::EPillar type, int tag, fixed_t speed, fixed_t height, diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 87d9e6737..9e57f4baf 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -57,9 +57,17 @@ void DPlat::Serialize (FArchive &arc) void DPlat::PlayPlatSound (const char *sound) { if (m_Sector->seqType >= 0) + { SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0); + } + else if (m_Sector->SeqName != NAME_None) + { + SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->SeqName, 0); + } else + { SN_StartSequence (m_Sector, CHAN_FLOOR, sound, 0); + } } // diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 783517764..1ee18eeb2 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -348,6 +348,15 @@ void P_SerializeWorld (FArchive &arc) << sec->interpolations[2] << sec->interpolations[3]; + if (SaveVersion < 2492) + { + sec->SeqName = NAME_None; + } + else + { + arc << sec->SeqName; + } + sec->e->Serialize(arc); if (arc.IsStoring ()) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 4df7a367e..a324a393a 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1407,6 +1407,7 @@ void P_LoadSectors (MapData * map) ss->thinglist = NULL; ss->touching_thinglist = NULL; // phares 3/14/98 ss->seqType = defSeqType; + ss->SeqName = NAME_None; ss->nextsec = -1; //jff 2/26/98 add fields to support locking out ss->prevsec = -1; // stair retriggering until build completes diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 6cbfccbef..c057c253c 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1024,7 +1024,7 @@ struct UDMFParser sec->SetYScale(sector_t::ceiling, FRACUNIT); sec->thinglist = NULL; sec->touching_thinglist = NULL; // phares 3/14/98 - sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL)? 0:-1; + sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL) ? 0 : -1; sec->nextsec = -1; //jff 2/26/98 add fields to support locking out sec->prevsec = -1; // stair retriggering until build completes sec->heightsec = NULL; // sector used to get floor and ceiling height @@ -1175,6 +1175,11 @@ struct UDMFParser Flag(sec->Flags, SECF_FLOORDROP, key); continue; + case NAME_SoundSequence: + sec->SeqName = CheckString(key); + sec->seqType = -1; + continue; + default: break; } diff --git a/src/r_defs.h b/src/r_defs.h index 8e0d779d2..3c8ab46d7 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -640,6 +640,7 @@ struct sector_t int sky; short seqType; // this sector's sound sequence + FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this. fixed_t soundorg[2]; // origin for any sounds played by the sector int validcount; // if == validcount, already checked From 1cabac3c5f18343920c345b844efd6cc452c8d68 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 00:57:52 +0000 Subject: [PATCH 146/251] - Added SoundSequence sector property to udmf_zdoom.txt. SVN r2493 (trunk) --- specs/udmf_zdoom.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index e0ec43925..5ceb573aa 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -161,6 +161,8 @@ Note: All fields default to false unless mentioned otherwise. nofallingdamage = ; // Falling damage is disabled in this sector dropactors = ; // Actors drop with instantly moving floors (*) norespawn = ; // Players can not respawn in this sector + soundsequence = ; // The sound sequence to play when this sector moves. Placing a + // sound sequence thing in the sector will override this property. * Note about dropactors @@ -263,6 +265,9 @@ Changed node specifications to deprecate compression of node lump. 1.10 25.04.2010 Added 'playeruseback' line trigger flag. +1.11 07.08.2010 +Added 'soundsequnce' sector property. + =============================================================================== EOF =============================================================================== From f5a1aa994b4d6c1f5308c75ed7c3941d59f05124 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 00:59:40 +0000 Subject: [PATCH 147/251] - pr_hom shouldn't have a name, since we don't care about it for save games or network sync. SVN r2494 (trunk) --- src/r_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index e3008862f..fa25f7ca1 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -100,7 +100,7 @@ static float CurrentVisibility = 8.f; static fixed_t MaxVisForWall; static fixed_t MaxVisForFloor; static FRandom pr_torchflicker ("TorchFlicker"); -static FRandom pr_hom ("HOM-Flasher"); +static FRandom pr_hom; static TArray PastViewers; static int centerxwide; static bool polyclipped; From d32d8b4f9f858be151b4d60b69dd3dc60a90b436 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 01:28:20 +0000 Subject: [PATCH 148/251] - Removed TheInvisibleCursor, since passing NULL to SetCursor() has exactly the same effect. - Two tweaks to raw mouse input to make it better behaved when the window suddenly has focus removed (e.g. because of a debugger break): * Keep the pointer centered in the window, as for Win32Mouse. Even though it's not generating any traditional input events, it's still moving all over the screen. e.g. If we have focus yanked away and you're pressing the right mouse button as it happens, you can suddenly find yourself with a popup menu open. * Use SetCursorState() like the other mouse modes instead of ShowCursor() to hide the pointer. This way, we don't need to worry about being stuck with trying to use the system with an invisible pointer, because only the game window will be pointer-less. SVN r2495 (trunk) --- src/win32/cursor1.cur | Bin 326 -> 0 bytes src/win32/i_main.cpp | 3 +- src/win32/i_mouse.cpp | 89 ++++++++++++++++++++++-------------------- src/win32/zdoom.rc | 7 ---- 4 files changed, 48 insertions(+), 51 deletions(-) delete mode 100644 src/win32/cursor1.cur diff --git a/src/win32/cursor1.cur b/src/win32/cursor1.cur deleted file mode 100644 index 048f06b4aefde54e0ff825ccb5a5db4d7001d513..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 326 zcmZQzU}9ioP*7k10|Q0|1~DK@1BexX*a3(cfe;L!6oi8y|NsAw;0zE8=!O9W0CiJ? AlK=n! diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index a76380bda..e590fbd3b 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -118,7 +118,7 @@ extern BYTE *ST_Util_BitsForBitmap (BITMAPINFO *bitmap_info); extern EXCEPTION_POINTERS CrashPointers; extern BITMAPINFO *StartupBitmap; extern UINT TimerPeriod; -extern HCURSOR TheArrowCursor, TheInvisibleCursor; +extern HCURSOR TheArrowCursor; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -931,7 +931,6 @@ void DoMain (HINSTANCE hInstance) x = y = 0; } - TheInvisibleCursor = LoadCursor (hInstance, MAKEINTRESOURCE(IDC_INVISIBLECURSOR)); TheArrowCursor = LoadCursor (NULL, IDC_ARROW); WNDCLASS WndClass; diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index 80c00bdbe..87de7269a 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -87,8 +87,6 @@ public: void Ungrab(); protected: - void CenterMouse(int x, int y); - POINT UngrabbedPointerPos; LONG PrevX, PrevY; bool Grabbed; @@ -112,6 +110,7 @@ static void SetCursorState(bool visible); static FMouse *CreateWin32Mouse(); static FMouse *CreateDInputMouse(); static FMouse *CreateRawMouse(); +static void CenterMouse(int x, int y, LONG *centx, LONG *centy); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -136,7 +135,6 @@ static FMouse *(*MouseFactory[])() = FMouse *Mouse; HCURSOR TheArrowCursor; -HCURSOR TheInvisibleCursor; CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -183,7 +181,7 @@ CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) static void SetCursorState(bool visible) { - HCURSOR usingCursor = visible ? TheArrowCursor : TheInvisibleCursor; + HCURSOR usingCursor = visible ? TheArrowCursor : NULL; SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)usingCursor); if (GetForegroundWindow() == Window) { @@ -191,6 +189,37 @@ static void SetCursorState(bool visible) } } +//========================================================================== +// +// CenterMouse +// +// Moves the mouse to the center of the window, but only if the current +// position isn't already in the center. +// +//========================================================================== + +static void CenterMouse(int curx, int cury, LONG *centxp, LONG *centyp) +{ + RECT rect; + + GetWindowRect(Window, &rect); + + int centx = (rect.left + rect.right) >> 1; + int centy = (rect.top + rect.bottom) >> 1; + + // Reduce the number of WM_MOUSEMOVE messages that get sent + // by only calling SetCursorPos when we really need to. + if (centx != curx || centy != cury) + { + if (centxp != NULL) + { + *centxp = centx; + *centyp = centy; + } + SetCursorPos(centx, centy); + } +} + //========================================================================== // // CaptureMode_InGame @@ -512,12 +541,11 @@ void FRawMouse::Grab() { GetCursorPos(&UngrabbedPointerPos); Grabbed = true; - while (ShowCursor(FALSE) >= 0) - { } + SetCursorState(false); // By setting the cursor position, we force the pointer image // to change right away instead of having it delayed until // some time in the future. - SetCursorPos(0, 0); + CenterMouse(-1, -1, NULL, NULL); } } } @@ -543,7 +571,7 @@ void FRawMouse::Ungrab() Grabbed = false; ClearButtonState(); } - ShowCursor(TRUE); + SetCursorState(true); SetCursorPos(UngrabbedPointerPos.x, UngrabbedPointerPos.y); } } @@ -586,8 +614,13 @@ bool FRawMouse::ProcessRawInput(RAWINPUT *raw, int code) { WheelMoved(1, (SHORT)raw->data.mouse.usButtonData); } - PostMouseMove(m_noprescale ? raw->data.mouse.lLastX : raw->data.mouse.lLastX<<2, - -raw->data.mouse.lLastY); + int x = m_noprescale ? raw->data.mouse.lLastX : raw->data.mouse.lLastX << 2; + int y = -raw->data.mouse.lLastY; + PostMouseMove(x, y); + if (x | y) + { + CenterMouse(-1, -1, NULL, NULL); + } return true; } @@ -920,7 +953,7 @@ void FWin32Mouse::ProcessInput() } if (x | y) { - CenterMouse(pt.x, pt.y); + CenterMouse(pt.x, pt.y, &PrevX, &PrevY); } PostMouseMove(x, y); } @@ -944,13 +977,13 @@ bool FWin32Mouse::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa { if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) { - CenterMouse(-1, -1); + CenterMouse(-1, -1, &PrevX, &PrevY); return true; } } else if (message == WM_MOVE) { - CenterMouse(-1, -1); + CenterMouse(-1, -1, &PrevX, &PrevY); return true; } else if (message == WM_SYSCOMMAND) @@ -1059,7 +1092,7 @@ void FWin32Mouse::Grab() ClipCursor(&rect); SetCursorState(false); - CenterMouse(-1, -1); + CenterMouse(-1, -1, &PrevX, &PrevY); Grabbed = true; } @@ -1085,34 +1118,6 @@ void FWin32Mouse::Ungrab() ClearButtonState(); } -//========================================================================== -// -// FWin32Mouse :: CenterMouse -// -// Moves the mouse to the center of the window, but only if the current -// position isn't already in the center. -// -//========================================================================== - -void FWin32Mouse::CenterMouse(int curx, int cury) -{ - RECT rect; - - GetWindowRect (Window, &rect); - - int centx = (rect.left + rect.right) >> 1; - int centy = (rect.top + rect.bottom) >> 1; - - // Reduce the number of WM_MOUSEMOVE messages that get sent - // by only calling SetCursorPos when we really need to. - if (centx != curx || centy != cury) - { - PrevX = centx; - PrevY = centy; - SetCursorPos (centx, centy); - } -} - /**************************************************************************/ /**************************************************************************/ diff --git a/src/win32/zdoom.rc b/src/win32/zdoom.rc index 7c953edac..bddfc1347 100644 --- a/src/win32/zdoom.rc +++ b/src/win32/zdoom.rc @@ -444,13 +444,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// Cursor -// - -IDC_INVISIBLECURSOR CURSOR "cursor1.cur" - ///////////////////////////////////////////////////////////////////////////// // // Bitmap From 600021788966b2b53ffc592810ebdf81247aa5b4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 01:53:41 +0000 Subject: [PATCH 149/251] - Hide the cursor by overriding WM_SETCURSOR, as seen in the IDirect3DDEvice9::ShowCursor() example. Do not modify the window class pointer. I still had an instance where I was left with an invisible pointer no matter where I moved it, so hopefully this takes care of that. (edit: it doesn't.) SVN r2496 (trunk) --- src/win32/i_input.cpp | 9 +++++++++ src/win32/i_main.cpp | 5 +---- src/win32/i_mouse.cpp | 14 ++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index e9d2a26bb..d01547dae 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -147,6 +147,7 @@ EXTERN_CVAR (Bool, lookstrafe) EXTERN_CVAR (Bool, use_joystick) static int WheelDelta; +extern bool CursorState; extern BOOL paused; static bool noidle = false; @@ -418,6 +419,14 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) I_CheckNativeMouse (false); break; + case WM_SETCURSOR: + if (!CursorState) + { + SetCursor(NULL); // turn off window cursor + return TRUE; // Prevent Windows from setting cursor to window class cursor + } + break; + case WM_SIZE: InvalidateRect (Window, NULL, FALSE); break; diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index e590fbd3b..808ae4fbe 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -118,7 +118,6 @@ extern BYTE *ST_Util_BitsForBitmap (BITMAPINFO *bitmap_info); extern EXCEPTION_POINTERS CrashPointers; extern BITMAPINFO *StartupBitmap; extern UINT TimerPeriod; -extern HCURSOR TheArrowCursor; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -931,8 +930,6 @@ void DoMain (HINSTANCE hInstance) x = y = 0; } - TheArrowCursor = LoadCursor (NULL, IDC_ARROW); - WNDCLASS WndClass; WndClass.style = 0; WndClass.lpfnWndProc = LConProc; @@ -940,7 +937,7 @@ void DoMain (HINSTANCE hInstance) WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1)); - WndClass.hCursor = TheArrowCursor; + WndClass.hCursor = LoadCursor (NULL, IDC_ARROW); WndClass.hbrBackground = NULL; WndClass.lpszMenuName = NULL; WndClass.lpszClassName = (LPCTSTR)WinClassName; diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index 87de7269a..fc55c0456 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -134,7 +134,7 @@ static FMouse *(*MouseFactory[])() = FMouse *Mouse; -HCURSOR TheArrowCursor; +bool CursorState; CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -181,11 +181,17 @@ CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) static void SetCursorState(bool visible) { - HCURSOR usingCursor = visible ? TheArrowCursor : NULL; - SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)usingCursor); + CursorState = visible; if (GetForegroundWindow() == Window) { - SetCursor(usingCursor); + if (visible) + { + SetCursor((HCURSOR)(intptr_t)GetClassLongPtr(Window, GCLP_HCURSOR)); + } + else + { + SetCursor(NULL); + } } } From 6234e7445b440cbd53c2b4aee78966949af098d5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 02:04:47 +0000 Subject: [PATCH 150/251] - Added m_hidepointer cvar to control whether or not the mouse pointer is hidden when it's grabbed. At least if the pointer is visible when the debugger break happens, I don't worry about it getting stuck hidden. (Note that that seems to be related to Alt+Tabbing out of the game and coming back. I wish I knew what's going on.) SVN r2497 (trunk) --- src/win32/i_mouse.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index fc55c0456..af595dea5 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -136,9 +136,10 @@ FMouse *Mouse; bool CursorState; -CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, m_hidepointer, true, 0) CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { @@ -181,10 +182,10 @@ CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) static void SetCursorState(bool visible) { - CursorState = visible; + CursorState = visible || !m_hidepointer; if (GetForegroundWindow() == Window) { - if (visible) + if (CursorState) { SetCursor((HCURSOR)(intptr_t)GetClassLongPtr(Window, GCLP_HCURSOR)); } From 100731e3abafae8730f0cdcb5b7be943e4432337 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 8 Aug 2010 02:19:40 +0000 Subject: [PATCH 151/251] - Shorten the description of DF2_KILLBOSSMONST in the menu. SVN r2498 (trunk) --- src/m_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index ddfd0f897..7cef6242e 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1054,7 +1054,7 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Allow spying", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DISALLOW_SPYING} }, { bitflag, "Chasecam cheat", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_CHASECAM} }, { bitflag, "Check ammo for weapon switch", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DONTCHECKAMMO} }, - { bitflag, "Killing boss brain kills all its monsters", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_KILLBOSSMONST} }, + { bitflag, "Killing Romero kills all his spawns", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_KILLBOSSMONST} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, { whitetext,"Deathmatch Settings", {NULL}, {0}, {0}, {0}, {NULL} }, From 79ff9ae3aef614ab7963d66698446b9c2306f5c7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 10 Aug 2010 08:13:23 +0000 Subject: [PATCH 152/251] - fixed: FNodeBuilder::ExtractMini needs to check for segs that were created from minisegs. - made polyobject node building code more update friendly for GZDoom by making R_BuildPolyBSP public. SVN r2500 (trunk) --- src/g_shared/a_armor.cpp | 4 ++-- src/nodebuild_extract.cpp | 12 ++++++++++-- src/r_bsp.cpp | 2 +- src/r_bsp.h | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 6dd39885d..6bed525d8 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -217,7 +217,7 @@ AInventory *ABasicArmorPickup::CreateCopy (AActor *other) copy->MaxFullAbsorb = MaxFullAbsorb; if (!(ItemFlags & IF_IGNORESKILL)) - { // extra ammo in baby mode and nightmare mode + { SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); } @@ -300,7 +300,7 @@ AInventory *ABasicArmorBonus::CreateCopy (AActor *other) copy->MaxFullAbsorb = MaxFullAbsorb; if (!(ItemFlags & IF_IGNORESKILL)) - { // extra ammo in baby mode and nightmare mode + { SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); } return copy; diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index 24fadcf3b..d8675aa6e 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -224,8 +224,16 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp) out->v2 = &bsp->Verts[org->v2]; out->backsector = org->backsector; out->frontsector = org->frontsector; - out->linedef = Level.Lines + org->linedef; - out->sidedef = Level.Sides + org->sidedef; + if (org->sidedef != int(NO_SIDE)) + { + out->linedef = Level.Lines + org->linedef; + out->sidedef = Level.Sides + org->sidedef; + } + else // part of a miniseg + { + out->linedef = NULL; + out->sidedef = NULL; + } out->PartnerSeg = NULL; out->bPolySeg = false; } diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 8eebac3d5..71d4f210a 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1032,7 +1032,7 @@ FMiniBSP::FMiniBSP() // //========================================================================== -static void R_BuildPolyBSP(subsector_t *sub) +void R_BuildPolyBSP(subsector_t *sub) { assert((sub->BSP == NULL || sub->BSP->bDirty) && "BSP computed more than once"); diff --git a/src/r_bsp.h b/src/r_bsp.h index 5701647a7..d8b00ec2a 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -75,6 +75,7 @@ EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs? // BSP? void R_ClearClipSegs (short left, short right); void R_ClearDrawSegs (); +void R_BuildPolyBSP(subsector_t *sub); void R_RenderBSPNode (void *node); // killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: From 5d5f25fdabb3c60776acd135d5d2e55a0efdd20b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 10 Aug 2010 16:22:57 +0000 Subject: [PATCH 153/251] - fixed: Changing APROP_Friendly in ACS did not adjust the monster count. - fixed: AActor::CanSeek had the check for the visibility of the target actor's alpha reversed. - added an Alt HUD icon for Hexen's fighter's fist. SVN r2501 (trunk) --- src/p_acs.cpp | 6 ++++++ src/p_mobj.cpp | 4 ++-- wadsrc/static/althudcf.txt | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index df3ff8173..fc1c5f0fc 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2662,9 +2662,15 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) case APROP_Friendly: if (value) + { + if (actor->CountsAsKill()) level.total_monsters--; actor->flags |= MF_FRIENDLY; + } else + { actor->flags &= ~MF_FRIENDLY; + if (actor->CountsAsKill()) level.total_monsters++; + } break; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 390bbbb47..16c70ef18 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1491,8 +1491,8 @@ bool AActor::CanSeek(AActor *target) const if (target->flags5 & MF5_CANTSEEK) return false; if ((flags2 & MF2_DONTSEEKINVISIBLE) && ((target->flags & MF_SHADOW) || - target->renderflags & RF_INVISIBLE || - target->RenderStyle.IsVisible(target->alpha) + (target->renderflags & RF_INVISIBLE) || + !target->RenderStyle.IsVisible(target->alpha) ) ) return false; return true; diff --git a/wadsrc/static/althudcf.txt b/wadsrc/static/althudcf.txt index 524561180..957b381bf 100644 --- a/wadsrc/static/althudcf.txt +++ b/wadsrc/static/althudcf.txt @@ -1,4 +1,5 @@ Fist PUNGC0 PunchDagger PNCHD0 +FWeapFist FPCHC0 Beak "" Snout "" From 25cb3593ce50c7731c5e2b50d7b4f8b2e43861d1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 10 Aug 2010 18:30:18 +0000 Subject: [PATCH 154/251] - Added GetPolyobjX and GetPolyobjY ACS functions. SVN r2502 (trunk) --- src/p_acs.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index fc1c5f0fc..9dddbcf7c 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -70,6 +70,7 @@ #include "cmdlib.h" #include "m_png.h" #include "p_setup.h" +#include "po_man.h" #include "g_shared/a_pickups.h" @@ -3030,6 +3031,8 @@ enum EACSFunctions ACSF_SoundSequenceOnActor, ACSF_SoundSequenceOnSector, ACSF_SoundSequenceOnPolyobj, + ACSF_GetPolyobjX, + ACSF_GetPolyobjY, }; int DLevelScript::SideFromID(int id, int side) @@ -3433,6 +3436,26 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } break; + case ACSF_GetPolyobjX: + { + FPolyObj *poly = PO_GetPolyobj(args[0]); + if (poly != NULL) + { + return poly->StartSpot.x; + } + } + return FIXED_MAX; + + case ACSF_GetPolyobjY: + { + FPolyObj *poly = PO_GetPolyobj(args[0]); + if (poly != NULL) + { + return poly->StartSpot.y; + } + } + return FIXED_MAX; + default: break; } From 482d7631f4c61d653240a4c8380a86705c7b2fc8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 10 Aug 2010 19:06:33 +0000 Subject: [PATCH 155/251] - sorted zspecials.acs properly so one can find all the specials. - added Polyobj_MoveToSpot action specials. They are functionally identical to Polyobj_MoveTo but get the target coordinate from a map spot instead. SVN r2503 (trunk) --- src/actionspecials.h | 6 ++++-- src/p_lnspec.cpp | 28 +++++++++++++++++++++++----- src/p_local.h | 2 +- src/po_man.cpp | 6 ++---- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 392efecb4..7f855147e 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -57,7 +57,7 @@ DEFINE_SPECIAL(Line_SetBlocking, 55, 3, 3, 3) DEFINE_SPECIAL(Line_SetTextureScale, 56, 5, 5, 5) DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5) DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2) - +DEFINE_SPECIAL(Polyobj_OR_MoveToSpot, 59, 3, 3, 3) DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3) DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1) DEFINE_SPECIAL(Plat_DownWaitUpStay, 62, 3, 3, 3) @@ -84,7 +84,7 @@ DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2, 2) DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5, 5) DEFINE_SPECIAL(ACS_ExecuteWithResult, 84, 1, 4, 4) DEFINE_SPECIAL(ACS_LockedExecuteDoor, 85, 5, 5, 5) - +DEFINE_SPECIAL(Polyobj_MoveToSpot, 86, 3, 3, 3) DEFINE_SPECIAL(Polyobj_Stop, 87, 1, 1, 1) DEFINE_SPECIAL(Polyobj_MoveTo, 88, 4, 4, 4) DEFINE_SPECIAL(Polyobj_OR_MoveTo, 89, 4, 4, 4) @@ -114,7 +114,9 @@ DEFINE_SPECIAL(Plane_Copy, 118, -1, -1, 5) DEFINE_SPECIAL(Thing_Damage, 119, 2, 3, 3) DEFINE_SPECIAL(Radius_Quake, 120, 5, 5, 5) // Earthquake DEFINE_SPECIAL(Line_SetIdentification, 121, -1, -1, 5) + DEFINE_SPECIAL(Thing_Move, 125, 2, 3, 3) + DEFINE_SPECIAL(Thing_SetSpecial, 127, 5, 5, 5) DEFINE_SPECIAL(ThrustThingZ, 128, 4, 4, 4) DEFINE_SPECIAL(UsePuzzleItem, 129, 2, 5, 5) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 61df5806d..72bea5c49 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -124,7 +124,16 @@ FUNC(LS_Polyobj_MoveTimes8) FUNC(LS_Polyobj_MoveTo) // Polyobj_MoveTo (po, speed, x, y) { - return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2, arg3, false); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2 << FRACBITS, arg3 << FRACBITS, false); +} + +FUNC(LS_Polyobj_MoveToSpot) +// Polyobj_MoveToSpot (po, speed, tid) +{ + FActorIterator iterator (arg2); + AActor *spot = iterator.Next(); + if (spot == NULL) return false; + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, false); } FUNC(LS_Polyobj_DoorSwing) @@ -166,7 +175,16 @@ FUNC(LS_Polyobj_OR_MoveTimes8) FUNC(LS_Polyobj_OR_MoveTo) // Polyobj_OR_MoveTo (po, speed, x, y) { - return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2, arg3, true); + return EV_MovePolyTo (ln, arg0, SPEED(arg1), arg2 << FRACBITS, arg3 << FRACBITS, true); +} + +FUNC(LS_Polyobj_OR_MoveToSpot) +// Polyobj_OR_MoveToSpot (po, speed, tid) +{ + FActorIterator iterator (arg2); + AActor *spot = iterator.Next(); + if (spot == NULL) return false; + return EV_MovePolyTo (ln, arg0, SPEED(arg1), spot->x, spot->y, true); } FUNC(LS_Polyobj_Stop) @@ -3049,8 +3067,8 @@ lnSpecFunc LineSpecials[256] = /* 55 */ LS_Line_SetBlocking, /* 56 */ LS_Line_SetTextureScale, /* 57 */ LS_NOP, // Sector_SetPortal - /* 58 */ LS_NOP, - /* 59 */ LS_NOP, + /* 58 */ LS_NOP, // Sector_CopyScroller + /* 59 */ LS_Polyobj_OR_MoveToSpot, /* 60 */ LS_Plat_PerpetualRaise, /* 61 */ LS_Plat_Stop, /* 62 */ LS_Plat_DownWaitUpStay, @@ -3077,7 +3095,7 @@ lnSpecFunc LineSpecials[256] = /* 83 */ LS_ACS_LockedExecute, /* 84 */ LS_ACS_ExecuteWithResult, /* 85 */ LS_ACS_LockedExecuteDoor, - /* 86 */ LS_NOP, + /* 86 */ LS_Polyobj_MoveToSpot, /* 87 */ LS_Polyobj_Stop, /* 88 */ LS_Polyobj_MoveTo, /* 89 */ LS_Polyobj_OR_MoveTo, diff --git a/src/p_local.h b/src/p_local.h index 6978be19d..91b134605 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -506,7 +506,7 @@ typedef enum bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); -bool EV_MovePolyTo (line_t *line, int polyNum, int speed, int x, int y, bool overRide); +bool EV_MovePolyTo (line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); bool EV_StopPoly (int polyNum); diff --git a/src/po_man.cpp b/src/po_man.cpp index e0597190c..1ca8d9a3a 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -120,7 +120,7 @@ protected: fixed_t m_xTarget; fixed_t m_yTarget; - friend bool EV_MovePolyTo(line_t *line, int polyNum, int speed, int x, int y, bool overRide); + friend bool EV_MovePolyTo(line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); }; @@ -605,10 +605,8 @@ void DMovePolyTo::Tick () // //========================================================================== -bool EV_MovePolyTo(line_t *line, int polyNum, int speed, int ix, int iy, bool overRide) +bool EV_MovePolyTo(line_t *line, int polyNum, int speed, fixed_t targx, fixed_t targy, bool overRide) { - fixed_t targx = ix << FRACBITS; - fixed_t targy = iy << FRACBITS; int mirror; DMovePolyTo *pe; FPolyObj *poly; From e0bd67de5a4dd7c2f3e986cfd714e09936608a39 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 10 Aug 2010 19:22:43 +0000 Subject: [PATCH 156/251] - added: If a PowerFlight item got a valid icon don't use the spinning wings for the HUD display SVN r2504 (trunk) --- src/g_shared/a_artifacts.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 088e480c5..c4f0f9d6a 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1004,6 +1004,12 @@ void APowerFlight::EndEffect () bool APowerFlight::DrawPowerup (int x, int y) { + // If this item got a valid icon use that instead of the default spinning wings. + if (Icon.isValid()) + { + return Super::DrawPowerup(x, y); + } + if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16)) { FTextureID picnum = TexMan.CheckForTexture ("SPFLY0", FTexture::TEX_MiscPatch); From 3416a7fc4752f0f5192efd6af7bfa3a84179eefb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 11 Aug 2010 03:56:31 +0000 Subject: [PATCH 157/251] - Fix compilation with MinGW + w32api and clean up warnings. SVN r2505 (trunk) --- src/compatibility.cpp | 10 ++++---- src/dobject.cpp | 2 +- src/m_misc.cpp | 2 +- src/p_enemy.cpp | 2 +- src/p_mobj.cpp | 2 +- src/r_segs.cpp | 42 ++++++++++++++++++++++++++------- src/sound/fmodsound.cpp | 2 +- src/sound/music_mus_midiout.cpp | 2 +- src/win32/win32video.cpp | 2 ++ 9 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index b93cb68f2..e091a7f1e 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -185,7 +185,7 @@ void ParseCompatibility() } while (!sc.Compare("{")); flags.CompatFlags = 0; flags.BCompatFlags = 0; - flags.ExtCommandIndex = -1; + flags.ExtCommandIndex = ~0u; while (sc.GetString()) { if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0) @@ -195,7 +195,7 @@ void ParseCompatibility() } else if (sc.Compare("clearlineflags")) { - if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_CLEARFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); @@ -204,7 +204,7 @@ void ParseCompatibility() } else if (sc.Compare("setlineflags")) { - if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETFLAGS); sc.MustGetNumber(); CompatParams.Push(sc.Number); @@ -213,7 +213,7 @@ void ParseCompatibility() } else if (sc.Compare("setlinespecial")) { - if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size(); + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); CompatParams.Push(CP_SETSPECIAL); sc.MustGetNumber(); CompatParams.Push(sc.Number); @@ -232,7 +232,7 @@ void ParseCompatibility() break; } } - if (flags.ExtCommandIndex != -1) + if (flags.ExtCommandIndex != ~0u) { CompatParams.Push(CP_END); } diff --git a/src/dobject.cpp b/src/dobject.cpp index 073be864f..3bd815bd6 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -190,7 +190,7 @@ const char *FMetaTable::GetMetaString (DWORD id) const CCMD (dumpactors) { - char * filters[32] = + const char *const filters[32] = { "0:All", "1:Doom", "2:Heretic", "3:DoomHeretic", "4:Hexen", "5:DoomHexen", "6:Raven", "7:IdRaven", "8:Strife", "9:DoomStrife", "10:HereticStrife", "11:DoomHereticStrife", "12:HexenStrife", diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 1f8b9f3e6..324095d5c 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -167,7 +167,7 @@ void M_FindResponseFile (void) int argc = 0; FILE *handle; int size; - long argsize; + long argsize = 0; int index; // Any more response files after the limit will be removed from the diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index e982ea0d0..cbbd8797f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2688,7 +2688,7 @@ void A_FaceTarget (AActor *self, angle_t max_turn) // 0 means no limit. Also, if we turn in a single step anyways, no need to go through the algorithms. // It also means that there is no need to check for going past the target. - if (max_turn && (max_turn < abs(self->angle - target_angle))) + if (max_turn && (max_turn < (angle_t)abs(self->angle - target_angle))) { if (self->angle > target_angle) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 16c70ef18..39a56eced 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1566,7 +1566,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool preci } else { - angle_t pitch; + angle_t pitch = 0; if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))) { // Need to seek vertically double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length()); diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 5bb3a09fc..eed5d78a8 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1781,6 +1781,7 @@ int OWallMost (short *mostbuf, fixed_t z) s3 = MulScale16 (globaldclip, WallSZ1); s4 = MulScale16 (globaldclip, WallSZ2); bad = (zs3)<<2)+((z>s4)<<3); +#if 1 if ((bad&3) == 3) { memset (&mostbuf[WallSX1], 0, (WallSX2 - WallSX1)*sizeof(mostbuf[0])); @@ -1792,10 +1793,10 @@ int OWallMost (short *mostbuf, fixed_t z) clearbufshort (&mostbuf[WallSX1], WallSX2 - WallSX1, viewheight); return bad; } - +#endif ix1 = WallSX1; iy1 = WallSZ1; ix2 = WallSX2; iy2 = WallSZ2; - +#if 1 if (bad & 3) { int t = DivScale30 (z-s1, s2-s1); @@ -1842,7 +1843,38 @@ int OWallMost (short *mostbuf, fixed_t z) fixed_t yinc = (Scale (z, InvZtoScale, iy2) - y) / (ix2 - ix1); qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac, yinc); } +#else + double max = viewheight; + double zz = z / 65536.0; +#if 0 + double z1 = zz * InvZtoScale / WallSZ1; + double z2 = zz * InvZtoScale / WallSZ2 - z1; + z2 /= (WallSX2 - WallSX1); + z1 += centeryfrac / 65536.0; + for (int x = WallSX1; x < WallSX2; ++x) + { + mostbuf[x] = xs_RoundToInt(clamp(z1, 0.0, max)); + z1 += z2; + } +#else + double top, bot, i; + + i = WallSX1 - centerx; + top = WallUoverZorg + WallUoverZstep * i; + bot = WallInvZorg + WallInvZstep * i; + double cy = centeryfrac / 65536.0; + + for (int x = WallSX1; x < WallSX2; x++) + { + double frac = top / bot; + double scale = frac * WallDepthScale + WallDepthOrg; + mostbuf[x] = xs_RoundToInt(clamp(zz / scale + cy, 0.0, max)); + top += WallUoverZstep; + bot += WallInvZstep; + } +#endif +#endif if (mostbuf[ix1] < 0) mostbuf[ix1] = 0; else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight; if (mostbuf[ix2] < 0) mostbuf[ix2] = 0; @@ -2046,13 +2078,10 @@ void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat) { // swall = scale, lwall = texturecolumn double top, bot, i; double xrepeat = walxrepeat; - double topinc, botinc; i = WallSX1 - centerx; top = WallUoverZorg + WallUoverZstep * i; bot = WallInvZorg + WallInvZstep * i; - topinc = WallUoverZstep * 4.f; - botinc = WallInvZstep * 4.f; for (int x = WallSX1; x < WallSX2; x++) { @@ -2069,14 +2098,11 @@ void PrepLWall (fixed_t *lwall, fixed_t walxrepeat) { // lwall = texturecolumn double top, bot, i; double xrepeat = walxrepeat; - double topinc, botinc; double topstep; i = WallSX1 - centerx; top = WallUoverZorg + WallUoverZstep * i; bot = WallInvZorg + WallInvZstep * i; - topinc = WallUoverZstep * 4.f; - botinc = WallInvZstep * 4.f; top *= xrepeat; topstep = WallUoverZstep * xrepeat; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index a31665803..30efe22d9 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1533,7 +1533,7 @@ static void SetCustomLoopPts(FMOD::Sound *sound) FMOD_MODE mode; if (FMOD_OK == (sound->getMode(&mode))) { - sound->setMode(mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL) | FMOD_LOOP_BIDI); + sound->setMode((mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL)) | FMOD_LOOP_BIDI); } } } diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 68558bdad..b89d9fd67 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -125,7 +125,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) // Read the remainder of the song. len = int(len - start); - if (len < sizeof(MusHeader)) + if (len < (int)sizeof(MusHeader)) { // It's too short. return; } diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index a610fd409..672e81df3 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -38,6 +38,7 @@ #define DIRECTDRAW_VERSION 0x0300 #define DIRECT3D_VERSION 0x0900 +#define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #include #include @@ -51,6 +52,7 @@ #include #include #include +#include #define USE_WINDOWS_DWORD #include "doomtype.h" From 0749466d2dd7658a38b32ba872b768d125eb9455 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 11 Aug 2010 04:00:38 +0000 Subject: [PATCH 158/251] - Set explicit positioning for the gameplay options menu instead of relying on the automatic positioning. SVN r2506 (trunk) --- src/m_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index 7cef6242e..7e17ef798 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1090,7 +1090,7 @@ static menu_t DMFlagsMenu = "GAMEPLAY OPTIONS", 0, countof(DMFlagsItems), - 0, + 222, DMFlagsItems, }; From ed5a8e597c0c48ab702da2c967e2cad9cfe4ddff Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 11 Aug 2010 04:01:26 +0000 Subject: [PATCH 159/251] - Version bump to 2.5.0. SVN r2507 (trunk) --- src/version.h | 8 ++++---- src/win32/zdoom.rc | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/version.h b/src/version.h index de017995c..5854c5f01 100644 --- a/src/version.h +++ b/src/version.h @@ -40,16 +40,16 @@ /** Lots of different version numbers **/ -#define DOTVERSIONSTR_NOREV "2.4.0" +#define DOTVERSIONSTR_NOREV "2.5.0" // The version string the user actually sees. #define DOTVERSIONSTR DOTVERSIONSTR_NOREV " (r" SVN_REVISION_STRING ")" // The version as seen in the Windows resource -#define RC_FILEVERSION 2,4,0,SVN_REVISION_NUMBER -#define RC_PRODUCTVERSION 2,4,0,0 +#define RC_FILEVERSION 2,5,0,SVN_REVISION_NUMBER +#define RC_PRODUCTVERSION 2,5,0,0 #define RC_FILEVERSION2 DOTVERSIONSTR -#define RC_PRODUCTVERSION2 "2.4" +#define RC_PRODUCTVERSION2 "2.5" // Version identifier for network games. // Bump it every time you do a release unless you're certain you diff --git a/src/win32/zdoom.rc b/src/win32/zdoom.rc index bddfc1347..b23fe14eb 100644 --- a/src/win32/zdoom.rc +++ b/src/win32/zdoom.rc @@ -72,7 +72,7 @@ BEGIN " VALUE ""FileDescription"", ""ZDoom""\r\n" " VALUE ""FileVersion"", RC_FILEVERSION2\r\n" " VALUE ""InternalName"", ""ZDoom""\r\n" - " VALUE ""LegalCopyright"", ""Copyright © 1993-1996 id Software, 1998-2007 Randy Heit""\r\n" + " VALUE ""LegalCopyright"", ""Copyright \u00A9 1993-1996 id Software, 1998-2010 Randy Heit, 2002-2010 Christoph Oelckers, et al.""\r\n" " VALUE ""LegalTrademarks"", ""Doom® is a Registered Trademark of id Software, Inc.""\r\n" " VALUE ""OriginalFilename"", ""zdoom.exe""\r\n" " VALUE ""ProductName"", ""ZDoom""\r\n" From 096edb0817b47d8c5293132bda9d7457b3f93944 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 11 Aug 2010 06:31:47 +0000 Subject: [PATCH 160/251] - move vid_listadapters CCMD into common code. SVN r2509 (trunk) --- src/p_enemy.cpp | 2 +- src/sdl/hardware.h | 1 + src/v_video.cpp | 11 +++++++++++ src/win32/hardware.h | 1 + src/win32/win32video.cpp | 8 -------- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index cbbd8797f..53d87e3dc 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1556,7 +1556,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if (actor->MissileState != NULL) { - actor->SetStateNF(actor->SeeState); + actor->SetState(actor->SeeState, true); actor->flags &= ~MF_JUSTHIT; } diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index 073a555b1..5b14b7cbb 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -52,6 +52,7 @@ class IVideo virtual bool SetResolution (int width, int height, int bits); + virtual void DumpAdapters(); }; void I_InitGraphics (); diff --git a/src/v_video.cpp b/src/v_video.cpp index 2327529be..1e8993e74 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1768,3 +1768,14 @@ const int BaseRatioSizes[5][4] = { 960, 600, 0, 48 }, { 960, 640, (int)(6.5*FRACUNIT), 48*15/16 } // 5:4 320, 213.3333, multiplied by three }; + +void IVideo::DumpAdapters () +{ + Printf("Multi-monitor support unavailable.\n"); +} + +CCMD(vid_listadapters) +{ + if (Video != NULL) + Video->DumpAdapters(); +} diff --git a/src/win32/hardware.h b/src/win32/hardware.h index bdff41cf8..223ba621c 100644 --- a/src/win32/hardware.h +++ b/src/win32/hardware.h @@ -52,6 +52,7 @@ class IVideo virtual bool SetResolution (int width, int height, int bits); + virtual void DumpAdapters(); }; void I_InitGraphics (); diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 672e81df3..e9df043d0 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -405,14 +405,6 @@ void Win32Video::DumpAdapters() } } -CCMD(vid_listadapters) -{ - if (Video != NULL) - { - static_cast(Video)->DumpAdapters(); - } -} - // Mode enumeration -------------------------------------------------------- HRESULT WINAPI Win32Video::EnumDDModesCB (LPDDSURFACEDESC desc, void *data) From 99e0adaf456c153f072fbd9489659eb9b1da472c Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 12 Aug 2010 02:32:03 +0000 Subject: [PATCH 161/251] - Fixed some issues with compiling on the Mac. Some options were added to force compilation of internal libraries and added checks for building ppc binaries on x86. SVN r2515 (trunk) --- CMakeLists.txt | 22 +++++++++++++--------- src/CMakeLists.txt | 12 ++++++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 215858b14..b541a9c20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,35 +64,39 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" ) -if( ZLIB_FOUND ) +option(FORCE_INTERNAL_ZLIB "Use internal zlib") +option(FORCE_INTERNAL_JPEG "Use internal jpeg") +option(FORCE_INTERNAL_BZIP2 "Use internal bzip2") + +if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB ) message( STATUS "Using system zlib" ) -else( ZLIB_FOUND ) +else( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB ) message( STATUS "Using internal zlib" ) add_subdirectory( zlib ) set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib ) set( ZLIB_LIBRARIES z ) set( ZLIB_LIBRARY z ) -endif( ZLIB_FOUND ) +endif( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB ) -if( JPEG_FOUND ) +if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG ) message( STATUS "Using system jpeg library" ) -else( JPEG_FOUND ) +else( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG ) message( STATUS "Using internal jpeg library" ) add_subdirectory( jpeg-6b ) set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jpeg-6b ) set( JPEG_LIBRARIES jpeg ) set( JPEG_LIBRARY jpeg ) -endif( JPEG_FOUND ) +endif( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG ) -if( BZIP2_FOUND ) +if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 ) message( STATUS "Using system bzip2 library" ) -else( BZIP2_FOUND ) +else( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 ) message( STATUS "Using internal bzip2 library" ) add_subdirectory( bzip2 ) set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bzip2" ) set( BZIP2_LIBRARIES bz2 ) set( BZIP2_LIBRARY bz2 ) -endif( BZIP2_FOUND) +endif( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 ) set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67e06cf3b..45b65da1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -232,12 +232,12 @@ endif( FMOD_LIBRARY ) # Search for NASM -if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc ) +if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc) if( NOT NO_ASM ) message( STATUS "Disabling assembly code for PowerPC." ) set( NO_ASM ON ) endif( NOT NO_ASM ) -endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc ) +endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) if( NOT NO_ASM ) if( UNIX AND X64 ) @@ -432,7 +432,7 @@ add_custom_target( revision_check ALL # Libraries ZDoom needs set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) # Start defining source files for ZDoom @@ -515,12 +515,12 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc ) +if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) set( X86_SOURCES ) set( NOT_X86 ON ) -else( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc ) +else( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) set( X86_SOURCES nodebuild_classify_sse2.cpp ) -endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc ) +endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) add_executable( zdoom WIN32 autostart.cpp From e9c43fe90801096518a9864c37b0c35cd9045fa1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 12 Aug 2010 06:43:12 +0000 Subject: [PATCH 162/251] - fixed: P_LoopSidedefs must be called again before setting up the polyobjects if the nodes were rebuilt. The original data is no longer valid in case vertexes were merged by the node builder. SVN r2516 (trunk) --- src/p_setup.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index a324a393a..50af213b5 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3844,6 +3844,9 @@ void P_SetupLevel (char *lumpname, int position) P_SpawnSpecials (); times[16].Clock(); + // The old sidedef looping data is no longer valid if the nodes were rebuilt + // and vertexes merged so it has to be redone before setting up the polyobjects. + if (ForceNodeBuild) P_LoopSidedefs (); PO_Init (); // Initialize the polyobjs times[16].Unclock(); From 185bd2f15d4400d7bbcee836fe52d1e2c7b6d3e5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 12 Aug 2010 07:05:31 +0000 Subject: [PATCH 163/251] - backported some 3D floor changes from GZDoom. SVN r2517 (trunk) --- src/p_3dfloors.cpp | 27 +++++++++++++++++++++++++++ src/p_3dfloors.h | 4 ++++ src/p_map.cpp | 10 ++++++++-- src/p_mobj.cpp | 30 ++++++++---------------------- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index b9b82a566..390fc23cf 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -680,5 +680,32 @@ void P_Spawn3DFloors (void) } +//========================================================================== +// +// Returns a 3D floorplane appropriate for the given coordinates +// +//========================================================================== + +secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z) +{ + secplane_t retplane = sector->floorplane; + if (sector->e) // apparently this can be called when the data is already gone + { + for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) + { + F3DFloor * rover= sector->e->XFloor.ffloors[i]; + if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; + + if (rover->top.plane->ZatPoint(x, y) == z) + { + retplane = *rover->top.plane; + if (retplane.c<0) retplane.FlipVert(); + break; + } + } + } + return retplane; +} + #endif \ No newline at end of file diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index dfaf5a5eb..4cdb14506 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -125,6 +125,8 @@ struct FLineOpening; void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx, fixed_t refy); + +secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z); #else @@ -156,6 +158,8 @@ struct FLineOpening; inline void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx, fixed_t refy) {} +//secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z){return sector->floorplane;} + #endif diff --git a/src/p_map.cpp b/src/p_map.cpp index f8c267070..2d105c284 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -655,8 +655,14 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm) if (!(tm.thing->flags & MF_DROPOFF) && !(tm.thing->flags & (MF_NOGRAVITY|MF_NOCLIP))) { - if (ld->frontsector->floorplane.c < STEEPSLOPE || - ld->backsector->floorplane.c < STEEPSLOPE) + secplane_t frontplane = ld->frontsector->floorplane; + secplane_t backplane = ld->backsector->floorplane; +#ifdef _3DFLOORS + // Check 3D floors as well + frontplane = P_FindFloorPlane(ld->frontsector, tm.thing->x, tm.thing->y, tm.thing->floorz); + backplane = P_FindFloorPlane(ld->backsector, tm.thing->x, tm.thing->y, tm.thing->floorz); +#endif + if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE) { const msecnode_t *node = tm.thing->touching_sectorlist; bool allow = false; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 39a56eced..f52067ba2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3178,41 +3178,27 @@ void AActor::Tick () velz <= 0 && floorz == z) { - const secplane_t * floorplane = &floorsector->floorplane; - static secplane_t copyplane; + secplane_t floorplane = floorsector->floorplane; #ifdef _3DFLOORS // Check 3D floors as well - if (floorsector->e) // apparently this can be called when the data is already gone- - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - F3DFloor * rover= floorsector->e->XFloor.ffloors[i]; - if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - if (rover->top.plane->ZatPoint(x, y) == floorz) - { - copyplane = *rover->top.plane; - if (copyplane.c<0) copyplane.FlipVert(); - floorplane = ©plane; - break; - } - } + floorplane = P_FindFloorPlane(floorsector, x, y, floorz); #endif - if (floorplane->c < STEEPSLOPE && - floorplane->ZatPoint (x, y) <= floorz) + if (floorplane.c < STEEPSLOPE && + floorplane.ZatPoint (x, y) <= floorz) { const msecnode_t *node; bool dopush = true; - if (floorplane->c > STEEPSLOPE*2/3) + if (floorplane.c > STEEPSLOPE*2/3) { for (node = touching_sectorlist; node; node = node->m_tnext) { const sector_t *sec = node->m_sector; if (sec->floorplane.c >= STEEPSLOPE) { - if (floorplane->ZatPoint (x, y) >= z - MaxStepHeight) + if (floorplane.ZatPoint (x, y) >= z - MaxStepHeight) { dopush = false; break; @@ -3222,8 +3208,8 @@ void AActor::Tick () } if (dopush) { - velx += floorplane->a; - vely += floorplane->b; + velx += floorplane.a; + vely += floorplane.b; } } } From c3fa9a54a074c60ddfeeaaeadf54de5373e6a6ea Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 12 Aug 2010 21:28:16 +0000 Subject: [PATCH 164/251] - Fix printf warnings in p_setup.cpp. - Fix buiding on PowerPC. SVN r2522 (trunk) --- src/CMakeLists.txt | 70 +++++++++++++++++++++++++++++++++++----------- src/p_setup.cpp | 6 ++-- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 45b65da1e..35e093e73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -327,6 +327,41 @@ if( NOT NO_ASM ) ENDMACRO( ADD_ASM_FILE ) endif( NOT NO_ASM ) +# Decide on SSE setup + +set( SSE_MATTERS NO ) + +# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it. +if( CMAKE_SIZEOF_VOID_P MATCHES "4" ) + CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH ) + CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 ) + if( CAN_DO_MFPMATH ) + set( SSE1_ENABLE "-msse -mfpmath=sse" ) + set( SSE2_ENABLE "-msse2 -mfpmath=sse" ) + set( SSE_MATTERS YES ) + elseif( CAN_DO_ARCHSSE2 ) + set( SSE1_ENABLE -arch:SSE ) + set( SSE2_ENABLE -arch:SSE2 ) + set( SSE_MATTERS YES ) + endif( CAN_DO_MFPMATH ) +endif( CMAKE_SIZEOF_VOID_P MATCHES "4" ) + +if( SSE_MATTERS ) + if( WIN32 ) + set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) + else( WIN32 ) + CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT) + if( HAVE_MPROTECT ) + set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) + else( HAVE_MPROTECT ) + set( BACKPATCH 0 ) + endif( HAVE_MPROTECT ) + endif( WIN32 ) + set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." ) +else( SSE_MATTERS ) + set( BACKPATCH 0 ) +endif( SSE_MATTERS ) + # Set up flags for GCC if( CMAKE_COMPILER_IS_GNUCXX ) @@ -422,6 +457,12 @@ if( NOT HAS_VA_COPY ) endif( HAS___VA_COPY ) endif( NOT HAS_VA_COPY ) +# Flags + +if( BACKPATCH ) + add_definitions( -DBACKPATCH ) +endif( BACKPATCH ) + # Update svnrevision.h add_custom_target( revision_check ALL @@ -515,12 +556,18 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) +if( SSE_MATTERS ) + if( SSE ) + set( X86_SOURCES nodebuild_classify_sse2.cpp ) + set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" ) + else( SSE ) + add_definitions( -DDISABLE_SSE ) + endif( SSE ) +else( SSE_MATTERS ) + add_definitions( -DDISABLE_SSE ) set( X86_SOURCES ) - set( NOT_X86 ON ) -else( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) - set( X86_SOURCES nodebuild_classify_sse2.cpp ) -endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) +endif( SSE_MATTERS ) + add_executable( zdoom WIN32 autostart.cpp @@ -824,21 +871,12 @@ if( NOT WIN32 ) COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) endif( NOT WIN32 ) - if( CMAKE_COMPILER_IS_GNUCXX ) # GCC misoptimizes this file set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" ) - - # Compile this one file with SSE2 support. - set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mfpmath=sse" ) # Need to enable intrinsics for this file. - if( NOT NOT_X86 ) + if( SSE_MATTERS ) set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" ) - endif( NOT NOT_X86 ) + endif( SSE_MATTERS ) endif( CMAKE_COMPILER_IS_GNUCXX ) - -if( MSVC ) - # Compile this one file with SSE2 support. - set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "/arch:SSE2" ) -endif( MSVC ) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 50af213b5..636d4d69f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1325,8 +1325,8 @@ void P_LoadSubsectors (MapData * map) if ((size_t)subsectors[i].firstline >= maxseg) { Printf ("Subsector %d contains invalid segs %u-%u\n" - "The BSP will be rebuilt.\n", i, subsectors[i].firstline, - subsectors[i].firstline + subsectors[i].numlines - 1); + "The BSP will be rebuilt.\n", i, (unsigned)subsectors[i].firstline, + (unsigned)subsectors[i].firstline + subsectors[i].numlines - 1); ForceNodeBuild = true; delete[] nodes; delete[] subsectors; @@ -1336,7 +1336,7 @@ void P_LoadSubsectors (MapData * map) { Printf ("Subsector %d contains invalid segs %u-%u\n" "The BSP will be rebuilt.\n", i, maxseg, - subsectors[i].firstline + subsectors[i].numlines - 1); + (unsigned)subsectors[i].firstline + subsectors[i].numlines - 1); ForceNodeBuild = true; delete[] nodes; delete[] subsectors; From 7d40b8a9a43d311124ec437dbfa3aac903d4d2af Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 12 Aug 2010 22:15:32 +0000 Subject: [PATCH 165/251] - Fixed a number of places in p_acs.cpp that did not do byte swapping but should have. SVN r2523 (trunk) --- src/p_acs.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9dddbcf7c..b62b39ecb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1085,8 +1085,8 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) if (Format == ACS_Old) { - StringTable = ((DWORD *)Data)[1]; - StringTable += ((DWORD *)(Data + StringTable))[0] * 12 + 4; + StringTable = LittleLong(((DWORD *)Data)[1]); + StringTable += LittleLong(((DWORD *)(Data + StringTable))[0]) * 12 + 4; } else { @@ -1397,8 +1397,8 @@ void FBehavior::LoadScriptsDirectory () switch (Format) { case ACS_Old: - scripts.dw = (DWORD *)(Data + ((DWORD *)Data)[1]); // FIXME: Has this been byte-swapped before-hand? - NumScripts = scripts.dw[0]; + scripts.dw = (DWORD *)(Data + LittleLong(((DWORD *)Data)[1])); + NumScripts = LittleLong(scripts.dw[0]); if (NumScripts != 0) { scripts.dw++; @@ -1760,7 +1760,7 @@ const char *FBehavior::LookupString (DWORD index) const if (index >= list[0]) return NULL; // Out of range for this list; - return (const char *)(Data + list[1+index]); + return (const char *)(Data + LittleLong(list[1+index])); } else { @@ -4615,12 +4615,12 @@ int DLevelScript::RunScript () break; case PCD_GOTO: - pc = activeBehavior->Ofs2PC (*pc); + pc = activeBehavior->Ofs2PC (LittleLong(*pc)); break; case PCD_IFGOTO: if (STACK(1)) - pc = activeBehavior->Ofs2PC (*pc); + pc = activeBehavior->Ofs2PC (LittleLong(*pc)); else pc++; sp--; @@ -4798,7 +4798,7 @@ int DLevelScript::RunScript () case PCD_IFNOTGOTO: if (!STACK(1)) - pc = activeBehavior->Ofs2PC (*pc); + pc = activeBehavior->Ofs2PC (LittleLong(*pc)); else pc++; sp--; @@ -4832,7 +4832,7 @@ int DLevelScript::RunScript () case PCD_CASEGOTO: if (STACK(1) == NEXTWORD) { - pc = activeBehavior->Ofs2PC (*pc); + pc = activeBehavior->Ofs2PC (LittleLong(*pc)); sp--; } else @@ -4853,7 +4853,7 @@ int DLevelScript::RunScript () SDWORD caseval = pc[mid*2]; if (caseval == STACK(1)) { - pc = activeBehavior->Ofs2PC (pc[mid*2+1]); + pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1])); sp--; break; } From 3cf25ad8e5a59f1bb7dc728651b84e4cc9f09faa Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 12 Aug 2010 22:39:06 +0000 Subject: [PATCH 166/251] - Fixed more byte swapping lackage in p_acs.cpp. A cursory run through Hexen seems to have scripting working now. SVN r2524 (trunk) --- src/p_acs.cpp | 75 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b62b39ecb..39e4a14a9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3491,6 +3491,20 @@ inline int getshort (int *&pc) return res; } +// Read a possibly unaligned four-byte little endian integer. +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) +inline int uallong(int &foo) +{ + return *foo; +} +#else +inline int uallong(int &foo) +{ + unsigned char *bar = (unsigned char *)&foo; + return bar[0] | (bar[1] << 8) | (bar[2] << 16) | (bar[3] << 24); +} +#endif + int DLevelScript::RunScript () { DACSThinker *controller = DACSThinker::ActiveThinker; @@ -3605,7 +3619,8 @@ int DLevelScript::RunScript () break; case PCD_PUSHNUMBER: - PushToStack (NEXTWORD); + PushToStack (uallong(pc[0])); + pc++; break; case PCD_PUSHBYTE: @@ -3707,35 +3722,35 @@ int DLevelScript::RunScript () case PCD_LSPEC1DIRECT: temp = NEXTBYTE; LineSpecials[temp] (activationline, activator, backSide, - pc[0], 0, 0, 0, 0); + uallong(pc[0]), 0, 0, 0, 0); pc += 1; break; case PCD_LSPEC2DIRECT: temp = NEXTBYTE; LineSpecials[temp] (activationline, activator, backSide, - pc[0], pc[1], 0, 0, 0); + uallong(pc[0]), uallong(pc[1]), 0, 0, 0); pc += 2; break; case PCD_LSPEC3DIRECT: temp = NEXTBYTE; LineSpecials[temp] (activationline, activator, backSide, - pc[0], pc[1], pc[2], 0, 0); + uallong(pc[0]), uallong(pc[1]), uallong(pc[2]), 0, 0); pc += 3; break; case PCD_LSPEC4DIRECT: temp = NEXTBYTE; LineSpecials[temp] (activationline, activator, backSide, - pc[0], pc[1], pc[2], pc[3], 0); + uallong(pc[0]), uallong(pc[1]), uallong(pc[2]), uallong(pc[3]), 0); pc += 4; break; case PCD_LSPEC5DIRECT: temp = NEXTBYTE; LineSpecials[temp] (activationline, activator, backSide, - pc[0], pc[1], pc[2], pc[3], pc[4]); + uallong(pc[0]), uallong(pc[1]), uallong(pc[2]), uallong(pc[3]), uallong(pc[4])); pc += 5; break; @@ -4642,7 +4657,8 @@ int DLevelScript::RunScript () break; case PCD_DELAYDIRECT: - statedata = NEXTWORD + (fmt == ACS_Old && gameinfo.gametype == GAME_Hexen); + statedata = uallong(pc[0]) + (fmt == ACS_Old && gameinfo.gametype == GAME_Hexen); + pc++; if (statedata > 0) { state = SCRIPT_Delayed; @@ -4664,7 +4680,7 @@ int DLevelScript::RunScript () break; case PCD_RANDOMDIRECT: - PushToStack (Random (pc[0], pc[1])); + PushToStack (Random (uallong(pc[0]), uallong(pc[1]))); pc += 2; break; @@ -4679,7 +4695,7 @@ int DLevelScript::RunScript () break; case PCD_THINGCOUNTDIRECT: - PushToStack (ThingCount (pc[0], -1, pc[1], -1)); + PushToStack (ThingCount (uallong(pc[0]), -1, uallong(pc[1]), -1)); pc += 2; break; @@ -4706,7 +4722,8 @@ int DLevelScript::RunScript () case PCD_TAGWAITDIRECT: state = SCRIPT_TagWait; - statedata = NEXTWORD; + statedata = uallong(pc[0]); + pc++; break; case PCD_POLYWAIT: @@ -4717,7 +4734,8 @@ int DLevelScript::RunScript () case PCD_POLYWAITDIRECT: state = SCRIPT_PolyWait; - statedata = NEXTWORD; + statedata = uallong(pc[0]); + pc++; break; case PCD_CHANGEFLOOR: @@ -4726,7 +4744,7 @@ int DLevelScript::RunScript () break; case PCD_CHANGEFLOORDIRECT: - ChangeFlat (pc[0], pc[1], 0); + ChangeFlat (uallong(pc[0]), uallong(pc[1]), 0); pc += 2; break; @@ -4736,7 +4754,7 @@ int DLevelScript::RunScript () break; case PCD_CHANGECEILINGDIRECT: - ChangeFlat (pc[0], pc[1], 1); + ChangeFlat (uallong(pc[0]), uallong(pc[1]), 1); pc += 2; break; @@ -4820,7 +4838,8 @@ int DLevelScript::RunScript () case PCD_SCRIPTWAITDIRECT: state = SCRIPT_ScriptWait; - statedata = NEXTWORD; + statedata = uallong(pc[0]); + pc++; PutLast (); break; @@ -4830,14 +4849,14 @@ int DLevelScript::RunScript () break; case PCD_CASEGOTO: - if (STACK(1) == NEXTWORD) + if (STACK(1) == uallong(pc[0])) { - pc = activeBehavior->Ofs2PC (LittleLong(*pc)); + pc = activeBehavior->Ofs2PC (uallong(pc[1])); sp--; } else { - pc++; + pc += 2; } break; @@ -4845,7 +4864,7 @@ int DLevelScript::RunScript () // The count and jump table are 4-byte aligned pc = (int *)(((size_t)pc + 3) & ~3); { - int numcases = NEXTWORD; + int numcases = uallong(pc[0]); pc++; int min = 0, max = numcases-1; while (min <= max) { @@ -5173,7 +5192,7 @@ int DLevelScript::RunScript () break; case PCD_SETFONTDIRECT: - DoSetFont (pc[0]); + DoSetFont (uallong(pc[0])); pc++; break; @@ -5462,7 +5481,7 @@ int DLevelScript::RunScript () break; case PCD_SETGRAVITYDIRECT: - level.gravity = (float)pc[0] / 65536.f; + level.gravity = (float)uallong(pc[0]) / 65536.f; pc++; break; @@ -5473,7 +5492,7 @@ int DLevelScript::RunScript () break; case PCD_SETAIRCONTROLDIRECT: - level.aircontrol = pc[0]; + level.aircontrol = uallong(pc[0]); pc++; G_AirControlChanged (); break; @@ -5484,7 +5503,7 @@ int DLevelScript::RunScript () break; case PCD_SPAWNDIRECT: - PushToStack (DoSpawn (pc[0], pc[1], pc[2], pc[3], pc[4], pc[5], false)); + PushToStack (DoSpawn (uallong(pc[0]), uallong(pc[1]), uallong(pc[2]), uallong(pc[3]), uallong(pc[4]), uallong(pc[5]), false)); pc += 6; break; @@ -5494,7 +5513,7 @@ int DLevelScript::RunScript () break; case PCD_SPAWNSPOTDIRECT: - PushToStack (DoSpawnSpot (pc[0], pc[1], pc[2], pc[3], false)); + PushToStack (DoSpawnSpot (uallong(pc[0]), uallong(pc[1]), uallong(pc[2]), uallong(pc[3]), false)); pc += 4; break; @@ -5550,7 +5569,7 @@ int DLevelScript::RunScript () break; case PCD_GIVEINVENTORYDIRECT: - GiveInventory (activator, FBehavior::StaticLookupString (pc[0]), pc[1]); + GiveInventory (activator, FBehavior::StaticLookupString (uallong(pc[0])), uallong(pc[1])); pc += 2; break; @@ -5580,7 +5599,7 @@ int DLevelScript::RunScript () break; case PCD_TAKEINVENTORYDIRECT: - TakeInventory (activator, FBehavior::StaticLookupString (pc[0]), pc[1]); + TakeInventory (activator, FBehavior::StaticLookupString (uallong(pc[0])), uallong(pc[1])); pc += 2; break; @@ -5595,7 +5614,7 @@ int DLevelScript::RunScript () break; case PCD_CHECKINVENTORYDIRECT: - PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (pc[0]))); + PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (uallong(pc[0])))); pc += 1; break; @@ -5699,7 +5718,7 @@ int DLevelScript::RunScript () break; case PCD_SETMUSICDIRECT: - S_ChangeMusic (FBehavior::StaticLookupString (pc[0]), pc[1]); + S_ChangeMusic (FBehavior::StaticLookupString (uallong(pc[0])), uallong(pc[1])); pc += 3; break; @@ -5714,7 +5733,7 @@ int DLevelScript::RunScript () case PCD_LOCALSETMUSICDIRECT: if (activator == players[consoleplayer].mo) { - S_ChangeMusic (FBehavior::StaticLookupString (pc[0]), pc[1]); + S_ChangeMusic (FBehavior::StaticLookupString (uallong(pc[0])), uallong(pc[1])); } pc += 3; break; From a27304baac96421f8407b14e117b2b5adfac90bf Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 12 Aug 2010 22:56:08 +0000 Subject: [PATCH 167/251] - Fixed byte swapping the script count for new-style ACS. My 2poly.wad now works on PPC. SVN r2525 (trunk) --- src/p_acs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 39e4a14a9..f1cbe4446 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1427,7 +1427,7 @@ void FBehavior::LoadScriptsDirectory () } else if (*(DWORD *)Data != MAKE_ID('A','C','S',0)) { - NumScripts = scripts.dw[1] / 12; + NumScripts = LittleLong(scripts.dw[1]) / 12; Scripts = new ScriptPtr[NumScripts]; scripts.dw += 2; @@ -1444,7 +1444,7 @@ void FBehavior::LoadScriptsDirectory () } else { - NumScripts = scripts.dw[1] / 8; + NumScripts = LittleLong(scripts.dw[1]) / 8; Scripts = new ScriptPtr[NumScripts]; scripts.dw += 2; From 4f03442a7a5ccc213bbe3ab8399ab8fa9d79036c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 13 Aug 2010 00:08:51 +0000 Subject: [PATCH 168/251] - Make the Cocoa IWAD picker behave like the others: Double-clicking an entry starts it, as does pressing Return, and pressing Escape is equivalent to the Cancel button. SVN r2526 (trunk) --- src/sdl/iwadpicker_cocoa.mm | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm index 2768c0e41..a835c6dff 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/sdl/iwadpicker_cocoa.mm @@ -115,6 +115,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; } - (void)buttonPressed:(id) sender; +- (void)doubleClicked:(id) sender; - (void)makeLabel:(NSTextField *)label:(const char*) str; - (int)pickIWad:(WadStuff *)wads:(int) numwads:(bool) showwin:(int) defaultiwad; @end @@ -130,6 +131,15 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [app stopModal]; } +- (void)doubleClicked:(id) sender; +{ + if ([sender clickedRow] >= 0) + { + [window orderOut:self]; + [app stopModal]; + } +} + // Apparently labels in Cocoa are uneditable text fields, so lets make this a // little more automated. - (void)makeLabel:(NSTextField *)label:(const char*) str @@ -148,18 +158,18 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; app = [NSApplication sharedApplication]; id windowTitle = [NSString stringWithCString:GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"]; - NSRect frame = NSMakeRect(0, 0, 400, 450); + NSRect frame = NSMakeRect(0, 0, 440, 450); window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; [window setTitle:windowTitle]; - NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(22, 379, 372, 50)]; + NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(22, 379, 412, 50)]; [self makeLabel:description:"ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"]; [[window contentView] addSubview:description]; [description release]; // Commented out version would account for an additional parameters box. - //NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 103, 362, 288)]; - NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 50, 362, 341)]; + //NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 103, 412, 288)]; + NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 50, 412, 341)]; NSTableView *iwadTable = [[NSTableView alloc] initWithFrame:[iwadScroller bounds]]; IWADTableData *tableData = [[IWADTableData alloc] init:wads:numwads]; for(int i = 0;i < NUM_COLUMNS;i++) @@ -177,6 +187,8 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [iwadScroller setHasVerticalScroller:YES]; [iwadTable setDataSource:tableData]; [iwadTable sizeToFit]; + [iwadTable setDoubleAction:@selector(doubleClicked:)]; + [iwadTable setTarget:self]; NSIndexSet *selection = [[NSIndexSet alloc] initWithIndex:defaultiwad]; [iwadTable selectRowIndexes:selection byExtendingSelection:NO]; [selection release]; @@ -198,18 +210,20 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [dontAsk setState:(showwin ? NSOffState : NSOnState)]; [[window contentView] addSubview:dontAsk];*/ - okButton = [[NSButton alloc] initWithFrame:NSMakeRect(196, 12, 96, 32)]; + okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 12, 96, 32)]; [okButton setTitle:[NSString stringWithCString:"OK"]]; [okButton setBezelStyle:NSRoundedBezelStyle]; [okButton setAction:@selector(buttonPressed:)]; [okButton setTarget:self]; + [okButton setKeyEquivalent:@"\r"]; [[window contentView] addSubview:okButton]; - cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(292, 12, 96, 32)]; + cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 12, 96, 32)]; [cancelButton setTitle:[NSString stringWithCString:"Cancel"]]; [cancelButton setBezelStyle:NSRoundedBezelStyle]; [cancelButton setAction:@selector(buttonPressed:)]; [cancelButton setTarget:self]; + [cancelButton setKeyEquivalent:@"\033"]; [[window contentView] addSubview:cancelButton]; [window center]; From 30ffe1d4b8bb24c840aef2998d9f845803757da9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 13 Aug 2010 03:14:05 +0000 Subject: [PATCH 169/251] - Maybe enable assembly on Intel Macs? SVN r2527 (trunk) --- src/CMakeLists.txt | 19 ++++++++++------- src/asm_ia32/a.asm | 14 ++++++++++++ src/asm_ia32/tmap.asm | 13 ++++++++++++ src/asm_ia32/tmap2.asm | 10 +++++++++ src/asm_ia32/tmap3.asm | 11 ++++++++++ src/d_main.cpp | 2 +- src/doomtype.h | 6 ------ src/p_acs.cpp | 2 +- src/sdl/i_main.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 109 insertions(+), 16 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 35e093e73..d00b88824 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,11 @@ include( FindPkgConfig ) option( NO_ASM "Disable assembly code" ) if( CMAKE_COMPILER_IS_GNUCXX ) option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) + # At least some versions of Xcode fail if you strip with the linker + # instead of the separate strip utility. + if( APPLE ) + set( NO_STRIP ON ) + endif( APPLE ) endif( CMAKE_COMPILER_IS_GNUCXX ) if( CMAKE_SIZEOF_VOID_P MATCHES "8" ) @@ -232,13 +237,6 @@ endif( FMOD_LIBRARY ) # Search for NASM -if( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc) - if( NOT NO_ASM ) - message( STATUS "Disabling assembly code for PowerPC." ) - set( NO_ASM ON ) - endif( NOT NO_ASM ) -endif( CMAKE_SYSTEM_PROCESSOR MATCHES powerpc OR CMAKE_OSX_ARCHITECTURES MATCHES ppc ) - if( NOT NO_ASM ) if( UNIX AND X64 ) find_program( GAS_PATH as ) @@ -297,7 +295,12 @@ if( NOT NO_ASM ) set( ASM_FLAGS ) set( ASM_SOURCE_EXTENSION .s ) else( X64 ) - set( ASM_FLAGS -f elf -DM_TARGET_LINUX -i${CMAKE_CURRENT_SOURCE_DIR}/ ) + if( APPLE ) + set( ASM_FLAGS -fmacho -DM_TARGET_MACHO ) + else( APPLE ) + set( ASM_FLAGS -felf ) + endif( APPLE ) + set( ASM_FLAGS "${ASM_FLAGS}" -DM_TARGET_LINUX -i${CMAKE_CURRENT_SOURCE_DIR}/ ) set( ASM_SOURCE_EXTENSION .asm ) endif( X64 ) else( UNIX ) diff --git a/src/asm_ia32/a.asm b/src/asm_ia32/a.asm index 196e8317a..07b00fe25 100644 --- a/src/asm_ia32/a.asm +++ b/src/asm_ia32/a.asm @@ -93,7 +93,16 @@ setupvlineasm: selfmod premach3a, machvsh8+6 ret +%ifdef M_TARGET_MACHO + SECTION .text align=64 +%else SECTION .rtext progbits alloc exec write align=64 +%endif + +%ifdef M_TARGET_MACHO +GLOBAL rtext_a_start +rtext_a_start: +%endif ;eax = xscale ;ebx = palookupoffse @@ -538,3 +547,8 @@ ALIGN 16 mvcase0: jmp beginmvlineasm4 align 16 + +%ifdef M_TARGET_MACHO +GLOBAL rtext_a_end +rtext_a_end: +%endif diff --git a/src/asm_ia32/tmap.asm b/src/asm_ia32/tmap.asm index e4c477598..04b86d09d 100644 --- a/src/asm_ia32/tmap.asm +++ b/src/asm_ia32/tmap.asm @@ -285,7 +285,16 @@ R_SetSpanSize_ASM: aret: ret +%ifdef M_TARGET_MACHO + SECTION .text align=64 +%else SECTION .rtext progbits alloc exec write align=64 +%endif + +%ifdef M_TARGET_MACHO +GLOBAL rtext_tmap_start +rtext_tmap_start: +%endif rtext_start: @@ -1738,6 +1747,10 @@ ac4nil: pop edi ret rtext_end: +%ifdef M_TARGET_MACHO +GLOBAL rtext_tmap_end +rtext_tmap_end: +%endif align 16 ;************************ diff --git a/src/asm_ia32/tmap2.asm b/src/asm_ia32/tmap2.asm index 7f6ed82da..63eee0044 100644 --- a/src/asm_ia32/tmap2.asm +++ b/src/asm_ia32/tmap2.asm @@ -216,7 +216,13 @@ SetTiltedSpanSize: ret +%ifndef M_TARGET_MACHO SECTION .rtext progbits alloc exec write align=64 +%else + SECTION .text align=64 +GLOBAL rtext_tmap2_start +rtext_tmap2_start: +%endif rtext_start: @@ -628,3 +634,7 @@ fetch10 mov al,[ebp+esi+SPACEFILLER4] ret rtext_end: +%ifdef M_TARGET_MACHO +GLOBAL rtext_tmap2_end +rtext_tmap2_end: +%endif diff --git a/src/asm_ia32/tmap3.asm b/src/asm_ia32/tmap3.asm index 49444419c..3791b4ff0 100644 --- a/src/asm_ia32/tmap3.asm +++ b/src/asm_ia32/tmap3.asm @@ -80,7 +80,13 @@ setupvlinetallasm: selfmod shifter1, shift12+6 ret +%ifdef M_TARGET_MACHO + SECTION .text align=64 +GLOBAL rtext_tmap3_start +rtext_tmap3_start: +%else SECTION .rtext progbits alloc exec write align=64 +%endif ALIGN 16 @@ -331,3 +337,8 @@ shift12: shr ecx,16 pop ebx pop ebp ret + +%ifdef M_TARGET_MACHO +GLOBAL rtext_tmap3_end +rtext_tmap3_end: +%endif diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b1e841a5..520127b9b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -38,7 +38,7 @@ #endif #include -#ifdef unix +#if defined(unix) || defined(__APPLE__) #include #endif diff --git a/src/doomtype.h b/src/doomtype.h index 7757a3cc6..31f96d2ab 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -44,12 +44,6 @@ // Since this file is included by everything, it seems an appropriate place // to check the NOASM/USEASM macros. -#if defined(__APPLE__) -// The assembly code needs to be tweaked for Mach-O before enabled on Macs. -#ifndef NOASM -#define NOASM -#endif -#endif // There are three assembly-related macros: // diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f1cbe4446..28217f663 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3495,7 +3495,7 @@ inline int getshort (int *&pc) #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) inline int uallong(int &foo) { - return *foo; + return foo; } #else inline int uallong(int &foo) diff --git a/src/sdl/i_main.cpp b/src/sdl/i_main.cpp index 5650c0781..4305a07ca 100644 --- a/src/sdl/i_main.cpp +++ b/src/sdl/i_main.cpp @@ -44,6 +44,10 @@ #include #endif #include +#if defined(__MACH__) && !defined(NOASM) +#include +#include +#endif #include "doomerrors.h" #include "m_argv.h" @@ -201,6 +205,46 @@ static int DoomSpecificInfo (char *buffer, char *end) return p; } +#if defined(__MACH__) && !defined(NOASM) +// NASM won't let us create custom sections for Mach-O. Whether that's a limitation of NASM +// or of Mach-O, I don't know, but since we're using NASM for the assembly, it doesn't much +// matter. +extern "C" +{ + extern void *rtext_a_start, *rtext_a_end; + extern void *rtext_tmap_start, *rtext_tmap_end; + extern void *rtext_tmap2_start, *rtext_tmap2_end; + extern void *rtext_tmap3_start, *rtext_tmap3_end; +}; + +static void unprotect_pages(long pagesize, void *start, void *end) +{ + char *page = (char *)((intptr_t)start & ~(pagesize - 1)); + size_t len = (char *)end - (char *)start; + if (mprotect(page, len, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + { + fprintf(stderr, "mprotect failed\n"); + exit(1); + } +} + +static void unprotect_rtext() +{ + static void *const pages[] = + { + rtext_a_start, rtext_a_end, + rtext_tmap_start, rtext_tmap_end, + rtext_tmap2_start, rtext_tmap2_end, + rtext_tmap3_start, rtext_tmap3_end + }; + long pagesize = sysconf(_SC_PAGESIZE); + for (void *const *p = pages; p < &pages[countof(pages)]; p += 2) + { + unprotect_pages(pagesize, p[0], p[1]); + } +} +#endif + int main (int argc, char **argv) { printf(GAMENAME" v%s - SVN revision %s - SDL version\nCompiled on %s\n\n", @@ -214,6 +258,10 @@ int main (int argc, char **argv) seteuid (getuid ()); std::set_new_handler (NewFailure); +#if defined(__MACH__) && !defined(NOASM) + unprotect_rtext(); +#endif + #ifndef NO_GTK GtkAvailable = gtk_init_check (&argc, &argv); #endif From dab3ff000e8fc984abe4cd04dbbc9aaf8052c813 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 13 Aug 2010 04:11:21 +0000 Subject: [PATCH 170/251] - Enable backpatching on non-Windows machines. SVN r2528 (trunk) --- src/CMakeLists.txt | 3 ++- src/nodebuild.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d00b88824..9b763dee3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ endif( COMMAND cmake_policy ) include( CheckCXXSourceCompiles ) include( CheckFunctionExists ) +include( CheckCXXCompilerFlag ) include( FindPkgConfig ) option( NO_ASM "Disable assembly code" ) @@ -37,7 +38,7 @@ set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41" "27" "26" "25" "24" "23" "22" "21" "20" "21" "19" "18" "17" "16" "15" "14" "13" "12" "11" "10" "09" "08" "07" "06" "05" "04" "03" "02" "01" "00" ) -set( MAJOR_VERSIONS "26" "24" "22" "20" ) +set( MAJOR_VERSIONS "30" "28" "26" "24" "22" "20" ) set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" ) foreach( majver ${MAJOR_VERSIONS} ) foreach( minver ${MINOR_VERSIONS} ) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 8298e9017..cbeb23f77 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -1082,6 +1082,7 @@ __declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsign #else #include #include +#include #endif #ifdef __GNUC__ From d904d8276e0541b817001db5e0ddb52ff4b6f2ad Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 13 Aug 2010 06:22:49 +0000 Subject: [PATCH 171/251] - added TheShooter7's patch for NOPITCH flags for hitscan attacks. SVN r2530 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 6 ++++-- wadsrc/static/actors/constants.txt | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4330c204c..aacb45b18 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -826,6 +826,7 @@ enum CBA_Flags CBAF_AIMFACING = 1, CBAF_NORANDOM = 2, CBAF_EXPLICITANGLE = 4, + CBAF_NOPITCH = 8, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) @@ -852,7 +853,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) if (!pufftype) pufftype = PClass::FindClass(NAME_BulletPuff); - bslope = P_AimLineAttack (self, bangle, MISSILERANGE); + if (!(Flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); for (i=0 ; i(self)->PlayAttacking2 (); - bslope = P_BulletSlope(self); + if (!(Flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); bangle = self->angle; if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index cbd91add6..05e77df2a 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -17,11 +17,13 @@ const int CMF_CHECKTARGETDEAD = 8; const int CBAF_AIMFACING = 1; const int CBAF_NORANDOM = 2; const int CBAF_EXPLICITANGLE = 4; +const int CBAF_NOPITCH = 8; // Flags for A_FireBullets const int FBF_USEAMMO = 1; const int FBF_NORANDOM = 2; const int FBF_EXPLICITANGLE = 4; +const int FBF_NOPITCH = 8; // Flags for A_SpawnItemEx const int SXF_TRANSFERTRANSLATION=1; From 564fb6a7233ecdf657f115cadaa1bb6a65b88380 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 13 Aug 2010 06:27:22 +0000 Subject: [PATCH 172/251] - added TheShooter7/Aroenai's patch for switch on pickup menu option. SVN r2531 (trunk) --- src/m_menu.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 49d5638ef..10ba3a336 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -196,6 +196,7 @@ static void M_ChangeClass (int choice); static void M_ChangeGender (int choice); static void M_ChangeSkin (int choice); static void M_ChangeAutoAim (int choice); +static void M_ChangeSwitchPickup (int choice); static void PickPlayerClass (); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -203,6 +204,7 @@ static void PickPlayerClass (); EXTERN_CVAR (String, playerclass) EXTERN_CVAR (String, name) EXTERN_CVAR (Int, team) +EXTERN_CVAR(Bool, neverswitchonpickup) extern bool sendpause; extern int flagsvar; @@ -545,7 +547,8 @@ static oldmenuitem_t PlayerSetupMenu[] = { 2,0,'t',NULL,M_ChangeClass, CR_UNTRANSLATED}, { 2,0,'s',NULL,M_ChangeSkin, CR_UNTRANSLATED}, { 2,0,'e',NULL,M_ChangeGender, CR_UNTRANSLATED}, - { 2,0,'a',NULL,M_ChangeAutoAim, CR_UNTRANSLATED} + { 2,0,'a',NULL,M_ChangeAutoAim, CR_UNTRANSLATED}, + { 2,0,'p',NULL,M_ChangeSwitchPickup, CR_UNTRANSLATED} }; enum @@ -2360,6 +2363,13 @@ static void M_PlayerSetupDrawer () autoaim <= 2 ? "High" : autoaim <= 3 ? "Very High" : "Always", DTA_Clean, true, TAG_DONE); + + // Draw Switch on Pickup setting + x = SmallFont->StringWidth ("Switch on Pickup") + 8 + PSetupDef.x; + screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*9+yo, "Switch on Pickup", DTA_Clean, true, TAG_DONE); + screen->DrawText (SmallFont, value, x, PSetupDef.y + LINEHEIGHT*9+yo, + neverswitchonpickup == false ? "Yes" : "No", + DTA_Clean, true, TAG_DONE); } // A 32x32 cloud rendered with Photoshop, plus some other filters @@ -2668,6 +2678,14 @@ static void M_ChangeAutoAim (int choice) autoaim = aim; } +static void M_ChangeSwitchPickup (int choice) +{ + if (!choice) + neverswitchonpickup = (neverswitchonpickup == 1) ? 0 : 1; + else + neverswitchonpickup = (neverswitchonpickup == 0) ? 1 : 0; +} + static void M_EditPlayerName (int choice) { // we are going to be intercepting all chars From 09bd076b17261afc785746585ab47e04cf845499 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 13 Aug 2010 06:31:22 +0000 Subject: [PATCH 173/251] - added PinkSilver's ACS Checksight submission. SVN r2532 (trunk) --- src/p_acs.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 28217f663..4aeb0595f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3033,6 +3033,7 @@ enum EACSFunctions ACSF_SoundSequenceOnPolyobj, ACSF_GetPolyobjX, ACSF_GetPolyobjY, + ACSF_CheckSight, }; int DLevelScript::SideFromID(int id, int side) @@ -3455,6 +3456,54 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } } return FIXED_MAX; + + case ACSF_CheckSight: + { + AActor *source; + AActor *dest; + + int flags = SF_IGNOREVISIBILITY; + + if (args[2] & 1) flags |= SF_IGNOREWATERBOUNDARY; + if (args[2] & 2) flags |= SF_SEEPASTBLOCKEVERYTHING | SF_SEEPASTSHOOTABLELINES; + + if (args[0] == 0) + { + source = (AActor *) activator; + + if (args[1] == 0) return 1; // [KS] I'm sure the activator can see itself. + + TActorIterator dstiter (args[1]); + + while ( (dest = dstiter.Next ()) ) + { + if (P_CheckSight(source, dest, flags)) return 1; + } + } + else + { + TActorIterator srciter (args[0]); + + if (args[1] == 0) dest = (AActor *) activator; + + while ( (source = srciter.Next ()) ) + { + if (args[1] != 0) + { + TActorIterator dstiter (args[1]); + while ( (dest = dstiter.Next ()) ) + { + if (P_CheckSight(source, dest, flags)) return 1; + } + } + else + { + if (P_CheckSight(source, dest, flags)) return 1; + } + } + } + return 0; + } default: break; From 1063a98c47c3272138090546a4de59e147562812 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 13 Aug 2010 22:12:42 +0000 Subject: [PATCH 174/251] - Maybe allow assembly on Intel Macs? - attempt 2 SVN r2537 (trunk) --- src/CMakeLists.txt | 4 ++-- src/asm_ia32/a.asm | 9 +++++---- src/asm_ia32/tmap.asm | 8 ++++---- src/asm_ia32/tmap2.asm | 8 ++++---- src/asm_ia32/tmap3.asm | 8 ++++---- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b763dee3..80d5e3800 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -299,9 +299,9 @@ if( NOT NO_ASM ) if( APPLE ) set( ASM_FLAGS -fmacho -DM_TARGET_MACHO ) else( APPLE ) - set( ASM_FLAGS -felf ) + set( ASM_FLAGS -felf -DM_TARGET_LINUX ) endif( APPLE ) - set( ASM_FLAGS "${ASM_FLAGS}" -DM_TARGET_LINUX -i${CMAKE_CURRENT_SOURCE_DIR}/ ) + set( ASM_FLAGS "${ASM_FLAGS}" -i${CMAKE_CURRENT_SOURCE_DIR}/ ) set( ASM_SOURCE_EXTENSION .asm ) endif( X64 ) else( UNIX ) diff --git a/src/asm_ia32/a.asm b/src/asm_ia32/a.asm index 07b00fe25..d68fba116 100644 --- a/src/asm_ia32/a.asm +++ b/src/asm_ia32/a.asm @@ -100,8 +100,8 @@ setupvlineasm: %endif %ifdef M_TARGET_MACHO -GLOBAL rtext_a_start -rtext_a_start: +GLOBAL _rtext_a_start +_rtext_a_start: %endif ;eax = xscale @@ -334,6 +334,7 @@ setupmvlineasm: mov ecx, dword [esp+4] mov byte [maskmach3a+2], cl mov byte [machmv13+2], cl + mov byte [machmv14+2], cl mov byte [machmv15+2], cl mov byte [machmv16+2], cl @@ -549,6 +550,6 @@ mvcase0: jmp beginmvlineasm4 align 16 %ifdef M_TARGET_MACHO -GLOBAL rtext_a_end -rtext_a_end: +GLOBAL _rtext_a_end +_rtext_a_end: %endif diff --git a/src/asm_ia32/tmap.asm b/src/asm_ia32/tmap.asm index 04b86d09d..e9713131f 100644 --- a/src/asm_ia32/tmap.asm +++ b/src/asm_ia32/tmap.asm @@ -292,8 +292,8 @@ aret: ret %endif %ifdef M_TARGET_MACHO -GLOBAL rtext_tmap_start -rtext_tmap_start: +GLOBAL _rtext_tmap_start +_rtext_tmap_start: %endif rtext_start: @@ -1748,8 +1748,8 @@ ac4nil: pop edi rtext_end: %ifdef M_TARGET_MACHO -GLOBAL rtext_tmap_end -rtext_tmap_end: +GLOBAL _rtext_tmap_end +_rtext_tmap_end: %endif align 16 diff --git a/src/asm_ia32/tmap2.asm b/src/asm_ia32/tmap2.asm index 63eee0044..e1f166878 100644 --- a/src/asm_ia32/tmap2.asm +++ b/src/asm_ia32/tmap2.asm @@ -220,8 +220,8 @@ SetTiltedSpanSize: SECTION .rtext progbits alloc exec write align=64 %else SECTION .text align=64 -GLOBAL rtext_tmap2_start -rtext_tmap2_start: +GLOBAL _rtext_tmap2_start +_rtext_tmap2_start: %endif rtext_start: @@ -635,6 +635,6 @@ fetch10 mov al,[ebp+esi+SPACEFILLER4] rtext_end: %ifdef M_TARGET_MACHO -GLOBAL rtext_tmap2_end -rtext_tmap2_end: +GLOBAL _rtext_tmap2_end +_rtext_tmap2_end: %endif diff --git a/src/asm_ia32/tmap3.asm b/src/asm_ia32/tmap3.asm index 3791b4ff0..3161ff368 100644 --- a/src/asm_ia32/tmap3.asm +++ b/src/asm_ia32/tmap3.asm @@ -82,8 +82,8 @@ setupvlinetallasm: %ifdef M_TARGET_MACHO SECTION .text align=64 -GLOBAL rtext_tmap3_start -rtext_tmap3_start: +GLOBAL _rtext_tmap3_start +_rtext_tmap3_start: %else SECTION .rtext progbits alloc exec write align=64 %endif @@ -339,6 +339,6 @@ shift12: shr ecx,16 ret %ifdef M_TARGET_MACHO -GLOBAL rtext_tmap3_end -rtext_tmap3_end: +GLOBAL _rtext_tmap3_end +_rtext_tmap3_end: %endif From b288a7a416375c960aa64e979776bfd8258aeb80 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 14 Aug 2010 06:25:38 +0000 Subject: [PATCH 175/251] - added option to set item pickup color through MAPINFO's GAMEINFO block. SVN r2539 (trunk) --- src/g_shared/shared_sbar.cpp | 4 +++- src/gi.cpp | 1 + src/gi.h | 1 + wadsrc/static/mapinfo/chex.txt | 1 + wadsrc/static/mapinfo/doomcommon.txt | 1 + wadsrc/static/mapinfo/heretic.txt | 1 + wadsrc/static/mapinfo/hexen.txt | 1 + wadsrc/static/mapinfo/strife.txt | 1 + 8 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index ef48d211a..beb459cda 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1504,7 +1504,9 @@ void DBaseStatusBar::BlendView (float blend[4]) if (CPlayer->bonuscount) { cnt = CPlayer->bonuscount << 3; - AddBlend (0.8431f, 0.7333f, 0.2706f, cnt > 128 ? 0.5f : cnt / 255.f, blend); + + AddBlend (RPART(gameinfo.pickupcolor)/255.f, GPART(gameinfo.pickupcolor)/255.f, + BPART(gameinfo.pickupcolor)/255.f, cnt > 128 ? 0.5f : cnt / 255.f, blend); } if (CPlayer->mo->DamageFade.a != 0) diff --git a/src/gi.cpp b/src/gi.cpp index e0813479a..03fea70a9 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -266,6 +266,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_INT(defKickback, "defKickback") GAMEINFOKEY_CSTRING(SkyFlatName, "SkyFlatName", 8) GAMEINFOKEY_STRING(translator, "translator") + GAMEINFOKEY_COLOR(pickupcolor, "pickupcolor") GAMEINFOKEY_COLOR(defaultbloodcolor, "defaultbloodcolor") GAMEINFOKEY_COLOR(defaultbloodparticlecolor, "defaultbloodparticlecolor") GAMEINFOKEY_STRING(backpacktype, "backpacktype") diff --git a/src/gi.h b/src/gi.h index a87098555..09a9d37a8 100644 --- a/src/gi.h +++ b/src/gi.h @@ -106,6 +106,7 @@ struct gameinfo_t int defaultrespawntime; int defaultdropstyle; int player5start; + DWORD pickupcolor; const char *GetFinalePage(unsigned int num) const; }; diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 9e313cf1e..deefea4d3 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -42,6 +42,7 @@ gameinfo endoom = "ENDOOM" player5start = 4001 drawreadthis = true + pickupcolor = "d6 ba 45" } skill baby diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 3de271756..f67783509 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -40,6 +40,7 @@ gameinfo defaultdropstyle = 1 endoom = "ENDOOM" player5start = 4001 + pickupcolor = "d6 ba 45" } skill baby diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 0c78f1184..4ca727272 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -41,6 +41,7 @@ gameinfo defaultdropstyle = 1 endoom = "ENDTEXT" player5start = 4001 + pickupcolor = "d6 ba 45" } skill baby diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index 344f4eb41..16ebcf5b4 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -39,6 +39,7 @@ gameinfo defaultrespawntime = 12 defaultdropstyle = 1 player5start = 9100 + pickupcolor = "d6 ba 45" } skill baby diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index 6c213d81e..e5c9043ee 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -42,6 +42,7 @@ gameinfo defaultdropstyle = 2 endoom = "ENDSTRF" player5start = 5 + pickupcolor = "d6 ba 45" } skill baby From 1fda9421ac1f310e61aaca76c5975722feef9960 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 14 Aug 2010 20:00:47 +0000 Subject: [PATCH 176/251] Backported from GZDoom: - Fixed: P_LoopSidedefs() needs to clean out sidetemp[] because when it's called a second time, the maximum of the number of vertices and that of sides may have increased compared to when P_AllocateSideDefs() created the array, which led to access violations. SVN r2541 (trunk) --- src/p_setup.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 636d4d69f..4ddb79e3c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2132,10 +2132,11 @@ static void P_LoopSidedefs () { int i; - if (sidetemp == NULL) + if (sidetemp != NULL) { - sidetemp = new sidei_t[MAX(numvertexes, numsides)]; + delete[] sidetemp; } + sidetemp = new sidei_t[MAX(numvertexes, numsides)]; for (i = 0; i < numvertexes; ++i) { From a0d16bc99a884b172a0f6894be1a6f0809cffb7b Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 14 Aug 2010 21:01:49 +0000 Subject: [PATCH 177/251] - Fixed: The center flag for drawimage didn't work. - Fixed: GCC didn't like casting from seg_t* to unsigned int on 64-bit systems. SVN r2542 (trunk) --- src/g_shared/sbarinfo.cpp | 18 +++++++++--------- src/p_setup.cpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 6895ce321..83f9e9bef 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -933,16 +933,16 @@ void Popup::close() //////////////////////////////////////////////////////////////////////////////// -inline void adjustRelCenter(const SBarInfoCoordinate &x, const SBarInfoCoordinate &y, double &outX, double &outY, const double &xScale, const double &yScale) +inline void adjustRelCenter(bool relX, bool relY, const double &x, const double &y, double &outX, double &outY, const double &xScale, const double &yScale) { - if(x.RelCenter()) - outX = *x + (SCREENWIDTH/(hud_scale ? xScale*2 : 2)); + if(relX) + outX = x + (SCREENWIDTH/(hud_scale ? xScale*2 : 2)); else - outX = *x; - if(y.RelCenter()) - outY = *y + (SCREENHEIGHT/(hud_scale ? yScale*2 : 2)); + outX = x; + if(relY) + outY = y + (SCREENHEIGHT/(hud_scale ? yScale*2 : 2)); else - outY = *y; + outY = y; } class DSBarInfo : public DBaseStatusBar @@ -1227,7 +1227,7 @@ public: double xScale = !hud_scale ? 1.0 : (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; double yScale = !hud_scale ? 1.0 : (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENHEIGHT/(double) script->resH; - adjustRelCenter(x, y, rx, ry, xScale, yScale); + adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale); // We can't use DTA_HUDRules since it forces a width and height. // Translation: No high res. @@ -1343,7 +1343,7 @@ public: xScale = (double) CleanXfac*320.0/(double) script->resW;//(double) SCREENWIDTH/(double) script->resW; yScale = (double) CleanYfac*200.0/(double) script->resH;//(double) SCREENWIDTH/(double) script->resW; } - adjustRelCenter(x, y, ax, ay, xScale, yScale); + adjustRelCenter(x.RelCenter(), y.RelCenter(), *x, *y, ax, ay, xScale, yScale); } while(*str != '\0') { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 4ddb79e3c..332e1d077 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1325,8 +1325,8 @@ void P_LoadSubsectors (MapData * map) if ((size_t)subsectors[i].firstline >= maxseg) { Printf ("Subsector %d contains invalid segs %u-%u\n" - "The BSP will be rebuilt.\n", i, (unsigned)subsectors[i].firstline, - (unsigned)subsectors[i].firstline + subsectors[i].numlines - 1); + "The BSP will be rebuilt.\n", i, (unsigned)((size_t)subsectors[i].firstline), + (unsigned)((size_t)subsectors[i].firstline) + subsectors[i].numlines - 1); ForceNodeBuild = true; delete[] nodes; delete[] subsectors; @@ -1336,7 +1336,7 @@ void P_LoadSubsectors (MapData * map) { Printf ("Subsector %d contains invalid segs %u-%u\n" "The BSP will be rebuilt.\n", i, maxseg, - (unsigned)subsectors[i].firstline + subsectors[i].numlines - 1); + (unsigned)((size_t)subsectors[i].firstline) + subsectors[i].numlines - 1); ForceNodeBuild = true; delete[] nodes; delete[] subsectors; From 66f6115c86db05471ff9aa4a9f1616c27bb98b6d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 15 Aug 2010 10:02:10 +0000 Subject: [PATCH 178/251] - added a compatibility option to render all segs of a polyobject in the center's subsector and automatically set it for Hexen MAP36 and HEXDD MAP47. SVN r2543 (trunk) --- src/compatibility.cpp | 14 ++++++++++++++ src/d_iwad.cpp | 4 ++-- src/d_main.cpp | 7 +++++++ src/doomdef.h | 1 + src/g_mapinfo.cpp | 1 + src/gi.h | 4 +++- src/m_options.cpp | 1 + src/po_man.cpp | 28 +++++++++++++++++++++++++--- src/po_man.h | 1 + 9 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index e091a7f1e..ab1c98ca7 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -118,6 +118,7 @@ static FCompatOption Options[] = { "spritesort", COMPATF_SPRITESORT, 0 }, { "hitscan", COMPATF_HITSCAN, 0 }, { "lightlevel", COMPATF_LIGHT, 0 }, + { "polyobj", COMPATF_POLYOBJ, 0 }, { NULL, 0, 0 } }; @@ -266,6 +267,19 @@ void CheckCompatibility(MapData *map) ib_compatflags = 0; ii_compatparams = -1; } + else if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATPOLY1) && Wads.CheckLumpName(map->lumpnum, "MAP36")) + { + ii_compatflags = COMPATF_POLYOBJ; + ib_compatflags = 0; + ii_compatparams = -1; + } + else if (Wads.GetLumpFile(map->lumpnum) == 2 && (gameinfo.flags & GI_COMPATPOLY2) && Wads.CheckLumpName(map->lumpnum, "MAP47")) + { + ii_compatflags = COMPATF_POLYOBJ; + ib_compatflags = 0; + ii_compatparams = -1; + } + else { map->GetChecksum(md5.Bytes); diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index e5939e1a7..9a49c533b 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -60,8 +60,8 @@ const IWADInfo IWADInfos[NUM_IWAD_TYPES] = // banner text, autoname, fg color, bg color { "Final Doom: TNT - Evilution", "TNT", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/tnt.txt", GI_MAPxx | GI_COMPATSHORTTEX | GI_COMPATSTAIRS }, { "Final Doom: Plutonia Experiment", "Plutonia", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/plutonia.txt", GI_MAPxx | GI_COMPATSHORTTEX }, - { "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx }, - { "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx }, + { "Hexen: Beyond Heretic", NULL, MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 }, + { "Hexen: Deathkings of the Dark Citadel", "HexenDK", MAKERGB(240,240,240), MAKERGB(139,68,9), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_COMPATPOLY1 | GI_COMPATPOLY2 }, { "Hexen: Demo Version", "HexenDemo",MAKERGB(240,240,240), MAKERGB(107,44,24), GAME_Hexen, "mapinfo/hexen.txt", GI_MAPxx | GI_SHAREWARE }, { "DOOM 2: Hell on Earth", "Doom2", MAKERGB(168,0,0), MAKERGB(168,168,168), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx | GI_COMPATSHORTTEX }, { "Heretic Shareware", NULL, MAKERGB(252,252,0), MAKERGB(168,0,0), GAME_Heretic, "mapinfo/hereticsw.txt",GI_SHAREWARE }, diff --git a/src/d_main.cpp b/src/d_main.cpp index 520127b9b..deef1d6c7 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -104,6 +104,7 @@ #include "compatibility.h" #include "m_joy.h" #include "sc_man.h" +#include "po_man.h" #include "resourcefiles/resourcefile.h" EXTERN_CVAR(Bool, hud_althud) @@ -480,7 +481,12 @@ static int GetCompatibility(int mask) CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO) { + int old = i_compatflags; i_compatflags = GetCompatibility(self) | ii_compatflags; + if ((old ^i_compatflags) & COMPATF_POLYOBJ) + { + FPolyObj::ClearAllSubsectorLinks(); + } } CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) @@ -559,6 +565,7 @@ CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS); CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT); CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN); CVAR (Flag, compat_light, compatflags,COMPATF_LIGHT); +CVAR (Flag, compat_polyobj, compatflags,COMPATF_POLYOBJ); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 3aa527523..1108e770f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -329,6 +329,7 @@ enum COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom + COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 1eb6363fd..9378db768 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1404,6 +1404,7 @@ MapFlagHandlers[] = { "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS}, { "compat_spritesort", MITYPE_COMPATFLAG, COMPATF_SPRITESORT}, { "compat_light", MITYPE_COMPATFLAG, COMPATF_LIGHT}, + { "compat_polyobj", MITYPE_COMPATFLAG, COMPATF_POLYOBJ}, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/gi.h b/src/gi.h index 09a9d37a8..cbb1a02bb 100644 --- a/src/gi.h +++ b/src/gi.h @@ -43,7 +43,9 @@ #define GI_MENUHACK_EXTENDED 0x00000004 // (Heretic) #define GI_TEASER2 0x00000008 // Alternate version of the Strife Teaser #define GI_COMPATSHORTTEX 0x00000010 // always force COMPAT_SHORTTEX for IWAD maps. -#define GI_COMPATSTAIRS 0x00000010 // same for stairbuilding +#define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding +#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing +#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47 #include "gametype.h" diff --git a/src/m_options.cpp b/src/m_options.cpp index 7e17ef798..2357c930a 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1133,6 +1133,7 @@ static menuitem_t CompatibilityItems[] = { { bitflag, "Invert sprite sorting", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SPRITESORT} }, { bitflag, "Use Doom code for hitscan checks", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_HITSCAN} }, { bitflag, "Cripple sound for silent BFG trick", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MAGICSILENCE} }, + { bitflag, "Draw polyobjects like Hexen", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_POLYOBJ} }, { discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} }, }; diff --git a/src/po_man.cpp b/src/po_man.cpp index 1ca8d9a3a..1aa065c19 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1752,8 +1752,8 @@ static void TranslateToStartSpot (int tag, int originX, int originY) po->OriginalPts[i].y = po->Vertices[i]->y - po->StartSpot.y; } po->CalcCenter(); - // subsector assignment no longer done here. - // Polyobjects will be sorted into the subsectors each frame before rendering them. + // For compatibility purposes + po->CenterSubsector = R_PointInSubsector(po->CenterSpot.x, po->CenterSpot.y); } //========================================================================== @@ -2193,7 +2193,29 @@ void FPolyObj::CreateSubsectorLinks() seg->v2 = side->V2(); seg->wall = side; } - SplitPoly(node, nodes + numnodes - 1, dummybbox); + if (!(i_compatflags & COMPATF_POLYOBJ)) + { + SplitPoly(node, nodes + numnodes - 1, dummybbox); + } + else + { + subsector_t *sub = CenterSubsector; + + // Link node to subsector + node->pnext = sub->polys; + if (node->pnext != NULL) + { + assert(node->pnext->state == 1337); + node->pnext->pprev = node; + } + node->pprev = NULL; + sub->polys = node; + + // link node to polyobject + node->snext = node->poly->subsectorlinks; + node->poly->subsectorlinks = node; + node->subsector = sub; + } } //========================================================================== diff --git a/src/po_man.h b/src/po_man.h index d76dff55f..074426d88 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -53,6 +53,7 @@ struct FPolyObj FPolyVertex StartSpot; FPolyVertex CenterSpot; FBoundingBox Bounds; // Bounds in map coordinates + subsector_t *CenterSubsector; angle_t angle; int tag; // reference tag assigned in HereticEd From 0657121847ade656974155459021977a3347d182 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 15 Aug 2010 14:09:17 +0000 Subject: [PATCH 179/251] - Backport from GZDoom: P_LoopSidedefs() needed another fix as it shouldn't try to report errors found on the second loop. SVN r2544 (trunk) --- src/p_setup.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 332e1d077..35ec40a43 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2128,7 +2128,7 @@ static void P_AllocateSideDefs (int count) // [RH] Group sidedefs into loops so that we can easily determine // what walls any particular wall neighbors. -static void P_LoopSidedefs () +static void P_LoopSidedefs (bool firstloop) { int i; @@ -2193,7 +2193,7 @@ static void P_LoopSidedefs () right = sidetemp[right].b.first; - if (right == NO_SIDE) + if (firstloop && right == NO_SIDE) { // There is no right side! Printf ("Line %d's right edge is unconnected\n", linemap[unsigned(line-lines)]); continue; @@ -3655,7 +3655,7 @@ void P_SetupLevel (char *lumpname, int position) } times[6].Clock(); - P_LoopSidedefs (); + P_LoopSidedefs (true); times[6].Unclock(); linemap.Clear(); @@ -3845,9 +3845,7 @@ void P_SetupLevel (char *lumpname, int position) P_SpawnSpecials (); times[16].Clock(); - // The old sidedef looping data is no longer valid if the nodes were rebuilt - // and vertexes merged so it has to be redone before setting up the polyobjects. - if (ForceNodeBuild) P_LoopSidedefs (); + if (ForceNodeBuild) P_LoopSidedefs (false); PO_Init (); // Initialize the polyobjs times[16].Unclock(); From 1fa4bbf69cf7d76ef0d2e8c9d78bf9aca01f8cfc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 15 Aug 2010 19:54:59 +0000 Subject: [PATCH 180/251] - Added FluidSynth support as snd_mididevice -5. Only tested with Linux. I will have to try compiling it myself on Windows to see if it's really that slow or if Ubuntu just ships an unoptimized version, because performance is pretty pathetic when compared to the other options. (I understand that it's a complete SoundFont2 renderer, so it is understandably slower than something like TiMidity++, but still. Does it really need to be around 10x slower? I played with the chorus, reverb, and interpolation settings, and none of them seemed to make much difference in performance.) SVN r2545 (trunk) --- FindFluidSynth.cmake | 23 ++++++++++ src/CMakeLists.txt | 21 +++++++-- src/sound/fmodsound.cpp | 31 +++++++++---- src/sound/fmodsound.h | 3 +- src/sound/i_music.cpp | 18 ++++++++ src/sound/i_music.h | 3 ++ src/sound/i_musicinterns.h | 67 ++++++++++++++++++++++++++- src/sound/music_midi_base.cpp | 9 ++-- src/sound/music_midistream.cpp | 82 +++++++++++++++++++++++++++++++++- 9 files changed, 239 insertions(+), 18 deletions(-) create mode 100644 FindFluidSynth.cmake diff --git a/FindFluidSynth.cmake b/FindFluidSynth.cmake new file mode 100644 index 000000000..7d5cb6a8e --- /dev/null +++ b/FindFluidSynth.cmake @@ -0,0 +1,23 @@ +# - Find fluidsynth +# Find the native fluidsynth includes and library +# +# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h +# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth. +# FLUIDSYNTH_FOUND - True if fluidsynth found. + + +IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES) + # Already in cache, be silent + SET(FluidSynth_FIND_QUIETLY TRUE) +ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES) + +FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h) + +FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth ) +MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR ) + +# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 80d5e3800..d6c0aa382 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,10 @@ endif( CMAKE_SIZEOF_VOID_P MATCHES "8" ) # fmodapilinux[64] -or simply- fmod # jpeg-6b # ... +# The recommended method is to put it in the zdoom tree, since its +# headers are unversioned. Especially now that we can't work properly +# with anything newer than 4.26.xx, you probably don't want to use +# a system-wide version. # Construct version numbers for searching for the FMOD library on Linux. set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41" @@ -236,6 +240,10 @@ else( FMOD_LIBRARY ) endif( FMOD_LIBRARY ) +# Search for FluidSynth + +include( ../FindFluidSynth.cmake ) + # Search for NASM if( NOT NO_ASM ) @@ -370,7 +378,8 @@ endif( SSE_MATTERS ) if( CMAKE_COMPILER_IS_GNUCXX ) if( PROFILE ) - set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) + set( CMAKE_C_FLinclude( FindFluidSynth.cmake ) +AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) @@ -476,8 +485,10 @@ add_custom_target( revision_check ALL # Libraries ZDoom needs -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) + +message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) +set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" "${FLUIDSYNTH_LIBRARIES}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${FLUIDSYNTH_INCLUDE_DIR}" ) # Start defining source files for ZDoom @@ -572,6 +583,9 @@ else( SSE_MATTERS ) set( X86_SOURCES ) endif( SSE_MATTERS ) +if( FLUIDSYNTH_FOUND ) + add_definitions( -DHAVE_FLUIDSYNTH ) +endif( FLUIDSYNTH_FOUND ) add_executable( zdoom WIN32 autostart.cpp @@ -793,6 +807,7 @@ add_executable( zdoom WIN32 sound/music_mus_midiout.cpp sound/music_mus_opl.cpp sound/music_stream.cpp + sound/music_fluidsynth_mididevice.cpp sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp textures/automaptexture.cpp diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 30efe22d9..bcd84b9fd 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -101,6 +101,7 @@ EXTERN_CVAR (Int, snd_buffersize) EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Bool, snd_pitched) EXTERN_CVAR (Int, snd_channels) +EXTERN_CVAR (String, snd_midipatchset) extern int sfx_empty; @@ -115,7 +116,6 @@ CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_profile, false, 0) // Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter. @@ -644,6 +644,7 @@ bool FMODSoundRenderer::Init() ChannelGroupTargetUnit = NULL; SfxReverbHooked = false; SfxReverbPlaceholder = NULL; + SfxHeadMixer = NULL; OutputPlugin = 0; Printf("I_InitSound: Initializing FMOD\n"); @@ -706,7 +707,8 @@ bool FMODSoundRenderer::Init() if (!ShowedBanner) { - Printf("FMOD Sound System, copyright © Firelight Technologies Pty, Ltd., 1994-2009.\n"); + // '\xa9' is the copyright symbol in the Windows-1252 code page. + Printf("FMOD Sound System, copyright \xa9 Firelight Technologies Pty, Ltd., 1994-2009.\n"); Printf("Loaded FMOD version %x.%02x.%02x\n", version >> 16, (version >> 8) & 255, version & 255); ShowedBanner = true; } @@ -1014,6 +1016,12 @@ bool FMODSoundRenderer::Init() result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxReverbPlaceholder); if (result == FMOD_OK) { + result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxHeadMixer); + result = sfx_head->addInput(SfxHeadMixer, &SfxConnection); + result = sfx_head->disconnectFrom(pausable_head); + sfx_head = SfxHeadMixer; + SfxHeadMixer->setActive(true); + SfxHeadMixer->setBypass(false); // Replace the PausableSFX->SFX connection with // PausableSFX->ReverbPlaceholder->SFX. result = SfxReverbPlaceholder->addInput(pausable_head, NULL); @@ -1023,13 +1031,13 @@ bool FMODSoundRenderer::Init() result = sfx_head->addInput(SfxReverbPlaceholder, &connection); if (result == FMOD_OK) { - sfx_head->disconnectFrom(pausable_head); +// sfx_head->disconnectFrom(pausable_head); SfxReverbPlaceholder->setActive(true); SfxReverbPlaceholder->setBypass(true); // The placeholder now takes the place of the pausable_head // for the following connections. pausable_head = SfxReverbPlaceholder; - SfxConnection = connection; + // SfxConnection = connection; } } else @@ -1038,6 +1046,7 @@ bool FMODSoundRenderer::Init() SfxReverbPlaceholder = NULL; } } +#if 1 result = WaterLP->addInput(pausable_head, NULL); WaterLP->setActive(false); WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); @@ -1069,6 +1078,7 @@ bool FMODSoundRenderer::Init() { result = sfx_head->addInput(WaterLP, NULL); } +#endif } } } @@ -1147,6 +1157,11 @@ void FMODSoundRenderer::Shutdown() SfxReverbPlaceholder->release(); SfxReverbPlaceholder = NULL; } + if (SfxHeadMixer != NULL) + { + SfxHeadMixer->release(); + SfxHeadMixer = NULL; + } Sys->close(); if (OutputPlugin != 0) @@ -1330,10 +1345,10 @@ FString FMODSoundRenderer::GatherStats() #endif out.Format ("%d channels,"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% CPU " - "(DSP:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% " - "Stream:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% " - "Geometry:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% " - "Update:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%%)", + "(DSP:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " + "Stream:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " + "Geometry:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " + "Update:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%%)", channels, total, dsp, stream, geometry, update); return out; } diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 1460b697b..f15629cb4 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -103,7 +103,8 @@ private: FMOD::DSP *WaterLP, *WaterReverb; FMOD::DSPConnection *SfxConnection; FMOD::DSP *ChannelGroupTargetUnit; - FMOD::DSP *SfxReverbPlaceholder; + FMOD::DSP *SfxReverbPlaceholder; + FMOD::DSP *SfxHeadMixer; bool SfxReverbHooked; float LastWaterLP; unsigned int OutputPlugin; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index e25d4b5d6..51640b747 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -162,6 +162,18 @@ void MusInfo::TimidityVolumeChanged() { } +void MusInfo::FluidSettingInt(const char *, int) +{ +} + +void MusInfo::FluidSettingNum(const char *, double) +{ +} + +void MusInfo::FluidSettingStr(const char *, const char *) +{ +} + FString MusInfo::GetStats() { return "No stats available for this song"; @@ -428,6 +440,12 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { info = new MUSSong2(file, musiccache, len, MIDI_Timidity); } +#ifdef HAVE_FLUIDSYNTH + else if (snd_mididevice == -5 && device == MDEV_DEFAULT) + { + info = new MUSSong2(file, musiccache, len, MIDI_Fluid); + } +#endif if (info != NULL && !info->IsValid()) { delete info; diff --git a/src/sound/i_music.h b/src/sound/i_music.h index 4bde02df1..88e6f61c0 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -98,6 +98,9 @@ public: virtual FString GetStats(); virtual MusInfo *GetOPLDumper(const char *filename); virtual MusInfo *GetWaveDumper(const char *filename, int rate); + virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings + virtual void FluidSettingNum(const char *setting, double value); // " + virtual void FluidSettingStr(const char *setting, const char *value); // " enum EState { diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index e5c4771eb..4deec4f55 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -95,6 +95,9 @@ public: virtual bool NeedThreadedCallback() = 0; virtual void PrecacheInstruments(const WORD *instruments, int count); virtual void TimidityVolumeChanged(); + virtual void FluidSettingInt(const char *setting, int value); + virtual void FluidSettingNum(const char *setting, double value); + virtual void FluidSettingStr(const char *setting, const char *value); virtual FString GetStats(); }; @@ -255,6 +258,64 @@ protected: FILE *File; }; +// FluidSynth implementation of a MIDI device ------------------------------- + +#ifdef HAVE_FLUIDSYNTH +#include + +class FluidSynthMIDIDevice : public MIDIDevice +{ +public: + FluidSynthMIDIDevice(); + ~FluidSynthMIDIDevice(); + + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + void Close(); + bool IsOpen() const; + int GetTechnology() const; + int SetTempo(int tempo); + int SetTimeDiv(int timediv); + int StreamOut(MIDIHDR *data); + int StreamOutSync(MIDIHDR *data); + int Resume(); + void Stop(); + int PrepareHeader(MIDIHDR *data); + int UnprepareHeader(MIDIHDR *data); + bool FakeVolume(); + bool Pause(bool paused); + bool NeedThreadedCallback(); + void PrecacheInstruments(const WORD *instruments, int count); + FString GetStats(); + void FluidSettingInt(const char *setting, int value); + void FluidSettingNum(const char *setting, double value); + void FluidSettingStr(const char *setting, const char *value); + +protected: + static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); + bool ServiceStream(void *buff, int numbytes); + void HandleEvent(int status, int parm1, int parm2); + int LoadPatchSets(const char *patches); + + void (*Callback)(unsigned int, void *, DWORD, DWORD); + void *CallbackData; + + void CalcTickRate(); + int PlayTick(); + + FCriticalSection CritSec; + SoundStream *Stream; + fluid_settings_t *FluidSettings; + fluid_synth_t *FluidSynth; + double Tempo; + double Division; + double SamplesPerTick; + double NextTickIn; + MIDIHDR *Events; + bool Started; + DWORD Position; +}; +#endif + // Base class for streaming MUS and MIDI files ------------------------------ // MIDI device selection. @@ -262,7 +323,8 @@ enum EMIDIDevice { MIDI_Win, MIDI_OPL, - MIDI_Timidity + MIDI_Timidity, + MIDI_Fluid }; class MIDIStreamer : public MusInfo @@ -282,6 +344,9 @@ public: bool IsValid() const; void Update(); FString GetStats(); + void FluidSettingInt(const char *setting, int value); + void FluidSettingNum(const char *setting, double value); + void FluidSettingStr(const char *setting, const char *value); protected: MIDIStreamer(const char *dumpname, EMIDIDevice type); diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index d7983a70f..0184c6a10 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -9,6 +9,9 @@ static DWORD nummididevices; static bool nummididevicesset; + +CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); + #ifdef _WIN32 UINT mididevice; @@ -19,7 +22,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) if (!nummididevicesset) return; - if ((self >= (signed)nummididevices) || (self < -4)) + if ((self >= (signed)nummididevices) || (self < -5)) { Printf ("ID out of range. Using default device.\n"); self = 0; @@ -177,8 +180,8 @@ CCMD (snd_listmididevices) CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { - if (self < -3) - self = -3; + if (self < -5) + self = -5; else if (self > -1) self = -1; } diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 5ed94c34c..d9449a657 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -215,6 +215,12 @@ void MIDIStreamer::Play(bool looping, int subsong) assert(0); // Intentional fall-through for non-Windows systems. +#ifdef HAVE_FLUIDSYNTH + case MIDI_Fluid: + MIDI = new FluidSynthMIDIDevice; + break; +#endif + case MIDI_Timidity: MIDI = new TimidityMIDIDevice; break; @@ -225,10 +231,10 @@ void MIDIStreamer::Play(bool looping, int subsong) } #ifndef _WIN32 - assert(MIDI->NeedThreadedCallback() == false); + assert(MIDI == NULL || MIDI->NeedThreadedCallback() == false); #endif - if (0 != MIDI->Open(Callback, this)) + if (MIDI == NULL || 0 != MIDI->Open(Callback, this)) { Printf(PRINT_BOLD, "Could not open MIDI out device\n"); return; @@ -435,6 +441,48 @@ void MIDIStreamer::TimidityVolumeChanged() } } +//========================================================================== +// +// MIDIStreamer :: FluidSettingInt +// +//========================================================================== + +void MIDIStreamer::FluidSettingInt(const char *setting, int value) +{ + if (MIDI != NULL) + { + MIDI->FluidSettingInt(setting, value); + } +} + +//========================================================================== +// +// MIDIStreamer :: FluidSettingNum +// +//========================================================================== + +void MIDIStreamer::FluidSettingNum(const char *setting, double value) +{ + if (MIDI != NULL) + { + MIDI->FluidSettingNum(setting, value); + } +} + +//========================================================================== +// +// MIDIDeviceStreamer :: FluidSettingStr +// +//========================================================================== + +void MIDIStreamer::FluidSettingStr(const char *setting, const char *value) +{ + if (MIDI != NULL) + { + MIDI->FluidSettingStr(setting, value); + } +} + //========================================================================== // @@ -840,6 +888,36 @@ void MIDIDevice::TimidityVolumeChanged() { } +//========================================================================== +// +// MIDIDevice :: FluidSettingInt +// +//========================================================================== + +void MIDIDevice::FluidSettingInt(const char *setting, int value) +{ +} + +//========================================================================== +// +// MIDIDevice :: FluidSettingNum +// +//========================================================================== + +void MIDIDevice::FluidSettingNum(const char *setting, double value) +{ +} + +//========================================================================== +// +// MIDIDevice :: FluidSettingStr +// +//========================================================================== + +void MIDIDevice::FluidSettingStr(const char *setting, const char *value) +{ +} + //========================================================================== // // MIDIDevice :: GetStats From ea4ac390d98f99de27fa710c1709e4a0e104aaae Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 15 Aug 2010 19:55:40 +0000 Subject: [PATCH 181/251] - Forgot to include this music_fluidsynth_mididevice.cpp. SVN r2546 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 799 ++++++++++++++++++++++ 1 file changed, 799 insertions(+) create mode 100644 src/sound/music_fluidsynth_mididevice.cpp diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp new file mode 100644 index 000000000..302166ad1 --- /dev/null +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -0,0 +1,799 @@ +/* +** music_fluidsynth_mididevice.cpp +** Provides access to FluidSynth as a generic MIDI device. +** +**--------------------------------------------------------------------------- +** Copyright 2010 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef HAVE_FLUIDSYNTH + +// HEADER FILES ------------------------------------------------------------ + +#include "i_musicinterns.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "w_wad.h" +#include "v_text.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +EXTERN_CVAR(String, snd_midipatchset) + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 10) + self = 10; + else if (currSong != NULL) + currSong->FluidSettingNum("synth.gain", self); +} + +CUSTOM_CVAR(Bool, fluid_reverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (currSong != NULL) + currSong->FluidSettingStr("synth.reverb.active", self ? "yes" : "no"); +} + +CUSTOM_CVAR(Bool, fluid_chorus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (currSong != NULL) + currSong->FluidSettingStr("synth.chorus.active", self ? "yes" : "no"); +} + +CUSTOM_CVAR(Int, fluid_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 16) + self = 16; + else if (self > 4096) + self = 4096; + else if (currSong != NULL) + currSong->FluidSettingInt("synth.polyphony", self); +} + +CUSTOM_CVAR(Int, fluid_interp, FLUID_INTERP_LINEAR, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + // Values are: 0 = FLUID_INTERP_NONE + // 1 = FLUID_INTERP_LINEAR + // 2 = FLUID_INTERP_4THORDER (the FluidSynth default) + // 3 = FLUID_INTERP_7THORDER + if (self < FLUID_INTERP_NONE) + self = FLUID_INTERP_NONE; + else if (self > FLUID_INTERP_HIGHEST) + self = FLUID_INTERP_HIGHEST; + else if (currSong != NULL) + currSong->FluidSettingInt("synth.interpolation", self); +} + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FluidSynthMIDIDevice Constructor +// +//========================================================================== + +FluidSynthMIDIDevice::FluidSynthMIDIDevice() +{ + Stream = NULL; + Tempo = 0; + Division = 0; + Events = NULL; + Started = false; + FluidSynth = NULL; + FluidSettings = new_fluid_settings(); + if (FluidSettings == NULL) + { + printf("Failed to create FluidSettings.\n"); + return; + } + fluid_settings_setnum(FluidSettings, "synth.gain", fluid_gain); + fluid_settings_setstr(FluidSettings, "synth.reverb.active", fluid_reverb ? "yes" : "no"); + fluid_settings_setstr(FluidSettings, "synth.chorus.active", fluid_chorus ? "yes" : "no"); + fluid_settings_setint(FluidSettings, "synth.polyphony", fluid_voices); + FluidSynth = new_fluid_synth(FluidSettings); + if (FluidSynth == NULL) + { + Printf("Failed to create FluidSynth.\n"); + return; + } + if (FLUID_FAILED == fluid_synth_set_interp_method(FluidSynth, -1, fluid_interp)) + { + Printf("Failed to set interpolation method %d.\n", *fluid_interp); + } + if (0 == LoadPatchSets(snd_midipatchset)) + { +#ifdef unix + // This is the standard location on Ubuntu. + if (0 == LoadPatchSets("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2")) + { +#endif + Printf("Failed to load any MIDI patches.\n"); + delete_fluid_synth(FluidSynth); + FluidSynth = NULL; +#ifdef unix + } +#endif + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice Destructor +// +//========================================================================== + +FluidSynthMIDIDevice::~FluidSynthMIDIDevice() +{ + Close(); + if (FluidSynth != NULL) + { + delete_fluid_synth(FluidSynth); + } + if (FluidSettings != NULL) + { + delete_fluid_settings(FluidSettings); + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: Open +// +// Returns 0 on success. +// +//========================================================================== + +int FluidSynthMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +{ + if (FluidSynth == NULL) + { + return 2; + } + Stream = GSnd->CreateStream(FillStream, int(44100 / 4) * 4, + SoundStream::Float, 44100, this); + if (Stream == NULL) + { + return 2; + } + + fluid_synth_system_reset(FluidSynth); + Callback = callback; + CallbackData = userdata; + Tempo = 500000; + Division = 100; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: Close +// +//========================================================================== + +void FluidSynthMIDIDevice::Close() +{ + if (Stream != NULL) + { + delete Stream; + Stream = NULL; + } + Started = false; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: IsOpen +// +//========================================================================== + +bool FluidSynthMIDIDevice::IsOpen() const +{ + return Stream != NULL; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: GetTechnology +// +//========================================================================== + +int FluidSynthMIDIDevice::GetTechnology() const +{ + return MOD_SWSYNTH; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: SetTempo +// +//========================================================================== + +int FluidSynthMIDIDevice::SetTempo(int tempo) +{ + Tempo = tempo; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: SetTimeDiv +// +//========================================================================== + +int FluidSynthMIDIDevice::SetTimeDiv(int timediv) +{ + Division = timediv; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: CalcTickRate +// +// Tempo is the number of microseconds per quarter note. +// Division is the number of ticks per quarter note. +// +//========================================================================== + +void FluidSynthMIDIDevice::CalcTickRate() +{ + SamplesPerTick = 44100 / (1000000.0 / Tempo) / Division; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: Resume +// +//========================================================================== + +int FluidSynthMIDIDevice::Resume() +{ + if (!Started) + { + if (Stream->Play(true, 1)) + { + Started = true; + return 0; + } + return 1; + } + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: Stop +// +//========================================================================== + +void FluidSynthMIDIDevice::Stop() +{ + if (Started) + { + Stream->Stop(); + Started = false; + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: StreamOutSync +// +// This version is called from the main game thread and needs to +// synchronize with the player thread. +// +//========================================================================== + +int FluidSynthMIDIDevice::StreamOutSync(MIDIHDR *header) +{ + CritSec.Enter(); + StreamOut(header); + CritSec.Leave(); + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: StreamOut +// +// This version is called from the player thread so does not need to +// arbitrate for access to the Events pointer. +// +//========================================================================== + +int FluidSynthMIDIDevice::StreamOut(MIDIHDR *header) +{ + header->lpNext = NULL; + if (Events == NULL) + { + Events = header; + NextTickIn = SamplesPerTick * *(DWORD *)header->lpData; + Position = 0; + } + else + { + MIDIHDR **p; + + for (p = &Events; *p != NULL; p = &(*p)->lpNext) + { } + *p = header; + } + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: PrepareHeader +// +//========================================================================== + +int FluidSynthMIDIDevice::PrepareHeader(MIDIHDR *header) +{ + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: UnprepareHeader +// +//========================================================================== + +int FluidSynthMIDIDevice::UnprepareHeader(MIDIHDR *header) +{ + return 0; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: FakeVolume +// +// Since the FluidSynth output is rendered as a normal stream, its volume is +// controlled through the GSnd interface, not here. +// +//========================================================================== + +bool FluidSynthMIDIDevice::FakeVolume() +{ + return false; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: NeedThreadedCallabck +// +// FluidSynth can service the callback directly rather than using a separate +// thread. +// +//========================================================================== + +bool FluidSynthMIDIDevice::NeedThreadedCallback() +{ + return false; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: Pause +// +//========================================================================== + +bool FluidSynthMIDIDevice::Pause(bool paused) +{ + if (Stream != NULL) + { + return Stream->SetPaused(paused); + } + return true; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: PrecacheInstruments +// +// Each entry is packed as follows: +// Bits 0- 6: Instrument number +// Bits 7-13: Bank number +// Bit 14: Select drum set if 1, tone bank if 0 +// +//========================================================================== + +void FluidSynthMIDIDevice::PrecacheInstruments(const WORD *instruments, int count) +{ +#if 0 + for (int i = 0; i < count; ++i) + { + Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); + } + Renderer->load_missing_instruments(); +#endif +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: HandleEvent +// +// Translates a MIDI event into FluidSynth calls. +// +//========================================================================== + +void FluidSynthMIDIDevice::HandleEvent(int status, int parm1, int parm2) +{ + int command = status & 0xF0; + int channel = status & 0x0F; + + switch (command) + { + case MIDI_NOTEOFF: + fluid_synth_noteoff(FluidSynth, channel, parm1); + break; + + case MIDI_NOTEON: + fluid_synth_noteon(FluidSynth, channel, parm1, parm2); + break; + + case MIDI_POLYPRESS: + break; + + case MIDI_CTRLCHANGE: + fluid_synth_cc(FluidSynth, channel, parm1, parm2); + break; + + case MIDI_PRGMCHANGE: + fluid_synth_program_change(FluidSynth, channel, parm1); + break; + + case MIDI_CHANPRESS: + fluid_synth_channel_pressure(FluidSynth, channel, parm1); + break; + + case MIDI_PITCHBEND: + fluid_synth_pitch_bend(FluidSynth, channel, (parm1 & 0x7f) | ((parm2 & 0x7f) << 7)); + break; + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: PlayTick +// +// event[0] = delta time +// event[1] = unused +// event[2] = event +// +//========================================================================== + +int FluidSynthMIDIDevice::PlayTick() +{ + DWORD delay = 0; + + while (delay == 0 && Events != NULL) + { + DWORD *event = (DWORD *)(Events->lpData + Position); + if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) + { + SetTempo(MEVT_EVENTPARM(event[2])); + } + else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) + { +#if 0 + Renderer->HandleLongMessage((BYTE *)&event[3], MEVT_EVENTPARM(event[2])); +#endif + } + else if (MEVT_EVENTTYPE(event[2]) == 0) + { // Short MIDI event + int status = event[2] & 0xff; + int parm1 = (event[2] >> 8) & 0x7f; + int parm2 = (event[2] >> 16) & 0x7f; + HandleEvent(status, parm1, parm2); + } + + // Advance to next event. + if (event[2] < 0x80000000) + { // Short message + Position += 12; + } + else + { // Long message + Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); + } + + // Did we use up this buffer? + if (Position >= Events->dwBytesRecorded) + { + Events = Events->lpNext; + Position = 0; + + if (Callback != NULL) + { + Callback(MOM_DONE, CallbackData, 0, 0); + } + } + + if (Events == NULL) + { // No more events. Just return something to keep the song playing + // while we wait for more to be submitted. + return int(Division); + } + + delay = *(DWORD *)(Events->lpData + Position); + } + return delay; +} + +//========================================================================== +// +// FluidSynthtMIDIDevice :: ServiceStream +// +//========================================================================== + +bool FluidSynthMIDIDevice::ServiceStream (void *buff, int numbytes) +{ + float *samples = (float *)buff; + float *samples1; + int numsamples = numbytes / sizeof(float) / 2; + bool prev_ended = false; + bool res = true; + + samples1 = samples; + memset(buff, 0, numbytes); + + CritSec.Enter(); + while (Events != NULL && numsamples > 0) + { + double ticky = NextTickIn; + int tick_in = int(NextTickIn); + int samplesleft = MIN(numsamples, tick_in); + + if (samplesleft > 0) + { + fluid_synth_write_float(FluidSynth, samplesleft, + samples1, 0, 2, + samples1, 1, 2); + assert(NextTickIn == ticky); + NextTickIn -= samplesleft; + assert(NextTickIn >= 0); + numsamples -= samplesleft; + samples1 += samplesleft * 2; + } + + if (NextTickIn < 1) + { + int next = PlayTick(); + assert(next >= 0); + if (next == 0) + { // end of song + if (numsamples > 0) + { + fluid_synth_write_float(FluidSynth, numsamples, + samples1, 0, 2, + samples1, 1, 2); + } + res = false; + break; + } + else + { + NextTickIn += SamplesPerTick * next; + assert(NextTickIn >= 0); + } + } + } + if (Events == NULL) + { + res = false; + } + CritSec.Leave(); + return res; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: LoadPatchSets +// +// Loads a delimiter-separated list of patch sets. This delimiter matches +// that of the PATH environment variable. On Windows, it is ';'. On other +// systems, it is ':'. Returns the number of patch sets loaded. +// +//========================================================================== + +int FluidSynthMIDIDevice::LoadPatchSets(const char *patches) +{ + int count; + char *wpatches = strdup(patches); + char *tok; +#ifdef _WIN32 + const char *const delim = ";"; +#else + const char *const delim = ":"; +#endif + + if (wpatches == NULL) + { + return 0; + } + tok = strtok(wpatches, delim); + count = 0; + while (tok != NULL) + { + if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, tok, count == 0)) + { + DPrintf("Loaded patch set %s.\n", tok); + count++; + } + else + { + DPrintf("Failed to load patch set %s.\n", tok); + } + tok = strtok(NULL, delim); + } + free(wpatches); + return count; +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: FluidSettingInt +// +// Changes an integer setting. +// +//========================================================================== + +void FluidSynthMIDIDevice::FluidSettingInt(const char *setting, int value) +{ + if (strcmp(setting, "synth.interpolation") == 0) + { + if (FluidSynth != NULL) + { + if (FLUID_OK != fluid_synth_set_interp_method(FluidSynth, -1, value)) + { + Printf("Setting interpolation method %d failed.\n", value); + } + } + } + else if (FluidSynth != NULL && strcmp(setting, "synth.polyphony") == 0) + { + if (FLUID_OK != fluid_synth_set_polyphony(FluidSynth, value)) + { + Printf("Setting polyphony to %d failed.\n", value); + } + } + else if (FluidSettings != NULL) + { + if (!fluid_settings_setint(FluidSettings, setting, value)) + { + Printf("Faild to set %s to %d.\n", setting, value); + } + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: FluidSettingNum +// +// Changes a numeric setting. +// +//========================================================================== + +void FluidSynthMIDIDevice::FluidSettingNum(const char *setting, double value) +{ + if (FluidSettings != NULL) + { + if (!fluid_settings_setnum(FluidSettings, setting, value)) + { + Printf("Failed to set %s to %g.\n", setting, value); + } + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: FluidSettingStr +// +// Changes a string setting. +// +//========================================================================== + +void FluidSynthMIDIDevice::FluidSettingStr(const char *setting, const char *value) +{ + if (FluidSettings != NULL) + { + if (!fluid_settings_setstr(FluidSettings, setting, value)) + { + Printf("Failed to set %s to %s.\n", setting, value); + } + } +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: FillStream static +// +//========================================================================== + +bool FluidSynthMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +{ + FluidSynthMIDIDevice *device = (FluidSynthMIDIDevice *)userdata; + return device->ServiceStream(buff, len); +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: GetStats +// +//========================================================================== + +FString FluidSynthMIDIDevice::GetStats() +{ + if (FluidSynth == NULL || FluidSettings == NULL) + { + return "FluidSynth is invalid"; + } + FString out; + + CritSec.Enter(); + int polyphony = fluid_synth_get_polyphony(FluidSynth); + int voices = fluid_synth_get_active_voice_count(FluidSynth); + double load = fluid_synth_get_cpu_load(FluidSynth); + char *chorus, *reverb; + int maxpoly; + fluid_settings_getstr(FluidSettings, "synth.chorus.active", &chorus); + fluid_settings_getstr(FluidSettings, "synth.reverb.active", &reverb); + fluid_settings_getint(FluidSettings, "synth.polyphony", &maxpoly); + CritSec.Leave(); + + out.Format("Voices: "TEXTCOLOR_YELLOW"%3d"TEXTCOLOR_NORMAL"/"TEXTCOLOR_ORANGE"%3d"TEXTCOLOR_NORMAL"("TEXTCOLOR_RED"%3d"TEXTCOLOR_NORMAL")" + TEXTCOLOR_YELLOW"%6.2f"TEXTCOLOR_NORMAL"%% CPU " + "Reverb: "TEXTCOLOR_YELLOW"%3s"TEXTCOLOR_NORMAL + " Chorus: "TEXTCOLOR_YELLOW"%3s", + voices, polyphony, maxpoly, load, reverb, chorus); + return out; +} + +#endif + From d53ef3f38a41776fd7abba5920be03e5dd43ee3d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 15 Aug 2010 20:05:35 +0000 Subject: [PATCH 182/251] - Oops. These changes didn't belong in the repository. SVN r2547 (trunk) --- src/sound/fmodsound.cpp | 18 ++---------------- src/sound/fmodsound.h | 3 +-- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index bcd84b9fd..ff99d516e 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -644,7 +644,6 @@ bool FMODSoundRenderer::Init() ChannelGroupTargetUnit = NULL; SfxReverbHooked = false; SfxReverbPlaceholder = NULL; - SfxHeadMixer = NULL; OutputPlugin = 0; Printf("I_InitSound: Initializing FMOD\n"); @@ -1016,12 +1015,6 @@ bool FMODSoundRenderer::Init() result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxReverbPlaceholder); if (result == FMOD_OK) { - result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxHeadMixer); - result = sfx_head->addInput(SfxHeadMixer, &SfxConnection); - result = sfx_head->disconnectFrom(pausable_head); - sfx_head = SfxHeadMixer; - SfxHeadMixer->setActive(true); - SfxHeadMixer->setBypass(false); // Replace the PausableSFX->SFX connection with // PausableSFX->ReverbPlaceholder->SFX. result = SfxReverbPlaceholder->addInput(pausable_head, NULL); @@ -1031,13 +1024,13 @@ bool FMODSoundRenderer::Init() result = sfx_head->addInput(SfxReverbPlaceholder, &connection); if (result == FMOD_OK) { -// sfx_head->disconnectFrom(pausable_head); + sfx_head->disconnectFrom(pausable_head); SfxReverbPlaceholder->setActive(true); SfxReverbPlaceholder->setBypass(true); // The placeholder now takes the place of the pausable_head // for the following connections. pausable_head = SfxReverbPlaceholder; - // SfxConnection = connection; + SfxConnection = connection; } } else @@ -1046,7 +1039,6 @@ bool FMODSoundRenderer::Init() SfxReverbPlaceholder = NULL; } } -#if 1 result = WaterLP->addInput(pausable_head, NULL); WaterLP->setActive(false); WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp); @@ -1078,7 +1070,6 @@ bool FMODSoundRenderer::Init() { result = sfx_head->addInput(WaterLP, NULL); } -#endif } } } @@ -1157,11 +1148,6 @@ void FMODSoundRenderer::Shutdown() SfxReverbPlaceholder->release(); SfxReverbPlaceholder = NULL; } - if (SfxHeadMixer != NULL) - { - SfxHeadMixer->release(); - SfxHeadMixer = NULL; - } Sys->close(); if (OutputPlugin != 0) diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index f15629cb4..1460b697b 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -103,8 +103,7 @@ private: FMOD::DSP *WaterLP, *WaterReverb; FMOD::DSPConnection *SfxConnection; FMOD::DSP *ChannelGroupTargetUnit; - FMOD::DSP *SfxReverbPlaceholder; - FMOD::DSP *SfxHeadMixer; + FMOD::DSP *SfxReverbPlaceholder; bool SfxReverbHooked; float LastWaterLP; unsigned int OutputPlugin; From 050b82f543f2286f21f521ccb4bf872b298de26c Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 17 Aug 2010 04:22:17 +0000 Subject: [PATCH 183/251] - Fixed: ZDoom wouldn't compile without FluidSynth. SVN r2548 (trunk) --- src/CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6c0aa382..03cedcded 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -485,10 +485,14 @@ add_custom_target( revision_check ALL # Libraries ZDoom needs - message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" "${FLUIDSYNTH_LIBRARIES}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${FLUIDSYNTH_INCLUDE_DIR}" ) +set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) + +if( FLUIDSYNTH_FOUND ) + set( ZDOOM_LIBS "${FLUIDSYNTH_LIBRARIES}" ) + include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) +endif( FLUIDSYNTH_FOUND ) # Start defining source files for ZDoom From f9523a01e37b6fc8c44d5e299405864b509bf13b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 18 Aug 2010 20:26:25 +0000 Subject: [PATCH 184/251] - Added Gez's patch for moving tag strings into the language file and adding tags for all weapons and inventory items. SVN r2552 (trunk) --- src/g_game.cpp | 32 ++- src/g_shared/a_pickups.cpp | 1 + src/m_options.cpp | 11 +- wadsrc/static/actors/chex/chexweapons.txt | 9 + wadsrc/static/actors/doom/doomweapons.txt | 9 + .../actors/heretic/hereticartifacts.txt | 3 + wadsrc/static/actors/heretic/hereticweaps.txt | 50 +++- wadsrc/static/actors/hexen/blastradius.txt | 1 + wadsrc/static/actors/hexen/boostarmor.txt | 1 + wadsrc/static/actors/hexen/clericflame.txt | 3 + wadsrc/static/actors/hexen/clericholy.txt | 2 + wadsrc/static/actors/hexen/clericmace.txt | 2 + wadsrc/static/actors/hexen/clericstaff.txt | 3 + wadsrc/static/actors/hexen/fighteraxe.txt | 2 + wadsrc/static/actors/hexen/fighterfist.txt | 2 + wadsrc/static/actors/hexen/fighterhammer.txt | 3 + wadsrc/static/actors/hexen/fighterquietus.txt | 2 + wadsrc/static/actors/hexen/flechette.txt | 4 + wadsrc/static/actors/hexen/healingradius.txt | 1 + wadsrc/static/actors/hexen/magecone.txt | 3 + wadsrc/static/actors/hexen/magelightning.txt | 3 + wadsrc/static/actors/hexen/magestaff.txt | 2 + wadsrc/static/actors/hexen/magewand.txt | 2 + wadsrc/static/actors/hexen/mana.txt | 1 + wadsrc/static/actors/hexen/puzzleitems.txt | 17 ++ wadsrc/static/actors/hexen/speedboots.txt | 1 + wadsrc/static/actors/hexen/summon.txt | 1 + wadsrc/static/actors/hexen/teleportother.txt | 1 + wadsrc/static/actors/raven/artiegg.txt | 2 + wadsrc/static/actors/raven/artitele.txt | 1 + wadsrc/static/actors/raven/ravenartifacts.txt | 6 + wadsrc/static/actors/strife/acolyte.txt | 2 +- wadsrc/static/actors/strife/beggars.txt | 2 +- wadsrc/static/actors/strife/coin.txt | 10 +- wadsrc/static/actors/strife/loremaster.txt | 2 +- wadsrc/static/actors/strife/macil.txt | 3 +- wadsrc/static/actors/strife/merchants.txt | 8 +- wadsrc/static/actors/strife/oracle.txt | 2 +- wadsrc/static/actors/strife/questitems.txt | 6 +- wadsrc/static/actors/strife/ratbuddy.txt | 2 +- wadsrc/static/actors/strife/rebels.txt | 4 +- wadsrc/static/actors/strife/sigil.txt | 2 +- wadsrc/static/actors/strife/strifeammo.txt | 22 +- wadsrc/static/actors/strife/strifearmor.txt | 4 +- wadsrc/static/actors/strife/strifeitems.txt | 52 ++-- wadsrc/static/actors/strife/strifekeys.txt | 58 ++--- wadsrc/static/actors/strife/strifeweapons.txt | 29 ++- wadsrc/static/actors/strife/templar.txt | 2 +- wadsrc/static/language.enu | 245 ++++++++++++++++++ 49 files changed, 520 insertions(+), 116 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index d68ead9ef..fadfb6c55 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -116,13 +116,13 @@ EXTERN_CVAR (Float, con_midtime); // // CVAR displaynametags // -// Selects whether to display name tags or not when changing weapons +// Selects whether to display name tags or not when changing weapons/items // //========================================================================== -CUSTOM_CVAR (Bool, displaynametags, 0, CVAR_ARCHIVE) +CUSTOM_CVAR (Int, displaynametags, 0, CVAR_ARCHIVE) { - if (self != 0 && self != 1) + if (self < 0 || self > 3) { self = 0; } @@ -322,11 +322,23 @@ CCMD (turn180) CCMD (weapnext) { SendItemUse = players[consoleplayer].weapons.PickNextWeapon (&players[consoleplayer]); + // [BC] Option to display the name of the weapon being cycled to. + if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse) + { + StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(), + 1.5f, 0.90f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' )); + } } CCMD (weapprev) { SendItemUse = players[consoleplayer].weapons.PickPrevWeapon (&players[consoleplayer]); + // [BC] Option to display the name of the weapon being cycled to. + if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse) + { + StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(), + 1.5f, 0.90f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' )); + } } CCMD (invnext) @@ -354,10 +366,9 @@ CCMD (invnext) who->InvSel = who->Inventory; } } - if (displaynametags && StatusBar && SmallFont - && gamestate == GS_LEVEL && level.time > con_midtime && who->InvSel) - StatusBar->AttachMessage (new DHUDMessage (SmallFont, who->InvSel->GetTag(), - 2.5f, 0.375f, 0, 0, CR_YELLOW, con_midtime), MAKE_ID('S','I','N','V')); + if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel) + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(), + 1.5f, 0.80f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID('S','I','N','V')); } who->player->inventorytics = 5*TICRATE; } @@ -385,10 +396,9 @@ CCMD (invprev) } who->InvSel = item; } - if (displaynametags && StatusBar && SmallFont - && gamestate == GS_LEVEL && level.time > con_midtime && who->InvSel) - StatusBar->AttachMessage (new DHUDMessage (SmallFont, who->InvSel->GetTag(), - 2.5f, 0.375f, 0, 0, CR_YELLOW, con_midtime), MAKE_ID('S','I','N','V')); + if ((displaynametags & 1) && StatusBar && SmallFont && who->InvSel) + StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, who->InvSel->GetTag(), + 1.5f, 0.80f, 0, 0, CR_GOLD, 2.f, 0.35f), MAKE_ID('S','I','N','V')); } who->player->inventorytics = 5*TICRATE; } diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 194618933..3802bd477 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -356,6 +356,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) self->z += FloatBobOffsets[(self->FloatBobPhase + level.maptime) & 63]; } } + self->SetOrigin (self->x, self->y, self->z); } int AInventory::StaticLastMessageTic; diff --git a/src/m_options.cpp b/src/m_options.cpp index 2357c930a..4f822befe 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -93,7 +93,7 @@ EXTERN_CVAR(Int, showendoom) EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Int, compatmode) EXTERN_CVAR (Bool, vid_vsync) -EXTERN_CVAR(Bool, displaynametags) +EXTERN_CVAR(Int, displaynametags) EXTERN_CVAR (Int, snd_channels) // @@ -485,6 +485,13 @@ static value_t Contrast[] = { { 2.0, "Smooth" } }; +static value_t DisplayTagsTypes[] = { + { 0.0, "None" }, + { 1.0, "Items" }, + { 2.0, "Weapons" }, + { 3.0, "Both" } +}; + static menuitem_t VideoItems[] = { { more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} }, { more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} }, @@ -510,7 +517,7 @@ static menuitem_t VideoItems[] = { { discrete, "Rocket Trails", {&cl_rockettrails}, {4.0}, {0.0}, {0.0}, {RocketTrailTypes} }, { discrete, "Blood Type", {&cl_bloodtype}, {3.0}, {0.0}, {0.0}, {BloodTypes} }, { discrete, "Bullet Puff Type", {&cl_pufftype}, {2.0}, {0.0}, {0.0}, {PuffTypes} }, - { discrete, "Display nametags", {&displaynametags}, {2.0}, {0.0}, {0.0}, {YesNo} }, + { discrete, "Display nametags", {&displaynametags}, {4.0}, {0.0}, {0.0}, {DisplayTagsTypes} }, }; #define CROSSHAIR_INDEX 7 diff --git a/wadsrc/static/actors/chex/chexweapons.txt b/wadsrc/static/actors/chex/chexweapons.txt index 4fa7eec56..97043f2ca 100644 --- a/wadsrc/static/actors/chex/chexweapons.txt +++ b/wadsrc/static/actors/chex/chexweapons.txt @@ -4,6 +4,7 @@ actor Bootspoon : Fist { game Chex obituary "$OB_MPSPOON" + Tag "$TAG_SPOON" } actor SuperBootspork : Chainsaw 2005 @@ -11,6 +12,7 @@ actor SuperBootspork : Chainsaw 2005 game Chex obituary "$OB_MPBOOTSPORK" Inventory.PickupMessage "$GOTSUPERBOOTSPORK" + Tag "$TAG_SPORK" } actor MiniZorcher : Pistol @@ -18,6 +20,7 @@ actor MiniZorcher : Pistol game Chex obituary "$OP_MPZORCH" inventory.pickupmessage "$GOTMINIZORCHER" + Tag "$TAG_MINIZORCHER" states { Spawn: @@ -30,6 +33,7 @@ actor LargeZorcher : Shotgun 2001 game Chex obituary "$OP_MPZORCH" inventory.pickupmessage "$GOTLARGEZORCHER" + Tag "$TAG_LARGEZORCHER" } actor SuperLargeZorcher : SuperShotgun 82 @@ -37,6 +41,7 @@ actor SuperLargeZorcher : SuperShotgun 82 game Chex obituary "$OB_MPMEGAZORCH" inventory.pickupmessage "$GOTSUPERLARGEZORCHER" + Tag "$TAG_SUPERLARGEZORCHER" } actor RapidZorcher : Chaingun 2002 @@ -44,6 +49,7 @@ actor RapidZorcher : Chaingun 2002 game Chex obituary "$OB_MPRAPIDZORCH" inventory.pickupmessage "$GOTRAPIDZORCHER" + Tag "$TAG_RAPIDZORCHER" } actor ZorchPropulsor : RocketLauncher 2003 @@ -51,6 +57,7 @@ actor ZorchPropulsor : RocketLauncher 2003 game Chex obituary "" inventory.pickupmessage "$GOTZORCHPROPULSOR" + Tag "$TAG_ZORCHPROPULSOR" States { Fire: @@ -75,6 +82,7 @@ actor PhasingZorcher : PlasmaRifle 2004 game Chex obituary "" inventory.pickupmessage "$GOTPHASINGZORCHER" + Tag "$TAG_PHASINGZORCHER" states { Fire: @@ -104,6 +112,7 @@ actor LAZDevice : BFG9000 2006 game Chex obituary "" inventory.pickupmessage "$GOTLAZDEVICE" + Tag "$TAG_LAZDEVICE" states { Fire: diff --git a/wadsrc/static/actors/doom/doomweapons.txt b/wadsrc/static/actors/doom/doomweapons.txt index 076559c0e..b748f8611 100644 --- a/wadsrc/static/actors/doom/doomweapons.txt +++ b/wadsrc/static/actors/doom/doomweapons.txt @@ -21,6 +21,7 @@ ACTOR Fist : Weapon Weapon.SelectionOrder 3700 Weapon.Kickback 100 Obituary "$OB_MPFIST" + Tag "$FIST" +WEAPON.WIMPY_WEAPON +WEAPON.MELEEWEAPON States @@ -61,6 +62,7 @@ ACTOR Pistol : DoomWeapon 5010 Obituary "$OB_MPPISTOL" +WEAPON.WIMPY_WEAPON Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED" + Tag "$TAG_PISTOL" States { Ready: @@ -105,6 +107,7 @@ ACTOR Chainsaw : Weapon 2005 Weapon.ReadySound "weapons/sawidle" Inventory.PickupMessage "$GOTCHAINSAW" Obituary "$OB_MPCHAINSAW" + Tag "$TAG_CHAINSAW" +WEAPON.MELEEWEAPON States { @@ -144,6 +147,7 @@ ACTOR Shotgun : DoomWeapon 2001 Weapon.AmmoType "Shell" Inventory.PickupMessage "$GOTSHOTGUN" Obituary "$OB_MPSHOTGUN" + Tag "$TAG_SHOTGUN" States { Ready: @@ -190,6 +194,7 @@ ACTOR SuperShotgun : DoomWeapon 82 Weapon.AmmoType "Shell" Inventory.PickupMessage "$GOTSHOTGUN2" Obituary "$OB_MPSSHOTGUN" + Tag "$TAG_SUPERSHOTGUN" States { Ready: @@ -243,6 +248,7 @@ ACTOR Chaingun : DoomWeapon 2002 Weapon.AmmoType "Clip" Inventory.PickupMessage "$GOTCHAINGUN" Obituary "$OB_MPCHAINGUN" + Tag "$TAG_CHAINGUN" States { Ready: @@ -285,6 +291,7 @@ ACTOR RocketLauncher : DoomWeapon 2003 Weapon.AmmoType "RocketAmmo" +WEAPON.NOAUTOFIRE Inventory.PickupMessage "$GOTLAUNCHER" + Tag "$TAG_ROCKETLAUNCHER" States { Ready: @@ -406,6 +413,7 @@ ACTOR PlasmaRifle : DoomWeapon 2004 Weapon.AmmoGive 40 Weapon.AmmoType "Cell" Inventory.PickupMessage "$GOTPLASMA" + Tag "$TAG_PLASMARIFLE" States { Ready: @@ -511,6 +519,7 @@ ACTOR BFG9000 : DoomWeapon 2006 Weapon.AmmoType "Cell" +WEAPON.NOAUTOFIRE Inventory.PickupMessage "$GOTBFG9000" + Tag "$TAG_BFG9000" States { Ready: diff --git a/wadsrc/static/actors/heretic/hereticartifacts.txt b/wadsrc/static/actors/heretic/hereticartifacts.txt index 0d5ede1a6..67d3946b9 100644 --- a/wadsrc/static/actors/heretic/hereticartifacts.txt +++ b/wadsrc/static/actors/heretic/hereticartifacts.txt @@ -33,6 +33,7 @@ ACTOR ArtiInvisibility : PowerupGiver 75 Inventory.Icon ARTIINVS Powerup.Type Ghost Inventory.PickupMessage "$TXT_ARTIINVISIBILITY" + Tag "$TAG_ARTIINVISIBILITY" States { Spawn: @@ -54,6 +55,7 @@ ACTOR ArtiTomeOfPower : PowerupGiver 86 native Inventory.Icon "ARTIPWBK" Powerup.Type Weaponlevel2 Inventory.PickupMessage "$TXT_ARTITOMEOFPOWER" + Tag "$TAG_ARTITOMEOFPOWER" States { Spawn: @@ -98,6 +100,7 @@ ACTOR ArtiTimeBomb : Inventory 34 native Inventory.Icon "ARTIFBMB" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIFIREBOMB" + Tag "$TAG_ARTIFIREBOMB" Inventory.DefMaxAmount States { diff --git a/wadsrc/static/actors/heretic/hereticweaps.txt b/wadsrc/static/actors/heretic/hereticweaps.txt index 993da1485..7e2d0a2ee 100644 --- a/wadsrc/static/actors/heretic/hereticweaps.txt +++ b/wadsrc/static/actors/heretic/hereticweaps.txt @@ -15,6 +15,8 @@ ACTOR Staff : HereticWeapon +WIMPY_WEAPON +MELEEWEAPON Weapon.sisterweapon "StaffPowered" + Obituary "$OB_MPSTAFF" + Tag "$TAG_STAFF" action native A_StaffAttack (int damage, class puff); @@ -45,6 +47,8 @@ ACTOR StaffPowered : Staff +WEAPON.POWERED_UP +WEAPON.READYSNDHALF +WEAPON.STAFF2_KICKBACK + Obituary "$OB_MPPSTAFF" + Tag "$TAG_STAFFP" States { Ready: @@ -116,6 +120,8 @@ ACTOR GoldWand : HereticWeapon Weapon.AmmoType "GoldWandAmmo" Weapon.SisterWeapon "GoldWandPowered" Weapon.YAdjust 5 + Obituary "$OB_MPGOLDWAND" + Tag "$TAG_GOLDWAND" action native A_FireGoldWandPL1 (); @@ -145,6 +151,8 @@ ACTOR GoldWandPowered : GoldWand +WEAPON.POWERED_UP Weapon.AmmoGive 0 Weapon.SisterWeapon "GoldWand" + Obituary "$OB_MPPGOLDWAND" + Tag "$TAG_GOLDWANDP" action native A_FireGoldWandPL2 (); @@ -173,6 +181,7 @@ ACTOR GoldWandFX1 Projectile RenderStyle Add DeathSound "weapons/wandhit" + Obituary "$OB_MPPGOLDWAND" States { Spawn: @@ -209,7 +218,8 @@ ACTOR GoldWandPuff1 +NOGRAVITY +PUFFONACTORS RenderStyle Add - States { + States + { Spawn: PUF2 ABCDE 3 BRIGHT Stop @@ -243,7 +253,8 @@ ACTOR Crossbow : HereticWeapon 2001 Weapon.AmmoType "CrossbowAmmo" Weapon.SisterWeapon "CrossbowPowered" Weapon.YAdjust 15 - Inventory.PickupMessage "$TxT_WPNCROSSBOW" + Inventory.PickupMessage "$TXT_WPNCROSSBOW" + Tag "$TAG_CROSSBOW" action native A_FireCrossbowPL1 (); @@ -277,6 +288,7 @@ ACTOR CrossbowPowered : Crossbow +WEAPON.POWERED_UP Weapon.AmmoGive 0 Weapon.SisterWeapon "Crossbow" + Tag "$TAG_CROSSBOWP" action native A_FireCrossbowPL2(); @@ -310,6 +322,7 @@ ACTOR CrossbowFX1 RenderStyle Add SeeSound "weapons/bowshoot" DeathSound "weapons/bowhit" + Obituary "$OB_MPCROSSBOW" States { Spawn: @@ -330,6 +343,7 @@ ACTOR CrossbowFX2 : CrossbowFX1 SpawnID 148 Speed 32 Damage 6 + Obituary "$OB_MPPCROSSBOW" States { Spawn: @@ -394,6 +408,8 @@ ACTOR Gauntlets : Weapon 2005 Weapon.UpSound "weapons/gauntletsactivate" Weapon.SisterWeapon "GauntletsPowered" Inventory.PickupMessage "$TXT_WPNGAUNTLETS" + Tag "$TAG_GAUNTLETS" + Obituary "$OB_MPGAUNTLETS" action native A_GauntletAttack (int power); @@ -427,6 +443,8 @@ ACTOR GauntletsPowered : Gauntlets { Game Heretic +POWERED_UP + Tag "$TAG_GAUNTLETSP" + Obituary "$OB_MPPGAUNTLETS" Weapon.SisterWeapon "Gauntlets" States { @@ -469,7 +487,7 @@ ACTOR GauntletPuff1 } } -// Gauntlett puff 2 --------------------------------------------------------- +// Gauntlet puff 2 --------------------------------------------------------- ACTOR GauntletPuff2 : GauntletPuff1 { @@ -494,7 +512,8 @@ ACTOR Mace : HereticWeapon Weapon.YAdjust 15 Weapon.AmmoType "MaceAmmo" Weapon.SisterWeapon "MacePowered" - Inventory.PickupMessage "$TxT_WPNMACE" + Inventory.PickupMessage "$TXT_WPNMACE" + Tag "$TAG_MACE" action native A_FireMacePL1(); @@ -529,6 +548,7 @@ ACTOR MacePowered : Mace Weapon.AmmoUse 5 Weapon.AmmoGive 0 Weapon.SisterWeapon "Mace" + Tag "$TAG_MACEP" action native A_FireMacePL2(); @@ -558,6 +578,7 @@ ACTOR MaceFX1 +THRUGHOST BounceType "HereticCompat" SeeSound "weapons/maceshoot" + Obituary "$OB_MPMACE" action native A_MacePL1Check(); action native A_MaceBallImpact(); @@ -636,6 +657,7 @@ ACTOR MaceFX4 native -NOTELEPORT BounceType "HereticCompat" SeeSound "" + Obituary "$OB_MPPMACE" action native A_DeathBallImpact(); @@ -682,7 +704,9 @@ ACTOR Blaster : HereticWeapon 53 Weapon.YAdjust 15 Weapon.AmmoType "BlasterAmmo" Weapon.SisterWeapon "BlasterPowered" - Inventory.PickupMessage "$TxT_WPNBLASTER" + Inventory.PickupMessage "$TXT_WPNBLASTER" + Tag "$TAG_BLASTER" + Obituary "$OB_MPBLASTER" action native A_FireBlasterPL1(); @@ -740,6 +764,8 @@ ACTOR BlasterFX1 : FastProjectile native SeeSound "weapons/blastershoot" DeathSound "weapons/blasterhit" +SPAWNSOUNDSOURCE + Obituary "$OB_MPPBLASTER" + Tag "$TAG_BLASTERP" action native A_SpawnRippers(); @@ -787,6 +813,7 @@ ACTOR Ripper native Projectile +RIPPER DeathSound "weapons/blasterpowhit" + Obituary "$OB_MPPBLASTER" States { Spawn: @@ -832,7 +859,8 @@ ACTOR SkullRod : HereticWeapon 2004 Weapon.YAdjust 15 Weapon.AmmoType1 "SkullRodAmmo" Weapon.SisterWeapon "SkullRodPowered" - Inventory.PickupMessage "$TxT_WPNSKULLROD" + Inventory.PickupMessage "$TXT_WPNSKULLROD" + Tag "$TAG_SKULLROD" action native A_FireSkullRodPL1(); @@ -864,6 +892,7 @@ ACTOR SkullRodPowered : SkullRod Weapon.AmmoUse1 5 Weapon.AmmoGive1 0 Weapon.SisterWeapon "SkullRod" + Tag "$TAG_SKULLRODP" action native A_FireSkullRodPL2(); @@ -899,6 +928,7 @@ ACTOR HornRodFX1 RenderStyle Add SeeSound "weapons/hornrodshoot" DeathSound "weapons/hornrodhit" + Obituary "$OB_MPSKULLROD" States { Spawn: @@ -926,6 +956,7 @@ ACTOR HornRodFX2 native RenderStyle Add SeeSound "weapons/hornrodpowshoot" DeathSound "weapons/hornrodpowhit" + Obituary "$OB_MPPSKULLROD" action native A_AddPlayerRain(); action native A_HideInCeiling(); @@ -963,6 +994,7 @@ ACTOR RainPillar native -ACTIVATEPCROSS -ACTIVATEIMPACT RenderStyle Add + Obituary "$OB_MPPSKULLROD" action native A_RainImpact(); @@ -1003,7 +1035,8 @@ ACTOR PhoenixRod : Weapon 2003 native Weapon.AmmoGive 2 Weapon.AmmoType "PhoenixRodAmmo" Weapon.Sisterweapon "PhoenixRodPowered" - Inventory.PickupMessage "$TxT_WPNPHOENIxROD" + Inventory.PickupMessage "$TXT_WPNPHOENIxROD" + Tag "$TAG_PHOENIxROD" action native A_FirePhoenixPL1(); @@ -1037,6 +1070,7 @@ ACTOR PhoenixRodPowered : PhoenixRod native +WEAPON.MELEEWEAPON Weapon.SisterWeapon "PhoenixRod" Weapon.AmmoGive 0 + Tag "$TAG_PHOENIxRODP" action native A_InitPhoenixPL2(); action native A_FirePhoenixPL2(); @@ -1071,6 +1105,7 @@ ACTOR PhoenixFX1 native +SPECIALFIREDAMAGE SeeSound "weapons/phoenixshoot" DeathSound "weapons/phoenixhit" + Obituary "$OB_MPPHOENIXROD" action native A_PhoenixPuff(); @@ -1116,6 +1151,7 @@ ACTOR PhoenixFX2 native DamageType Fire Projectile RenderStyle Add + Obituary "$OB_MPPPHOENIXROD" action native A_FlameEnd(); action native A_FloatPuff(); diff --git a/wadsrc/static/actors/hexen/blastradius.txt b/wadsrc/static/actors/hexen/blastradius.txt index 7e4259cf8..ad98d7ecc 100644 --- a/wadsrc/static/actors/hexen/blastradius.txt +++ b/wadsrc/static/actors/hexen/blastradius.txt @@ -10,6 +10,7 @@ ACTOR ArtiBlastRadius : CustomInventory 10110 Inventory.Icon "ARTIBLST" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIBLASTRADIUS" + Tag "$TAG_ARTIBLASTRADIUS" States { Spawn: diff --git a/wadsrc/static/actors/hexen/boostarmor.txt b/wadsrc/static/actors/hexen/boostarmor.txt index ca3b8384c..607c8d66a 100644 --- a/wadsrc/static/actors/hexen/boostarmor.txt +++ b/wadsrc/static/actors/hexen/boostarmor.txt @@ -13,6 +13,7 @@ ACTOR ArtiBoostArmor : Inventory 8041 native Inventory.Icon "ARTIBRAC" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIBOOSTARMOR" + Tag "$TAG_ARTIBOOSTARMOR" States { Spawn: diff --git a/wadsrc/static/actors/hexen/clericflame.txt b/wadsrc/static/actors/hexen/clericflame.txt index 29312ca79..5fb4175fd 100644 --- a/wadsrc/static/actors/hexen/clericflame.txt +++ b/wadsrc/static/actors/hexen/clericflame.txt @@ -12,6 +12,7 @@ ACTOR CWeapFlame : ClericWeapon 8009 Weapon.YAdjust 10 Weapon.AmmoType1 "Mana2" Inventory.PickupMessage "$TXT_WEAPON_C3" + Tag "$TAG_CWEAPFLAME" action native A_CFlameAttack(); @@ -126,6 +127,7 @@ ACTOR CircleFlame -ACTIVATEPCROSS RenderStyle Add DeathSound "ClericFlameCircle" + Obituary "$OB_MPCWEAPFLAME" action native A_CFlameRotate(); @@ -166,6 +168,7 @@ ACTOR CFlameMissile : FastProjectile native DamageType "Fire" +INVISIBLE RenderStyle Add + Obituary "$OB_MPCWEAPFLAME" action native A_CFlamePuff(); action native A_CFlameMissile(); diff --git a/wadsrc/static/actors/hexen/clericholy.txt b/wadsrc/static/actors/hexen/clericholy.txt index 0c441726d..15673ab1b 100644 --- a/wadsrc/static/actors/hexen/clericholy.txt +++ b/wadsrc/static/actors/hexen/clericholy.txt @@ -84,6 +84,7 @@ ACTOR CWeapWraithverge : ClericWeapon native Weapon.AmmoType1 "Mana1" Weapon.AmmoType2 "Mana2" Inventory.PickupMessage "$TXT_WEAPON_C4" + Tag "$TAG_CWEAPWRAITHVERGE" Inventory.PickupSound "WeaponBuild" action native A_CHolyAttack(); @@ -187,6 +188,7 @@ ACTOR HolySpirit native RenderStyle Translucent Alpha 0.4 DeathSound "SpiritDie" + Obituary "$OB_MPCWEAPWRAITHVERGE" action native A_CHolySeek(); action native A_CHolyCheckScream(); diff --git a/wadsrc/static/actors/hexen/clericmace.txt b/wadsrc/static/actors/hexen/clericmace.txt index ae9d3b84a..14ef4b00f 100644 --- a/wadsrc/static/actors/hexen/clericmace.txt +++ b/wadsrc/static/actors/hexen/clericmace.txt @@ -8,6 +8,8 @@ ACTOR CWeapMace : ClericWeapon Weapon.KickBack 150 Weapon.YAdjust -8 +BLOODSPLATTER + Obituary "$OB_MPCWEAPMACE" + Tag "$TAG_CWEAPMACE" action native A_CMaceAttack(); diff --git a/wadsrc/static/actors/hexen/clericstaff.txt b/wadsrc/static/actors/hexen/clericstaff.txt index 3b9cd1699..e55674fa5 100644 --- a/wadsrc/static/actors/hexen/clericstaff.txt +++ b/wadsrc/static/actors/hexen/clericstaff.txt @@ -12,6 +12,8 @@ ACTOR CWeapStaff : ClericWeapon 10 Weapon.YAdjust 10 Weapon.AmmoType1 "Mana1" Inventory.PickupMessage "$TXT_WEAPON_C2" + Obituary "$OB_MPCWEAPSTAFFM" + Tag "$TAG_CWEAPSTAFF" action native A_CStaffInitBlink(); action native A_CStaffCheckBlink(); @@ -65,6 +67,7 @@ ACTOR CStaffMissile native RenderStyle Add Projectile DeathSound "ClericCStaffExplode" + Obituary "$OB_MPCWEAPSTAFFR" States { Spawn: diff --git a/wadsrc/static/actors/hexen/fighteraxe.txt b/wadsrc/static/actors/hexen/fighteraxe.txt index 78cbbf0a3..502de5030 100644 --- a/wadsrc/static/actors/hexen/fighteraxe.txt +++ b/wadsrc/static/actors/hexen/fighteraxe.txt @@ -13,6 +13,8 @@ ACTOR FWeapAxe : FighterWeapon 8010 native Weapon.YAdjust -12 Weapon.AmmoType1 "Mana1" Inventory.PickupMessage "$TXT_WEAPON_F2" + Obituary "$OB_MPFWEAPAXE" + Tag "$TAG_FWEAPAXE" action native A_FAxeCheckUp(); action native A_FAxeCheckReady(); diff --git a/wadsrc/static/actors/hexen/fighterfist.txt b/wadsrc/static/actors/hexen/fighterfist.txt index 6693b79bf..0122d7f74 100644 --- a/wadsrc/static/actors/hexen/fighterfist.txt +++ b/wadsrc/static/actors/hexen/fighterfist.txt @@ -8,6 +8,8 @@ ACTOR FWeapFist : FighterWeapon Weapon.SelectionOrder 3400 +WEAPON.MELEEWEAPON Weapon.KickBack 150 + Obituary "$OB_MPFWEAPFIST" + Tag "$TAG_FWEAPFIST" action native A_FPunchAttack(); diff --git a/wadsrc/static/actors/hexen/fighterhammer.txt b/wadsrc/static/actors/hexen/fighterhammer.txt index 63585b1cc..5c7d6dc25 100644 --- a/wadsrc/static/actors/hexen/fighterhammer.txt +++ b/wadsrc/static/actors/hexen/fighterhammer.txt @@ -14,6 +14,8 @@ ACTOR FWeapHammer : FighterWeapon 123 Weapon.YAdjust -10 Weapon.AmmoType1 "Mana2" Inventory.PickupMessage "$TXT_WEAPON_F3" + Obituary "$OB_MPFWEAPHAMMERM" + Tag "$TAG_FWEAPHAMMER" action native A_FHammerAttack(); action native A_FHammerThrow(); @@ -60,6 +62,7 @@ ACTOR HammerMissile DamageType "Fire" Projectile DeathSound "FighterHammerExplode" + Obituary "$OB_MPFWEAPHAMMERR" States { diff --git a/wadsrc/static/actors/hexen/fighterquietus.txt b/wadsrc/static/actors/hexen/fighterquietus.txt index 3bd5904f7..034914d23 100644 --- a/wadsrc/static/actors/hexen/fighterquietus.txt +++ b/wadsrc/static/actors/hexen/fighterquietus.txt @@ -86,6 +86,7 @@ ACTOR FWeapQuietus : FighterWeapon Weapon.AmmoType2 "Mana2" Inventory.PickupMessage "$TXT_WEAPON_F4" Inventory.PickupSound "WeaponBuild" + Tag "$TAG_FWEAPQUIETUS" action native A_FSwordAttack(); @@ -131,6 +132,7 @@ ACTOR FSwordMissile native +EXTREMEDEATH RenderStyle Add DeathSound "FighterSwordExplode" + Obituary "$OB_MPFWEAPQUIETUS" action native A_FSwordFlames(); diff --git a/wadsrc/static/actors/hexen/flechette.txt b/wadsrc/static/actors/hexen/flechette.txt index 4820a706d..b2063a6ec 100644 --- a/wadsrc/static/actors/hexen/flechette.txt +++ b/wadsrc/static/actors/hexen/flechette.txt @@ -105,6 +105,7 @@ ACTOR ArtiPoisonBag : Inventory 8000 native Inventory.Icon "ARTIPSBG" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIPOISONBAG" + Tag "$TAG_ARTIPOISONBAG" States { Spawn: @@ -118,6 +119,7 @@ ACTOR ArtiPoisonBag : Inventory 8000 native ACTOR ArtiPoisonBag1 : ArtiPoisonBag native { Inventory.Icon "ARTIPSB1" + Tag "$TAG_ARTIPOISONBAG1" } // Poison Bag 2 (The Mage's) ------------------------------------------------ @@ -125,6 +127,7 @@ ACTOR ArtiPoisonBag1 : ArtiPoisonBag native ACTOR ArtiPoisonBag2 : ArtiPoisonBag native { Inventory.Icon "ARTIPSB2" + Tag "$TAG_ARTIPOISONBAG2" } // Poison Bag 3 (The Fighter's) --------------------------------------------- @@ -132,6 +135,7 @@ ACTOR ArtiPoisonBag2 : ArtiPoisonBag native ACTOR ArtiPoisonBag3 : ArtiPoisonBag native { Inventory.Icon "ARTIPSB3" + Tag "$TAG_ARTIPOISONBAG3" } // Poison Cloud ------------------------------------------------------------- diff --git a/wadsrc/static/actors/hexen/healingradius.txt b/wadsrc/static/actors/hexen/healingradius.txt index 8c5b0e53a..e0556915b 100644 --- a/wadsrc/static/actors/hexen/healingradius.txt +++ b/wadsrc/static/actors/hexen/healingradius.txt @@ -13,6 +13,7 @@ ACTOR ArtiHealingRadius : Inventory 10120 native Inventory.Icon "ARTIHRAD" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIHEALINGRADIUS" + Tag "$TAG_ARTIHEALINGRADIUS" States { Spawn: diff --git a/wadsrc/static/actors/hexen/magecone.txt b/wadsrc/static/actors/hexen/magecone.txt index 17c7ccf4f..b5dfdb546 100644 --- a/wadsrc/static/actors/hexen/magecone.txt +++ b/wadsrc/static/actors/hexen/magecone.txt @@ -13,6 +13,8 @@ ACTOR MWeapFrost : MageWeapon 53 Weapon.YAdjust 20 Weapon.AmmoType1 "Mana1" Inventory.PickupMessage "$TXT_WEAPON_M2" + Obituary "$OB_MPMWEAPFROST" + Tag "$TAG_MWEAPFROST" action native A_FireConePL1(); @@ -55,6 +57,7 @@ ACTOR FrostMissile native DamageType "Ice" Projectile DeathSound "MageShardsExplode" + Obituary "$OB_MPMWEAPFROST" action native A_ShedShard(); diff --git a/wadsrc/static/actors/hexen/magelightning.txt b/wadsrc/static/actors/hexen/magelightning.txt index 02658bcba..85402f223 100644 --- a/wadsrc/static/actors/hexen/magelightning.txt +++ b/wadsrc/static/actors/hexen/magelightning.txt @@ -12,6 +12,7 @@ ACTOR MWeapLightning : MageWeapon 8040 Weapon.YAdjust 20 Weapon.AmmoType1 "Mana2" Inventory.PickupMessage "$TXT_WEAPON_M3" + Tag "$TAG_MWEAPLIGHTNING" action native A_LightningReady(); action native A_MLightningAttack(class floor = "LightningFloor", class ceiling = "LightningCeiling"); @@ -56,6 +57,7 @@ ACTOR Lightning native MissileType "LightningZap" AttackSound "MageLightningZap" ActiveSound "MageLightningContinuous" + Obituary "$OB_MPMWEAPLIGHTNING" } ACTOR LightningCeiling : Lightning @@ -137,6 +139,7 @@ ACTOR LightningZap native -ACTIVATEIMPACT -ACTIVATEPCROSS RenderStyle Add + Obituary "$OB_MPMWEAPLIGHTNING" action native A_ZapMimic(); diff --git a/wadsrc/static/actors/hexen/magestaff.txt b/wadsrc/static/actors/hexen/magestaff.txt index e402e57c0..65c0ac893 100644 --- a/wadsrc/static/actors/hexen/magestaff.txt +++ b/wadsrc/static/actors/hexen/magestaff.txt @@ -86,6 +86,7 @@ ACTOR MWeapBloodscourge : MageWeapon native +Inventory.NoAttenPickupSound Inventory.PickupMessage "$TXT_WEAPON_M4" Inventory.PickupSound "WeaponBuild" + Tag "$TAG_MWEAPBLOODSCOURGE" action native A_MStaffAttack(); action native A_MStaffPalette(); @@ -128,6 +129,7 @@ ACTOR MageStaffFX2 native +SCREENSEEKER +EXTREMEDEATH DeathSound "MageStaffExplode" + Obituary "$OB_MPMWEAPBLOODSCOURGE" action native A_MStaffTrack(); diff --git a/wadsrc/static/actors/hexen/magewand.txt b/wadsrc/static/actors/hexen/magewand.txt index ebb8e2ca1..aaac9e5da 100644 --- a/wadsrc/static/actors/hexen/magewand.txt +++ b/wadsrc/static/actors/hexen/magewand.txt @@ -7,6 +7,7 @@ ACTOR MWeapWand : MageWeapon Weapon.SelectionOrder 3600 Weapon.KickBack 0 Weapon.YAdjust 9 + Tag "$TAG_MWEAPWAND" States { @@ -56,6 +57,7 @@ ACTOR MageWandMissile : FastProjectile +SPAWNSOUNDSOURCE MissileType "MageWandSmoke" SeeSound "MageWandFire" + Obituary "$OB_MPMWEAPWAND" States { Spawn: diff --git a/wadsrc/static/actors/hexen/mana.txt b/wadsrc/static/actors/hexen/mana.txt index 6130fe962..ee7ddd37c 100644 --- a/wadsrc/static/actors/hexen/mana.txt +++ b/wadsrc/static/actors/hexen/mana.txt @@ -81,6 +81,7 @@ ACTOR ArtiBoostMana : CustomInventory 8003 Inventory.Icon "ARTIBMAN" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIBOOSTMANA" + Tag "$TAG_ARTIBOOSTMANA" States { Spawn: diff --git a/wadsrc/static/actors/hexen/puzzleitems.txt b/wadsrc/static/actors/hexen/puzzleitems.txt index c3bdf29ba..dd15fc8fd 100644 --- a/wadsrc/static/actors/hexen/puzzleitems.txt +++ b/wadsrc/static/actors/hexen/puzzleitems.txt @@ -8,6 +8,7 @@ ACTOR PuzzSkull : PuzzleItem 9002 PuzzleItem.Number 0 Inventory.Icon ARTISKLL Inventory.PickupMessage "$TXT_ARTIPUZZSKULL" + Tag "$TAG_ARTIPUZZSKULL" States { Spawn: @@ -26,6 +27,7 @@ ACTOR PuzzGemBig : PuzzleItem 9003 PuzzleItem.Number 1 Inventory.Icon ARTIBGEM Inventory.PickupMessage "$TXT_ARTIPUZZGEMBIG" + Tag "$TAG_ARTIPUZZGEMBIG" States { Spawn: @@ -43,6 +45,7 @@ ACTOR PuzzGemRed : PuzzleItem 9004 PuzzleItem.Number 2 Inventory.Icon ARTIGEMR Inventory.PickupMessage "$TXT_ARTIPUZZGEMRED" + Tag "$TAG_ARTIPUZZGEMRED" States { Spawn: @@ -61,6 +64,7 @@ ACTOR PuzzGemGreen1 : PuzzleItem 9005 PuzzleItem.Number 3 Inventory.Icon ARTIGEMG Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN1" + Tag "$TAG_ARTIPUZZGEMGREEN1" States { Spawn: @@ -79,6 +83,7 @@ ACTOR PuzzGemGreen2 : PuzzleItem 9009 PuzzleItem.Number 4 Inventory.Icon ARTIGMG2 Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN2" + Tag "$TAG_ARTIPUZZGEMGREEN2" States { Spawn: @@ -97,6 +102,7 @@ ACTOR PuzzGemBlue1 : PuzzleItem 9006 PuzzleItem.Number 5 Inventory.Icon ARTIGEMB Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE1" + Tag "$TAG_ARTIPUZZGEMBLUE1" States { Spawn: @@ -115,6 +121,7 @@ ACTOR PuzzGemBlue2 : PuzzleItem 9010 PuzzleItem.Number 6 Inventory.Icon ARTIGMB2 Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE2" + Tag "$TAG_ARTIPUZZGEMBLUE2" States { Spawn: @@ -133,6 +140,7 @@ ACTOR PuzzBook1 : PuzzleItem 9007 PuzzleItem.Number 7 Inventory.Icon ARTIBOK1 Inventory.PickupMessage "$TXT_ARTIPUZZBOOK1" + Tag "$TAG_ARTIPUZZBOOK1" States { Spawn: @@ -151,6 +159,7 @@ ACTOR PuzzBook2 : PuzzleItem 9008 PuzzleItem.Number 8 Inventory.Icon ARTIBOK2 Inventory.PickupMessage "$TXT_ARTIPUZZBOOK2" + Tag "$TAG_ARTIPUZZBOOK2" States { Spawn: @@ -169,6 +178,7 @@ ACTOR PuzzFlameMask : PuzzleItem 9014 PuzzleItem.Number 9 Inventory.Icon ARTISKL2 Inventory.PickupMessage "$TXT_ARTIPUZZSKULL2" + Tag "$TAG_ARTIPUZZSKULL2" States { Spawn: @@ -185,6 +195,7 @@ ACTOR PuzzFWeapon : PuzzleItem 9015 PuzzleItem.Number 10 Inventory.Icon ARTIFWEP Inventory.PickupMessage "$TXT_ARTIPUZZFWEAPON" + Tag "$TAG_ARTIPUZZFWEAPON" States { Spawn: @@ -202,6 +213,7 @@ ACTOR PuzzCWeapon : PuzzleItem 9016 PuzzleItem.Number 11 Inventory.Icon ARTICWEP Inventory.PickupMessage "$TXT_ARTIPUZZCWEAPON" + Tag "$TAG_ARTIPUZZCWEAPON" States { Spawn: @@ -219,6 +231,7 @@ ACTOR PuzzMWeapon : PuzzleItem 9017 PuzzleItem.Number 12 Inventory.Icon ARTIMWEP Inventory.PickupMessage "$TXT_ARTIPUZZMWEAPON" + Tag "$TAG_ARTIPUZZMWEAPON" States { Spawn: @@ -235,6 +248,7 @@ ACTOR PuzzGear1 : PuzzleItem 9018 PuzzleItem.Number 13 Inventory.Icon ARTIGEAR Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" + Tag "$TAG_ARTIPUZZGEAR1" States { Spawn: @@ -252,6 +266,7 @@ ACTOR PuzzGear2 : PuzzleItem 9019 PuzzleItem.Number 14 Inventory.Icon ARTIGER2 Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" + Tag "$TAG_ARTIPUZZGEAR2" States { Spawn: @@ -269,6 +284,7 @@ ACTOR PuzzGear3 : PuzzleItem 9020 PuzzleItem.Number 15 Inventory.Icon ARTIGER3 Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" + Tag "$TAG_ARTIPUZZGEAR3" States { Spawn: @@ -286,6 +302,7 @@ ACTOR PuzzGear4 : PuzzleItem 9021 PuzzleItem.Number 16 Inventory.Icon ARTIGER4 Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" + Tag "$TAG_ARTIPUZZGEAR4" States { Spawn: diff --git a/wadsrc/static/actors/hexen/speedboots.txt b/wadsrc/static/actors/hexen/speedboots.txt index 17d193d2a..5fd6703b8 100644 --- a/wadsrc/static/actors/hexen/speedboots.txt +++ b/wadsrc/static/actors/hexen/speedboots.txt @@ -9,6 +9,7 @@ ACTOR ArtiSpeedBoots : PowerupGiver 8002 +INVENTORY.PICKUPFLASH Inventory.Icon ARTISPED Inventory.PickupMessage "$TXT_ARTISPEED" + Tag "$TAG_ARTISPEED" Powerup.Type Speed States { diff --git a/wadsrc/static/actors/hexen/summon.txt b/wadsrc/static/actors/hexen/summon.txt index 399c2dd89..a4b3b8584 100644 --- a/wadsrc/static/actors/hexen/summon.txt +++ b/wadsrc/static/actors/hexen/summon.txt @@ -14,6 +14,7 @@ ACTOR ArtiDarkServant : Inventory 86 native Inventory.Icon "ARTISUMN" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTISUMMON" + Tag "$TAG_ARTISUMMON" States { Spawn: diff --git a/wadsrc/static/actors/hexen/teleportother.txt b/wadsrc/static/actors/hexen/teleportother.txt index bcbdfc33c..77a05f6af 100644 --- a/wadsrc/static/actors/hexen/teleportother.txt +++ b/wadsrc/static/actors/hexen/teleportother.txt @@ -14,6 +14,7 @@ ACTOR ArtiTeleportOther : Inventory 10040 native Inventory.Icon "ARTITELO" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTITELEPORTOTHER" + Tag "$TAG_ARTITELEPORTOTHER" States { Spawn: diff --git a/wadsrc/static/actors/raven/artiegg.txt b/wadsrc/static/actors/raven/artiegg.txt index 6b8de50c9..466235588 100644 --- a/wadsrc/static/actors/raven/artiegg.txt +++ b/wadsrc/static/actors/raven/artiegg.txt @@ -38,6 +38,7 @@ ACTOR ArtiEgg : CustomInventory 30 Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIEGG" Inventory.DefMaxAmount + Tag "$TAG_ARTIEGG" States { Spawn: @@ -91,6 +92,7 @@ ACTOR ArtiPork : CustomInventory 30 Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIEGG2" Inventory.DefMaxAmount + Tag "$TAG_ARTIPORK" States { Spawn: diff --git a/wadsrc/static/actors/raven/artitele.txt b/wadsrc/static/actors/raven/artitele.txt index 5c1fa9d8f..1f0fe73d2 100644 --- a/wadsrc/static/actors/raven/artitele.txt +++ b/wadsrc/static/actors/raven/artitele.txt @@ -13,6 +13,7 @@ ACTOR ArtiTeleport : Inventory 36 native Inventory.Icon "ARTIATLP" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTITELEPORT" + Tag "$TAG_ARTITELEPORT" States { Spawn: diff --git a/wadsrc/static/actors/raven/ravenartifacts.txt b/wadsrc/static/actors/raven/ravenartifacts.txt index 84264764b..c02c19c3b 100644 --- a/wadsrc/static/actors/raven/ravenartifacts.txt +++ b/wadsrc/static/actors/raven/ravenartifacts.txt @@ -13,6 +13,7 @@ ACTOR ArtiHealth : HealthPickup 82 Inventory.Icon ARTIPTN2 Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTIHEALTH" + Tag "$TAG_ARTIHEALTH" HealthPickup.Autouse 1 States { @@ -36,6 +37,7 @@ ACTOR ArtiSuperHealth : HealthPickup 32 Inventory.Icon ARTISPHL Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_ARTISUPERHEALTH" + Tag "$TAG_ARTISUPERHEALTH" HealthPickup.Autouse 2 States { @@ -58,6 +60,7 @@ ACTOR ArtiFly : PowerupGiver 83 Inventory.RespawnTics 4230 Inventory.Icon ARTISOAR Inventory.PickupMessage "$TXT_ARTIFLY" + Tag "$TAG_ARTIFLY" Powerup.Type Flight States { @@ -79,6 +82,7 @@ ACTOR ArtiInvulnerability : PowerupGiver 84 Inventory.RespawnTics 4230 Inventory.Icon ARTIINVU Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY" + Tag "$TAG_ARTIINVULNERABILITY" Powerup.Type Invulnerable Powerup.Color GoldMap States @@ -102,6 +106,7 @@ ACTOR ArtiInvulnerability2 : PowerupGiver 84 Inventory.Icon ARTIDEFN Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY2" Powerup.Type Invulnerable + Tag "$TAG_ARTIDEFENDER" States { Spawn: @@ -121,6 +126,7 @@ ACTOR ArtiTorch : PowerupGiver 33 +INVENTORY.PICKUPFLASH Inventory.Icon ARTITRCH Inventory.PickupMessage "$TXT_ARTITORCH" + Tag "$TAG_ARTITORCH" Powerup.Type Torch States { diff --git a/wadsrc/static/actors/strife/acolyte.txt b/wadsrc/static/actors/strife/acolyte.txt index 73b27864b..1d04147f0 100644 --- a/wadsrc/static/actors/strife/acolyte.txt +++ b/wadsrc/static/actors/strife/acolyte.txt @@ -15,7 +15,7 @@ ACTOR Acolyte : StrifeHumanoid +FLOORCLIP +NEVERRESPAWN MinMissileChance 150 - Tag "ACOLYTE" + Tag "$TAG_ACOLYTE" SeeSound "acolyte/sight" PainSound "acolyte/pain" AttackSound "acolyte/rifle" diff --git a/wadsrc/static/actors/strife/beggars.txt b/wadsrc/static/actors/strife/beggars.txt index 8820f32d0..b24080b1a 100644 --- a/wadsrc/static/actors/strife/beggars.txt +++ b/wadsrc/static/actors/strife/beggars.txt @@ -13,7 +13,7 @@ ACTOR Beggar : StrifeHumanoid -COUNTKILL +NOSPLASHALERT MinMissileChance 150 - Tag "Beggar" + Tag "$TAG_BEGGAR" MaxStepHeight 16 MaxDropoffHeight 32 HitObituary "$OB_BEGGAR" diff --git a/wadsrc/static/actors/strife/coin.txt b/wadsrc/static/actors/strife/coin.txt index f569fb1ed..e4e50af77 100644 --- a/wadsrc/static/actors/strife/coin.txt +++ b/wadsrc/static/actors/strife/coin.txt @@ -10,7 +10,7 @@ ACTOR Coin : Inventory 93 native +FLOORCLIP Inventory.MaxAmount 0x7fffffff +INVENTORY.INVBAR - Tag "coin" + Tag "$TAG_COIN" Inventory.Icon "I_COIN" Inventory.PickupMessage "$TXT_COIN" States @@ -29,7 +29,7 @@ ACTOR Gold10 : Coin 138 Game Strife ConversationID 169, 162, 166 Inventory.Amount 10 - Tag "10 gold" + Tag "$TAG_10GOLD" Inventory.PickupMessage "$TXT_10GOLD" States { @@ -46,7 +46,7 @@ ACTOR Gold25 : Coin 139 Game Strife ConversationID 170, 163, 167 Inventory.Amount 25 - Tag "25 gold" + Tag "$TAG_25GOLD" Inventory.PickupMessage "$TXT_25GOLD" States { @@ -63,7 +63,7 @@ ACTOR Gold50 : Coin 140 Game Strife ConversationID 171, 164, 168 Inventory.Amount 50 - Tag "50 gold" + Tag "$TAG_50GOLD" Inventory.PickupMessage "$TXT_50GOLD" States { @@ -79,7 +79,7 @@ ACTOR Gold300 : Coin { ConversationID 172, -1, -1 Inventory.Amount 300 - Tag "300 gold" + Tag "$TAG_300GOLD" Inventory.PickupMessage "$TXT_300GOLD" Inventory.GiveQuest 3 +INVENTORY.ALWAYSPICKUP diff --git a/wadsrc/static/actors/strife/loremaster.txt b/wadsrc/static/actors/strife/loremaster.txt index dd79c0f19..fee3eb0f0 100644 --- a/wadsrc/static/actors/strife/loremaster.txt +++ b/wadsrc/static/actors/strife/loremaster.txt @@ -23,7 +23,7 @@ ACTOR Loremaster 12 +NEVERRESPAWN DamageFactor "Fire", 0.5 MinMissileChance 150 - Tag "PRIEST" + Tag "$TAG_PRIEST" SeeSound "loremaster/sight" AttackSound "loremaster/attack" PainSound "loremaster/pain" diff --git a/wadsrc/static/actors/strife/macil.txt b/wadsrc/static/actors/strife/macil.txt index 3666728e0..ac23e4e66 100644 --- a/wadsrc/static/actors/strife/macil.txt +++ b/wadsrc/static/actors/strife/macil.txt @@ -23,7 +23,7 @@ ACTOR Macil1 64 PainSound "macil/pain" ActiveSound "macil/active" CrushPainSound "misc/pcrush" - Tag "MACIL" + Tag "$TAG_MACIL1" Obituary "$OB_MACIL" DropItem "BoxOfBullets" MaxStepHeight 16 @@ -66,6 +66,7 @@ ACTOR Macil2 : Macil1 200 +COUNTKILL +SPECTRAL -NODAMAGE + Tag "$TAG_MACIL2" DeathSound "macil/slop" DropItem "None" DamageFactor "SpectralLow", 0 diff --git a/wadsrc/static/actors/strife/merchants.txt b/wadsrc/static/actors/strife/merchants.txt index 65f5ac653..b6a2e09a5 100644 --- a/wadsrc/static/actors/strife/merchants.txt +++ b/wadsrc/static/actors/strife/merchants.txt @@ -59,7 +59,7 @@ ACTOR WeaponSmith : Merchant 116 Game Strife ConversationID 2 PainSound "smith/pain" - Tag "Weapon Smith" + Tag "$TAG_WEAPONSMITH" } @@ -72,7 +72,7 @@ ACTOR BarKeep : Merchant 72 ConversationID 3 PainSound "barkeep/pain" ActiveSound "barkeep/active" - Tag "Bar Keep" + Tag "$TAG_BARKEEP" } @@ -84,7 +84,7 @@ ACTOR Armorer : Merchant 73 Translation 5 ConversationID 4 PainSound "armorer/pain" - Tag "Armorer" + Tag "$TAG_ARMORER" } @@ -96,6 +96,6 @@ ACTOR Medic : Merchant 74 Translation 6 ConversationID 5 PainSound "medic/pain" - Tag "Medic" + Tag "$TAG_MEDIC" } diff --git a/wadsrc/static/actors/strife/oracle.txt b/wadsrc/static/actors/strife/oracle.txt index 03b80c894..2e0aff948 100644 --- a/wadsrc/static/actors/strife/oracle.txt +++ b/wadsrc/static/actors/strife/oracle.txt @@ -15,7 +15,7 @@ ACTOR Oracle 199 DamageFactor "Fire", 0.5 DamageFactor "SpectralLow", 0 MaxDropoffHeight 32 - Tag "Oracle" + Tag "$TAG_ORACLE" DropItem "Meat" action native A_WakeOracleSpectre (); diff --git a/wadsrc/static/actors/strife/questitems.txt b/wadsrc/static/actors/strife/questitems.txt index b06cdfaa8..cf6b98b0b 100644 --- a/wadsrc/static/actors/strife/questitems.txt +++ b/wadsrc/static/actors/strife/questitems.txt @@ -64,19 +64,19 @@ ACTOR QuestItem3 : QuestItem ACTOR QuestItem4 : QuestItem { ConversationID 315, 296, 313 - Tag "quest4" + Tag "$TAG_QUEST4" } ACTOR QuestItem5 : QuestItem { ConversationID 316, 297, 314 - Tag "quest5" + Tag "$TAG_QUEST5" } ACTOR QuestItem6 : QuestItem { ConversationID 317, 298, 315 - Tag "quest4" + Tag "TAG_QUEST6" } ACTOR QuestItem7 : QuestItem diff --git a/wadsrc/static/actors/strife/ratbuddy.txt b/wadsrc/static/actors/strife/ratbuddy.txt index 762aff659..eaefda35d 100644 --- a/wadsrc/static/actors/strife/ratbuddy.txt +++ b/wadsrc/static/actors/strife/ratbuddy.txt @@ -12,7 +12,7 @@ ACTOR RatBuddy 85 MinMissileChance 150 MaxStepHeight 16 MaxDropoffHeight 32 - Tag "rat buddy" + Tag "$TAG_RATBUDDY" SeeSound "rat/sight" DeathSound "rat/death" ActiveSound "rat/active" diff --git a/wadsrc/static/actors/strife/rebels.txt b/wadsrc/static/actors/strife/rebels.txt index ff6faeec2..3c539bca4 100644 --- a/wadsrc/static/actors/strife/rebels.txt +++ b/wadsrc/static/actors/strife/rebels.txt @@ -14,7 +14,7 @@ ACTOR Rebel : StrifeHumanoid -COUNTKILL +NOSPLASHALERT MinMissileChance 150 - Tag "Rebel" + Tag "$TAG_REBEL" SeeSound "rebel/sight" PainSound "rebel/pain" DeathSound "rebel/death" @@ -124,7 +124,7 @@ ACTOR TeleporterBeacon : Inventory 10 native +DROPPED +INVENTORY.INVBAR Inventory.Icon "I_BEAC" - Tag "Teleporter Beacon" + Tag "$TAG_TELEPORTERBEACON" Inventory.PickupMessage "$TXT_BEACON" action native A_Beacon (); diff --git a/wadsrc/static/actors/strife/sigil.txt b/wadsrc/static/actors/strife/sigil.txt index ab9c6d21b..a2cc66c7b 100644 --- a/wadsrc/static/actors/strife/sigil.txt +++ b/wadsrc/static/actors/strife/sigil.txt @@ -11,7 +11,7 @@ ACTOR Sigil : Weapon native +FLOORCLIP +WEAPON.CHEATNOTWEAPON Inventory.PickupSound "weapons/sigilcharge" - Tag "SIGIL" + Tag "$TAG_SIGIL" Inventory.Icon "I_SGL1" Inventory.PickupMessage "$TXT_SIGIL" diff --git a/wadsrc/static/actors/strife/strifeammo.txt b/wadsrc/static/actors/strife/strifeammo.txt index 1de16474f..801714434 100644 --- a/wadsrc/static/actors/strife/strifeammo.txt +++ b/wadsrc/static/actors/strife/strifeammo.txt @@ -10,7 +10,7 @@ ACTOR HEGrenadeRounds : Ammo 152 Ammo.BackpackAmount 6 Ammo.BackpackMaxAmount 60 Inventory.Icon "I_GRN1" - Tag "HE-Grenade Rounds" + Tag "$TAG_HEGRENADES" Inventory.PickupMessage "$TXT_HEGRENADES" States { @@ -32,7 +32,7 @@ ACTOR PhosphorusGrenadeRounds : Ammo 153 Ammo.BackpackAmount 4 Ammo.BackpackMaxAmount 32 Inventory.Icon "I_GRN2" - Tag "Phoshorus-Grenade Rounds" // "Fire-Grenade_Rounds" in the Teaser + Tag "$TAG_PHGRENADES" Inventory.PickupMessage "$TXT_PHGRENADES" States { @@ -55,7 +55,7 @@ ACTOR ClipOfBullets : Ammo 2007 Ammo.BackpackAmount 10 Ammo.BackpackMaxAmount 500 Inventory.Icon "I_BLIT" - Tag "Clip of Bullets" // "bullets" in the Teaser + Tag "$TAG_CLIPOFBULLETS" Inventory.PickupMessage "$TXT_CLIPOFBULLETS" States { @@ -73,7 +73,7 @@ ACTOR BoxOfBullets : ClipOfBullets 2048 SpawnID 139 ConversationID 180, 174, 178 Inventory.Amount 50 - Tag "Ammo" + Tag "$TAG_BOXOFBULLETS" Inventory.PickupMessage "$TXT_BOXOFBULLETS" States { @@ -96,7 +96,7 @@ ACTOR MiniMissiles : Ammo 2010 Ammo.BackpackAmount 4 Ammo.BackpackMaxAmount 200 Inventory.Icon "I_ROKT" - Tag "Mini Missiles" //"rocket" in the Teaser + Tag "$TAG_MINIMISSILES" Inventory.PickupMessage "$TXT_MINIMISSILES" States { @@ -114,7 +114,7 @@ ACTOR CrateOfMissiles : MiniMissiles 2046 SpawnID 141 ConversationID 182, 176, 180 Inventory.Amount 20 - Tag "Crate of Missiles" //"box_of_rockets" in the Teaser + Tag "$TAG_CRATEOFMISSILES" Inventory.PickupMessage "$TXT_CRATEOFMISSILES" States { @@ -138,7 +138,7 @@ ACTOR EnergyPod : Ammo 2047 Ammo.BackpackMaxAmount 800 Ammo.DropAmount 20 Inventory.Icon "I_BRY1" - Tag "Energy Pod" + Tag "$TAG_ENERGYPOD" Inventory.PickupMessage "$TXT_ENERGYPOD" States { @@ -156,7 +156,7 @@ ACTOR EnergyPack : EnergyPod 17 SpawnID 142 ConversationID 184, 178, 182 Inventory.Amount 100 - Tag "Energy Pack" + Tag "$TAG_ENERGYPACK" Inventory.PickupMessage "$TXT_ENERGYPACK" States { @@ -178,7 +178,7 @@ ACTOR PoisonBolts : Ammo 115 Ammo.BackpackAmount 2 Ammo.BackpackMaxAmount 50 Inventory.Icon "I_PQRL" - Tag "Poison Bolts" // "poison_arrows" in the Teaser + Tag "$TAG_POISONBOLTS" Inventory.PickupMessage "$TXT_POISONBOLTS" States { @@ -200,7 +200,7 @@ ACTOR ElectricBolts : Ammo 114 Ammo.BackpackAmount 4 Ammo.BackpackMaxAmount 100 Inventory.Icon "I_XQRL" - Tag "Electric Bolts" // "electric_arrows" in the Teaser + Tag "$TAG_ELECTRICBOLTS" Inventory.PickupMessage "$TXT_ELECTRICBOLTS" States { @@ -219,7 +219,7 @@ ACTOR AmmoSatchel : BackpackItem 183 ConversationID 187, 181, 184 +FLOORCLIP Inventory.Icon "I_BKPK" - Tag "Ammo Satchel" // "Back_pack" in the Teaser + Tag "$TAG_AMMOSATCHEL" Inventory.PickupMessage "$TXT_AMMOSATCHEL" States { diff --git a/wadsrc/static/actors/strife/strifearmor.txt b/wadsrc/static/actors/strife/strifearmor.txt index 2be8d8ad6..2431e9438 100644 --- a/wadsrc/static/actors/strife/strifearmor.txt +++ b/wadsrc/static/actors/strife/strifearmor.txt @@ -14,7 +14,7 @@ ACTOR MetalArmor : BasicArmorPickup 2019 Inventory.PickupMessage "$TXT_METALARMOR" Armor.SaveAmount 200 Armor.SavePercent 50 - Tag "Metal Armor" + Tag "$TAG_METALARMOR" States { Spawn: @@ -38,7 +38,7 @@ ACTOR LeatherArmor : BasicArmorPickup 2018 Inventory.PickupMessage "$TXT_LEATHERARMOR" Armor.SaveAmount 100 Armor.SavePercent 33.335 - Tag "Leather Armor" + Tag "$TAG_LEATHER" States { Spawn: diff --git a/wadsrc/static/actors/strife/strifeitems.txt b/wadsrc/static/actors/strife/strifeitems.txt index 407a91843..74b957b83 100644 --- a/wadsrc/static/actors/strife/strifeitems.txt +++ b/wadsrc/static/actors/strife/strifeitems.txt @@ -8,7 +8,7 @@ ACTOR MedPatch : HealthPickup 2011 +FLOORCLIP +INVENTORY.INVBAR Inventory.MaxAmount 20 - Tag "Med patch" + Tag "$TAG_MEDPATCH" Inventory.Icon "I_STMP" Inventory.PickupMessage "$TXT_MEDPATCH" HealthPickup.Autouse 3 @@ -31,7 +31,7 @@ ACTOR MedicalKit : HealthPickup 2012 +FLOORCLIP +INVENTORY.INVBAR Inventory.MaxAmount 15 - Tag "Medical kit" + Tag "$TAG_MEDICALKIT" Inventory.Icon "I_MDKT" Inventory.PickupMessage "$TXT_MEDICALKIT" HealthPickup.Autouse 3 @@ -54,7 +54,7 @@ ACTOR SurgeryKit : HealthPickup 83 +INVENTORY.INVBAR Health -100 Inventory.MaxAmount 5 - Tag "Surgery Kit" // "full_health" in the Teaser + Tag "$TAG_SURGERYKIT" Inventory.Icon "I_FULL" Inventory.PickupMessage "$TXT_SURGERYKIT" States @@ -75,7 +75,7 @@ ACTOR StrifeMap : MapRevealer 2026 ConversationID 164, 160, 163 +FLOORCLIP Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_STRIFEMAP" + Inventory.PickupMessage "$TXT_STRIFEMAP" States { Spawn: @@ -94,7 +94,7 @@ ACTOR BeldinsRing : Inventory +FLOORCLIP +INVENTORY.INVBAR ConversationID 173, 165, 169 - Tag "Ring" + Tag "$TAG_BELDINSRING" Inventory.Icon "I_RING" Inventory.GiveQuest 1 Inventory.PickupMessage "$TXT_BELDINSRING" @@ -118,7 +118,7 @@ ACTOR OfferingChalice : Inventory 205 ConversationID 174, 166, 170 Radius 10 Height 16 - Tag "Offering Chalice" + Tag "$TAG_OFFERINGCHALICE" Inventory.Icon "I_RELC" Inventory.PickupMessage "$TXT_OFFERINGCHALICE" Inventory.GiveQuest 2 @@ -139,7 +139,7 @@ ACTOR Ear : Inventory +FLOORCLIP +INVENTORY.INVBAR ConversationID 175, 167, 171 - Tag "Ear" + Tag "$TAG_EAR" Inventory.Icon "I_EARS" Inventory.PickupMessage "$TXT_EAR" Inventory.GiveQuest 9 @@ -164,7 +164,7 @@ ACTOR BrokenPowerCoupling : Inventory 226 +INVENTORY.INVBAR Radius 16 Height 16 - Tag "Broken Power Coupling" + Tag "$TAG_BROKENCOUPLING" Inventory.MaxAmount 1 Inventory.Icon "I_COUP" Inventory.PickupMessage "$TXT_BROKENCOUPLING" @@ -190,7 +190,7 @@ ACTOR ShadowArmor : PowerupGiver 2024 +INVENTORY.INVBAR -INVENTORY.FANCYPICKUPSOUND RenderStyle Translucent - Tag "Shadow Armor" + Tag "$TAG_SHADOWARMOR" Inventory.MaxAmount 2 Powerup.Type "Shadow" Inventory.Icon "I_SHD1" @@ -217,7 +217,7 @@ ACTOR EnvironmentalSuit : PowerupGiver 2025 -INVENTORY.FANCYPICKUPSOUND Inventory.MaxAmount 5 Powerup.Type "Mask" - Tag "Environmental Suit" + Tag "$TAG_ENVSUIT" Inventory.Icon "I_MASK" Inventory.PickupSound "misc/i_pkup" Inventory.PickupMessage "$TXT_ENVSUIT" @@ -238,7 +238,7 @@ ACTOR GuardUniform : Inventory 90 ConversationID 162, 158, 161 +FLOORCLIP +INVENTORY.INVBAR - Tag "Guard Uniform" + Tag "$TAG_GUARDUNIFORM" Inventory.Icon "I_UNIF" Inventory.PickupMessage "$TXT_GUARDUNIFORM" Inventory.GiveQuest 15 @@ -259,7 +259,7 @@ ACTOR OfficersUniform : Inventory 52 ConversationID 163, 159, 162 +FLOORCLIP +INVENTORY.INVBAR - Tag "Officer's Uniform" + Tag "$TAG_OFFICERSUNIFORM" Inventory.Icon "I_OFIC" Inventory.PickupMessage "$TXT_OFFICERSUNIFORM" States @@ -280,7 +280,7 @@ ACTOR FlameThrowerParts : Inventory +FLOORCLIP +INVENTORY.INVBAR Inventory.Icon "I_BFLM" - Tag "Flame Thrower Parts" + Tag "$TAG_FTHROWERPARTS" Inventory.PickupMessage "$TXT_FTHROWERPARTS" States { @@ -300,7 +300,7 @@ ACTOR InterrogatorReport : Inventory Game Strife ConversationID 308, 289, 306 +FLOORCLIP - Tag "Report" + Tag "$TAG_REPORT" Inventory.PickupMessage "$TXT_REPORT" States { @@ -319,7 +319,7 @@ ACTOR Info : Inventory ConversationID 300, 282, 299 +FLOORCLIP +INVENTORY.INVBAR - Tag "Info" + Tag "$TAG_INFO" Inventory.Icon "I_TOKN" Inventory.PickupMessage "$TXT_INFO" States @@ -340,7 +340,7 @@ ACTOR Targeter : PowerupGiver 207 +FLOORCLIP +INVENTORY.INVBAR -INVENTORY.FANCYPICKUPSOUND - Tag "Targeter" + Tag "$TAG_TARGETER" Powerup.Type "Targeter" Inventory.MaxAmount 5 Inventory.Icon "I_TARG" @@ -361,7 +361,7 @@ ACTOR Communicator : Inventory 206 Game Strife ConversationID 176, 168, 172 +NOTDMATCH - Tag "Communicator" + Tag "$TAG_COMMUNICATOR" Inventory.Icon "I_COMM" Inventory.PickupSound "misc/p_pkup" Inventory.PickupMessage "$TXT_COMMUNICATOR" @@ -389,7 +389,7 @@ ACTOR DegninOre : Inventory 59 native +FLOORCLIP +INCOMBAT +INVENTORY.INVBAR - Tag "Degnin Ore" + Tag "$TAG_DEGNINORE" DeathSound "ore/explode" Inventory.Icon "I_XPRK" Inventory.PickupMessage "$TXT_DEGNINORE" @@ -418,7 +418,7 @@ ACTOR GunTraining : Inventory +INVENTORY.INVBAR +INVENTORY.UNDROPPABLE Inventory.MaxAmount 100 - Tag "Accuracy" + Tag "$TAG_GUNTRAINING" Inventory.Icon "I_GUNT" States { @@ -438,7 +438,7 @@ ACTOR HealthTraining : Inventory native +INVENTORY.INVBAR +INVENTORY.UNDROPPABLE Inventory.MaxAmount 100 - Tag "Toughness" + Tag "$TAG_HEALTHTRAINING" Inventory.Icon "I_HELT" States { @@ -459,7 +459,7 @@ ACTOR Scanner : PowerupGiver 2027 native +FLOORCLIP +INVENTORY.FANCYPICKUPSOUND Inventory.MaxAmount 1 - Tag "Scanner" + Tag "$TAG_SCANNER" Inventory.Icon "I_PMUP" Powerup.Type "Scanner" Inventory.PickupSound "misc/i_pkup" @@ -479,8 +479,8 @@ ACTOR PrisonPass : Key native Game Strife ConversationID 304, 286, 303 Inventory.Icon "I_TOKN" - Tag "Prison Pass" - Inventory.PickupMessage "TXT_PRISONPASS" + Tag "$TAG_PRISONPASS" + Inventory.PickupMessage "$TXT_PRISONPASS" States { Spawn: @@ -509,7 +509,7 @@ ACTOR DummyStrifeItem : Inventory native ACTOR RaiseAlarm : DummyStrifeItem native { ConversationID 301, 283, 300 - Tag "Alarm" + Tag "$TAG_ALARM" } // Open door tag 222 -------------------------------------------------------- @@ -538,7 +538,7 @@ ACTOR OpenDoor224 : DummyStrifeItem native ACTOR AmmoFillup : DummyStrifeItem native { ConversationID 298,280,297 - Tag "Ammo" + Tag "$TAG_AMMOFILLUP" } // Health ------------------------------------------------------------------- @@ -546,7 +546,7 @@ ACTOR AmmoFillup : DummyStrifeItem native ACTOR HealthFillup : DummyStrifeItem native { ConversationID 299,281,298 - Tag "Health" + Tag "$TAG_HEALTHFILLUP" } // Upgrade Stamina ---------------------------------------------------------- diff --git a/wadsrc/static/actors/strife/strifekeys.txt b/wadsrc/static/actors/strife/strifekeys.txt index d128cbbd6..b304f83bc 100644 --- a/wadsrc/static/actors/strife/strifekeys.txt +++ b/wadsrc/static/actors/strife/strifekeys.txt @@ -13,7 +13,7 @@ ACTOR BaseKey : StrifeKey 230 Game Strife ConversationID 133, 129, 132 Inventory.Icon "I_FUSL" - Tag "Base Key" + Tag "$TAG_BASEKEY" Inventory.PickupMessage "$TXT_BASEKEY" States { @@ -31,7 +31,7 @@ ACTOR GovsKey : StrifeKey Game Strife ConversationID 134, 130, 133 Inventory.Icon "I_REBL" - Tag "Govs Key" // "Rebel_Key" in the Teaser + Tag "$TAG_GOVSKEY" Inventory.PickupMessage "$TXT_GOVSKEY" States { @@ -49,7 +49,7 @@ ACTOR Passcard : StrifeKey 185 Game Strife ConversationID 135, 131, 134 Inventory.Icon "I_TPAS" - Tag "Passcard" + Tag "$TAG_PASSCARD" Inventory.PickupMessage "$TXT_PASSCARD" States { @@ -67,7 +67,7 @@ ACTOR IDBadge : StrifeKey 184 Game Strife ConversationID 136, 132, 135 Inventory.Icon "I_CRD1" - Tag "ID Badge" + Tag "$TAG_IDBADGE" Inventory.PickupMessage "$TXT_IDBADGE" States { @@ -85,7 +85,7 @@ ACTOR PrisonKey : StrifeKey Game Strife ConversationID 137, 133, 136 Inventory.Icon "I_PRIS" - Tag "Prison Key" + Tag "$TAG_PRISONKEY" Inventory.GiveQuest 11 Inventory.PickupMessage "$TXT_PRISONKEY" States @@ -104,7 +104,7 @@ ACTOR SeveredHand : StrifeKey 91 Game Strife ConversationID 138, 134, 137 Inventory.Icon "I_HAND" - Tag "Severed Hand" + Tag "$TAG_SEVEREDHAND" Inventory.GiveQuest 12 Inventory.PickupMessage "$TXT_SEVEREDHAND" States @@ -123,7 +123,7 @@ ACTOR Power1Key : StrifeKey Game Strife ConversationID 139, 135, 138 Inventory.Icon "I_PWR1" - Tag "Power1 Key" + Tag "$TAG_POWER1KEY" Inventory.PickupMessage "$TXT_POWER1KEY" States { @@ -141,7 +141,7 @@ ACTOR Power2Key : StrifeKey Game Strife ConversationID 140, 136, 139 Inventory.Icon "I_PWR2" - Tag "Power2 Key" + Tag "$TAG_POWER2KEY" Inventory.PickupMessage "$TXT_POWER2KEY" States { @@ -159,7 +159,7 @@ ACTOR Power3Key : StrifeKey Game Strife ConversationID 141, 137, 140 Inventory.Icon "I_PWR3" - Tag "Power3 Key" + Tag "$TAG_POWER3KEY" Inventory.PickupMessage "$TXT_POWER3KEY" States { @@ -177,7 +177,7 @@ ACTOR GoldKey : StrifeKey 40 Game Strife ConversationID 142, 138, 141 Inventory.Icon "I_KY1G" - Tag "Gold Key" + Tag "$TAG_GOLDKEY" Inventory.PickupMessage "$TXT_GOLDKEY" States { @@ -195,7 +195,7 @@ ACTOR IDCard : StrifeKey 13 Game Strife ConversationID 143, 139, 142 Inventory.Icon "I_CRD2" - Tag "ID Card" + Tag "$TAG_IDCARD" Inventory.PickupMessage "$TXT_IDCARD" States { @@ -213,7 +213,7 @@ ACTOR SilverKey : StrifeKey 38 Game Strife ConversationID 144, 140, 143 Inventory.Icon "I_KY2S" - Tag "Silver Key" + Tag "$TAG_SILVERKEY" Inventory.PickupMessage "$TXT_SILVERKEY" States { @@ -231,7 +231,7 @@ ACTOR OracleKey : StrifeKey 61 Game Strife ConversationID 145, 141, 144 Inventory.Icon "I_ORAC" - Tag "Oracle Key" + Tag "$TAG_ORACLEKEY" Inventory.PickupMessage "$TXT_ORACLEKEY" States { @@ -249,7 +249,7 @@ ACTOR MilitaryID : StrifeKey Game Strife ConversationID 146, 142, 145 Inventory.Icon "I_GYID" - Tag "Military ID" + Tag "$TAG_MILITARYID" Inventory.PickupMessage "$TXT_MILITARYID" States { @@ -267,7 +267,7 @@ ACTOR OrderKey : StrifeKey 86 Game Strife ConversationID 147, 143, 146 Inventory.Icon "I_FUBR" - Tag "Order Key" + Tag "$TAG_ORDERKEY" Inventory.PickupMessage "$TXT_ORDERKEY" States { @@ -285,7 +285,7 @@ ACTOR WarehouseKey : StrifeKey 166 Game Strife ConversationID 148, 144, 147 Inventory.Icon "I_WARE" - Tag "Warehouse Key" + Tag "$TAG_WAREHOUSEKEY" Inventory.PickupMessage "$TXT_WAREHOUSEKEY" States { @@ -303,7 +303,7 @@ ACTOR BrassKey : StrifeKey 39 Game Strife ConversationID 149, 145, 148 Inventory.Icon "I_KY3B" - Tag "Brass Key" + Tag "$TAG_BRASSKEY" Inventory.PickupMessage "$TXT_BRASSKEY" States { @@ -321,7 +321,7 @@ ACTOR RedCrystalKey : StrifeKey 192 Game Strife ConversationID 150, 146, 149 Inventory.Icon "I_RCRY" - Tag "Red Crystal Key" + Tag "$TAG_REDCRYSTALKEY" Inventory.PickupMessage "$TXT_REDCRYSTAL" States { @@ -339,7 +339,7 @@ ACTOR BlueCrystalKey : StrifeKey 193 Game Strife ConversationID 151, 147, 150 Inventory.Icon "I_BCRY" - Tag "Blue Crystal Key" + Tag "$TAG_BLUECRYSTALKEY" Inventory.PickupMessage "$TXT_BLUECRYSTAL" States { @@ -357,7 +357,7 @@ ACTOR ChapelKey : StrifeKey 195 Game Strife ConversationID 152, 148, 151 Inventory.Icon "I_CHAP" - Tag "Chapel Key" + Tag "$TAG_CHAPELKEY" Inventory.PickupMessage "$TXT_CHAPELKEY" States { @@ -375,7 +375,7 @@ ACTOR CatacombKey : StrifeKey Game Strife ConversationID 153, 149, 152 Inventory.Icon "I_TUNL" - Tag "Catacomb Key" // "Tunnel_Key" in the Teaser + Tag "$TAG_CATACOMBKEY" Inventory.GiveQuest 28 Inventory.PickupMessage "$TXT_CATACOMBKEY" States @@ -394,7 +394,7 @@ ACTOR SecurityKey : StrifeKey Game Strife ConversationID 154, 150, 153 Inventory.Icon "I_SECK" - Tag "Security Key" + Tag "$TAG_SECURITYKEY" Inventory.PickupMessage "$TXT_SECURITYKEY" States { @@ -412,7 +412,7 @@ ACTOR CoreKey : StrifeKey 236 Game Strife ConversationID 155, 151, 154 Inventory.Icon "I_GOID" - Tag "Core Key" // "New_Key1" in the Teaser + Tag "$TAG_COREKEY" Inventory.PickupMessage "$TXT_COREKEY" States { @@ -430,7 +430,7 @@ ACTOR MaulerKey : StrifeKey 233 Game Strife ConversationID 156, 152, 155 Inventory.Icon "I_BLTK" - Tag "Mauler Key" // "New_Key2" in the Teaser + Tag "$TAG_MAULERKEY" Inventory.PickupMessage "$TXT_MAULERKEY" States { @@ -448,7 +448,7 @@ ACTOR FactoryKey : StrifeKey 234 Game Strife ConversationID 157, 153, 156 Inventory.Icon "I_PROC" - Tag "Factory Key" // "New_Key3" in the Teaser + Tag "$TAG_FACTORYKEY" Inventory.PickupMessage "$TXT_FACTORYKEY" States { @@ -465,8 +465,8 @@ ACTOR MineKey : StrifeKey 235 { Game Strife ConversationID 158, 154, 157 - Inventory.Icon "I_MINE" // "New_Key4" in the Teaser - Tag "Mine_Key" + Inventory.Icon "I_MINE" + Tag "$TAG_MINEKEY" Inventory.PickupMessage "$TXT_MINEKEY" States { @@ -484,7 +484,7 @@ ACTOR NewKey5 : StrifeKey Game Strife ConversationID 159, 155, 158 Inventory.Icon "I_BLTK" - Tag "New Key5" + Tag "$TAG_NEWKEY5" Inventory.PickupMessage "$TXT_NEWKEY5" States { @@ -505,7 +505,7 @@ ACTOR OraclePass : Inventory Inventory.Icon "I_OTOK" Inventory.GiveQuest 18 Inventory.PickupMessage "$TXT_ORACLEPASS" - Tag "Oracle Pass" + Tag "$TAG_ORACLEPASS" States { Spawn: diff --git a/wadsrc/static/actors/strife/strifeweapons.txt b/wadsrc/static/actors/strife/strifeweapons.txt index d287ace08..5e3a419d5 100644 --- a/wadsrc/static/actors/strife/strifeweapons.txt +++ b/wadsrc/static/actors/strife/strifeweapons.txt @@ -48,6 +48,8 @@ ACTOR PunchDagger : StrifeWeapon Game Strife Weapon.SelectionOrder 3900 +WEAPON.NOALERT + Obituary "$OB_MPPUNCHDAGGER" + Tag "$TAG_PUNCHDAGGER" action native A_JabDagger (); @@ -109,6 +111,7 @@ ACTOR ElectricBolt : StrifeZap1 SeeSound "misc/swish" ActiveSound "misc/swish" DeathSound "weapons/xbowhit" + Obituary "$OB_MPELECTRICBOLT" States { Spawn: @@ -132,6 +135,7 @@ ACTOR PoisonBolt native MaxStepHeight 4 SeeSound "misc/swish" ActiveSound "misc/swish" + Obituary "$OB_MPPOISONBOLT" States { Spawn: @@ -158,8 +162,8 @@ ACTOR StrifeCrossbow : StrifeWeapon 2001 Weapon.AmmoType1 "ElectricBolts" Weapon.SisterWeapon "StrifeCrossbow2" Inventory.PickupMessage "$TXT_STRIFECROSSBOW" + Tag "$TAG_STRIFECROSSBOW1" Inventory.Icon "CBOWA0" - Tag "Crossbow" action native A_ClearFlash (); action native A_ShowElectricFlash (); @@ -205,6 +209,7 @@ ACTOR StrifeCrossbow2 : StrifeCrossbow Weapon.AmmoGive1 0 Weapon.AmmoType1 "PoisonBolts" Weapon.SisterWeapon "StrifeCrossbow" + Tag "$TAG_STRIFECROSSBOW2" States { @@ -243,8 +248,9 @@ actor AssaultGun : StrifeWeapon 2002 Weapon.AmmoGive1 20 Weapon.AmmoType1 "ClipOfBullets" Inventory.Icon "RIFLA0" - Tag "Assault Gun" + Tag "$TAG_ASSAULTGUN" Inventory.PickupMessage "$TXT_ASSAULTGUN" + Obituary "$OB_MPASSAULTGUN" States { Spawn: @@ -299,7 +305,7 @@ ACTOR MiniMissileLauncher : StrifeWeapon 2003 Weapon.AmmoGive1 8 Weapon.AmmoType1 "MiniMissiles" Inventory.Icon "MMSLA0" - Tag "Mini Missile Launcher" + Tag "$TAG_MMLAUNCHER" Inventory.PickupMessage "$TXT_MMLAUNCHER" action native A_FireMiniMissile (); @@ -376,6 +382,7 @@ ACTOR MiniMissile MaxStepHeight 4 SeeSound "weapons/minimissile" DeathSound "weapons/minimissilehit" + Obituary "$OB_MPMINIMISSILELAUNCHER" States { Spawn: @@ -407,7 +414,7 @@ ACTOR FlameThrower : StrifeWeapon 2005 Weapon.ReadySound "weapons/flameidle" Weapon.AmmoType1 "EnergyPod" Inventory.Icon "FLAMA0" - Tag "Flame Thrower" + Tag "$TAG_FLAMER" Inventory.PickupMessage "$TXT_FLAMER" action native A_FireFlamer (); @@ -451,6 +458,7 @@ ACTOR FlameMissile MaxStepHeight 4 RenderStyle Add SeeSound "weapons/flamethrower" + Obituary "$OB_MPFLAMETHROWER" action native A_FlameDie (); @@ -483,8 +491,9 @@ ACTOR Mauler : StrifeWeapon 2004 Weapon.AmmoType1 "EnergyPod" Weapon.SisterWeapon "Mauler2" Inventory.Icon "TRPDA0" - Tag "Mauler" + Tag "$TAG_MAULER1" Inventory.PickupMessage "$TXT_MAULER" + Obituary "$OB_MPMAULER1" action native A_FireMauler1 (); @@ -525,6 +534,8 @@ ACTOR Mauler2 : Mauler Weapon.AmmoGive1 0 Weapon.AmmoType1 "EnergyPod" Weapon.SisterWeapon "Mauler" + Obituary "$OB_MPMAULER2" + Tag "$TAG_MAULER2" action native A_FireMauler2Pre (); action native A_FireMauler2 (); @@ -586,6 +597,7 @@ ACTOR MaulerTorpedo RenderStyle Add SeeSound "weapons/mauler2fire" DeathSound "weapons/mauler2hit" + Obituary "$OB_MPMAULER" action native A_MaulerTorpedoWave (); @@ -616,6 +628,7 @@ ACTOR MaulerTorpedoWave +STRIFEDAMAGE MaxStepHeight 4 RenderStyle Add + Obituary "$OB_MPMAULER" States { Spawn: @@ -650,6 +663,7 @@ ACTOR HEGrenade BounceCount 2 SeeSound "weapons/hegrenadeshoot" DeathSound "weapons/hegrenadebang" + Obituary "$OB_MPSTRIFEGRENADE" States { Spawn: @@ -687,6 +701,7 @@ ACTOR PhosphorousGrenade BounceCount 2 SeeSound "weapons/phgrenadeshoot" DeathSound "weapons/phgrenadebang" + Obituary "$OB_MPPHOSPHOROUSGRENADE" States { Spawn: @@ -710,6 +725,7 @@ ACTOR PhosphorousFire native +NODAMAGETHRUST +DONTSPLASH RenderStyle Add + Obituary "$OB_MPPHOSPHOROUSGRENADE" action native A_Burnarea (); action native A_Burnination (); @@ -748,7 +764,7 @@ ACTOR StrifeGrenadeLauncher : StrifeWeapon 154 Weapon.AmmoType1 "HEGrenadeRounds" Weapon.SisterWeapon "StrifeGrenadeLauncher2" Inventory.Icon "GRNDA0" - Tag "Grenade Launcher" + Tag "$TAG_GLAUNCHER1" Inventory.PickupMessage "$TXT_GLAUNCHER" action native A_FireGrenade (class grenadetype, int angleofs, state flash); @@ -794,6 +810,7 @@ ACTOR StrifeGrenadeLauncher2 : StrifeGrenadeLauncher Weapon.AmmoGive1 0 Weapon.AmmoType1 "PhosphorusGrenadeRounds" Weapon.SisterWeapon "StrifeGrenadeLauncher" + Tag "$TAG_GLAUNCHER2" States { diff --git a/wadsrc/static/actors/strife/templar.txt b/wadsrc/static/actors/strife/templar.txt index 214804b34..c20aed49b 100644 --- a/wadsrc/static/actors/strife/templar.txt +++ b/wadsrc/static/actors/strife/templar.txt @@ -20,7 +20,7 @@ ACTOR Templar 3003 DeathSound "templar/death" ActiveSound "templar/active" CrushPainSound "misc/pcrush" - Tag "TEMPLAR" + Tag "$TAG_TEMPLAR" HitObituary "$OB_TEMPLARHIT" Obituary "$OB_TEMPLAR" DropItem "EnergyPod" diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 2f23edc2e..5f05ba447 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -727,6 +727,50 @@ OB_MPTELEFRAG = "%o was telefragged by %k."; OB_RAILGUN = "%o was railed by %k."; OB_MPBFG_MBF = "%o was burned by %k's BFG."; +OB_MPSTAFF = "%o got staffed by %k."; +OB_MPGAUNTLETS = "%o got a shock from %k's gauntlets."; +OB_MPGOLDWAND = "%o waved goodbye to %k's elven wand."; +OB_MPCROSSBOW = "%o was pegged by %k's ethereal crossbow."; +OB_MPBLASTER = "%o was blasted a new one by %k's dragon claw."; +OB_MPSKULLROD = "%o got sent down under by %k's hellstaff."; +OB_MPPHOENIXROD = "%o was scorched to cinders by %k's phoenix rod."; +OB_MPMACE = "%o was bounced by $k's firemace."; + +OB_MPPSTAFF = "%o got clapped by %k's charged staff."; +OB_MPPGAUNTLETS = "%o was bled dry by %k's gauntlets."; +OB_MPPGOLDWAND = "%o was assaulted by %k's elven wand."; +OB_MPPCROSSBOW = "%o was shafted by %k's ethereal crossbow."; +OB_MPPBLASTER = "%o was ripped apart by %k's dragon claw."; +OB_MPPSKULLROD = "%k poured his hellstaff on %o."; +OB_MPPPHOENIXROD = "%o was burned down by %k's phoenix staff."; +OB_MPPMACE = "%o was squished by %k's giant mace sphere."; + +OB_MPFWEAPFIST = "%o was beaten to a pulp by %k's bare fists."; +OB_MPFWEAPAXE = "%o got the axe from %k."; +OB_MPFWEAPHAMMERM = "%o had %p head caved in by %k's hammer."; +OB_MPFWEAPHAMMERR = "%o's soul was forged anew by %k's hammer."; +OB_MPFWEAPQUIETUS = "%o was silenced by %k's mighty Quietus."; +OB_MPCWEAPMACE = "%o got a mace to the face from %k."; +OB_MPCWEAPSTAFFM = "%o was bitten by %k's serpent staff."; +OB_MPCWEAPSTAFFR = "%o choked on %k's serpent staff."; +OB_MPCWEAPFLAME = "%o was lit up by %k's flames."; +OB_MPCWEAPWRAITHVERGE = "%o was cleansed by %k's Wraithverge."; +OB_MPMWEAPWAND = "%o took one too many sapphire beams from %k."; +OB_MPMWEAPFROST = "%o was turned into a frosty fellow by %k."; +OB_MPMWEAPLIGHTNING = "%o recieved a shocking revelation from %k."; +OB_MPMWEAPBLOODSCOURGE = "%o was wiped off the face of the universe by %k's Bloodscourge."; + +OB_MPPUNCHDAGGER = "%o was unwittingly backstabbed by %k."; +OB_MPELECTRICBOLT = "%o got bolted to the wall by %k."; +OB_MPPOISONBOLT = "%o recieved a lethal dose of %k's wrath."; +OB_MPASSAULTGUN = "%o was drilled full of holes by %k's assault gun."; +OB_MPMINIMISSILELAUNCHER = "%o gulped down %k's missile."; +OB_MPSTRIFEGRENADE = "%o was inverted by %k's H-E grenade."; +OB_MPPHOSPHOROUSGRENADE = "%o took a flame bath in %k's phosphorous pyre."; +OB_MPFLAMETHROWER = "%o was barbecued by %k."; +OB_MPMAULER = "%o was viciously vaporized by %k."; +OB_MPSIGIL = "%o bowed down to the sheer power of %k's Sigil."; + // Same as OB_MPTELEFRAG, but shown when a monster telefrags you OB_MONTELEFRAG = "%o was telefragged."; @@ -743,6 +787,207 @@ STARTUP3 = ""; STARTUP4 = ""; STARTUP5 = ""; + +// Item tags: Doom weapons +TAG_FIST = "Brass Knuckles"; +TAG_CHAINSAW = "Chainsaw"; +TAG_PISTOL = "Pistol"; +TAG_SHOTGUN = "Shotgun"; +TAG_SUPERSHOTGUN = "Super Shotgun"; +TAG_CHAINGUN = "Chaingun"; +TAG_ROCKETLAUNCHER = "Rocket Launcher"; +TAG_PLASMARIFLE = "Plama Rifle"; +TAG_BFG9000 = "BFG 9000"; + +// Item tags: Heretic weapons +TAG_STAFF = "Staff"; +TAG_GAUNTLETS = "Gauntlets of the Necromancer"; +TAG_GOLDWAND = "Elven Wand"; +TAG_CROSSBOW = "Ethereal Crossbow"; +TAG_BLASTER = "Dragon Claw"; +TAG_SKULLROD = "Hellstaff"; +TAG_PHOENIXROD = "Phoenix Rod"; +TAG_MACE = "Firemace"; + +// Item tags: Heretic artifacts +TAG_ARTIEGG = "Morph Ovum"; +TAG_ARTIFIREBOMB = "Timebomb of the Ancients"; +TAG_ARTIFLY = "Wings of Wrath"; +TAG_ARTIHEALTH = "Quartz Flask"; +TAG_ARTIINVISIBILITY = "Shadowsphere"; +TAG_ARTIINVULNERABILITY = "Ring of Invincibility"; +TAG_ARTISUPERHEALTH = "Mystic Urn"; +TAG_ARTITELEPORT = "Chaos Device"; +TAG_ARTITOMEOFPOWER = "Tome of Power"; +TAG_ARTITORCH = "Torch"; + +// Item tags: Hexen weapons +TAG_CWEAPMACE = "Mace of Contrition"; +TAG_CWEAPSTAFF = "Serpent Staff"; +TAG_CWEAPFLAME = "Firestorm"; +TAG_CWEAPWRAITHVERGE = "Wraithverge"; +TAG_FWEAPFIST = "Spiked Gauntlets"; +TAG_FWEAPAXE = "Timon's Axe"; +TAG_FWEAPHAMMER = "Hammer of Retribution"; +TAG_FWEAPQUIETUS = "Quietus"; +TAG_MWEAPWAND = "Sapphire Wand"; +TAG_MWEAPFROST = "Frost Shards"; +TAG_MWEAPLIGHTNING = "Arcs of Death"; +TAG_MWEAPBLOODSCOURGE = "Bloodscourge"; + +// Item tags: Hexen artifacts +TAG_ARTIBLASTRADIUS = "Disc of Repulsion"; +TAG_ARTIBOOSTARMOR = "Dragonskin Bracers"; +TAG_ARTIBOOSTMANA = "Krater of Might"; +TAG_ARTIPOISONBAG = "Flechette"; +TAG_ARTIPOISONBAG1 = "Poison Cloud Flechette"; +TAG_ARTIPOISONBAG2 = "Timebomb Flechette"; +TAG_ARTIPOISONBAG3 = "Grenade Flechette"; +TAG_ARTIHEALINGRADIUS = "Mystic Ambit Incant"; +TAG_ARTIDEFENDER = "Icon of the Defender"; +TAG_ARTIPORK = "Porkelator"; +TAG_ARTISPEED = "Boots of Speed"; +TAG_ARTISUMMON = "Dark Servant"; +TAG_ARTITELEPORTOTHER = "Banishment Device"; + +// Item tags: Hexen puzzle items +TAG_ARTIPUZZSKULL = "Yorick's Skull"; +TAG_ARTIPUZZGEMBIG = "Heart of D'Sparil"; +TAG_ARTIPUZZGEMRED = "Ruby Planet"; +TAG_ARTIPUZZGEMGREEN1 = "Emerald Planet (1)"; +TAG_ARTIPUZZGEMGREEN2 = "Emerald Planet (2)"; +TAG_ARTIPUZZGEMBLUE1 = "Sapphire Planet (1)"; +TAG_ARTIPUZZGEMBLUE2 = "Sapphire Planet (2)"; +TAG_ARTIPUZZBOOK1 = "Daemon Codex"; +TAG_ARTIPUZZBOOK2 = "Liber Obscura"; +TAG_ARTIPUZZSKULL2 = "Flame Mask"; +TAG_ARTIPUZZFWEAPON = "Glaive Seal"; +TAG_ARTIPUZZCWEAPON = "Holy Relic"; +TAG_ARTIPUZZMWEAPON = "Sigil of the Magus"; +TAG_ARTIPUZZGEAR1 = "Iron gear"; +TAG_ARTIPUZZGEAR2 = "Brass gear"; +TAG_ARTIPUZZGEAR3 = "Brass and iron gear"; +TAG_ARTIPUZZGEAR4 = "Silver and brass gear"; + +// Item tags: Strife weapons +TAG_PUNCHDAGGER = "Dagger"; +TAG_STRIFECROSSBOW1 = "Crossbow"; +TAG_STRIFECROSSBOW2 = "Crossbow"; +TAG_ASSAULTGUN = "Assault Gun"; +TAG_MMLAUNCHER = "Mini Missile Launcher"; +TAG_FLAMER = "Flame Thrower"; +TAG_MAULER1 = "Mauler"; +TAG_MAULER2 = "Mauler"; +TAG_GLAUNCHER1 = "Grenade Launcher"; +TAG_GLAUNCHER2 = "Grenade Launcher"; +TAG_SIGIL = "SIGIL"; + +// Item tags: Strife artifacts +TAG_COIN = "coin"; +TAG_MEDPATCH = "Med patch"; +TAG_MEDICALKIT = "Medical kit"; +TAG_SURGERYKIT = "Surgery Kit"; // "full_health" in the Teaser +TAG_BELDINSRING = "Ring"; +TAG_OFFERINGCHALICE = "Offering Chalice"; +TAG_EAR = "Ear"; +TAG_BROKENCOUPLING = "Broken Power Coupling"; +TAG_SHADOWARMOR = "Shadow Armor"; +TAG_ENVSUIT = "Environmental Suit"; +TAG_GUARDUNIFORM = "Guard Uniform"; +TAG_OFFICERSUNIFORM = "Officer's Uniform"; +TAG_FTHROWERPARTS = "Flame Thrower Parts"; +TAG_REPORT = "Report"; +TAG_INFO = "Info"; +TAG_TARGETER = "Targeter"; +TAG_COMMUNICATOR = "Communicator"; +TAG_DEGNINORE = "Degnin Ore"; +TAG_GUNTRAINING = "Accuracy"; +TAG_HEALTHTRAINING = "Toughness"; +TAG_SCANNER = "Scanner"; +TAG_PRISONPASS = "Prison Pass"; +TAG_ALARM = "Alarm"; +TAG_AMMOFILLUP = "Ammo"; +TAG_HEALTHFILLUP = "Health"; +TAG_TELEPORTERBEACON = "Teleporter Beacon"; +TAG_METALARMOR = "Metal Armor"; +TAG_LEATHER = "Leather Armor"; +TAG_HEGRENADES = "HE-Grenade Rounds"; +TAG_PHGRENADES = "Phoshorus-Grenade Rounds"; // "Fire-Grenade_Rounds" in the Teaser +TAG_CLIPOFBULLETS = "Clip of Bullets"; // "bullets" in the Teaser +TAG_BOXOFBULLETS = "Ammo"; +TAG_MINIMISSILES = "Mini Missiles"; //"rocket" in the Teaser +TAG_CRATEOFMISSILES = "Crate of Missiles"; //"box_of_rockets" in the Teaser +TAG_ENERGYPOD = "Energy Pod"; +TAG_ENERGYPACK = "Energy Pack"; +TAG_POISONBOLTS = "Poison Bolts"; // "poison_arrows" in the Teaser +TAG_ELECTRICBOLTS = "Electric Bolts"; // "electric_arrows" in the Teaser +TAG_AMMOSATCHEL = "Ammo Satchel"; // "Back_pack" in the Teaser + +// Item tags: Strife keys +TAG_BASEKEY = "Base Key"; +TAG_GOVSKEY = "Govs Key"; // "Rebel_Key" in the Teaser +TAG_PASSCARD = "Passcard"; +TAG_IDBADGE = "ID Badge"; +TAG_PRISONKEY = "Prison Key"; +TAG_SEVEREDHAND = "Severed Hand"; +TAG_POWER1KEY = "Power1 Key"; +TAG_POWER2KEY = "Power2 Key"; +TAG_POWER3KEY = "Power3 Key"; +TAG_GOLDKEY = "Gold Key"; +TAG_IDCARD = "ID Card"; +TAG_SILVERKEY = "Silver Key"; +TAG_ORACLEKEY = "Oracle Key"; +TAG_MILITARYID = "Military ID"; +TAG_ORDERKEY = "Order Key"; +TAG_WAREHOUSEKEY = "Warehouse Key"; +TAG_BRASSKEY = "Brass Key"; +TAG_REDCRYSTALKEY = "Red Crystal Key"; +TAG_BLUECRYSTALKEY = "Blue Crystal Key"; +TAG_CHAPELKEY = "Chapel Key"; +TAG_CATACOMBKEY = "Catacomb Key"; // "Tunnel_Key" in the Teaser +TAG_SECURITYKEY = "Security Key"; +TAG_COREKEY = "Core Key"; // "New_Key1" in the Teaser +TAG_MAULERKEY = "Mauler Key"; // "New_Key2" in the Teaser +TAG_FACTORYKEY = "Factory Key"; // "New_Key3" in the Teaser +TAG_MINEKEY = "Mine_Key"; // "New_Key4" in the Teaser +TAG_NEWKEY5 = "New Key5"; +TAG_ORACLEPASS = "Oracle Pass"; + +// Item tags: misc Strife stuff +TAG_10GOLD = "10 gold"; +TAG_25GOLD = "25 gold"; +TAG_50GOLD = "50 gold"; +TAG_300GOLD = "300 gold"; +TAG_QUEST4 = "quest4"; +TAG_QUEST5 = "quest5"; +TAG_QUEST6 = "quest4"; + +// Item tags: Strife NPCs +TAG_ACOLYTE = "ACOLYTE"; +TAG_ARMORER = "Armorer"; +TAG_BARKEEP = "Bar Keep"; +TAG_BEGGAR = "Beggar"; +TAG_MACIL1 = "MACIL"; +TAG_MACIL2 = "MACIL"; +TAG_MEDIC = "Medic"; +TAG_ORACLE = "Oracle"; +TAG_PRIEST = "PRIEST"; +TAG_RATBUDDY = "rat buddy"; +TAG_REBEL = "Rebel"; +TAG_TEMPLAR = "TEMPLAR"; +TAG_WEAPONSMITH = "Weapon Smith"; + +// Item tags: Chex weapons +TAG_SPOON = "Spoon"; +TAG_SPORK = "Super Bootspork"; +TAG_MINIZORCHER = "Mini Zorcher"; +TAG_LARGEZORCHER = "Large Zorcher"; +TAG_SUPERLARGEZORCHER = "Super-Large Zorcher"; +TAG_RAPIDZORCHER = "Rapid Zorcher"; +TAG_ZORCHPROPULSOR = "Zorch Propulsor"; +TAG_PHASINGZORCHER = "Phasing Zorcher"; +TAG_LAZDEVICE = "LAZ Device"; + // Heretic strings HE1TEXT = "with the destruction of the iron\n" From f6edfd1300fb681119086c1814a4f28b7d384e18 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 19 Aug 2010 07:59:32 +0000 Subject: [PATCH 185/251] - The Wiki seems to imply that FMod 4.28 is not the best choice for ZDoom so mention this in fmod_version.txt. SVN r2553 (trunk) --- specs/fmod_version.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/fmod_version.txt b/specs/fmod_version.txt index a65aec918..c285c50b9 100644 --- a/specs/fmod_version.txt +++ b/specs/fmod_version.txt @@ -1 +1,3 @@ This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive. +Use of the latest 4.26 is recommended though due to technical issues with 4.28. + From 576e597d2b71fd03a07972623e1476396f74fceb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 15:31:44 +0000 Subject: [PATCH 186/251] - Increase the fluid_voices default to 128. It apparently has a poor voice cutting algorithm which is painfully apparent on hexen.wad MAP01's music, which hits around 90 voices. - Patch from Chris: * Add FluidSynth to the menu. * Enable FluidSynth for MIDI as well as MUS. * Fix CmakeLists.txt. SVN r2554 (trunk) --- src/CMakeLists.txt | 2 +- src/sound/i_music.cpp | 6 +++ src/sound/music_fluidsynth_mididevice.cpp | 2 +- src/sound/music_midi_base.cpp | 61 ++++++++++++++++------- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 03cedcded..f8ebfa9f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -490,7 +490,7 @@ set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_L include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) if( FLUIDSYNTH_FOUND ) - set( ZDOOM_LIBS "${FLUIDSYNTH_LIBRARIES}" ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) endif( FLUIDSYNTH_FOUND ) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 51640b747..859422387 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -527,6 +527,12 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int { info = new MIDISong2(file, musiccache, len, MIDI_Timidity); } +#ifdef HAVE_FLUIDSYNTH + else if (snd_mididevice == -5 && device == MDEV_DEFAULT) + { + info = new MIDISong2(file, musiccache, len, MIDI_Fluid); + } +#endif if (info != NULL && !info->IsValid()) { delete info; diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 302166ad1..36a38d630 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -83,7 +83,7 @@ CUSTOM_CVAR(Bool, fluid_chorus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) currSong->FluidSettingStr("synth.chorus.active", self ? "yes" : "no"); } -CUSTOM_CVAR(Int, fluid_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 16) self = 16; diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 0184c6a10..dd3cc95d8 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -77,25 +77,34 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues) { if (*outValues == NULL) { - int count = 3 + nummididevices; + int count = 4 + nummididevices; value_t *values; UINT id; - int p; + int p = 0; *outValues = values = new value_t[count]; - values[0].name = "OPL Synth Emulation"; - values[0].value = -3.0; - values[1].name = "TiMidity++"; - values[1].value = -2.0; - values[2].name = "FMOD"; - values[2].value = -1.0; - for (id = 0, p = 3; id < nummididevices; ++id) +#ifdef HAVE_FLUIDSYNTH + values[p].name = "FluidSynth"; + values[p].value = -5.0; + ++p; +#endif + values[p].name = "OPL Synth Emulation"; + values[p].value = -3.0; + ++p; + values[p].name = "TiMidity++"; + values[p].value = -2.0; + ++p; + values[p].name = "FMOD"; + values[p].value = -1.0; + ++p; + for (id = 0; id < nummididevices; ++id) { MIDIOUTCAPS caps; MMRESULT res; res = midiOutGetDevCaps (id, &caps, sizeof(caps)); + assert(res == MMSYSERR_NOERROR); if (res == MMSYSERR_NOERROR) { size_t len = strlen (caps.szPname) + 1; @@ -107,8 +116,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues) ++p; } } - assert(p == count); - *numValues = float(count); + *numValues = float(p); } } @@ -154,6 +162,9 @@ CCMD (snd_listmididevices) MIDIOUTCAPS caps; MMRESULT res; +#ifdef HAVE_FLUIDSYNTH + PrintMidiDevice (-5, "FluidSynth", MOD_SWSYNTH, 0); +#endif PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0); PrintMidiDevice (-2, "TiMidity++", 0, MOD_SWSYNTH); PrintMidiDevice (-1, "FMOD", 0, MOD_SWSYNTH); @@ -191,21 +202,33 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues) if (*outValues == NULL) { value_t *values; + int p = 0; - *outValues = values = new value_t[3]; + *outValues = values = new value_t[4]; - values[0].name = "OPL Synth Emulation"; - values[0].value = -3.0; - values[1].name = "TiMidity++"; - values[1].value = -2.0; - values[2].name = "FMOD"; - values[2].value = -1.0; - *numValues = 3.f; +#ifdef HAVE_FLUIDSYNTH + values[p].name = "FluidSynth"; + values[p].value = -5.0; + ++p; +#endif + values[p].name = "OPL Synth Emulation"; + values[p].value = -3.0; + ++p; + values[p].name = "TiMidity++"; + values[p].value = -2.0; + ++p; + values[p].name = "FMOD"; + values[p].value = -1.0; + ++p; + *numValues = float(p); } } CCMD (snd_listmididevices) { +#ifdef HAVE_FLUIDSYNTH + Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : ""); +#endif Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : ""); Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : ""); Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : ""); From 2c397b1aaccb9e47ce7e0424626daf9706562407 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 15:46:49 +0000 Subject: [PATCH 187/251] - Add a default search for Creative's CT4MGM.SF2 on Windows if fluid_patchset is unspecified. - Use fluid_patchset to specify the SoundFont(s) for FluidSynth instead of doubling up with snd_midipatchset, which is already used by FMOD. SVN r2555 (trunk) --- src/sound/fmodsound.cpp | 2 +- src/sound/music_fluidsynth_mididevice.cpp | 25 +++++++++++++++++------ src/sound/music_midi_base.cpp | 2 -- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index ff99d516e..23e374a7b 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -101,7 +101,6 @@ EXTERN_CVAR (Int, snd_buffersize) EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Bool, snd_pitched) EXTERN_CVAR (Int, snd_channels) -EXTERN_CVAR (String, snd_midipatchset) extern int sfx_empty; @@ -117,6 +116,7 @@ CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_profile, false, 0) +CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter. CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 36a38d630..fba167b71 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -55,12 +55,12 @@ // EXTERNAL DATA DECLARATIONS ---------------------------------------------- -EXTERN_CVAR(String, snd_midipatchset) - // PRIVATE DATA DEFINITIONS ------------------------------------------------ // PUBLIC DATA DEFINITIONS ------------------------------------------------- +CVAR(String, fluid_patchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) @@ -143,16 +143,29 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() { Printf("Failed to set interpolation method %d.\n", *fluid_interp); } - if (0 == LoadPatchSets(snd_midipatchset)) + if (0 == LoadPatchSets(fluid_patchset)) { #ifdef unix // This is the standard location on Ubuntu. if (0 == LoadPatchSets("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2")) { #endif - Printf("Failed to load any MIDI patches.\n"); - delete_fluid_synth(FluidSynth); - FluidSynth = NULL; +#ifdef _WIN32 + // On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default. + char sysdir[MAX_PATH+sizeof("\\CT4MGM.SF2")]; + if (0 != GetSystemDirectoryA(sysdir, MAX_PATH)) + { + strcat(sysdir, "\\CT4MGM.SF2"); + if (0 == LoadPatchSets(sysdir)) + { +#endif + Printf("Failed to load any MIDI patches.\n"); + delete_fluid_synth(FluidSynth); + FluidSynth = NULL; +#ifdef _WIN32 + } + } +#endif #ifdef unix } #endif diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index dd3cc95d8..39f42cc35 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -10,8 +10,6 @@ static DWORD nummididevices; static bool nummididevicesset; -CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG); - #ifdef _WIN32 UINT mididevice; From 2136ef2abafff34142a52f2a13a5c04ad95fdf79 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 15:51:07 +0000 Subject: [PATCH 188/251] - Also check for CT2MGM.SF2 if CT4MGM.SF2 is not found. SVN r2556 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index fba167b71..d151cd86f 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -153,16 +153,22 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() #ifdef _WIN32 // On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default. char sysdir[MAX_PATH+sizeof("\\CT4MGM.SF2")]; - if (0 != GetSystemDirectoryA(sysdir, MAX_PATH)) + UINT filepart; + if (0 != (filepart = GetSystemDirectoryA(sysdir, MAX_PATH))) { strcat(sysdir, "\\CT4MGM.SF2"); if (0 == LoadPatchSets(sysdir)) { + // Try again with CT2MGM.SF2 + sysdir[filepart + 3] = '2'; + if (0 == LoadPatchSets(sysdir)) + { #endif - Printf("Failed to load any MIDI patches.\n"); - delete_fluid_synth(FluidSynth); - FluidSynth = NULL; + Printf("Failed to load any MIDI patches.\n"); + delete_fluid_synth(FluidSynth); + FluidSynth = NULL; #ifdef _WIN32 + } } } #endif From f389cd8b0fb60404c7daded316175ae49cedead1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 16:49:43 +0000 Subject: [PATCH 189/251] - Add on-demand loading for fluidsynth.dll. This also lets you build with FluidSynth support without actually having the FluidSynth development files installed. SVN r2557 (trunk) --- src/sound/i_musicinterns.h | 38 ++++++ src/sound/music_fluidsynth_mididevice.cpp | 145 ++++++++++++++++++++-- zdoom.vcproj | 12 +- 3 files changed, 184 insertions(+), 11 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 4deec4f55..041e3db00 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -261,7 +261,12 @@ protected: // FluidSynth implementation of a MIDI device ------------------------------- #ifdef HAVE_FLUIDSYNTH +#ifndef DYN_FLUIDSYNTH #include +#else +struct fluid_settings_t; +struct fluid_synth_t; +#endif class FluidSynthMIDIDevice : public MIDIDevice { @@ -313,6 +318,39 @@ protected: MIDIHDR *Events; bool Started; DWORD Position; + +#ifdef DYN_FLUIDSYNTH + enum { FLUID_FAILED = 1, FLUID_OK = 0 }; + fluid_settings_t *(STACK_ARGS *new_fluid_settings)(); + fluid_synth_t *(STACK_ARGS *new_fluid_synth)(fluid_settings_t *); + int (STACK_ARGS *delete_fluid_synth)(fluid_synth_t *); + void (STACK_ARGS *delete_fluid_settings)(fluid_settings_t *); + int (STACK_ARGS *fluid_settings_setnum)(fluid_settings_t *, const char *, double); + int (STACK_ARGS *fluid_settings_setstr)(fluid_settings_t *, const char *, const char *); + int (STACK_ARGS *fluid_settings_setint)(fluid_settings_t *, const char *, int); + int (STACK_ARGS *fluid_settings_getstr)(fluid_settings_t *, const char *, char **); + int (STACK_ARGS *fluid_settings_getint)(fluid_settings_t *, const char *, int *); + int (STACK_ARGS *fluid_synth_set_interp_method)(fluid_synth_t *, int, int); + int (STACK_ARGS *fluid_synth_set_polyphony)(fluid_synth_t *, int); + int (STACK_ARGS *fluid_synth_get_polyphony)(fluid_synth_t *); + int (STACK_ARGS *fluid_synth_get_active_voice_count)(fluid_synth_t *); + double (STACK_ARGS *fluid_synth_get_cpu_load)(fluid_synth_t *); + int (STACK_ARGS *fluid_synth_system_reset)(fluid_synth_t *); + int (STACK_ARGS *fluid_synth_noteon)(fluid_synth_t *, int, int, int); + int (STACK_ARGS *fluid_synth_noteoff)(fluid_synth_t *, int, int); + int (STACK_ARGS *fluid_synth_cc)(fluid_synth_t *, int, int, int); + int (STACK_ARGS *fluid_synth_program_change)(fluid_synth_t *, int, int); + int (STACK_ARGS *fluid_synth_channel_pressure)(fluid_synth_t *, int, int); + int (STACK_ARGS *fluid_synth_pitch_bend)(fluid_synth_t *, int, int); + int (STACK_ARGS *fluid_synth_write_float)(fluid_synth_t *, int, void *, int, int, void *, int, int); + int (STACK_ARGS *fluid_synth_sfload)(fluid_synth_t *, const char *, int); + +#ifdef _WIN32 + HMODULE FluidSynthDLL; +#endif + bool LoadFluidSynth(); + void UnloadFluidSynth(); +#endif }; #endif diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index d151cd86f..6cb576b18 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -45,6 +45,20 @@ // MACROS ------------------------------------------------------------------ +#ifdef DYN_FLUIDSYNTH + +#ifdef _WIN32 +#ifndef _M_X64 +#define FLUIDSYNTHLIB "fluidsynth.dll" +#else +#define FLUIDSYNTHLIB "fluidsynth64.dll" +#endif +#else +#error "TODO: Write a dlopen() version of this code." +#endif + +#endif + // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -93,16 +107,22 @@ CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) currSong->FluidSettingInt("synth.polyphony", self); } -CUSTOM_CVAR(Int, fluid_interp, FLUID_INTERP_LINEAR, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { // Values are: 0 = FLUID_INTERP_NONE // 1 = FLUID_INTERP_LINEAR - // 2 = FLUID_INTERP_4THORDER (the FluidSynth default) - // 3 = FLUID_INTERP_7THORDER - if (self < FLUID_INTERP_NONE) - self = FLUID_INTERP_NONE; - else if (self > FLUID_INTERP_HIGHEST) - self = FLUID_INTERP_HIGHEST; + // 4 = FLUID_INTERP_4THORDER (the FluidSynth default) + // 7 = FLUID_INTERP_7THORDER + // (And here I thought it was just a linear list.) + // Round undefined values to the nearest valid one. + if (self < 0) + self = 0; + else if (self == 2) + self = 1; + else if (self == 3 || self == 5) + self = 4; + else if (self == 6 || self > 7) + self = 7; else if (currSong != NULL) currSong->FluidSettingInt("synth.interpolation", self); } @@ -123,6 +143,13 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() Events = NULL; Started = false; FluidSynth = NULL; + FluidSettings = NULL; +#ifdef DYN_FLUIDSYNTH + if (!LoadFluidSynth()) + { + return; + } +#endif FluidSettings = new_fluid_settings(); if (FluidSettings == NULL) { @@ -195,6 +222,9 @@ FluidSynthMIDIDevice::~FluidSynthMIDIDevice() { delete_fluid_settings(FluidSettings); } +#ifdef DYN_FLUIDSYNTH + UnloadFluidSynth(); +#endif } //========================================================================== @@ -814,5 +844,106 @@ FString FluidSynthMIDIDevice::GetStats() return out; } +#ifdef DYN_FLUIDSYNTH + +struct LibFunc +{ + void **FuncPointer; + const char *FuncName; +}; + +//========================================================================== +// +// FluidSynthMIDIDevice :: LoadFluidSynth +// +// Returns true if the FluidSynth library was successfully loaded. +// +//========================================================================== + +bool FluidSynthMIDIDevice::LoadFluidSynth() +{ + LibFunc imports[] = + { + { (void **)&new_fluid_settings, "new_fluid_settings" }, + { (void **)&new_fluid_synth, "new_fluid_synth" }, + { (void **)&delete_fluid_synth, "delete_fluid_synth" }, + { (void **)&delete_fluid_settings, "delete_fluid_settings" }, + { (void **)&fluid_settings_setnum, "fluid_settings_setnum" }, + { (void **)&fluid_settings_setstr, "fluid_settings_setstr" }, + { (void **)&fluid_settings_setint, "fluid_settings_setint" }, + { (void **)&fluid_settings_getstr, "fluid_settings_getstr" }, + { (void **)&fluid_settings_getint, "fluid_settings_getint" }, + { (void **)&fluid_synth_set_interp_method, "fluid_synth_set_interp_method" }, + { (void **)&fluid_synth_set_polyphony, "fluid_synth_set_polyphony" }, + { (void **)&fluid_synth_get_polyphony, "fluid_synth_get_polyphony" }, + { (void **)&fluid_synth_get_active_voice_count, "fluid_synth_get_active_voice_count" }, + { (void **)&fluid_synth_get_cpu_load, "fluid_synth_get_cpu_load" }, + { (void **)&fluid_synth_system_reset, "fluid_synth_system_reset" }, + { (void **)&fluid_synth_noteon, "fluid_synth_noteon" }, + { (void **)&fluid_synth_noteoff, "fluid_synth_noteoff" }, + { (void **)&fluid_synth_cc, "fluid_synth_cc" }, + { (void **)&fluid_synth_program_change, "fluid_synth_program_change" }, + { (void **)&fluid_synth_channel_pressure, "fluid_synth_channel_pressure" }, + { (void **)&fluid_synth_pitch_bend, "fluid_synth_pitch_bend" }, + { (void **)&fluid_synth_write_float, "fluid_synth_write_float" }, + { (void **)&fluid_synth_sfload, "fluid_synth_sfload" } + }; + int fail = 0; + +#ifdef _WIN32 + FluidSynthDLL = LoadLibrary(FLUIDSYNTHLIB); +#endif + if (FluidSynthDLL == NULL) + { + Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB "\n"); + return false; + } + + for (int i = 0; i < countof(imports); ++i) + { +#ifdef _WIN32 + FARPROC proc = GetProcAddress(FluidSynthDLL, imports[i].FuncName); + if (proc == NULL) + { + Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, FLUIDSYNTHLIB); + fail++; + } + *imports[i].FuncPointer = proc; +#endif + } + if (fail == 0) + { + return true; + } + else + { +#ifdef _WIN32 + FreeLibrary(FluidSynthDLL); + FluidSynthDLL = NULL; +#endif + return false; + } + +} + +//========================================================================== +// +// FluidSynthMIDIDevice :: UnloadFluidSynth +// +//========================================================================== + +void FluidSynthMIDIDevice::UnloadFluidSynth() +{ +#ifdef _WIN32 + if (FluidSynthDLL != NULL) + { + FreeLibrary(FluidSynthDLL); + FluidSynthDLL = NULL; + } +#endif +} + +#endif + #endif diff --git a/zdoom.vcproj b/zdoom.vcproj index 913cff4a9..3edc5d20e 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -56,8 +56,8 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" WholeProgramOptimization="false" - AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu\gme;gdtoa;bzip2;lzma\C" - PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH" + AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";"game-music-emu\gme";gdtoa;bzip2;lzma\C" + PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH" StringPooling="true" ExceptionHandling="1" RuntimeLibrary="0" @@ -286,8 +286,8 @@ + + From a68e9c8fa61a3a32e986d4c8d5e574d139df29c9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 20:46:19 +0000 Subject: [PATCH 190/251] - Added a dlopen() version of on-demand FluidSynth loading and exposed it to CMake through the DYN_FLUIDSYNTH option. SVN r2558 (trunk) --- src/CMakeLists.txt | 10 +++++++-- src/sound/i_musicinterns.h | 2 ++ src/sound/music_fluidsynth_mididevice.cpp | 26 ++++++++++++++++++++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8ebfa9f2..281be10b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,8 @@ if( CMAKE_COMPILER_IS_GNUCXX ) endif( APPLE ) endif( CMAKE_COMPILER_IS_GNUCXX ) +option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ) + if( CMAKE_SIZEOF_VOID_P MATCHES "8" ) set( X64 64 ) endif( CMAKE_SIZEOF_VOID_P MATCHES "8" ) @@ -490,8 +492,10 @@ set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_L include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) if( FLUIDSYNTH_FOUND ) + if( NOT DYN_FLUIDSYNTH) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) + endif( NOT DYN_FLUIDSYNTH ) endif( FLUIDSYNTH_FOUND ) # Start defining source files for ZDoom @@ -587,9 +591,11 @@ else( SSE_MATTERS ) set( X86_SOURCES ) endif( SSE_MATTERS ) -if( FLUIDSYNTH_FOUND ) +if( DYN_FLUIDSYNTH ) + add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) +elseif( FLUIDSYNTH_FOUND ) add_definitions( -DHAVE_FLUIDSYNTH ) -endif( FLUIDSYNTH_FOUND ) +endif( DYN_FLUIDSYNTH ) add_executable( zdoom WIN32 autostart.cpp diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 041e3db00..18b6937df 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -347,6 +347,8 @@ protected: #ifdef _WIN32 HMODULE FluidSynthDLL; +#else + void *FluidSynthSO; #endif bool LoadFluidSynth(); void UnloadFluidSynth(); diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 6cb576b18..fb573f2fb 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -54,7 +54,9 @@ #define FLUIDSYNTHLIB "fluidsynth64.dll" #endif #else -#error "TODO: Write a dlopen() version of this code." +#include + +#define FLUIDSYNTHLIB "libfluidsynth.so.1" #endif #endif @@ -892,24 +894,33 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() #ifdef _WIN32 FluidSynthDLL = LoadLibrary(FLUIDSYNTHLIB); -#endif if (FluidSynthDLL == NULL) { Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB "\n"); return false; } +#else + FluidSynthSO = dlopen(FLUIDSYNTHLIB, RTLD_LAZY); + if (FluidSynthSO == NULL) + { + Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB ": %s\n", dlerror()); + return false; + } +#endif for (int i = 0; i < countof(imports); ++i) { #ifdef _WIN32 FARPROC proc = GetProcAddress(FluidSynthDLL, imports[i].FuncName); +#else + void *proc = dlsym(FluidSynthSO, imports[i].FuncName); +#endif if (proc == NULL) { Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, FLUIDSYNTHLIB); fail++; } *imports[i].FuncPointer = proc; -#endif } if (fail == 0) { @@ -920,6 +931,9 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() #ifdef _WIN32 FreeLibrary(FluidSynthDLL); FluidSynthDLL = NULL; +#else + dlclose(FluidSynthSO); + FluidSynthSO = NULL; #endif return false; } @@ -940,6 +954,12 @@ void FluidSynthMIDIDevice::UnloadFluidSynth() FreeLibrary(FluidSynthDLL); FluidSynthDLL = NULL; } +#else + if (FluidSynthSO != NULL) + { + dlclose(FluidSynthSO); + FluidSynthSO = NULL; + } #endif } From eafb0ab7cfd835d9c156848dc4dad13fd80ffddc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 19 Aug 2010 23:11:16 +0000 Subject: [PATCH 191/251] - Expose more FluidSynth settings through these cvars: * fluid_samplerate * fluid_threads * fluid_reverb_roomsize * fluid_reverb_damping * fluid_reverb_width * fluid_reverb_level * fluid_chorus_voices * fluid_chorus_level * fluid_chorus_speed * fluid_chorus_depth * fluid_chorus_type SVN r2559 (trunk) --- src/sound/i_musicinterns.h | 3 + src/sound/music_fluidsynth_mididevice.cpp | 172 +++++++++++++++++++--- 2 files changed, 156 insertions(+), 19 deletions(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 18b6937df..2f7a83b22 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -318,6 +318,7 @@ protected: MIDIHDR *Events; bool Started; DWORD Position; + int SampleRate; #ifdef DYN_FLUIDSYNTH enum { FLUID_FAILED = 1, FLUID_OK = 0 }; @@ -344,6 +345,8 @@ protected: int (STACK_ARGS *fluid_synth_pitch_bend)(fluid_synth_t *, int, int); int (STACK_ARGS *fluid_synth_write_float)(fluid_synth_t *, int, void *, int, int, void *, int, int); int (STACK_ARGS *fluid_synth_sfload)(fluid_synth_t *, const char *, int); + void (STACK_ARGS *fluid_synth_set_reverb)(fluid_synth_t *, double, double, double, double); + void (STACK_ARGS *fluid_synth_set_chorus)(fluid_synth_t *, int, double, double, double, int); #ifdef _WIN32 HMODULE FluidSynthDLL; diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index fb573f2fb..32cd0da46 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -59,6 +59,20 @@ #define FLUIDSYNTHLIB "libfluidsynth.so.1" #endif +#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f +#define FLUID_REVERB_DEFAULT_DAMP 0.0f +#define FLUID_REVERB_DEFAULT_WIDTH 0.5f +#define FLUID_REVERB_DEFAULT_LEVEL 0.9f + +#define FLUID_CHORUS_MOD_SINE 0 +#define FLUID_CHORUS_MOD_TRIANGLE 1 + +#define FLUID_CHORUS_DEFAULT_N 3 +#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f +#define FLUID_CHORUS_DEFAULT_SPEED 0.3f +#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f +#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE + #endif // TYPES ------------------------------------------------------------------- @@ -129,6 +143,107 @@ CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) currSong->FluidSettingInt("synth.interpolation", self); } +CVAR(Int, fluid_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +// I don't know if this setting even matters for us, since we aren't letting +// FluidSynth drives its own output. +CUSTOM_CVAR(Int, fluid_threads, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 1) + self = 1; + else if (self > 256) + self = 256; +} + +CUSTOM_CVAR(Float, fluid_reverb_roomsize, FLUID_REVERB_DEFAULT_ROOMSIZE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 1.2f) + self = 1.2f; + else if (currSong != NULL) + currSong->FluidSettingInt("z.reverb-changed", 0); +} + +CUSTOM_CVAR(Float, fluid_reverb_damping, FLUID_REVERB_DEFAULT_DAMP, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 1) + self = 1; + else if (currSong != NULL) + currSong->FluidSettingInt("z.reverb-changed", 0); +} + +CUSTOM_CVAR(Float, fluid_reverb_width, FLUID_REVERB_DEFAULT_WIDTH, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 100) + self = 100; + else if (currSong != NULL) + currSong->FluidSettingInt("z.reverb-changed", 0); +} + +CUSTOM_CVAR(Float, fluid_reverb_level, FLUID_REVERB_DEFAULT_LEVEL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 1) + self = 1; + else if (currSong != NULL) + currSong->FluidSettingInt("z.reverb-changed", 0); +} + +CUSTOM_CVAR(Int, fluid_chorus_voices, FLUID_CHORUS_DEFAULT_N, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 99) + self = 99; + else if (currSong != NULL) + currSong->FluidSettingInt("z.chorus-changed", 0); +} + +CUSTOM_CVAR(Float, fluid_chorus_level, FLUID_CHORUS_DEFAULT_LEVEL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 1) + self = 1; + else if (currSong != NULL) + currSong->FluidSettingInt("z.chorus-changed", 0); +} + +CUSTOM_CVAR(Float, fluid_chorus_speed, FLUID_CHORUS_DEFAULT_SPEED, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0.29f) + self = 0.29f; + else if (self > 5) + self = 5; + else if (currSong != NULL) + currSong->FluidSettingInt("z.chorus-changed", 0); +} + +// depth is in ms and actual maximum depends on the sample rate +CUSTOM_CVAR(Float, fluid_chorus_depth, FLUID_CHORUS_DEFAULT_DEPTH, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; + else if (self > 21) + self = 21; + else if (currSong != NULL) + currSong->FluidSettingInt("z.chorus-changed", 0); +} + +CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self != FLUID_CHORUS_MOD_SINE && self != FLUID_CHORUS_MOD_TRIANGLE) + self = FLUID_CHORUS_DEFAULT_TYPE; + else if (currSong != NULL) + currSong->FluidSettingInt("z.chorus-changed", 0); +} + // CODE -------------------------------------------------------------------- //========================================================================== @@ -158,20 +273,28 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() printf("Failed to create FluidSettings.\n"); return; } + SampleRate = fluid_samplerate; + if (SampleRate < 22050 || SampleRate > 96000) + { // Match sample rate to SFX rate + SampleRate = clamp((int)GSnd->GetOutputRate(), 22050, 96000); + } + fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate); fluid_settings_setnum(FluidSettings, "synth.gain", fluid_gain); fluid_settings_setstr(FluidSettings, "synth.reverb.active", fluid_reverb ? "yes" : "no"); fluid_settings_setstr(FluidSettings, "synth.chorus.active", fluid_chorus ? "yes" : "no"); fluid_settings_setint(FluidSettings, "synth.polyphony", fluid_voices); + fluid_settings_setint(FluidSettings, "synth.cpu-cores", fluid_threads); FluidSynth = new_fluid_synth(FluidSettings); if (FluidSynth == NULL) { Printf("Failed to create FluidSynth.\n"); return; } - if (FLUID_FAILED == fluid_synth_set_interp_method(FluidSynth, -1, fluid_interp)) - { - Printf("Failed to set interpolation method %d.\n", *fluid_interp); - } + fluid_synth_set_interp_method(FluidSynth, -1, fluid_interp); + fluid_synth_set_reverb(FluidSynth, fluid_reverb_roomsize, fluid_reverb_damping, + fluid_reverb_width, fluid_reverb_level); + fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level, + fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type); if (0 == LoadPatchSets(fluid_patchset)) { #ifdef unix @@ -243,8 +366,8 @@ int FluidSynthMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO { return 2; } - Stream = GSnd->CreateStream(FillStream, int(44100 / 4) * 4, - SoundStream::Float, 44100, this); + Stream = GSnd->CreateStream(FillStream, (SampleRate / 4) * 4, + SoundStream::Float, SampleRate, this); if (Stream == NULL) { return 2; @@ -334,7 +457,7 @@ int FluidSynthMIDIDevice::SetTimeDiv(int timediv) void FluidSynthMIDIDevice::CalcTickRate() { - SamplesPerTick = 44100 / (1000000.0 / Tempo) / Division; + SamplesPerTick = SampleRate / (1000000.0 / Tempo) / Division; } //========================================================================== @@ -737,29 +860,38 @@ int FluidSynthMIDIDevice::LoadPatchSets(const char *patches) void FluidSynthMIDIDevice::FluidSettingInt(const char *setting, int value) { + if (FluidSynth == NULL || FluidSettings == NULL) + { + return; + } + if (strcmp(setting, "synth.interpolation") == 0) { - if (FluidSynth != NULL) + if (FLUID_OK != fluid_synth_set_interp_method(FluidSynth, -1, value)) { - if (FLUID_OK != fluid_synth_set_interp_method(FluidSynth, -1, value)) - { - Printf("Setting interpolation method %d failed.\n", value); - } + Printf("Setting interpolation method %d failed.\n", value); } } - else if (FluidSynth != NULL && strcmp(setting, "synth.polyphony") == 0) + else if (strcmp(setting, "synth.polyphony") == 0) { if (FLUID_OK != fluid_synth_set_polyphony(FluidSynth, value)) { Printf("Setting polyphony to %d failed.\n", value); } } - else if (FluidSettings != NULL) + else if (strcmp(setting, "z.reverb-changed") == 0) { - if (!fluid_settings_setint(FluidSettings, setting, value)) - { - Printf("Faild to set %s to %d.\n", setting, value); - } + fluid_synth_set_reverb(FluidSynth, fluid_reverb_roomsize, fluid_reverb_damping, + fluid_reverb_width, fluid_reverb_level); + } + else if (strcmp(setting, "z.chorus-changed") == 0) + { + fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level, + fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type); + } + else if (FLUID_OK != fluid_settings_setint(FluidSettings, setting, value)) + { + Printf("Faild to set %s to %d.\n", setting, value); } } @@ -888,7 +1020,9 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() { (void **)&fluid_synth_channel_pressure, "fluid_synth_channel_pressure" }, { (void **)&fluid_synth_pitch_bend, "fluid_synth_pitch_bend" }, { (void **)&fluid_synth_write_float, "fluid_synth_write_float" }, - { (void **)&fluid_synth_sfload, "fluid_synth_sfload" } + { (void **)&fluid_synth_sfload, "fluid_synth_sfload" }, + { (void **)&fluid_synth_set_reverb, "fluid_synth_set_reverb" }, + { (void **)&fluid_synth_set_chorus, "fluid_synth_set_chorus" }, }; int fail = 0; From 6f82db47b857218d147dd8fbddfc42ce371f6461 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 20 Aug 2010 04:21:53 +0000 Subject: [PATCH 192/251] - Merge the shared code for the softsynths into a common base class. SVN r2560 (trunk) --- src/CMakeLists.txt | 1 + src/oplsynth/music_opl_mididevice.cpp | 323 ++------------ src/sound/i_music.cpp | 2 +- src/sound/i_musicinterns.h | 135 +++--- src/sound/music_fluidsynth_mididevice.cpp | 421 +----------------- src/sound/music_softsynth_mididevice.cpp | 498 ++++++++++++++++++++++ src/sound/music_timidity_mididevice.cpp | 433 +------------------ zdoom.vcproj | 4 + 8 files changed, 630 insertions(+), 1187 deletions(-) create mode 100644 src/sound/music_softsynth_mididevice.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 281be10b9..9fb4cab09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -818,6 +818,7 @@ add_executable( zdoom WIN32 sound/music_mus_opl.cpp sound/music_stream.cpp sound/music_fluidsynth_mididevice.cpp + sound/music_softsynth_mididevice.cpp sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp textures/automaptexture.cpp diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index 9413ae4bb..ade5b5c12 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -74,25 +74,9 @@ OPLMIDIDevice::OPLMIDIDevice() { - Stream = NULL; - Tempo = 0; - Division = 0; - Events = NULL; - Started = false; - FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); -} - -//========================================================================== -// -// OPLMIDIDevice Destructor -// -//========================================================================== - -OPLMIDIDevice::~OPLMIDIDevice() -{ - Close(); + SampleRate = (int)OPL_SAMPLE_RATE; } //========================================================================== @@ -109,25 +93,14 @@ int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), vo { return 1; } - - Stream = GSnd->CreateStream(FillStream, int(OPL_SAMPLE_RATE / 14) * 4, - SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this); - if (Stream == NULL) + int ret = OpenStream(14, SoundStream::Mono, callback, userdata); + if (ret == 0) { - return 2; + OPLstopMusic(); + OPLplayMusic(100); + DEBUGOUT("========= New song started ==========\n", 0, 0, 0); } - - Callback = callback; - CallbackData = userdata; - Tempo = 500000; - Division = 100; - CalcTickRate(); - - OPLstopMusic(); - OPLplayMusic(100); - DEBUGOUT("========= New song started ==========\n", 0, 0, 0); - - return 0; + return ret; } //========================================================================== @@ -138,24 +111,8 @@ int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), vo void OPLMIDIDevice::Close() { - if (Stream != NULL) - { - delete Stream; - Stream = NULL; - } + SoftSynthMIDIDevice::Close(); io->OPLdeinit(); - Started = false; -} - -//========================================================================== -// -// OPLMIDIDevice :: IsOpen -// -//========================================================================== - -bool OPLMIDIDevice::IsOpen() const -{ - return Stream != NULL; } //========================================================================== @@ -169,34 +126,6 @@ int OPLMIDIDevice::GetTechnology() const return MOD_FMSYNTH; } -//========================================================================== -// -// OPLMIDIDevice :: SetTempo -// -//========================================================================== - -int OPLMIDIDevice::SetTempo(int tempo) -{ - Tempo = tempo; - CalcTickRate(); - DEBUGOUT("Tempo changed to %.0f, %.2f samples/tick\n", Tempo, SamplesPerTick, 0); - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: SetTimeDiv -// -//========================================================================== - -int OPLMIDIDevice::SetTimeDiv(int timediv) -{ - Division = timediv; - CalcTickRate(); - DEBUGOUT("Division changed to %.0f, %.2f samples/tick\n", Division, SamplesPerTick, 0); - return 0; -} - //========================================================================== // // OPLMIDIDevice :: CalcTickRate @@ -208,219 +137,22 @@ int OPLMIDIDevice::SetTimeDiv(int timediv) void OPLMIDIDevice::CalcTickRate() { - SamplesPerTick = OPL_SAMPLE_RATE / (1000000.0 / Tempo) / Division; - io->SetClockRate(SamplesPerTick); -} - -//========================================================================== -// -// OPLMIDIDevice :: Resume -// -//========================================================================== - -int OPLMIDIDevice::Resume() -{ - if (!Started) - { - if (Stream->Play(true, 1)) - { - Started = true; - return 0; - } - return 1; - } - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: Stop -// -//========================================================================== - -void OPLMIDIDevice::Stop() -{ - if (Started) - { - Stream->Stop(); - Started = false; - } -} - -//========================================================================== -// -// OPLMIDIDevice :: StreamOutSync -// -// This version is called from the main game thread and needs to -// synchronize with the player thread. -// -//========================================================================== - -int OPLMIDIDevice::StreamOutSync(MIDIHDR *header) -{ - ChipAccess.Enter(); - StreamOut(header); - ChipAccess.Leave(); - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: StreamOut -// -// This version is called from the player thread so does not need to -// arbitrate for access to the Events pointer. -// -//========================================================================== - -int OPLMIDIDevice::StreamOut(MIDIHDR *header) -{ - header->lpNext = NULL; - if (Events == NULL) - { - Events = header; - NextTickIn = SamplesPerTick * *(DWORD *)header->lpData; - Position = 0; - } - else - { - MIDIHDR **p; - - for (p = &Events; *p != NULL; p = &(*p)->lpNext) - { } - *p = header; - } - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: PrepareHeader -// -//========================================================================== - -int OPLMIDIDevice::PrepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: UnprepareHeader -// -//========================================================================== - -int OPLMIDIDevice::UnprepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: FakeVolume -// -// Since the OPL output is rendered as a normal stream, its volume is -// controlled through the GSnd interface, not here. -// -//========================================================================== - -bool OPLMIDIDevice::FakeVolume() -{ - return false; -} - -//========================================================================== -// -// OPLMIDIDevice :: NeedThreadedCallabck -// -// OPL can service the callback directly rather than using a separate -// thread. -// -//========================================================================== - -bool OPLMIDIDevice::NeedThreadedCallback() -{ - return false; -} - -//========================================================================== -// -// OPLMIDIDevice :: Pause -// -//========================================================================== - -bool OPLMIDIDevice::Pause(bool paused) -{ - if (Stream != NULL) - { - return Stream->SetPaused(paused); - } - return true; + SoftSynthMIDIDevice::CalcTickRate(); + io->SetClockRate(OPLmusicBlock::SamplesPerTick = SoftSynthMIDIDevice::SamplesPerTick); } //========================================================================== // // OPLMIDIDevice :: PlayTick // -// event[0] = delta time -// event[1] = unused -// event[2] = event +// We derive from two base classes that both define PlayTick(), so we need +// to be unambiguous about which one to use. // //========================================================================== int OPLMIDIDevice::PlayTick() { - DWORD delay = 0; - - while (delay == 0 && Events != NULL) - { - DWORD *event = (DWORD *)(Events->lpData + Position); - if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) - { - SetTempo(MEVT_EVENTPARM(event[2])); - } - else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) - { // Should I handle master volume changes? - } - else if (MEVT_EVENTTYPE(event[2]) == 0) - { // Short MIDI event - int status = event[2] & 0xff; - int parm1 = (event[2] >> 8) & 0x7f; - int parm2 = (event[2] >> 16) & 0x7f; - HandleEvent(status, parm1, parm2); - } - - // Advance to next event. - if (event[2] < 0x80000000) - { // Short message - Position += 12; - } - else - { // Long message - Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); - } - - // Did we use up this buffer? - if (Position >= Events->dwBytesRecorded) - { - Events = Events->lpNext; - Position = 0; - - if (Callback != NULL) - { - Callback(MOM_DONE, CallbackData, 0, 0); - } - } - - if (Events == NULL) - { // No more events. Just return something to keep the song playing - // while we wait for more to be submitted. - return int(Division); - } - - delay = *(DWORD *)(Events->lpData + Position); - } - return delay; + return SoftSynthMIDIDevice::PlayTick(); } //========================================================================== @@ -508,14 +240,35 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) //========================================================================== // -// OPLMIDIDevice :: FillStream static +// OPLMIDIDevice :: HandleLongEvent // //========================================================================== -bool OPLMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +void OPLMIDIDevice::HandleLongEvent(const BYTE *data, int len) { - OPLMIDIDevice *device = (OPLMIDIDevice *)userdata; - return device->ServiceStream(buff, len); +} + +//========================================================================== +// +// OPLMIDIDevice :: ComputeOutput +// +// We override ServiceStream, so this function is never actually called. +// +//========================================================================== + +void OPLMIDIDevice::ComputeOutput(float *buffer, int len) +{ +} + +//========================================================================== +// +// OPLMIDIDevice :: ServiceStream +// +//========================================================================== + +bool OPLMIDIDevice::ServiceStream(void *buff, int numbytes) +{ + return OPLmusicBlock::ServiceStream(buff, numbytes); } //========================================================================== diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 859422387..60a87ea67 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -810,7 +810,7 @@ CCMD (writeopl) } else { - Printf ("Usage: writeopl "); + Printf ("Usage: writeopl \n"); } } diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 2f7a83b22..334002963 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -139,14 +139,14 @@ protected: }; #endif -// OPL implementation of a MIDI output device ------------------------------- +// Base class for software synthesizer MIDI output devices ------------------ -class OPLMIDIDevice : public MIDIDevice, protected OPLmusicBlock +class SoftSynthMIDIDevice : public MIDIDevice { public: - OPLMIDIDevice(); - ~OPLMIDIDevice(); - int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + SoftSynthMIDIDevice(); + ~SoftSynthMIDIDevice(); + void Close(); bool IsOpen() const; int GetTechnology() const; @@ -161,24 +161,51 @@ public: bool FakeVolume(); bool NeedThreadedCallback(); bool Pause(bool paused); - FString GetStats(); protected: - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); + FCriticalSection CritSec; + SoundStream *Stream; + double Tempo; + double Division; + double SamplesPerTick; + double NextTickIn; + MIDIHDR *Events; + bool Started; + DWORD Position; + int SampleRate; void (*Callback)(unsigned int, void *, DWORD, DWORD); void *CallbackData; - void CalcTickRate(); - void HandleEvent(int status, int parm1, int parm2); + virtual void CalcTickRate(); int PlayTick(); + int OpenStream(int chunks, int flags, void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); + virtual bool ServiceStream (void *buff, int numbytes); - SoundStream *Stream; - double Tempo; - double Division; - MIDIHDR *Events; - bool Started; - DWORD Position; + virtual void HandleEvent(int status, int parm1, int parm2) = 0; + virtual void HandleLongEvent(const BYTE *data, int len) = 0; + virtual void ComputeOutput(float *buffer, int len) = 0; +}; + +// OPL implementation of a MIDI output device ------------------------------- + +class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock +{ +public: + OPLMIDIDevice(); + int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); + void Close(); + int GetTechnology() const; + FString GetStats(); + +protected: + void CalcTickRate(); + int PlayTick(); + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const BYTE *data, int len); + void ComputeOutput(float *buffer, int len); + bool ServiceStream(void *buff, int numbytes); }; // OPL dumper implementation of a MIDI output device ------------------------ @@ -196,52 +223,22 @@ public: namespace Timidity { struct Renderer; } -class TimidityMIDIDevice : public MIDIDevice +class TimidityMIDIDevice : public SoftSynthMIDIDevice { public: TimidityMIDIDevice(); - TimidityMIDIDevice(int rate); ~TimidityMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); - void Close(); - bool IsOpen() const; - int GetTechnology() const; - int SetTempo(int tempo); - int SetTimeDiv(int timediv); - int StreamOut(MIDIHDR *data); - int StreamOutSync(MIDIHDR *data); - int Resume(); - void Stop(); - int PrepareHeader(MIDIHDR *data); - int UnprepareHeader(MIDIHDR *data); - bool FakeVolume(); - bool Pause(bool paused); - bool NeedThreadedCallback(); void PrecacheInstruments(const WORD *instruments, int count); - void TimidityVolumeChanged(); FString GetStats(); protected: - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); - bool ServiceStream (void *buff, int numbytes); - - void (*Callback)(unsigned int, void *, DWORD, DWORD); - void *CallbackData; - - void CalcTickRate(); - int PlayTick(); - - FCriticalSection CritSec; - SoundStream *Stream; Timidity::Renderer *Renderer; - double Tempo; - double Division; - double SamplesPerTick; - double NextTickIn; - MIDIHDR *Events; - bool Started; - DWORD Position; + + void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const BYTE *data, int len); + void ComputeOutput(float *buffer, int len); }; // Internal TiMidity disk writing version of a MIDI device ------------------ @@ -268,57 +265,26 @@ struct fluid_settings_t; struct fluid_synth_t; #endif -class FluidSynthMIDIDevice : public MIDIDevice +class FluidSynthMIDIDevice : public SoftSynthMIDIDevice { public: FluidSynthMIDIDevice(); ~FluidSynthMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); - void Close(); - bool IsOpen() const; - int GetTechnology() const; - int SetTempo(int tempo); - int SetTimeDiv(int timediv); - int StreamOut(MIDIHDR *data); - int StreamOutSync(MIDIHDR *data); - int Resume(); - void Stop(); - int PrepareHeader(MIDIHDR *data); - int UnprepareHeader(MIDIHDR *data); - bool FakeVolume(); - bool Pause(bool paused); - bool NeedThreadedCallback(); - void PrecacheInstruments(const WORD *instruments, int count); FString GetStats(); void FluidSettingInt(const char *setting, int value); void FluidSettingNum(const char *setting, double value); void FluidSettingStr(const char *setting, const char *value); protected: - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); - bool ServiceStream(void *buff, int numbytes); void HandleEvent(int status, int parm1, int parm2); + void HandleLongEvent(const BYTE *data, int len); + void ComputeOutput(float *buffer, int len); int LoadPatchSets(const char *patches); - void (*Callback)(unsigned int, void *, DWORD, DWORD); - void *CallbackData; - - void CalcTickRate(); - int PlayTick(); - - FCriticalSection CritSec; - SoundStream *Stream; fluid_settings_t *FluidSettings; fluid_synth_t *FluidSynth; - double Tempo; - double Division; - double SamplesPerTick; - double NextTickIn; - MIDIHDR *Events; - bool Started; - DWORD Position; - int SampleRate; #ifdef DYN_FLUIDSYNTH enum { FLUID_FAILED = 1, FLUID_OK = 0 }; @@ -347,6 +313,7 @@ protected: int (STACK_ARGS *fluid_synth_sfload)(fluid_synth_t *, const char *, int); void (STACK_ARGS *fluid_synth_set_reverb)(fluid_synth_t *, double, double, double, double); void (STACK_ARGS *fluid_synth_set_chorus)(fluid_synth_t *, int, double, double, double, int); + int (STACK_ARGS *fluid_synth_sysex)(fluid_synth_t *, const char *, int, char *, int *, int *, int); #ifdef _WIN32 HMODULE FluidSynthDLL; diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 32cd0da46..1e88af055 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -59,18 +59,18 @@ #define FLUIDSYNTHLIB "libfluidsynth.so.1" #endif -#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f -#define FLUID_REVERB_DEFAULT_DAMP 0.0f -#define FLUID_REVERB_DEFAULT_WIDTH 0.5f -#define FLUID_REVERB_DEFAULT_LEVEL 0.9f +#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f +#define FLUID_REVERB_DEFAULT_DAMP 0.0f +#define FLUID_REVERB_DEFAULT_WIDTH 0.5f +#define FLUID_REVERB_DEFAULT_LEVEL 0.9f #define FLUID_CHORUS_MOD_SINE 0 #define FLUID_CHORUS_MOD_TRIANGLE 1 -#define FLUID_CHORUS_DEFAULT_N 3 -#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f -#define FLUID_CHORUS_DEFAULT_SPEED 0.3f -#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f +#define FLUID_CHORUS_DEFAULT_N 3 +#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f +#define FLUID_CHORUS_DEFAULT_SPEED 0.3f +#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f #define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE #endif @@ -254,11 +254,6 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR FluidSynthMIDIDevice::FluidSynthMIDIDevice() { - Stream = NULL; - Tempo = 0; - Division = 0; - Events = NULL; - Started = false; FluidSynth = NULL; FluidSettings = NULL; #ifdef DYN_FLUIDSYNTH @@ -366,266 +361,12 @@ int FluidSynthMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO { return 2; } - Stream = GSnd->CreateStream(FillStream, (SampleRate / 4) * 4, - SoundStream::Float, SampleRate, this); - if (Stream == NULL) + int ret = OpenStream(4, 0, callback, userdata); + if (ret == 0) { - return 2; + fluid_synth_system_reset(FluidSynth); } - - fluid_synth_system_reset(FluidSynth); - Callback = callback; - CallbackData = userdata; - Tempo = 500000; - Division = 100; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: Close -// -//========================================================================== - -void FluidSynthMIDIDevice::Close() -{ - if (Stream != NULL) - { - delete Stream; - Stream = NULL; - } - Started = false; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: IsOpen -// -//========================================================================== - -bool FluidSynthMIDIDevice::IsOpen() const -{ - return Stream != NULL; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: GetTechnology -// -//========================================================================== - -int FluidSynthMIDIDevice::GetTechnology() const -{ - return MOD_SWSYNTH; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: SetTempo -// -//========================================================================== - -int FluidSynthMIDIDevice::SetTempo(int tempo) -{ - Tempo = tempo; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: SetTimeDiv -// -//========================================================================== - -int FluidSynthMIDIDevice::SetTimeDiv(int timediv) -{ - Division = timediv; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: CalcTickRate -// -// Tempo is the number of microseconds per quarter note. -// Division is the number of ticks per quarter note. -// -//========================================================================== - -void FluidSynthMIDIDevice::CalcTickRate() -{ - SamplesPerTick = SampleRate / (1000000.0 / Tempo) / Division; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: Resume -// -//========================================================================== - -int FluidSynthMIDIDevice::Resume() -{ - if (!Started) - { - if (Stream->Play(true, 1)) - { - Started = true; - return 0; - } - return 1; - } - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: Stop -// -//========================================================================== - -void FluidSynthMIDIDevice::Stop() -{ - if (Started) - { - Stream->Stop(); - Started = false; - } -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: StreamOutSync -// -// This version is called from the main game thread and needs to -// synchronize with the player thread. -// -//========================================================================== - -int FluidSynthMIDIDevice::StreamOutSync(MIDIHDR *header) -{ - CritSec.Enter(); - StreamOut(header); - CritSec.Leave(); - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: StreamOut -// -// This version is called from the player thread so does not need to -// arbitrate for access to the Events pointer. -// -//========================================================================== - -int FluidSynthMIDIDevice::StreamOut(MIDIHDR *header) -{ - header->lpNext = NULL; - if (Events == NULL) - { - Events = header; - NextTickIn = SamplesPerTick * *(DWORD *)header->lpData; - Position = 0; - } - else - { - MIDIHDR **p; - - for (p = &Events; *p != NULL; p = &(*p)->lpNext) - { } - *p = header; - } - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: PrepareHeader -// -//========================================================================== - -int FluidSynthMIDIDevice::PrepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: UnprepareHeader -// -//========================================================================== - -int FluidSynthMIDIDevice::UnprepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: FakeVolume -// -// Since the FluidSynth output is rendered as a normal stream, its volume is -// controlled through the GSnd interface, not here. -// -//========================================================================== - -bool FluidSynthMIDIDevice::FakeVolume() -{ - return false; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: NeedThreadedCallabck -// -// FluidSynth can service the callback directly rather than using a separate -// thread. -// -//========================================================================== - -bool FluidSynthMIDIDevice::NeedThreadedCallback() -{ - return false; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: Pause -// -//========================================================================== - -bool FluidSynthMIDIDevice::Pause(bool paused) -{ - if (Stream != NULL) - { - return Stream->SetPaused(paused); - } - return true; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: PrecacheInstruments -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -//========================================================================== - -void FluidSynthMIDIDevice::PrecacheInstruments(const WORD *instruments, int count) -{ -#if 0 - for (int i = 0; i < count; ++i) - { - Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); - } - Renderer->load_missing_instruments(); -#endif + return ret; } //========================================================================== @@ -674,136 +415,31 @@ void FluidSynthMIDIDevice::HandleEvent(int status, int parm1, int parm2) //========================================================================== // -// FluidSynthMIDIDevice :: PlayTick +// FluidSynthMIDIDevice :: HandleLongEvent // -// event[0] = delta time -// event[1] = unused -// event[2] = event +// Handle SysEx messages. // //========================================================================== -int FluidSynthMIDIDevice::PlayTick() +void FluidSynthMIDIDevice::HandleLongEvent(const BYTE *data, int len) { - DWORD delay = 0; - - while (delay == 0 && Events != NULL) + if (len > 1 && (data[0] == 0xF0 || data[0] == 0xF7)) { - DWORD *event = (DWORD *)(Events->lpData + Position); - if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) - { - SetTempo(MEVT_EVENTPARM(event[2])); - } - else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) - { -#if 0 - Renderer->HandleLongMessage((BYTE *)&event[3], MEVT_EVENTPARM(event[2])); -#endif - } - else if (MEVT_EVENTTYPE(event[2]) == 0) - { // Short MIDI event - int status = event[2] & 0xff; - int parm1 = (event[2] >> 8) & 0x7f; - int parm2 = (event[2] >> 16) & 0x7f; - HandleEvent(status, parm1, parm2); - } - - // Advance to next event. - if (event[2] < 0x80000000) - { // Short message - Position += 12; - } - else - { // Long message - Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); - } - - // Did we use up this buffer? - if (Position >= Events->dwBytesRecorded) - { - Events = Events->lpNext; - Position = 0; - - if (Callback != NULL) - { - Callback(MOM_DONE, CallbackData, 0, 0); - } - } - - if (Events == NULL) - { // No more events. Just return something to keep the song playing - // while we wait for more to be submitted. - return int(Division); - } - - delay = *(DWORD *)(Events->lpData + Position); + fluid_synth_sysex(FluidSynth, (const char *)data + 1, len - 1, NULL, NULL, NULL, 0); } - return delay; } //========================================================================== // -// FluidSynthtMIDIDevice :: ServiceStream +// FluidSynthMIDIDevice :: ComputeOutput // //========================================================================== -bool FluidSynthMIDIDevice::ServiceStream (void *buff, int numbytes) +void FluidSynthMIDIDevice::ComputeOutput(float *buffer, int len) { - float *samples = (float *)buff; - float *samples1; - int numsamples = numbytes / sizeof(float) / 2; - bool prev_ended = false; - bool res = true; - - samples1 = samples; - memset(buff, 0, numbytes); - - CritSec.Enter(); - while (Events != NULL && numsamples > 0) - { - double ticky = NextTickIn; - int tick_in = int(NextTickIn); - int samplesleft = MIN(numsamples, tick_in); - - if (samplesleft > 0) - { - fluid_synth_write_float(FluidSynth, samplesleft, - samples1, 0, 2, - samples1, 1, 2); - assert(NextTickIn == ticky); - NextTickIn -= samplesleft; - assert(NextTickIn >= 0); - numsamples -= samplesleft; - samples1 += samplesleft * 2; - } - - if (NextTickIn < 1) - { - int next = PlayTick(); - assert(next >= 0); - if (next == 0) - { // end of song - if (numsamples > 0) - { - fluid_synth_write_float(FluidSynth, numsamples, - samples1, 0, 2, - samples1, 1, 2); - } - res = false; - break; - } - else - { - NextTickIn += SamplesPerTick * next; - assert(NextTickIn >= 0); - } - } - } - if (Events == NULL) - { - res = false; - } - CritSec.Leave(); - return res; + fluid_synth_write_float(FluidSynth, len, + buffer, 0, 2, + buffer, 1, 2); } //========================================================================== @@ -933,18 +569,6 @@ void FluidSynthMIDIDevice::FluidSettingStr(const char *setting, const char *valu } } -//========================================================================== -// -// FluidSynthMIDIDevice :: FillStream static -// -//========================================================================== - -bool FluidSynthMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) -{ - FluidSynthMIDIDevice *device = (FluidSynthMIDIDevice *)userdata; - return device->ServiceStream(buff, len); -} - //========================================================================== // // FluidSynthMIDIDevice :: GetStats @@ -1023,6 +647,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() { (void **)&fluid_synth_sfload, "fluid_synth_sfload" }, { (void **)&fluid_synth_set_reverb, "fluid_synth_set_reverb" }, { (void **)&fluid_synth_set_chorus, "fluid_synth_set_chorus" }, + { (void **)&fluid_synth_sysex, "fluid_synth_sysex" }, }; int fail = 0; diff --git a/src/sound/music_softsynth_mididevice.cpp b/src/sound/music_softsynth_mididevice.cpp new file mode 100644 index 000000000..9d2e69298 --- /dev/null +++ b/src/sound/music_softsynth_mididevice.cpp @@ -0,0 +1,498 @@ +/* +** music_softsynth_mididevice.cpp +** Common base clase for software synthesis MIDI devices. +** +**--------------------------------------------------------------------------- +** Copyright 2008-2010 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "i_musicinterns.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "w_wad.h" +#include "v_text.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR(Bool, synth_watch, false, 0) + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// SoftSynthMIDIDevice Constructor +// +//========================================================================== + +SoftSynthMIDIDevice::SoftSynthMIDIDevice() +{ + Stream = NULL; + Tempo = 0; + Division = 0; + Events = NULL; + Started = false; + SampleRate = GSnd != NULL ? (int)GSnd->GetOutputRate() : 44100; +} + +//========================================================================== +// +// SoftSynthMIDIDevice Destructor +// +//========================================================================== + +SoftSynthMIDIDevice::~SoftSynthMIDIDevice() +{ + Close(); +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: OpenStream +// +//========================================================================== + +int SoftSynthMIDIDevice::OpenStream(int chunks, int flags, void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +{ + Stream = GSnd->CreateStream(FillStream, (SampleRate / chunks) * 4, SoundStream::Float | flags, SampleRate, this); + if (Stream == NULL) + { + return 2; + } + + Callback = callback; + CallbackData = userdata; + Tempo = 500000; + Division = 100; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: Close +// +//========================================================================== + +void SoftSynthMIDIDevice::Close() +{ + if (Stream != NULL) + { + delete Stream; + Stream = NULL; + } + Started = false; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: IsOpen +// +//========================================================================== + +bool SoftSynthMIDIDevice::IsOpen() const +{ + return Stream != NULL; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: GetTechnology +// +//========================================================================== + +int SoftSynthMIDIDevice::GetTechnology() const +{ + return MOD_SWSYNTH; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: SetTempo +// +//========================================================================== + +int SoftSynthMIDIDevice::SetTempo(int tempo) +{ + Tempo = tempo; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: SetTimeDiv +// +//========================================================================== + +int SoftSynthMIDIDevice::SetTimeDiv(int timediv) +{ + Division = timediv; + CalcTickRate(); + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: CalcTickRate +// +// Tempo is the number of microseconds per quarter note. +// Division is the number of ticks per quarter note. +// +//========================================================================== + +void SoftSynthMIDIDevice::CalcTickRate() +{ + SamplesPerTick = SampleRate / (1000000.0 / Tempo) / Division; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: Resume +// +//========================================================================== + +int SoftSynthMIDIDevice::Resume() +{ + if (!Started) + { + if (Stream->Play(true, 1)) + { + Started = true; + return 0; + } + return 1; + } + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: Stop +// +//========================================================================== + +void SoftSynthMIDIDevice::Stop() +{ + if (Started) + { + Stream->Stop(); + Started = false; + } +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: StreamOutSync +// +// This version is called from the main game thread and needs to +// synchronize with the player thread. +// +//========================================================================== + +int SoftSynthMIDIDevice::StreamOutSync(MIDIHDR *header) +{ + CritSec.Enter(); + StreamOut(header); + CritSec.Leave(); + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: StreamOut +// +// This version is called from the player thread so does not need to +// arbitrate for access to the Events pointer. +// +//========================================================================== + +int SoftSynthMIDIDevice::StreamOut(MIDIHDR *header) +{ + header->lpNext = NULL; + if (Events == NULL) + { + Events = header; + NextTickIn = SamplesPerTick * *(DWORD *)header->lpData; + Position = 0; + } + else + { + MIDIHDR **p; + + for (p = &Events; *p != NULL; p = &(*p)->lpNext) + { } + *p = header; + } + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: PrepareHeader +// +//========================================================================== + +int SoftSynthMIDIDevice::PrepareHeader(MIDIHDR *header) +{ + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: UnprepareHeader +// +//========================================================================== + +int SoftSynthMIDIDevice::UnprepareHeader(MIDIHDR *header) +{ + return 0; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: FakeVolume +// +// Since the softsynth output is rendered as a normal stream, its volume is +// controlled through the GSnd interface, not here. +// +//========================================================================== + +bool SoftSynthMIDIDevice::FakeVolume() +{ + return false; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: NeedThreadedCallabck +// +// We can service the callback directly rather than using a separate +// thread. +// +//========================================================================== + +bool SoftSynthMIDIDevice::NeedThreadedCallback() +{ + return false; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: Pause +// +//========================================================================== + +bool SoftSynthMIDIDevice::Pause(bool paused) +{ + if (Stream != NULL) + { + return Stream->SetPaused(paused); + } + return true; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: PlayTick +// +// event[0] = delta time +// event[1] = unused +// event[2] = event +// +//========================================================================== + +int SoftSynthMIDIDevice::PlayTick() +{ + DWORD delay = 0; + + while (delay == 0 && Events != NULL) + { + DWORD *event = (DWORD *)(Events->lpData + Position); + if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) + { + SetTempo(MEVT_EVENTPARM(event[2])); + } + else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) + { + HandleLongEvent((BYTE *)&event[3], MEVT_EVENTPARM(event[2])); + } + else if (MEVT_EVENTTYPE(event[2]) == 0) + { // Short MIDI event + int status = event[2] & 0xff; + int parm1 = (event[2] >> 8) & 0x7f; + int parm2 = (event[2] >> 16) & 0x7f; + HandleEvent(status, parm1, parm2); + + if (synth_watch) + { + static const char *const commands[8] = + { + "Note off", + "Note on", + "Poly press", + "Ctrl change", + "Prgm change", + "Chan press", + "Pitch bend", + "SysEx" + }; + char buffer[128]; + mysnprintf(buffer, countof(buffer), "C%02d: %11s %3d %3d\n", (status & 15) + 1, commands[(status >> 4) & 7], parm1, parm2); +#ifdef _WIN32 + OutputDebugString(buffer); +#else + fputs(buffer, stderr); +#endif + } + } + + // Advance to next event. + if (event[2] < 0x80000000) + { // Short message + Position += 12; + } + else + { // Long message + Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); + } + + // Did we use up this buffer? + if (Position >= Events->dwBytesRecorded) + { + Events = Events->lpNext; + Position = 0; + + if (Callback != NULL) + { + Callback(MOM_DONE, CallbackData, 0, 0); + } + } + + if (Events == NULL) + { // No more events. Just return something to keep the song playing + // while we wait for more to be submitted. + return int(Division); + } + + delay = *(DWORD *)(Events->lpData + Position); + } + return delay; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: ServiceStream +// +//========================================================================== + +bool SoftSynthMIDIDevice::ServiceStream (void *buff, int numbytes) +{ + float *samples = (float *)buff; + float *samples1; + int numsamples = numbytes / sizeof(float) / 2; + bool prev_ended = false; + bool res = true; + + samples1 = samples; + memset(buff, 0, numbytes); + + CritSec.Enter(); + while (Events != NULL && numsamples > 0) + { + double ticky = NextTickIn; + int tick_in = int(NextTickIn); + int samplesleft = MIN(numsamples, tick_in); + + if (samplesleft > 0) + { + ComputeOutput(samples1, samplesleft); + assert(NextTickIn == ticky); + NextTickIn -= samplesleft; + assert(NextTickIn >= 0); + numsamples -= samplesleft; + samples1 += samplesleft * 2; + } + + if (NextTickIn < 1) + { + int next = PlayTick(); + assert(next >= 0); + if (next == 0) + { // end of song + if (numsamples > 0) + { + ComputeOutput(samples1, numsamples); + } + res = false; + break; + } + else + { + NextTickIn += SamplesPerTick * next; + assert(NextTickIn >= 0); + } + } + } + + if (Events == NULL) + { + res = false; + } + CritSec.Leave(); + return res; +} + +//========================================================================== +// +// SoftSynthMIDIDevice :: FillStream static +// +//========================================================================== + +bool SoftSynthMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +{ + SoftSynthMIDIDevice *device = (SoftSynthMIDIDevice *)userdata; + return device->ServiceStream(buff, len); +} diff --git a/src/sound/music_timidity_mididevice.cpp b/src/sound/music_timidity_mididevice.cpp index a13f46e61..9e5be625b 100644 --- a/src/sound/music_timidity_mididevice.cpp +++ b/src/sound/music_timidity_mididevice.cpp @@ -78,8 +78,6 @@ struct FmtChunk // PUBLIC DATA DEFINITIONS ------------------------------------------------- -CVAR(Bool, timidity_watch, false, 0) - // CODE -------------------------------------------------------------------- //========================================================================== @@ -90,33 +88,8 @@ CVAR(Bool, timidity_watch, false, 0) TimidityMIDIDevice::TimidityMIDIDevice() { - Stream = NULL; - Tempo = 0; - Division = 0; - Events = NULL; - Started = false; Renderer = NULL; - Renderer = new Timidity::Renderer(GSnd->GetOutputRate()); -} - -//========================================================================== -// -// TimidityMIDIDevice Constructor with rate parameter -// -//========================================================================== - -TimidityMIDIDevice::TimidityMIDIDevice(int rate) -{ - // Need to support multiple instances with different playback rates - // before we can use this parameter. - rate = (int)GSnd->GetOutputRate(); - Stream = NULL; - Tempo = 0; - Division = 0; - Events = NULL; - Started = false; - Renderer = NULL; - Renderer = new Timidity::Renderer((float)rate); + Renderer = new Timidity::Renderer((float)SampleRate); } //========================================================================== @@ -144,261 +117,12 @@ TimidityMIDIDevice::~TimidityMIDIDevice() int TimidityMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { - Stream = GSnd->CreateStream(FillStream, int(Renderer->rate / 2) * 4, - SoundStream::Float, int(Renderer->rate), this); - if (Stream == NULL) + int ret = OpenStream(2, 0, callback, userdata); + if (ret == 0) { - return 2; + Renderer->Reset(); } - - Callback = callback; - CallbackData = userdata; - Tempo = 500000; - Division = 100; - CalcTickRate(); - Renderer->Reset(); - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: Close -// -//========================================================================== - -void TimidityMIDIDevice::Close() -{ - if (Stream != NULL) - { - delete Stream; - Stream = NULL; - } - Started = false; -} - -//========================================================================== -// -// TimidityMIDIDevice :: IsOpen -// -//========================================================================== - -bool TimidityMIDIDevice::IsOpen() const -{ - return Stream != NULL; -} - -//========================================================================== -// -// TimidityMIDIDevice :: GetTechnology -// -//========================================================================== - -int TimidityMIDIDevice::GetTechnology() const -{ - return MOD_SWSYNTH; -} - -//========================================================================== -// -// TimidityMIDIDevice :: SetTempo -// -//========================================================================== - -int TimidityMIDIDevice::SetTempo(int tempo) -{ - Tempo = tempo; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: SetTimeDiv -// -//========================================================================== - -int TimidityMIDIDevice::SetTimeDiv(int timediv) -{ - Division = timediv; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: CalcTickRate -// -// Tempo is the number of microseconds per quarter note. -// Division is the number of ticks per quarter note. -// -//========================================================================== - -void TimidityMIDIDevice::CalcTickRate() -{ - SamplesPerTick = Renderer->rate / (1000000.0 / Tempo) / Division; -} - -//========================================================================== -// -// TimidityMIDIDevice :: Resume -// -//========================================================================== - -int TimidityMIDIDevice::Resume() -{ - if (!Started) - { - if (Stream->Play(true, 1/*timidity_mastervolume*/)) - { - Started = true; - return 0; - } - return 1; - } - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: Stop -// -//========================================================================== - -void TimidityMIDIDevice::Stop() -{ - if (Started) - { - Stream->Stop(); - Started = false; - } -} - -//========================================================================== -// -// TimidityMIDIDevice :: StreamOutSync -// -// This version is called from the main game thread and needs to -// synchronize with the player thread. -// -//========================================================================== - -int TimidityMIDIDevice::StreamOutSync(MIDIHDR *header) -{ - CritSec.Enter(); - StreamOut(header); - CritSec.Leave(); - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: StreamOut -// -// This version is called from the player thread so does not need to -// arbitrate for access to the Events pointer. -// -//========================================================================== - -int TimidityMIDIDevice::StreamOut(MIDIHDR *header) -{ - header->lpNext = NULL; - if (Events == NULL) - { - Events = header; - NextTickIn = SamplesPerTick * *(DWORD *)header->lpData; - Position = 0; - } - else - { - MIDIHDR **p; - - for (p = &Events; *p != NULL; p = &(*p)->lpNext) - { } - *p = header; - } - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: PrepareHeader -// -//========================================================================== - -int TimidityMIDIDevice::PrepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: UnprepareHeader -// -//========================================================================== - -int TimidityMIDIDevice::UnprepareHeader(MIDIHDR *header) -{ - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: FakeVolume -// -// Since the TiMidity output is rendered as a normal stream, its volume is -// controlled through the GSnd interface, not here. -// -//========================================================================== - -bool TimidityMIDIDevice::FakeVolume() -{ - return false; -} - -//========================================================================== -// -// TimidityMIDIDevice :: NeedThreadedCallabck -// -// OPL can service the callback directly rather than using a separate -// thread. -// -//========================================================================== - -bool TimidityMIDIDevice::NeedThreadedCallback() -{ - return false; -} - - -//========================================================================== -// -// TimidityMIDIDevice :: TimidityVolumeChanged -// -//========================================================================== - -void TimidityMIDIDevice::TimidityVolumeChanged() -{ - /* - if (Stream != NULL) - { - Stream->SetVolume(timidity_mastervolume); - } - */ -} - -//========================================================================== -// -// TimidityMIDIDevice :: Pause -// -//========================================================================== - -bool TimidityMIDIDevice::Pause(bool paused) -{ - if (Stream != NULL) - { - return Stream->SetPaused(paused); - } - return true; + return ret; } //========================================================================== @@ -423,164 +147,35 @@ void TimidityMIDIDevice::PrecacheInstruments(const WORD *instruments, int count) //========================================================================== // -// TimidityMIDIDevice :: PlayTick -// -// event[0] = delta time -// event[1] = unused -// event[2] = event +// TimidityMIDIDevice :: HandleEvent // //========================================================================== -int TimidityMIDIDevice::PlayTick() +void TimidityMIDIDevice::HandleEvent(int status, int parm1, int parm2) { - DWORD delay = 0; - - while (delay == 0 && Events != NULL) - { - DWORD *event = (DWORD *)(Events->lpData + Position); - if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) - { - SetTempo(MEVT_EVENTPARM(event[2])); - } - else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) - { - Renderer->HandleLongMessage((BYTE *)&event[3], MEVT_EVENTPARM(event[2])); - } - else if (MEVT_EVENTTYPE(event[2]) == 0) - { // Short MIDI event - int status = event[2] & 0xff; - int parm1 = (event[2] >> 8) & 0x7f; - int parm2 = (event[2] >> 16) & 0x7f; - Renderer->HandleEvent(status, parm1, parm2); - - if (timidity_watch) - { - static const char *const commands[8] = - { - "Note off", - "Note on", - "Poly press", - "Ctrl change", - "Prgm change", - "Chan press", - "Pitch bend", - "SysEx" - }; -#ifdef _WIN32 - char buffer[128]; - mysnprintf(buffer, countof(buffer), "C%02d: %11s %3d %3d\n", (status & 15) + 1, commands[(status >> 4) & 7], parm1, parm2); - OutputDebugString(buffer); -#else - //fprintf(stderr, "C%02d: %11s %3d %3d\n", (status & 15) + 1, commands[(status >> 4) & 7], parm1, parm2); -#endif - } - } - - // Advance to next event. - if (event[2] < 0x80000000) - { // Short message - Position += 12; - } - else - { // Long message - Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); - } - - // Did we use up this buffer? - if (Position >= Events->dwBytesRecorded) - { - Events = Events->lpNext; - Position = 0; - - if (Callback != NULL) - { - Callback(MOM_DONE, CallbackData, 0, 0); - } - } - - if (Events == NULL) - { // No more events. Just return something to keep the song playing - // while we wait for more to be submitted. - return int(Division); - } - - delay = *(DWORD *)(Events->lpData + Position); - } - return delay; + Renderer->HandleEvent(status, parm1, parm2); } //========================================================================== // -// TimidityMIDIDevice :: ServiceStream +// TimidityMIDIDevice :: HandleLongEvent // //========================================================================== -bool TimidityMIDIDevice::ServiceStream (void *buff, int numbytes) +void TimidityMIDIDevice::HandleLongEvent(const BYTE *data, int len) { - float *samples = (float *)buff; - float *samples1; - int numsamples = numbytes / sizeof(float) / 2; - bool prev_ended = false; - bool res = true; - - samples1 = samples; - memset(buff, 0, numbytes); - - CritSec.Enter(); - while (Events != NULL && numsamples > 0) - { - double ticky = NextTickIn; - int tick_in = int(NextTickIn); - int samplesleft = MIN(numsamples, tick_in); - - if (samplesleft > 0) - { - Renderer->ComputeOutput(samples1, samplesleft); - assert(NextTickIn == ticky); - NextTickIn -= samplesleft; - assert(NextTickIn >= 0); - numsamples -= samplesleft; - samples1 += samplesleft * 2; - } - - if (NextTickIn < 1) - { - int next = PlayTick(); - assert(next >= 0); - if (next == 0) - { // end of song - if (numsamples > 0) - { - Renderer->ComputeOutput(samples1, numsamples); - } - res = false; - break; - } - else - { - NextTickIn += SamplesPerTick * next; - assert(NextTickIn >= 0); - } - } - } - if (Events == NULL) - { - res = false; - } - CritSec.Leave(); - return res; + Renderer->HandleLongMessage(data, len); } //========================================================================== // -// TimidityMIDIDevice :: FillStream static +// TimidityMIDIDevice :: ComputeOutput // //========================================================================== -bool TimidityMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) +void TimidityMIDIDevice::ComputeOutput(float *buffer, int len) { - TimidityMIDIDevice *device = (TimidityMIDIDevice *)userdata; - return device->ServiceStream(buff, len); + Renderer->ComputeOutput(buffer, len); } //========================================================================== diff --git a/zdoom.vcproj b/zdoom.vcproj index 3edc5d20e..7885a5174 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -5485,6 +5485,10 @@ RelativePath=".\src\oplsynth\music_opldumper_mididevice.cpp" > + + From b452bec0eef75723406e952ddf304e51e2ea81cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 20 Aug 2010 12:20:51 +0000 Subject: [PATCH 193/251] - merge USDF branch into trunk. - add USDF spexs. SVN r2561 (trunk) --- specs/usdf.txt | 158 ++++++ specs/usdf_zdoom.txt | 56 +++ src/CMakeLists.txt | 1 + src/actionspecials.h | 2 +- src/actor.h | 5 +- src/cmdlib.cpp | 17 + src/cmdlib.h | 1 + src/dobjtype.cpp | 2 + src/farchive.h | 4 + src/g_shared/a_action.cpp | 2 +- src/info.h | 1 + src/namedef.h | 20 + src/p_conversation.cpp | 267 +++++++---- src/p_conversation.h | 38 +- src/p_lnspec.cpp | 32 +- src/p_mobj.cpp | 67 +-- src/p_udmf.cpp | 260 +++++----- src/p_udmf.h | 38 ++ src/p_usdf.cpp | 505 ++++++++++++++++++++ src/p_user.cpp | 10 +- src/thingdef/thingdef_properties.cpp | 10 +- wadsrc/static/actors/strife/strifestuff.txt | 1 - zdoom.vcproj | 4 + 23 files changed, 1227 insertions(+), 274 deletions(-) create mode 100644 specs/usdf.txt create mode 100644 specs/usdf_zdoom.txt create mode 100644 src/p_udmf.h create mode 100644 src/p_usdf.cpp diff --git a/specs/usdf.txt b/specs/usdf.txt new file mode 100644 index 000000000..fc955f02d --- /dev/null +++ b/specs/usdf.txt @@ -0,0 +1,158 @@ +=============================================================================== +Universal Strife Dialog Format Specification v2.0 - 08/20/10 + +Written by Braden "Blzut3" Obrzut - admin@maniacsvault.net + +Defined with input from: + +CodeImp +Gez +Graf Zahl +Quasar +et al. + + Copyright (c) 2010 Braden Obrzut. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + +=============================================================================== + +======================================= +I. Grammar / Syntax +======================================= + +The grammar and syntax is similar to that of UDMF. A compliant UDMF parser +should be applyable to the USDF. However, it will need to be capable of +handling sub-blocks. Unknown sub-blocks should be skipped. + +======================================= +II. Implementation Semantics +======================================= + +------------------------------------ +II.A : Storage and Retrieval of Data +------------------------------------ + +This is the same as in UDMF. + +----------------------------------- +II.B : Storage Within Archive Files +----------------------------------- + +There are two options for the USDF lump placement. This can either be a part +of the UDMF lump list or standalone. If used stand alone the lump name +DIALOGXY is used corresponding with MAPXY. For UDMF the lump shall be called +"DIALOGUE". + +-------------------------------- +II.C : Implementation Dependence +-------------------------------- + +USDF also implements the namespace statement. This has all the same +requirements as UDMF. + +======================================= +III. Standardized Fields +======================================= + +The following are required for all USDF complient implementations. Like UDMF, +any unknown field/function should be ignored and not treated as an error. + +NOTE: "mobj" refers to Strife's conversationIDs and not doom editor numbers or + Hexen's spawnids. A valid mobj value is any positive integer greater + than or equal to 1. + +--------------------- +III.A : Conversations +--------------------- + +Conversations are groups of pages that can be assigned to a particular object. +Implementors should preserve the IDs to allow for dynamic reassignment through +scripting although this is not a requirement. + +conversation // Starts a dialog. +{ + actor = ; // mobj for this conversation's actor. If previously + // used, this will override the previous conversation. + + page // Starts a new page. Pages are automatically numbered starting at 0. + { + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are + // satisified. + + // jumps to the specified page if the player has the specified amount + // or more of item in their inventory. This can be repeated as many + // times as the author wants, all conditions must be met for the + // jump to occur. + ifitem + { + item = ; // mobj of item to check. + amount = ; // amount required to be in inventory. + } + + // Choices shall be automatically numbered. + choice + { + text = ; // Name of the choice. + + // The amount of an item needed to successfully pick this option. + // This can be repeated, but only the first will be shown (provided + // diaplaycost is true). All costs must be satisfied for success. + cost + { + item = ; // Item that is required for this option. + amount = ; // Minimum amount of the item needed. + } + + displaycost = ; // Weather the cost should be + // displayed with the option. + // If no cost is specified this should + // be ignored. + yesmessage = ; // Text to add to console when choice + // is accepted. + nomessage = ; // Text to add to console when choice + // is denied. + + log = ; // LOG entry to use on success. + giveitem = ; // Gives the specified item upon + // success. + // The following are the same as the special for linedefs in UDMF. + // They are executed on success. + special = ; + arg0 = ; + arg1 = ; + arg2 = ; + arg3 = ; + arg4 = ; + + nextpage = ; // Sets the next page. + closedialog = ; // Should the dialog be closed upon + // selecting this choice? + // Default: false + } + } +} + +------------------------------- +III.B : Including Other Dialogs +------------------------------- + +Unlike the original Strife dialog format. The lump "SCRIPT00" should not be +included automatically. Instead the user must specify this behavior by using +the include function, which takes the name of a lump to include. Include only +needs to be available in the global scope and for compatibility reasons, must +include the result of the script and not act like a preprocessor statement. + +include = ; + +=============================================================================== +EOF +=============================================================================== diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt new file mode 100644 index 000000000..8fd8fec40 --- /dev/null +++ b/specs/usdf_zdoom.txt @@ -0,0 +1,56 @@ +=============================================================================== +Universal Strife Dialog Format ZDoom extensions v1.0 - 14.08.2010 + + Copyright (c) 2010 Christoph Oelckers. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + +=============================================================================== + +======================================= +I. Grammar / Syntax +======================================= + + No changes. + +======================================= +II. Implementation Semantics +======================================= + +No changes. + +======================================= +III. Standardized Fields +======================================= + +ZDoom implements the base specification as described with one important change: +To take advantage of named actor classes any field specifying an actor type +by a conversationID takes a class name instead. +This means that ZDoom dialogues are not forward-compatible with the 'Strife' +namespace. Other ports should be aware of this. +ZDoom-format dialogues need to start with the line: + +namespace = "ZDoom"; + + +--------------------- +III.A : Conversations +--------------------- + +This block only lists the newly added fields. Currently ZDoom only adds one +field to the specification: + +conversation // Starts a dialog. +{ + id = ; // assigns an ID to a dialogue. IDs are used to dynamically assign + // dialogues to actors. For 'Strife' namespace or binary dialogues + // the standard conversation ID ('actor' property) is used instead + // for this purpose but since 'ZDoom' namespace requires the actor + // to be a class name it needs a separate field for this. +} + +=============================================================================== +EOF +=============================================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fb4cab09..5fadf0b2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -703,6 +703,7 @@ add_executable( zdoom WIN32 p_tick.cpp p_trace.cpp p_udmf.cpp + p_usdf.cpp p_user.cpp p_writemap.cpp p_xlat.cpp diff --git a/src/actionspecials.h b/src/actionspecials.h index 7f855147e..c735c7a9d 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -77,7 +77,7 @@ DEFINE_SPECIAL(Teleport_EndGame, 75, 0, 0, 0) DEFINE_SPECIAL(TeleportOther, 76, 3, 3, 3) DEFINE_SPECIAL(TeleportGroup, 77, 5, 5, 5) DEFINE_SPECIAL(TeleportInSector, 78, 4, 5, 5) - +DEFINE_SPECIAL(Thing_SetConversation, 79, 2, 2, 2) DEFINE_SPECIAL(ACS_Execute, 80, 1, 5, 5) DEFINE_SPECIAL(ACS_Suspend, 81, 2, 2, 2) DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2, 2) diff --git a/src/actor.h b/src/actor.h index 9ae11696b..84aab5fed 100644 --- a/src/actor.h +++ b/src/actor.h @@ -892,8 +892,9 @@ public: FState *MeleeState; FState *MissileState; - // [RH] The dialogue to show when this actor is "used." - FStrifeDialogueNode *Conversation; + + int ConversationRoot; // THe root of the current dialogue + FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." // [RH] Decal(s) this weapon/projectile generates on impact. FDecalBase *DecalGenerator; diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index dd32cdb55..9c06b6714 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -90,6 +90,23 @@ char *copystring (const char *s) return b; } +//============================================================================ +// +// ncopystring +// +// If the string has no content, returns NULL. Otherwise, returns a copy. +// +//============================================================================ + +char *ncopystring (const char *string) +{ + if (string == NULL || string[0] == 0) + { + return NULL; + } + return copystring (string); +} + //========================================================================== // // ReplaceString diff --git a/src/cmdlib.h b/src/cmdlib.h index fe41204ec..f9d7fae70 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -36,6 +36,7 @@ int ParseNum (const char *str); bool IsNum (const char *str); // [RH] added char *copystring(const char *s); +char *ncopystring(const char *s); void ReplaceString (char **ptr, const char *str); bool CheckWildcards (const char *pattern, const char *text); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index cdac25902..0d443bb69 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -317,6 +317,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) info->DamageFactors = NULL; info->PainChances = NULL; info->ColorSets = NULL; + info->ConversationID = -1; m_RuntimeActors.Push (type); } return type; @@ -411,6 +412,7 @@ void PClass::InitializeActorInfo () info->DamageFactors = NULL; info->PainChances = NULL; info->ColorSets = NULL; + info->ConversationID = -1; m_RuntimeActors.Push (this); } diff --git a/src/farchive.h b/src/farchive.h index 9af7d25ba..533b3920e 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -290,6 +290,10 @@ template<> inline FArchive &operator<< (FArchive &arc, FFont* &font) return SerializeFFontPtr (arc, font); } +struct FStrifeDialogueNode; +template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node); + + template inline FArchive &operator<< (FArchive &arc, TArray &self) diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 3697bcba8..2243d48a4 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -68,7 +68,7 @@ void A_Unblock(AActor *self, bool drop) self->flags &= ~MF_SOLID; - // If the self has a conversation that sets an item to drop, drop that. + // If the actor has a conversation that sets an item to drop, drop that. if (self->Conversation != NULL && self->Conversation->DropType != NULL) { P_DropItem (self, self->Conversation->DropType, -1, 256); diff --git a/src/info.h b/src/info.h index 9480f5f59..d7d939c0b 100644 --- a/src/info.h +++ b/src/info.h @@ -203,6 +203,7 @@ struct FActorInfo BYTE GameFilter; BYTE SpawnID; SWORD DoomEdNum; + int ConversationID; FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; diff --git a/src/namedef.h b/src/namedef.h index 94e0c97bd..b91781b86 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -443,3 +443,23 @@ xx(blockprojectiles) xx(blockuse) xx(Renderstyle) + +// USDF keywords +xx(Amount) +xx(Text) +xx(Displaycost) +xx(Yesmessage) +xx(Nomessage) +xx(Log) +xx(Giveitem) +xx(Nextpage) +xx(Closedialog) +xx(Cost) +xx(Page) +xx(Count) +xx(Name) +xx(Panel) +xx(Dialog) +xx(Ifitem) +xx(Choice) +xx(Link) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 8e32ee8ab..37739a43d 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -59,6 +59,8 @@ #include "doomstat.h" #include "c_console.h" #include "sbar.h" +#include "farchive.h" +#include "p_lnspec.h" // The conversations as they exist inside a SCRIPTxx lump. struct Response @@ -103,19 +105,20 @@ void GiveSpawner (player_t *player, const PClass *type); TArray StrifeDialogues; -// There were 344 types in Strife, and Strife conversations refer -// to their index in the mobjinfo table. This table indexes all -// the Strife actor types in the order Strife had them and is -// initialized as part of the actor's setup in infodefaults.cpp. -const PClass *StrifeTypes[1001]; +typedef TMap FStrifeTypeMap; // maps conversation IDs to actor classes +typedef TMap FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) +typedef TMap FDialogueMap; // maps actor class names to dialogue array index + +static FStrifeTypeMap StrifeTypes; +static FDialogueIDMap DialogueRoots; +static FDialogueMap ClassRoots; static menu_t ConversationMenu; static TArray ConversationItems; static int ConversationPauseTic; static bool ShowGold; -static void LoadScriptFile (const char *name); -static void LoadScriptFile(FileReader *lump, int numnodes); +static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type); static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeakerType); static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeakerType); static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses); @@ -139,13 +142,42 @@ static FBrokenLines *DialogueLines; // //============================================================================ -static const PClass *GetStrifeType (int typenum) +void SetStrifeType(int convid, const PClass *Class) { - if (typenum > 0 && typenum < 1001) + StrifeTypes[convid] = Class; +} + +void SetConversation(int convid, const PClass *Class, int dlgindex) +{ + if (convid != -1) { - return StrifeTypes[typenum]; + DialogueRoots[convid] = dlgindex; } - return NULL; + if (Class != NULL) + { + ClassRoots[Class->TypeName] = dlgindex; + } +} + +const PClass *GetStrifeType (int typenum) +{ + const PClass **ptype = StrifeTypes.CheckKey(typenum); + if (ptype == NULL) return NULL; + else return *ptype; +} + +int GetConversation(int conv_id) +{ + int *pindex = DialogueRoots.CheckKey(conv_id); + if (pindex == NULL) return -1; + else return *pindex; +} + +int GetConversation(FName classname) +{ + int *pindex = ClassRoots.CheckKey(classname); + if (pindex == NULL) return -1; + else return *pindex; } //============================================================================ @@ -158,11 +190,11 @@ static const PClass *GetStrifeType (int typenum) void P_LoadStrifeConversations (MapData *map, const char *mapname) { + P_FreeStrifeConversations (); if (map->Size(ML_CONVERSATION) > 0) { - LoadScriptFile ("SCRIPT00"); map->Seek(ML_CONVERSATION); - LoadScriptFile (map->file, map->Size(ML_CONVERSATION)); + LoadScriptFile (map->lumpnum, map->file, map->Size(ML_CONVERSATION), false, 0); } else { @@ -170,10 +202,13 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) { return; } - char scriptname[9] = { 'S','C','R','I','P','T',mapname[3],mapname[4],0 }; + char scriptname_b[9] = { 'S','C','R','I','P','T',mapname[3],mapname[4],0 }; + char scriptname_t[9] = { 'D','I','A','L','O','G',mapname[3],mapname[4],0 }; - LoadScriptFile ("SCRIPT00"); - LoadScriptFile (scriptname); + if (!LoadScriptFile(scriptname_t, false, 2)) + { + LoadScriptFile (scriptname_b, false, 1); + } } } @@ -192,36 +227,13 @@ void P_FreeStrifeConversations () delete node; } - for (int i = 0; i < 344; ++i) - { - if (StrifeTypes[i] != NULL) - { - AActor * ac = GetDefaultByType (StrifeTypes[i]); - if (ac != NULL) ac->Conversation = NULL; - } - } + DialogueRoots.Clear(); + ClassRoots.Clear(); CurNode = NULL; PrevNode = NULL; } -//============================================================================ -// -// ncopystring -// -// If the string has no content, returns NULL. Otherwise, returns a copy. -// -//============================================================================ - -static char *ncopystring (const char *string) -{ - if (string == NULL || string[0] == 0) - { - return NULL; - } - return copystring (string); -} - //============================================================================ // // LoadScriptFile @@ -230,61 +242,89 @@ static char *ncopystring (const char *string) // //============================================================================ -static void LoadScriptFile (const char *name) +bool LoadScriptFile (const char *name, bool include, int type) { int lumpnum = Wads.CheckNumForName (name); FileReader *lump; if (lumpnum < 0) { - return; + return false; } lump = Wads.ReopenLumpNum (lumpnum); - LoadScriptFile(lump, Wads.LumpLength(lumpnum)); + bool res = LoadScriptFile(lumpnum, lump, Wads.LumpLength(lumpnum), include, type); delete lump; + return res; } -static void LoadScriptFile(FileReader *lump, int numnodes) +static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type) { int i; DWORD prevSpeakerType; FStrifeDialogueNode *node; + char buffer[4]; - if (!(gameinfo.flags & GI_SHAREWARE)) + lump->Read(buffer, 4); + lump->Seek(0, SEEK_SET); + + // The binary format is so primitive that this check is enough to detect it. + bool isbinary = (buffer[0] == 0 || buffer[1] == 0 || buffer[2] == 0 || buffer[3] == 0); + + if ((type == 1 && !isbinary) || (type == 2 && isbinary)) { - // Strife scripts are always a multiple of 1516 bytes because each entry - // is exactly 1516 bytes long. - if (numnodes % 1516 != 0) - { - return; - } - numnodes /= 1516; - } - else - { - // And the teaser version has 1488-byte entries. - if (numnodes % 1488 != 0) - { - return; - } - numnodes /= 1488; + DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + return false; } - prevSpeakerType = 0; - - for (i = 0; i < numnodes; ++i) + if (!isbinary) { + P_ParseUSDF(lumpnum, lump, numnodes); + } + else + { + if (!include) + { + LoadScriptFile("SCRIPT00", true, 1); + } if (!(gameinfo.flags & GI_SHAREWARE)) { - node = ReadRetailNode (lump, prevSpeakerType); + // Strife scripts are always a multiple of 1516 bytes because each entry + // is exactly 1516 bytes long. + if (numnodes % 1516 != 0) + { + DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + return false; + } + numnodes /= 1516; } else { - node = ReadTeaserNode (lump, prevSpeakerType); + // And the teaser version has 1488-byte entries. + if (numnodes % 1488 != 0) + { + DPrintf("Incorrect data format for %s.", Wads.GetLumpFullName(lumpnum)); + return false; + } + numnodes /= 1488; + } + + prevSpeakerType = 0; + + for (i = 0; i < numnodes; ++i) + { + if (!(gameinfo.flags & GI_SHAREWARE)) + { + node = ReadRetailNode (lump, prevSpeakerType); + } + else + { + node = ReadTeaserNode (lump, prevSpeakerType); + } + node->ThisNodeNum = StrifeDialogues.Push(node); } - node->ThisNodeNum = StrifeDialogues.Push(node); } + return true; } //============================================================================ @@ -316,12 +356,14 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker // actor, so newly spawned actors will use this conversation by default. type = GetStrifeType (speech.SpeakerType); node->SpeakerType = type; - if (prevSpeakerType != speech.SpeakerType) + + if (speech.SpeakerType >= 0 && prevSpeakerType != speech.SpeakerType) { if (type != NULL) { - GetDefaultByType (type)->Conversation = node; + ClassRoots[type->TypeName] = StrifeDialogues.Size(); } + DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } @@ -345,9 +387,11 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker node->DropType = GetStrifeType (speech.DropType); // Items you need to have to make the speaker use a different node. + node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j] = GetStrifeType (speech.ItemCheck[j]); + node->ItemCheck[j].Item = GetStrifeType (speech.ItemCheck[j]); + node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = speech.Link; node->Children = NULL; @@ -385,12 +429,14 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker // actor, so newly spawned actors will use this conversation by default. type = GetStrifeType (speech.SpeakerType); node->SpeakerType = type; - if (prevSpeakerType != speech.SpeakerType) + + if (speech.SpeakerType >= 0 && prevSpeakerType != speech.SpeakerType) { if (type != NULL) { - GetDefaultByType (type)->Conversation = node; + ClassRoots[type->TypeName] = StrifeDialogues.Size(); } + DialogueRoots[speech.SpeakerType] = StrifeDialogues.Size(); prevSpeakerType = speech.SpeakerType; } @@ -419,9 +465,11 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker node->DropType = GetStrifeType (speech.DropType); // Items you need to have to make the speaker use a different node. + node->ItemCheck.Resize(3); for (j = 0; j < 3; ++j) { - node->ItemCheck[j] = NULL; + node->ItemCheck[j].Item = NULL; + node->ItemCheck[j].Amount = -1; } node->ItemCheckNode = 0; node->Children = NULL; @@ -476,15 +524,18 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) // The message to record in the log for this reply. reply->LogNumber = rsp->Log; + reply->LogString = NULL; // The item to receive when this reply is used. reply->GiveType = GetStrifeType (rsp->GiveType); + reply->ActionSpecial = 0; // Do you need anything special for this reply to succeed? + reply->ItemCheck.Resize(3); for (k = 0; k < 3; ++k) { - reply->ItemCheck[k] = GetStrifeType (rsp->Item[k]); - reply->ItemCheckAmount[k] = rsp->Count[k]; + reply->ItemCheck[k].Item = GetStrifeType (rsp->Item[k]); + reply->ItemCheck[k].Amount = rsp->Count[k]; } // ReplyLines is calculated when the menu is shown. It is just Reply @@ -517,7 +568,7 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) { reply->QuickYes = ncopystring (rsp->Yes); } - if (reply->ItemCheck[0] != 0) + if (reply->ItemCheck[0].Item != 0) { reply->QuickNo = ncopystring (rsp->No); } @@ -713,13 +764,20 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang } // Check if we should jump to another node - while (CurNode->ItemCheck[0] != NULL) + while (CurNode->ItemCheck.Size() > 0 && CurNode->ItemCheck[0].Item != NULL) { - if (CheckStrifeItem (pc->player, CurNode->ItemCheck[0]) && - CheckStrifeItem (pc->player, CurNode->ItemCheck[1]) && - CheckStrifeItem (pc->player, CurNode->ItemCheck[2])) + bool jump = true; + for (i = 0; i < (int)CurNode->ItemCheck.Size(); ++i) { - int root = FindNode (pc->player->ConversationNPC->GetDefault()->Conversation); + if(!CheckStrifeItem (pc->player, CurNode->ItemCheck[i].Item, CurNode->ItemCheck[i].Amount)) + { + jump = false; + break; + } + } + if (jump) + { + int root = pc->player->ConversationNPC->ConversationRoot; CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1]; } else @@ -1063,9 +1121,9 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply npc = player->ConversationNPC; // Check if you have the requisite items for this choice - for (i = 0; i < 3; ++i) + for (i = 0; i < (int)reply->ItemCheck.Size(); ++i) { - if (!CheckStrifeItem(player, reply->ItemCheck[i], reply->ItemCheckAmount[i])) + if (!CheckStrifeItem(player, reply->ItemCheck[i].Item, reply->ItemCheck[i].Amount)) { // No, you don't. Say so and let the NPC animate negatively. if (reply->QuickNo && isconsole) @@ -1132,12 +1190,18 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } + if (reply->ActionSpecial != 0) + { + takestuff |= !!LineSpecials[reply->ActionSpecial](NULL, player->mo, false, + reply->Args[0], reply->Args[1], reply->Args[2], reply->Args[3], reply->Args[4]); + } + // Take away required items if the give was successful or none was needed. if (takestuff) { - for (i = 0; i < 3; ++i) + for (i = 0; i < (int)reply->ItemCheck.Size(); ++i) { - TakeStrifeItem (player, reply->ItemCheck[i], reply->ItemCheckAmount[i]); + TakeStrifeItem (player, reply->ItemCheck[i].Item, reply->ItemCheck[i].Amount); } replyText = reply->QuickYes; } @@ -1147,7 +1211,11 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } // Update the quest log, if needed. - if (reply->LogNumber != 0) + if (reply->LogString != NULL) + { + player->SetLogText(reply->LogString); + } + else if (reply->LogNumber != 0) { player->SetLogNumber(reply->LogNumber); } @@ -1162,7 +1230,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply // will show the new node right away without terminating the dialogue. if (reply->NextNode != 0) { - int rootnode = FindNode (npc->GetDefault()->Conversation); + int rootnode = npc->ConversationRoot; if (reply->NextNode < 0) { npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1]; @@ -1316,3 +1384,26 @@ static void TerminalResponse (const char *str) } } } + + +template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node) +{ + DWORD convnum; + if (arc.IsStoring()) + { + arc.WriteCount (node == NULL? ~0u : node->ThisNodeNum); + } + else + { + convnum = arc.ReadCount(); + if (convnum >= StrifeDialogues.Size()) + { + node = NULL; + } + else + { + node = StrifeDialogues[convnum]; + } + } + return arc; +} diff --git a/src/p_conversation.h b/src/p_conversation.h index 13658e0f0..61c0ef8f4 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -1,22 +1,24 @@ #ifndef P_CONVERSATION_H #define P_CONVERSATION_H 1 -// TODO: Generalize the conversation system to something NWN-like that -// users can edit as simple text files. Particularly useful would be -// the ability to call ACS functions to implement AppearsWhen properties -// and ACS scripts to implement ActionTaken properties. -// TODO: Make this work in demos. +#include struct FStrifeDialogueReply; class FTexture; struct FBrokenLines; +struct FStrifeDialogueItemCheck +{ + const PClass *Item; + int Amount; +}; + // FStrifeDialogueNode holds text an NPC says to the player struct FStrifeDialogueNode { ~FStrifeDialogueNode (); const PClass *DropType; - const PClass *ItemCheck[3]; + TArray ItemCheck; int ThisNodeNum; // location of this node in StrifeDialogues int ItemCheckNode; // index into StrifeDialogues @@ -36,12 +38,14 @@ struct FStrifeDialogueReply FStrifeDialogueReply *Next; const PClass *GiveType; - const PClass *ItemCheck[3]; - int ItemCheckAmount[3]; + int ActionSpecial; + int Args[5]; + TArray ItemCheck; char *Reply; char *QuickYes; int NextNode; // index into StrifeDialogues int LogNumber; + char *LogString; char *QuickNo; bool NeedsGold; @@ -50,14 +54,16 @@ struct FStrifeDialogueReply extern TArray StrifeDialogues; -// There were 344 types in Strife, and Strife conversations refer -// to their index in the mobjinfo table. This table indexes all -// the Strife actor types in the order Strife had them and is -// initialized as part of the actor's setup in infodefaults.cpp. -extern const PClass *StrifeTypes[1001]; - struct MapData; +void SetStrifeType(int convid, const PClass *Class); +void SetConversation(int convid, const PClass *Class, int dlgindex); +const PClass *GetStrifeType (int typenum); +int GetConversation(int conv_id); +int GetConversation(FName classname); + +bool LoadScriptFile (const char *name, bool include, int type = 0); + void P_LoadStrifeConversations (MapData *map, const char *mapname); void P_FreeStrifeConversations (); @@ -66,4 +72,8 @@ void P_ResumeConversation (); void P_ConversationCommand (int netcode, int player, BYTE **stream); +class FileReader; +bool P_ParseUSDF(int lumpnum, FileReader *lump, int lumplen); + + #endif diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 72bea5c49..a53356a8e 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3006,6 +3006,36 @@ FUNC(LS_StartConversation) return false; } +FUNC(LS_Thing_SetConversation) +// Thing_SetConversation (tid, dlg_id) +{ + int dlg_index = -1; + FStrifeDialogueNode *node = NULL; + + if (arg1 != 0) + { + dlg_index = GetConversation(arg1); + if (dlg_index == -1) return false; + node = StrifeDialogues[dlg_index]; + } + + if (arg0 != 0) + { + FActorIterator iterator (arg0); + while ((it = iterator.Next()) != NULL) + { + it->ConversationRoot = dlg_index; + it->Conversation = node; + } + } + else if (it) + { + it->ConversationRoot = dlg_index; + it->Conversation = node; + } + return true; +} + lnSpecFunc LineSpecials[256] = { @@ -3088,7 +3118,7 @@ lnSpecFunc LineSpecials[256] = /* 76 */ LS_TeleportOther, /* 77 */ LS_TeleportGroup, /* 78 */ LS_TeleportInSector, - /* 79 */ LS_NOP, + /* 79 */ LS_Thing_SetConversation, /* 80 */ LS_ACS_Execute, /* 81 */ LS_ACS_Suspend, /* 82 */ LS_ACS_Terminate, diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f52067ba2..7b7e25888 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -361,65 +361,24 @@ void AActor::Serialize (FArchive &arc) arc << foo; } - if (arc.IsStoring ()) + if (SaveVersion > 2500) // adjust after merging into trunk! { - int convnum = 0; - unsigned int i; - - if (Conversation != NULL) - { - for (i = 0; i < StrifeDialogues.Size(); ++i) - { - if (StrifeDialogues[i] == GetDefault()->Conversation) - { - break; - } - } - for (; i + convnum < StrifeDialogues.Size(); ++convnum) - { - if (StrifeDialogues[i + convnum] == Conversation) - { - break; - } - } - if (i + convnum < StrifeDialogues.Size()) - { - convnum++; - } - else - { - convnum = 0; - } - } - arc.WriteCount (convnum); + arc << ConversationRoot << Conversation; } - else + else // old code which uses relative indexing. { int convnum; - unsigned int i; convnum = arc.ReadCount(); - if (convnum == 0 || GetDefault()->Conversation == NULL) + if (convnum == 0) { Conversation = NULL; + ConversationRoot = -1; } else { - for (i = 0; i < StrifeDialogues.Size(); ++i) - { - if (StrifeDialogues[i] == GetDefault()->Conversation) - { - break; - } - } - if (i + convnum <= StrifeDialogues.Size()) - { - Conversation = StrifeDialogues[i + convnum - 1]; - } - else - { - Conversation = GetDefault()->Conversation; - } + // This cannot be restored anymore. + I_Error("Cannot load old savegames with active dialogues"); } } @@ -3482,6 +3441,7 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash) return false; // we did the splash ourselves } + //========================================================================== // // P_SpawnMobj @@ -3508,6 +3468,17 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t actor = static_cast(const_cast(type)->CreateNew ()); + // Set default dialogue + actor->ConversationRoot = GetConversation(actor->GetClass()->TypeName); + if (actor->ConversationRoot != -1) + { + actor->Conversation = StrifeDialogues[actor->ConversationRoot]; + } + else + { + actor->Conversation = NULL; + } + actor->x = actor->PrevX = ix; actor->y = actor->PrevY = iy; actor->z = actor->PrevZ = iz; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index c057c253c..ef7f991ff 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -35,7 +35,6 @@ #include "r_data.h" #include "p_setup.h" -#include "sc_man.h" #include "p_lnspec.h" #include "templates.h" #include "i_system.h" @@ -43,6 +42,7 @@ #include "r_sky.h" #include "g_level.h" #include "v_palette.h" +#include "p_udmf.h" //=========================================================================== // @@ -124,6 +124,152 @@ extern TArray linemap; #define CHECK_N(f) if (!(namespace_bits&(f))) break; +//=========================================================================== +// +// Common parsing routines +// +//=========================================================================== + +//=========================================================================== +// +// Skip a key or block +// +//=========================================================================== + +void UDMFParserBase::Skip() +{ + if (developer) sc.ScriptMessage("Ignoring unknown key \"%s\".", sc.String); + if(sc.CheckToken('{')) + { + int level = 1; + while(sc.GetToken()) + { + if (sc.TokenType == '}') + { + level--; + if(level == 0) + { + sc.UnGet(); + break; + } + } + else if (sc.TokenType == '{') + { + level++; + } + } + } + else + { + sc.MustGetToken('='); + do + { + sc.MustGetAnyToken(); + } + while(sc.TokenType != ';'); + } +} + +//=========================================================================== +// +// Parses a 'key = value' line of the map +// +//=========================================================================== + +FName UDMFParserBase::ParseKey(bool checkblock, bool *isblock) +{ + sc.MustGetString(); + FName key = sc.String; + if (checkblock) + { + if (sc.CheckToken('{')) + { + if (isblock) *isblock = true; + return key; + } + else if (isblock) *isblock = false; + } + sc.MustGetToken('='); + + sc.Number = 0; + sc.Float = 0; + sc.MustGetAnyToken(); + + if (sc.TokenType == '+' || sc.TokenType == '-') + { + bool neg = (sc.TokenType == '-'); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) + { + sc.ScriptMessage("Numeric constant expected"); + } + if (neg) + { + sc.Number = -sc.Number; + sc.Float = -sc.Float; + } + } + if (sc.TokenType == TK_StringConst) + { + parsedString = sc.String; + } + int savedtoken = sc.TokenType; + sc.MustGetToken(';'); + sc.TokenType = savedtoken; + return key; +} + +//=========================================================================== +// +// Syntax checks +// +//=========================================================================== + +int UDMFParserBase::CheckInt(const char *key) +{ + if (sc.TokenType != TK_IntConst) + { + sc.ScriptMessage("Integer value expected for key '%s'", key); + } + return sc.Number; +} + +double UDMFParserBase::CheckFloat(const char *key) +{ + if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) + { + sc.ScriptMessage("Floating point value expected for key '%s'", key); + } + return sc.Float; +} + +fixed_t UDMFParserBase::CheckFixed(const char *key) +{ + return FLOAT2FIXED(CheckFloat(key)); +} + +angle_t UDMFParserBase::CheckAngle(const char *key) +{ + return angle_t(CheckFloat(key) * ANGLE_90 / 90.); +} + +bool UDMFParserBase::CheckBool(const char *key) +{ + if (sc.TokenType == TK_True) return true; + if (sc.TokenType == TK_False) return false; + sc.ScriptMessage("Boolean value expected for key '%s'", key); + return false; +} + +const char *UDMFParserBase::CheckString(const char *key) +{ + if (sc.TokenType != TK_StringConst) + { + sc.ScriptMessage("String value expected for key '%s'", key); + } + return parsedString; +} + //=========================================================================== // // Storage of UDMF user properties @@ -233,15 +379,11 @@ fixed_t GetUDMFFixed(int type, int index, const char *key) // //=========================================================================== -struct UDMFParser +class UDMFParser : public UDMFParserBase { - FScanner sc; - FName namespc; - int namespace_bits; bool isTranslated; bool isExtended; bool floordrop; - FString parsedString; TArray ParsedLines; TArray ParsedSides; @@ -251,113 +393,13 @@ struct UDMFParser FDynamicColormap *fogMap, *normMap; +public: UDMFParser() { linemap.Clear(); fogMap = normMap = NULL; } - //=========================================================================== - // - // Parses a 'key = value' line of the map - // - //=========================================================================== - - FName ParseKey() - { - sc.MustGetString(); - FName key = sc.String; - sc.MustGetToken('='); - - sc.Number = 0; - sc.Float = 0; - sc.MustGetAnyToken(); - - if (sc.TokenType == '+' || sc.TokenType == '-') - { - bool neg = (sc.TokenType == '-'); - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) - { - sc.ScriptMessage("Numeric constant expected"); - } - if (neg) - { - sc.Number = -sc.Number; - sc.Float = -sc.Float; - } - } - if (sc.TokenType == TK_StringConst) - { - parsedString = sc.String; - } - int savedtoken = sc.TokenType; - sc.MustGetToken(';'); - sc.TokenType = savedtoken; - return key; - } - - //=========================================================================== - // - // Syntax checks - // - //=========================================================================== - - int CheckInt(const char *key) - { - if (sc.TokenType != TK_IntConst) - { - sc.ScriptMessage("Integer value expected for key '%s'", key); - } - return sc.Number; - } - - double CheckFloat(const char *key) - { - if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst) - { - sc.ScriptMessage("Floating point value expected for key '%s'", key); - } - return sc.Float; - } - - fixed_t CheckFixed(const char *key) - { - return FLOAT2FIXED(CheckFloat(key)); - } - - angle_t CheckAngle(const char *key) - { - return angle_t(CheckFloat(key) * ANGLE_90 / 90.); - } - - bool CheckBool(const char *key) - { - if (sc.TokenType == TK_True) return true; - if (sc.TokenType == TK_False) return false; - sc.ScriptMessage("Boolean value expected for key '%s'", key); - return false; - } - - const char *CheckString(const char *key) - { - if (sc.TokenType != TK_StringConst) - { - sc.ScriptMessage("String value expected for key '%s'", key); - } - return parsedString; - } - - template - void Flag(T &value, int mask, const char *key) - { - if (CheckBool(key)) - value |= mask; - else - value &= ~mask; - } - - void AddUserKey(FName key, int kind, int index) { FUDMFKeys &keyarray = UDMFKeys[kind][index]; @@ -1457,6 +1499,10 @@ struct UDMFParser ParseVertex(&vt); ParsedVertices.Push(vt); } + else + { + Skip(); + } } // Create the real vertices diff --git a/src/p_udmf.h b/src/p_udmf.h new file mode 100644 index 000000000..0fc2f5564 --- /dev/null +++ b/src/p_udmf.h @@ -0,0 +1,38 @@ +#ifndef __P_UDMF_H +#define __P_UDMF_H + +#include "sc_man.h" +#include "m_fixed.h" +#include "tables.h" + +class UDMFParserBase +{ +protected: + FScanner sc; + FName namespc; + int namespace_bits; + FString parsedString; + + void Skip(); + FName ParseKey(bool checkblock = false, bool *isblock = NULL); + int CheckInt(const char *key); + double CheckFloat(const char *key); + fixed_t CheckFixed(const char *key); + angle_t CheckAngle(const char *key); + bool CheckBool(const char *key); + const char *CheckString(const char *key); + + template + void Flag(T &value, int mask, const char *key) + { + if (CheckBool(key)) + value |= mask; + else + value &= ~mask; + } + +}; + +#define BLOCK_ID (ENamedName)-1 + +#endif \ No newline at end of file diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp new file mode 100644 index 000000000..21bd8eeb3 --- /dev/null +++ b/src/p_usdf.cpp @@ -0,0 +1,505 @@ +// +// p_usdf.cpp +// +// USDF dialogue parser +// +//--------------------------------------------------------------------------- +// Copyright (c) 2010 +// Braden "Blzut3" Obrzut +// Christoph Oelckers +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "r_data.h" +#include "p_setup.h" +#include "p_lnspec.h" +#include "templates.h" +#include "i_system.h" +#include "p_conversation.h" +#include "p_udmf.h" +#include "doomerrors.h" + +#define Zd 1 +#define St 2 + +class USDFParser : public UDMFParserBase +{ + //=========================================================================== + // + // Checks an actor type (different representation depending on manespace) + // + //=========================================================================== + + const PClass *CheckActorType(const char *key) + { + if (namespace_bits == St) + { + return GetStrifeType(CheckInt(key)); + } + else if (namespace_bits == Zd) + { + const PClass *cls = PClass::FindClass(CheckString(key)); + if (cls == NULL) + { + sc.ScriptMessage("Unknown actor class '%s'", key); + return NULL; + } + if (!cls->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + sc.ScriptMessage("'%s' is not an actor type", key); + return NULL; + } + } + return NULL; + } + + //=========================================================================== + // + // Parse a cost block + // + //=========================================================================== + + bool ParseCost(FStrifeDialogueReply *response) + { + FStrifeDialogueItemCheck check; + check.Item = NULL; + check.Amount = -1; + + while (!sc.CheckToken('}')) + { + FName key = ParseKey(); + switch(key) + { + case NAME_Item: + check.Item = CheckActorType(key); + break; + + case NAME_Amount: + check.Amount = CheckInt(key); + break; + } + } + + response->ItemCheck.Push(check); + return true; + } + + //=========================================================================== + // + // Parse a choice block + // + //=========================================================================== + + bool ParseChoice(FStrifeDialogueReply **&replyptr) + { + FStrifeDialogueReply *reply = new FStrifeDialogueReply; + memset(reply, 0, sizeof(*reply)); + + reply->Next = *replyptr; + *replyptr = reply; + replyptr = &reply->Next; + + FString ReplyString; + FString QuickYes; + FString QuickNo; + FString LogString; + bool closeDialog = false; + + + reply->NeedsGold = false; + while (!sc.CheckToken('}')) + { + bool block = false; + int costs = 0; + FName key = ParseKey(true, &block); + if (!block) + { + switch(key) + { + case NAME_Text: + ReplyString = CheckString(key); + break; + + case NAME_Displaycost: + reply->NeedsGold = CheckBool(key); + break; + + case NAME_Yesmessage: + QuickYes = CheckString(key); + //if (!QuickYes.Compare("_")) QuickYes = ""; + break; + + case NAME_Nomessage: + QuickNo = CheckString(key); + break; + + case NAME_Log: + if (namespace_bits == St) + { + const char *s = CheckString(key); + if(strlen(s) < 4 || strnicmp(s, "LOG", 3) != 0) + { + sc.ScriptMessage("Log must be in the format of LOG# to compile, ignoring."); + } + else + { + reply->LogNumber = atoi(s + 3); + } + } + else + { + LogString = CheckString(key); + } + break; + + case NAME_Giveitem: + reply->GiveType = CheckActorType(key); + break; + + case NAME_Nextpage: + reply->NextNode = CheckInt(key); + break; + + case NAME_Closedialog: + closeDialog = CheckBool(key); + break; + + case NAME_Special: + reply->ActionSpecial = CheckInt(key); + if (reply->ActionSpecial < 0 || reply->ActionSpecial > 255) + reply->ActionSpecial = 0; + break; + + case NAME_Arg0: + case NAME_Arg1: + case NAME_Arg2: + case NAME_Arg3: + case NAME_Arg4: + reply->Args[int(key)-int(NAME_Arg0)] = CheckInt(key); + break; + + + } + } + else + { + switch(key) + { + case NAME_Cost: + ParseCost(reply); + break; + + default: + sc.UnGet(); + Skip(); + } + } + } + // Todo: Finalize + if (reply->ItemCheck.Size() > 0) + { + if (reply->ItemCheck[0].Amount <= 0) reply->NeedsGold = false; + if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->ItemCheck[0].Amount); + } + + reply->Reply = ncopystring(ReplyString); + reply->QuickYes = ncopystring(QuickYes); + if (reply->ItemCheck.Size() > 0 && reply->ItemCheck[0].Item != NULL) + { + reply->QuickNo = ncopystring(QuickNo); + } + else + { + reply->QuickNo = NULL; + } + reply->LogString = ncopystring(LogString); + if(!closeDialog) reply->NextNode *= -1; + return true; + } + + //=========================================================================== + // + // Parse an ifitem block + // + //=========================================================================== + + bool ParseIfItem(FStrifeDialogueNode *node) + { + FStrifeDialogueItemCheck check; + check.Item = NULL; + check.Amount = -1; + + while (!sc.CheckToken('}')) + { + FName key = ParseKey(); + switch(key) + { + case NAME_Item: + check.Item = CheckActorType(key); + break; + + case NAME_Count: + // Not yet implemented in the engine. Todo later + check.Amount = CheckInt(key); + break; + } + } + + node->ItemCheck.Push(check); + return true; + } + + //=========================================================================== + // + // Parse a page block + // + //=========================================================================== + + bool ParsePage() + { + FStrifeDialogueNode *node = new FStrifeDialogueNode; + FStrifeDialogueReply **replyptr = &node->Children; + memset(node, 0, sizeof(*node)); + //node->ItemCheckCount[0] = node->ItemCheckCount[1] = node->ItemCheckCount[2] = -1; + + node->ThisNodeNum = StrifeDialogues.Push(node); + + FString SpeakerName; + FString Dialogue; + + while (!sc.CheckToken('}')) + { + bool block = false; + FName key = ParseKey(true, &block); + if (!block) + { + switch(key) + { + case NAME_Name: + SpeakerName = CheckString(key); + break; + + case NAME_Panel: + node->Backdrop = TexMan.CheckForTexture (CheckString(key), FTexture::TEX_MiscPatch); + break; + + case NAME_Voice: + { + FString soundname = (namespace_bits == St? "svox/" : ""); + const char * name = CheckString(key); + if (name[0] != 0) + { + soundname += name; + node->SpeakerVoice = FSoundID(S_FindSound(soundname)); + } + } + break; + + case NAME_Dialog: + Dialogue = CheckString(key); + break; + + case NAME_Drop: + node->DropType = CheckActorType(key); + break; + + case NAME_Link: + node->ItemCheckNode = CheckInt(key); + break; + + + } + } + else + { + switch(key) + { + case NAME_Ifitem: + if (!ParseIfItem(node)) return false; + break; + + case NAME_Choice: + if (!ParseChoice(replyptr)) return false; + break; + + default: + sc.UnGet(); + Skip(); + } + } + } + node->SpeakerName = ncopystring(SpeakerName); + node->Dialogue = ncopystring(Dialogue); + return true; + } + + + //=========================================================================== + // + // Parse a conversation block + // + //=========================================================================== + + bool ParseConversation() + { + const PClass *type = NULL; + int dlgid = -1; + unsigned int startpos = StrifeDialogues.Size(); + + while (!sc.CheckToken('}')) + { + bool block = false; + FName key = ParseKey(true, &block); + if (!block) + { + switch(key) + { + case NAME_Actor: + type = CheckActorType(key); + if (namespace_bits == St) + { + dlgid = CheckInt(key); + } + break; + + case NAME_Id: + if (namespace_bits == Zd) + { + dlgid = CheckInt(key); + } + break; + } + } + else + { + switch(key) + { + case NAME_Page: + if (!ParsePage()) return false; + break; + + default: + sc.UnGet(); + Skip(); + } + } + } + if (type == NULL) + { + sc.ScriptMessage("No valid actor type defined in conversation."); + return false; + } + SetConversation(dlgid, type, startpos); + for(;startpos < StrifeDialogues.Size(); startpos++) + { + StrifeDialogues[startpos]->SpeakerType = type; + } + return true; + } + + //=========================================================================== + // + // Parse an USDF lump + // + //=========================================================================== + +public: + bool Parse(int lumpnum, FileReader *lump, int lumplen) + { + char *buffer = new char[lumplen]; + lump->Read(buffer, lumplen); + sc.OpenMem(Wads.GetLumpFullName(lumpnum), buffer, lumplen); + delete [] buffer; + sc.SetCMode(true); + // Namespace must be the first field because everything else depends on it. + if (sc.CheckString("namespace")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + namespc = sc.String; + switch(namespc) + { + case NAME_ZDoom: + namespace_bits = Zd; + break; + case NAME_Strife: + namespace_bits = St; + break; + default: + sc.ScriptMessage("Unknown namespace %s. Ignoring dialogue lump.\n", sc.String); + return false; + } + sc.MustGetToken(';'); + } + else + { + sc.ScriptMessage("Map does not define a namespace.\n"); + return false; + } + + while (sc.GetString()) + { + if (sc.Compare("conversation")) + { + sc.MustGetToken('{'); + if (!ParseConversation()) return false; + } + else if (sc.Compare("include")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + LoadScriptFile(sc.String, true); + sc.MustGetToken(';'); + } + else + { + Skip(); + } + } + return true; + } +}; + + + +bool P_ParseUSDF(int lumpnum, FileReader *lump, int lumplen) +{ + USDFParser parse; + + try + { + if (!parse.Parse(lumpnum, lump, lumplen)) + { + // clean up the incomplete dialogue structures here + return false; + } + return true; + } + catch(CRecoverableError &err) + { + Printf("%s", err.GetMessage()); + return false; + } +} diff --git a/src/p_user.cpp b/src/p_user.cpp index 65909b3d3..cf80d3819 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -376,17 +376,17 @@ void player_t::SetLogNumber (int num) data[length]=0; SetLogText (data); delete[] data; - - // Print log text to console - AddToConsole(-1, TEXTCOLOR_GOLD); - AddToConsole(-1, LogText); - AddToConsole(-1, "\n"); } } void player_t::SetLogText (const char *text) { LogText = text; + + // Print log text to console + AddToConsole(-1, TEXTCOLOR_GOLD); + AddToConsole(-1, LogText); + AddToConsole(-1, "\n"); } int player_t::GetSpawnClass() diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index ffe287035..1e8f51f97 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -255,13 +255,11 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE|GI_TEASER2)) convid=id2; - if (convid==-1) return; } - if (convid<0 || convid>1000) - { - I_Error ("ConversationID must be in the range [0,1000]"); - } - else StrifeTypes[convid] = info->Class; + + bag.Info->ConversationID = convid; + if (convid <= 0) return; // 0 is not usable because the dialogue scripts use it as 'no object'. + SetStrifeType(convid, info->Class); } //========================================================================== diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index d8ecd9bbb..a80685c35 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -1662,7 +1662,6 @@ ACTOR TargetPractice 208 ACTOR ForceFieldGuard 25 native { Game Strife - ConversationID 0 Health 10 Radius 2 Height 1 diff --git a/zdoom.vcproj b/zdoom.vcproj index 7885a5174..21247821f 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -900,6 +900,10 @@ RelativePath=".\src\p_udmf.cpp" > + + From 1460b8feeda6c853f0fc68c165bd71799247f461 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 20 Aug 2010 19:10:02 +0000 Subject: [PATCH 194/251] - fixed: The check for old incompatible savegames with dialogues was wrong. SVN r2562 (trunk) --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7b7e25888..4d3af4568 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -370,7 +370,7 @@ void AActor::Serialize (FArchive &arc) int convnum; convnum = arc.ReadCount(); - if (convnum == 0) + if (GetConversation(GetClass()->TypeName) == -1) { Conversation = NULL; ConversationRoot = -1; From 96a8f1ceee566ca50343c6cade593c1eaae2fa51 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 21 Aug 2010 19:50:07 +0000 Subject: [PATCH 195/251] - fixed: The SaveVersion check for the USDF related changes for the current dialogue did not have the correct version number. - fixed: All blood spawning functions checked the ALLOWPARTICLES flag on the class defaults before actor replacement instead of after. SVN r2563 (trunk) --- src/actor.h | 13 ++++++++++--- src/p_mobj.cpp | 10 +++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/actor.h b/src/actor.h index 84aab5fed..68eda132b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -722,19 +722,26 @@ public: const PClass *GetBloodType(int type = 0) const { + const PClass *bloodcls; if (type == 0) { - return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType, NAME_Blood)); } else if (type == 1) { - return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType2, NAME_BloodSplatter)); } else if (type == 2) { - return PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); + bloodcls = PClass::FindClass((ENamedName)GetClass()->Meta.GetMetaInt(AMETA_BloodType3, NAME_AxeBlood)); } else return NULL; + + if (bloodcls != NULL) + { + bloodcls = bloodcls->ActorInfo->GetReplacement()->Class; + } + return bloodcls; } // Calculate amount of missile damage diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4d3af4568..c6011d4ea 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -361,7 +361,7 @@ void AActor::Serialize (FArchive &arc) arc << foo; } - if (SaveVersion > 2500) // adjust after merging into trunk! + if (SaveVersion > 2560) { arc << ConversationRoot << Conversation; } @@ -4486,7 +4486,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc if (bloodcls!=NULL && bloodtype <= 1) { z += pr_spawnblood.Random2 () << 10; - th = Spawn (bloodcls, x, y, z, ALLOW_REPLACE); + th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement th->velz = FRACUNIT*2; th->angle = dir; if (gameinfo.gametype & GAME_DoomChex) @@ -4549,7 +4549,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { AActor *mo; - mo = Spawn(bloodcls, x, y, z, ALLOW_REPLACE); + mo = Spawn(bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement mo->target = originator; mo->velx = pr_splatter.Random2 () << 10; mo->vely = pr_splatter.Random2 () << 10; @@ -4590,7 +4590,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) x += ((pr_splat()-128)<<11); y += ((pr_splat()-128)<<11); - mo = Spawn (bloodcls, x, y, z, ALLOW_REPLACE); + mo = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement mo->target = originator; // colorize the blood! @@ -4629,7 +4629,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) if (bloodcls!=NULL && bloodtype <= 1) { AActor *th; - th = Spawn (bloodcls, x, y, z, ALLOW_REPLACE); + th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement if (gameinfo.gametype == GAME_Heretic) th->flags |= MF_NOGRAVITY; th->velx = mo->velx >> 1; From 883510efe2eb5dabc2de06338d6e625edf387bcf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Aug 2010 17:18:46 +0000 Subject: [PATCH 196/251] - added UMDF property to assign conversation dialogues to mapthings. SVN r2567 (trunk) --- specs/udmf_zdoom.txt | 5 +++++ src/doomdata.h | 1 + src/namedef.h | 1 + src/p_mobj.cpp | 11 +++++++++++ src/p_udmf.cpp | 5 +++++ 5 files changed, 23 insertions(+) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 5ceb573aa..9f91c748e 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -180,6 +180,8 @@ Note: All fields default to false unless mentioned otherwise. class# = // Unlike the base spec, # can range from 1-8. // 8 is the maximum amount of classes the class // menu can display. + conversation = // Assigns a conversation dialogue to this thing. + // Parameter is the conversation ID, 0 meaning none. } @@ -268,6 +270,9 @@ Added 'playeruseback' line trigger flag. 1.11 07.08.2010 Added 'soundsequnce' sector property. +1.12 22.08.2010 +Added 'conversation' thing property. + =============================================================================== EOF =============================================================================== diff --git a/src/doomdata.h b/src/doomdata.h index 859246261..9c22b22a6 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -340,6 +340,7 @@ struct FMapThing DWORD flags; int special; int args[5]; + int Conversation; void Serialize (FArchive &); }; diff --git a/src/namedef.h b/src/namedef.h index b91781b86..cb3e78ea2 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -383,6 +383,7 @@ xx(Firstsideonly) xx(Transparent) xx(Passuse) xx(Repeatspecial) +xx(Conversation) xx(Playercross) xx(Playeruse) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c6011d4ea..2b9da7a54 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4394,6 +4394,17 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->AddToHash (); mobj->PrevAngle = mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360); + + // Check if this actor's mapthing has a conversation defined + if (mthing->Conversation > 0) + { + mobj->ConversationRoot = GetConversation(mthing->Conversation); + if (mobj->ConversationRoot != -1) + { + mobj->Conversation = StrifeDialogues[mobj->ConversationRoot]; + } + } + mobj->BeginPlay (); if (!(mobj->ObjectFlags & OF_EuthanizeMe)) { diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index ef7f991ff..e75d324df 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -493,6 +493,11 @@ public: th->type = (short)CheckInt(key); break; + case NAME_Conversation: + CHECK_N(Zd | Zdt) + th->Conversation = CheckInt(key); + break; + case NAME_Special: CHECK_N(Hx | Zd | Zdt | Va) th->special = CheckInt(key); From ec71635ca13ace99068e0a664af9aa35e1566e9b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Aug 2010 17:31:42 +0000 Subject: [PATCH 197/251] - fixed: The USDF CheckActorType function did not return the class object for ZDoom namespace. - fixed: The binary check for dialogue lumps must only rewind the file by 4 bytes, not completely to the start. SVN r2568 (trunk) --- src/p_conversation.cpp | 2 +- src/p_usdf.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 37739a43d..96b00b1a5 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -266,7 +266,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc char buffer[4]; lump->Read(buffer, 4); - lump->Seek(0, SEEK_SET); + lump->Seek(-4, SEEK_CUR); // The binary format is so primitive that this check is enough to detect it. bool isbinary = (buffer[0] == 0 || buffer[1] == 0 || buffer[2] == 0 || buffer[3] == 0); diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 21bd8eeb3..7bcca2204 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -71,6 +71,7 @@ class USDFParser : public UDMFParserBase sc.ScriptMessage("'%s' is not an actor type", key); return NULL; } + return cls; } return NULL; } From 9073b8cdeaa363db696b000f60ca312456d89bd9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Aug 2010 17:49:28 +0000 Subject: [PATCH 198/251] - removed FActorInfo::ConversationID which was development garbage of the USDF branch. SVN r2569 (trunk) --- src/dobjtype.cpp | 2 -- src/info.h | 1 - src/thingdef/thingdef_properties.cpp | 1 - 3 files changed, 4 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0d443bb69..cdac25902 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -317,7 +317,6 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size) info->DamageFactors = NULL; info->PainChances = NULL; info->ColorSets = NULL; - info->ConversationID = -1; m_RuntimeActors.Push (type); } return type; @@ -412,7 +411,6 @@ void PClass::InitializeActorInfo () info->DamageFactors = NULL; info->PainChances = NULL; info->ColorSets = NULL; - info->ConversationID = -1; m_RuntimeActors.Push (this); } diff --git a/src/info.h b/src/info.h index d7d939c0b..9480f5f59 100644 --- a/src/info.h +++ b/src/info.h @@ -203,7 +203,6 @@ struct FActorInfo BYTE GameFilter; BYTE SpawnID; SWORD DoomEdNum; - int ConversationID; FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 1e8f51f97..1e47dfd86 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -257,7 +257,6 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) } - bag.Info->ConversationID = convid; if (convid <= 0) return; // 0 is not usable because the dialogue scripts use it as 'no object'. SetStrifeType(convid, info->Class); } From 3662ed4f271b0b83d5771eb5d328f9bdd8a4fac5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 23 Aug 2010 06:18:17 +0000 Subject: [PATCH 199/251] - Changed wording of usdf_zdoom.txt because technically this format is not USDF anymore due to the required changes to allow specifying classes by name. SVN r2571 (trunk) --- specs/usdf_zdoom.txt | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index 8fd8fec40..217354292 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -1,5 +1,6 @@ =============================================================================== -Universal Strife Dialog Format ZDoom extensions v1.0 - 14.08.2010 +ZDoom Strife Dialog Format ZDoom v1.1 - 23.08.2010 +based on Universal Strife Dialog Format v2.0 Copyright (c) 2010 Christoph Oelckers. Permission is granted to copy, distribute and/or modify this document @@ -22,14 +23,46 @@ II. Implementation Semantics No changes. ======================================= -III. Standardized Fields +III. Changes to USDF spec ======================================= -ZDoom implements the base specification as described with one important change: +ZDoom Strife Dialogue format implements the USDF base specification as described with one important change: To take advantage of named actor classes any field specifying an actor type by a conversationID takes a class name instead. -This means that ZDoom dialogues are not forward-compatible with the 'Strife' -namespace. Other ports should be aware of this. +The following fields are affected by this change: + +conversation +{ + actor = ; + + page + { + drop = ; + ifitem + { + item = ; + } + + choice + { + cost + { + item = ; + } + + giveitem = ; + } + } +} + +It should be noted that this change creates an incompatibility with USDF +so technically speaking the ZDoom format is no longer 'real' USDF. +To accomodate what is needed here this is unavoidable, unfortunately. +Any proper USDF implementation not supporting named actor classes should +either refuse loading dialogues with the 'ZDoom' namespace or if it does not +outright abort on incompatible namespaces fail with a type mismatch error on +one of the specified propeties. + ZDoom-format dialogues need to start with the line: namespace = "ZDoom"; From c058c644a416c121928c7a9d0a98c37e1d986af5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 24 Aug 2010 02:35:10 +0000 Subject: [PATCH 200/251] - MinGW did not like this assignment in the FluidSynth loader. SVN r2573 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 1e88af055..d50e236b7 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -667,7 +667,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() } #endif - for (int i = 0; i < countof(imports); ++i) + for (size_t i = 0; i < countof(imports); ++i) { #ifdef _WIN32 FARPROC proc = GetProcAddress(FluidSynthDLL, imports[i].FuncName); @@ -679,7 +679,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, FLUIDSYNTHLIB); fail++; } - *imports[i].FuncPointer = proc; + *imports[i].FuncPointer = (void *)proc; } if (fail == 0) { From f08c66d664fbb0cd72cfab04802ba8a460a3c0f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 24 Aug 2010 09:53:10 +0000 Subject: [PATCH 201/251] - externalized the "You seem to have enough" string to language lump. - allow all texts in conversations to reference the string table. - fixed: If no dialogue is found for the current map, SCRIPT00 should still be loaded. SVN r2577 (trunk) --- src/p_conversation.cpp | 39 +++++++++++++++++++++++++++++++++++--- wadsrc/static/language.enu | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 96b00b1a5..0d7d311b4 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -207,7 +207,10 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) if (!LoadScriptFile(scriptname_t, false, 2)) { - LoadScriptFile (scriptname_b, false, 1); + if (!LoadScriptFile (scriptname_b, false, 1)) + { + LoadScriptFile ("SCRIPT00", false, 1); + } } } } @@ -813,6 +816,18 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;) } } + else + { + // handle string table replacement + if (toSay[0] == '$') + { + toSay = GStrings(toSay + 1); + } + } + if (toSay == NULL) + { + toSay = "."; + } DialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay); // Fill out the possible choices @@ -830,6 +845,12 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang for (j = 0; reply->ReplyLines[j].Width >= 0; ++j) { item.label = reply->ReplyLines[j].Text.LockBuffer(); + // handle string table replacement + if (item.label[0] == '$') + { + item.label = GStrings(item.label + 1); + } + item.b.position = j == 0 ? i : 0; item.c.extra = reply; ConversationItems.Push (item); @@ -1207,13 +1228,19 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } else { - replyText = "You seem to have enough!"; + replyText = "$txt_haveenough"; } // Update the quest log, if needed. if (reply->LogString != NULL) { - player->SetLogText(reply->LogString); + const char *log = reply->LogString; + if (log[0] == '$') + { + log = GStrings(log + 1); + } + + player->SetLogText(log); } else if (reply->LogNumber != 0) { @@ -1366,6 +1393,12 @@ static void TerminalResponse (const char *str) { if (str != NULL) { + // handle string table replacement + if (str[0] == '$') + { + str = GStrings(str + 1); + } + if (StatusBar != NULL) { AddToConsole(-1, str); diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 5f05ba447..883b0e325 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1476,6 +1476,7 @@ TXT_RANDOM_PGUARD_10 = "If there is any honor inside that pathetic shell of a bo TXT_RANDOMGOODBYE_1 = "Bye!"; TXT_RANDOMGOODBYE_2 = "Thanks, bye!"; TXT_RANDOMGOODBYE_3 = "See you later!"; +TXT_HAVEENOUGH = "You seem to have enough!"; // Skills: From 6c57441bcdaa701658900f46b4e0a2b984e28662 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 24 Aug 2010 13:57:17 +0000 Subject: [PATCH 202/251] - fixed: The UDMF check for dialogues without owning class needs to be relaxed. A dialogue with an id and no class is a valid construct. - fixed: Trying to assign a non-existent dialogue to an actor in UDMF partially overwrote the default dialogue. SVN r2579 (trunk) --- src/p_mobj.cpp | 6 ++++-- src/p_usdf.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2b9da7a54..85ca7662e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4398,9 +4398,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // Check if this actor's mapthing has a conversation defined if (mthing->Conversation > 0) { - mobj->ConversationRoot = GetConversation(mthing->Conversation); - if (mobj->ConversationRoot != -1) + // Make sure that this does not partially overwrite the default dialogue settings. + int root = GetConversation(mthing->Conversation); + if (root != -1) { + mobj->ConversationRoot = root; mobj->Conversation = StrifeDialogues[mobj->ConversationRoot]; } } diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 7bcca2204..b831b4140 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -407,7 +407,7 @@ class USDFParser : public UDMFParserBase } } } - if (type == NULL) + if (type == NULL && dlgid == 0) { sc.ScriptMessage("No valid actor type defined in conversation."); return false; From eed581279986f2853f261900031445a5e3137697 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Aug 2010 16:46:01 +0000 Subject: [PATCH 203/251] - added 'fluidsynth' option for $mididevice command. SVN r2598 (trunk) --- src/s_advsound.cpp | 1 + src/s_sound.h | 1 + src/sound/i_music.cpp | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index e121bc2ee..46d4bc813 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1294,6 +1294,7 @@ static void S_AddSNDINFO (int lump) else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; + else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; else sc.ScriptError("Unknown MIDI device %s\n", sc.String); } break; diff --git a/src/s_sound.h b/src/s_sound.h index 8d89d1a0d..05237ba27 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -378,6 +378,7 @@ enum EMidiDevice MDEV_OPL = 1, MDEV_FMOD = 2, MDEV_TIMIDITY = 3, + MDEV_FLUIDSYNTH = 4, }; typedef TMap MidiDeviceMap; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 60a87ea67..eb68d290e 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -441,7 +441,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int info = new MUSSong2(file, musiccache, len, MIDI_Timidity); } #ifdef HAVE_FLUIDSYNTH - else if (snd_mididevice == -5 && device == MDEV_DEFAULT) + else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) { info = new MUSSong2(file, musiccache, len, MIDI_Fluid); } @@ -528,7 +528,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int info = new MIDISong2(file, musiccache, len, MIDI_Timidity); } #ifdef HAVE_FLUIDSYNTH - else if (snd_mididevice == -5 && device == MDEV_DEFAULT) + else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) { info = new MIDISong2(file, musiccache, len, MIDI_Fluid); } From 06a35dea11f9028398b90197907703bf28ea323d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Aug 2010 18:03:15 +0000 Subject: [PATCH 204/251] - added: offset the trail actors spawned by AFastProjectile by missileheight. SVN r2599 (trunk) --- src/g_shared/a_fastprojectile.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 3bd2903ee..161323b2b 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -158,10 +158,13 @@ void AFastProjectile::Effect() if (name != NAME_None) { fixed_t hitz = z-8*FRACUNIT; + if (hitz < floorz) { hitz = floorz; } + // Do not clip this offset to the floor. + hitz += GetClass()->Meta.GetMetaFixed (ACMETA_MissileHeight); const PClass *trail = PClass::FindClass(name); if (trail != NULL) From ffa58aadbe99984b7b5a5c8fe05645784bbe55ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Aug 2010 18:08:09 +0000 Subject: [PATCH 205/251] - added Aroenai's snd_menuvolume submission. SVN r2600 (trunk) --- src/m_menu.cpp | 43 ++++++++++++++-------------- src/m_options.cpp | 72 ++++++++++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 10ba3a336..b3e28b88e 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -205,6 +205,7 @@ EXTERN_CVAR (String, playerclass) EXTERN_CVAR (String, name) EXTERN_CVAR (Int, team) EXTERN_CVAR(Bool, neverswitchonpickup) +EXTERN_CVAR(Float, snd_menuvolume) extern bool sendpause; extern int flagsvar; @@ -663,28 +664,28 @@ CCMD (menu_help) CCMD (quicksave) { // F6 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); M_QuickSave(); } CCMD (quickload) { // F9 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); M_QuickLoad(); } CCMD (menu_endgame) { // F7 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); M_EndGame(0); } CCMD (menu_quit) { // F10 //M_StartControlPanel (true); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); M_QuitGame(0); } @@ -1439,7 +1440,7 @@ void M_QuickSaveResponse (int ch) if (ch == 'y') { M_DoSave (quickSaveSlot); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); } } @@ -1447,7 +1448,7 @@ void M_QuickSave () { if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer)) { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); return; } @@ -1478,7 +1479,7 @@ void M_QuickLoadResponse (int ch) if (ch == 'y') { M_LoadSelect (quickSaveSlot); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); } } @@ -1981,7 +1982,7 @@ void M_EndGame(int choice) choice = 0; if (!usergame) { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); return; } @@ -2042,7 +2043,7 @@ void M_QuitResponse(int ch) { if (gameinfo.quitSound.IsNotEmpty()) { - S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE); I_WaitVBL (105); } } @@ -2879,7 +2880,7 @@ void M_StartMessage (const char *string, void (*routine)(int)) if (messageRoutine != NULL) { S_StopSound (CHAN_VOICE); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE); } return; } @@ -2898,7 +2899,7 @@ void M_EndMessage(int key) } SB_state = screen->GetPageCount(); // refresh the status bar BorderNeedRefresh = screen->GetPageCount(); - S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", 1, ATTN_NONE); + S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); } @@ -3101,7 +3102,7 @@ bool M_Responder (event_t *ev) if (currentMenu->menuitems[i].alphaKey == ch) { itemOn = i; - S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); return true; } } @@ -3337,7 +3338,7 @@ void M_ButtonHandler(EMenuKey key, bool repeat) if (itemOn + 1 >= currentMenu->numitems) itemOn = 0; else itemOn++; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } while (currentMenu->menuitems[itemOn].status == -1); break; @@ -3347,7 +3348,7 @@ void M_ButtonHandler(EMenuKey key, bool repeat) if (itemOn == 0) itemOn = currentMenu->numitems - 1; else itemOn--; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } while (currentMenu->menuitems[itemOn].status == -1); break; @@ -3355,7 +3356,7 @@ void M_ButtonHandler(EMenuKey key, bool repeat) if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); currentMenu->menuitems[itemOn].routine(0); } break; @@ -3364,7 +3365,7 @@ void M_ButtonHandler(EMenuKey key, bool repeat) if (currentMenu->menuitems[itemOn].routine && currentMenu->menuitems[itemOn].status == 2) { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); currentMenu->menuitems[itemOn].routine(1); } break; @@ -3377,12 +3378,12 @@ void M_ButtonHandler(EMenuKey key, bool repeat) if (currentMenu->menuitems[itemOn].status == 2) { currentMenu->menuitems[itemOn].routine(1); // right arrow - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } else { currentMenu->menuitems[itemOn].routine(itemOn); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); } } break; @@ -3602,7 +3603,7 @@ void M_StartControlPanel (bool makeSound, bool wantTop) if (makeSound) { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); } } @@ -3946,12 +3947,12 @@ void M_PopMenuStack (void) } drawSkull = MenuStack[MenuStackDepth].drawSkull; ++MenuStackDepth; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/backup", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/backup", snd_menuvolume, ATTN_NONE); } else { M_ClearMenus (); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/clear", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/clear", snd_menuvolume, ATTN_NONE); } } diff --git a/src/m_options.cpp b/src/m_options.cpp index 4f822befe..06c3017bf 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -100,6 +100,7 @@ EXTERN_CVAR (Int, snd_channels) // defaulted values // CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) // Show messages has default, 0 = off, 1 = on CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -1274,6 +1275,7 @@ static valueenum_t Resamplers[] = static menuitem_t SoundItems[] = { { slider, "Sounds volume", {&snd_sfxvolume}, {0.0}, {1.0}, {0.05f}, {NULL} }, + { slider, "Menu volume", {&snd_menuvolume}, {0.0}, {1.0}, {0.05f}, {NULL} }, { slider, "Music volume", {&snd_musicvolume}, {0.0}, {1.0}, {0.05f}, {NULL} }, { discrete, "MIDI device", {&snd_mididevice}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, @@ -1304,7 +1306,7 @@ static menu_t SoundMenu = SoundItems, }; -#define MIDI_DEVICE_ITEM 2 +#define MIDI_DEVICE_ITEM 3 /*======================================= * @@ -1506,13 +1508,13 @@ void M_SizeDisplay (int diff) CCMD (sizedown) { M_SizeDisplay (-1); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } CCMD (sizeup) { M_SizeDisplay (1); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } // Draws a string in the console font, scaled to the 8x8 cells @@ -2186,7 +2188,7 @@ void M_OptResponder(event_t *ev) NewBits = BitTranslate[DummyDepthCvar]; setmodeneeded = true; testingmode = I_GetTime(false) + 5 * TICRATE; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewBits); } else if (ev->data1 >= '0' && ev->data1 <= '9') @@ -2291,7 +2293,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) CurrentMenu->items[CurrentItem].a.selmode = modecol; } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } break; @@ -2361,7 +2363,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (CurrentMenu->items[CurrentItem].type == screenres) CurrentMenu->items[CurrentItem].a.selmode = modecol; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } break; @@ -2383,7 +2385,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) { ++CurrentItem; } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } break; @@ -2406,7 +2408,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) { ++CurrentItem; } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); } break; @@ -2444,7 +2446,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) else item->a.cvar->SetGenericRep (newval, CVAR_Float); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_sens: @@ -2452,7 +2454,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (value.Float < item->b.min) value.Float = item->b.min; SELECTED_JOYSTICK->SetSensitivity(value.Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_slider: @@ -2485,12 +2487,12 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) { SELECTED_JOYSTICK->SetAxisDeadZone(item->a.joyselection, value.Float); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case palettegrid: SelColorIndex = (SelColorIndex - 1) & 15; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); break; case discretes: @@ -2535,14 +2537,14 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case ediscrete: value = item->a.cvar->GetGenericRep(CVAR_String); value.String = const_cast(M_FindPrevVal(value.String, item->e.enumvalues, (int)item->b.numvalues)); item->a.cvar->SetGenericRep(value, CVAR_String); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case bitmask: @@ -2561,21 +2563,21 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); item->a.cvar->SetGenericRep (value, CVAR_Int); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_inverter: assert(item->e.joyslidernum == 0); value.Float = SELECTED_JOYSTICK->GetAxisScale(item->a.joyselection); SELECTED_JOYSTICK->SetAxisScale(item->a.joyselection, -value.Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case screenres: @@ -2599,7 +2601,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) item->a.selmode = col; } } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); break; default: @@ -2641,7 +2643,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) else item->a.cvar->SetGenericRep (newval, CVAR_Float); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_sens: @@ -2649,7 +2651,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (value.Float > item->c.max) value.Float = item->c.max; SELECTED_JOYSTICK->SetSensitivity(value.Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_slider: @@ -2682,12 +2684,12 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) { SELECTED_JOYSTICK->SetAxisDeadZone(item->a.joyselection, value.Float); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case palettegrid: SelColorIndex = (SelColorIndex + 1) & 15; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); break; case discretes: @@ -2732,14 +2734,14 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case ediscrete: value = item->a.cvar->GetGenericRep(CVAR_String); value.String = const_cast(M_FindNextVal(value.String, item->e.enumvalues, (int)item->b.numvalues)); item->a.cvar->SetGenericRep(value, CVAR_String); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case bitmask: @@ -2758,21 +2760,21 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); item->a.cvar->SetGenericRep (value, CVAR_Int); } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case inverter: value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case joy_inverter: assert(item->e.joyslidernum == 0); value.Float = SELECTED_JOYSTICK->GetAxisScale(item->a.joyselection); SELECTED_JOYSTICK->SetAxisScale(item->a.joyselection, -value.Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); break; case screenres: @@ -2799,7 +2801,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) item->a.selmode = col; } } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); break; default: @@ -2829,7 +2831,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) setmodeneeded = true; NewBits = BitTranslate[DummyDepthCvar]; } - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewBits); } else if ((item->type == more || @@ -2841,7 +2843,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) && item->e.mfunc) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); if (item->type == safemore || item->type == rsafemore) { ActivateConfirm (item->label, item->e.mfunc); @@ -2876,7 +2878,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) if (item->e.values == Depths) BuildModesList (SCREENWIDTH, SCREENHEIGHT, DisplayBits); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } else if (item->type == control) { @@ -2889,7 +2891,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) else if (item->type == listelement) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); item->e.lfunc (CurrentItem); } else if (item->type == inverter) @@ -2897,14 +2899,14 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) value = item->a.cvar->GetGenericRep (CVAR_Float); value.Float = -value.Float; item->a.cvar->SetGenericRep (value, CVAR_Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } else if (item->type == joy_inverter) { assert(item->e.joyslidernum == 0); value.Float = SELECTED_JOYSTICK->GetAxisScale(item->a.joyselection); SELECTED_JOYSTICK->SetAxisScale(item->a.joyselection, -value.Float); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } else if (item->type == screenres) { @@ -2912,7 +2914,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) else if (item->type == colorpicker) { CurrentMenu->lastOn = CurrentItem; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", 1, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); StartColorPickerMenu (item->label, item->a.colorcvar); } else if (item->type == palettegrid) From 9102200771e16e7adc94cc9af973f3b53b49c704 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 26 Aug 2010 20:59:15 +0000 Subject: [PATCH 206/251] - added: Let the kill CCMD also kill replacements of the monster that is specified. - add a GetReplacement method to PClass to clean up some really ugly code - Who wrote the 'kill' CCMD? The way it checked if two classes were identical was horrendously overcomplicated. SVN r2601 (trunk) --- src/actor.h | 2 +- src/d_net.cpp | 29 ++++++++++++++++++++++------- src/dobjtype.cpp | 5 +++++ src/dobjtype.h | 1 + src/g_shared/a_randomspawner.cpp | 2 +- src/m_cheat.cpp | 4 ++-- src/p_acs.cpp | 2 +- src/p_map.cpp | 4 ++-- src/p_mobj.cpp | 6 +++--- src/p_things.cpp | 4 ++-- 10 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/actor.h b/src/actor.h index 68eda132b..15439e767 100644 --- a/src/actor.h +++ b/src/actor.h @@ -739,7 +739,7 @@ public: if (bloodcls != NULL) { - bloodcls = bloodcls->ActorInfo->GetReplacement()->Class; + bloodcls = bloodcls->GetReplacement(); } return bloodcls; } diff --git a/src/d_net.cpp b/src/d_net.cpp index 997919963..be592b238 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1917,6 +1917,22 @@ BYTE *FDynamicBuffer::GetData (int *len) } +static int KillAll(const PClass *cls) +{ + AActor *actor; + int killcount = 0; + TThinkerIterator iterator(cls); + while ( (actor = iterator.Next ()) ) + { + if (actor->IsA(cls)) + { + if (!(actor->flags2 & MF2_DORMANT) && (actor->flags3 & MF3_ISMONSTER)) + killcount += actor->Massacre (); + } + } + return killcount; + +} // [RH] Execute a special "ticcmd". The type byte should // have already been read, and the stream is positioned // at the beginning of the command's actual data. @@ -2348,18 +2364,17 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_KILLCLASSCHEAT: { - AActor *actor; - TThinkerIterator iterator; - char *classname = ReadString (stream); int killcount = 0; + const PClass *cls = PClass::FindClass(classname); - while ( (actor = iterator.Next ()) ) + if (classname != NULL) { - if (!stricmp (actor->GetClass ()->TypeName.GetChars (), classname)) + killcount = KillAll(cls); + const PClass *cls_rep = cls->GetReplacement(); + if (cls != cls_rep) { - if (!(actor->flags2 & MF2_DORMANT) && (actor->flags3 & MF3_ISMONSTER)) - killcount += actor->Massacre (); + killcount += KillAll(cls_rep); } } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index cdac25902..f232d81f2 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -486,6 +486,11 @@ const PClass *PClass::NativeClass() const return cls; } +PClass *PClass::GetReplacement() const +{ + return ActorInfo->GetReplacement()->Class; +} + // Symbol tables ------------------------------------------------------------ PSymbol::~PSymbol() diff --git a/src/dobjtype.h b/src/dobjtype.h index dd35e7e47..e01929901 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -174,6 +174,7 @@ struct PClass static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } static const PClass *FindClass (FName name); const PClass *FindClassTentative (FName name); // not static! + PClass *GetReplacement() const; static TArray m_Types; static TArray m_RuntimeActors; diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 67bd4b84a..4c1b5b964 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -71,7 +71,7 @@ class ARandomSpawner : public AActor cls = PClass::FindClass(di->Name); if (cls != NULL) { - const PClass *rep = cls->ActorInfo->GetReplacement()->Class; + const PClass *rep = cls->GetReplacement(); if (rep != NULL) { cls = rep; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 0a7928a91..9da1b1ff5 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -754,8 +754,8 @@ void cht_Give (player_t *player, const char *name, int amount) // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && - (type->ActorInfo->GetReplacement() == type->ActorInfo || - type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) + (type->GetReplacement() == type || + type->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { // Give the weapon only if it belongs to the current game or diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4aeb0595f..f04cfbdff 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2136,7 +2136,7 @@ do_count: { // Again, with decorate replacements replacemented = true; - PClass *newkind = kind->ActorInfo->GetReplacement()->Class; + PClass *newkind = kind->GetReplacement(); if (newkind != kind) { kind = newkind; diff --git a/src/p_map.cpp b/src/p_map.cpp index 2d105c284..06483c44e 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3352,7 +3352,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, (t1->player->ReadyWeapon->flags2 & MF2_THRUGHOST)); // We need to check the defaults of the replacement here - AActor *puffDefaults = GetDefaultByType(pufftype->ActorInfo->GetReplacement()->Class); + AActor *puffDefaults = GetDefaultByType(pufftype->GetReplacement()); // if the puff uses a non-standard damage type this will override default and melee damage type. // All other explicitly passed damage types (currenty only MDK) will be preserved. @@ -3819,7 +3819,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color int flags; AActor *puffDefaults = puffclass == NULL? - NULL : GetDefaultByType (puffclass->ActorInfo->GetReplacement()->Class); + NULL : GetDefaultByType (puffclass->GetReplacement()); if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) flags = 0; else flags = TRACE_PCross|TRACE_Impact; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 85ca7662e..9dfa8d5ca 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1011,7 +1011,7 @@ bool AActor::Grind(bool items) if (i != NULL) { - i = i->ActorInfo->GetReplacement()->Class; + i = i->GetReplacement(); const AActor *defaults = GetDefaultByType (i); if (defaults->SpawnState == NULL || @@ -3461,7 +3461,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t } if (allowreplacement) - type = type->ActorInfo->GetReplacement()->Class; + type = type->GetReplacement(); AActor *actor; @@ -4297,7 +4297,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) { // Handle decorate replacements explicitly here // to check for missing frames in the replacement object. - i = i->ActorInfo->GetReplacement()->Class; + i = i->GetReplacement(); const AActor *defaults = GetDefaultByType (i); if (defaults->SpawnState == NULL || diff --git a/src/p_things.cpp b/src/p_things.cpp index cd1540f4f..6622ac0a7 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -65,7 +65,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, return false; // Handle decorate replacements. - kind = kind->ActorInfo->GetReplacement()->Class; + kind = kind->GetReplacement(); if ((GetDefaultByType (kind)->flags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) @@ -200,7 +200,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam // Handle decorate replacements. - kind = kind->ActorInfo->GetReplacement()->Class; + kind = kind->GetReplacement(); defflags3 = GetDefaultByType (kind)->flags3; if ((defflags3 & MF3_ISMONSTER) && From 9a4abe0915c4146a572256fe0df3b6d00e5c4174 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Aug 2010 15:20:05 +0000 Subject: [PATCH 207/251] - merged automap branch into trunk. SVN r2609 (trunk) --- src/CMakeLists.txt | 1 + src/actor.h | 2 + src/am_map.cpp | 369 +++++---- src/am_map.h | 2 +- src/asm_ia32/tmap.asm | 76 +- src/c_bind.cpp | 932 ++++++++++++---------- src/c_bind.h | 60 +- src/c_dispatch.cpp | 11 +- src/c_dispatch.h | 5 +- src/cmdlib.cpp | 154 ++++ src/cmdlib.h | 8 + src/d_main.cpp | 26 + src/f_finale.cpp | 2 +- src/g_game.cpp | 14 +- src/g_level.cpp | 2 +- src/gameconfigfile.cpp | 41 +- src/m_menu.h | 1 + src/m_options.cpp | 80 +- src/namedef.h | 1 + src/nodebuild.h | 16 +- src/nodebuild_extract.cpp | 47 +- src/p_acs.cpp | 2 +- src/p_glnodes.cpp | 1537 ++++++++++++++++++++++++++++++++++++ src/p_local.h | 3 +- src/p_maputl.cpp | 5 +- src/p_mobj.cpp | 16 +- src/p_saveg.cpp | 106 +++ src/p_saveg.h | 1 + src/p_setup.cpp | 133 +++- src/p_setup.h | 8 + src/p_udmf.cpp | 4 + src/po_man.cpp | 6 - src/r_bsp.cpp | 80 +- src/r_defs.h | 18 +- src/r_draw.cpp | 71 ++ src/r_draw.h | 5 +- src/r_plane.cpp | 15 +- src/r_plane.h | 1 - src/r_polymost.cpp | 2 +- src/r_state.h | 7 + src/v_draw.cpp | 172 +++- src/v_video.h | 6 + src/win32/fb_d3d9.cpp | 177 ++++- src/win32/fb_d3d9_wipe.cpp | 4 +- src/win32/win32iface.h | 13 +- wadsrc/static/language.enu | 2 + zdoom.vcproj | 4 + 47 files changed, 3497 insertions(+), 751 deletions(-) create mode 100644 src/p_glnodes.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fadf0b2d..6906bec5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -679,6 +679,7 @@ add_executable( zdoom WIN32 p_effect.cpp p_enemy.cpp p_floor.cpp + p_glnodes.cpp p_interaction.cpp p_lights.cpp p_linkedsectors.cpp diff --git a/src/actor.h b/src/actor.h index 15439e767..2a8921b56 100644 --- a/src/actor.h +++ b/src/actor.h @@ -40,6 +40,7 @@ #include "r_blend.h" #include "s_sound.h" +struct subsector_t; // // NOTES: AActor // @@ -773,6 +774,7 @@ public: fixed_t pitch, roll; FBlockNode *BlockNode; // links in blocks (if needed) struct sector_t *Sector; + subsector_t * subsector; fixed_t floorz, ceilingz; // closest together of contacted secs fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. diff --git a/src/am_map.cpp b/src/am_map.cpp index 9dccdf2c0..63d328c64 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -36,6 +36,9 @@ #include "r_translate.h" #include "d_event.h" #include "gi.h" +#include "r_bsp.h" +#include "p_setup.h" +#include "c_bind.h" #include "m_cheat.h" #include "i_system.h" @@ -183,6 +186,14 @@ CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE); +static int bigstate = 0; +static bool textured = 1; // internal toggle for texture mode + +CUSTOM_CVAR(Bool, am_textured, false, CVAR_ARCHIVE) +{ + textured |= self; +} + CVAR(Int, am_showsubsector, -1, 0); @@ -225,21 +236,6 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it. } -// drawing stuff -#define AM_PANDOWNKEY KEY_DOWNARROW -#define AM_PANUPKEY KEY_UPARROW -#define AM_PANRIGHTKEY KEY_RIGHTARROW -#define AM_PANLEFTKEY KEY_LEFTARROW -#define AM_ZOOMINKEY KEY_EQUALS -#define AM_ZOOMINKEY2 0x4e // DIK_ADD -#define AM_ZOOMOUTKEY KEY_MINUS -#define AM_ZOOMOUTKEY2 0x4a // DIK_SUBTRACT -#define AM_GOBIGKEY 0x0b // DIK_0 -#define AM_FOLLOWKEY 'f' -#define AM_GRIDKEY 'g' -#define AM_MARKKEY 'm' -#define AM_CLEARMARKKEY 'c' - #define AM_NUMMARKPOINTS 10 // player radius for automap checking @@ -417,7 +413,6 @@ static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) -static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords) static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) @@ -466,7 +461,69 @@ static void AM_calcMinMaxMtoF(); void AM_rotatePoint (fixed_t *x, fixed_t *y); void AM_rotate (fixed_t *x, fixed_t *y, angle_t an); void AM_doFollowPlayer (); -static void AM_ToggleFollowPlayer(); + + +//============================================================================= +// +// map functions +// +//============================================================================= +bool AM_addMark (); +bool AM_clearMarks (); +void AM_saveScaleAndLoc (); +void AM_restoreScaleAndLoc (); +void AM_minOutWindowScale (); + + +CCMD(am_togglefollow) +{ + followplayer = !followplayer; + f_oldloc.x = FIXED_MAX; + Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); +} + +CCMD(am_togglegrid) +{ + grid = !grid; + Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF")); +} + +CCMD(am_toggletexture) +{ + if (am_textured && hasglnodes) + { + textured = !textured; + Printf ("%s\n", GStrings(textured ? "AMSTR_TEXON" : "AMSTR_TEXOFF")); + } +} + +CCMD(am_setmark) +{ + if (AM_addMark()) + { + Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum); + } +} + +CCMD(am_clearmarks) +{ + if (AM_clearMarks()) + { + Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED")); + } +} + +CCMD(am_gobig) +{ + bigstate = !bigstate; + if (bigstate) + { + AM_saveScaleAndLoc(); + AM_minOutWindowScale(); + } + else + AM_restoreScaleAndLoc(); +} // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so @@ -775,11 +832,19 @@ void AM_initVariables () automapactive = true; + // Reset AM buttons + Button_AM_PanLeft.Reset(); + Button_AM_PanRight.Reset(); + Button_AM_PanUp.Reset(); + Button_AM_PanDown.Reset(); + Button_AM_ZoomIn.Reset(); + Button_AM_ZoomOut.Reset(); + + f_oldloc.x = FIXED_MAX; amclock = 0; m_paninc.x = m_paninc.y = 0; - ftom_zoommul = MAPUNIT; mtof_zoommul = MAPUNIT; m_w = FTOM(SCREENWIDTH); @@ -1158,127 +1223,28 @@ void AM_ToggleMap () // //============================================================================= -bool AM_Responder (event_t *ev) +bool AM_Responder (event_t *ev, bool last) { - bool rc; - static int cheatstate = 0; - static int bigstate = 0; - - rc = false; - - if (automapactive && ev->type == EV_KeyDown) + if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) { - rc = true; - switch (ev->data1) + if (followplayer) { - case AM_PANRIGHTKEY: // pan right - if (!followplayer) - m_paninc.x = FTOM(F_PANINC); - else - rc = false; - break; - case AM_PANLEFTKEY: // pan left - if (!followplayer) - m_paninc.x = -FTOM(F_PANINC); - else - rc = false; - break; - case AM_PANUPKEY: // pan up - if (!followplayer) - m_paninc.y = FTOM(F_PANINC); - else - rc = false; - break; - case AM_PANDOWNKEY: // pan down - if (!followplayer) - m_paninc.y = -FTOM(F_PANINC); - else - rc = false; - break; - case AM_ZOOMOUTKEY: // zoom out - case AM_ZOOMOUTKEY2: - mtof_zoommul = M_ZOOMOUT; - ftom_zoommul = M_ZOOMIN; - break; - case AM_ZOOMINKEY: // zoom in - case AM_ZOOMINKEY2: - mtof_zoommul = M_ZOOMIN; - ftom_zoommul = M_ZOOMOUT; - break; - case AM_GOBIGKEY: - bigstate = !bigstate; - if (bigstate) - { - AM_saveScaleAndLoc(); - AM_minOutWindowScale(); - } - else - AM_restoreScaleAndLoc(); - break; - default: - switch (ev->data2) - { - case AM_FOLLOWKEY: - AM_ToggleFollowPlayer(); - break; - case AM_GRIDKEY: - grid = !grid; - Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF")); - break; - case AM_MARKKEY: - if (AM_addMark()) - { - Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum); - } - else - { - rc = false; - } - break; - case AM_CLEARMARKKEY: - if (AM_clearMarks()) - { - Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED")); - } - else - { - rc = false; - } - break; - default: - cheatstate = 0; - rc = false; - } + // check for am_pan* and ignore in follow mode + const char *defbind = AutomapBindings.GetBind(ev->data1); + if (!strnicmp(defbind, "+am_pan", 7)) return false; } - } - else if (ev->type == EV_KeyUp) - { - rc = false; - switch (ev->data1) - { - case AM_PANRIGHTKEY: - if (!followplayer) m_paninc.x = 0; - break; - case AM_PANLEFTKEY: - if (!followplayer) m_paninc.x = 0; - break; - case AM_PANUPKEY: - if (!followplayer) m_paninc.y = 0; - break; - case AM_PANDOWNKEY: - if (!followplayer) m_paninc.y = 0; - break; - case AM_ZOOMOUTKEY: - case AM_ZOOMOUTKEY2: - case AM_ZOOMINKEY: - case AM_ZOOMINKEY2: - mtof_zoommul = MAPUNIT; - ftom_zoommul = MAPUNIT; - break; - } - } - return rc; + bool res = C_DoKey(ev, &AutomapBindings, NULL); + if (res && ev->type == EV_KeyUp && !last) + { + // If this is a release event we also need to check if it released a button in the main Bindings + // so that that button does not get stuck. + const char *defbind = Bindings.GetBind(ev->data1); + return (defbind[0] != '+'); // Let G_Responder handle button releases + } + return res; + } + return false; } @@ -1290,6 +1256,11 @@ bool AM_Responder (event_t *ev) void AM_changeWindowScale () { + int mtof_zoommul; + + if (Button_AM_ZoomIn.bDown) mtof_zoommul = M_ZOOMIN; + else if (Button_AM_ZoomOut.bDown) mtof_zoommul = M_ZOOMOUT; + // Change the scaling multipliers scale_mtof = MapMul(scale_mtof, mtof_zoommul); scale_ftom = MapDiv(MAPUNIT, scale_mtof); @@ -1334,19 +1305,6 @@ void AM_doFollowPlayer () } } -//============================================================================= -// -// -// -//============================================================================= - -static void AM_ToggleFollowPlayer() -{ - followplayer = !followplayer; - f_oldloc.x = FIXED_MAX; - Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); -} - //============================================================================= // // Updates on Game Tick @@ -1361,10 +1319,20 @@ void AM_Ticker () amclock++; if (followplayer) + { AM_doFollowPlayer(); + } + else + { + m_paninc.x = m_paninc.y = 0; + if (Button_AM_PanLeft.bDown) m_paninc.x -= FTOM(F_PANINC); + if (Button_AM_PanRight.bDown) m_paninc.x += FTOM(F_PANINC); + if (Button_AM_PanUp.bDown) m_paninc.y += FTOM(F_PANINC); + if (Button_AM_PanDown.bDown) m_paninc.y -= FTOM(F_PANINC); + } // Change the zoom if necessary - if (ftom_zoommul != MAPUNIT) + if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown) AM_changeWindowScale(); // Change x,y location @@ -1622,6 +1590,92 @@ void AM_drawGrid (const AMColor &color) } } +//============================================================================= +// +// AM_drawSubsectors +// +//============================================================================= + +void AM_drawSubsectors() +{ + static TArray points; + float scale = float(scale_mtof); + angle_t rotation; + sector_t tempsec; + int floorlight, ceilinglight; + double originx, originy; + FDynamicColormap *colormap; + + + for (int i = 0; i < numsubsectors; ++i) + { + if ((!(subsectors[i].flags & SSECF_DRAWN) || (subsectors[i].render_sector->MoreFlags & SECF_HIDDEN)) && am_cheat == 0) + { + continue; + } + // Fill the points array from the subsector. + points.Resize(subsectors[i].numlines); + for (DWORD j = 0; j < subsectors[i].numlines; ++j) + { + mpoint_t pt = { subsectors[i].firstline[j].v1->x >> FRACTOMAPBITS, + subsectors[i].firstline[j].v1->y >> FRACTOMAPBITS }; + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + AM_rotatePoint(&pt.x, &pt.y); + } + points[j].X = f_x + ((pt.x - m_x) * scale / float(1 << 24)); + points[j].Y = f_y + (f_h - (pt.y - m_y) * scale / float(1 << 24)); + } + // For lighting and texture determination + sector_t *sec = R_FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight, + &ceilinglight, false); + // Find texture origin. + mpoint_t originpt = { -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS, + sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS }; + rotation = 0 - sec->GetAngle(sector_t::floor); + // Apply the floor's rotation to the texture origin. + if (rotation != 0) + { + AM_rotate(&originpt.x, &originpt.y, rotation); + } + // Apply the automap's rotation to the texture origin. + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + rotation += ANG90 - players[consoleplayer].camera->angle; + AM_rotatePoint(&originpt.x, &originpt.y); + } + originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24)); + originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24)); + // Coloring for the polygon + colormap = sec->ColorMap; + // If this subsector has not actually been seen yet (because you are cheating + // to see it on the map), tint and desaturate it. + if (!(subsectors[i].flags & SSECF_DRAWN)) + { + colormap = GetSpecialLights( + MAKERGB( + (colormap->Color.r + 255) / 2, + (colormap->Color.g + 200) / 2, + (colormap->Color.b + 160) / 2), + colormap->Fade, + 255 - (255 - colormap->Desaturate) / 4); + floorlight = (floorlight + 200*15) / 16; + } + + // Draw the polygon. + screen->FillSimplePoly( + TexMan(sec->GetTexture(sector_t::floor)), + &points[0], points.Size(), + originx, originy, + scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)), + scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)), + rotation, + colormap, + floorlight + ); + } +} + //============================================================================= // // @@ -2232,11 +2286,19 @@ void AM_drawAuthorMarkers () while (marked != NULL) { - if (mark->args[1] == 0 || (mark->args[1] == 1 && marked->Sector->MoreFlags & SECF_DRAWN)) + if (mark->args[1] == 0 || (mark->args[1] == 1)) { - DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, - flip, mark->scaleX, mark->scaleY, mark->Translation, - mark->alpha, mark->fillcolor, mark->RenderStyle); + // Use more correct info if we have GL nodes available + INTBOOL drawn = hasglnodes? + marked->subsector->flags & SSECF_DRAWN : + marked->Sector->MoreFlags & SECF_DRAWN; + + if (drawn) + { + DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, + flip, mark->scaleX, mark->scaleY, mark->Translation, + mark->alpha, mark->fillcolor, mark->RenderStyle); + } } marked = mark->args[0] != 0 ? it.Next() : NULL; } @@ -2291,6 +2353,9 @@ void AM_Drawer () } AM_activateNewScale(); + if (am_textured && hasglnodes && textured) + AM_drawSubsectors(); + if (grid) AM_drawGrid(GridColor); diff --git a/src/am_map.h b/src/am_map.h index 71740b9a7..20da6b96b 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -26,7 +26,7 @@ struct event_t; class FArchive; // Called by main loop. -bool AM_Responder (event_t* ev); +bool AM_Responder (event_t* ev, bool last); // Called by main loop. void AM_Ticker (void); diff --git a/src/asm_ia32/tmap.asm b/src/asm_ia32/tmap.asm index e9713131f..cbcd9f4f1 100644 --- a/src/asm_ia32/tmap.asm +++ b/src/asm_ia32/tmap.asm @@ -309,6 +309,8 @@ GLOBAL R_DrawSpanP_ASM ; edi: dest ; ebp: scratch ; esi: count +; [esp]: xstep +; [esp+4]: ystep align 16 @@ -324,6 +326,7 @@ R_DrawSpanP_ASM: push edi push ebp push esi + sub esp, 8 mov edi,ecx add edi,[dc_destorg] @@ -335,13 +338,13 @@ dsy1: shl edx,6 dsy3: shr ebp,26 xor ebx,ebx lea esi,[eax+1] - mov [ds_xstep],edx + mov [esp],edx mov edx,[ds_ystep] mov ecx,[ds_xfrac] dsy4: shr ecx,26 dsm8: and edx,0xffffffc0 or ebp,edx - mov [ds_ystep],ebp + mov [esp+4],ebp mov ebp,[ds_yfrac] mov edx,[ds_xfrac] dsy2: shl edx,6 @@ -355,8 +358,8 @@ dsm9: and ebp,0xffffffc0 mov ebp,ecx dsx1: rol ebp,6 dsm1: and ebp,0xfff - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] spreada mov bl,[ebp+SPACEFILLER4] spmapa mov bl,[ebx+SPACEFILLER4] mov [edi],bl @@ -367,13 +370,13 @@ dseven1 shr esi,1 ; do two more pixels mov ebp,ecx - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] dsm2: and ebp,0xfc00003f dsx2: rol ebp,6 mov eax,ecx - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] spreadb mov bl,[ebp+SPACEFILLER4] ;read texel1 dsx3: rol eax,6 dsm6: and eax,0xfff @@ -392,13 +395,13 @@ dsrest test esi,esi align 16 dsloop mov ebp,ecx -spstep1d add edx,[ds_xstep] -spstep2d adc ecx,[ds_ystep] +spstep1d add edx,[esp] +spstep2d adc ecx,[esp+4] dsm3: and ebp,0xfc00003f dsx4: rol ebp,6 mov eax,ecx -spstep1e add edx,[ds_xstep] -spstep2e adc ecx,[ds_ystep] +spstep1e add edx,[esp] +spstep2e adc ecx,[esp+4] spreadd mov bl,[ebp+SPACEFILLER4] ;read texel1 dsx5: rol eax,6 dsm5: and eax,0xfff @@ -406,8 +409,8 @@ spmapd mov bl,[ebx+SPACEFILLER4] ;map texel1 mov [edi],bl ;store texel1 mov ebp,ecx spreade mov bl,[eax+SPACEFILLER4] ;read texel2 -spstep1f add edx,[ds_xstep] -spstep2f adc ecx,[ds_ystep] +spstep1f add edx,[esp] +spstep2f adc ecx,[esp+4] dsm4: and ebp,0xfc00003f dsx6: rol ebp,6 spmape mov bl,[ebx+SPACEFILLER4] ;map texel2 @@ -420,14 +423,15 @@ dsx7: rol eax,6 dsm7: and eax,0xfff mov [edi-2],bl ;store texel3 spreadg mov bl,[eax+SPACEFILLER4] ;read texel4 -spstep1g add edx,[ds_xstep] -spstep2g adc ecx,[ds_ystep] +spstep1g add edx,[esp] +spstep2g adc ecx,[esp+4] spmapg mov bl,[ebx+SPACEFILLER4] ;map texel4 dec esi mov [edi-1],bl ;store texel4 jnz near dsloop -dsdone pop esi +dsdone add esp,8 + pop esi pop ebp pop edi pop ebx @@ -448,6 +452,8 @@ GLOBAL R_DrawSpanMaskedP_ASM ; edi: dest ; ebp: scratch ; esi: count +; [esp]: xstep +; [esp+4]: ystep align 16 @@ -463,6 +469,7 @@ R_DrawSpanMaskedP_ASM: push edi push ebp push esi + sub esp,8 mov edi,ecx add edi,[dc_destorg] @@ -474,13 +481,13 @@ dmsy1: shl edx,6 dmsy3: shr ebp,26 xor ebx,ebx lea esi,[eax+1] - mov [ds_xstep],edx + mov [esp],edx mov edx,[ds_ystep] mov ecx,[ds_xfrac] dmsy4: shr ecx,26 dmsm8: and edx,0xffffffc0 or ebp,edx - mov [ds_ystep],ebp + mov [esp+4],ebp mov ebp,[ds_yfrac] mov edx,[ds_xfrac] dmsy2: shl edx,6 @@ -494,8 +501,8 @@ dmsm9: and ebp,0xffffffc0 mov ebp,ecx dmsx1: rol ebp,6 dmsm1: and ebp,0xfff - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] mspreada mov bl,[ebp+SPACEFILLER4] cmp bl,0 je mspskipa @@ -508,13 +515,13 @@ dmseven1 shr esi,1 ; do two more pixels mov ebp,ecx - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] dmsm2: and ebp,0xfc00003f dmsx2: rol ebp,6 mov eax,ecx - add edx,[ds_xstep] - adc ecx,[ds_ystep] + add edx,[esp] + adc ecx,[esp+4] mspreadb mov bl,[ebp+SPACEFILLER4] ;read texel1 dmsx3: rol eax,6 dmsm6: and eax,0xfff @@ -537,13 +544,13 @@ dmsrest test esi,esi align 16 dmsloop mov ebp,ecx -mspstep1d add edx,[ds_xstep] -mspstep2d adc ecx,[ds_ystep] +mspstep1d add edx,[esp] +mspstep2d adc ecx,[esp+4] dmsm3: and ebp,0xfc00003f dmsx4: rol ebp,6 mov eax,ecx -mspstep1e add edx,[ds_xstep] -mspstep2e adc ecx,[ds_ystep] +mspstep1e add edx,[esp] +mspstep2e adc ecx,[esp+4] mspreadd mov bl,[ebp+SPACEFILLER4] ;read texel1 dmsx5: rol eax,6 dmsm5: and eax,0xfff @@ -553,8 +560,8 @@ dmsm5: and eax,0xfff mspmapd mov bl,[ebx+SPACEFILLER4] ;map texel1 mov [edi],bl ;store texel1 mspreade mov bl,[eax+SPACEFILLER4] ;read texel2 -mspstep1f add edx,[ds_xstep] -mspstep2f adc ecx,[ds_ystep] +mspstep1f add edx,[esp] +mspstep2f adc ecx,[esp+4] dmsm4: and ebp,0xfc00003f dmsx6: rol ebp,6 cmp bl,0 @@ -571,8 +578,8 @@ dmsm7: and eax,0xfff mspmapf mov bl,[ebx+SPACEFILLER4] ;map texel3 mov [edi-2],bl ;store texel3 mspreadg mov bl,[eax+SPACEFILLER4] ;read texel4 -mspstep1g add edx,[ds_xstep] -mspstep2g adc ecx,[ds_ystep] +mspstep1g add edx,[esp] +mspstep2g adc ecx,[esp+4] cmp bl,0 je mspskipg mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4 @@ -580,7 +587,8 @@ mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4 mspskipg dec esi jnz near dmsloop -dmsdone pop esi +dmsdone add esp,8 + pop esi pop ebp pop edi pop ebx diff --git a/src/c_bind.cpp b/src/c_bind.cpp index d96b5a742..6afb0c677 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -47,12 +47,6 @@ #include #include -struct FBinding -{ - const char *Key; - const char *Bind; -}; - /* Default keybindings for Doom (and all other games) */ static const FBinding DefBindings[] = @@ -178,6 +172,27 @@ static const FBinding DefStrifeBindings[] = // h - use health }; +static const FBinding DefAutomapBindings[] = +{ + { "f", "am_togglefollow" }, + { "g", "am_togglegrid" }, + { "t", "am_toggletexture" }, + { "m", "am_setmark" }, + { "c", "am_clearmarks" }, + { "0", "am_gobig" }, + { "rightarrow", "+am_panright" }, + { "leftarrow", "+am_panleft" }, + { "uparrow", "+am_panup" }, + { "downarrow", "+am_pandown" }, + { "-", "+am_zoomout" }, + { "=", "+am_zoomin" }, + { "kp-", "+am_zoomout" }, + { "kp+", "+am_zoomin" }, + { NULL } +}; + + + const char *KeyNames[NUM_KEYS] = { // This array is dependant on the particular keyboard input @@ -278,11 +293,19 @@ const char *KeyNames[NUM_KEYS] = "pad_a", "pad_b", "pad_x", "pad_y" }; -static FString Bindings[NUM_KEYS]; -static FString DoubleBindings[NUM_KEYS]; +FKeyBindings Bindings; +FKeyBindings DoubleBindings; +FKeyBindings AutomapBindings; + static unsigned int DClickTime[NUM_KEYS]; static BYTE DClicked[(NUM_KEYS+7)/8]; +//============================================================================= +// +// +// +//============================================================================= + static int GetKeyFromName (const char *name) { int i; @@ -302,380 +325,15 @@ static int GetKeyFromName (const char *name) return 0; } -static const char *KeyName (int key) -{ - static char name[5]; - - if (KeyNames[key]) - return KeyNames[key]; - - mysnprintf (name, countof(name), "#%d", key); - return name; -} - -void C_UnbindAll () -{ - for (int i = 0; i < NUM_KEYS; ++i) - { - Bindings[i] = ""; - DoubleBindings[i] = ""; - } -} - -CCMD (unbindall) -{ - C_UnbindAll (); -} - -CCMD (unbind) -{ - int i; - - if (argv.argc() > 1) - { - if ( (i = GetKeyFromName (argv[1])) ) - { - Bindings[i] = ""; - } - else - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - - } -} - -CCMD (bind) -{ - int i; - - if (argv.argc() > 1) - { - i = GetKeyFromName (argv[1]); - if (!i) - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - if (argv.argc() == 2) - { - Printf ("\"%s\" = \"%s\"\n", argv[1], Bindings[i].GetChars()); - } - else - { - Bindings[i] = argv[2]; - } - } - else - { - Printf ("Current key bindings:\n"); - - for (i = 0; i < NUM_KEYS; i++) - { - if (!Bindings[i].IsEmpty()) - Printf ("%s \"%s\"\n", KeyName (i), Bindings[i].GetChars()); - } - } -} - -//========================================================================== +//============================================================================= // -// CCMD defaultbind // -// Binds a command to a key if that key is not already bound and if -// that command is not already bound to another key. // -//========================================================================== +//============================================================================= -CCMD (defaultbind) +static int GetConfigKeyFromName (const char *key) { - if (argv.argc() < 3) - { - Printf ("Usage: defaultbind \n"); - } - else - { - int key = GetKeyFromName (argv[1]); - if (key == 0) - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - if (!Bindings[key].IsEmpty()) - { // This key is already bound. - return; - } - for (int i = 0; i < NUM_KEYS; ++i) - { - if (!Bindings[i].IsEmpty() && stricmp (Bindings[i], argv[2]) == 0) - { // This command is already bound to a key. - return; - } - } - // It is safe to do the bind, so do it. - Bindings[key] = argv[2]; - } -} - -CCMD (undoublebind) -{ - int i; - - if (argv.argc() > 1) - { - if ( (i = GetKeyFromName (argv[1])) ) - { - DoubleBindings[i] = ""; - } - else - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - - } -} - -CCMD (doublebind) -{ - int i; - - if (argv.argc() > 1) - { - i = GetKeyFromName (argv[1]); - if (!i) - { - Printf ("Unknown key \"%s\"\n", argv[1]); - return; - } - if (argv.argc() == 2) - { - Printf ("\"%s\" = \"%s\"\n", argv[1], DoubleBindings[i].GetChars()); - } - else - { - DoubleBindings[i] = argv[2]; - } - } - else - { - Printf ("Current key doublebindings:\n"); - - for (i = 0; i < NUM_KEYS; i++) - { - if (!DoubleBindings[i].IsEmpty()) - Printf ("%s \"%s\"\n", KeyName (i), DoubleBindings[i].GetChars()); - } - } -} - -CCMD (rebind) -{ - FString *bindings; - - if (key == 0) - { - Printf ("Rebind cannot be used from the console\n"); - return; - } - - if (key & KEY_DBLCLICKED) - { - bindings = DoubleBindings; - key &= KEY_DBLCLICKED-1; - } - else - { - bindings = Bindings; - } - - if (argv.argc() > 1) - { - bindings[key] = argv[1]; - } -} - -static void SetBinds (const FBinding *array) -{ - while (array->Key) - { - C_DoBind (array->Key, array->Bind, false); - array++; - } -} - -void C_BindDefaults () -{ - SetBinds (DefBindings); - - if (gameinfo.gametype & (GAME_Raven|GAME_Strife)) - { - SetBinds (DefRavenBindings); - } - - if (gameinfo.gametype == GAME_Heretic) - { - SetBinds (DefHereticBindings); - } - - if (gameinfo.gametype == GAME_Hexen) - { - SetBinds (DefHexenBindings); - } - - if (gameinfo.gametype == GAME_Strife) - { - SetBinds (DefStrifeBindings); - } -} - -CCMD(binddefaults) -{ - C_BindDefaults (); -} - -void C_SetDefaultBindings () -{ - C_UnbindAll (); - C_BindDefaults (); -} - -bool C_DoKey (event_t *ev) -{ - FString binding; - bool dclick; - int dclickspot; - BYTE dclickmask; - - if (ev->type != EV_KeyDown && ev->type != EV_KeyUp) - return false; - - if ((unsigned int)ev->data1 >= NUM_KEYS) - return false; - - dclickspot = ev->data1 >> 3; - dclickmask = 1 << (ev->data1 & 7); - dclick = false; - - // This used level.time which didn't work outside a level. - if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown) - { - // Key pressed for a double click - binding = DoubleBindings[ev->data1]; - DClicked[dclickspot] |= dclickmask; - dclick = true; - } - else - { - if (ev->type == EV_KeyDown) - { // Key pressed for a normal press - binding = Bindings[ev->data1]; - DClickTime[ev->data1] = I_MSTime() + 571; - } - else if (DClicked[dclickspot] & dclickmask) - { // Key released from a double click - binding = DoubleBindings[ev->data1]; - DClicked[dclickspot] &= ~dclickmask; - DClickTime[ev->data1] = 0; - dclick = true; - } - else - { // Key released from a normal press - binding = Bindings[ev->data1]; - } - } - - - if (binding.IsEmpty()) - { - binding = Bindings[ev->data1]; - dclick = false; - } - - if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256)) - { - if (ev->type == EV_KeyUp && binding[0] != '+') - { - return false; - } - - char *copy = binding.LockBuffer(); - - if (ev->type == EV_KeyUp) - { - copy[0] = '-'; - } - - AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1); - return true; - } - return false; -} - -const char *C_ConfigKeyName(int keynum) -{ - const char *name = KeyName(keynum); - if (name[1] == 0) // Make sure given name is config-safe - { - if (name[0] == '[') - return "LeftBracket"; - else if (name[0] == ']') - return "RightBracket"; - else if (name[0] == '=') - return "Equals"; - else if (strcmp (name, "kp=") == 0) - return "KP-Equals"; - } - return name; -} - -// This function is first called for functions in custom key sections. -// In this case, matchcmd is non-NULL, and only keys bound to that command -// are stored. If a match is found, its binding is set to "\1". -// After all custom key sections are saved, it is called one more for the -// normal Bindings and DoubleBindings sections for this game. In this case -// matchcmd is NULL and all keys will be stored. The config section was not -// previously cleared, so all old bindings are still in place. If the binding -// for a key is empty, the corresponding key in the config is removed as well. -// If a binding is "\1", then the binding itself is cleared, but nothing -// happens to the entry in the config. -void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd) -{ - FString *bindings; - int i; - - bindings = dodouble ? DoubleBindings : Bindings; - - for (i = 0; i < NUM_KEYS; i++) - { - if (bindings[i].IsEmpty()) - { - if (matchcmd == NULL) - { - f->ClearKey(C_ConfigKeyName(i)); - } - } - else if (matchcmd == NULL || stricmp(bindings[i], matchcmd) == 0) - { - if (bindings[i][0] == '\1') - { - bindings[i] = ""; - continue; - } - f->SetValueForKey(C_ConfigKeyName(i), bindings[i]); - if (matchcmd != NULL) - { // If saving a specific command, set a marker so that - // it does not get saved in the general binding list. - bindings[i] = "\1"; - } - } - } -} - -void C_DoBind (const char *key, const char *bind, bool dodouble) -{ - int keynum = GetKeyFromName (key); + int keynum = GetKeyFromName(key); if (keynum == 0) { if (stricmp (key, "LeftBracket") == 0) @@ -695,32 +353,55 @@ void C_DoBind (const char *key, const char *bind, bool dodouble) keynum = GetKeyFromName ("kp="); } } - if (keynum != 0) - { - (dodouble ? DoubleBindings : Bindings)[keynum] = bind; - } + return keynum; } -int C_GetKeysForCommand (char *cmd, int *first, int *second) +//============================================================================= +// +// +// +//============================================================================= + +static const char *KeyName (int key) { - int c, i; + static char name[5]; - *first = *second = c = i = 0; + if (KeyNames[key]) + return KeyNames[key]; - while (i < NUM_KEYS && c < 2) - { - if (stricmp (cmd, Bindings[i]) == 0) - { - if (c++ == 0) - *first = i; - else - *second = i; - } - i++; - } - return c; + mysnprintf (name, countof(name), "#%d", key); + return name; } +//============================================================================= +// +// +// +//============================================================================= + +static const char *ConfigKeyName(int keynum) +{ + const char *name = KeyName(keynum); + if (name[1] == 0) // Make sure given name is config-safe + { + if (name[0] == '[') + return "LeftBracket"; + else if (name[0] == ']') + return "RightBracket"; + else if (name[0] == '=') + return "Equals"; + else if (strcmp (name, "kp=") == 0) + return "KP-Equals"; + } + return name; +} + +//============================================================================= +// +// +// +//============================================================================= + void C_NameKeys (char *str, int first, int second) { int c = 0; @@ -744,28 +425,471 @@ void C_NameKeys (char *str, int first, int second) *str = '\0'; } -void C_UnbindACommand (char *str) +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::DoBind (const char *key, const char *bind) +{ + int keynum = GetConfigKeyFromName (key); + if (keynum != 0) + { + Binds[keynum] = bind; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::SetBinds(const FBinding *binds) +{ + while (binds->Key) + { + DoBind (binds->Key, binds->Bind); + binds++; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindAll () +{ + for (int i = 0; i < NUM_KEYS; ++i) + { + Binds[i] = ""; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindKey(const char *key) +{ + int i; + + if ( (i = GetKeyFromName (key)) ) + { + Binds[i] = ""; + } + else + { + Printf ("Unknown key \"%s\"\n", key); + return; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::PerformBind(FCommandLine &argv, const char *msg) +{ + int i; + + if (argv.argc() > 1) + { + i = GetKeyFromName (argv[1]); + if (!i) + { + Printf ("Unknown key \"%s\"\n", argv[1]); + return; + } + if (argv.argc() == 2) + { + Printf ("\"%s\" = \"%s\"\n", argv[1], Binds[i].GetChars()); + } + else + { + Binds[i] = argv[2]; + } + } + else + { + Printf ("%s:\n", msg); + + for (i = 0; i < NUM_KEYS; i++) + { + if (!Binds[i].IsEmpty()) + Printf ("%s \"%s\"\n", KeyName (i), Binds[i].GetChars()); + } + } +} + + +//============================================================================= +// +// This function is first called for functions in custom key sections. +// In this case, matchcmd is non-NULL, and only keys bound to that command +// are stored. If a match is found, its binding is set to "\1". +// After all custom key sections are saved, it is called one more for the +// normal Bindings and DoubleBindings sections for this game. In this case +// matchcmd is NULL and all keys will be stored. The config section was not +// previously cleared, so all old bindings are still in place. If the binding +// for a key is empty, the corresponding key in the config is removed as well. +// If a binding is "\1", then the binding itself is cleared, but nothing +// happens to the entry in the config. +// +//============================================================================= + +void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd) { int i; for (i = 0; i < NUM_KEYS; i++) { - if (!stricmp (str, Bindings[i])) + if (Binds[i].IsEmpty()) { - Bindings[i] = ""; + if (matchcmd == NULL) + { + f->ClearKey(ConfigKeyName(i)); + } + } + else if (matchcmd == NULL || stricmp(Binds[i], matchcmd) == 0) + { + if (Binds[i][0] == '\1') + { + Binds[i] = ""; + continue; + } + f->SetValueForKey(ConfigKeyName(i), Binds[i]); + if (matchcmd != NULL) + { // If saving a specific command, set a marker so that + // it does not get saved in the general binding list. + Binds[i] = "\1"; + } } } } -void C_ChangeBinding (const char *str, int newone) +//============================================================================= +// +// +// +//============================================================================= + +int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second) { - if ((unsigned int)newone < NUM_KEYS) + int c, i; + + *first = *second = c = i = 0; + + while (i < NUM_KEYS && c < 2) { - Bindings[newone] = str; + if (stricmp (cmd, Binds[i]) == 0) + { + if (c++ == 0) + *first = i; + else + *second = i; + } + i++; + } + return c; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::UnbindACommand (char *str) +{ + int i; + + for (i = 0; i < NUM_KEYS; i++) + { + if (!stricmp (str, Binds[i])) + { + Binds[i] = ""; + } } } -const char *C_GetBinding (int key) +//============================================================================= +// +// +// +//============================================================================= + +void FKeyBindings::DefaultBind(const char *keyname, const char *cmd) { - return (unsigned int)key < NUM_KEYS ? Bindings[key].GetChars() : NULL; + int key = GetKeyFromName (keyname); + if (key == 0) + { + Printf ("Unknown key \"%s\"\n", keyname); + return; + } + if (!Binds[key].IsEmpty()) + { // This key is already bound. + return; + } + for (int i = 0; i < NUM_KEYS; ++i) + { + if (!Binds[i].IsEmpty() && stricmp (Binds[i], cmd) == 0) + { // This command is already bound to a key. + return; + } + } + // It is safe to do the bind, so do it. + Binds[key] = cmd; } + +//============================================================================= +// +// +// +//============================================================================= + +void C_UnbindAll () +{ + Bindings.UnbindAll(); + DoubleBindings.UnbindAll(); + AutomapBindings.UnbindAll(); +} + +CCMD (unbindall) +{ + C_UnbindAll (); +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (unbind) +{ + if (argv.argc() > 1) + { + Bindings.UnbindKey(argv[1]); + } +} + +CCMD (undoublebind) +{ + if (argv.argc() > 1) + { + DoubleBindings.UnbindKey(argv[1]); + } +} + +CCMD (unmapbind) +{ + if (argv.argc() > 1) + { + AutomapBindings.UnbindKey(argv[1]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (bind) +{ + Bindings.PerformBind(argv, "Current key bindings"); +} + +CCMD (doublebind) +{ + DoubleBindings.PerformBind(argv, "Current key doublebindings"); +} + +CCMD (mapbind) +{ + AutomapBindings.PerformBind(argv, "Current automap key bindings"); +} + +//========================================================================== +// +// CCMD defaultbind +// +// Binds a command to a key if that key is not already bound and if +// that command is not already bound to another key. +// +//========================================================================== + +CCMD (defaultbind) +{ + if (argv.argc() < 3) + { + Printf ("Usage: defaultbind \n"); + } + else + { + Bindings.DefaultBind(argv[1], argv[2]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +CCMD (rebind) +{ + FKeyBindings *bindings; + + if (key == 0) + { + Printf ("Rebind cannot be used from the console\n"); + return; + } + + if (key & KEY_DBLCLICKED) + { + bindings = &DoubleBindings; + key &= KEY_DBLCLICKED-1; + } + else + { + bindings = &Bindings; + } + + if (argv.argc() > 1) + { + bindings->SetBind(key, argv[1]); + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void C_BindDefaults () +{ + Bindings.SetBinds (DefBindings); + + if (gameinfo.gametype & (GAME_Raven|GAME_Strife)) + { + Bindings.SetBinds (DefRavenBindings); + } + + if (gameinfo.gametype == GAME_Heretic) + { + Bindings.SetBinds (DefHereticBindings); + } + + if (gameinfo.gametype == GAME_Hexen) + { + Bindings.SetBinds (DefHexenBindings); + } + + if (gameinfo.gametype == GAME_Strife) + { + Bindings.SetBinds (DefStrifeBindings); + } + + AutomapBindings.SetBinds(DefAutomapBindings); +} + +CCMD(binddefaults) +{ + C_BindDefaults (); +} + +void C_SetDefaultBindings () +{ + C_UnbindAll (); + C_BindDefaults (); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) +{ + FString binding; + bool dclick; + int dclickspot; + BYTE dclickmask; + + if (ev->type != EV_KeyDown && ev->type != EV_KeyUp) + return false; + + if ((unsigned int)ev->data1 >= NUM_KEYS) + return false; + + dclickspot = ev->data1 >> 3; + dclickmask = 1 << (ev->data1 & 7); + dclick = false; + + // This used level.time which didn't work outside a level. + if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown) + { + // Key pressed for a double click + if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1); + DClicked[dclickspot] |= dclickmask; + dclick = true; + } + else + { + if (ev->type == EV_KeyDown) + { // Key pressed for a normal press + binding = binds->GetBinding(ev->data1); + DClickTime[ev->data1] = I_MSTime() + 571; + } + else if (DClicked[dclickspot] & dclickmask) + { // Key released from a double click + if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1); + DClicked[dclickspot] &= ~dclickmask; + DClickTime[ev->data1] = 0; + dclick = true; + } + else + { // Key released from a normal press + binding = binds->GetBinding(ev->data1); + } + } + + + if (binding.IsEmpty()) + { + binding = binds->GetBinding(ev->data1); + dclick = false; + } + + if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256)) + { + if (ev->type == EV_KeyUp && binding[0] != '+') + { + return false; + } + + char *copy = binding.LockBuffer(); + + if (ev->type == EV_KeyUp) + { + copy[0] = '-'; + } + + AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1); + return true; + } + return false; +} + diff --git a/src/c_bind.h b/src/c_bind.h index 2b46118cf..7d71b462a 100644 --- a/src/c_bind.h +++ b/src/c_bind.h @@ -34,25 +34,65 @@ #ifndef __C_BINDINGS_H__ #define __C_BINDINGS_H__ +#include "doomdef.h" struct event_t; class FConfigFile; +class FCommandLine; -bool C_DoKey (event_t *ev); -void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd=NULL); +void C_NameKeys (char *str, int first, int second); + +struct FBinding +{ + const char *Key; + const char *Bind; +}; + +class FKeyBindings +{ + FString Binds[NUM_KEYS]; + +public: + void PerformBind(FCommandLine &argv, const char *msg); + void SetBinds(const FBinding *binds); + bool DoKey(event_t *ev); + void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL); + int GetKeysForCommand (char *cmd, int *first, int *second); + void UnbindACommand (char *str); + void UnbindAll (); + void UnbindKey(const char *key); + void DoBind (const char *key, const char *bind); + void DefaultBind(const char *keyname, const char *cmd); + + void SetBind(unsigned int key, const char *bind) + { + if (key < NUM_KEYS) Binds[key] = bind; + } + + const FString &GetBinding(unsigned int index) const + { + return Binds[index]; + } + + const char *GetBind(unsigned int index) const + { + if (index < NUM_KEYS) return Binds[index]; + else return NULL; + } + +}; + +extern FKeyBindings Bindings; +extern FKeyBindings DoubleBindings; +extern FKeyBindings AutomapBindings; + + +bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds); // Stuff used by the customize controls menu -int C_GetKeysForCommand (char *cmd, int *first, int *second); -void C_NameKeys (char *str, int first, int second); -void C_UnbindACommand (char *str); -void C_ChangeBinding (const char *str, int newone); -void C_DoBind (const char *key, const char *bind, bool doublebind); void C_SetDefaultBindings (); void C_UnbindAll (); -// Returns string bound to given key (NULL if none) -const char *C_GetBinding (int key); - extern const char *KeyNames[]; #endif //__C_BINDINGS_H__ diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 2fbafd2a9..413b8d64c 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -119,7 +119,9 @@ FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, Button_Forward, Button_Right, Button_Left, Button_MoveDown, Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, Button_Zoom, Button_Reload, - Button_User1, Button_User2, Button_User3, Button_User4; + Button_User1, Button_User2, Button_User3, Button_User4, + Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp, + Button_AM_ZoomIn, Button_AM_ZoomOut; bool ParsingKeyConf; @@ -131,13 +133,16 @@ bool ParsingKeyConf; FActionMap ActionMaps[] = { + { 0x0d52d67b, &Button_AM_PanLeft, "am_panleft"}, { 0x125f5226, &Button_User2, "user2" }, { 0x1eefa611, &Button_Jump, "jump" }, { 0x201f1c55, &Button_Right, "right" }, { 0x20ccc4d5, &Button_Zoom, "zoom" }, { 0x23a99cd7, &Button_Back, "back" }, + { 0x41df90c2, &Button_AM_ZoomIn, "am_zoomin"}, { 0x426b69e7, &Button_Reload, "reload" }, { 0x4463f43a, &Button_LookDown, "lookdown" }, + { 0x51f7a334, &Button_AM_ZoomOut, "am_zoomout"}, { 0x534c30ee, &Button_User4, "user4" }, { 0x5622bf42, &Button_Attack, "attack" }, { 0x577712d0, &Button_User1, "user1" }, @@ -147,12 +152,15 @@ FActionMap ActionMaps[] = { 0x676885b8, &Button_AltAttack, "altattack" }, { 0x6fa41b84, &Button_MoveLeft, "moveleft" }, { 0x818f08e6, &Button_MoveRight, "moveright" }, + { 0x8197097b, &Button_AM_PanRight, "am_panright"}, + { 0x8d89955e, &Button_AM_PanUp, "am_panup"} , { 0xa2b62d8b, &Button_Mlook, "mlook" }, { 0xab2c3e71, &Button_Crouch, "crouch" }, { 0xb000b483, &Button_Left, "left" }, { 0xb62b1e49, &Button_LookUp, "lookup" }, { 0xb6f8fe92, &Button_User3, "user3" }, { 0xb7e6a54b, &Button_Strafe, "strafe" }, + { 0xce301c81, &Button_AM_PanDown, "am_pandown"}, { 0xd5897c73, &Button_ShowScores, "showscores" }, { 0xe0ccb317, &Button_Speed, "speed" }, { 0xe0cfc260, &Button_Use, "use" }, @@ -160,6 +168,7 @@ FActionMap ActionMaps[] = }; #define NUM_ACTIONS countof(ActionMaps) + // PRIVATE DATA DEFINITIONS ------------------------------------------------ static const char *KeyConfCommands[] = diff --git a/src/c_dispatch.h b/src/c_dispatch.h index a19352d32..d93709c90 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -146,6 +146,7 @@ struct FButtonStatus bool PressKey (int keynum); // Returns true if this key caused the button to be pressed. bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed. void ResetTriggers () { bWentDown = bWentUp = false; } + void Reset () { bDown = bWentDown = bWentUp = false; } }; extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, @@ -154,7 +155,9 @@ extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, Button_Forward, Button_Right, Button_Left, Button_MoveDown, Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, Button_Zoom, Button_Reload, - Button_User1, Button_User2, Button_User3, Button_User4; + Button_User1, Button_User2, Button_User3, Button_User4, + Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp, + Button_AM_ZoomIn, Button_AM_ZoomOut; extern bool ParsingKeyConf; void ResetButtonTriggers (); // Call ResetTriggers for all buttons diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 9c06b6714..36a900709 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -2,10 +2,14 @@ #ifdef _WIN32 #include +#include #else #include #include #include +#if !defined(__sun) +#include +#endif #endif #include "doomtype.h" #include "cmdlib.h" @@ -885,3 +889,153 @@ FString NicePath(const char *path) return where; #endif } + + +#ifdef _WIN32 + +//========================================================================== +// +// ScanDirectory +// +//========================================================================== + +void ScanDirectory(TArray &list, const char *dirpath) +{ + struct _finddata_t fileinfo; + intptr_t handle; + FString dirmatch; + + dirmatch << dirpath << "*"; + + if ((handle = _findfirst(dirmatch, &fileinfo)) == -1) + { + I_Error("Could not scan '%s': %s\n", dirpath, strerror(errno)); + } + else + { + do + { + if (fileinfo.attrib & _A_HIDDEN) + { + // Skip hidden files and directories. (Prevents SVN bookkeeping + // info from being included.) + continue; + } + + if (fileinfo.attrib & _A_SUBDIR) + { + if (fileinfo.name[0] == '.' && + (fileinfo.name[1] == '\0' || + (fileinfo.name[1] == '.' && fileinfo.name[2] == '\0'))) + { + // Do not record . and .. directories. + continue; + } + + FFileList *fl = &list[list.Reserve(1)]; + fl->Filename << dirpath << fileinfo.name; + fl->isDirectory = true; + FString newdir = fl->Filename; + newdir << "/"; + ScanDirectory(list, newdir); + } + else + { + FFileList *fl = &list[list.Reserve(1)]; + fl->Filename << dirpath << fileinfo.name; + fl->isDirectory = false; + } + } + while (_findnext(handle, &fileinfo) == 0); + _findclose(handle); + } +} + +#elif defined(__sun) || defined(linux) + +//========================================================================== +// +// ScanDirectory +// Solaris version +// +// Given NULL-terminated array of directory paths, create trees for them. +// +//========================================================================== + +void ScanDirectory(TArray &list, const char *dirpath) +{ + DIR *directory = opendir(dirpath); + if(directory == NULL) + return; + + struct dirent *file; + while((file = readdir(directory)) != NULL) + { + if(file->d_name[0] == '.') //File is hidden or ./.. directory so ignore it. + continue; + + FFileList *fl = &list[list.Reserve(1)]; + fl->Filename << dirpath << file->d_name; + + struct stat fileStat; + stat(fl->Filename, &fileStat); + fl->isDirectory = S_ISDIR(fileStat.st_mode); + + if(fl->isDirectory) + { + FString newdir = fl->Filename; + newdir += "/"; + ScanDirectory(list, newdir); + continue; + } + } + + closedir(directory); +} + +#else + +//========================================================================== +// +// ScanDirectory +// 4.4BSD version +// +//========================================================================== + +void ScanDirectory(TArray &list, const char *dirpath) +{ + const char **argv[] = {dirpath, NULL }; + FTS *fts; + FTSENT *ent; + + fts = fts_open(argv, FTS_LOGICAL, NULL); + if (fts == NULL) + { + I_Error("Failed to start directory traversal: %s\n", strerror(errno)); + return; + } + while ((ent = fts_read(fts)) != NULL) + { + if (ent->fts_info == FTS_D && ent->fts_name[0] == '.') + { + // Skip hidden directories. (Prevents SVN bookkeeping + // info from being included.) + fts_set(fts, ent, FTS_SKIP); + } + if (ent->fts_info == FTS_D && ent->fts_level == 0) + { + FFileList *fl = &list[list.Reserve(1)]; + fl->Filename = ent->fts_path; + fl->isDirectory = true; + } + if (ent->fts_info == FTS_F) + { + // We're only interested in remembering files. + FFileList *fl = &list[list.Reserve(1)]; + fl->Filename = ent->fts_path; + fl->isDirectory = false; + } + } + fts_close(fts); +} +#endif diff --git a/src/cmdlib.h b/src/cmdlib.h index f9d7fae70..7c29644d5 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -54,4 +54,12 @@ void CreatePath(const char * fn); FString ExpandEnvVars(const char *searchpathstring); FString NicePath(const char *path); +struct FFileList +{ + FString Filename; + bool isDirectory; +}; + +void ScanDirectory(TArray &list, const char *dirpath); + #endif diff --git a/src/d_main.cpp b/src/d_main.cpp index deef1d6c7..20ba2c467 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2294,6 +2294,14 @@ void FStartupScreen::AppendStatusLine(const char *status) // //========================================================================== +//========================================================================== +// +// STAT fps +// +// Displays statistics about rendering times +// +//========================================================================== + ADD_STAT (fps) { FString out; @@ -2302,6 +2310,24 @@ ADD_STAT (fps) return out; } + +static double f_acc, w_acc,p_acc,m_acc; +static int acc_c; + +ADD_STAT (fps_accumulated) +{ + f_acc += FrameCycles.TimeMS(); + w_acc += WallCycles.TimeMS(); + p_acc += PlaneCycles.TimeMS(); + m_acc += MaskedCycles.TimeMS(); + acc_c++; + FString out; + out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms %d counts", + f_acc/acc_c, w_acc/acc_c, p_acc/acc_c, m_acc/acc_c, acc_c); + Printf(PRINT_LOG, "%s\n", out.GetChars()); + return out; +} + //========================================================================== // // STAT wallcycles diff --git a/src/f_finale.cpp b/src/f_finale.cpp index c37d1f459..a851fdc31 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -723,7 +723,7 @@ bool F_CastResponder (event_t* ev) if (ev->type != EV_KeyDown) return false; - const char *cmd = C_GetBinding (ev->data1); + const char *cmd = Bindings.GetBind (ev->data1); if (cmd != NULL && !stricmp (cmd, "toggleconsole")) return false; diff --git a/src/g_game.cpp b/src/g_game.cpp index fadfb6c55..f85601c6e 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -879,7 +879,7 @@ bool G_Responder (event_t *ev) if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL)) { - const char *cmd = C_GetBinding (ev->data1); + const char *cmd = Bindings.GetBind (ev->data1); if (ev->type == EV_KeyDown) { @@ -902,11 +902,11 @@ bool G_Responder (event_t *ev) } else { - return C_DoKey (ev); + return C_DoKey (ev, &Bindings, &DoubleBindings); } } if (cmd && cmd[0] == '+') - return C_DoKey (ev); + return C_DoKey (ev, &Bindings, &DoubleBindings); return false; } @@ -918,7 +918,7 @@ bool G_Responder (event_t *ev) { if (ST_Responder (ev)) return true; // status window ate it - if (!viewactive && AM_Responder (ev)) + if (!viewactive && AM_Responder (ev, false)) return true; // automap ate it } else if (gamestate == GS_FINALE) @@ -930,12 +930,12 @@ bool G_Responder (event_t *ev) switch (ev->type) { case EV_KeyDown: - if (C_DoKey (ev)) + if (C_DoKey (ev, &Bindings, &DoubleBindings)) return true; break; case EV_KeyUp: - C_DoKey (ev); + C_DoKey (ev, &Bindings, &DoubleBindings); break; // [RH] mouse buttons are sent as key up/down events @@ -949,7 +949,7 @@ bool G_Responder (event_t *ev) // the events *last* so that any bound keys get precedence. if (gamestate == GS_LEVEL && viewactive) - return AM_Responder (ev); + return AM_Responder (ev, true); return (ev->type == EV_KeyDown || ev->type == EV_Mouse); diff --git a/src/g_level.cpp b/src/g_level.cpp index b14959efe..8f475d3f3 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1464,8 +1464,8 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad) P_SerializeThinkers (arc, hubLoad); P_SerializeWorld (arc); P_SerializePolyobjs (arc); + P_SerializeSubsectors(arc); StatusBar->Serialize (arc); - //SerializeInterpolations (arc); arc << level.total_monsters << level.total_items << level.total_secrets; diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 936d4e7f7..acf2bbad1 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -399,29 +399,38 @@ void FGameConfigFile::DoGameSetup (const char *gamename) ReadCVars (0); } - strncpy (subsection, "Bindings", sublen); - if (!SetSection (section)) - { // Config has no bindings for the given game - if (!bMigrating) - { - C_SetDefaultBindings (); - } - } - else + if (!bMigrating) { - C_UnbindAll (); + C_SetDefaultBindings (); + } + + strncpy (subsection, "Bindings", sublen); + if (SetSection (section)) + { + Bindings.UnbindAll(); while (NextInSection (key, value)) { - C_DoBind (key, value, false); + Bindings.DoBind (key, value); } } strncpy (subsection, "DoubleBindings", sublen); if (SetSection (section)) { + DoubleBindings.UnbindAll(); while (NextInSection (key, value)) { - C_DoBind (key, value, true); + DoubleBindings.DoBind (key, value); + } + } + + strncpy (subsection, "AutomapBindings", sublen); + if (SetSection (section)) + { + AutomapBindings.UnbindAll(); + while (NextInSection (key, value)) + { + AutomapBindings.DoBind (key, value); } } @@ -512,11 +521,15 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strcpy (subsection, "Bindings"); SetSection (section, true); - C_ArchiveBindings (this, false); + Bindings.ArchiveBindings (this); strncpy (subsection, "DoubleBindings", sublen); SetSection (section, true); - C_ArchiveBindings (this, true); + DoubleBindings.ArchiveBindings (this); + + strncpy (subsection, "AutomapBindings", sublen); + SetSection (section, true); + AutomapBindings.ArchiveBindings (this); } void FGameConfigFile::ArchiveGlobalData () diff --git a/src/m_menu.h b/src/m_menu.h index 4f45cbed2..5653b694a 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -116,6 +116,7 @@ typedef enum { joy_slider, joy_map, joy_inverter, + mapcontrol, } itemtype; struct IJoystickConfig; diff --git a/src/m_options.cpp b/src/m_options.cpp index 06c3017bf..dae45c994 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -204,6 +204,7 @@ static menu_t ConfirmMenu = { * *=======================================*/ +static void StartAutomapMenu (void); static void CustomizeControls (void); static void GameplayOptions (void); static void CompatibilityOptions (void); @@ -228,6 +229,7 @@ static menuitem_t OptionItems[] = { more, "Player Setup", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)M_PlayerSetup} }, { more, "Gameplay Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)GameplayOptions} }, { more, "Compatibility Options",{NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)CompatibilityOptions} }, + { more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} }, { more, "Sound Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)SoundOptions} }, { more, "Display Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)VideoOptions} }, { more, "Set video mode", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)SetVidMode} }, @@ -419,13 +421,13 @@ menu_t ControlsMenu = 2, }; + /*======================================= * * Display Options Menu * *=======================================*/ static void StartMessagesMenu (void); -static void StartAutomapMenu (void); static void StartScoreboardMenu (void); static void InitCrosshairsList(); @@ -495,7 +497,6 @@ static value_t DisplayTagsTypes[] = { static menuitem_t VideoItems[] = { { more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} }, - { more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} }, { more, "Scoreboard Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartScoreboardMenu} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { slider, "Screen size", {&screenblocks}, {3.0}, {12.0}, {1.0}, {NULL} }, @@ -538,6 +539,7 @@ menu_t VideoMenu = * *=======================================*/ static void StartMapColorsMenu (void); +static void StartMapControlsMenu (void); EXTERN_CVAR (Int, am_rotate) EXTERN_CVAR (Int, am_overlay) @@ -548,6 +550,7 @@ EXTERN_CVAR (Bool, am_showtime) EXTERN_CVAR (Int, am_map_secrets) EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, am_drawmapback) +EXTERN_CVAR (Bool, am_textured) static value_t MapColorTypes[] = { { 0, "Custom" }, @@ -577,9 +580,11 @@ static value_t OverlayTypes[] = { static menuitem_t AutomapItems[] = { { discrete, "Map color set", {&am_colorset}, {4.0}, {0.0}, {0.0}, {MapColorTypes} }, { more, "Set custom colors", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t*)StartMapColorsMenu} }, + { more, "Customize map controls", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t*)StartMapControlsMenu} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Rotate automap", {&am_rotate}, {3.0}, {0.0}, {0.0}, {RotateTypes} }, { discrete, "Overlay automap", {&am_overlay}, {3.0}, {0.0}, {0.0}, {OverlayTypes} }, + { discrete, "Enable textured display", {&am_textured}, {3.0}, {0.0}, {0.0}, {OnOff} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Show item counts", {&am_showitems}, {2.0}, {0.0}, {0.0}, {OnOff} }, { discrete, "Show monster counts", {&am_showmonsters}, {2.0}, {0.0}, {0.0}, {OnOff} }, @@ -600,6 +605,37 @@ menu_t AutomapMenu = AutomapItems, }; +menuitem_t MapControlsItems[] = +{ + { redtext,"ENTER to change, BACKSPACE to clear", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, + { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, + { whitetext,"Map Controls", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, + { mapcontrol, "Pan left", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panleft"} }, + { mapcontrol, "Pan right", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panright"} }, + { mapcontrol, "Pan up", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panup"} }, + { mapcontrol, "Pan down", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_pandown"} }, + { mapcontrol, "Zoom in", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_zoomin"} }, + { mapcontrol, "Zoom out", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_zoomout"} }, + { mapcontrol, "Toggle zoom", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_gobig"} }, + { mapcontrol, "Toggle follow", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_togglefollow"} }, + { mapcontrol, "Toggle grid", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_togglegrid"} }, + { mapcontrol, "Toggle texture", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_toggletexture"} }, + { mapcontrol, "Set mark", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_setmark"} }, + { mapcontrol, "Clear mark", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_clearmarks"} }, +}; + +menu_t MapControlsMenu = +{ + "CUSTOMIZE MAP CONTROLS", + 3, + countof(MapControlsItems), + 0, + MapControlsItems, + 2, +}; + + + /*======================================= * * Map Colors Menu @@ -1536,7 +1572,9 @@ void M_BuildKeyList (menuitem_t *item, int numitems) for (i = 0; i < numitems; i++, item++) { if (item->type == control) - C_GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2); + Bindings.GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2); + else if (item->type == mapcontrol) + AutomapBindings.GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2); } } @@ -1825,7 +1863,7 @@ void M_OptDrawer () default: x = indent - width; - color = (item->type == control && menuactive == MENU_WaitKey && i == CurrentItem) + color = ((item->type == control || item->type == mapcontrol) && menuactive == MENU_WaitKey && i == CurrentItem) ? CR_YELLOW : LabelColor; break; } @@ -1983,6 +2021,7 @@ void M_OptDrawer () break; case control: + case mapcontrol: { char description[64]; @@ -2165,7 +2204,14 @@ void M_OptResponder(event_t *ev) { if (ev->data1 != KEY_ESCAPE) { - C_ChangeBinding(item->e.command, ev->data1); + if (item->type == control) + { + Bindings.SetBind(ev->data1, item->e.command); + } + else if (item->type == mapcontrol) + { + AutomapBindings.SetBind(ev->data1, item->e.command); + } M_BuildKeyList(CurrentMenu->items, CurrentMenu->numitems); } menuactive = MENU_On; @@ -2812,7 +2858,12 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) case MKEY_Clear: if (item->type == control) { - C_UnbindACommand (item->e.command); + Bindings.UnbindACommand (item->e.command); + item->b.key1 = item->c.key2 = 0; + } + else if (item->type == mapcontrol) + { + AutomapBindings.UnbindACommand (item->e.command); item->b.key1 = item->c.key2 = 0; } break; @@ -2880,7 +2931,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat) S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); } - else if (item->type == control) + else if (item->type == control || item->type == mapcontrol) { menuactive = MENU_WaitKey; OldMessage = CurrentMenu->items[0].label; @@ -3000,6 +3051,12 @@ static void StartMapColorsMenu (void) M_SwitchMenu (&MapColorsMenu); } +static void StartMapControlsMenu (void) +{ + M_BuildKeyList (MapControlsMenu.items, MapControlsMenu.numitems); + M_SwitchMenu (&MapControlsMenu); +} + CCMD (menu_mapcolors) { M_StartControlPanel (true); @@ -3644,12 +3701,14 @@ void M_LoadKeys (const char *modname, bool dbl) mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname, dbl ? ".Double" : "."); + + FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings; if (GameConfig->SetSection (section)) { const char *key, *value; while (GameConfig->NextInSection (key, value)) { - C_DoBind (key, value, dbl); + bindings->DoBind (key, value); } } } @@ -3660,12 +3719,13 @@ int M_DoSaveKeys (FConfigFile *config, char *section, int i, bool dbl) config->SetSection (section, true); config->ClearCurrentSection (); + FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings; for (++i; i < most; ++i) { menuitem_t *item = &CustomControlsItems[i]; if (item->type == control) { - C_ArchiveBindings (config, dbl, item->e.command); + bindings->ArchiveBindings (config, item->e.command); continue; } break; @@ -3711,7 +3771,7 @@ void FreeKeySections() for (i = numStdControls; i < CustomControlsItems.Size(); ++i) { menuitem_t *item = &CustomControlsItems[i]; - if (item->type == whitetext || item->type == control) + if (item->type == whitetext || item->type == control || item->type == mapcontrol) { if (item->label != NULL) { diff --git a/src/namedef.h b/src/namedef.h index cb3e78ea2..99737eda5 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -442,6 +442,7 @@ xx(nofakecontrast) xx(smoothlighting) xx(blockprojectiles) xx(blockuse) +xx(hidden) xx(Renderstyle) diff --git a/src/nodebuild.h b/src/nodebuild.h index d1ed2cb15..da82e26a2 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -111,6 +111,12 @@ class FNodeBuilder bool Forward; }; + struct glseg_t : public seg_t + { + DWORD Partner; + }; + + // Like a blockmap, but for vertices instead of lines class IVertexMap { @@ -200,7 +206,7 @@ public: ~FNodeBuilder (); void Extract (node_t *&nodes, int &nodeCount, - seg_t *&segs, int &segCount, + seg_t *&segs, glsegextra_t *&glsegextras, int &segCount, subsector_t *&ssecs, int &subCount, vertex_t *&verts, int &vertCount); @@ -282,10 +288,10 @@ private: DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg); void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const; - int CloseSubsector (TArray &segs, int subsector, vertex_t *outVerts); - DWORD PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_t *outVerts); - void PushConnectingGLSeg (int subsector, TArray &segs, vertex_t *v1, vertex_t *v2); - int OutputDegenerateSubsector (TArray &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts); + int CloseSubsector (TArray &segs, int subsector, vertex_t *outVerts); + DWORD PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_t *outVerts); + void PushConnectingGLSeg (int subsector, TArray &segs, vertex_t *v1, vertex_t *v2); + int OutputDegenerateSubsector (TArray &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts); static int STACK_ARGS SortSegs (const void *a, const void *b); diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index d8675aa6e..5355179ea 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -54,7 +54,7 @@ #endif void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, - seg_t *&outSegs, int &segCount, + seg_t *&outSegs, glsegextra_t *&outSegExtras, int &segCount, subsector_t *&outSubs, int &subCount, vertex_t *&outVerts, int &vertCount) { @@ -99,7 +99,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, if (GLNodes) { - TArray segs (Segs.Size()*5/4); + TArray segs (Segs.Size()*5/4); for (i = 0; i < subCount; ++i) { @@ -110,14 +110,12 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, segCount = segs.Size (); outSegs = new seg_t[segCount]; - memcpy (outSegs, &segs[0], segCount*sizeof(seg_t)); + outSegExtras = new glsegextra_t[segCount]; for (i = 0; i < segCount; ++i) { - if (outSegs[i].PartnerSeg != NULL) - { - outSegs[i].PartnerSeg = &outSegs[Segs[(unsigned int)(size_t)outSegs[i].PartnerSeg-1].storedseg]; - } + outSegs[i] = *(seg_t *)&segs[i]; + outSegExtras[i].PartnerSeg = segs[i].Partner; } } else @@ -125,6 +123,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, memcpy (outSubs, &Subsectors[0], subCount*sizeof(subsector_t)); segCount = Segs.Size (); outSegs = new seg_t[segCount]; + outSegExtras = NULL; for (i = 0; i < segCount; ++i) { const FPrivSeg *org = &Segs[SegList[i].SegNum]; @@ -138,8 +137,6 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, out->frontsector = org->frontsector; out->linedef = Level.Lines + org->linedef; out->sidedef = Level.Sides + org->sidedef; - out->PartnerSeg = NULL; - out->bPolySeg = false; } } for (i = 0; i < subCount; ++i) @@ -194,19 +191,17 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp) if (GLNodes) { + TArray glsegs; for (i = 0; i < Subsectors.Size(); ++i) { - DWORD numsegs = CloseSubsector (bsp->Segs, i, &bsp->Verts[0]); + DWORD numsegs = CloseSubsector (glsegs, i, &bsp->Verts[0]); bsp->Subsectors[i].numlines = numsegs; bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs]; } - - for (i = 0; i < Segs.Size(); ++i) + bsp->Segs.Resize(glsegs.Size()); + for (i = 0; i < glsegs.Size(); ++i) { - if (bsp->Segs[i].PartnerSeg != NULL) - { - bsp->Segs[i].PartnerSeg = &bsp->Segs[Segs[(unsigned int)(size_t)bsp->Segs[i].PartnerSeg-1].storedseg]; - } + bsp->Segs[i] = *(seg_t *)&glsegs[i]; } } else @@ -234,8 +229,6 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp) out->linedef = NULL; out->sidedef = NULL; } - out->PartnerSeg = NULL; - out->bPolySeg = false; } for (i = 0; i < bsp->Subsectors.Size(); ++i) { @@ -244,7 +237,7 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp) } } -int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t *outVerts) +int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t *outVerts) { FPrivSeg *seg, *prev; angle_t prevAngle; @@ -406,7 +399,7 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t * return count; } -int FNodeBuilder::OutputDegenerateSubsector (TArray &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts) +int FNodeBuilder::OutputDegenerateSubsector (TArray &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts) { static const double bestinit[2] = { -DBL_MAX, DBL_MAX }; FPrivSeg *seg; @@ -473,9 +466,9 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray &segs, int subsector, return count; } -DWORD FNodeBuilder::PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_t *outVerts) +DWORD FNodeBuilder::PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_t *outVerts) { - seg_t newseg; + glseg_t newseg; newseg.v1 = outVerts + seg->v1; newseg.v2 = outVerts + seg->v2; @@ -491,14 +484,13 @@ DWORD FNodeBuilder::PushGLSeg (TArray &segs, const FPrivSeg *seg, vertex_ newseg.linedef = NULL; newseg.sidedef = NULL; } - newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1); - newseg.bPolySeg = false; + newseg.Partner = seg->partner; return (DWORD)segs.Push (newseg); } -void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray &segs, vertex_t *v1, vertex_t *v2) +void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray &segs, vertex_t *v1, vertex_t *v2) { - seg_t newseg; + glseg_t newseg; newseg.v1 = v1; newseg.v2 = v2; @@ -506,7 +498,6 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray &segs, vert newseg.frontsector = NULL; newseg.linedef = NULL; newseg.sidedef = NULL; - newseg.PartnerSeg = NULL; - newseg.bPolySeg = false; + newseg.Partner = DWORD_MAX; segs.Push (newseg); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f04cfbdff..bf480fe73 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5097,7 +5097,7 @@ int DLevelScript::RunScript () { int key1 = 0, key2 = 0; - C_GetKeysForCommand ((char *)lookup, &key1, &key2); + Bindings.GetKeysForCommand ((char *)lookup, &key1, &key2); if (key2) work << KeyNames[key1] << " or " << KeyNames[key2]; diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp new file mode 100644 index 000000000..426552c37 --- /dev/null +++ b/src/p_glnodes.cpp @@ -0,0 +1,1537 @@ +/* +** gl_nodes.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2005-2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ +#include +#ifdef _MSC_VER +#include // for alloca() +#include +#endif + +#ifndef _WIN32 +#include + +#else + +#define rmdir _rmdir + +// TODO, maybe: stop using DWORD so I don't need to worry about conflicting +// with Windows' typedef. Then I could just include the header file instead +// of declaring everything here. +#define MAX_PATH 260 +#define CSIDL_LOCAL_APPDATA 0x001c +extern "C" __declspec(dllimport) long __stdcall SHGetFolderPathA(void *hwnd, int csidl, void *hToken, unsigned long dwFlags, char *pszPath); + +#endif + +#ifdef __APPLE__ +#include +#endif + +#include "templates.h" +#include "m_alloc.h" +#include "m_argv.h" +#include "c_dispatch.h" +#include "m_swap.h" +#include "g_game.h" +#include "i_system.h" +#include "w_wad.h" +#include "doomdef.h" +#include "p_local.h" +#include "nodebuild.h" +#include "doomstat.h" +#include "vectors.h" +#include "stats.h" +#include "doomerrors.h" +#include "p_setup.h" +#include "x86.h" +#include "version.h" +#include "md5.h" + +void P_GetPolySpots (MapData * lump, TArray &spots, TArray &anchors); + +CVAR(Bool, gl_cachenodes, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Float, gl_cachetime, 0.6f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +void P_LoadZNodes (FileReader &dalump, DWORD id); +static bool CheckCachedNodes(MapData *map); +static void CreateCachedNodes(MapData *map); + + +// fixed 32 bit gl_vert format v2.0+ (glBsp 1.91) +struct mapglvertex_t +{ + fixed_t x,y; +}; + +struct gl3_mapsubsector_t +{ + SDWORD numsegs; + SDWORD firstseg; // Index of first one; segs are stored sequentially. +}; + +struct glseg_t +{ + WORD v1; // start vertex (16 bit) + WORD v2; // end vertex (16 bit) + WORD linedef; // linedef, or -1 for minisegs + WORD side; // side on linedef: 0 for right, 1 for left + WORD partner; // corresponding partner seg, or 0xffff on one-sided walls +}; + +struct glseg3_t +{ + SDWORD v1; + SDWORD v2; + WORD linedef; + WORD side; + SDWORD partner; +}; + +struct gl5_mapnode_t +{ + SWORD x,y,dx,dy; // partition line + SWORD bbox[2][4]; // bounding box for each child + // If NF_SUBSECTOR is or'ed in, it's a subsector, + // else it's a node of another subtree. + DWORD children[2]; +}; + + + +//========================================================================== +// +// Collect all sidedefs which are not entirely covered by segs +// Old ZDBSPs could create such maps. If such a BSP is discovered +// a node rebuild must be done to ensure proper rendering +// +//========================================================================== + +static int CheckForMissingSegs() +{ + float *added_seglen = new float[numsides]; + int missing = 0; + + memset(added_seglen, 0, sizeof(float)*numsides); + for(int i=0;isidedef!=NULL) + { + // check all the segs and calculate the length they occupy on their sidedef + TVector2 vec1(seg->v2->x - seg->v1->x, seg->v2->y - seg->v1->y); + added_seglen[seg->sidedef - sides] += float(vec1.Length()); + } + } + + for(int i=0;ilinedef; + + TVector2 lvec(line->dx, line->dy); + float linelen = float(lvec.Length()); + + missing += (added_seglen[i] < linelen - FRACUNIT); + } + + delete [] added_seglen; + return missing; +} + +//========================================================================== +// +// Checks whether the nodes are suitable for GL rendering +// +//========================================================================== + +bool P_CheckForGLNodes() +{ + int i; + + for(i=0;ifirstline; + seg_t * lastseg = sub->firstline + sub->numlines - 1; + + if (firstseg->v1 != lastseg->v2) + { + // This subsector is incomplete which means that these + // are normal nodes + return false; + } + else + { + for(DWORD j=0;jnumlines;j++) + { + if (segs[j].linedef==NULL) // miniseg + { + // We already have GL nodes. Great! + return true; + } + } + } + } + // all subsectors were closed but there are no minisegs + // Although unlikely this can happen. Such nodes are not a problem. + // all that is left is to check whether the BSP covers all sidedefs completely. + int missing = CheckForMissingSegs(); + if (missing > 0) + { + Printf("%d missing segs counted\nThe BSP needs to be rebuilt", missing); + } + return missing == 0; +} + + +//========================================================================== +// +// LoadGLVertexes +// +// loads GL vertices +// +//========================================================================== + +#define gNd2 MAKE_ID('g','N','d','2') +#define gNd4 MAKE_ID('g','N','d','4') +#define gNd5 MAKE_ID('g','N','d','5') + +#define GL_VERT_OFFSET 4 +static int firstglvertex; +static bool format5; + +static bool LoadGLVertexes(FileReader * f, wadlump_t * lump) +{ + BYTE *gldata; + int i; + + firstglvertex = numvertexes; + + int gllen=lump->Size; + + gldata = new BYTE[gllen]; + f->Seek(lump->FilePos, SEEK_SET); + f->Read(gldata, gllen); + + if (*(int *)gldata == gNd5) + { + format5=true; + } + else if (*(int *)gldata != gNd2) + { + // GLNodes V1 and V4 are unsupported. + // V1 because the precision is insufficient and + // V4 due to the missing partner segs + Printf("GL nodes v%d found. This format is not supported by "GAMENAME"\n", + (*(int *)gldata == gNd4)? 4:1); + + delete [] gldata; + return false; + } + else format5=false; + + mapglvertex_t* mgl; + + vertex_t * oldvertexes = vertexes; + numvertexes += (gllen - GL_VERT_OFFSET)/sizeof(mapglvertex_t); + vertexes = new vertex_t[numvertexes]; + mgl = (mapglvertex_t *) (gldata + GL_VERT_OFFSET); + + memcpy(vertexes, oldvertexes, firstglvertex * sizeof(vertex_t)); + for(i=0;ix); + vertexes[i].y = LittleLong(mgl->y); + mgl++; + } + delete[] gldata; + return true; +} + +//========================================================================== +// +// GL Nodes utilities +// +//========================================================================== + +static inline int checkGLVertex(int num) +{ + if (num & 0x8000) + num = (num&0x7FFF)+firstglvertex; + return num; +} + +static inline int checkGLVertex3(int num) +{ + if (num & 0xc0000000) + num = (num&0x3FFFFFFF)+firstglvertex; + return num; +} + +//========================================================================== +// +// LoadGLSegs +// +//========================================================================== + +static bool LoadGLSegs(FileReader * f, wadlump_t * lump) +{ + char *data; + int i; + line_t *ldef=NULL; + + numsegs = lump->Size; + data= new char[numsegs]; + f->Seek(lump->FilePos, SEEK_SET); + f->Read(data, lump->Size); + segs=NULL; + +#ifdef _MSC_VER + __try +#endif + { + if (!format5 && memcmp(data, "gNd3", 4)) + { + numsegs/=sizeof(glseg_t); + segs = new seg_t[numsegs]; + memset(segs,0,sizeof(seg_t)*numsegs); + glsegextras = new glsegextra_t[numsegs]; + + glseg_t * ml = (glseg_t*)data; + for(i = 0; i < numsegs; i++) + { // check for gl-vertices + segs[i].v1 = &vertexes[checkGLVertex(LittleShort(ml->v1))]; + segs[i].v2 = &vertexes[checkGLVertex(LittleShort(ml->v2))]; + + glsegextras[i].PartnerSeg = ml->partner == 0xFFFF ? DWORD_MAX : LittleShort(ml->partner); + if(ml->linedef != 0xffff) + { + ldef = &lines[LittleShort(ml->linedef)]; + segs[i].linedef = ldef; + + + ml->side=LittleShort(ml->side); + segs[i].sidedef = ldef->sidedef[ml->side]; + segs[i].frontsector = ldef->sidedef[ml->side]->sector; + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) + { + segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + } + else + { + ldef->flags &= ~ML_TWOSIDED; + segs[i].backsector = 0; + } + + } + else + { + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; + } + } + else + { + if (!format5) numsegs-=4; + numsegs/=sizeof(glseg3_t); + segs = new seg_t[numsegs]; + memset(segs,0,sizeof(seg_t)*numsegs); + glsegextras = new glsegextra_t[numsegs]; + + glseg3_t * ml = (glseg3_t*)(data+ (format5? 0:4)); + for(i = 0; i < numsegs; i++) + { // check for gl-vertices + segs[i].v1 = &vertexes[checkGLVertex3(LittleLong(ml->v1))]; + segs[i].v2 = &vertexes[checkGLVertex3(LittleLong(ml->v2))]; + + glsegextras[i].PartnerSeg = LittleLong(ml->partner); + + if(ml->linedef != 0xffff) // skip minisegs + { + ldef = &lines[LittleLong(ml->linedef)]; + segs[i].linedef = ldef; + + + ml->side=LittleShort(ml->side); + segs[i].sidedef = ldef->sidedef[ml->side]; + segs[i].frontsector = ldef->sidedef[ml->side]->sector; + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) + { + segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + } + else + { + ldef->flags &= ~ML_TWOSIDED; + segs[i].backsector = 0; + } + + } + else + { + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; + } + } + delete [] data; + return true; + } +#ifdef _MSC_VER + __except(1) + { + // Invalid data has the bad habit of requiring extensive checks here + // so let's just catch anything invalid and output a message. + // (at least under MSVC. GCC can't do SEH even for Windows... :( ) + Printf("Invalid GL segs. The BSP will have to be rebuilt.\n"); + delete [] data; + delete [] segs; + segs = NULL; + return false; + } +#endif +} + + +//========================================================================== +// +// LoadGLSubsectors +// +//========================================================================== + +static bool LoadGLSubsectors(FileReader * f, wadlump_t * lump) +{ + char * datab; + int i; + + numsubsectors = lump->Size; + datab = new char[numsubsectors]; + f->Seek(lump->FilePos, SEEK_SET); + f->Read(datab, lump->Size); + + if (numsubsectors == 0) + { + delete [] datab; + return false; + } + + if (!format5 && memcmp(datab, "gNd3", 4)) + { + mapsubsector_t * data = (mapsubsector_t*) datab; + numsubsectors /= sizeof(mapsubsector_t); + subsectors = new subsector_t[numsubsectors]; + memset(subsectors,0,numsubsectors * sizeof(subsector_t)); + + for (i=0; ilinedef==NULL) seg->frontsector = seg->backsector = subsectors[i].firstline->frontsector; + } + seg_t *firstseg = subsectors[i].firstline; + seg_t *lastseg = subsectors[i].firstline + subsectors[i].numlines - 1; + // The subsector must be closed. If it isn't we can't use these nodes and have to do a rebuild. + if (lastseg->v2 != firstseg->v1) + { + delete [] datab; + return false; + } + + } + delete [] datab; + return true; +} + +//========================================================================== +// +// P_LoadNodes +// +//========================================================================== + +static bool LoadNodes (FileReader * f, wadlump_t * lump) +{ + const int NF_SUBSECTOR = 0x8000; + const int GL5_NF_SUBSECTOR = (1 << 31); + + int i; + int j; + int k; + node_t* no; + WORD* used; + + if (!format5) + { + mapnode_t* mn, * basemn; + numnodes = lump->Size / sizeof(mapnode_t); + + if (numnodes == 0) return false; + + nodes = new node_t[numnodes]; + f->Seek(lump->FilePos, SEEK_SET); + + basemn = mn = new mapnode_t[numnodes]; + f->Read(mn, lump->Size); + + used = (WORD *)alloca (sizeof(WORD)*numnodes); + memset (used, 0, sizeof(WORD)*numnodes); + + no = nodes; + + for (i = 0; i < numnodes; i++, no++, mn++) + { + no->x = LittleShort(mn->x)<y = LittleShort(mn->y)<dx = LittleShort(mn->dx)<dy = LittleShort(mn->dy)<children[j]); + if (child & NF_SUBSECTOR) + { + child &= ~NF_SUBSECTOR; + if (child >= numsubsectors) + { + delete [] basemn; + return false; + } + no->children[j] = (BYTE *)&subsectors[child] + 1; + } + else if (child >= numnodes) + { + delete [] basemn; + return false; + } + else if (used[child]) + { + delete [] basemn; + return false; + } + else + { + no->children[j] = &nodes[child]; + used[child] = j + 1; + } + for (k = 0; k < 4; k++) + { + no->bbox[j][k] = LittleShort(mn->bbox[j][k])<Size / sizeof(gl5_mapnode_t); + + if (numnodes == 0) return false; + + nodes = new node_t[numnodes]; + f->Seek(lump->FilePos, SEEK_SET); + + basemn = mn = new gl5_mapnode_t[numnodes]; + f->Read(mn, lump->Size); + + used = (WORD *)alloca (sizeof(WORD)*numnodes); + memset (used, 0, sizeof(WORD)*numnodes); + + no = nodes; + + for (i = 0; i < numnodes; i++, no++, mn++) + { + no->x = LittleShort(mn->x)<y = LittleShort(mn->y)<dx = LittleShort(mn->dx)<dy = LittleShort(mn->dy)<children[j]); + if (child & GL5_NF_SUBSECTOR) + { + child &= ~GL5_NF_SUBSECTOR; + if (child >= numsubsectors) + { + delete [] basemn; + return false; + } + no->children[j] = (BYTE *)&subsectors[child] + 1; + } + else if (child >= numnodes) + { + delete [] basemn; + return false; + } + else if (used[child]) + { + delete [] basemn; + return false; + } + else + { + no->children[j] = &nodes[child]; + used[child] = j + 1; + } + for (k = 0; k < 4; k++) + { + no->bbox[j][k] = LittleShort(mn->bbox[j][k])<sidedef) + { + Printf("GL nodes contain invalid data. The BSP has to be rebuilt.\n"); + delete [] nodes; + nodes = NULL; + delete [] subsectors; + subsectors = NULL; + delete [] segs; + segs = NULL; + return false; + } + } + + // check whether the BSP covers all sidedefs completely. + int missing = CheckForMissingSegs(); + if (missing > 0) + { + Printf("%d missing segs counted in GL nodes.\nThe BSP has to be rebuilt", missing); + } + return missing == 0; +} + + +//=========================================================================== +// +// MatchHeader +// +// Checks whether a GL_LEVEL header belongs to this level +// +//=========================================================================== + +static bool MatchHeader(const char * label, const char * hdata) +{ + if (!memcmp(hdata, "LEVEL=", 6) == 0) + { + size_t labellen = strlen(label); + + if (strnicmp(hdata+6, label, labellen)==0 && + (hdata[6+labellen]==0xa || hdata[6+labellen]==0xd)) + { + return true; + } + } + return false; +} + +//=========================================================================== +// +// FindGLNodesInWAD +// +// Looks for GL nodes in the same WAD as the level itself +// +//=========================================================================== + +static int FindGLNodesInWAD(int labellump) +{ + int wadfile = Wads.GetLumpFile(labellump); + FString glheader; + + glheader.Format("GL_%s", Wads.GetLumpFullName(labellump)); + if (glheader.Len()<=8) + { + int gllabel = Wads.CheckNumForName(glheader, ns_global, wadfile); + if (gllabel >= 0) return gllabel; + } + else + { + // Before scanning the entire WAD directory let's check first whether + // it is necessary. + int gllabel = Wads.CheckNumForName("GL_LEVEL", ns_global, wadfile); + + if (gllabel >= 0) + { + int lastlump=0; + int lump; + while ((lump=Wads.FindLump("GL_LEVEL", &lastlump))>=0) + { + if (Wads.GetLumpFile(lump)==wadfile) + { + FMemLump mem = Wads.ReadLump(lump); + if (MatchHeader(Wads.GetLumpFullName(labellump), (const char *)mem.GetMem())) return true; + } + } + } + } + return -1; +} + +//=========================================================================== +// +// FindGLNodesInWAD +// +// Looks for GL nodes in the same WAD as the level itself +// When this function returns the file pointer points to +// the directory entry of the GL_VERTS lump +// +//=========================================================================== + +static int FindGLNodesInFile(FileReader * f, const char * label) +{ + FString glheader; + bool mustcheck=false; + DWORD id, dirofs, numentries; + DWORD offset, size; + char lumpname[9]; + + glheader.Format("GL_%.8s", label); + if (glheader.Len()>8) + { + glheader="GL_LEVEL"; + mustcheck=true; + } + + f->Seek(0, SEEK_SET); + (*f) >> id >> numentries >> dirofs; + + if ((id == IWAD_ID || id == PWAD_ID) && numentries > 4) + { + f->Seek(dirofs, SEEK_SET); + for(DWORD i=0;i> offset >> size; + f->Read(lumpname, 8); + if (!strnicmp(lumpname, glheader, 8)) + { + if (mustcheck) + { + char check[16]={0}; + int filepos = f->Tell(); + f->Seek(offset, SEEK_SET); + f->Read(check, 16); + f->Seek(filepos, SEEK_SET); + if (MatchHeader(label, check)) return i; + } + else return i; + } + } + } + return -1; +} + +//========================================================================== +// +// Checks for the presence of GL nodes in the loaded WADs or a .GWA file +// returns true if successful +// +//========================================================================== + +bool P_LoadGLNodes(MapData * map) +{ + if (!CheckCachedNodes(map)) + { + wadlump_t gwalumps[4]; + char path[256]; + int li; + int lumpfile = Wads.GetLumpFile(map->lumpnum); + bool mapinwad = map->file == Wads.GetFileReader(lumpfile); + FileReader * fr = map->file; + FILE * f_gwa = NULL; + + const char * name = Wads.GetWadFullName(lumpfile); + + if (mapinwad) + { + li = FindGLNodesInWAD(map->lumpnum); + + if (li>=0) + { + // GL nodes are loaded with a WAD + for(int i=0;i<4;i++) + { + gwalumps[i].FilePos=Wads.GetLumpOffset(li+i+1); + gwalumps[i].Size=Wads.LumpLength(li+i+1); + } + return DoLoadGLNodes(fr, gwalumps); + } + else + { + strcpy(path, name); + + char * ext = strrchr(path, '.'); + if (ext) + { + strcpy(ext, ".gwa"); + // Todo: Compare file dates + + f_gwa = fopen(path, "rb"); + if (f_gwa==NULL) return false; + + fr = new FileReader(f_gwa); + + strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(map->lumpnum), 8); + } + } + } + + bool result = false; + li = FindGLNodesInFile(fr, map->MapLumps[0].Name); + if (li!=-1) + { + static const char check[][9]={"GL_VERT","GL_SEGS","GL_SSECT","GL_NODES"}; + result=true; + for(unsigned i=0; i<4;i++) + { + (*fr) >> gwalumps[i].FilePos; + (*fr) >> gwalumps[i].Size; + fr->Read(gwalumps[i].Name, 8); + if (strnicmp(gwalumps[i].Name, check[i], 8)) + { + result=false; + break; + } + } + if (result) result = DoLoadGLNodes(fr, gwalumps); + } + + if (f_gwa) + { + delete fr; + fclose(f_gwa); + } + return result; + } + else return true; +} + +//========================================================================== +// +// Checks whether nodes are GL friendly or not +// +//========================================================================== + +bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime) +{ + bool ret = false; + + // If the map loading code has performed a node rebuild we don't need to check for it again. + if (!rebuilt && !P_CheckForGLNodes()) + { + ret = true; // we are not using the level's original nodes if we get here. + for (int i = 0; i < numsubsectors; i++) + { + gamesubsectors[i].sector = gamesubsectors[i].firstline->sidedef->sector; + } + + nodes = NULL; + numnodes = 0; + subsectors = NULL; + numsubsectors = 0; + if (segs) delete [] segs; + segs = NULL; + numsegs = 0; + + // Try to load GL nodes (cached or GWA) + if (!P_LoadGLNodes(map)) + { + // none found - we have to build new ones! + unsigned int startTime, endTime; + + startTime = I_FPSTime (); + TArray polyspots, anchors; + P_GetPolySpots (map, polyspots, anchors); + FNodeBuilder::FLevel leveldata = + { + vertexes, numvertexes, + sides, numsides, + lines, numlines + }; + leveldata.FindMapBounds (); + FNodeBuilder builder (leveldata, polyspots, anchors, true); + delete[] vertexes; + builder.Extract (nodes, numnodes, + segs, glsegextras, numsegs, + subsectors, numsubsectors, + vertexes, numvertexes); + endTime = I_FPSTime (); + DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); + buildtime = endTime - startTime; + } + } + +#ifdef DEBUG + // Building nodes in debug is much slower so let's cache them only if cachetime is 0 + buildtime = 0; +#endif + if (gl_cachenodes && buildtime/1000.f >= gl_cachetime) + { + DPrintf("Caching nodes\n"); + CreateCachedNodes(map); + } + else + { + DPrintf("Not caching nodes (time = %f)\n", buildtime/1000.f); + } + + + if (!gamenodes) + { + gamenodes = nodes; + numgamenodes = numnodes; + gamesubsectors = subsectors; + numgamesubsectors = numsubsectors; + } + return ret; +} + +//========================================================================== +// +// Node caching +// +//========================================================================== + +typedef TArray MemFile; + +static FString GetCachePath() +{ + FString path; + +#ifdef _WIN32 + char pathstr[MAX_PATH]; + if (0 != SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathstr)) + { // Failed (e.g. On Win9x): use program directory + path = progdir; + } + else + { + path = pathstr; + } + path += "/zdoom/cache"; +#elif defined(__APPLE__) + char pathstr[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path = pathstr; + } + else + { + path = progdir; + } + path += "/zdoom/cache"; +#else + // Don't use GAME_DIR and such so that ZDoom and its child ports can share the node cache. + path = NicePath("~/.zdoom/cache"); +#endif + return path; +} + +static FString CreateCacheName(MapData *map, bool create) +{ + FString path = GetCachePath(); + FString lumpname = Wads.GetLumpFullPath(map->lumpnum); + int separator = lumpname.IndexOf(':'); + path << '/' << lumpname.Left(separator); + if (create) CreatePath(path); + + lumpname.ReplaceChars('/', '%'); + path << '/' << lumpname.Right(lumpname.Len() - separator - 1) << ".gzc"; + return path; +} + +static void WriteByte(MemFile &f, BYTE b) +{ + f.Push(b); +} + +static void WriteWord(MemFile &f, WORD b) +{ + int v = f.Reserve(2); + f[v] = (BYTE)b; + f[v+1] = (BYTE)(b>>8); +} + +static void WriteLong(MemFile &f, DWORD b) +{ + int v = f.Reserve(4); + f[v] = (BYTE)b; + f[v+1] = (BYTE)(b>>8); + f[v+2] = (BYTE)(b>>16); + f[v+3] = (BYTE)(b>>24); +} + +static void CreateCachedNodes(MapData *map) +{ + MemFile ZNodes; + + WriteLong(ZNodes, 0); + WriteLong(ZNodes, numvertexes); + for(int i=0;isidedef[0]? 0:1); + } + else + { + WriteLong(ZNodes, 0xffffffffu); + WriteByte(ZNodes, 0); + } + } + + WriteLong(ZNodes, numnodes); + for(int i=0;i> FRACBITS); + WriteWord(ZNodes, nodes[i].y >> FRACBITS); + WriteWord(ZNodes, nodes[i].dx >> FRACBITS); + WriteWord(ZNodes, nodes[i].dy >> FRACBITS); + for (int j = 0; j < 2; ++j) + { + for (int k = 0; k < 4; ++k) + { + WriteWord(ZNodes, nodes[i].bbox[j][k] >> FRACBITS); + } + } + + for (int j = 0; j < 2; ++j) + { + DWORD child; + if ((size_t)nodes[i].children[j] & 1) + { + child = 0x80000000 | DWORD((subsector_t *)((BYTE *)nodes[i].children[j] - 1) - subsectors); + } + else + { + child = DWORD((node_t *)nodes[i].children[j] - nodes); + } + WriteLong(ZNodes, child); + } + } + + uLongf outlen = ZNodes.Size(); + BYTE *compressed; + int offset = numlines * 8 + 12 + 16; + int r; + do + { + compressed = new Bytef[outlen + offset]; + r = compress (compressed + offset, &outlen, &ZNodes[0], ZNodes.Size()); + if (r == Z_BUF_ERROR) + { + delete[] compressed; + outlen += 1024; + } + } + while (r == Z_BUF_ERROR); + + memcpy(compressed, "CACH", 4); + DWORD len = LittleLong(numlines); + memcpy(compressed+4, &len, 4); + map->GetChecksum(compressed+8); + for(int i=0;iGetChecksum(md5map); + if (memcmp(md5, md5map, 16)) goto errorout; + + verts = new DWORD[numlin * 8]; + if (fread(verts, 8, numlin, f) != numlin) goto errorout; + + if (fread(magic, 1, 4, f) != 4) goto errorout; + if (memcmp(magic, "ZGL2", 4)) goto errorout; + + + try + { + long pos = ftell(f); + FileReader fr(f); + fr.Seek(pos, SEEK_SET); + P_LoadZNodes (fr, MAKE_ID('Z','G','L','2')); + } + catch (CRecoverableError &error) + { + Printf ("Error loading nodes: %s\n", error.GetMessage()); + + if (subsectors != NULL) + { + delete[] subsectors; + subsectors = NULL; + } + if (segs != NULL) + { + delete[] segs; + segs = NULL; + } + if (nodes != NULL) + { + delete[] nodes; + nodes = NULL; + } + goto errorout; + } + + for(int i=0;i list; + FString path = GetCachePath(); + path += "/"; + + try + { + ScanDirectory(list, path); + } + catch (CRecoverableError &err) + { + Printf("%s", err.GetMessage()); + return; + } + + // Scan list backwards so that when we reach a directory + // all files within are already deleted. + for(int i = list.Size()-1; i >= 0; i--) + { + if (list[i].isDirectory) + { + rmdir(list[i].Filename); + } + else + { + remove(list[i].Filename); + } + } + + +} + +//========================================================================== +// +// Keep both the original nodes from the WAD and the GL nodes created here. +// The original set is only being used to get the sector for in-game +// positioning of actors but not for rendering. +// +// This is necessary because ZDBSP is much more sensitive +// to sloppy mapping practices that produce overlapping sectors. +// The crane in P:AR E1M3 is a good example that would be broken if +// this wasn't done. +// +//========================================================================== + + +//========================================================================== +// +// P_PointInSubsector +// +//========================================================================== + +subsector_t *P_PointInSubsector (fixed_t x, fixed_t y) +{ + node_t *node; + int side; + + // single subsector is a special case + if (numgamenodes == 0) + return gamesubsectors; + + node = gamenodes + numgamenodes - 1; + + do + { + side = R_PointOnSide (x, y, node); + node = (node_t *)node->children[side]; + } + while (!((size_t)node & 1)); + + return (subsector_t *)((BYTE *)node - 1); +} + + +//========================================================================== +// +// PointOnLine +// +// Same as the one im the node builder, but not part of a specific class +// +//========================================================================== + +static bool PointOnLine (int x, int y, int x1, int y1, int dx, int dy) +{ + const double SIDE_EPSILON = 6.5536; + + // For most cases, a simple dot product is enough. + double d_dx = double(dx); + double d_dy = double(dy); + double d_x = double(x); + double d_y = double(y); + double d_x1 = double(x1); + double d_y1 = double(y1); + + double s_num = (d_y1-d_y)*d_dx - (d_x1-d_x)*d_dy; + + if (fabs(s_num) < 17179869184.0) // 4<<32 + { + // Either the point is very near the line, or the segment defining + // the line is very short: Do a more expensive test to determine + // just how far from the line the point is. + double l = sqrt(d_dx*d_dx+d_dy*d_dy); + double dist = fabs(s_num)/l; + if (dist < SIDE_EPSILON) + { + return true; + } + } + return false; +} + + +//========================================================================== +// +// SetRenderSector +// +// Sets the render sector for each GL subsector so that the proper flat +// information can be retrieved +// +//========================================================================== + +void P_SetRenderSector() +{ + int i; + DWORD j; + TArray undetermined; + subsector_t * ss; + + // hide all sectors on textured automap that only have hidden lines. + bool *hidesec = new bool[numsectors]; + for(i = 0; i < numsectors; i++) + { + hidesec[i] = true; + } + for(i = 0; i < numlines; i++) + { + if (!(lines[i].flags & ML_DONTDRAW)) + { + hidesec[lines[i].frontsector - sectors] = false; + if (lines[i].backsector != NULL) + { + hidesec[lines[i].backsector - sectors] = false; + } + } + } + for(i = 0; i < numsectors; i++) + { + if (hidesec[i]) sectors[i].MoreFlags |= SECF_HIDDEN; + } + delete [] hidesec; + + // Check for incorrect partner seg info so that the following code does not crash. + for(i=0;i=numsegs/*eh? || &segs[partner]!=glsegextras[i].PartnerSeg*/) + { + glsegextras[i].PartnerSeg=DWORD_MAX; + } + + // glbsp creates such incorrect references for Strife. + if (segs[i].linedef && glsegextras[i].PartnerSeg != DWORD_MAX && !segs[glsegextras[i].PartnerSeg].linedef) + { + glsegextras[i].PartnerSeg = glsegextras[glsegextras[i].PartnerSeg].PartnerSeg = DWORD_MAX; + } + } + + for(i=0;ifirstline; + + // Check for one-dimensional subsectors. These should be ignored when + // being processed for automap drawinng etc. + ss->flags |= SSECF_DEGENERATE; + for(j=2; jnumlines; j++) + { + if (!PointOnLine(seg[j].v1->x, seg[j].v1->y, seg->v1->x, seg->v1->y, seg->v2->x-seg->v1->x, seg->v2->y-seg->v1->y)) + { + // Not on the same line + ss->flags &= ~SSECF_DEGENERATE; + break; + } + } + + seg = ss->firstline; + for(j=0; jnumlines; j++) + { + if(seg->sidedef && (glsegextras[seg - segs].PartnerSeg == DWORD_MAX || seg->sidedef->sector!=segs[glsegextras[seg - segs].PartnerSeg].sidedef->sector)) + { + ss->render_sector = seg->sidedef->sector; + break; + } + seg++; + } + if(ss->render_sector == NULL) + { + undetermined.Push(ss); + } + } + + // assign a vaild render sector to all subsectors which haven't been processed yet. + while (undetermined.Size()) + { + bool deleted=false; + for(i=undetermined.Size()-1;i>=0;i--) + { + ss=undetermined[i]; + seg_t * seg = ss->firstline; + + for(j=0; jnumlines; j++) + { + DWORD partner = glsegextras[seg - segs].PartnerSeg; + if (partner != DWORD_MAX && glsegextras[partner].Subsector) + { + sector_t * backsec = glsegextras[partner].Subsector->render_sector; + if (backsec) + { + ss->render_sector=backsec; + undetermined.Delete(i); + deleted=1; + break; + } + } + seg++; + } + } + // We still got some left but the loop above was unable to assign them. + // This only happens when a subsector is off the map. + // Don't bother and just assign the real sector for rendering + if (!deleted && undetermined.Size()) + { + for(i=undetermined.Size()-1;i>=0;i--) + { + ss=undetermined[i]; + ss->render_sector=ss->sector; + } + break; + } + } + +#if 0 // may be useful later so let's keep it here for now + // now group the subsectors by sector + subsector_t ** subsectorbuffer = new subsector_t * [numsubsectors]; + + for(i=0, ss=subsectors; irender_sector->subsectorcount++; + } + + for (i=0; irender_sector->subsectors[ss->render_sector->subsectorcount++]=ss; + } +#endif + +} diff --git a/src/p_local.h b/src/p_local.h index 91b134605..2997f3121 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -456,9 +456,10 @@ const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymo // (For ZDoom itself this doesn't make any difference here but for GZDoom it does.) // //---------------------------------------------------------------------------------- +subsector_t *P_PointInSubsector (fixed_t x, fixed_t y); inline sector_t *P_PointInSector(fixed_t x, fixed_t y) { - return R_PointInSubsector(x,y)->sector; + return P_PointInSubsector(x,y)->sector; } // diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 91370c070..9f4ddb39a 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -302,7 +302,7 @@ void AActor::LinkToWorld (bool buggy) // link into subsector sector_t *sec; - if (!buggy || numnodes == 0) + if (!buggy || numgamenodes == 0) { sec = P_PointInSector (x, y); } @@ -322,6 +322,7 @@ void AActor::LinkToWorld (sector_t *sec) return; } Sector = sec; + subsector = R_PointInSubsector(x, y); // this is from the rendering nodes, not the gameplay nodes! if ( !(flags & MF_NOSECTOR) ) { @@ -460,7 +461,7 @@ static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node) sector_t *AActor::LinkToWorldForMapThing () { - node_t *node = nodes + numnodes - 1; + node_t *node = gamenodes + numgamenodes - 1; do { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9dfa8d5ca..98f0801bc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4705,6 +4705,20 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z // don't splash above the object if (checkabove && z > thing->z + (thing->height >> 1)) return false; +#if 0 // needs some rethinking before activation + + // This avoids spawning splashes on invisible self referencing sectors. + // For network consistency do this only in single player though because + // it is not guaranteed that all players have GL nodes loaded. + if (!multiplayer && thing->subsector->sector != thing->subsector->render_sector) + { + fixed_t zs = thing->subsector->sector->floorplane.ZatPoint(x, y); + fixed_t zr = thing->subsector->render_sector->floorplane.ZatPoint(x, y); + + if (zs > zr && thing->z >= zs) return false; + } +#endif + #ifdef _3DFLOORS for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) { @@ -4823,7 +4837,7 @@ bool P_HitFloor (AActor *thing) { thing->flags6 &= ~MF6_ARMED; // Disarm P_DamageMobj (thing, NULL, NULL, thing->health, NAME_Crush, DMG_FORCED); // kill object - return true; + return false; } if (thing->flags2 & MF2_FLOATBOB || thing->flags3 & MF3_DONTSPLASH) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 1ee18eeb2..1b4442649 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -47,6 +47,7 @@ #include "r_interpolate.h" #include "g_level.h" #include "po_man.h" +#include "p_setup.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); @@ -542,3 +543,108 @@ void P_SerializePolyobjs (FArchive &arc) } } } + +//========================================================================== +// +// RecalculateDrawnSubsectors +// +// In case the subsector data is unusable this function tries to reconstruct +// if from the linedefs' ML_MAPPED info. +// +//========================================================================== + +void RecalculateDrawnSubsectors() +{ + for(int i=0;inumlines;j++) + { + if (sub->firstline[j].linedef != NULL && + (sub->firstline[j].linedef->flags & ML_MAPPED)) + { + sub->flags |= SSECF_DRAWN; + } + } + } +} + +//========================================================================== +// +// ArchiveSubsectors +// +//========================================================================== + +void P_SerializeSubsectors(FArchive &arc) +{ + int num_verts, num_subs, num_nodes; + BYTE by; + + if (arc.IsStoring()) + { + if (hasglnodes) + { + arc << numvertexes << numsubsectors << numnodes; // These are only for verification + for(int i=0;i linemap; -bool UsingGLNodes; - // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of @@ -152,7 +161,6 @@ fixed_t bmaporgx; // origin of block map fixed_t bmaporgy; FBlockNode** blocklinks; // for thing chains - // REJECT @@ -790,7 +798,6 @@ void P_LoadZSegs (FileReaderBase &data) segs[i].v2 = &vertexes[v2]; segs[i].linedef = ldef = &lines[line]; segs[i].sidedef = ldef->sidedef[side]; - segs[i].PartnerSeg = NULL; segs[i].frontsector = ldef->sidedef[side]->sector; if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != NULL) { @@ -846,14 +853,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type) { seg[-1].v2 = seg->v1; } - if (partner == 0xFFFFFFFF) - { - seg->PartnerSeg = NULL; - } - else - { - seg->PartnerSeg = &segs[partner]; - } + glsegextras[seg - segs].PartnerSeg = partner; if (line != 0xFFFFFFFF) { line_t *ldef; @@ -887,7 +887,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type) // //=========================================================================== -static void LoadZNodes(FileReaderBase &data, int glnodes) +void LoadZNodes(FileReaderBase &data, int glnodes) { // Read extra vertices added during node building DWORD orgVerts, newVerts; @@ -956,6 +956,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes) numsegs = numSegs; segs = new seg_t[numsegs]; memset (segs, 0, numsegs*sizeof(seg_t)); + glsegextras = NULL; for (i = 0; i < numSubs; ++i) { @@ -968,6 +969,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes) } else { + glsegextras = new glsegextra_t[numsegs]; P_LoadGLZSegs (data, glnodes); } @@ -1014,7 +1016,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes) } -static void P_LoadZNodes (FileReader &dalump, DWORD id) +void P_LoadZNodes (FileReader &dalump, DWORD id) { int type; bool compressed; @@ -1162,7 +1164,6 @@ void P_LoadSegs (MapData * map) li->v1 = &vertexes[vnum1]; li->v2 = &vertexes[vnum2]; - li->PartnerSeg = NULL; segangle = (WORD)LittleShort(ml->angle); @@ -2904,6 +2905,16 @@ static void P_GroupLines (bool buildmap) { subsectors[i].sector = subsectors[i].firstline->sidedef->sector; } + if (glsegextras != NULL) + { + for (i = 0; i < numsubsectors; i++) + { + for (jj = 0; jj < subsectors[i].numlines; ++jj) + { + glsegextras[subsectors[i].firstline - segs + jj].Subsector = &subsectors[i]; + } + } + } times[0].Unclock(); // count number of lines in each sector @@ -3339,6 +3350,11 @@ void P_FreeLevelData () delete[] segs; segs = NULL; } + if (glsegextras != NULL) + { + delete[] glsegextras; + glsegextras = NULL; + } if (sectors != NULL) { delete[] sectors[0].e; @@ -3346,6 +3362,18 @@ void P_FreeLevelData () sectors = NULL; numsectors = 0; // needed for the pointer cleanup code } + if (gamenodes && gamenodes!=nodes) + { + delete [] gamenodes; + gamenodes = NULL; + numgamenodes = 0; + } + if (gamesubsectors && gamesubsectors!=subsectors) + { + delete [] gamesubsectors; + gamesubsectors = NULL; + numgamesubsectors = 0; + } if (subsectors != NULL) { for (int i = 0; i < numsubsectors; ++i) @@ -3480,6 +3508,9 @@ void P_SetupLevel (char *lumpname, int position) int i; bool buildmap; + // This is motivated as follows: + bool RequireGLNodes = am_textured; + for (i = 0; i < (int)countof(times); ++i) { times[i].Reset(); @@ -3537,6 +3568,7 @@ void P_SetupLevel (char *lumpname, int position) // find map num level.lumpnum = map->lumpnum; + hasglnodes = false; // [RH] Support loading Build maps (because I felt like it. :-) buildmap = false; @@ -3665,23 +3697,23 @@ void P_SetupLevel (char *lumpname, int position) { ForceNodeBuild = true; } + bool reloop = false; - UsingGLNodes = false; if (!ForceNodeBuild) { // Check for compressed nodes first, then uncompressed nodes FWadLump test; DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0; - if (map->MapLumps[ML_ZNODES].Size != 0 && !UsingGLNodes) + if (map->MapLumps[ML_ZNODES].Size != 0) { + // Test normal nodes first map->Seek(ML_ZNODES); idcheck = MAKE_ID('Z','N','O','D'); idcheck2 = MAKE_ID('X','N','O','D'); } else if (map->MapLumps[ML_GLZNODES].Size != 0) { - // If normal nodes are not present but GL nodes are, use them. map->Seek(ML_GLZNODES); idcheck = MAKE_ID('Z','G','L','N'); idcheck2 = MAKE_ID('Z','G','L','2'); @@ -3756,10 +3788,23 @@ void P_SetupLevel (char *lumpname, int position) else ForceNodeBuild = true; } else ForceNodeBuild = true; + + // If loading the regular nodes failed try GL nodes before considering a rebuild + if (ForceNodeBuild) + { + if (P_LoadGLNodes(map)) + { + ForceNodeBuild=false; + reloop = true; + } + } } + else reloop = true; + + unsigned int startTime=0, endTime=0; + if (ForceNodeBuild) { - unsigned int startTime, endTime; startTime = I_FPSTime (); TArray polyspots, anchors; @@ -3771,15 +3816,46 @@ void P_SetupLevel (char *lumpname, int position) lines, numlines }; leveldata.FindMapBounds (); - UsingGLNodes |= genglnodes; - FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes); + // We need GL nodes if am_textured is on. + // In case a sync critical game mode is started, also build GL nodes to avoid problems + // if the different machines' am_textured setting differs. + bool BuildGLNodes = am_textured || multiplayer || demoplayback || demorecording || genglnodes; + FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes); delete[] vertexes; builder.Extract (nodes, numnodes, - segs, numsegs, + segs, glsegextras, numsegs, subsectors, numsubsectors, vertexes, numvertexes); endTime = I_FPSTime (); DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); + reloop = true; + } + + // Copy pointers to the old nodes so that R_PointInSubsector can use them + if (nodes && subsectors) + { + gamenodes = nodes; + numgamenodes = numnodes; + gamesubsectors = subsectors; + numgamesubsectors = numsubsectors; + } + else + { + gamenodes=NULL; + } + + if (RequireGLNodes) + { + // Build GL nodes if we want a textured automap or GL nodes are forced to be built. + // If the original nodes being loaded are not GL nodes they will be kept around for + // use in P_PointInSubsector to avoid problems with maps that depend on the specific + // nodes they were built with (P:AR E1M3 is a good example for a map where this is the case.) + reloop |= P_CheckNodes(map, ForceNodeBuild, endTime - startTime); + hasglnodes = true; + } + else + { + hasglnodes = P_CheckForGLNodes(); } times[10].Clock(); @@ -3798,6 +3874,11 @@ void P_SetupLevel (char *lumpname, int position) P_FloodZones (); times[13].Unclock(); + if (hasglnodes) + { + P_SetRenderSector(); + } + bodyqueslot = 0; // phares 8/10/98: Clear body queue so the corpses from previous games are // not assumed to be from this one. @@ -3845,7 +3926,7 @@ void P_SetupLevel (char *lumpname, int position) P_SpawnSpecials (); times[16].Clock(); - if (ForceNodeBuild) P_LoopSidedefs (false); + if (reloop) P_LoopSidedefs (false); PO_Init (); // Initialize the polyobjs times[16].Unclock(); @@ -3922,6 +4003,12 @@ void P_SetupLevel (char *lumpname, int position) } } MapThingsConverted.Clear(); + + if (glsegextras != NULL) + { + delete[] glsegextras; + glsegextras = NULL; + } } diff --git a/src/p_setup.h b/src/p_setup.h index 80196e317..aa860af0e 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -111,6 +111,12 @@ int P_TranslateSectorSpecial (int); int GetUDMFInt(int type, int index, const char *key); fixed_t GetUDMFFixed(int type, int index, const char *key); +bool P_LoadGLNodes(MapData * map); +bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime); +bool P_CheckForGLNodes(); +void P_SetRenderSector(); + + struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init { union @@ -133,5 +139,7 @@ struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init }; }; extern sidei_t *sidetemp; +extern bool hasglnodes; +extern struct glsegextra_t *glsegextras; #endif diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e75d324df..5f2fca941 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1227,6 +1227,10 @@ public: sec->seqType = -1; continue; + case NAME_hidden: + sec->MoreFlags |= SECF_HIDDEN; + break; + default: break; } diff --git a/src/po_man.cpp b/src/po_man.cpp index 1aa065c19..7619bd06a 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1827,12 +1827,6 @@ void PO_Init (void) // [RH] Don't need the seg lists anymore KillSideLists (); - // We still need to flag the segs of the polyobj's sidedefs so that they are excluded from rendering. - for(int i=0;iFlags & WALLF_POLYOBJ); - } - for(int i=0;i WallMirrors; static FNodeBuilder::FLevel PolyNodeLevel; static FNodeBuilder PolyNodeBuilder(PolyNodeLevel); +static subsector_t *InSubsector; + CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? @@ -167,10 +170,11 @@ static cliprange_t solidsegs[MAXWIDTH/2+2]; // //========================================================================== -void R_ClipWallSegment (int first, int last, bool solid) +bool R_ClipWallSegment (int first, int last, bool solid) { cliprange_t *next, *start; int i, j; + bool res = false; // Find the first range that touches the range // (adjacent pixels are touching). @@ -180,6 +184,7 @@ void R_ClipWallSegment (int first, int last, bool solid) if (first < start->first) { + res = true; if (last <= start->first) { // Post is entirely visible (above start). @@ -205,7 +210,7 @@ void R_ClipWallSegment (int first, int last, bool solid) next->last = last; } } - return; + return true; } // There is a fragment above *start. @@ -220,7 +225,7 @@ void R_ClipWallSegment (int first, int last, bool solid) // Bottom contained in start? if (last <= start->last) - return; + return res; next = start; while (last >= (next+1)->first) @@ -257,6 +262,31 @@ crunch: newend = start+i; } } + return true; +} + +bool R_CheckClipWallSegment (int first, int last) +{ + cliprange_t *start; + + // Find the first range that touches the range + // (adjacent pixels are touching). + start = solidsegs; + while (start->last < first) + start++; + + if (first < start->first) + { + return true; + } + + // Bottom contained in start? + if (last > start->last) + { + return true; + } + + return false; } @@ -626,6 +656,10 @@ void R_AddLine (seg_t *line) if (line->linedef == NULL) { + if (R_CheckClipWallSegment (WallSX1, WallSX2)) + { + InSubsector->flags |= SSECF_DRAWN; + } return; } @@ -792,6 +826,16 @@ void R_AddLine (seg_t *line) // Reject empty lines used for triggers and special events. // Identical floor and ceiling on both sides, identical light levels // on both sides, and no middle texture. + + // When using GL nodes, do a clipping test for these lines so we can + // mark their subsectors as visible for automap texturing. + if (hasglnodes && !(InSubsector->flags & SSECF_DRAWN)) + { + if (R_CheckClipWallSegment(WallSX1, WallSX2)) + { + InSubsector->flags |= SSECF_DRAWN; + } + } return; } } @@ -827,7 +871,10 @@ void R_AddLine (seg_t *line) #endif } - R_ClipWallSegment (WallSX1, WallSX2, solid); + if (R_ClipWallSegment (WallSX1, WallSX2, solid)) + { + InSubsector->flags |= SSECF_DRAWN; + } } @@ -1096,12 +1143,21 @@ void R_Subsector (subsector_t *sub) sector_t tempsec; // killough 3/7/98: deep water hack int floorlightlevel; // killough 3/16/98: set floor lightlevel int ceilinglightlevel; // killough 4/11/98 + bool outersubsector; + + if (InSubsector != NULL) + { // InSubsector is not NULL. This means we are rendering from a mini-BSP. + outersubsector = false; + } + else + { + outersubsector = true; + InSubsector = sub; + } -#if 0 #ifdef RANGECHECK - if (sub - subsectors >= (ptrdiff_t)numsubsectors) + if (outersubsector && sub - subsectors >= (ptrdiff_t)numsubsectors) I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors); -#endif #endif assert(sub->sector != NULL); @@ -1109,6 +1165,10 @@ void R_Subsector (subsector_t *sub) if (sub->polys) { // Render the polyobjs in the subsector first R_AddPolyobjs(sub); + if (outersubsector) + { + InSubsector = NULL; + } return; } @@ -1190,12 +1250,16 @@ void R_Subsector (subsector_t *sub) while (count--) { - if (!line->bPolySeg) + if (!outersubsector || line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ)) { R_AddLine (line); } line++; } + if (outersubsector) + { + InSubsector = NULL; + } } // diff --git a/src/r_defs.h b/src/r_defs.h index 3c8ab46d7..55b896a80 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -319,6 +319,7 @@ enum SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater SECF_UNDERWATERMASK = 32+64, SECF_DRAWN = 128, // sector has been drawn at least once + SECF_HIDDEN = 256, // Do not draw on textured automap }; enum @@ -942,10 +943,12 @@ struct seg_t // Sector references. Could be retrieved from linedef, too. sector_t* frontsector; sector_t* backsector; // NULL for one-sided lines +}; - seg_t* PartnerSeg; - - BITFIELD bPolySeg:1; +struct glsegextra_t +{ + DWORD PartnerSeg; + subsector_t *Subsector; }; // @@ -954,13 +957,22 @@ struct seg_t // Basically, this is a list of LineSegs indicating the visible walls that // define (all or some) sides of a convex BSP leaf. // + +enum +{ + SSECF_DEGENERATE = 1, + SSECF_DRAWN = 2, +}; + struct subsector_t { sector_t *sector; FPolyNode *polys; FMiniBSP *BSP; seg_t *firstline; + sector_t *render_sector; DWORD numlines; + int flags; }; diff --git a/src/r_draw.cpp b/src/r_draw.cpp index ce836f839..4334f6f79 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -1000,6 +1000,77 @@ const BYTE* ds_source; // just for profiling int dscount; + +#ifdef X86_ASM +extern "C" void R_SetSpanSource_ASM (const BYTE *flat); +extern "C" void STACK_ARGS R_SetSpanSize_ASM (int xbits, int ybits); +extern "C" void R_SetSpanColormap_ASM (BYTE *colormap); +extern "C" BYTE *ds_curcolormap, *ds_cursource, *ds_curtiltedsource; +#endif +} + +//========================================================================== +// +// R_SetSpanSource +// +// Sets the source bitmap for the span drawing routines. +// +//========================================================================== + +void R_SetSpanSource(const BYTE *pixels) +{ + ds_source = pixels; +#ifdef X86_ASM + if (ds_cursource != ds_source) + { + R_SetSpanSource_ASM(pixels); + } +#endif +} + +//========================================================================== +// +// R_SetSpanColormap +// +// Sets the colormap for the span drawing routines. +// +//========================================================================== + +void R_SetSpanColormap(BYTE *colormap) +{ + ds_colormap = colormap; +#ifdef X86_ASM + if (ds_colormap != ds_curcolormap) + { + R_SetSpanColormap_ASM (ds_colormap); + } +#endif +} + +//========================================================================== +// +// R_SetupSpanBits +// +// Sets the texture size for the span drawing routines. +// +//========================================================================== + +void R_SetupSpanBits(FTexture *tex) +{ + tex->GetWidth (); + ds_xbits = tex->WidthBits; + ds_ybits = tex->HeightBits; + if ((1 << ds_xbits) > tex->GetWidth()) + { + ds_xbits--; + } + if ((1 << ds_ybits) > tex->GetHeight()) + { + ds_ybits--; + } +#ifdef X86_ASM + R_SetSpanSize_ASM (ds_xbits, ds_ybits); +#endif } // diff --git a/src/r_draw.h b/src/r_draw.h index 4d452b49d..96e58bf8d 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -91,8 +91,11 @@ extern void (*R_DrawShadedColumn)(void); // Green/Red/Blue/Indigo shirts. extern void (*R_DrawTranslatedColumn)(void); -// Span drawing for rows, floor/ceiling. No Sepctre effect needed. +// Span drawing for rows, floor/ceiling. No Spectre effect needed. extern void (*R_DrawSpan)(void); +void R_SetupSpanBits(FTexture *tex); +void R_SetSpanColormap(BYTE *colormap); +void R_SetSpanSource(const BYTE *pixels); // Span drawing for masked textures. extern void (*R_DrawSpanMasked)(void); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index b89a2979e..cd0b9f4a5 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -991,22 +991,9 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool masked) { // Don't waste time on a masked texture if it isn't really masked. masked = false; } - tex->GetWidth (); - ds_xbits = tex->WidthBits; - ds_ybits = tex->HeightBits; - if ((1 << ds_xbits) > tex->GetWidth()) - { - ds_xbits--; - } - if ((1 << ds_ybits) > tex->GetHeight()) - { - ds_ybits--; - } + R_SetupSpanBits(tex); pl->xscale = MulScale16 (pl->xscale, tex->xScale); pl->yscale = MulScale16 (pl->yscale, tex->yScale); -#ifdef X86_ASM - R_SetSpanSize_ASM (ds_xbits, ds_ybits); -#endif ds_source = tex->GetPixels (); basecolormap = pl->colormap; diff --git a/src/r_plane.h b/src/r_plane.h index d52fc6db2..369083bad 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -110,5 +110,4 @@ bool R_PlaneInitData (void); extern visplane_t* floorplane; extern visplane_t* ceilingplane; - #endif // __R_PLANE_H__ diff --git a/src/r_polymost.cpp b/src/r_polymost.cpp index 2cb3e2225..12050440f 100644 --- a/src/r_polymost.cpp +++ b/src/r_polymost.cpp @@ -1485,7 +1485,7 @@ void RP_Subsector (subsector_t *sub) while (count--) { - if (!line->bPolySeg) + if (line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ)) { RP_AddLine (line); } diff --git a/src/r_state.h b/src/r_state.h index 38f8e4c3e..9044da72b 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -77,6 +77,13 @@ extern side_t* sides; extern int numzones; extern zone_t* zones; +extern node_t * gamenodes; +extern int numgamenodes; + +extern subsector_t * gamesubsectors; +extern int numgamesubsectors; + + extern FExtraLight* ExtraLights; extern FLightStack* LightStacks; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 3c2ed74d0..af6b804d1 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -62,6 +62,9 @@ int CleanWidth, CleanHeight; // Above minus 1 (or 1, if they are already 1) int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; +// FillSimplePoly uses this +extern "C" short spanend[MAXHEIGHT]; + CVAR (Bool, hud_scale, false, CVAR_ARCHIVE); // For routines that take RGB colors, cache the previous lookup in case there @@ -69,6 +72,7 @@ CVAR (Bool, hud_scale, false, CVAR_ARCHIVE); static int LastPal = -1; static uint32 LastRGB; + static int PalFromRGB(uint32 rgb) { if (LastPal >= 0 && LastRGB == rgb) @@ -186,7 +190,7 @@ void STACK_ARGS DCanvas::DrawTextureV(FTexture *img, double x, double y, uint32 double iyscale = 1 / yscale; spryscale = FLOAT2FIXED(yscale); - + assert(spryscale > 2); #if 0 // Fix precision errors that are noticeable at some resolutions if ((y0 + parms.destheight) > (y0 + yscale * img->GetHeight())) @@ -1091,6 +1095,172 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin } } +//========================================================================== +// +// DCanvas :: FillSimplePoly +// +// Fills a simple polygon with a texture. Here, "simple" means that a +// horizontal scanline at any vertical position within the polygon will +// not cross it more than twice. +// +// The originx, originy, scale, and rotation parameters specify +// transformation of the filling texture, not of the points. +// +// The points must be specified in clockwise order. +// +//========================================================================== + +void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, angle_t rotation, + FDynamicColormap *colormap, int lightlevel) +{ + // Use an equation similar to player sprites to determine shade + fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT; + float topy, boty, leftx, rightx; + int toppt, botpt, pt1, pt2; + int i; + int y1, y2, y; + fixed_t x; + double rot = rotation * M_PI / double(1u << 31); + bool dorotate = rot != 0; + double cosrot, sinrot; + + if (--npoints < 2 || Buffer == NULL) + { // not a polygon or we're not locked + return; + } + + // Find the extents of the polygon, in particular the highest and lowest points. + for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i) + { + if (points[i].Y < topy) + { + topy = points[i].Y; + toppt = i; + } + if (points[i].Y > boty) + { + boty = points[i].Y; + botpt = i; + } + if (points[i].X < leftx) + { + leftx = points[i].X; + } + if (points[i].X > rightx) + { + rightx = points[i].X; + } + } + if (topy >= Height || // off the bottom of the screen + boty <= 0 || // off the top of the screen + leftx >= Width || // off the right of the screen + rightx <= 0) // off the left of the screen + { + return; + } + + cosrot = cos(rot); + sinrot = sin(rot); + + // Setup constant texture mapping parameters. + R_SetupSpanBits(tex); + R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap); + R_SetSpanSource(tex->GetPixels()); + scalex = double(1u << (32 - ds_xbits)) / scalex; + scaley = double(1u << (32 - ds_ybits)) / scaley; + ds_xstep = xs_RoundToInt(cosrot * scalex); + ds_ystep = xs_RoundToInt(sinrot * scaley); + + // Travel down the right edge and create an outline of that edge. + pt1 = toppt; + pt2 = toppt + 1; if (pt2 > npoints) pt2 = 0; + y1 = xs_RoundToInt(points[pt1].Y + 0.5f); + do + { + x = FLOAT2FIXED(points[pt1].X + 0.5f); + y2 = xs_RoundToInt(points[pt2].Y + 0.5f); + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + { + } + else + { + fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); + int y3 = MIN(y2, Height); + if (y1 < 0) + { + x += xinc * -y1; + y1 = 0; + } + for (y = y1; y < y3; ++y) + { + spanend[y] = clamp(x >> FRACBITS, -1, Width); + x += xinc; + } + } + y1 = y2; + pt1 = pt2; + pt2++; if (pt2 > npoints) pt2 = 0; + } while (pt1 != botpt); + + // Travel down the left edge and fill it in. + pt1 = toppt; + pt2 = toppt - 1; if (pt2 < 0) pt2 = npoints; + y1 = xs_RoundToInt(points[pt1].Y + 0.5f); + do + { + x = FLOAT2FIXED(points[pt1].X + 0.5f); + y2 = xs_RoundToInt(points[pt2].Y + 0.5f); + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + { + } + else + { + fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); + int y3 = MIN(y2, Height); + if (y1 < 0) + { + x += xinc * -y1; + y1 = 0; + } + for (y = y1; y < y3; ++y) + { + int x1 = x >> FRACBITS; + int x2 = spanend[y]; + if (x2 > x1 && x2 > 0 && x1 < Width) + { + x1 = MAX(x1, 0); + x2 = MIN(x2, Width); +#if 0 + memset(this->Buffer + y * this->Pitch + x1, (int)tex, x2 - x1); +#else + ds_y = y; + ds_x1 = x1; + ds_x2 = x2 - 1; + + TVector2 tex(x1 - originx, y - originy); + if (dorotate) + { + double t = tex.X; + tex.X = t * cosrot - tex.Y * sinrot; + tex.Y = tex.Y * cosrot + t * sinrot; + } + ds_xfrac = xs_RoundToInt(tex.X * scalex); + ds_yfrac = xs_RoundToInt(tex.Y * scaley); + + R_DrawSpan(); +#endif + } + x += xinc; + } + } + y1 = y2; + pt1 = pt2; + pt2--; if (pt2 < 0) pt2 = npoints; + } while (pt1 != botpt); +} + + /********************************/ /* */ /* Other miscellaneous routines */ diff --git a/src/v_video.h b/src/v_video.h index 77a3f8a65..b1ba7a863 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -133,6 +133,7 @@ enum class FFont; struct FRemapTable; class player_t; +typedef uint32 angle_t; // // VIDEO @@ -175,6 +176,11 @@ public: // Fill an area with a texture virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); + // Fill a simple polygon with a texture + virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, angle_t rotation, + struct FDynamicColormap *colormap, int lightlevel); + // Set an area to a specified color virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color); diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index b2c8e1bfa..020be2de1 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -278,7 +278,7 @@ D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen) GatheringWipeScreen = false; ScreenWipe = NULL; InScene = false; - QuadExtra = new BufferedQuad[MAX_QUAD_BATCH]; + QuadExtra = new BufferedTris[MAX_QUAD_BATCH]; Packs = NULL; PixelDoubling = 0; SkipAt = -1; @@ -1865,7 +1865,7 @@ void D3DFB::DrawPackedTextures(int packnum) CheckQuadBatch(); - BufferedQuad *quad = &QuadExtra[QuadBatchPos]; + BufferedTris *quad = &QuadExtra[QuadBatchPos]; FBVERTEX *vert = &VertexData[VertexPos]; quad->Group1 = 0; @@ -1881,6 +1881,8 @@ void D3DFB::DrawPackedTextures(int packnum) } quad->Palette = NULL; quad->Texture = pack->Tex; + quad->NumVerts = 4; + quad->NumTris = 2; float x0 = float(x) - 0.5f; float y0 = float(y) - 0.5f; @@ -3021,16 +3023,20 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, double x, double y, uint32 t parms.bilinear = false; D3DCOLOR color0, color1; - if (!SetStyle(tex, parms, color0, color1, QuadExtra[QuadBatchPos])) + BufferedTris *quad = &QuadExtra[QuadBatchPos]; + + if (!SetStyle(tex, parms, color0, color1, *quad)) { return; } - QuadExtra[QuadBatchPos].Texture = tex->Box->Owner->Tex; + quad->Texture = tex->Box->Owner->Tex; if (parms.bilinear) { - QuadExtra[QuadBatchPos].Flags |= BQF_Bilinear; + quad->Flags |= BQF_Bilinear; } + quad->NumTris = 2; + quad->NumVerts = 4; float yoffs = GatheringWipeScreen ? 0.5f : 0.5f - LBOffset; @@ -3152,7 +3158,7 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo CheckQuadBatch(); - BufferedQuad *quad = &QuadExtra[QuadBatchPos]; + BufferedTris *quad = &QuadExtra[QuadBatchPos]; FBVERTEX *vert = &VertexData[VertexPos]; quad->Group1 = 0; @@ -3168,6 +3174,8 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo } quad->Palette = NULL; quad->Texture = tex->Box->Owner->Tex; + quad->NumVerts = 4; + quad->NumTris = 2; vert[0].x = x0; vert[0].y = y0; @@ -3217,6 +3225,128 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo IndexPos += 6; } +//========================================================================== +// +// D3DFB :: FillSimplePoly +// +// Here, "simple" means that a simple triangle fan can draw it. +// +//========================================================================== + +void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + angle_t rotation, FDynamicColormap *colormap, int lightlevel) +{ + // Use an equation similar to player sprites to determine shade + fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT; + BufferedTris *quad; + FBVERTEX *verts; + D3DTex *tex; + float yoffs, uscale, vscale; + int i, ipos; + D3DCOLOR color0, color1; + float ox, oy; + float cosrot, sinrot; + float rot = float(rotation * M_PI / float(1u << 31)); + bool dorotate = rot != 0; + + if (npoints < 3) + { // This is no polygon. + return; + } + if (In2D < 2) + { + Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel); + return; + } + if (!InScene) + { + return; + } + tex = static_cast(texture->GetNative(true)); + if (tex == NULL) + { + return; + } + + cosrot = cos(rot); + sinrot = sin(rot); + + CheckQuadBatch(npoints - 2, npoints); + quad = &QuadExtra[QuadBatchPos]; + verts = &VertexData[VertexPos]; + + color0 = 0; + color1 = 0xFFFFFFFF; + + quad->Group1 = 0; + if (tex->GetTexFormat() == D3DFMT_L8 && !tex->IsGray) + { + quad->Flags = BQF_WrapUV | BQF_GamePalette | BQF_DisableAlphaTest; + quad->ShaderNum = BQS_PalTex; + if (colormap != NULL) + { + if (colormap->Desaturate != 0) + { + quad->Flags |= BQF_Desaturated; + } + quad->ShaderNum = BQS_InGameColormap; + color0 = D3DCOLOR_ARGB(colormap->Desaturate, + colormap->Color.r, colormap->Color.g, colormap->Color.b); + double fadelevel = clamp(shade / (NUMCOLORMAPS * 65536.0), 0.0, 1.0); + color1 = D3DCOLOR_ARGB(DWORD((1 - fadelevel) * 255), + DWORD(colormap->Fade.r * fadelevel), + DWORD(colormap->Fade.g * fadelevel), + DWORD(colormap->Fade.b * fadelevel)); + } + } + else + { + quad->Flags = BQF_WrapUV | BQF_DisableAlphaTest; + quad->ShaderNum = BQS_Plain; + } + quad->Palette = NULL; + quad->Texture = tex->Box->Owner->Tex; + quad->NumVerts = npoints; + quad->NumTris = npoints - 2; + + yoffs = GatheringWipeScreen ? 0 : LBOffset; + uscale = float(1.f / (texture->GetWidth() * scalex)); + vscale = float(1.f / (texture->GetHeight() * scaley)); + ox = float(originx); + oy = float(originy); + + for (i = 0; i < npoints; ++i) + { + verts[i].x = points[i].X; + verts[i].y = points[i].Y + yoffs; + verts[i].z = 0; + verts[i].rhw = 1; + verts[i].color0 = color0; + verts[i].color1 = color1; + float u = points[i].X - 0.5f - ox; + float v = points[i].Y - 0.5f - oy; + if (dorotate) + { + float t = u; + u = t * cosrot - v * sinrot; + v = v * cosrot + t * sinrot; + } + verts[i].tu = u * uscale; + verts[i].tv = v * vscale; + } + for (ipos = IndexPos, i = 2; i < npoints; ++i, ipos += 3) + { + IndexData[ipos ] = VertexPos; + IndexData[ipos + 1] = VertexPos + i - 1; + IndexData[ipos + 2] = VertexPos + i; + } + + QuadBatchPos++; + VertexPos += npoints; + IndexPos = ipos; +} + //========================================================================== // // D3DFB :: AddColorOnlyQuad @@ -3227,7 +3357,7 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color) { - BufferedQuad *quad; + BufferedTris *quad; FBVERTEX *verts; CheckQuadBatch(); @@ -3247,6 +3377,8 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR } quad->Palette = NULL; quad->Texture = NULL; + quad->NumVerts = 4; + quad->NumTris = 2; verts[0].x = x; verts[0].y = y; @@ -3300,17 +3432,19 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR // // D3DFB :: CheckQuadBatch // -// Make sure there's enough room in the batch for one more quad. +// Make sure there's enough room in the batch for one more set of triangles. // //========================================================================== -void D3DFB::CheckQuadBatch() +void D3DFB::CheckQuadBatch(int numtris, int numverts) { if (BatchType == BATCH_Lines) { EndLineBatch(); } - else if (QuadBatchPos == MAX_QUAD_BATCH) + else if (QuadBatchPos == MAX_QUAD_BATCH || + VertexPos + numverts > NUM_VERTS || + IndexPos + numtris * 3 > NUM_INDEXES) { EndQuadBatch(); } @@ -3371,23 +3505,33 @@ void D3DFB::EndQuadBatch() D3DDevice->SetIndices(IndexBuffer); bool uv_wrapped = false; bool uv_should_wrap; + int indexpos, vertpos; + indexpos = vertpos = 0; for (int i = 0; i < QuadBatchPos; ) { - const BufferedQuad *quad = &QuadExtra[i]; + const BufferedTris *quad = &QuadExtra[i]; int j; + int startindex = indexpos; + int startvertex = vertpos; + + indexpos += quad->NumTris * 3; + vertpos += quad->NumVerts; + // Quads with matching parameters should be done with a single // DrawPrimitive call. for (j = i + 1; j < QuadBatchPos; ++j) { - const BufferedQuad *q2 = &QuadExtra[j]; + const BufferedTris *q2 = &QuadExtra[j]; if (quad->Texture != q2->Texture || quad->Group1 != q2->Group1 || quad->Palette != q2->Palette) { break; } + indexpos += q2->NumTris * 3; + vertpos += q2->NumVerts; } // Set the palette (if one) @@ -3467,7 +3611,12 @@ void D3DFB::EndQuadBatch() } // Draw the quad - D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4 * i, 4 * (j - i), 6 * i, 2 * (j - i)); + D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, + startvertex, // MinIndex + vertpos - startvertex, // NumVertices + startindex, // StartIndex + (indexpos - startindex) / 3 // PrimitiveCount + /*4 * i, 4 * (j - i), 6 * i, 2 * (j - i)*/); i = j; } if (uv_wrapped) @@ -3508,7 +3657,7 @@ void D3DFB::EndBatch() // //========================================================================== -bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedQuad &quad) +bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedTris &quad) { D3DFORMAT fmt = tex->GetTexFormat(); FRenderStyle style = parms.style; diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp index 9024fa804..3407136aa 100644 --- a/src/win32/fb_d3d9_wipe.cpp +++ b/src/win32/fb_d3d9_wipe.cpp @@ -466,7 +466,7 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) { fb->CheckQuadBatch(); - BufferedQuad *quad = &fb->QuadExtra[fb->QuadBatchPos]; + BufferedTris *quad = &fb->QuadExtra[fb->QuadBatchPos]; FBVERTEX *vert = &fb->VertexData[fb->VertexPos]; WORD *index = &fb->IndexData[fb->IndexPos]; @@ -475,6 +475,8 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) quad->ShaderNum = BQS_Plain; quad->Palette = NULL; quad->Texture = fb->InitialWipeScreen; + quad->NumVerts = 4; + quad->NumTris = 2; // Fill the vertex buffer. float u0 = rect.left / float(fb->FBWidth); diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index e46c392c3..62f06fa99 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -257,6 +257,9 @@ public: void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin); void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor); void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor); + void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + angle_t rotation, FDynamicColormap *colormap, int lightlevel); bool WipeStartScreen(int type); void WipeEndScreen(); bool WipeDo(int ticks); @@ -278,7 +281,7 @@ private: }; #define D3DFVF_FBVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1) - struct BufferedQuad + struct BufferedTris { union { @@ -293,6 +296,8 @@ private: }; D3DPal *Palette; IDirect3DTexture9 *Texture; + WORD NumVerts; // Number of _unique_ vertices used by this set. + WORD NumTris; // Number of triangles used by this set. }; enum @@ -355,12 +360,12 @@ private: void DrawPackedTextures(int packnum); void DrawLetterbox(); void Draw3DPart(bool copy3d); - bool SetStyle(D3DTex *tex, DCanvas::DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedQuad &quad); + bool SetStyle(D3DTex *tex, DCanvas::DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedTris &quad); static D3DBLEND GetStyleAlpha(int type); static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1); void DoWindowedGamma(); void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color); - void CheckQuadBatch(); + void CheckQuadBatch(int numtris=2, int numverts=4); void BeginQuadBatch(); void EndQuadBatch(); void BeginLineBatch(); @@ -433,7 +438,7 @@ private: FBVERTEX *VertexData; IDirect3DIndexBuffer9 *IndexBuffer; WORD *IndexData; - BufferedQuad *QuadExtra; + BufferedTris *QuadExtra; int VertexPos; int IndexPos; int QuadBatchPos; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 883b0e325..6a7580fbf 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -268,6 +268,8 @@ AMSTR_FOLLOWON = "Follow Mode ON"; AMSTR_FOLLOWOFF = "Follow Mode OFF"; AMSTR_GRIDON = "Grid ON"; AMSTR_GRIDOFF = "Grid OFF"; +AMSTR_TEXON = "Texture Mode ON"; +AMSTR_TEXOFF = "Texture Mode OFF"; AMSTR_MARKEDSPOT = "Marked Spot"; AMSTR_MARKSCLEARED = "All Marks Cleared"; STSTR_MUS = "Music Change"; diff --git a/zdoom.vcproj b/zdoom.vcproj index 21247821f..b2a3f4fe3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -804,6 +804,10 @@ RelativePath=".\src\p_floor.cpp" > + + From a11e70bf5f8d97ec6893673fc6d668bbae1e058a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Aug 2010 15:22:21 +0000 Subject: [PATCH 208/251] - changed savegame version check for automap stuff. SVN r2610 (trunk) --- src/p_saveg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 1b4442649..52ebf88d2 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -606,7 +606,7 @@ void P_SerializeSubsectors(FArchive &arc) } else { - if (SaveVersion < 2500) + if (SaveVersion < 2609) { if (hasglnodes) { From 2152bc88d604e5895d6150b8a71ace996ef8fd12 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Aug 2010 16:06:10 +0000 Subject: [PATCH 209/251] - fixed CROSSHAIR_INDEX in m_options.cpp. SVN r2611 (trunk) --- src/m_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_options.cpp b/src/m_options.cpp index dae45c994..fc5f1b7bb 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -522,7 +522,7 @@ static menuitem_t VideoItems[] = { { discrete, "Display nametags", {&displaynametags}, {4.0}, {0.0}, {0.0}, {DisplayTagsTypes} }, }; -#define CROSSHAIR_INDEX 7 +#define CROSSHAIR_INDEX 6 menu_t VideoMenu = { From 3afa8149deaa0bbe1968ed80f56ed5095fa69534 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Aug 2010 16:53:11 +0000 Subject: [PATCH 210/251] - added a fix from GZDoom to handle levels with compressed sidedefs that were processed by older ZDBSPs. SVN r2612 (trunk) --- src/p_setup.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b0a92b2c4..3f7f91454 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3830,6 +3830,28 @@ void P_SetupLevel (char *lumpname, int position) DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); reloop = true; } + else + { + // Older ZDBSPs had problems with compressed sidedefs and assigned wrong sides to the segs if both sides were the same sidedef. + for(i=0;ibacksector == seg->frontsector && seg->linedef) + { + fixed_t d1=P_AproxDistance(seg->v1->x-seg->linedef->v1->x,seg->v1->y-seg->linedef->v1->y); + fixed_t d2=P_AproxDistance(seg->v2->x-seg->linedef->v1->x,seg->v2->y-seg->linedef->v1->y); + + if (d2sidedef = seg->linedef->sidedef[1]; + } + else // front side + { + seg->sidedef = seg->linedef->sidedef[0]; + } + } + } + } // Copy pointers to the old nodes so that R_PointInSubsector can use them if (nodes && subsectors) From ece980d372741046cb0253777ff2ee95e15bf6cd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 27 Aug 2010 17:34:25 +0000 Subject: [PATCH 211/251] - fixed check for GL nodebuild SVN r2613 (trunk) --- src/p_setup.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 3f7f91454..d8e86a9cd 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3803,8 +3803,10 @@ void P_SetupLevel (char *lumpname, int position) unsigned int startTime=0, endTime=0; + bool BuildGLNodes; if (ForceNodeBuild) { + BuildGLNodes = am_textured || multiplayer || demoplayback || demorecording || genglnodes; startTime = I_FPSTime (); TArray polyspots, anchors; @@ -3819,7 +3821,6 @@ void P_SetupLevel (char *lumpname, int position) // We need GL nodes if am_textured is on. // In case a sync critical game mode is started, also build GL nodes to avoid problems // if the different machines' am_textured setting differs. - bool BuildGLNodes = am_textured || multiplayer || demoplayback || demorecording || genglnodes; FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes); delete[] vertexes; builder.Extract (nodes, numnodes, @@ -3832,6 +3833,7 @@ void P_SetupLevel (char *lumpname, int position) } else { + BuildGLNodes = false; // Older ZDBSPs had problems with compressed sidedefs and assigned wrong sides to the segs if both sides were the same sidedef. for(i=0;i Date: Fri, 27 Aug 2010 17:49:27 +0000 Subject: [PATCH 212/251] - disable check for hidden sectors because it does more harm than good. - don't draw a textured automap in overlay mode. SVN r2614 (trunk) --- src/am_map.cpp | 2 +- src/p_glnodes.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 63d328c64..fd3f4373f 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2353,7 +2353,7 @@ void AM_Drawer () } AM_activateNewScale(); - if (am_textured && hasglnodes && textured) + if (am_textured && hasglnodes && textured && !viewactive) AM_drawSubsectors(); if (grid) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 426552c37..f08ef55ed 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1387,6 +1387,8 @@ void P_SetRenderSector() TArray undetermined; subsector_t * ss; +#if 0 // doesn't work as expected :( + // hide all sectors on textured automap that only have hidden lines. bool *hidesec = new bool[numsectors]; for(i = 0; i < numsectors; i++) @@ -1409,6 +1411,7 @@ void P_SetRenderSector() if (hidesec[i]) sectors[i].MoreFlags |= SECF_HIDDEN; } delete [] hidesec; +#endif // Check for incorrect partner seg info so that the following code does not crash. for(i=0;i Date: Fri, 27 Aug 2010 20:03:40 +0000 Subject: [PATCH 213/251] - fixed Hexen's flame calls to A_CountdownArg. SVN r2615 (trunk) --- wadsrc/static/actors/hexen/flame.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/wadsrc/static/actors/hexen/flame.txt b/wadsrc/static/actors/hexen/flame.txt index c3a222ea6..984c2d90c 100644 --- a/wadsrc/static/actors/hexen/flame.txt +++ b/wadsrc/static/actors/hexen/flame.txt @@ -10,10 +10,10 @@ ACTOR FlameSmallTemp 10500 { Spawn: FFSM AB 3 Bright - FFSM C 2 Bright A_CountdownArg(1) + FFSM C 2 Bright A_CountdownArg(0) FFSM C 2 Bright FFSM D 3 Bright - FFSM E 3 Bright A_CountdownArg(1) + FFSM E 3 Bright A_CountdownArg(0) Loop } } @@ -31,21 +31,21 @@ ACTOR FlameLargeTemp 10502 { Spawn: FFLG A 4 Bright - FFLG B 4 Bright A_CountdownArg(1) + FFLG B 4 Bright A_CountdownArg(0) FFLG C 4 Bright - FFLG D 4 Bright A_CountdownArg(1) + FFLG D 4 Bright A_CountdownArg(0) FFLG E 4 Bright - FFLG F 4 Bright A_CountdownArg(1) + FFLG F 4 Bright A_CountdownArg(0) FFLG G 4 Bright - FFLG H 4 Bright A_CountdownArg(1) + FFLG H 4 Bright A_CountdownArg(0) FFLG I 4 Bright - FFLG J 4 Bright A_CountdownArg(1) + FFLG J 4 Bright A_CountdownArg(0) FFLG K 4 Bright - FFLG L 4 Bright A_CountdownArg(1) + FFLG L 4 Bright A_CountdownArg(0) FFLG M 4 Bright - FFLG N 4 Bright A_CountdownArg(1) + FFLG N 4 Bright A_CountdownArg(0) FFLG O 4 Bright - FFLG P 4 Bright A_CountdownArg(1) + FFLG P 4 Bright A_CountdownArg(0) Goto Spawn+4 } } From 0d5386740901d9b9152a1d09af76523ece19ffd2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 28 Aug 2010 01:46:26 +0000 Subject: [PATCH 214/251] - Changed the default key for am_toggletexture to P so as not to conflict with the default chat key. SVN r2616 (trunk) --- src/c_bind.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c_bind.cpp b/src/c_bind.cpp index 6afb0c677..471959f6c 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -176,7 +176,7 @@ static const FBinding DefAutomapBindings[] = { { "f", "am_togglefollow" }, { "g", "am_togglegrid" }, - { "t", "am_toggletexture" }, + { "p", "am_toggletexture" }, { "m", "am_setmark" }, { "c", "am_clearmarks" }, { "0", "am_gobig" }, From 5a9151d7d2631182dbfd59398dc6170cc2ec649c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 11:17:25 +0000 Subject: [PATCH 215/251] - fixed: Extraction of partner segs was broken in the internal node builder. SVN r2617 (trunk) --- src/nodebuild_extract.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index 5355179ea..c4546bb5b 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -115,7 +115,15 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, for (i = 0; i < segCount; ++i) { outSegs[i] = *(seg_t *)&segs[i]; - outSegExtras[i].PartnerSeg = segs[i].Partner; + + if (segs[i].Partner != DWORD_MAX) + { + outSegExtras[i].PartnerSeg = Segs[segs[i].Partner].storedseg; + } + else + { + outSegExtras[i].PartnerSeg = DWORD_MAX; + } } } else From 80f1a63cc9638d204f43f4f0c1ecb94a6bd50b48 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 12:00:42 +0000 Subject: [PATCH 216/251] - fixed: The textured automap node initialization code could crash on maps that only have single isolated sectors. SVN r2618 (trunk) --- src/p_glnodes.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index f08ef55ed..d7332def2 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1414,6 +1414,19 @@ void P_SetRenderSector() #endif // Check for incorrect partner seg info so that the following code does not crash. + if (glsegextras == NULL) + { + // This can be normal nodes, mistakenly identified as GL nodes so we must fill + // in the missing pieces differently. + + for (i = 0; i < numsubsectors; i++) + { + ss = &subsectors[i]; + ss->render_sector = ss->sector; + } + return; + } + for(i=0;i Date: Sat, 28 Aug 2010 12:23:20 +0000 Subject: [PATCH 217/251] - fixed: Hexen's CorpseBloodDrip was missing its death sound. SVN r2619 (trunk) --- wadsrc/static/actors/hexen/hexenspecialdecs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/hexen/hexenspecialdecs.txt b/wadsrc/static/actors/hexen/hexenspecialdecs.txt index 7d4a13a94..e36451e7f 100644 --- a/wadsrc/static/actors/hexen/hexenspecialdecs.txt +++ b/wadsrc/static/actors/hexen/hexenspecialdecs.txt @@ -216,6 +216,7 @@ ACTOR CorpseBloodDrip Gravity 0.125 +MISSILE +NOICEDEATH + DeathSound "Drip" States { Spawn: From 5647fed0cff45865a57d7c4e85be58ff1fad71b1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 12:57:23 +0000 Subject: [PATCH 218/251] - fixed: armor factor application was done wrong. - fixed: APROP_Invulnerable could only be set and unset but not checked. - fixed: Two sided polyobjects applied thrust to sctors in a way that did not work. SVN r2620 (trunk) --- src/g_shared/a_armor.cpp | 19 +++++++++++-------- src/p_acs.cpp | 2 ++ src/po_man.cpp | 12 ++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 6bed525d8..1475f86d2 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -211,16 +211,17 @@ void ABasicArmorPickup::Serialize (FArchive &arc) AInventory *ABasicArmorPickup::CreateCopy (AActor *other) { ABasicArmorPickup *copy = static_cast (Super::CreateCopy (other)); - copy->SavePercent = SavePercent; - copy->SaveAmount = SaveAmount; - copy->MaxAbsorb = MaxAbsorb; - copy->MaxFullAbsorb = MaxFullAbsorb; if (!(ItemFlags & IF_IGNORESKILL)) { SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); } + copy->SavePercent = SavePercent; + copy->SaveAmount = SaveAmount; + copy->MaxAbsorb = MaxAbsorb; + copy->MaxFullAbsorb = MaxFullAbsorb; + return copy; } @@ -291,6 +292,12 @@ void ABasicArmorBonus::Serialize (FArchive &arc) AInventory *ABasicArmorBonus::CreateCopy (AActor *other) { ABasicArmorBonus *copy = static_cast (Super::CreateCopy (other)); + + if (!(ItemFlags & IF_IGNORESKILL)) + { + SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); + } + copy->SavePercent = SavePercent; copy->SaveAmount = SaveAmount; copy->MaxSaveAmount = MaxSaveAmount; @@ -299,10 +306,6 @@ AInventory *ABasicArmorBonus::CreateCopy (AActor *other) copy->MaxAbsorb = MaxAbsorb; copy->MaxFullAbsorb = MaxFullAbsorb; - if (!(ItemFlags & IF_IGNORESKILL)) - { - SaveAmount = FixedMul(SaveAmount, G_SkillProperty(SKILLP_ArmorFactor)); - } return copy; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bf480fe73..556592991 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2759,6 +2759,7 @@ int DLevelScript::GetActorProperty (int tid, int property) // so pretends it's normal. return STYLE_Normal; case APROP_Gravity: return actor->gravity; + case APROP_Invulnerable:return !!(actor->flags2 & MF2_INVULNERABLE); case APROP_Ambush: return !!(actor->flags & MF_AMBUSH); case APROP_Dropped: return !!(actor->flags & MF_DROPPED); case APROP_ChaseGoal: return !!(actor->flags5 & MF5_CHASEGOAL); @@ -2820,6 +2821,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) // Boolean values need to compare to a binary version of value case APROP_Ambush: + case APROP_Invulnerable: case APROP_Dropped: case APROP_ChaseGoal: case APROP_Frightened: diff --git a/src/po_man.cpp b/src/po_man.cpp index 7619bd06a..da8399b3d 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1245,6 +1245,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) bool blocked; ld = sd->linedef; + top = (ld->bbox[BOXTOP]-bmaporgy) >> MAPBLOCKSHIFT; bottom = (ld->bbox[BOXBOTTOM]-bmaporgy) >> MAPBLOCKSHIFT; left = (ld->bbox[BOXLEFT]-bmaporgx) >> MAPBLOCKSHIFT; @@ -1294,6 +1295,17 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) { continue; } + // We have a two-sided linedef so we should only check one side + // so that the thrust from both sides doesn't cancel each other out. + // Best use the one facing the player and ignore the back side. + if (ld->sidedef[1] != NULL) + { + int side = P_PointOnLineSide(mobj->x, mobj->y, ld); + if (ld->sidedef[side] != sd) + { + continue; + } + } ThrustMobj (mobj, sd); blocked = true; } From 1dd3ecd6e2ab9ea5db9b42acaa1ad4fa8e9c49d2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 13:36:41 +0000 Subject: [PATCH 219/251] - fixed: -nosfx deactivated the entire sound system which also made music inoperable. Changed it so that all it does is block sound effects from being started. SVN r2621 (trunk) --- src/s_sound.cpp | 2 +- src/sound/i_sound.cpp | 4 +++- src/sound/i_sound.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 40be1b927..8d6424169 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -827,7 +827,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO FVector3 pos, vel; FRolloffInfo *rolloff; - if (sound_id <= 0 || volume <= 0) + if (sound_id <= 0 || volume <= 0 || nosfx) return NULL; int type; diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index b25bbd6fb..0a946b3c1 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -81,6 +81,7 @@ CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) SoundRenderer *GSnd; +bool nosfx; void I_CloseSound (); @@ -234,7 +235,8 @@ public: void I_InitSound () { /* Get command line options: */ - bool nosound = !!Args->CheckParm ("-nosfx") || !!Args->CheckParm ("-nosound"); + bool nosound = !!Args->CheckParm ("-nosound"); + nosfx = !!Args->CheckParm ("-nosfx"); if (nosound) { diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index d8cf166fc..e5edcbb40 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -143,6 +143,7 @@ public: }; extern SoundRenderer *GSnd; +extern bool nosfx; void I_InitSound (); void I_ShutdownSound (); From 4e1a5144551473293594550ef1ceeec306f60492 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 16:51:41 +0000 Subject: [PATCH 220/251] - fixed: Subsectors which are the origin of polyobjects should not be drawn on the textured automap because the vertices no longer are where they'd be expected to be. SVN r2622 (trunk) --- src/am_map.cpp | 5 +++++ src/po_man.cpp | 17 +++++++++++++++++ src/r_defs.h | 1 + 3 files changed, 23 insertions(+) diff --git a/src/am_map.cpp b/src/am_map.cpp index fd3f4373f..ea5e9c3b4 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1609,6 +1609,11 @@ void AM_drawSubsectors() for (int i = 0; i < numsubsectors; ++i) { + if (subsectors[i].flags & SSECF_POLYORG) + { + continue; + } + if ((!(subsectors[i].flags & SSECF_DRAWN) || (subsectors[i].render_sector->MoreFlags & SECF_HIDDEN)) && am_cheat == 0) { continue; diff --git a/src/po_man.cpp b/src/po_man.cpp index da8399b3d..0f9b0b15a 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1846,6 +1846,23 @@ void PO_Init (void) double fdy = (double)no->dy; no->len = (float)sqrt(fdx * fdx + fdy * fdy); } + + // mark all subsectors which have a seg belonging to a polyobj + // These ones should not be rendered on the textured automap. + for (int i = 0; i < numsubsectors; i++) + { + subsector_t *ss = &subsectors[i]; + for(DWORD j=0;jnumlines; j++) + { + if (ss->firstline[j].sidedef != NULL && + ss->firstline[j].sidedef->Flags & WALLF_POLYOBJ) + { + ss->flags |= SSECF_POLYORG; + break; + } + } + } + } //========================================================================== diff --git a/src/r_defs.h b/src/r_defs.h index 55b896a80..9e0477ac2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -962,6 +962,7 @@ enum { SSECF_DEGENERATE = 1, SSECF_DRAWN = 2, + SSECF_POLYORG = 4, }; struct subsector_t From 387bfc0260566d3c4cbcf96d0be1aab45a7a3896 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 17:19:48 +0000 Subject: [PATCH 221/251] - added 'nospriterename' key to GAMEINFO lump so that PWADs have a means to disable this feature without having to specify a command line switch. SVN r2623 (trunk) --- src/d_main.cpp | 5 +++++ src/w_wad.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 20ba2c467..19ed60437 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -201,6 +201,7 @@ gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe bool PageBlank; FTexture *Page; FTexture *Advisory; +bool nospriterename; cycle_t FrameCycles; @@ -1678,6 +1679,10 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char } while (sc.CheckToken(',')); } + else if (!nextKey.CompareNoCase("NOSPRITERENAME")) + { + nospriterename = true; + } } return iwad; } diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 5727c8bcc..13e7ff14a 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -70,6 +70,7 @@ struct FWadCollection::LumpRecord }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +extern bool nospriterename; // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -759,7 +760,7 @@ void FWadCollection::RenameSprites () } } - renameAll = !!Args->CheckParm ("-oldsprites"); + renameAll = !!Args->CheckParm ("-oldsprites") || nospriterename; for (DWORD i = 0; i < LumpInfo.Size(); i++) { From 56cc0569bbbe730a326c4c356176428a3110ad90 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 17:24:17 +0000 Subject: [PATCH 222/251] - fixed: ArtiPork had wrong frame durations. SVN r2624 (trunk) --- wadsrc/static/actors/raven/artiegg.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/raven/artiegg.txt b/wadsrc/static/actors/raven/artiegg.txt index 466235588..d94f00151 100644 --- a/wadsrc/static/actors/raven/artiegg.txt +++ b/wadsrc/static/actors/raven/artiegg.txt @@ -96,7 +96,7 @@ ACTOR ArtiPork : CustomInventory 30 States { Spawn: - PORK ABCDEFGH 6 + PORK ABCDEFGH 5 Loop Use: TNT1 A 0 A_FireCustomMissile("PorkFX", -15, 0, 0, 0, 1) From eb3340e8725401e162bd3938a77fd864c702c9de Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 19:20:14 +0000 Subject: [PATCH 223/251] - fixed: Clearing a pickup message for inventory items was not possible. Changed it so that "You got a pickup" is AInventory's pickup message and not a default returned when nothing valid is set. SVN r2625 (trunk) --- src/g_shared/a_pickups.cpp | 6 ++---- wadsrc/static/actors/shared/inventory.txt | 1 + wadsrc/static/language.enu | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 3802bd477..30dcd482c 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -890,7 +890,7 @@ void AInventory::Touch (AActor *toucher) { const char * message = PickupMessage (); - if (toucher->CheckLocalView (consoleplayer) + if (message != NULL && *message != 0 && toucher->CheckLocalView (consoleplayer) && (StaticLastMessageTic != gametic || StaticLastMessage != message)) { StaticLastMessageTic = gametic; @@ -960,9 +960,7 @@ void AInventory::DoPickupSpecial (AActor *toucher) const char *AInventory::PickupMessage () { - const char *message = GetClass()->Meta.GetMetaString (AIMETA_PickupMessage); - - return message != NULL? message : "You got a pickup"; + return GetClass()->Meta.GetMetaString (AIMETA_PickupMessage); } //=========================================================================== diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index a61519df0..49b6b39a2 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -5,6 +5,7 @@ ACTOR Inventory native Inventory.InterHubAmount 1 Inventory.UseSound "misc/invuse" Inventory.PickupSound "misc/i_pkup" + Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG" action native A_JumpIfNoAmmo(state label); action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 6a7580fbf..58cc87049 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -286,6 +286,7 @@ STSTR_CHOPPERS = "... doesn't suck - GM"; STSTR_CLEV = "Changing Level...\n"; TXT_BUDDHAON = "Buddha mode ON"; TXT_BUDDHAOFF = "Buddha mode OFF"; +TXT_DEFAULTPICKUPMSG = "You got a pickup"; E1TEXT = "Once you beat the big badasses and\n" From cbff41f481da548251199db6bfacdb6406fbb6f8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 20:22:35 +0000 Subject: [PATCH 224/251] - assws PinkSilver's LOF_NOJUMP submission for A_LookEx. SVN r2626 (trunk) --- src/p_enemy.cpp | 19 +++++++++++-------- src/p_enemy.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 53d87e3dc..01c31794e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1975,14 +1975,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (self->target && !(self->flags & MF_INCHASE)) { - if (seestate) - { - self->SetState (seestate); - } - else - { - self->SetState (self->SeeState); - } + if (!(flags & LOF_NOJUMP)) + { + if (seestate) + { + self->SetState (seestate); + } + else + { + self->SetState (self->SeeState); + } + } } } diff --git a/src/p_enemy.h b/src/p_enemy.h index 1d80e08e3..f996a0c52 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -32,6 +32,7 @@ enum LO_Flags LOF_DONTCHASEGOAL = 4, LOF_NOSEESOUND = 8, LOF_FULLVOLSEESOUND = 16, + LOF_NOJUMP = 32, }; struct FLookExParams From a3c8e0c0428f093c96c01d0e2f7b6ce7a4584da4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 28 Aug 2010 20:25:52 +0000 Subject: [PATCH 225/251] - fixed: P_LineAttack mixed up two flags variables. SVN r2627 (trunk) --- src/p_map.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 06483c44e..f578ec7fe 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3502,12 +3502,12 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, // Note: The puff may not yet be spawned here so we must check the class defaults, not the actor. if (damage || (puffDefaults->flags6 & MF6_FORCEPAIN)) { - int flags = DMG_INFLICTOR_IS_PUFF; + int dmgflags = DMG_INFLICTOR_IS_PUFF; // Allow MF5_PIERCEARMOR on a weapon as well. if (t1->player != NULL && t1->player->ReadyWeapon != NULL && t1->player->ReadyWeapon->flags5 & MF5_PIERCEARMOR) { - flags |= DMG_NO_ARMOR; + dmgflags |= DMG_NO_ARMOR; } if (puff == NULL) @@ -3517,7 +3517,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY); killPuff = true; } - P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, flags); + P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); } if (victim != NULL) { From f9691a24ffab4bdbcce3dfd283009e75e0f44773 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 29 Aug 2010 03:37:41 +0000 Subject: [PATCH 226/251] - Fixed: The automap was too aggressive about hiding markers. SVN r2628 (trunk) --- src/am_map.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index ea5e9c3b4..fd46c8018 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2291,19 +2291,15 @@ void AM_drawAuthorMarkers () while (marked != NULL) { - if (mark->args[1] == 0 || (mark->args[1] == 1)) + // Use more correct info if we have GL nodes available + if (mark->args[1] == 0 || + (mark->args[1] == 1 && (hasglnodes ? + marked->subsector->flags & SSECF_DRAWN : + marked->Sector->MoreFlags & SECF_DRAWN))) { - // Use more correct info if we have GL nodes available - INTBOOL drawn = hasglnodes? - marked->subsector->flags & SSECF_DRAWN : - marked->Sector->MoreFlags & SECF_DRAWN; - - if (drawn) - { - DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, - flip, mark->scaleX, mark->scaleY, mark->Translation, - mark->alpha, mark->fillcolor, mark->RenderStyle); - } + DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0, + flip, mark->scaleX, mark->scaleY, mark->Translation, + mark->alpha, mark->fillcolor, mark->RenderStyle); } marked = mark->args[0] != 0 ? it.Next() : NULL; } From d4b03e2b773e91ab71233c17bf18183137a587af Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 29 Aug 2010 03:52:02 +0000 Subject: [PATCH 227/251] - SVN r2629 (trunk) --- src/p_setup.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index d8e86a9cd..236a52137 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1094,6 +1094,14 @@ static bool P_CheckV4Nodes(MapData *map) // //=========================================================================== +struct badseg +{ + badseg(int t, int s, int d) : badtype(t), badsegnum(s), baddata(d) {} + int badtype; + int badsegnum; + int baddata; +}; + template void P_LoadSegs (MapData * map) { @@ -1159,7 +1167,7 @@ void P_LoadSegs (MapData * map) if (vnum1 >= numvertexes || vnum2 >= numvertexes) { - throw i * 4; + throw badseg(0, i, MAX(vnum1, vnum2)); } li->v1 = &vertexes[vnum1]; @@ -1226,14 +1234,14 @@ void P_LoadSegs (MapData * map) linedef = LittleShort(ml->linedef); if ((unsigned)linedef >= (unsigned)numlines) { - throw i * 4 + 1; + throw badseg(1, i, linedef); } ldef = &lines[linedef]; li->linedef = ldef; side = LittleShort(ml->side); if ((unsigned)(ldef->sidedef[side] - sides) >= (unsigned)numsides) { - throw i * 4 + 2; + throw badseg(2, i, int(ldef->sidedef[side] - sides)); } li->sidedef = ldef->sidedef[side]; li->frontsector = ldef->sidedef[side]->sector; @@ -1250,20 +1258,20 @@ void P_LoadSegs (MapData * map) } } } - catch (int foo) + catch (badseg bad) { - switch (foo & 3) + switch (bad.badtype) { case 0: - Printf ("Seg %d references a nonexistant vertex.\n", foo >> 2); + Printf ("Seg %d references a nonexistant vertex %d (max %d).\n", bad.badsegnum, bad.baddata, numvertexes); break; case 1: - Printf ("Seg %d references a nonexistant linedef.\n", foo >> 2); + Printf ("Seg %d references a nonexistant linedef %d (max %d).\n", bad.badsegnum, bad.baddata, numlines); break; case 2: - Printf ("The linedef for seg %d references a nonexistant sidedef.\n", foo >> 2); + Printf ("The linedef for seg %d references a nonexistant sidedef %d (max %d).\n", bad.badsegnum, bad.baddata, numsides); break; } Printf ("The BSP will be rebuilt.\n"); From c304b39ecc656dbdcfd2014bdb8b35b761a72559 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Aug 2010 12:20:35 +0000 Subject: [PATCH 228/251] - added new sector special 195 to set the 'hidden' sector flag in non-UDMF maps. SVN r2637 (trunk) --- specs/udmf_zdoom.txt | 4 ++++ src/p_lnspec.h | 5 +++-- src/p_spec.cpp | 5 +++++ wadsrc/static/xlat/defines.i | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 9f91c748e..fe6897d9f 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -163,6 +163,7 @@ Note: All fields default to false unless mentioned otherwise. norespawn = ; // Players can not respawn in this sector soundsequence = ; // The sound sequence to play when this sector moves. Placing a // sound sequence thing in the sector will override this property. + hidden = ; // if true this sector will not be drawn on the textured automap. * Note about dropactors @@ -273,6 +274,9 @@ Added 'soundsequnce' sector property. 1.12 22.08.2010 Added 'conversation' thing property. +1.13 29.08.2010 +Added 'hidden' sector property. + =============================================================================== EOF =============================================================================== diff --git a/src/p_lnspec.h b/src/p_lnspec.h index f0942c4fd..050e0fe7b 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -114,8 +114,9 @@ typedef enum { sDamage_SuperHellslime = 116, Scroll_StrifeCurrent = 118, - // Caverns of Darkness healing sector - Sector_Heal = 196, + + Sector_Hidden = 195, + Sector_Heal = 196, // Caverns of Darkness healing sector Light_OutdoorLightning = 197, Light_IndoorLightning1 = 198, diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 915d4a508..e37df68b1 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1104,6 +1104,11 @@ void P_SpawnSpecials (void) 0, -1, int(sector-sectors), 0); break; + case Sector_Hidden: + sector->MoreFlags |= SECF_HIDDEN; + sector->special &= 0xff00; + break; + default: if ((sector->special & 0xff) >= Scroll_North_Slow && (sector->special & 0xff) <= Scroll_SouthWest_Fast) diff --git a/wadsrc/static/xlat/defines.i b/wadsrc/static/xlat/defines.i index b72641d30..60d582f70 100644 --- a/wadsrc/static/xlat/defines.i +++ b/wadsrc/static/xlat/defines.i @@ -145,8 +145,8 @@ enum sDamage_SuperHellslime = 116, Scroll_StrifeCurrent = 118, - // Caverns of Darkness healing sector - Sector_Heal = 196, + Sector_Hidden = 195, + Sector_Heal = 196, // Caverns of Darkness healing sector Light_OutdoorLightning = 197, Light_IndoorLightning1 = 198, From 08a40b22be6fd42bdbd00bd8dcaf0d917ae9bae7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 29 Aug 2010 17:57:10 +0000 Subject: [PATCH 229/251] - BOOM compatibility fix: Allow voodoo dolls to spawn inside narrow pits. SVN r2641 (trunk) --- src/p_user.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_user.cpp b/src/p_user.cpp index cf80d3819..cea9c9b9f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -503,6 +503,15 @@ void APlayerPawn::Tick() void APlayerPawn::PostBeginPlay() { SetupWeaponSlots(); + + // Voodoo dolls: restore original floorz/ceilingz logic + if (player->mo != this) + { + dropoffz = floorz = Sector->floorplane.ZatPoint(x, y); + ceilingz = Sector->ceilingplane.ZatPoint(x, y); + P_FindFloorCeiling(this, true); + z = floorz; + } } //=========================================================================== From 39daeb25e3918979d832539c9eb8fa41b0dfd27a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 30 Aug 2010 15:11:11 +0000 Subject: [PATCH 230/251] - fixed: Hexen's pig was missing an A_QueueCorpse call. SVN r2644 (trunk) --- wadsrc/static/actors/hexen/pig.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/hexen/pig.txt b/wadsrc/static/actors/hexen/pig.txt index eaecd692e..45b649597 100644 --- a/wadsrc/static/actors/hexen/pig.txt +++ b/wadsrc/static/actors/hexen/pig.txt @@ -142,7 +142,7 @@ ACTOR Pig : MorphedMonster Death: PIGY E 4 A_Scream PIGY F 3 A_NoBlocking - PIGY G 4 + PIGY G 4 A_QueueCorpse PIGY H 3 PIGY IJK 4 PIGY L -1 From 399cfc4890983d7f65f2016c621910cbdb9f9a48 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 31 Aug 2010 04:35:13 +0000 Subject: [PATCH 231/251] - Fixd MinGW compilation of p_glnodes.cpp. SVN r2650 (trunk) --- src/p_glnodes.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index d7332def2..382f026b2 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -33,13 +33,13 @@ #include #ifdef _MSC_VER #include // for alloca() -#include #endif #ifndef _WIN32 #include #else +#include #define rmdir _rmdir @@ -1201,7 +1201,7 @@ static bool CheckCachedNodes(MapData *map) if (fread(&numlin, 4, 1, f) != 1) goto errorout; numlin = LittleLong(numlin); - if (numlin != numlines) goto errorout; + if ((int)numlin != numlines) goto errorout; if (fread(md5, 1, 16, f) != 16) goto errorout; map->GetChecksum(md5map); @@ -1445,7 +1445,7 @@ void P_SetRenderSector() for(i=0;i Date: Tue, 31 Aug 2010 21:24:03 +0000 Subject: [PATCH 232/251] - added kgsws-cz's FBF_NOFLASH submission. SVN r2655 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 3 ++- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index aacb45b18..b304e638f 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -996,6 +996,7 @@ enum FB_Flags FBF_NORANDOM = 2, FBF_EXPLICITANGLE = 4, FBF_NOPITCH = 8, + FBF_NOFLASH = 16, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) @@ -1025,7 +1026,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if (Range == 0) Range = PLAYERMISSILERANGE; - static_cast(self)->PlayAttacking2 (); + if (!(Flags & FBF_NOFLASH)) static_cast(self)->PlayAttacking2 (); if (!(Flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); bangle = self->angle; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 05e77df2a..d6fdd42de 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -24,6 +24,7 @@ const int FBF_USEAMMO = 1; const int FBF_NORANDOM = 2; const int FBF_EXPLICITANGLE = 4; const int FBF_NOPITCH = 8; +const int FBF_NOFLASH = 16; // Flags for A_SpawnItemEx const int SXF_TRANSFERTRANSLATION=1; From 230178bf98949803de8072fe2f646be74b07a060 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Tue, 31 Aug 2010 21:36:30 +0000 Subject: [PATCH 233/251] - Added drawshadow flag to drawstring. SVN r2656 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 8339a3592..e4413faf0 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -614,6 +614,19 @@ class CommandDrawString : public SBarInfoCommand sc.ScriptError("Unknown alignment '%s'.", sc.String); sc.MustGetToken(')'); } + else if(sc.Compare("drawshadow")) + { + if(sc.CheckToken('(')) + { + sc.MustGetToken(TK_IntConst); + shadowX = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + shadowY = sc.Number; + sc.MustGetToken(')'); + } + shadow = true; + } else sc.ScriptError("Unknown flag '%s'.", sc.String); if(!sc.CheckToken('|') && !sc.CheckToken(',')) break; From 4b817cfd8b28148594cf30a8cb7a18fa8ef2c352 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Sep 2010 03:22:43 +0000 Subject: [PATCH 234/251] - Fix an ICE when compiling with GCC 4.5.0. SVN r2659 (trunk) --- src/win32/st_start.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index 8fe844f70..1f0838ef2 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -656,23 +656,23 @@ FHexenStartupScreen::FHexenStartupScreen(int max_progress, HRESULT &hr) { RGBQUAD color; DWORD quad; - }; + } c; Wads.ReadLump (startup_lump, startup_screen); - color.rgbReserved = 0; + c.color.rgbReserved = 0; StartupBitmap = ST_Util_CreateBitmap (640, 480, 4); // Initialize the bitmap palette. for (int i = 0; i < 16; ++i) { - color.rgbRed = startup_screen[i*3+0]; - color.rgbGreen = startup_screen[i*3+1]; - color.rgbBlue = startup_screen[i*3+2]; + c.color.rgbRed = startup_screen[i*3+0]; + c.color.rgbGreen = startup_screen[i*3+1]; + c.color.rgbBlue = startup_screen[i*3+2]; // Convert from 6-bit per component to 8-bit per component. - quad = (quad << 2) | ((quad >> 4) & 0x03030303); - StartupBitmap->bmiColors[i] = color; + c.quad = (c.quad << 2) | ((c.quad >> 4) & 0x03030303); + StartupBitmap->bmiColors[i] = c.color; } // Fill in the bitmap data. Convert to chunky, because I can't figure out From a2573e4bb30dd9f01510a3630a67dd7c46cb7e2c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Sep 2010 03:30:18 +0000 Subject: [PATCH 235/251] - Fixes to compile with GCC 4.5.0. SVN r2660 (trunk) --- src/basicinlines.h | 4 +-- src/g_raven/a_minotaur.cpp | 4 +-- src/g_shared/a_fastprojectile.cpp | 2 +- src/p_enemy.cpp | 4 +-- src/p_mobj.cpp | 2 +- src/p_user.cpp | 2 +- src/textures/pngtexture.cpp | 8 ++--- src/win32/i_crash.cpp | 50 ++++++++++++++++++++++++++++++- src/win32/i_rawps2.cpp | 5 ++-- 9 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/basicinlines.h b/src/basicinlines.h index fa6ce822b..80f861c22 100644 --- a/src/basicinlines.h +++ b/src/basicinlines.h @@ -11,8 +11,8 @@ #pragma once #endif -#ifndef _MSC_VER -#define __forceinline inline +#if defined(__GNUC__) && !defined(__forceinline) +#define __forceinline __inline__ __attribute__((always_inline)) #endif static __forceinline SDWORD Scale (SDWORD a, SDWORD b, SDWORD c) diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index a614d3b41..eb5444147 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -448,9 +448,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) { // Turn if (pr_minotaurroam() & 1) - self->movedir = (++self->movedir)%8; + self->movedir = (self->movedir + 1) % 8; else - self->movedir = (self->movedir+7)%8; + self->movedir = (self->movedir + 7) % 8; FaceMovementDirection (self); } } diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 161323b2b..d45a9f2a8 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -72,7 +72,7 @@ void AFastProjectile::Tick () tm.LastRipped = NULL; // [RH] Do rip damage each step, like Hexen } - if (!P_TryMove (this, x + xfrac,y + yfrac, true, false, tm)) + if (!P_TryMove (this, x + xfrac,y + yfrac, true, NULL, tm)) { // Blocked move if (!(flags3 & MF3_SKYEXPLODE)) { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 01c31794e..1cf28aa5d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -512,12 +512,12 @@ bool P_Move (AActor *actor) try_ok = true; for(int i=1; i < steps; i++) { - try_ok = P_TryMove(actor, origx + Scale(deltax, i, steps), origy + Scale(deltay, i, steps), dropoff, false, tm); + try_ok = P_TryMove(actor, origx + Scale(deltax, i, steps), origy + Scale(deltay, i, steps), dropoff, NULL, tm); if (!try_ok) break; } // killough 3/15/98: don't jump over dropoffs: - if (try_ok) try_ok = P_TryMove (actor, tryx, tryy, dropoff, false, tm); + if (try_ok) try_ok = P_TryMove (actor, tryx, tryy, dropoff, NULL, tm); // [GrafZahl] Interpolating monster movement as it is done here just looks bad // so make it switchable diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 98f0801bc..4d6cdc765 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4963,7 +4963,7 @@ bool P_CheckMissileSpawn (AActor* th) bool MBFGrenade = (!(th->flags & MF_MISSILE) || (th->BounceFlags & BOUNCE_MBF)); // killough 3/15/98: no dropoff (really = don't care for missiles) - if (!(P_TryMove (th, th->x, th->y, false, false, tm))) + if (!(P_TryMove (th, th->x, th->y, false, NULL, tm))) { // [RH] Don't explode ripping missiles that spawn inside something if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP)) diff --git a/src/p_user.cpp b/src/p_user.cpp index cea9c9b9f..a00843d84 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1975,7 +1975,7 @@ void P_CrouchMove(player_t * player, int direction) // check whether the move is ok player->mo->height = FixedMul(defaultheight, player->crouchfactor); - if (!P_TryMove(player->mo, player->mo->x, player->mo->y, false, false)) + if (!P_TryMove(player->mo, player->mo->x, player->mo->y, false, NULL)) { player->mo->height = savedheight; if (direction > 0) diff --git a/src/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index d1fe3e8f5..4e30802c4 100644 --- a/src/textures/pngtexture.cpp +++ b/src/textures/pngtexture.cpp @@ -202,7 +202,7 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename { DWORD palette[256]; BYTE pngpal[256][3]; - }; + } p; BYTE trans[256]; bool havetRNS = false; DWORD len, id; @@ -260,14 +260,14 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename case MAKE_ID('P','L','T','E'): PaletteSize = MIN (len / 3, 256); - lump.Read (pngpal, PaletteSize * 3); + lump.Read (p.pngpal, PaletteSize * 3); if (PaletteSize * 3 != (int)len) { lump.Seek (len - PaletteSize * 3, SEEK_CUR); } for (i = PaletteSize - 1; i >= 0; --i) { - palette[i] = MAKERGB(pngpal[i][0], pngpal[i][1], pngpal[i][2]); + p.palette[i] = MAKERGB(p.pngpal[i][0], p.pngpal[i][1], p.pngpal[i][2]); } break; @@ -314,7 +314,7 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename case 3: // Paletted PaletteMap = new BYTE[PaletteSize]; - GPalette.MakeRemap (palette, PaletteMap, trans, PaletteSize); + GPalette.MakeRemap (p.palette, PaletteMap, trans, PaletteSize); for (i = 0; i < PaletteSize; ++i) { if (trans[i] == 0) diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index 727e4b7ed..5e4dfb1c9 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -69,6 +69,54 @@ #include #include +#if defined(_WIN64) && defined(__GNUC__) +struct KNONVOLATILE_CONTEXT_POINTERS { + union { + PDWORD64 IntegerContext[16]; + struct { + PDWORD64 Rax; + PDWORD64 Rcx; + PDWORD64 Rdx; + PDWORD64 Rbx; + PDWORD64 Rsp; + PDWORD64 Rbp; + PDWORD64 Rsi; + PDWORD64 Rdi; + PDWORD64 R8; + PDWORD64 R9; + PDWORD64 R10; + PDWORD64 R11; + PDWORD64 R12; + PDWORD64 R13; + PDWORD64 R14; + PDWORD64 R15; + }; + }; +}; +typedef +EXCEPTION_DISPOSITION +NTAPI +EXCEPTION_ROUTINE ( + struct _EXCEPTION_RECORD *ExceptionRecord, + PVOID EstablisherFrame, + struct _CONTEXT *ContextRecord, + PVOID DispatcherContext + ); +NTSYSAPI +EXCEPTION_ROUTINE * +NTAPI +RtlVirtualUnwind ( + DWORD HandlerType, + DWORD64 ImageBase, + DWORD64 ControlPc, + PRUNTIME_FUNCTION FunctionEntry, + PCONTEXT ContextRecord, + PVOID *HandlerData, + PDWORD64 EstablisherFrame, + KNONVOLATILE_CONTEXT_POINTERS *ContextPointers + ); +#endif + // MACROS ------------------------------------------------------------------ #define REMOTE_HOST "localhost" @@ -1312,7 +1360,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD } // If we reach a RIP of zero, this means we've walked off the end of // the call stack and are done. - if (context.Rip == NULL) + if (context.Rip == 0) { break; } diff --git a/src/win32/i_rawps2.cpp b/src/win32/i_rawps2.cpp index 68803fefb..d060b869d 100644 --- a/src/win32/i_rawps2.cpp +++ b/src/win32/i_rawps2.cpp @@ -388,8 +388,9 @@ FRawPS2Controller::~FRawPS2Controller() bool FRawPS2Controller::ProcessInput(RAWHID *raw, int code) { - // w32api has an incompatible definition of bRawData -#if __GNUC__ + // w32api has an incompatible definition of bRawData. + // (But the version that comes with MinGW64 is fine.) +#if defined(__GNUC__) && !defined(_WIN64) BYTE *rawdata = &raw->bRawData; #else BYTE *rawdata = raw->bRawData; From c25f206fbbe0305efb1eb64fa2f377f9c898b7e7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Sep 2010 04:13:36 +0000 Subject: [PATCH 236/251] - Disable framebuffer debug spew. All those OutputDebugString messages from DCanvas::DrawLine()'s Lock and Unlock calls were slowing things down extremely when looking at a software-drawn automap. SVN r2661 (trunk) --- src/win32/win32iface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 62f06fa99..6193c641c 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -504,7 +504,7 @@ enum #define LOG4(x,y,z,a,b) do { if (dbg) { fprintf (dbg, x, y, z, a, b); fflush (dbg); } } while(0) #define LOG5(x,y,z,a,b,c) do { if (dbg) { fprintf (dbg, x, y, z, a, b, c); fflush (dbg); } } while(0) FILE *dbg; -#elif _DEBUG +#elif _DEBUG && 0 #define STARTLOG #define STOPLOG #define LOG(x) { OutputDebugString(x); } From 7bf0cd13a6fd3803a2f21681ffea2fdaef1664bb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Sep 2010 04:24:56 +0000 Subject: [PATCH 237/251] - Fixed: The mouse pointer stayed hidden on startup because the CursorState variable was not set until the mouse was grabbed. SVN r2662 (trunk) --- src/win32/i_mouse.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index af595dea5..d347a4d72 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -485,6 +485,7 @@ static FMouse *CreateRawMouse() FRawMouse::FRawMouse() { Grabbed = false; + SetCursorState(true); } //========================================================================== @@ -678,6 +679,7 @@ FDInputMouse::FDInputMouse() { Device = NULL; Grabbed = false; + SetCursorState(true); } //========================================================================== @@ -903,6 +905,7 @@ FWin32Mouse::FWin32Mouse() { GetCursorPos(&UngrabbedPointerPos); Grabbed = false; + SetCursorState(true); } //========================================================================== From 0202c0c3a98a4c50b2b40cf48d50110ce1def4cc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Sep 2010 05:03:17 +0000 Subject: [PATCH 238/251] - Added the am_zoom command to zoom the automap by a specific step and set default mouse wheel bindings for it. I'm not sure how this should be exposed through the menu, however. Technically, it's different from the pan keys, but from an end user's point of view, they both zoom the automap, so they should both be listed under the Zoom in and out controls. But the menu code can't handle that. SVN r2663 (trunk) --- src/am_map.cpp | 33 ++++++++++++++++++++++++++++----- src/c_bind.cpp | 2 ++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index fd46c8018..0a0dafd66 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -246,10 +246,10 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it. #define F_PANINC (140/TICRATE) // how much zoom-in per tic // goes to 2x in 1 second -#define M_ZOOMIN ((int) (1.02*MAPUNIT)) +#define M_ZOOMIN (1.02*MAPUNIT) // how much zoom-out per tic // pulls out to 0.5x in 1 second -#define M_ZOOMOUT ((int) (MAPUNIT/1.02)) +#define M_ZOOMOUT (MAPUNIT/1.02) // translates between frame-buffer and map coordinates #define CXMTOF(x) (MTOF((x)-m_x)/* - f_x*/) @@ -413,6 +413,7 @@ static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) +static float am_zoomdir; static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords) @@ -1258,8 +1259,23 @@ void AM_changeWindowScale () { int mtof_zoommul; - if (Button_AM_ZoomIn.bDown) mtof_zoommul = M_ZOOMIN; - else if (Button_AM_ZoomOut.bDown) mtof_zoommul = M_ZOOMOUT; + if (am_zoomdir > 0) + { + mtof_zoommul = int(M_ZOOMIN * am_zoomdir); + } + else if (am_zoomdir < 0) + { + mtof_zoommul = int(M_ZOOMOUT / -am_zoomdir); + } + else if (Button_AM_ZoomIn.bDown) + { + mtof_zoommul = int(M_ZOOMIN); + } + else if (Button_AM_ZoomOut.bDown) + { + mtof_zoommul = int(M_ZOOMOUT); + } + am_zoomdir = 0; // Change the scaling multipliers scale_mtof = MapMul(scale_mtof, mtof_zoommul); @@ -1271,6 +1287,13 @@ void AM_changeWindowScale () AM_maxOutWindowScale(); } +CCMD(am_zoom) +{ + if (argv.argc() >= 2) + { + am_zoomdir = (float)atof(argv[1]); + } +} //============================================================================= // @@ -1332,7 +1355,7 @@ void AM_Ticker () } // Change the zoom if necessary - if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown) + if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown || am_zoomdir != 0) AM_changeWindowScale(); // Change x,y location diff --git a/src/c_bind.cpp b/src/c_bind.cpp index 471959f6c..b9489ca65 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -188,6 +188,8 @@ static const FBinding DefAutomapBindings[] = { "=", "+am_zoomin" }, { "kp-", "+am_zoomout" }, { "kp+", "+am_zoomin" }, + { "mwheelup", "am_zoom 1.2" }, + { "mwheeldown", "am_zoom -1.2" }, { NULL } }; From 241e09c2717a925fc8aa1c4303961b13b9b7dff4 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 1 Sep 2010 22:26:07 +0000 Subject: [PATCH 239/251] - Fixed: font monospacing didn't apply to the space character. SVN r2666 (trunk) --- src/g_shared/sbarinfo.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 83f9e9bef..29ea9774b 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1349,7 +1349,10 @@ public: { if(*str == ' ') { - ax += font->GetSpaceWidth(); + if(script->spacingCharacter == '\0') + ax += font->GetSpaceWidth(); + else + ax += font->GetCharWidth((int) script->spacingCharacter); str++; continue; } From 77ca7f7a87117fd3b74d2c91afe14427b22d6e95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Sep 2010 22:33:34 +0000 Subject: [PATCH 240/251] - set 'setslopeoverflow' compatibility flag for all maps in Massmouth2. SVN r2674 (trunk) --- wadsrc/static/compatibility.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 09f38a80b..98528363d 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -21,6 +21,7 @@ A80E7EE40E0D0C76A6FBD242BE29FE27 // map15 2F1F8E27FBB5EF21AFBE1F3B13C03037 // map16 1CE294781A2455DE72C197E0B3DF6212 // map31 { + setslopeoverflow resetplayerspeed } From 81e21b0688b43a91becd0cad079bab331f587913 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 2 Sep 2010 23:17:58 +0000 Subject: [PATCH 241/251] - Renamed music_midi_midiout.cpp to music_smf_midiout.cpp. - Moved MIDI precaching logic into MIDIStreamer so that SMF and HMI files can both use the same implementation. - Added a player for HMI midi files. SVN r2675 (trunk) --- src/CMakeLists.txt | 5 +- src/sound/i_music.cpp | 30 +- src/sound/i_musicinterns.h | 62 +- src/sound/music_hmi_midiout.cpp | 882 ++++++++++++++++++ src/sound/music_midistream.cpp | 106 ++- ...midi_midiout.cpp => music_smf_midiout.cpp} | 167 +--- zdoom.vcproj | 8 +- 7 files changed, 1106 insertions(+), 154 deletions(-) create mode 100644 src/sound/music_hmi_midiout.cpp rename src/sound/{music_midi_midiout.cpp => music_smf_midiout.cpp} (80%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6906bec5b..18f13abd6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -812,11 +812,12 @@ add_executable( zdoom WIN32 sound/music_cd.cpp sound/music_dumb.cpp sound/music_gme.cpp + sound/music_mus_midiout.cpp + sound/music_smf_midiout.cpp + sound/music_hmi_midiout.cpp sound/music_midistream.cpp sound/music_midi_base.cpp - sound/music_midi_midiout.cpp sound/music_midi_timidity.cpp - sound/music_mus_midiout.cpp sound/music_mus_opl.cpp sound/music_stream.cpp sound/music_fluidsynth_mididevice.cpp diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index eb68d290e..717f98eaa 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -489,10 +489,36 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int } #endif // _WIN32 } - // Check for MIDI format else { - if (id[0] == MAKE_ID('M','T','h','d')) + // Check for HMI format + if (id[0] == MAKE_ID('H','M','I','-') && + id[1] == MAKE_ID('M','I','D','I') && + id[2] == MAKE_ID('S','O','N','G')) + { + if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL) + { + info = new HMISong(file, musiccache, len, MIDI_OPL); + } + else if (snd_mididevice == -4 && device == MDEV_DEFAULT) + { + info = new HMISong(file, musiccache, len, MIDI_Timidity); + } +#ifdef HAVE_FLUIDSYNTH + else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) + { + info = new HMISong(file, musiccache, len, MIDI_Fluid); + } +#endif +#ifdef _WIN32 + else + { + info = new HMISong(file, musiccache, len, MIDI_Win); + } +#endif + } + // Check for MIDI format + else if (id[0] == MAKE_ID('M','T','h','d')) { // This is a midi file diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 334002963..6bfe9c2f4 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -373,7 +373,7 @@ protected: virtual void DoInitialSetup() = 0; virtual void DoRestart() = 0; virtual bool CheckDone() = 0; - virtual void Precache() = 0; + virtual void Precache(); virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0; enum @@ -413,6 +413,7 @@ protected: DWORD Volume; EMIDIDevice DeviceType; bool CallbackIsThreaded; + bool IgnoreLoops; FString DumpFilename; }; @@ -460,7 +461,6 @@ protected: void DoInitialSetup(); void DoRestart(); bool CheckDone(); - void Precache(); DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time); void AdvanceTracks(DWORD time); @@ -480,6 +480,64 @@ protected: WORD DesignationMask; }; +// HMI file played with a MIDI stream --------------------------------------- + +class HMISong : public MIDIStreamer +{ +public: + HMISong(FILE *file, BYTE *musiccache, int length, EMIDIDevice type); + ~HMISong(); + + MusInfo *GetOPLDumper(const char *filename); + MusInfo *GetWaveDumper(const char *filename, int rate); + +protected: + HMISong(const HMISong *original, const char *filename, EMIDIDevice type); // file dump constructor + + void CheckCaps(); + void DoInitialSetup(); + void DoRestart(); + bool CheckDone(); + DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time); + void AdvanceTracks(DWORD time); + + struct TrackInfo; + + void ProcessInitialMetaEvents (); + DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay); + TrackInfo *FindNextDue (); + void SetTempo(int new_tempo); + + struct AutoNoteOff + { + DWORD Delay; + BYTE Channel, Key; + }; + // Sorry, std::priority_queue, but I want to be able to modify the contents of the heap. + class NoteOffQueue : public TArray + { + public: + void AddNoteOff(DWORD delay, BYTE channel, BYTE key); + void AdvanceTime(DWORD time); + bool Pop(AutoNoteOff &item); + + protected: + void Heapify(); + + unsigned int Parent(unsigned int i) { return (i + 1u) / 2u - 1u; } + unsigned int Left(unsigned int i) { return (i + 1u) * 2u - 1u; } + unsigned int Right(unsigned int i) { return (i + 1u) * 2u; } + }; + + BYTE *MusHeader; + int SongLen; + int NumTracks; + TrackInfo *Tracks; + TrackInfo *TrackDue; + TrackInfo *FakeTrack; + NoteOffQueue NoteOffs; +}; + // Anything supported by FMOD out of the box -------------------------------- class StreamSong : public MusInfo diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp new file mode 100644 index 000000000..078e98c94 --- /dev/null +++ b/src/sound/music_hmi_midiout.cpp @@ -0,0 +1,882 @@ +/* +** music_midi_midiout.cpp +** Code to let ZDoom play HMI MIDI music through the MIDI streaming API. +** +**--------------------------------------------------------------------------- +** Copyright 2010 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include "i_musicinterns.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" + +// MACROS ------------------------------------------------------------------ + +#define SONG_MAGIC "HMI-MIDISONG" +#define TRACK_MAGIC "HMI-MIDITRACK" + +// Used by SendCommand to check for unexpected end-of-track conditions. +#define CHECK_FINISHED \ + if (track->TrackP >= track->MaxTrackP) \ + { \ + track->Finished = true; \ + return events; \ + } + +// In song header +#define TRACK_COUNT_OFFSET 0xE4 +#define TRACK_DIR_PTR_OFFSET 0xE8 + +// In track header +#define TRACK_DATA_PTR_OFFSET 0x57 +#define TRACK_DESIGNATION_OFFSET 0x99 + +#define NUM_DESIGNATIONS 8 + +// MIDI device types for designation +#define HMI_DEV_GM 0xA000 // Generic General MIDI (not a real device) +#define HMI_DEV_MPU401 0xA001 // MPU-401, Roland Sound Canvas, Ensoniq SoundScape, Rolad RAP-10 +#define HMI_DEV_OPL2 0xA002 // SoundBlaster (Pro), ESS AudioDrive +#define HMI_DEV_MT32 0xA004 // MT-32 +#define HMI_DEV_SBAWE32 0xA008 // SoundBlaster AWE32 +#define HMI_DEV_OPL3 0xA009 // SoundBlaster 16, Microsoft Sound System, Pro Audio Spectrum 16 +#define HMI_DEV_GUS 0xA00A // Gravis UltraSound, Gravis UltraSound Max/Ace + + +// Data accessors, since this data is highly likely to be unaligned. +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) +inline int GetShort(const BYTE *foo) +{ + return *(const short *)foo; +} +inline int GetInt(const BYTE *foo) +{ + return *(const int *)foo; +} +#else +inline int GetShort(const BYTE *foo) +{ + return short(foo[0] | (foo[1] << 8)); +} +inline int GetInt(const BYTE *foo) +{ + return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); +} +#endif + +// TYPES ------------------------------------------------------------------- + +struct HMISong::TrackInfo +{ + const BYTE *TrackBegin; + size_t TrackP; + size_t MaxTrackP; + DWORD Delay; + DWORD PlayedTime; + WORD Designation[NUM_DESIGNATIONS]; + bool Enabled; + bool Finished; + BYTE RunningStatus; + + DWORD ReadVarLen (); +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern char MIDI_EventLengths[7]; +extern char MIDI_CommonLengths[15]; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// HMISong Constructor +// +// Buffers the file and does some validation of the HMI header. +// +//========================================================================== + +HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMIDIDevice type) +: MIDIStreamer(type), MusHeader(0), Tracks(0) +{ + int p; + int i; + +#ifdef _WIN32 + if (ExitEvent == NULL) + { + return; + } +#endif + if (len < 0x100) + { // Way too small to be HMI. + return; + } + MusHeader = new BYTE[len]; + SongLen = len; + if (file != NULL) + { + if (fread(MusHeader, 1, len, file) != (size_t)len) + return; + } + else + { + memcpy(MusHeader, musiccache, len); + } + + // Do some validation of the MIDI file + if (memcmp(MusHeader, SONG_MAGIC, 12) != 0) + return; + + NumTracks = GetShort(MusHeader + TRACK_COUNT_OFFSET); + if (NumTracks <= 0) + { + return; + } + + // The division is the number of pulses per quarter note (PPQN). + Division = 60; + + Tracks = new TrackInfo[NumTracks + 1]; + int track_dir = GetInt(MusHeader + TRACK_DIR_PTR_OFFSET); + + // Gather information about each track + for (i = 0, p = 0; i < NumTracks; ++i) + { + int start = GetInt(MusHeader + track_dir + i*4); + int tracklen, datastart; + + if (start > len - TRACK_DESIGNATION_OFFSET - 4) + { // Track is incomplete. + continue; + } + + // BTW, HMI does not actually check the track header. + if (memcmp(MusHeader + start, TRACK_MAGIC, 13) != 0) + { + continue; + } + + // The track ends where the next one begins. If this is the + // last track, then it ends at the end of the file. + if (i == NumTracks - 1) + { + tracklen = len - start; + } + else + { + tracklen = GetInt(MusHeader + track_dir + i*4 + 4) - start; + } + // Clamp incomplete tracks to the end of the file. + tracklen = MIN(tracklen, len - start); + if (tracklen <= 0) + { + continue; + } + + // Offset to actual MIDI events. + datastart = GetInt(MusHeader + start + TRACK_DATA_PTR_OFFSET); + tracklen -= datastart; + if (tracklen <= 0) + { + continue; + } + + // Store track information + Tracks[p].TrackBegin = MusHeader + start + datastart; + Tracks[p].TrackP = 0; + Tracks[p].MaxTrackP = tracklen; + + // Retrieve track designations. We can't check them yet, since we have not yet + // connected to the MIDI device. + for (int ii = 0; ii < NUM_DESIGNATIONS; ++ii) + { + Tracks[p].Designation[ii] = GetShort(MusHeader + start + TRACK_DESIGNATION_OFFSET + ii*2); + } + + p++; + } + + // In case there were fewer actual chunks in the file than the + // header specified, update NumTracks with the current value of p. + NumTracks = p; + + if (NumTracks == 0) + { // No tracks, so nothing to play + return; + } +} + +//========================================================================== +// +// HMISong Destructor +// +//========================================================================== + +HMISong::~HMISong () +{ + if (Tracks != NULL) + { + delete[] Tracks; + } + if (MusHeader != NULL) + { + delete[] MusHeader; + } +} + +//========================================================================== +// +// HMISong :: CheckCaps +// +// Check track designations and disable tracks that have not been +// designated for the device we will be playing on. +// +//========================================================================== + +void HMISong::CheckCaps() +{ + int tech = MIDI->GetTechnology(); + + // What's the equivalent HMI device for our technology? + if (tech == MOD_FMSYNTH) + { + tech = HMI_DEV_OPL3; + } + else if (tech == MOD_MIDIPORT) + { + tech = HMI_DEV_MPU401; + } + else + { // Good enough? Or should we just say we're GM. + tech = HMI_DEV_SBAWE32; + } + + for (int i = 0; i < NumTracks; ++i) + { + Tracks[i].Enabled = false; + // Track designations are stored in a 0-terminated array. + for (int j = 0; j < NUM_DESIGNATIONS && Tracks[i].Designation[j] != 0; ++j) + { + if (Tracks[i].Designation[j] == tech) + { + Tracks[i].Enabled = true; + } + // If a track is designated for device 0xA000, it will be played by a MIDI + // driver for device types 0xA000, 0xA001, and 0xA008. Why this does not + // include the GUS, I do not know. + else if (Tracks[i].Designation[j] == HMI_DEV_GM) + { + Tracks[i].Enabled = (tech == HMI_DEV_MPU401 || tech == HMI_DEV_SBAWE32); + } + // If a track is designated for device 0xA002, it will be played by a MIDI + // driver for device types 0xA002 or 0xA009. + else if (Tracks[i].Designation[j] == HMI_DEV_OPL2) + { + Tracks[i].Enabled = (tech == HMI_DEV_OPL3); + } + // Any other designation must match the specific MIDI driver device number. + // (Which we handled first above.) + + if (Tracks[i].Enabled) + { // This track's been enabled, so we can stop checking other designations. + break; + } + } + } +} + + +//========================================================================== +// +// HMISong :: DoInitialSetup +// +// Sets the starting channel volumes. +// +//========================================================================== + +void HMISong :: DoInitialSetup() +{ + for (int i = 0; i < 16; ++i) + { + ChannelVolumes[i] = 100; + } +} + +//========================================================================== +// +// HMISong :: DoRestart +// +// Rewinds every track. +// +//========================================================================== + +void HMISong :: DoRestart() +{ + int i; + + // Set initial state. + FakeTrack = &Tracks[NumTracks]; + NoteOffs.Clear(); + for (i = 0; i <= NumTracks; ++i) + { + Tracks[i].TrackP = 0; + Tracks[i].Finished = false; + Tracks[i].RunningStatus = 0; + Tracks[i].PlayedTime = 0; + } + ProcessInitialMetaEvents (); + for (i = 0; i < NumTracks; ++i) + { + Tracks[i].Delay = Tracks[i].ReadVarLen(); + } + Tracks[i].Delay = 0; // for the FakeTrack + Tracks[i].Enabled = true; + TrackDue = Tracks; + TrackDue = FindNextDue(); +} + +//========================================================================== +// +// HMISong :: CheckDone +// +//========================================================================== + +bool HMISong::CheckDone() +{ + return TrackDue == NULL; +} + +//========================================================================== +// +// HMISong :: MakeEvents +// +// Copies MIDI events from the file and puts them into a MIDI stream +// buffer. Returns the new position in the buffer. +// +//========================================================================== + +DWORD *HMISong::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) +{ + DWORD *start_events; + DWORD tot_time = 0; + DWORD time = 0; + DWORD delay; + + start_events = events; + while (TrackDue && events < max_event_p && tot_time <= max_time) + { + // It's possible that this tick may be nothing but meta-events and + // not generate any real events. Repeat this until we actually + // get some output so we don't send an empty buffer to the MIDI + // device. + do + { + delay = TrackDue->Delay; + time += delay; + // Advance time for all tracks by the amount needed for the one up next. + tot_time += delay * Tempo / Division; + AdvanceTracks(delay); + // Play all events for this tick. + do + { + DWORD *new_events = SendCommand(events, TrackDue, time); + TrackDue = FindNextDue(); + if (new_events != events) + { + time = 0; + } + events = new_events; + } + while (TrackDue && TrackDue->Delay == 0 && events < max_event_p); + } + while (start_events == events && TrackDue); + time = 0; + } + return events; +} + +//========================================================================== +// +// HMISong :: AdvanceTracks +// +// Advaces time for all tracks by the specified amount. +// +//========================================================================== + +void HMISong::AdvanceTracks(DWORD time) +{ + for (int i = 0; i <= NumTracks; ++i) + { + if (Tracks[i].Enabled && !Tracks[i].Finished) + { + Tracks[i].Delay -= time; + Tracks[i].PlayedTime += time; + } + } + NoteOffs.AdvanceTime(time); +} + +//========================================================================== +// +// HMISong :: SendCommand +// +// Places a single MIDIEVENT in the event buffer. +// +//========================================================================== + +DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) +{ + DWORD len; + BYTE event, data1 = 0, data2 = 0; + + // If the next event comes from the fake track, pop an entry off the note-off queue. + if (track == FakeTrack) + { + AutoNoteOff off; + NoteOffs.Pop(off); + events[0] = delay; + events[1] = 0; + events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8); + return events + 3; + } + + CHECK_FINISHED + event = track->TrackBegin[track->TrackP++]; + CHECK_FINISHED + + if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND && event != 0xFe) + { + // Normal short message + if ((event & 0xF0) == 0xF0) + { + if (MIDI_CommonLengths[event & 15] > 0) + { + data1 = track->TrackBegin[track->TrackP++]; + if (MIDI_CommonLengths[event & 15] > 1) + { + data2 = track->TrackBegin[track->TrackP++]; + } + } + } + else if ((event & 0x80) == 0) + { + data1 = event; + event = track->RunningStatus; + } + else + { + track->RunningStatus = event; + data1 = track->TrackBegin[track->TrackP++]; + } + + CHECK_FINISHED + + if (MIDI_EventLengths[(event&0x70)>>4] == 2) + { + data2 = track->TrackBegin[track->TrackP++]; + } + + // Monitor channel volume controller changes. + if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70) && data1 == 7) + { + data2 = VolumeControllerChange(event & 15, data2); + } + + events[0] = delay; + events[1] = 0; + if (event != MIDI_META) + { + events[2] = event | (data1<<8) | (data2<<16); + } + else + { + events[2] = MEVT_NOP; + } + events += 3; + + if ((event & 0x70) == (MIDI_NOTEON & 0x70)) + { // HMI note on events include the time until an implied note off event. + NoteOffs.AddNoteOff(track->ReadVarLen(), event & 0x0F, data1); + } + } + else + { + // Skip SysEx events just because I don't want to bother with them. + // The old MIDI player ignored them too, so this won't break + // anything that played before. + if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) + { + len = track->ReadVarLen (); + track->TrackP += len; + } + else if (event == MIDI_META) + { + // It's a meta-event + event = track->TrackBegin[track->TrackP++]; + CHECK_FINISHED + len = track->ReadVarLen (); + CHECK_FINISHED + + if (track->TrackP + len <= track->MaxTrackP) + { + switch (event) + { + case MIDI_META_EOT: + track->Finished = true; + break; + + case MIDI_META_TEMPO: + Tempo = + (track->TrackBegin[track->TrackP+0]<<16) | + (track->TrackBegin[track->TrackP+1]<<8) | + (track->TrackBegin[track->TrackP+2]); + events[0] = delay; + events[1] = 0; + events[2] = (MEVT_TEMPO << 24) | Tempo; + events += 3; + break; + } + track->TrackP += len; + if (track->TrackP == track->MaxTrackP) + { + track->Finished = true; + } + } + else + { + track->Finished = true; + } + } + else if (event == 0xFE) + { // Skip unknown HMI events. + event = track->TrackBegin[track->TrackP++]; + CHECK_FINISHED + if (event == 0x13 || event == 0x15) + { + track->TrackP += 6; + } + else if (event == 0x12 || event == 0x14) + { + track->TrackP += 2; + } + else if (event == 0x10) + { + track->TrackP += 2; + CHECK_FINISHED + track->TrackP += track->TrackBegin[track->TrackP] + 5; + CHECK_FINISHED + } + else + { // No idea. + track->Finished = true; + } + } + } + if (!track->Finished) + { + track->Delay = track->ReadVarLen(); + } + return events; +} + +//========================================================================== +// +// HMISong :: ProcessInitialMetaEvents +// +// Handle all the meta events at the start of each track. +// +//========================================================================== + +void HMISong::ProcessInitialMetaEvents () +{ + TrackInfo *track; + int i; + BYTE event; + DWORD len; + + for (i = 0; i < NumTracks; ++i) + { + track = &Tracks[i]; + while (!track->Finished && + track->TrackP < track->MaxTrackP - 4 && + track->TrackBegin[track->TrackP] == 0 && + track->TrackBegin[track->TrackP+1] == 0xFF) + { + event = track->TrackBegin[track->TrackP+2]; + track->TrackP += 3; + len = track->ReadVarLen (); + if (track->TrackP + len <= track->MaxTrackP) + { + switch (event) + { + case MIDI_META_EOT: + track->Finished = true; + break; + + case MIDI_META_TEMPO: + SetTempo( + (track->TrackBegin[track->TrackP+0]<<16) | + (track->TrackBegin[track->TrackP+1]<<8) | + (track->TrackBegin[track->TrackP+2]) + ); + break; + } + } + track->TrackP += len; + } + if (track->TrackP >= track->MaxTrackP - 4) + { + track->Finished = true; + } + } +} + +//========================================================================== +// +// HMISong :: TrackInfo :: ReadVarLen +// +// Reads a variable-length SMF number. +// +//========================================================================== + +DWORD HMISong::TrackInfo::ReadVarLen () +{ + DWORD time = 0, t = 0x80; + + while ((t & 0x80) && TrackP < MaxTrackP) + { + t = TrackBegin[TrackP++]; + time = (time << 7) | (t & 127); + } + return time; +} + +//========================================================================== +// +// HMISong :: NoteOffQueue :: AddNoteOff +// +//========================================================================== + +void HMISong::NoteOffQueue::AddNoteOff(DWORD delay, BYTE channel, BYTE key) +{ + unsigned int i = Reserve(1); + while (i > 0 && (*this)[Parent(i)].Delay > delay) + { + (*this)[i] = (*this)[Parent(i)]; + i = Parent(i); + } + (*this)[i].Delay = delay; + (*this)[i].Channel = channel; + (*this)[i].Key = key; +} + +//========================================================================== +// +// HMISong :: NoteOffQueue :: Pop +// +//========================================================================== + +bool HMISong::NoteOffQueue::Pop(AutoNoteOff &item) +{ + item = (*this)[0]; + if (TArray::Pop((*this)[0])) + { + Heapify(); + return true; + } + return false; +} + +//========================================================================== +// +// HMISong :: NoteOffQueue :: AdvanceTime +// +//========================================================================== + +void HMISong::NoteOffQueue::AdvanceTime(DWORD time) +{ + // Because the time is decreasing by the same amount for every entry, + // the heap property is maintained. + for (unsigned int i = 0; i < Size(); ++i) + { + assert((*this)[i].Delay >= time); + (*this)[i].Delay -= time; + } +} + +//========================================================================== +// +// HMISong :: NoteOffQueue :: Heapify +// +//========================================================================== + +void HMISong::NoteOffQueue::Heapify() +{ + unsigned int i = 0; + for (;;) + { + unsigned int l = Left(i); + unsigned int r = Right(i); + unsigned int smallest = i; + if (l < Size() && (*this)[l].Delay < (*this)[i].Delay) + { + smallest = l; + } + if (r < Size() && (*this)[r].Delay < (*this)[smallest].Delay) + { + smallest = r; + } + if (smallest == i) + { + break; + } + swapvalues((*this)[i], (*this)[smallest]); + i = smallest; + } +} + +//========================================================================== +// +// HMISong :: FindNextDue +// +// Scans every track for the next event to play. Returns NULL if all events +// have been consumed. +// +//========================================================================== + +HMISong::TrackInfo *HMISong::FindNextDue () +{ + TrackInfo *track; + DWORD best; + int i; + + if (TrackDue != FakeTrack && !TrackDue->Finished && TrackDue->Delay == 0) + { + return TrackDue; + } + + // Check regular tracks. + track = NULL; + best = 0xFFFFFFFF; + for (i = 0; i < NumTracks; ++i) + { + if (Tracks[i].Enabled && !Tracks[i].Finished && Tracks[i].Delay < best) + { + best = Tracks[i].Delay; + track = &Tracks[i]; + } + } + // Check automatic note-offs. + if (NoteOffs.Size() != 0 && NoteOffs[0].Delay <= best) + { + FakeTrack->Delay = NoteOffs[0].Delay; + return FakeTrack; + } + return track; +} + + +//========================================================================== +// +// HMISong :: SetTempo +// +// Sets the tempo from a track's initial meta events. +// +//========================================================================== + +void HMISong::SetTempo(int new_tempo) +{ + if (0 == MIDI->SetTempo(new_tempo)) + { + Tempo = new_tempo; + } +} + +//========================================================================== +// +// HMISong :: GetOPLDumper +// +//========================================================================== + +MusInfo *HMISong::GetOPLDumper(const char *filename) +{ + return new HMISong(this, filename, MIDI_OPL); +} + +//========================================================================== +// +// HMISong :: GetWaveDumper +// +//========================================================================== + +MusInfo *HMISong::GetWaveDumper(const char *filename, int rate) +{ + return new HMISong(this, filename, MIDI_Timidity); +} + +//========================================================================== +// +// HMISong File Dumping Constructor +// +//========================================================================== + +HMISong::HMISong(const HMISong *original, const char *filename, EMIDIDevice type) +: MIDIStreamer(filename, type) +{ + SongLen = original->SongLen; + MusHeader = new BYTE[original->SongLen]; + memcpy(MusHeader, original->MusHeader, original->SongLen); + NumTracks = original->NumTracks; + Division = original->Division; + Tempo = InitialTempo = original->InitialTempo; + Tracks = new TrackInfo[NumTracks]; + for (int i = 0; i < NumTracks; ++i) + { + TrackInfo *newtrack = &Tracks[i]; + const TrackInfo *oldtrack = &original->Tracks[i]; + + newtrack->TrackBegin = MusHeader + (oldtrack->TrackBegin - original->MusHeader); + newtrack->TrackP = 0; + newtrack->MaxTrackP = oldtrack->MaxTrackP; + } +} diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index d9449a657..ddba36006 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -242,6 +242,7 @@ void MIDIStreamer::Play(bool looping, int subsong) CheckCaps(); Precache(); + IgnoreLoops = true; // Set time division and tempo. if (0 != MIDI->SetTimeDiv(Division) || @@ -734,7 +735,7 @@ fill: // // MIDIStreamer :: FillBuffer // -// Copies MIDI events from the SMF and puts them into a MIDI stream +// Copies MIDI events from the MIDI file and puts them into a MIDI stream // buffer. Filling the buffer stops when the song end is encountered, the // buffer space is used up, or the maximum time for a buffer is hit. // @@ -829,6 +830,109 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time) return SONG_MORE; } +//========================================================================== +// +// MIDIStreamer :: Precache +// +// Generates a list of instruments this song uses them and passes them to +// the MIDI device for precaching. The default implementation here pretends +// to play the song and watches for program change events on normal channels +// and note on events on channel 10. +// +//========================================================================== + +void MIDIStreamer::Precache() +{ + BYTE found_instruments[256] = { 0, }; + BYTE found_banks[256] = { 0, }; + bool multiple_banks = false; + + IgnoreLoops = true; + DoRestart(); + found_banks[0] = true; // Bank 0 is always used. + found_banks[128] = true; + + // Simulate playback to pick out used instruments. + while (!CheckDone()) + { + DWORD *event_end = MakeEvents(Events[0], &Events[0][MAX_EVENTS*3], 1000000*600); + for (DWORD *event = Events[0]; event < event_end; ) + { + if (MEVT_EVENTTYPE(event[2]) == 0) + { + int command = (event[2] & 0x70); + int channel = (event[2] & 0x0f); + int data1 = (event[2] >> 8) & 0x7f; + int data2 = (event[2] >> 16) & 0x7f; + + if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70)) + { + found_instruments[data1] = true; + } + else if (channel == 9 && command == (MIDI_PRGMCHANGE & 0x70) && data1 != 0) + { // On a percussion channel, program change also serves as bank select. + multiple_banks = true; + found_banks[data1 | 128] = true; + } + else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0) + { + found_instruments[data1 | 128] = true; + } + else if (command == (MIDI_CTRLCHANGE & 0x70) && data1 == 0 && data2 != 0) + { + multiple_banks = true; + if (channel == 9) + { + found_banks[data2 | 128] = true; + } + else + { + found_banks[data2] = true; + } + } + } + // Advance to next event + if (event[2] < 0x80000000) + { // short message + event += 3; + } + else + { // long message + event += 3 + ((MEVT_EVENTPARM(event[2]) + 3) >> 2); + } + } + } + DoRestart(); + + // Now pack everything into a contiguous region for the PrecacheInstruments call(). + TArray packed; + + for (int i = 0; i < 256; ++i) + { + if (found_instruments[i]) + { + WORD packnum = (i & 127) | ((i & 128) << 7); + if (!multiple_banks) + { + packed.Push(packnum); + } + else + { // In order to avoid having to multiplex tracks in a type 1 file, + // precache every used instrument in every used bank, even if not + // all combinations are actually used. + for (int j = 0; j < 128; ++j) + { + if (found_banks[j + (i & 128)]) + { + packed.Push(packnum | (j << 7)); + } + } + } + } + } + MIDI->PrecacheInstruments(&packed[0], packed.Size()); +} + //========================================================================== // // MIDIStreamer :: GetStats diff --git a/src/sound/music_midi_midiout.cpp b/src/sound/music_smf_midiout.cpp similarity index 80% rename from src/sound/music_midi_midiout.cpp rename to src/sound/music_smf_midiout.cpp index 00d816c66..2607de341 100644 --- a/src/sound/music_midi_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -86,11 +86,11 @@ struct MIDISong2::TrackInfo // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static BYTE EventLengths[7] = { 2, 2, 2, 2, 1, 1, 2 }; -static BYTE CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - // PUBLIC DATA DEFINITIONS ------------------------------------------------- +char MIDI_EventLengths[7] = { 2, 2, 2, 2, 1, 1, 2 }; +char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + // CODE -------------------------------------------------------------------- //========================================================================== @@ -389,10 +389,10 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) // Normal short message if ((event & 0xF0) == 0xF0) { - if (CommonLengths[event & 15] > 0) + if (MIDI_CommonLengths[event & 15] > 0) { data1 = track->TrackBegin[track->TrackP++]; - if (CommonLengths[event & 15] > 1) + if (MIDI_CommonLengths[event & 15] > 1) { data2 = track->TrackBegin[track->TrackP++]; } @@ -411,7 +411,7 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) CHECK_FINISHED - if (EventLengths[(event&0x70)>>4] == 2) + if (MIDI_EventLengths[(event&0x70)>>4] == 2) { data2 = track->TrackBegin[track->TrackP++]; } @@ -500,10 +500,13 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) break; case 116: // EMIDI Loop Begin - track->LoopBegin = track->TrackP; - track->LoopDelay = 0; - track->LoopCount = data2; - track->LoopFinished = track->Finished; + if (!IgnoreLoops) + { + track->LoopBegin = track->TrackP; + track->LoopDelay = 0; + track->LoopCount = data2; + track->LoopFinished = track->Finished; + } event = MIDI_META; break; @@ -529,12 +532,15 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay) break; case 118: // EMIDI Global Loop Begin - for (i = 0; i < NumTracks; ++i) + if (!IgnoreLoops) { - Tracks[i].LoopBegin = Tracks[i].TrackP; - Tracks[i].LoopDelay = Tracks[i].Delay; - Tracks[i].LoopCount = data2; - Tracks[i].LoopFinished = Tracks[i].Finished; + for (i = 0; i < NumTracks; ++i) + { + Tracks[i].LoopBegin = Tracks[i].TrackP; + Tracks[i].LoopDelay = Tracks[i].Delay; + Tracks[i].LoopCount = data2; + Tracks[i].LoopFinished = Tracks[i].Finished; + } } event = MIDI_META; break; @@ -709,7 +715,7 @@ DWORD MIDISong2::TrackInfo::ReadVarLen () //========================================================================== // -// MIDISong2 :: TrackInfo :: FindNextDue +// MIDISong2 :: FindNextDue // // Scans every track for the next event to play. Returns NULL if all events // have been consumed. @@ -776,135 +782,6 @@ void MIDISong2::SetTempo(int new_tempo) } } -//========================================================================== -// -// MIDISong2 :: Precache -// -// Scans each track for program change events on normal channels and note on -// events on channel 10. Does not care about bank selects, since they're -// unlikely to appear in a song aimed at Doom. -// -//========================================================================== - -void MIDISong2::Precache() -{ - // This array keeps track of instruments that are used. The first 128 - // entries are for melodic instruments. The second 128 are for - // percussion. - BYTE found_instruments[256] = { 0, }; - BYTE found_banks[256] = { 0, }; - bool multiple_banks = false; - int i, j; - - DoRestart(); - found_banks[0] = true; // Bank 0 is always used. - found_banks[128] = true; - for (i = 0; i < NumTracks; ++i) - { - TrackInfo *track = &Tracks[i]; - BYTE running_status = 0; - BYTE ev, data1, data2, command, channel; - int len; - - data2 = 0; // Silence, GCC - while (track->TrackP < track->MaxTrackP) - { - ev = track->TrackBegin[track->TrackP++]; - command = ev & 0xF0; - - if (ev == MIDI_META) - { - track->TrackP++; - len = track->ReadVarLen(); - track->TrackP += len; - } - else if (ev == MIDI_SYSEX || ev == MIDI_SYSEXEND) - { - len = track->ReadVarLen(); - track->TrackP += len; - } - else if (command == 0xF0) - { - track->TrackP += CommonLengths[ev & 0x0F]; - } - else - { - if ((ev & 0x80) == 0) - { // Use running status. - data1 = ev; - ev = running_status; - } - else - { // Store new running status. - running_status = ev; - data1 = track->TrackBegin[track->TrackP++]; - } - command = ev & 0x70; - channel = ev & 0x0F; - if (EventLengths[command >> 4] == 2) - { - data2 = track->TrackBegin[track->TrackP++]; - } - if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70)) - { - found_instruments[data1 & 127] = true; - } - else if (channel == 9 && command == (MIDI_PRGMCHANGE & 0x70) && data1 != 0) - { // On a percussion channel, program change also serves as bank select. - multiple_banks = true; - found_banks[data1 | 128] = true; - } - else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0) - { - found_instruments[data1 | 128] = true; - } - else if (command == (MIDI_CTRLCHANGE & 0x70) && data1 == 0 && data2 != 0) - { - multiple_banks = true; - if (channel == 9) - { - found_banks[data2 | 128] = true; - } - else - { - found_banks[data2 & 127] = true; - } - } - } - track->ReadVarLen(); // Skip delay. - } - } - DoRestart(); - - // Now pack everything into a contiguous region for the PrecacheInstruments call(). - TArray packed; - - for (i = 0; i < 256; ++i) - { - if (found_instruments[i]) - { - WORD packnum = (i & 127) | ((i & 128) << 7); - if (!multiple_banks) - { - packed.Push(packnum); - } - else - { // In order to avoid having to multiplex tracks in a type 1 file, - // precache every used instrument in every used bank, even if not - // all combinations are actually used. - for (j = 0; j < 128; ++j) - { - if (found_banks[j + (i & 128)]) - { - packed.Push(packnum | (j << 7)); - } - } - } - } - } - MIDI->PrecacheInstruments(&packed[0], packed.Size()); -} - //========================================================================== // // MIDISong2 :: GetOPLDumper diff --git a/zdoom.vcproj b/zdoom.vcproj index b2a3f4fe3..c61cfa9d7 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -5462,11 +5462,11 @@ > + + From 092cbfd55b46dfd83201b142b48cb0bacc4c8a29 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 3 Sep 2010 02:11:35 +0000 Subject: [PATCH 242/251] - Fixed: When the game nodes were the same as the render nodes, their pointers would not be NULLed. SVN r2676 (trunk) --- src/p_setup.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 236a52137..02329bdb9 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3370,17 +3370,13 @@ void P_FreeLevelData () sectors = NULL; numsectors = 0; // needed for the pointer cleanup code } - if (gamenodes && gamenodes!=nodes) + if (gamenodes != NULL && gamenodes != nodes) { - delete [] gamenodes; - gamenodes = NULL; - numgamenodes = 0; + delete[] gamenodes; } - if (gamesubsectors && gamesubsectors!=subsectors) + if (gamesubsectors != NULL && gamesubsectors != subsectors) { - delete [] gamesubsectors; - gamesubsectors = NULL; - numgamesubsectors = 0; + delete[] gamesubsectors; } if (subsectors != NULL) { @@ -3392,13 +3388,15 @@ void P_FreeLevelData () } } delete[] subsectors; - subsectors = NULL; } if (nodes != NULL) { delete[] nodes; - nodes = NULL; } + subsectors = gamesubsectors = NULL; + numsubsectors = numgamesubsectors = 0; + nodes = gamenodes = NULL; + numnodes = numgamenodes = 0; if (lines != NULL) { delete[] lines; From 070ec7578548d97e61d9754572ce36107cd75cab Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 3 Sep 2010 05:08:05 +0000 Subject: [PATCH 243/251] - Cleaned up the ugly MIDI song creating code a little. - Added a generic Standard MIDI File creator that works with any of the sequencers. mus2midi.cpp is no longer used but is kept around as a reference. SVN r2677 (trunk) --- src/CMakeLists.txt | 1 - src/mus2midi.cpp | 4 +- src/mus2midi.h | 3 - src/sound/i_music.cpp | 306 +++++++++++++++--------------- src/sound/i_musicinterns.h | 16 +- src/sound/music_hmi_midiout.cpp | 6 +- src/sound/music_midi_timidity.cpp | 16 +- src/sound/music_midistream.cpp | 169 ++++++++++++++++- src/sound/music_mus_midiout.cpp | 6 +- src/sound/music_smf_midiout.cpp | 6 +- src/tarray.h | 9 + zdoom.vcproj | 4 - 12 files changed, 344 insertions(+), 202 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18f13abd6..16a658a10 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -661,7 +661,6 @@ add_executable( zdoom WIN32 m_png.cpp m_random.cpp md5.cpp - mus2midi.cpp name.cpp nodebuild.cpp nodebuild_classify_nosse2.cpp diff --git a/src/mus2midi.cpp b/src/mus2midi.cpp index 63e59e755..2157b4a89 100644 --- a/src/mus2midi.cpp +++ b/src/mus2midi.cpp @@ -195,9 +195,9 @@ bool ProduceMIDI (const BYTE *musBuf, int len, TArray &outFile) switch (event & 0x70) { case MUS_NOTEOFF: - midStatus |= MIDI_NOTEOFF; + midStatus |= MIDI_NOTEON; mid1 = t & 127; - mid2 = 64; + mid2 = 0; break; case MUS_NOTEON: diff --git a/src/mus2midi.h b/src/mus2midi.h index 6dc75dc03..f1d846927 100644 --- a/src/mus2midi.h +++ b/src/mus2midi.h @@ -75,7 +75,4 @@ typedef struct // WORD UsedInstruments[NumInstruments]; } MUSHeader; -bool ProduceMIDI (const BYTE *musBuf, int len, TArray &outFile); -bool ProduceMIDI (const BYTE *musBuf, int len, FILE *outFile); - #endif //__MUS2MIDI_H__ diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 717f98eaa..172553df5 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -3,7 +3,7 @@ ** Plays music ** **--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit +** Copyright 1998-2010 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -84,6 +84,14 @@ extern void ChildSigHandler (int signum); #define GZIP_FNAME 8 #define GZIP_FCOMMENT 16 +enum EMIDIType +{ + MIDI_NOTMIDI, + MIDI_MIDI, + MIDI_HMI, + MIDI_MUS +}; + extern int MUSHeaderSearch(const BYTE *head, int len); EXTERN_CVAR (Int, snd_samplerate) @@ -305,6 +313,40 @@ MusInfo *I_RegisterURLSong (const char *url) return NULL; } +static MusInfo *CreateMIDISong(FILE *file, const char *filename, BYTE *musiccache, int offset, int len, EMIDIDevice devtype, EMIDIType miditype) +{ + if (devtype == MIDI_Timidity) + { + assert(miditype == MIDI_MIDI); + return new TimiditySong(file, musiccache, len); + } + else if (devtype >= MIDI_Null) + { + assert(miditype == MIDI_MIDI); + if (musiccache != NULL) + { + return new StreamSong((char *)musiccache, -1, len); + } + else + { + return new StreamSong(filename, offset, len); + } + } + else if (miditype == MIDI_MUS) + { + return new MUSSong2(file, musiccache, len, devtype); + } + else if (miditype == MIDI_MIDI) + { + return new MIDISong2(file, musiccache, len, devtype); + } + else if (miditype == MIDI_HMI) + { + return new HMISong(file, musiccache, len, devtype); + } + return NULL; +} + MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device) { FILE *file; @@ -405,191 +447,147 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int } } + EMIDIType miditype = MIDI_NOTMIDI; + // Check for MUS format // Tolerate sloppy wads by searching up to 32 bytes for the header if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0) { - /* MUS are played as: - - OPL: - - if explicitly selected by $mididevice - - when snd_mididevice is -3 and no midi device is set for the song + miditype = MIDI_MUS; + } + // Check for HMI format + else + if (id[0] == MAKE_ID('H','M','I','-') && + id[1] == MAKE_ID('M','I','D','I') && + id[2] == MAKE_ID('S','O','N','G')) + { + miditype = MIDI_HMI; + } + // Check for MIDI format + else if (id[0] == MAKE_ID('M','T','h','d')) + { + miditype = MIDI_MIDI; + } - Timidity: - - if explicitly selected by $mididevice - - when snd_mididevice is -2 and no midi device is set for the song + if (miditype != MIDI_NOTMIDI) + { + TArray midi; + /* MIDI are played as: + - OPL: + - if explicitly selected by $mididevice + - when snd_mididevice is -3 and no midi device is set for the song - FMod: - - if explicitly selected by $mididevice - - when snd_mididevice is -1 and no midi device is set for the song - - as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0 + - Timidity: + - if explicitly selected by $mididevice + - when snd_mididevice is -2 and no midi device is set for the song - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) - - when snd_mididevice is >= 0 and no midi device is set for the song - - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 + - FMod: + - if explicitly selected by $mididevice + - when snd_mididevice is -1 and no midi device is set for the song + - as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0 + + - MMAPI (Win32 only): + - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) + - when snd_mididevice is >= 0 and no midi device is set for the song + - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 */ - if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL) + EMIDIDevice devtype = MIDI_Null; + + // Choose the type of MIDI device we want. + if (device == MDEV_FMOD || (snd_mididevice == -1 && device == MDEV_DEFAULT)) { - info = new MUSSong2 (file, musiccache, len, MIDI_OPL); + devtype = MIDI_FMOD; } - else if (device == MDEV_TIMIDITY || (device == MDEV_DEFAULT && snd_mididevice == -2)) + else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT)) { - info = new TimiditySong (file, musiccache, len); + devtype = MIDI_Timidity; + } + else if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT)) + { + devtype = MIDI_OPL; } else if (snd_mididevice == -4 && device == MDEV_DEFAULT) { - info = new MUSSong2(file, musiccache, len, MIDI_Timidity); + devtype = MIDI_GUS; } #ifdef HAVE_FLUIDSYNTH else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) { - info = new MUSSong2(file, musiccache, len, MIDI_Fluid); + devtype = MIDI_Fluid; } #endif +#ifdef _WIN32 + else + { + devtype = MIDI_Win; + } +#endif + +retry_as_fmod: + if (miditype != MIDI_MIDI && devtype >= MIDI_Null) + { + // Convert to standard MIDI for external sequencers. + MIDIStreamer *streamer; + + if (miditype == MIDI_MUS) + { + streamer = new MUSSong2(file, musiccache, len, MIDI_Null); + } + else + { + assert(miditype == MIDI_HMI); + streamer = new HMISong(file, musiccache, len, MIDI_Null); + } + if (streamer->IsValid()) + { + streamer->CreateSMF(midi); + miditype = MIDI_MIDI; + musiccache = &midi[0]; + len = midi.Size(); + if (file != NULL) + { + fclose(file); + file = NULL; + } + } + delete streamer; + } + info = CreateMIDISong(file, filename, musiccache, offset, len, devtype, miditype); if (info != NULL && !info->IsValid()) { delete info; info = NULL; - device = MDEV_DEFAULT; } - if (info == NULL && (snd_mididevice == -1 || device == MDEV_FMOD) && device != MDEV_MMAPI) + if (info == NULL && devtype != MIDI_FMOD && snd_mididevice < 0) { - TArray midi; - bool midi_made = false; - - if (file == NULL) - { - midi_made = ProduceMIDI((BYTE *)musiccache, len, midi); - } - else - { - BYTE *mus = new BYTE[len]; - size_t did_read = fread(mus, 1, len, file); - if (did_read == (size_t)len) - { - midi_made = ProduceMIDI(mus, len, midi); - } - fseek(file, -(long)did_read, SEEK_CUR); - delete[] mus; - } - if (midi_made) - { - info = new StreamSong((char *)&midi[0], -1, midi.Size()); - if (!info->IsValid()) - { - delete info; - info = NULL; - } - } + devtype = MIDI_FMOD; + goto retry_as_fmod; } #ifdef _WIN32 - if (info == NULL) + if (info == NULL && devtype != MIDI_Win && snd_mididevice >= 0) { - info = new MUSSong2 (file, musiccache, len, MIDI_Win); + info = CreateMIDISong(file, filename, musiccache, offset, len, MIDI_Win, miditype); } -#endif // _WIN32 +#endif } - else + + // Check for various raw OPL formats + else if ( + (id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL + (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL + (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - // Check for HMI format - if (id[0] == MAKE_ID('H','M','I','-') && - id[1] == MAKE_ID('M','I','D','I') && - id[2] == MAKE_ID('S','O','N','G')) - { - if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL) - { - info = new HMISong(file, musiccache, len, MIDI_OPL); - } - else if (snd_mididevice == -4 && device == MDEV_DEFAULT) - { - info = new HMISong(file, musiccache, len, MIDI_Timidity); - } -#ifdef HAVE_FLUIDSYNTH - else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) - { - info = new HMISong(file, musiccache, len, MIDI_Fluid); - } -#endif -#ifdef _WIN32 - else - { - info = new HMISong(file, musiccache, len, MIDI_Win); - } -#endif - } - // Check for MIDI format - else if (id[0] == MAKE_ID('M','T','h','d')) - { - // This is a midi file - - /* MIDI are played as: - OPL: - - if explicitly selected by $mididevice - - when snd_mididevice is -3 and no midi device is set for the song - - Timidity: - - if explicitly selected by $mididevice - - when snd_mididevice is -2 and no midi device is set for the song - - FMOD: - - if explicitly selected by $mididevice - - when snd_mididevice is -1 and no midi device is set for the song - - as fallback when Timidity failed unless snd_mididevice is >= 0 - - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) - - when snd_mididevice is >= 0 and no midi device is set for the song - - as fallback when Timidity failed and snd_mididevice is >= 0 - */ - if (device == MDEV_OPL || (snd_mididevice == -3 && device == MDEV_DEFAULT)) - { - info = new MIDISong2 (file, musiccache, len, MIDI_OPL); - } - else if (device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT)) - { - info = new TimiditySong (file, musiccache, len); - } - else if (snd_mididevice == -4 && device == MDEV_DEFAULT) - { - info = new MIDISong2(file, musiccache, len, MIDI_Timidity); - } -#ifdef HAVE_FLUIDSYNTH - else if (device == MDEV_FLUIDSYNTH || (snd_mididevice == -5 && device == MDEV_DEFAULT)) - { - info = new MIDISong2(file, musiccache, len, MIDI_Fluid); - } -#endif - if (info != NULL && !info->IsValid()) - { - delete info; - info = NULL; - device = MDEV_DEFAULT; - } -#ifdef _WIN32 - if (info == NULL && device != MDEV_FMOD && (snd_mididevice >= 0 || device == MDEV_MMAPI)) - { - info = new MIDISong2 (file, musiccache, len, MIDI_Win); - } -#endif // _WIN32 - } - // Check for various raw OPL formats - else if ( - (id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL - (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL - (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF - { - info = new OPLMUSSong (file, musiccache, len); - } - // Check for game music - else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') - { - info = GME_OpenSong(file, musiccache, len, fmt); - } - // Check for module formats - else - { - info = MOD_OpenSong(file, musiccache, len); - } + info = new OPLMUSSong (file, musiccache, len); + } + // Check for game music + else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') + { + info = GME_OpenSong(file, musiccache, len, fmt); + } + // Check for module formats + else + { + info = MOD_OpenSong(file, musiccache, len); } if (info == NULL) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 6bfe9c2f4..8c6507167 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -333,8 +333,13 @@ enum EMIDIDevice { MIDI_Win, MIDI_OPL, - MIDI_Timidity, - MIDI_Fluid + MIDI_GUS, + MIDI_Fluid, + + // only used by I_RegisterSong + MIDI_Null, + MIDI_FMOD, + MIDI_Timidity }; class MIDIStreamer : public MusInfo @@ -357,6 +362,7 @@ public: void FluidSettingInt(const char *setting, int value); void FluidSettingNum(const char *setting, double value); void FluidSettingStr(const char *setting, const char *value); + void CreateSMF(TArray &file); protected: MIDIStreamer(const char *dumpname, EMIDIDevice type); @@ -369,7 +375,7 @@ protected: static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2); // Virtuals for subclasses to override - virtual void CheckCaps(); + virtual void CheckCaps(int tech); virtual void DoInitialSetup() = 0; virtual void DoRestart() = 0; virtual bool CheckDone() = 0; @@ -457,7 +463,7 @@ public: protected: MIDISong2(const MIDISong2 *original, const char *filename, EMIDIDevice type); // file dump constructor - void CheckCaps(); + void CheckCaps(int tech); void DoInitialSetup(); void DoRestart(); bool CheckDone(); @@ -494,7 +500,7 @@ public: protected: HMISong(const HMISong *original, const char *filename, EMIDIDevice type); // file dump constructor - void CheckCaps(); + void CheckCaps(int tech); void DoInitialSetup(); void DoRestart(); bool CheckDone(); diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 078e98c94..c73c9f619 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -273,10 +273,8 @@ HMISong::~HMISong () // //========================================================================== -void HMISong::CheckCaps() +void HMISong::CheckCaps(int tech) { - int tech = MIDI->GetTechnology(); - // What's the equivalent HMI device for our technology? if (tech == MOD_FMSYNTH) { @@ -851,7 +849,7 @@ MusInfo *HMISong::GetOPLDumper(const char *filename) MusInfo *HMISong::GetWaveDumper(const char *filename, int rate) { - return new HMISong(this, filename, MIDI_Timidity); + return new HMISong(this, filename, MIDI_GUS); } //========================================================================== diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index ea725d0da..6e2acb32d 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -207,7 +207,7 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len) BYTE *buf; - if (file!=NULL) + if (file != NULL) { buf = new BYTE[len]; fread (buf, 1, len, file); @@ -217,18 +217,8 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len) buf = musiccache; } - - // The file type has already been checked before this class instance was - // created, so we only need to check one character to determine if this - // is a MUS or MIDI file and write it to disk as appropriate. - if (buf[1] == 'T') - { - success = (fwrite (buf, 1, len, f) == (size_t)len); - } - else - { - success = ProduceMIDI (buf, len, f); - } + // Write to temporary file + success = (fwrite (buf, 1, len, f) == (size_t)len); fclose (f); if (file != NULL) { diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index ddba36006..085c996e2 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -49,6 +49,8 @@ // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- +static void WriteVarLen (TArray &file, DWORD value); + // EXTERNAL DATA DECLARATIONS ---------------------------------------------- EXTERN_CVAR(Float, snd_musicvolume) @@ -57,8 +59,21 @@ EXTERN_CVAR(Float, snd_musicvolume) extern UINT mididevice; #endif +extern char MIDI_EventLengths[7]; + // PRIVATE DATA DEFINITIONS ------------------------------------------------ +static const BYTE StaticMIDIhead[] = +{ + 'M','T','h','d', 0, 0, 0, 6, + 0, 0, // format 0: only one track + 0, 1, // yes, there is really only one track + 0, 0, // divisions (filled in) + 'M','T','r','k', 0, 0, 0, 0, + // The first event sets the tempo (filled in) + 0, 255, 81, 3, 0, 0, 0 +}; + // PUBLIC DATA DEFINITIONS ------------------------------------------------- // CODE -------------------------------------------------------------------- @@ -172,7 +187,7 @@ bool MIDIStreamer::IsValid() const // //========================================================================== -void MIDIStreamer::CheckCaps() +void MIDIStreamer::CheckCaps(int tech) { } @@ -200,7 +215,7 @@ void MIDIStreamer::Play(bool looping, int subsong) { MIDI = new OPLDumperMIDIDevice(DumpFilename); } - else if (DeviceType == MIDI_Timidity) + else if (DeviceType == MIDI_GUS) { MIDI = new TimidityWaveWriterMIDIDevice(DumpFilename, 0); } @@ -221,13 +236,17 @@ void MIDIStreamer::Play(bool looping, int subsong) break; #endif - case MIDI_Timidity: + case MIDI_GUS: MIDI = new TimidityMIDIDevice; break; case MIDI_OPL: MIDI = new OPLMIDIDevice; break; + + default: + MIDI = NULL; + break; } #ifndef _WIN32 @@ -240,9 +259,9 @@ void MIDIStreamer::Play(bool looping, int subsong) return; } - CheckCaps(); + CheckCaps(MIDI->GetTechnology()); Precache(); - IgnoreLoops = true; + IgnoreLoops = false; // Set time division and tempo. if (0 != MIDI->SetTimeDiv(Division) || @@ -515,7 +534,7 @@ void MIDIStreamer::OutputVolume (DWORD volume) int MIDIStreamer::VolumeControllerChange(int channel, int volume) { ChannelVolumes[channel] = volume; - return ((volume + 1) * Volume) >> 16; + return IgnoreLoops ? volume : ((volume + 1) * Volume) >> 16; } //========================================================================== @@ -834,9 +853,9 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time) // // MIDIStreamer :: Precache // -// Generates a list of instruments this song uses them and passes them to -// the MIDI device for precaching. The default implementation here pretends -// to play the song and watches for program change events on normal channels +// Generates a list of instruments this song uses and passes them to the +// MIDI device for precaching. The default implementation here pretends to +// play the song and watches for program change events on normal channels // and note on events on channel 10. // //========================================================================== @@ -933,6 +952,138 @@ void MIDIStreamer::Precache() MIDI->PrecacheInstruments(&packed[0], packed.Size()); } +//========================================================================== +// +// MIDIStreamer :: CreateSMF +// +// Simulates playback to create a Standard MIDI File. +// +//========================================================================== + +void MIDIStreamer::CreateSMF(TArray &file) +{ + DWORD delay = 0; + BYTE running_status = 0; + + // Always create songs aimed at GM devices. + CheckCaps(MOD_MIDIPORT); + IgnoreLoops = true; + DoRestart(); + + file.Reserve(sizeof(StaticMIDIhead)); + memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead)); + file[12] = Division >> 8; + file[13] = Division & 0xFF; + file[26] = InitialTempo >> 16; + file[27] = InitialTempo >> 8; + file[28] = InitialTempo; + + while (!CheckDone()) + { + DWORD *event_end = MakeEvents(Events[0], &Events[0][MAX_EVENTS*3], 1000000*600); + for (DWORD *event = Events[0]; event < event_end; ) + { + delay += event[0]; + if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) + { + WriteVarLen(file, delay); + delay = 0; + DWORD tempo = MEVT_EVENTPARM(event[2]); + file.Push(MIDI_META); + file.Push(MIDI_META_TEMPO); + file.Push(3); + file.Push(BYTE(tempo >> 16)); + file.Push(BYTE(tempo >> 8)); + file.Push(BYTE(tempo)); + } + else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) + { + WriteVarLen(file, delay); + delay = 0; + DWORD len = MEVT_EVENTPARM(event[2]); + BYTE *bytes = (BYTE *)&event[3]; + if (bytes[0] == MIDI_SYSEX) + { + len--; + file.Push(MIDI_SYSEX); + WriteVarLen(file, len); + memcpy(&file[file.Reserve(len - 1)], bytes, len); + } + } + else if (MEVT_EVENTTYPE(event[2]) == 0) + { + WriteVarLen(file, delay); + delay = 0; + BYTE status = BYTE(event[2]); + if (status != running_status) + { + running_status = status; + file.Push(status); + } + file.Push(BYTE((event[2] >> 8) & 0x7F)); + if (MIDI_EventLengths[(status >> 4) & 7] == 2) + { + file.Push(BYTE((event[2] >> 16) & 0x7F)); + } + } + // Advance to next event + if (event[2] < 0x80000000) + { // short message + event += 3; + } + else + { // long message + event += 3 + ((MEVT_EVENTPARM(event[2]) + 3) >> 2); + } + } + } + + // End track + WriteVarLen(file, delay); + file.Push(MIDI_META); + file.Push(MIDI_META_EOT); + file.Push(0); + + // Fill in track length + DWORD len = file.Size() - 22; + file[18] = BYTE(len >> 24); + file[19] = BYTE(len >> 16); + file[20] = BYTE(len >> 8); + file[21] = BYTE(len & 255); + + IgnoreLoops = false; +} + +//========================================================================== +// +// WriteVarLen +// +//========================================================================== + +static void WriteVarLen (TArray &file, DWORD value) +{ + DWORD buffer = value & 0x7F; + + while ( (value >>= 7) ) + { + buffer <<= 8; + buffer |= (value & 0x7F) | 0x80; + } + + for (;;) + { + file.Push(BYTE(buffer)); + if (buffer & 0x80) + { + buffer >>= 8; + } + else + { + break; + } + } +} + //========================================================================== // // MIDIStreamer :: GetStats diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index b89d9fd67..44a0d45e6 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -283,9 +283,9 @@ DWORD *MUSSong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) switch (event & 0x70) { case MUS_NOTEOFF: - status |= MIDI_NOTEOFF; + status |= MIDI_NOTEON; mid1 = t; - mid2 = 64; + mid2 = 0; break; case MUS_NOTEON: @@ -382,7 +382,7 @@ MusInfo *MUSSong2::GetOPLDumper(const char *filename) MusInfo *MUSSong2::GetWaveDumper(const char *filename, int rate) { - return new MUSSong2(this, filename, MIDI_Timidity); + return new MUSSong2(this, filename, MIDI_GUS); } //========================================================================== diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 2607de341..0f01be75b 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -216,10 +216,8 @@ MIDISong2::~MIDISong2 () // //========================================================================== -void MIDISong2::CheckCaps() +void MIDISong2::CheckCaps(int tech) { - int tech = MIDI->GetTechnology(); - DesignationMask = 0xFF0F; if (tech == MOD_FMSYNTH) { @@ -801,7 +799,7 @@ MusInfo *MIDISong2::GetOPLDumper(const char *filename) MusInfo *MIDISong2::GetWaveDumper(const char *filename, int rate) { - return new MIDISong2(this, filename, MIDI_Timidity); + return new MIDISong2(this, filename, MIDI_GUS); } //========================================================================== diff --git a/src/tarray.h b/src/tarray.h index 9ee5eff2b..3eab7be33 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -141,6 +141,15 @@ public: ::new((void*)&Array[Count]) T(item); return Count++; } + bool Pop () + { + if (Count > 0) + { + Array[--Count].~T(); + return true; + } + return false; + } bool Pop (T &item) { if (Count > 0) diff --git a/zdoom.vcproj b/zdoom.vcproj index c61cfa9d7..4df675804 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -712,10 +712,6 @@ RelativePath=".\src\md5.cpp" > - - From 84b9de8c14bbe7563eb8174e0c31d2bcf94445e4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 Sep 2010 02:57:36 +0000 Subject: [PATCH 244/251] - Make sure Tempo is initialized before creating SMFs. SVN r2684 (trunk) --- src/sound/music_midistream.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index 085c996e2..454ff0d3f 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -969,6 +969,7 @@ void MIDIStreamer::CreateSMF(TArray &file) CheckCaps(MOD_MIDIPORT); IgnoreLoops = true; DoRestart(); + Tempo = InitialTempo; file.Reserve(sizeof(StaticMIDIhead)); memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead)); From 61d438e1eb1c7ab4ddcfb2e47af088bd28d799ca Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 Sep 2010 03:02:13 +0000 Subject: [PATCH 245/251] - Don't call M_NotifyNewSave() before closing the new savegame. - Disallow negative read lengths in FileReader::Read(). SVN r2685 (trunk) --- src/files.cpp | 2 ++ src/g_game.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/files.cpp b/src/files.cpp index 5705b938a..332bddb1f 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -132,6 +132,8 @@ long FileReader::Seek (long offset, int origin) long FileReader::Read (void *buffer, long len) { + assert(len >= 0); + if (len <= 0) return 0; if (FilePos + len > StartPos + Length) { len = Length - FilePos + StartPos; diff --git a/src/g_game.cpp b/src/g_game.cpp index f85601c6e..39a424097 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2060,11 +2060,11 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio M_AppendPNGChunk (stdfile, MAKE_ID('s','n','X','t'), &next, 1); } - M_NotifyNewSave (filename.GetChars(), description, okForQuicksave); - M_FinishPNG (stdfile); fclose (stdfile); + M_NotifyNewSave (filename.GetChars(), description, okForQuicksave); + // Check whether the file is ok. bool success = false; stdfile = fopen (filename.GetChars(), "rb"); From 3dbf807345fc23ea256c7b5feaea43efcd9d1dd9 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 4 Sep 2010 18:21:51 +0000 Subject: [PATCH 246/251] - Applied Chris's patch to fix hmi compilation error on Linux. SVN r2689 (trunk) --- src/sound/music_hmi_midiout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index c73c9f619..c2075bf1a 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -717,7 +717,7 @@ void HMISong::NoteOffQueue::AddNoteOff(DWORD delay, BYTE channel, BYTE key) bool HMISong::NoteOffQueue::Pop(AutoNoteOff &item) { item = (*this)[0]; - if (TArray::Pop((*this)[0])) + if (TArray::Pop((*this)[0])) { Heapify(); return true; From e9211aaad32e2f025ed9ee3cd691cb697381852c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Sep 2010 20:51:13 +0000 Subject: [PATCH 247/251] - added some NULL pointer checks to the kill CCMD and APlayerPawn::PostBeginPlay. SVN r2697 (trunk) --- src/d_net.cpp | 8 ++++++-- src/p_user.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index be592b238..73d800b51 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2368,7 +2368,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) int killcount = 0; const PClass *cls = PClass::FindClass(classname); - if (classname != NULL) + if (cls != NULL && cls->ActorInfo != NULL) { killcount = KillAll(cls); const PClass *cls_rep = cls->GetReplacement(); @@ -2376,9 +2376,13 @@ void Net_DoCommand (int type, BYTE **stream, int player) { killcount += KillAll(cls_rep); } + Printf ("Killed %d monsters of type %s.\n",killcount, classname); + } + else + { + Printf ("%s is not an actor class.\n", classname); } - Printf ("Killed %d monsters of type %s.\n",killcount, classname); } break; diff --git a/src/p_user.cpp b/src/p_user.cpp index a00843d84..eef4f5025 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -505,7 +505,7 @@ void APlayerPawn::PostBeginPlay() SetupWeaponSlots(); // Voodoo dolls: restore original floorz/ceilingz logic - if (player->mo != this) + if (player == NULL || player->mo != this) { dropoffz = floorz = Sector->floorplane.ZatPoint(x, y); ceilingz = Sector->ceilingplane.ZatPoint(x, y); From 31754a582d11aaa77ab9af5808cf8ac85b2caef0 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 6 Sep 2010 20:12:44 +0000 Subject: [PATCH 248/251] - Fixed: when using the border property of drawbar, interpolation didn't work quite right. SVN r2705 (trunk) --- src/g_shared/sbarinfo.cpp | 2 +- src/g_shared/sbarinfo_commands.cpp | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 29ea9774b..eed9d86c7 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1288,7 +1288,7 @@ public: } if(clearDontDraw) - screen->Clear(static_cast(rcx), static_cast(rcy), static_cast(MIN(rcr, w)), static_cast(MIN(rcb, h)), GPalette.BlackIndex, 0); + screen->Clear(static_cast(rcx), static_cast(rcy), static_cast(MIN(rcr, rcx+w)), static_cast(MIN(rcb, rcy+h)), GPalette.BlackIndex, 0); else { if(alphaMap) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index e4413faf0..e66d23f79 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2084,9 +2084,12 @@ class CommandDrawBar : public SBarInfoCommand FTexture *fg = statusBar->Images[foreground]; FTexture *bg = (background != -1) ? statusBar->Images[background] : NULL; - + + fixed_t value = drawValue; if(border != 0) { + value = FRACUNIT - value; //invert since the new drawing method requires drawing the bg on the fg. + //Draw the whole foreground statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } @@ -2103,7 +2106,7 @@ class CommandDrawBar : public SBarInfoCommand fixed_t clip[4] = {0, 0, 0, 0}; fixed_t sizeOfImage = (horizontal ? fg->GetScaledWidth()-border*2 : fg->GetScaledHeight()-border*2)< 0) { value = (value << FRACBITS) / max; if(value > FRACUNIT) value = FRACUNIT; } - else if(border != 0 && max == 0 && value <= 0) - value = FRACUNIT; else value = 0; if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) From ce2c2bd825a0783154a4c345f96a5398e492d384 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Sep 2010 20:23:44 +0000 Subject: [PATCH 249/251] - replaced AM_Rotate with a more precise floating point version posted by Entryway. SVN r2713 (trunk) --- src/am_map.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 0a0dafd66..f3f7d7a39 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1938,14 +1938,19 @@ void AM_drawWalls (bool allmap) // //============================================================================= -void AM_rotate (fixed_t *x, fixed_t *y, angle_t a) +void AM_rotate(fixed_t *xp, fixed_t *yp, angle_t a) { - fixed_t tmpx; + double x = FIXED2FLOAT(*xp); + double y = FIXED2FLOAT(*yp); + double rot = (double)a / (double)(1u << 31) * (double)M_PI; + double sinrot = sin(rot); + double cosrot = cos(rot); - a >>= ANGLETOFINESHIFT; - tmpx = DMulScale16 (*x,finecosine[a],*y,-finesine[a]); - *y = DMulScale16 (*x,finesine[a],*y,finecosine[a]); - *x = tmpx; + double tmpx = (x * cosrot) - (y * sinrot); + y = (x * sinrot) + (y * cosrot); + x = tmpx; + *xp = FLOAT2FIXED(x); + *yp = FLOAT2FIXED(y); } //============================================================================= From 610ff3956e658c4ac3defc9131aeed80aa5afc16 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 8 Sep 2010 08:53:39 +0000 Subject: [PATCH 250/251] - fixed P_LoopSideDefs could crash on the second P_LoopSidedefs call if there were unconnected linedefs in the map. SVN r2716 (trunk) --- src/p_setup.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 02329bdb9..09d2d2e8d 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2202,9 +2202,10 @@ static void P_LoopSidedefs (bool firstloop) right = sidetemp[right].b.first; - if (firstloop && right == NO_SIDE) - { // There is no right side! - Printf ("Line %d's right edge is unconnected\n", linemap[unsigned(line-lines)]); + if (right == NO_SIDE) + { + // There is no right side! + if (firstloop) Printf ("Line %d's right edge is unconnected\n", linemap[unsigned(line-lines)]); continue; } From ec0b07b5e2e2eef417c10bfec3a1cdfad581d06f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 10 Sep 2010 13:49:08 +0000 Subject: [PATCH 251/251] - added Entryway's AM_Rotate optimization. SVN r2739 (trunk) --- src/am_map.cpp | 16 ++++++++++++---- src/win32/fb_d3d9.cpp | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index f3f7d7a39..73a7f8c98 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1940,12 +1940,20 @@ void AM_drawWalls (bool allmap) void AM_rotate(fixed_t *xp, fixed_t *yp, angle_t a) { + static angle_t angle_saved = 0; + static double sinrot = 0; + static double cosrot = 1; + + if (angle_saved != a) + { + angle_saved = a; + double rot = (double)a / (double)(1u << 31) * (double)M_PI; + sinrot = sin(rot); + cosrot = cos(rot); + } + double x = FIXED2FLOAT(*xp); double y = FIXED2FLOAT(*yp); - double rot = (double)a / (double)(1u << 31) * (double)M_PI; - double sinrot = sin(rot); - double cosrot = cos(rot); - double tmpx = (x * cosrot) - (y * sinrot); y = (x * sinrot) + (y * cosrot); x = tmpx; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 020be2de1..7453571e5 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -3311,8 +3311,8 @@ void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, quad->NumTris = npoints - 2; yoffs = GatheringWipeScreen ? 0 : LBOffset; - uscale = float(1.f / (texture->GetWidth() * scalex)); - vscale = float(1.f / (texture->GetHeight() * scaley)); + uscale = float(1.f / (texture->GetScaledWidth() * scalex)); + vscale = float(1.f / (texture->GetScaledHeight() * scaley)); ox = float(originx); oy = float(originy);