From 1907983ab7bff1e88d3f7e60fc10c2e82c925091 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 17 Oct 2012 19:45:04 +0000 Subject: [PATCH 001/387] - Ported frame rate limiting code to SDL. SVN r3891 (trunk) --- src/sdl/hardware.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++- src/sdl/hardware.h | 24 +++++++++++++ src/sdl/i_system.cpp | 33 +++--------------- src/sdl/sdlvideo.cpp | 6 ++++ 4 files changed, 116 insertions(+), 30 deletions(-) diff --git a/src/sdl/hardware.cpp b/src/sdl/hardware.cpp index ef78b4c31..49730802b 100644 --- a/src/sdl/hardware.cpp +++ b/src/sdl/hardware.cpp @@ -33,6 +33,8 @@ */ #include +#include +#include #include "hardware.h" #include "i_video.h" @@ -175,10 +177,89 @@ void I_ClosestResolution (int *width, int *height, int bits) return; } } -} +} + +//========================================================================== +// +// SetFPSLimit +// +// Initializes an event timer to fire at a rate of /sec. The video +// update will wait for this timer to trigger before updating. +// +// Pass 0 as the limit for unlimited. +// Pass a negative value for the limit to use the value of vid_maxfps. +// +//========================================================================== + +EXTERN_CVAR(Int, vid_maxfps); +EXTERN_CVAR(Bool, cl_capfps); + +Semaphore FPSLimitSemaphore; + +static void FPSLimitNotify(sigval val) +{ + SEMAPHORE_SIGNAL(FPSLimitSemaphore) +} void I_SetFPSLimit(int limit) { + static sigevent FPSLimitEvent; + static timer_t FPSLimitTimer; + static bool FPSLimitTimerEnabled = false; + static bool EventSetup = false; + if(!EventSetup) + { + EventSetup = true; + FPSLimitEvent.sigev_notify = SIGEV_THREAD; + FPSLimitEvent.sigev_signo = 0; + FPSLimitEvent.sigev_value.sival_int = 0; + FPSLimitEvent.sigev_notify_function = FPSLimitNotify; + FPSLimitEvent.sigev_notify_attributes = NULL; + + SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0) + } + + if (limit < 0) + { + limit = vid_maxfps; + } + // Kill any leftover timer. + if (FPSLimitTimerEnabled) + { + timer_delete(FPSLimitTimer); + FPSLimitTimerEnabled = false; + } + if (limit == 0) + { // no limit + DPrintf("FPS timer disabled\n"); + } + else + { + FPSLimitTimerEnabled = true; + if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1) + Printf("Failed to create FPS limitter event\n"); + itimerspec period = { {0, 0}, {0, 0} }; + period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit; + if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1) + Printf("Failed to set FPS limitter timer\n"); + DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); + } +} + +CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (vid_maxfps < TICRATE && vid_maxfps != 0) + { + vid_maxfps = TICRATE; + } + else if (vid_maxfps > 1000) + { + vid_maxfps = 1000; + } + else if (cl_capfps == 0) + { + I_SetFPSLimit(vid_maxfps); + } } extern int NewWidth, NewHeight, NewBits, DisplayBits; diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index 651d3ee2b..86f3bd242 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -37,6 +37,29 @@ #include "i_video.h" #include "v_video.h" +// Semaphores +#ifdef __APPLE__ +#include +#include +#include +typedef semaphore_t Semaphore; +#define SEMAPHORE_WAIT(sem) \ + while(semaphore_wait(sem) != KERN_SUCCESS){} +#define SEMAPHORE_SIGNAL(sem) \ + semaphore_signal(sem) +#define SEMAPHORE_INIT(sem, shared, value) \ + semaphore_create(mach_task_self(), &sem, shared, value); +#else +#include +typedef sem_t Semaphore; +#define SEMAPHORE_WAIT(sem) \ + while(sem_wait(&sem) != 0); +#define SEMAPHORE_SIGNAL(sem) \ + sem_post(&sem); +#define SEMAPHORE_INIT(sem, shared, value) \ + sem_init(&sem, shared, value); +#endif + class IVideo { public: @@ -59,6 +82,7 @@ void I_InitGraphics (); void I_ShutdownGraphics (); void I_CreateRenderer(); +extern Semaphore FPSLimitSemaphore; void I_SetFPSLimit(int limit); extern IVideo *Video; diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index f7ca515d3..df15ce774 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -38,14 +38,6 @@ #include #endif -#ifdef __APPLE__ -#include -#include -#include -#else -#include -#endif - #include "doomerrors.h" #include @@ -144,11 +136,7 @@ static DWORD BaseTime; static int TicFrozen; // Signal based timer. -#ifdef __APPLE__ -static semaphore_t timerWait; -#else -static sem_t timerWait; -#endif +static Semaphore timerWait; static int tics; static DWORD sig_start, sig_next; @@ -221,12 +209,7 @@ int I_WaitForTicSignaled (int prevtic) while(tics <= prevtic) { -#ifdef __APPLE__ - while(semaphore_wait(timerWait) != KERN_SUCCESS) - ; -#else - while(sem_wait(&timerWait) != 0); -#endif + SEMAPHORE_WAIT(timerWait) } return tics; @@ -276,11 +259,7 @@ void I_HandleAlarm (int sig) tics++; sig_start = SDL_GetTicks(); sig_next = Scale((Scale (sig_start, TICRATE, 1000) + 1), 1000, TICRATE); -#ifdef __APPLE__ - semaphore_signal(timerWait); -#else - sem_post(&timerWait); -#endif + SEMAPHORE_SIGNAL(timerWait) } // @@ -290,11 +269,7 @@ void I_HandleAlarm (int sig) // void I_SelectTimer() { -#ifdef __APPLE__ - semaphore_create(mach_task_self(), &timerWait, 0, 0); -#else - sem_init(&timerWait, 0, 0); -#endif + SEMAPHORE_INIT(timerWait, 0, 0) signal(SIGALRM, I_HandleAlarm); struct itimerval itv; diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index 26723c583..f0a324565 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -80,6 +80,7 @@ extern SDL_Rect cursorBlit; extern bool GUICapture; EXTERN_CVAR (Float, Gamma) +EXTERN_CVAR (Int, vid_maxfps) // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -374,6 +375,11 @@ void SDLFB::Update () DrawRateStuff (); + if(vid_maxfps) + { + SEMAPHORE_WAIT(FPSLimitSemaphore) + } + Buffer = NULL; LockCount = 0; UpdatePending = false; From df5d43badf99ed5186b29d8dd3936a7d9292237c Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 18 Oct 2012 00:57:56 +0000 Subject: [PATCH 002/387] - OK, so we can't have vid_maxfps on OS X since there does not appear to be an equivalent to POSIX timers. The only thing I could find would require Objective-C and an event loop. SVN r3892 (trunk) --- src/sdl/hardware.cpp | 14 +++++++++++--- src/sdl/hardware.h | 2 +- src/sdl/sdlvideo.cpp | 6 ++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sdl/hardware.cpp b/src/sdl/hardware.cpp index 49730802b..ee907e601 100644 --- a/src/sdl/hardware.cpp +++ b/src/sdl/hardware.cpp @@ -190,10 +190,11 @@ void I_ClosestResolution (int *width, int *height, int bits) // Pass a negative value for the limit to use the value of vid_maxfps. // //========================================================================== - + EXTERN_CVAR(Int, vid_maxfps); EXTERN_CVAR(Bool, cl_capfps); - + +#ifndef __APPLE__ Semaphore FPSLimitSemaphore; static void FPSLimitNotify(sigval val) @@ -244,7 +245,14 @@ void I_SetFPSLimit(int limit) Printf("Failed to set FPS limitter timer\n"); DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); } -} +} +#else +// So Apple doesn't support POSIX timers and I can't find a good substitute short of +// having Objective-C Cocoa events or something like that. +void I_SetFPSLimit(int limit) +{ +} +#endif CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index 86f3bd242..04d02c9bf 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -46,7 +46,7 @@ typedef semaphore_t Semaphore; #define SEMAPHORE_WAIT(sem) \ while(semaphore_wait(sem) != KERN_SUCCESS){} #define SEMAPHORE_SIGNAL(sem) \ - semaphore_signal(sem) + semaphore_signal(sem); #define SEMAPHORE_INIT(sem, shared, value) \ semaphore_create(mach_task_self(), &sem, shared, value); #else diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index f0a324565..cba5c4cf7 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -374,11 +374,13 @@ void SDLFB::Update () } DrawRateStuff (); - + +#ifndef __APPLE__ if(vid_maxfps) { SEMAPHORE_WAIT(FPSLimitSemaphore) - } + } +#endif Buffer = NULL; LockCount = 0; From b52c3238ebbc3ee9bad8b040661941bf33c858bf Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 22 Oct 2012 01:28:11 +0000 Subject: [PATCH 003/387] - Instead of implementing the wad code in three places, use the normal resource code for map loading and GL node loading. SVN r3897 (trunk) --- src/compatibility.cpp | 1 + src/p_glnodes.cpp | 76 +++++++++++++-------------- src/p_setup.cpp | 117 ++++++++++++++++++------------------------ src/p_setup.h | 30 +++++++---- src/p_udmf.cpp | 1 + src/p_usdf.cpp | 1 + 6 files changed, 109 insertions(+), 117 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 2a721c33f..ddbe8b3e8 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -50,6 +50,7 @@ #include "g_level.h" #include "p_lnspec.h" #include "r_state.h" +#include "w_wad.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index ee32df4b0..a139f7a69 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -230,18 +230,18 @@ bool P_CheckForGLNodes() static int firstglvertex; static bool format5; -static bool LoadGLVertexes(FileReader * f, wadlump_t * lump) +static bool LoadGLVertexes(FileReader * lump) { BYTE *gldata; int i; firstglvertex = numvertexes; - int gllen=lump->Size; + int gllen=lump->GetLength(); gldata = new BYTE[gllen]; - f->Seek(lump->FilePos, SEEK_SET); - f->Read(gldata, gllen); + lump->Seek(0, SEEK_SET); + lump->Read(gldata, gllen); if (*(int *)gldata == gNd5) { @@ -310,16 +310,16 @@ static inline int checkGLVertex3(int num) // //========================================================================== -static bool LoadGLSegs(FileReader * f, wadlump_t * lump) +static bool LoadGLSegs(FileReader * lump) { char *data; int i; line_t *ldef=NULL; - numsegs = lump->Size; + numsegs = lump->GetLength(); data= new char[numsegs]; - f->Seek(lump->FilePos, SEEK_SET); - f->Read(data, lump->Size); + lump->Seek(0, SEEK_SET); + lump->Read(data, numsegs); segs=NULL; #ifdef _MSC_VER @@ -442,15 +442,15 @@ static bool LoadGLSegs(FileReader * f, wadlump_t * lump) // //========================================================================== -static bool LoadGLSubsectors(FileReader * f, wadlump_t * lump) +static bool LoadGLSubsectors(FileReader * lump) { char * datab; int i; - numsubsectors = lump->Size; + numsubsectors = lump->GetLength(); datab = new char[numsubsectors]; - f->Seek(lump->FilePos, SEEK_SET); - f->Read(datab, lump->Size); + lump->Seek(0, SEEK_SET); + lump->Read(datab, numsubsectors); if (numsubsectors == 0) { @@ -524,7 +524,7 @@ static bool LoadGLSubsectors(FileReader * f, wadlump_t * lump) // //========================================================================== -static bool LoadNodes (FileReader * f, wadlump_t * lump) +static bool LoadNodes (FileReader * lump) { const int NF_SUBSECTOR = 0x8000; const int GL5_NF_SUBSECTOR = (1 << 31); @@ -538,15 +538,15 @@ static bool LoadNodes (FileReader * f, wadlump_t * lump) if (!format5) { mapnode_t* mn, * basemn; - numnodes = lump->Size / sizeof(mapnode_t); + numnodes = lump->GetLength() / sizeof(mapnode_t); if (numnodes == 0) return false; nodes = new node_t[numnodes]; - f->Seek(lump->FilePos, SEEK_SET); + lump->Seek(0, SEEK_SET); basemn = mn = new mapnode_t[numnodes]; - f->Read(mn, lump->Size); + lump->Read(mn, lump->GetLength()); used = (WORD *)alloca (sizeof(WORD)*numnodes); memset (used, 0, sizeof(WORD)*numnodes); @@ -598,15 +598,15 @@ static bool LoadNodes (FileReader * f, wadlump_t * lump) else { gl5_mapnode_t* mn, * basemn; - numnodes = lump->Size / sizeof(gl5_mapnode_t); + numnodes = lump->GetLength() / sizeof(gl5_mapnode_t); if (numnodes == 0) return false; nodes = new node_t[numnodes]; - f->Seek(lump->FilePos, SEEK_SET); + lump->Seek(0, SEEK_SET); basemn = mn = new gl5_mapnode_t[numnodes]; - f->Read(mn, lump->Size); + lump->Read(mn, lump->GetLength()); used = (WORD *)alloca (sizeof(WORD)*numnodes); memset (used, 0, sizeof(WORD)*numnodes); @@ -664,19 +664,19 @@ static bool LoadNodes (FileReader * f, wadlump_t * lump) // //========================================================================== -static bool DoLoadGLNodes(FileReader * f, wadlump_t * lumps) +static bool DoLoadGLNodes(FileReader ** lumps) { - if (!LoadGLVertexes(f, &lumps[0])) + if (!LoadGLVertexes(lumps[0])) { return false; } - if (!LoadGLSegs(f, &lumps[1])) + if (!LoadGLSegs(lumps[1])) { delete [] segs; segs = NULL; return false; } - if (!LoadGLSubsectors(f, &lumps[2])) + if (!LoadGLSubsectors(lumps[2])) { delete [] subsectors; subsectors = NULL; @@ -684,7 +684,7 @@ static bool DoLoadGLNodes(FileReader * f, wadlump_t * lumps) segs = NULL; return false; } - if (!LoadNodes(f, &lumps[3])) + if (!LoadNodes(lumps[3])) { delete [] nodes; nodes = NULL; @@ -851,7 +851,7 @@ static int FindGLNodesInFile(FileReader * f, const char * label) bool P_LoadGLNodes(MapData * map) { - if (map->MapLumps[ML_GLZNODES].Size != 0) + if (map->MapLumps[ML_GLZNODES].Reader && map->MapLumps[ML_GLZNODES].Reader->GetLength() != 0) { const int idcheck = MAKE_ID('Z','G','L','N'); const int idcheck2 = MAKE_ID('Z','G','L','2'); @@ -894,13 +894,13 @@ bool P_LoadGLNodes(MapData * map) if (!CheckCachedNodes(map)) { - wadlump_t gwalumps[4]; + FileReader *gwalumps[4] = { NULL, NULL, NULL, NULL }; 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; + FResourceFile * f_gwa = NULL; const char * name = Wads.GetWadFullName(lumpfile); @@ -913,10 +913,9 @@ bool P_LoadGLNodes(MapData * map) // 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); + gwalumps[i]=Wads.ReopenLumpNum(li+i+1); } - return DoLoadGLNodes(fr, gwalumps); + return DoLoadGLNodes(gwalumps); } else { @@ -928,10 +927,10 @@ bool P_LoadGLNodes(MapData * map) strcpy(ext, ".gwa"); // Todo: Compare file dates - f_gwa = fopen(path, "rb"); + f_gwa = FResourceFile::OpenResourceFile(path, NULL, true); if (f_gwa==NULL) return false; - fr = new FileReader(f_gwa); + fr = f_gwa->GetReader(); strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(map->lumpnum), 8); } @@ -946,23 +945,24 @@ bool P_LoadGLNodes(MapData * map) 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)) + if (strnicmp(f_gwa->GetLump(i)->Name, check[i], 8)) { result=false; break; } + else + gwalumps[i] = f_gwa->GetLump(i)->NewReader(); } - if (result) result = DoLoadGLNodes(fr, gwalumps); + if (result) result = DoLoadGLNodes(gwalumps); } if (f_gwa) { delete fr; - fclose(f_gwa); + delete f_gwa; } + for(unsigned int i = 0;i < 4;++i) + delete gwalumps[i]; return result; } else return true; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 37a9da789..075c934dc 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -251,6 +251,7 @@ static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname, MapData *P_OpenMapData(const char * mapname) { MapData * map = new MapData; + FileReader * wadReader = NULL; bool externalfile = !strnicmp(mapname, "file:", 5); if (externalfile) @@ -261,8 +262,8 @@ MapData *P_OpenMapData(const char * mapname) delete map; return NULL; } - map->file = new FileReader(mapname); - map->CloseOnDestruct = true; + map->resource = FResourceFile::OpenResourceFile(mapname, NULL, true); + wadReader = map->resource->GetReader(); } else { @@ -284,18 +285,13 @@ MapData *P_OpenMapData(const char * mapname) int lumpfile = Wads.GetLumpFile(lump_name); int nextfile = Wads.GetLumpFile(lump_name+1); - map->file = Wads.GetFileReader(lumpfile); - map->CloseOnDestruct = false; map->lumpnum = lump_name; if (lumpfile != nextfile) { // The following lump is from a different file so whatever this is, // it is not a multi-lump Doom level so let's assume it is a Build map. - map->MapLumps[0].FilePos = 0; - map->MapLumps[0].Size = Wads.LumpLength(lump_name); - map->file = Wads.ReopenLumpNum(lump_name); - map->CloseOnDestruct = true; + map->MapLumps[0].Reader = map->file = Wads.ReopenLumpNum(lump_name); if (!P_IsBuildMap(map)) { delete map; @@ -306,15 +302,12 @@ MapData *P_OpenMapData(const char * mapname) // This case can only happen if the lump is inside a real WAD file. // As such any special handling for other types of lumps is skipped. - map->MapLumps[0].FilePos = Wads.GetLumpOffset(lump_name); - map->MapLumps[0].Size = Wads.LumpLength(lump_name); + map->MapLumps[0].Reader = Wads.ReopenLumpNum(lump_name); map->Encrypted = Wads.IsEncryptedFile(lump_name); if (map->Encrypted) { // If it's encrypted, then it's a Blood file, presumably a map. - map->file = Wads.ReopenLumpNum(lump_name); - map->CloseOnDestruct = true; - map->MapLumps[0].FilePos = 0; + map->MapLumps[0].Reader = map->file = Wads.ReopenLumpNum(lump_name); if (!P_IsBuildMap(map)) { delete map; @@ -332,22 +325,20 @@ MapData *P_OpenMapData(const char * mapname) // Since levels must be stored in WADs they can't really have full // names and for any valid level lump this always returns the short name. const char * lumpname = Wads.GetLumpFullName(lump_name + i); - index = GetMapIndex(mapname, index, lumpname, i != 1 || map->MapLumps[0].Size == 0); + index = GetMapIndex(mapname, index, lumpname, i != 1 || Wads.LumpLength(lump_name + i) == 0); if (index == ML_BEHAVIOR) map->HasBehavior = true; // The next lump is not part of this map anymore if (index < 0) break; - map->MapLumps[index].FilePos = Wads.GetLumpOffset(lump_name + i); - map->MapLumps[index].Size = Wads.LumpLength(lump_name + i); + map->MapLumps[index].Reader = Wads.ReopenLumpNum(lump_name + i); strncpy(map->MapLumps[index].Name, lumpname, 8); } } else { map->isText = true; - map->MapLumps[1].FilePos = Wads.GetLumpOffset(lump_name + 1); - map->MapLumps[1].Size = Wads.LumpLength(lump_name + 1); + map->MapLumps[1].Reader = Wads.ReopenLumpNum(lump_name + 1); for(int i = 2;; i++) { const char * lumpname = Wads.GetLumpFullName(lump_name + i); @@ -383,8 +374,7 @@ MapData *P_OpenMapData(const char * mapname) break; } else continue; - map->MapLumps[index].FilePos = Wads.GetLumpOffset(lump_name + i); - map->MapLumps[index].Size = Wads.LumpLength(lump_name + i); + map->MapLumps[index].Reader = Wads.ReopenLumpNum(lump_name + i); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -402,42 +392,35 @@ MapData *P_OpenMapData(const char * mapname) return NULL; } map->lumpnum = lump_wad; - map->file = Wads.ReopenLumpNum(lump_wad); - map->CloseOnDestruct = true; + map->resource = FResourceFile::OpenResourceFile(Wads.GetLumpFullName(lump_wad), Wads.ReopenLumpNum(lump_wad), true); + wadReader = map->resource->GetReader(); } } DWORD id; - map->file->Read(&id, sizeof(id)); + // Although we're using the resource system, we still want to be sure we're + // reading from a wad file. + wadReader->Seek(0, SEEK_SET); + wadReader->Read(&id, sizeof(id)); if (id == IWAD_ID || id == PWAD_ID) { char maplabel[9]=""; int index=0; - DWORD dirofs, numentries; - (*map->file) >> numentries >> dirofs; + map->MapLumps[0].Reader = map->resource->GetLump(0)->NewReader(); - map->file->Seek(dirofs, SEEK_SET); - (*map->file) >> map->MapLumps[0].FilePos >> map->MapLumps[0].Size; - map->file->Read(map->MapLumps[0].Name, 8); - - for(DWORD i = 1; i < numentries; i++) + for(DWORD i = 1; i < map->resource->LumpCount(); i++) { - DWORD offset, size; - char lumpname[8]; + const char* lumpname = map->resource->GetLump(i)->Name; - (*map->file) >> offset >> size; - map->file->Read(lumpname, 8); if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) { map->isText = true; - map->MapLumps[1].FilePos = offset; - map->MapLumps[1].Size = size; for(int i = 2;; i++) { - (*map->file) >> offset >> size; - long v = map->file->Read(lumpname, 8); + lumpname = map->resource->GetLump(i)->Name; + long v = strlen(lumpname); if (v < 8) { I_Error("Invalid map definition for %s", mapname); @@ -469,8 +452,7 @@ MapData *P_OpenMapData(const char * mapname) return map; } else continue; - map->MapLumps[index].FilePos = offset; - map->MapLumps[index].Size = size; + map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -489,15 +471,14 @@ MapData *P_OpenMapData(const char * mapname) maplabel[8]=0; } - map->MapLumps[index].FilePos = offset; - map->MapLumps[index].Size = size; + map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); strncpy(map->MapLumps[index].Name, lumpname, 8); } } else { // This is a Build map and not subject to WAD consistency checks. - map->MapLumps[0].Size = map->file->GetLength(); + //map->MapLumps[0].Size = wadReader->GetLength(); if (!P_IsBuildMap(map)) { delete map; @@ -532,29 +513,29 @@ void MapData::GetChecksum(BYTE cksum[16]) { if (isText) { - file->Seek(MapLumps[ML_TEXTMAP].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_TEXTMAP].Size); + Seek(ML_TEXTMAP); + md5.Update(file, Size(ML_TEXTMAP)); } else { - if (MapLumps[ML_LABEL].Size != 0) + if (Size(ML_LABEL) != 0) { - file->Seek(MapLumps[ML_LABEL].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_LABEL].Size); + Seek(ML_LABEL); + md5.Update(file, Size(ML_LABEL)); } - file->Seek(MapLumps[ML_THINGS].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_THINGS].Size); - file->Seek(MapLumps[ML_LINEDEFS].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_LINEDEFS].Size); - file->Seek(MapLumps[ML_SIDEDEFS].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_SIDEDEFS].Size); - file->Seek(MapLumps[ML_SECTORS].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_SECTORS].Size); + Seek(ML_THINGS); + md5.Update(file, Size(ML_THINGS)); + Seek(ML_LINEDEFS); + md5.Update(file, Size(ML_LINEDEFS)); + Seek(ML_SIDEDEFS); + md5.Update(file, Size(ML_SIDEDEFS)); + Seek(ML_SECTORS); + md5.Update(file, Size(ML_SECTORS)); } if (HasBehavior) { - file->Seek(MapLumps[ML_BEHAVIOR].FilePos, SEEK_SET); - md5.Update(file, MapLumps[ML_BEHAVIOR].Size); + Seek(ML_BEHAVIOR); + md5.Update(file, Size(ML_BEHAVIOR)); } } md5.Final(cksum); @@ -834,7 +815,7 @@ void P_LoadVertexes (MapData * map) // Determine number of vertices: // total lump length / vertex record length. - numvertexes = map->MapLumps[ML_VERTEXES].Size / sizeof(mapvertex_t); + numvertexes = map->Size(ML_VERTEXES) / sizeof(mapvertex_t); numvertexdatas = 0; if (numvertexes == 0) @@ -1199,7 +1180,7 @@ void P_LoadSegs (MapData * map) int dis; // phares 10/4/98 int dx,dy; // phares 10/4/98 int vnum1,vnum2; // phares 10/4/98 - int lumplen = map->MapLumps[ML_SEGS].Size; + int lumplen = map->Size(ML_SEGS); memset (vertchanged,0,numvertexes); // phares 10/4/98 @@ -1382,7 +1363,7 @@ void P_LoadSubsectors (MapData * map) int i; DWORD maxseg = map->Size(ML_SEGS) / sizeof(segtype); - numsubsectors = map->MapLumps[ML_SSECTORS].Size / sizeof(subsectortype); + numsubsectors = map->Size(ML_SSECTORS) / sizeof(subsectortype); if (numsubsectors == 0 || maxseg == 0 ) { @@ -1746,7 +1727,7 @@ void P_LoadThings (MapData * map) void P_LoadThings2 (MapData * map) { - int lumplen = map->MapLumps[ML_THINGS].Size; + int lumplen = map->Size(ML_THINGS); int numthings = lumplen / sizeof(mapthinghexen_t); char *mtp; @@ -3561,13 +3542,13 @@ void P_SetupLevel (char *lumpname, int position) // [RH] Support loading Build maps (because I felt like it. :-) buildmap = false; - if (map->MapLumps[0].Size > 0) + if (map->Size(0) > 0) { - BYTE *mapdata = new BYTE[map->MapLumps[0].Size]; + BYTE *mapdata = new BYTE[map->Size(0)]; map->Seek(0); - map->file->Read(mapdata, map->MapLumps[0].Size); + map->file->Read(mapdata, map->Size(0)); times[0].Clock(); - buildmap = P_LoadBuildMap (mapdata, map->MapLumps[0].Size, &buildthings, &numbuildthings); + buildmap = P_LoadBuildMap (mapdata, map->Size(0), &buildthings, &numbuildthings); times[0].Unclock(); delete[] mapdata; } @@ -3704,14 +3685,14 @@ void P_SetupLevel (char *lumpname, int position) 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) + if (map->Size(ML_ZNODES) != 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) + else if (map->Size(ML_GLZNODES) != 0) { map->Seek(ML_GLZNODES); idcheck = MAKE_ID('Z','G','L','N'); diff --git a/src/p_setup.h b/src/p_setup.h index 4bb0435e0..dc171e071 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -23,42 +23,50 @@ #ifndef __P_SETUP__ #define __P_SETUP__ -#include "w_wad.h" +#include "resourcefiles/resourcefile.h" #include "doomdata.h" struct MapData { - wadlump_t MapLumps[ML_MAX]; + struct + { + char Name[8]; + FileReader *Reader; + } MapLumps[ML_MAX]; bool HasBehavior; - bool CloseOnDestruct; bool Encrypted; bool isText; int lumpnum; FileReader * file; + FResourceFile * resource; MapData() { memset(MapLumps, 0, sizeof(MapLumps)); file = NULL; + resource = NULL; lumpnum = -1; HasBehavior = false; - CloseOnDestruct = true; Encrypted = false; isText = false; } ~MapData() { - if (CloseOnDestruct && file != NULL) delete file; - file = NULL; + for (unsigned int i = 0;i < ML_MAX;++i) + delete MapLumps[i].Reader; + + delete resource; + resource = NULL; } void Seek(unsigned int lumpindex) { if (lumpindexSeek(MapLumps[lumpindex].FilePos, SEEK_SET); + file = MapLumps[lumpindex].Reader; + file->Seek(0, SEEK_SET); } } @@ -66,17 +74,17 @@ struct MapData { if (lumpindexSeek(MapLumps[lumpindex].FilePos, SEEK_SET); + if (size == -1) size = MapLumps[lumpindex].Reader->GetLength(); + Seek(lumpindex); file->Read(buffer, size); } } DWORD Size(unsigned int lumpindex) { - if (lumpindexGetLength(); } return 0; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index ce05903e0..2bc3e0bea 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -45,6 +45,7 @@ #include "p_udmf.h" #include "r_state.h" #include "r_data/colormaps.h" +#include "w_wad.h" //=========================================================================== // diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d25cc8605..dc287384d 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -41,6 +41,7 @@ #include "doomerrors.h" #include "cmdlib.h" #include "actor.h" +#include "w_wad.h" #define Zd 1 #define St 2 From 4b218c1c18235503d9216367ac5ea7c226f7c687 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 22 Oct 2012 19:54:13 +0000 Subject: [PATCH 004/387] - Added support for compression in wads and big endian wads (which basically means the Jaguar Doom wad can be loaded as a pwad although it's pretty ugly since the graphic formats aren't supported). SVN r3898 (trunk) --- src/resourcefiles/file_wad.cpp | 334 ++++++++++++++++++++++++++++++--- 1 file changed, 312 insertions(+), 22 deletions(-) diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index a0f04269c..219f851eb 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -35,24 +35,267 @@ #include "resourcefile.h" #include "cmdlib.h" +#include "templates.h" #include "v_text.h" #include "w_wad.h" +// Console Doom LZSS wrapper. +class FileReaderLZSS : public FileReaderBase +{ +private: + enum { BUFF_SIZE = 4096, WINDOW_SIZE = 4096, INTERNAL_BUFFER_SIZE = 128 }; + + FileReader &File; + bool SawEOF; + BYTE InBuff[BUFF_SIZE]; + + enum StreamState + { + STREAM_EMPTY, + STREAM_BITS, + STREAM_FLUSH, + STREAM_FINAL + }; + struct + { + StreamState State; + + BYTE *In; + unsigned int AvailIn; + unsigned int InternalOut; + + BYTE CFlags, Bits; + + BYTE Window[WINDOW_SIZE+INTERNAL_BUFFER_SIZE]; + const BYTE *WindowData; + BYTE *InternalBuffer; + } Stream; + + void FillBuffer() + { + if(Stream.AvailIn) + memmove(InBuff, Stream.In, Stream.AvailIn); + + long numread = File.Read(InBuff+Stream.AvailIn, BUFF_SIZE-Stream.AvailIn); + + if (numread < BUFF_SIZE) + { + SawEOF = true; + } + Stream.In = InBuff; + Stream.AvailIn = numread+Stream.AvailIn; + } + + // Reads a flag byte. + void PrepareBlocks() + { + assert(Stream.InternalBuffer == Stream.WindowData); + Stream.CFlags = *Stream.In++; + --Stream.AvailIn; + Stream.Bits = 0xFF; + Stream.State = STREAM_BITS; + } + + // Reads the next chunk in the block. Returns true if successful and + // returns false if it ran out of input data. + bool UncompressBlock() + { + if(Stream.CFlags & 1) + { + // Check to see if we have enough input + if(Stream.AvailIn < 2) + return false; + Stream.AvailIn -= 2; + + WORD pos = BigShort(*(WORD*)Stream.In); + BYTE len = (pos & 0xF)+1; + pos >>= 4; + Stream.In += 2; + if(len == 1) + { + // We've reached the end of the stream. + Stream.State = STREAM_FINAL; + return true; + } + + const BYTE* copyStart = Stream.InternalBuffer-pos-1; + + // Complete overlap: Single byte repeated + if(pos == 0) + memset(Stream.InternalBuffer, *copyStart, len); + // No overlap: One copy + else if(pos >= len) + memcpy(Stream.InternalBuffer, copyStart, len); + else + { + // Partial overlap: Copy in 2 or 3 chunks. + do + { + unsigned int copy = MIN(len, pos+1); + memcpy(Stream.InternalBuffer, copyStart, copy); + Stream.InternalBuffer += copy; + Stream.InternalOut += copy; + len -= copy; + pos += copy; // Increase our position since we can copy twice as much the next round. + } + while(len); + } + + Stream.InternalOut += len; + Stream.InternalBuffer += len; + } + else + { + // Uncompressed byte. + *Stream.InternalBuffer++ = *Stream.In++; + --Stream.AvailIn; + ++Stream.InternalOut; + } + + Stream.CFlags >>= 1; + Stream.Bits >>= 1; + + // If we're done with this block, flush the output + if(Stream.Bits == 0) + Stream.State = STREAM_FLUSH; + + return true; + } + +public: + FileReaderLZSS(FileReader &file) : File(file), SawEOF(false) + { + Stream.State = STREAM_EMPTY; + Stream.WindowData = Stream.InternalBuffer = Stream.Window+WINDOW_SIZE; + Stream.InternalOut = 0; + Stream.AvailIn = 0; + + FillBuffer(); + } + + ~FileReaderLZSS() + { + } + + long Read(void *buffer, long len) + { + + BYTE *Out = (BYTE*)buffer; + long AvailOut = len; + + do + { + while(Stream.AvailIn) + { + if(Stream.State == STREAM_EMPTY) + PrepareBlocks(); + else if(Stream.State == STREAM_BITS && !UncompressBlock()) + break; + else + break; + } + + unsigned int copy = MIN(Stream.InternalOut, AvailOut); + if(copy > 0) + { + memcpy(Out, Stream.WindowData, copy); + Out += copy; + AvailOut -= copy; + + // Slide our window + memmove(Stream.Window, Stream.Window+copy, WINDOW_SIZE+INTERNAL_BUFFER_SIZE-copy); + Stream.InternalBuffer -= copy; + Stream.InternalOut -= copy; + } + + if(Stream.State == STREAM_FINAL) + break; + + if(Stream.InternalOut == 0 && Stream.State == STREAM_FLUSH) + Stream.State = STREAM_EMPTY; + + if(Stream.AvailIn < 2) + FillBuffer(); + } + while(AvailOut && Stream.State != STREAM_FINAL); + + assert(AvailOut == 0); + return Out - (BYTE*)buffer; + } +}; + +//========================================================================== +// +// Wad Lump (with console doom LZSS support) +// +//========================================================================== + +class FWadFileLump : public FResourceLump +{ +public: + bool Compressed; + int Position; + + int GetFileOffset() { return Position; } + FileReader *GetReader() + { + if(!Compressed) + { + Owner->Reader->Seek(Position, SEEK_SET); + return Owner->Reader; + } + return NULL; + } + int FillCache() + { + if(!Compressed) + { + const char * buffer = Owner->Reader->GetBuffer(); + + if (buffer != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } + } + + Owner->Reader->Seek(Position, SEEK_SET); + Cache = new char[LumpSize]; + + if(Compressed) + { + FileReaderLZSS lzss(*Owner->Reader); + lzss.Read(Cache, LumpSize); + } + else + Owner->Reader->Read(Cache, LumpSize); + + RefCount = 1; + return 1; + } +}; + //========================================================================== // // Wad file // //========================================================================== -class FWadFile : public FUncompressedFile +class FWadFile : public FResourceFile { + FWadFileLump *Lumps; + bool IsMarker(int lump, const char *marker); void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack=false); void SkinHack (); public: FWadFile(const char * filename, FileReader *file); + ~FWadFile(); void FindStrifeTeaserVoices (); + FResourceLump *GetLump(int lump) { return &Lumps[lump]; } bool Open(bool quiet); }; @@ -65,11 +308,16 @@ public: // //========================================================================== -FWadFile::FWadFile(const char *filename, FileReader *file) : FUncompressedFile(filename, file) +FWadFile::FWadFile(const char *filename, FileReader *file) : FResourceFile(filename, file) { Lumps = NULL; } +FWadFile::~FWadFile() +{ + delete[] Lumps; +} + //========================================================================== // // Open it @@ -79,33 +327,76 @@ FWadFile::FWadFile(const char *filename, FileReader *file) : FUncompressedFile(f bool FWadFile::Open(bool quiet) { wadinfo_t header; + DWORD InfoTableOfs; + bool isBigEndian = false; // Little endian is assumed until proven otherwise + const long wadSize = Reader->GetLength(); Reader->Read(&header, sizeof(header)); NumLumps = LittleLong(header.NumLumps); - header.InfoTableOfs = LittleLong(header.InfoTableOfs); - - wadlump_t *fileinfo = new wadlump_t[NumLumps]; - Reader->Seek (header.InfoTableOfs, SEEK_SET); - Reader->Read (fileinfo, NumLumps * sizeof(wadlump_t)); + InfoTableOfs = LittleLong(header.InfoTableOfs); - Lumps = new FUncompressedLump[NumLumps]; - - if (!quiet) Printf(", %d lumps\n", NumLumps); - - for(DWORD i = 0; i < NumLumps; i++) + // Check to see if the little endian interpretation is valid + // This should detect most big endian wads + if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) { - uppercopy (Lumps[i].Name, fileinfo[i].Name); - Lumps[i].Name[8] = 0; - Lumps[i].Owner = this; - Lumps[i].Position = LittleLong(fileinfo[i].FilePos); - Lumps[i].LumpSize = LittleLong(fileinfo[i].Size); - Lumps[i].Namespace = ns_global; - Lumps[i].Flags = 0; - Lumps[i].FullName = NULL; + NumLumps = BigLong(header.NumLumps); + InfoTableOfs = BigLong(header.InfoTableOfs); + isBigEndian = true; } - if (!quiet) // don't bother with namespaces here. We won't need them. + // Read the directory. If we're still assuming little endian and the lump + // is out of range then we switch to big endian mode and try again. + do { + wadlump_t *fileinfo = new wadlump_t[NumLumps]; + Reader->Seek (InfoTableOfs, SEEK_SET); + Reader->Read (fileinfo, NumLumps * sizeof(wadlump_t)); + + Lumps = new FWadFileLump[NumLumps]; + + bool valid = true; + for(DWORD i = 0; i < NumLumps; i++) + { + uppercopy (Lumps[i].Name, fileinfo[i].Name); + Lumps[i].Name[8] = 0; + Lumps[i].Compressed = Lumps[i].Name[0] & 0x80; + Lumps[i].Name[0] &= ~0x80; + + Lumps[i].Owner = this; + Lumps[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); + Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); + if(Lumps[i].Position > wadSize || Lumps[i].Position + Lumps[i].LumpSize > wadSize) + { + valid = false; + break; + } + Lumps[i].Namespace = ns_global; + Lumps[i].Flags = 0; + Lumps[i].FullName = NULL; + } + + delete[] fileinfo; + if(!valid) + { + if(isBigEndian) + return false; + + delete[] Lumps; + NumLumps = BigLong(header.NumLumps); + InfoTableOfs = BigLong(header.InfoTableOfs); + isBigEndian = true; + continue; + } + + break; + } + while(true); + + if (!quiet) + { + Printf(", %d lumps\n", NumLumps); + + // don't bother with namespaces here. We won't need them. SetNamespace("S_START", "S_END", ns_sprites); SetNamespace("F_START", "F_END", ns_flats, true); SetNamespace("C_START", "C_END", ns_colormaps); @@ -116,7 +407,6 @@ bool FWadFile::Open(bool quiet) SetNamespace("VX_START", "VX_END", ns_voxels); SkinHack(); } - delete [] fileinfo; return true; } From cd2c1f68162e0c41f8ba10175c61dcd73ec73a2a Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 22 Oct 2012 21:58:52 +0000 Subject: [PATCH 005/387] - Remove 255 character length restriction on lump names. - Removed directory checking for big endian wads since the header check should be sufficient. SVN r3899 (trunk) --- src/resourcefiles/file_7z.cpp | 6 +-- src/resourcefiles/file_wad.cpp | 65 +++++++++--------------------- src/resourcefiles/file_zip.cpp | 11 ++--- src/resourcefiles/resourcefile.cpp | 9 +---- 4 files changed, 28 insertions(+), 63 deletions(-) diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 2943d00aa..2f955705e 100644 --- a/src/resourcefiles/file_7z.cpp +++ b/src/resourcefiles/file_7z.cpp @@ -271,7 +271,6 @@ bool F7ZFile::Open(bool quiet) for (DWORD i = 0; i < NumLumps; ++i) { CSzFileItem *file = &Archive->DB.db.Files[i]; - char name[256]; // skip Directories if (file->IsDir) @@ -280,10 +279,9 @@ bool F7ZFile::Open(bool quiet) continue; } - strncpy(name, file->Name, countof(name)-1); - name[countof(name)-1] = 0; + FString name = file->Name; FixPathSeperator(name); - strlwr(name); + name.ToLower(); lump_p->LumpNameSetup(name); lump_p->LumpSize = int(file->Size); diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index 219f851eb..1ea7b39ce 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -336,7 +336,7 @@ bool FWadFile::Open(bool quiet) InfoTableOfs = LittleLong(header.InfoTableOfs); // Check to see if the little endian interpretation is valid - // This should detect most big endian wads + // This should be sufficient to detect big endian wads. if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) { NumLumps = BigLong(header.NumLumps); @@ -344,53 +344,28 @@ bool FWadFile::Open(bool quiet) isBigEndian = true; } - // Read the directory. If we're still assuming little endian and the lump - // is out of range then we switch to big endian mode and try again. - do + wadlump_t *fileinfo = new wadlump_t[NumLumps]; + Reader->Seek (InfoTableOfs, SEEK_SET); + Reader->Read (fileinfo, NumLumps * sizeof(wadlump_t)); + + Lumps = new FWadFileLump[NumLumps]; + + for(DWORD i = 0; i < NumLumps; i++) { - wadlump_t *fileinfo = new wadlump_t[NumLumps]; - Reader->Seek (InfoTableOfs, SEEK_SET); - Reader->Read (fileinfo, NumLumps * sizeof(wadlump_t)); + uppercopy (Lumps[i].Name, fileinfo[i].Name); + Lumps[i].Name[8] = 0; + Lumps[i].Compressed = Lumps[i].Name[0] & 0x80; + Lumps[i].Name[0] &= ~0x80; - Lumps = new FWadFileLump[NumLumps]; - - bool valid = true; - for(DWORD i = 0; i < NumLumps; i++) - { - uppercopy (Lumps[i].Name, fileinfo[i].Name); - Lumps[i].Name[8] = 0; - Lumps[i].Compressed = Lumps[i].Name[0] & 0x80; - Lumps[i].Name[0] &= ~0x80; - - Lumps[i].Owner = this; - Lumps[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); - Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); - if(Lumps[i].Position > wadSize || Lumps[i].Position + Lumps[i].LumpSize > wadSize) - { - valid = false; - break; - } - Lumps[i].Namespace = ns_global; - Lumps[i].Flags = 0; - Lumps[i].FullName = NULL; - } - - delete[] fileinfo; - if(!valid) - { - if(isBigEndian) - return false; - - delete[] Lumps; - NumLumps = BigLong(header.NumLumps); - InfoTableOfs = BigLong(header.InfoTableOfs); - isBigEndian = true; - continue; - } - - break; + Lumps[i].Owner = this; + Lumps[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); + Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); + Lumps[i].Namespace = ns_global; + Lumps[i].Flags = 0; + Lumps[i].FullName = NULL; } - while(true); + + delete[] fileinfo; if (!quiet) { diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index e33938144..7e59bd35a 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -210,11 +210,8 @@ bool FZipFile::Open(bool quiet) { FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; - char name[256]; - int len = LittleShort(zip_fh->NameLength); - strncpy(name, dirptr + sizeof(FZipCentralDirectoryInfo), MIN(len, 255)); - name[len] = 0; + FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); dirptr += sizeof(FZipCentralDirectoryInfo) + LittleShort(zip_fh->NameLength) + LittleShort(zip_fh->ExtraLength) + @@ -236,7 +233,7 @@ bool FZipFile::Open(bool quiet) zip_fh->Method != METHOD_IMPLODE && zip_fh->Method != METHOD_SHRINK) { - if (!quiet) Printf("\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", Filename, name, zip_fh->Method); + if (!quiet) Printf("\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", Filename, name.GetChars(), zip_fh->Method); skipped++; continue; } @@ -244,13 +241,13 @@ bool FZipFile::Open(bool quiet) zip_fh->Flags = LittleShort(zip_fh->Flags); if (zip_fh->Flags & ZF_ENCRYPTED) { - if (!quiet) Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", Filename, name); + if (!quiet) Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", Filename, name.GetChars()); skipped++; continue; } FixPathSeperator(name); - strlwr(name); + name.ToLower(); lump_p->LumpNameSetup(name); lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize); diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 866605d14..8a4f07fd7 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -96,15 +96,10 @@ FResourceLump::~FResourceLump() void FResourceLump::LumpNameSetup(const char *iname) { - char base[256]; const char *lname = strrchr(iname,'/'); lname = (lname == NULL) ? iname : lname + 1; - strcpy(base, lname); - char *dot = strrchr(base, '.'); - if (dot != NULL) - { - *dot = 0; - } + FString base = lname; + base = base.Left(base.LastIndexOf('.')); uppercopy(Name, base); Name[8] = 0; FullName = copystring(iname); From 3ec5f7ed883bb0ba6fca1abd79570cc19dca4548 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 22 Oct 2012 23:42:20 +0000 Subject: [PATCH 006/387] - Run down the semaphores so they behave more like a mutex (note: mutexes/condition variables seem to be much slower). - Fixed: vid_maxfps and cl_capfps could run into a deadlock on Linux based operating systems. SVN r3900 (trunk) --- src/sdl/hardware.cpp | 18 +++++++++--------- src/sdl/hardware.h | 8 +++++++- src/sdl/sdlvideo.cpp | 7 ++++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/sdl/hardware.cpp b/src/sdl/hardware.cpp index ee907e601..352fe8558 100644 --- a/src/sdl/hardware.cpp +++ b/src/sdl/hardware.cpp @@ -190,10 +190,10 @@ void I_ClosestResolution (int *width, int *height, int bits) // Pass a negative value for the limit to use the value of vid_maxfps. // //========================================================================== - + EXTERN_CVAR(Int, vid_maxfps); EXTERN_CVAR(Bool, cl_capfps); - + #ifndef __APPLE__ Semaphore FPSLimitSemaphore; @@ -245,13 +245,13 @@ void I_SetFPSLimit(int limit) Printf("Failed to set FPS limitter timer\n"); DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); } -} -#else -// So Apple doesn't support POSIX timers and I can't find a good substitute short of -// having Objective-C Cocoa events or something like that. -void I_SetFPSLimit(int limit) -{ -} +} +#else +// So Apple doesn't support POSIX timers and I can't find a good substitute short of +// having Objective-C Cocoa events or something like that. +void I_SetFPSLimit(int limit) +{ +} #endif CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) diff --git a/src/sdl/hardware.h b/src/sdl/hardware.h index 04d02c9bf..6544f1498 100644 --- a/src/sdl/hardware.h +++ b/src/sdl/hardware.h @@ -53,7 +53,13 @@ typedef semaphore_t Semaphore; #include typedef sem_t Semaphore; #define SEMAPHORE_WAIT(sem) \ - while(sem_wait(&sem) != 0); + do { \ + while(sem_wait(&sem) != 0); \ + int semValue; \ + sem_getvalue(&sem, &semValue); \ + if(semValue < 1) \ + break; \ + } while(true); #define SEMAPHORE_SIGNAL(sem) \ sem_post(&sem); #define SEMAPHORE_INIT(sem, shared, value) \ diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index cba5c4cf7..2f11b8bbd 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -81,6 +81,7 @@ extern bool GUICapture; EXTERN_CVAR (Float, Gamma) EXTERN_CVAR (Int, vid_maxfps) +EXTERN_CVAR (Bool, cl_capfps) // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -374,12 +375,12 @@ void SDLFB::Update () } DrawRateStuff (); - + #ifndef __APPLE__ - if(vid_maxfps) + if(vid_maxfps && !cl_capfps) { SEMAPHORE_WAIT(FPSLimitSemaphore) - } + } #endif Buffer = NULL; From d833a6015db1a0a3c09c106e5ee1cb2a25310c16 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 22 Oct 2012 23:47:09 +0000 Subject: [PATCH 007/387] - Fixed some compiler warnings. SVN r3901 (trunk) --- src/g_shared/shared_sbar.cpp | 14 +++++++------- src/resourcefiles/file_wad.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 4ca4a519c..5c0ba7ae1 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -240,7 +240,7 @@ DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres) void DBaseStatusBar::Destroy () { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; while (msg) @@ -342,7 +342,7 @@ void DBaseStatusBar::MultiplayerChanged () void DBaseStatusBar::Tick () { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *msg = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -424,7 +424,7 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id, int layer) DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -451,7 +451,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; DHUDMessage **prev = &Messages[i]; @@ -484,7 +484,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) void DBaseStatusBar::DetachAllMessages () { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *probe = Messages[i]; @@ -1627,7 +1627,7 @@ void DBaseStatusBar::Serialize (FArchive &arc) } else { - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { arc << Messages[i]; } @@ -1639,7 +1639,7 @@ void DBaseStatusBar::ScreenSizeChanged () st_scale.Callback (); SB_state = screen->GetPageCount (); - for (int i = 0; i < countof(Messages); ++i) + for (unsigned int i = 0; i < countof(Messages); ++i) { DHUDMessage *message = Messages[i]; while (message != NULL) diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index 1ea7b39ce..ea9ea77fd 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -354,7 +354,7 @@ bool FWadFile::Open(bool quiet) { uppercopy (Lumps[i].Name, fileinfo[i].Name); Lumps[i].Name[8] = 0; - Lumps[i].Compressed = Lumps[i].Name[0] & 0x80; + Lumps[i].Compressed = (Lumps[i].Name[0] & 0x80) == 0x80; Lumps[i].Name[0] &= ~0x80; Lumps[i].Owner = this; From d393434d567cc27425c904e3239f330447baf2c6 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 24 Oct 2012 23:49:34 +0000 Subject: [PATCH 008/387] - Fixed: Broke UDMF in PK3 loader. SVN r3905 (trunk) --- src/p_setup.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 075c934dc..d3c43723f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -417,15 +417,12 @@ MapData *P_OpenMapData(const char * mapname) if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) { map->isText = true; + map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetLump(i)->NewReader(); + strncpy(map->MapLumps[ML_TEXTMAP].Name, lumpname, 8); for(int i = 2;; i++) { lumpname = map->resource->GetLump(i)->Name; - long v = strlen(lumpname); - if (v < 8) - { - I_Error("Invalid map definition for %s", mapname); - } - else if (!strnicmp(lumpname, "ZNODES",8)) + if (!strnicmp(lumpname, "ZNODES",8)) { index = ML_GLZNODES; } From bfae51ed2ebf1335a1ef21c994589deec9468165 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 1 Nov 2012 02:42:14 +0000 Subject: [PATCH 009/387] - Added Gez's BFG edition patch. SVN r3926 (trunk) --- src/d_iwad.cpp | 1 + src/g_mapinfo.cpp | 4 + src/w_wad.cpp | 65 ++++++++++++++++ src/w_wad.h | 3 +- wadsrc/static/iwadinfo.txt | 33 ++++++++ wadsrc/static/language.enu | 33 ++++++++ wadsrc/static/mapinfo/doom2.txt | 117 +++++++++++++++++++++++++++++ wadsrc/static/mapinfo/doom2bfg.txt | 67 +++++++++++++++++ 8 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 wadsrc/static/mapinfo/doom2bfg.txt diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 0bad0c3ed..e7d5c30ca 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -437,6 +437,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, static const char *const steam_dirs[] = { "doom 2/base", + "DOOM 3 BFG Edition/base/wads", "final doom/base", "heretic shadow of the serpent riders/base", "hexen/base", diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 7836c4377..9df7b39eb 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -305,6 +305,10 @@ FString level_info_t::LookupLevelName() { mysnprintf (checkstring, countof(checkstring), "%d: ", atoi(mapname + 3)); } + else if (mapname[0] == 'L' && mapname[1] == 'E' && mapname[2] == 'V' && mapname[3] == 'E' && mapname[4] == 'L') + { + mysnprintf (checkstring, countof(checkstring), "%d: ", atoi(mapname + 5)); + } thename = strstr (lookedup, checkstring); if (thename == NULL) { diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 84da1c474..fab0f4c18 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -55,6 +55,7 @@ #include "gi.h" #include "doomerrors.h" #include "resourcefiles/resourcefile.h" +#include "md5.h" // MACROS ------------------------------------------------------------------ @@ -180,6 +181,7 @@ void FWadCollection::InitMultipleFiles (TArray &filenames) { I_FatalError ("W_InitMultipleFiles: no files found"); } + RenameNerve(); RenameSprites(); // [RH] Set up hash table @@ -810,6 +812,69 @@ void FWadCollection::RenameSprites () } } +//========================================================================== +// +// RenameNerve +// +// Renames map headers and map name pictures in nerve.wad so as to load it +// alongside Doom II and offer both episodes without causing conflicts. +// MD5 checksum for NERVE.WAD: 967d5ae23daf45196212ae1b605da3b0 +// +//========================================================================== +void FWadCollection::RenameNerve () +{ + if (gameinfo.gametype != GAME_Doom) + return; + + bool found = false; + BYTE cksum[16]; + BYTE nerve[16] = { 0x96, 0x7d, 0x5a, 0xe2, 0x3d, 0xaf, 0x45, 0x19, + 0x62, 0x12, 0xae, 0x1b, 0x60, 0x5d, 0xa3, 0xb0 }; + size_t nervesize = 3819855; // NERVE.WAD's file size + int w = IWAD_FILENUM; + while (++w < GetNumWads()) + { + FileReader *fr = GetFileReader(w); + if (fr->GetLength() != nervesize) + { + // Skip MD5 computation when there is a + // cheaper way to know this is not the file + continue; + } + fr->Seek(0, SEEK_SET); + MD5Context md5; + md5.Update(fr, fr->GetLength()); + md5.Final(cksum); + if (memcmp(nerve, cksum, 16) == 0) + { + found = true; + break; + } + } + + if (!found) + return; + + for (DWORD i = 0; i < LumpInfo.Size(); i++) + { + // Only rename the maps from NERVE.WAD + if (LumpInfo[i].wadnum == w) + { + if (LumpInfo[i].lump->dwName == MAKE_ID('C', 'W', 'I', 'L')) + { + LumpInfo[i].lump->Name[0] = 'N'; + } + else if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'A', 'P', '0')) + { + LumpInfo[i].lump->Name[6] = LumpInfo[i].lump->Name[4]; + LumpInfo[i].lump->Name[5] = '0'; + LumpInfo[i].lump->Name[4] = 'L'; + LumpInfo[i].lump->dwName = MAKE_ID('L', 'E', 'V', 'E'); + } + } + } +} + //========================================================================== // // W_FindLump diff --git a/src/w_wad.h b/src/w_wad.h index 76d94959d..e0b21b66c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -227,7 +227,8 @@ protected: void InitHashChains (); // [RH] Set up the lumpinfo hashing private: - void RenameSprites (); + void RenameSprites(); + void RenameNerve(); void DeleteAll(); }; diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index c626dcbfa..e47951d31 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -220,6 +220,21 @@ IWad BannerColors = "32 54 43", "c6 dc d1" } +IWad +{ + Name = "DOOM 1: BFG Edition" + Autoname = "Doom1" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/ultdoom.txt" + Compatibility = "Shorttex" + MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", + "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", + "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", + "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" + BannerColors = "54 54 54", "a8 a8 a8" +} + IWad { Name = "The Ultimate DOOM" @@ -283,6 +298,19 @@ IWad BannerColors = "a8 00 00", "a8 a8 a8" } +IWad +{ + Name = "DOOM 2: BFG Edition" + Autoname = "Doom2BFG" + Game = "Doom" + Config = "Doom" + Mapinfo = "mapinfo/doom2bfg.txt" + Compatibility = "Shorttex" + MustContain = "MAP01", "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" + BannerColors = "a8 00 00", "a8 a8 a8" + Load = "nerve.wad" +} + // Doom 2 must be last to be checked becaude MAP01 is its only requirement IWad { @@ -300,10 +328,14 @@ IWad Names { + "bfgdoom2.wad" + "doom2bfg.wad" "doom2f.wad" "doom2.wad" "plutonia.wad" "tnt.wad" + "bfgdoom.wad" + "doombfg.wad" "doomu.wad" "doom.wad" "doom1.wad" @@ -315,6 +347,7 @@ Names "hexdemo.wad" "strife1.wad" "strife0.wad" + "strife.wad" "freedoom.wad" "freedoom1.wad" "freedoomu.wad" diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 7564ff85b..c719e9ba3 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -190,6 +190,19 @@ HUSTR_29 = "level 29: the living end"; HUSTR_30 = "level 30: icon of sin"; HUSTR_31 = "level 31: wolfenstein"; HUSTR_32 = "level 32: grosse"; +HUSTR_31B = "level 31: idkfa"; +HUSTR_32B = "level 32: keen"; +HUSTR_33 = "level 33: betray"; + +NHUSTR_1 = "level 1: the earth base"; +NHUSTR_2 = "level 2: the pain labs"; +NHUSTR_3 = "level 3: canyon of the dead"; +NHUSTR_4 = "level 4: hell mountain"; +NHUSTR_5 = "level 5: vivisection"; +NHUSTR_6 = "level 6: inferno of blood"; +NHUSTR_7 = "level 7: baron's banquet"; +NHUSTR_8 = "level 8: tomb of malevolence"; +NHUSTR_9 = "level 9: march of the demons"; PHUSTR_1 = "level 1: congo"; PHUSTR_2 = "level 2: well of souls"; @@ -540,6 +553,26 @@ T6TEXT = "As you step off the transport, you hear\n" "the stomp of a cyberdemon's iron shoe."; +NERVETEXT = + "TROUBLE WAS BREWING AGAIN IN YOUR FAVORITE\n" + "VACATION SPOT... HELL. SOME CYBERDEMON\n" + "PUNK THOUGHT HE COULD TURN HELL INTO A\n" + "PERSONAL AMUSEMENT PARK, AND MAKE EARTH\n" + "THE TICKET BOOTH.\n" + "\n" + "WELL THAT HALF-ROBOT FREAK SHOW DIDN'T\n" + "KNOW WHO WAS COMING TO THE FAIR. THERE'S\n" + "NOTHING LIKE A SHOOTING GALLERY FULL OF\n" + "HELLSPAWN TO GET THE BLOOD PUMPING...\n" + "\n" + "NOW THE WALLS OF THE DEMON'S LABYRINTH\n" + "ECHO WITH THE SOUND OF HIS METALLIC LIMBS\n" + "HITTING THE FLOOR. HIS DEATH MOAN GURGLES\n" + "OUT THROUGH THE MESS YOU LEFT OF HIS FACE.\n" + "\n" + "THIS RIDE IS CLOSED.\n"; + + // Cast list (must appear in this order) CC_ZOMBIE = "ZOMBIEMAN"; CC_SHOTGUN = "SHOTGUN GUY"; diff --git a/wadsrc/static/mapinfo/doom2.txt b/wadsrc/static/mapinfo/doom2.txt index 6dc9815b1..5d0d40517 100644 --- a/wadsrc/static/mapinfo/doom2.txt +++ b/wadsrc/static/mapinfo/doom2.txt @@ -8,6 +8,13 @@ episode map01 key = "h" } +episode level01 +{ + name = "No Rest for the Living" + key = "n" + optional +} + defaultmap { sucktime = 1 @@ -424,3 +431,113 @@ cluster 10 entertext = lookup, "C6TEXT" } +// No Rest for the Living + +map LEVEL01 lookup "NHUSTR_1" +{ + titlepatch = "NWILV00" + next = "LEVEL02" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 75 + music = "$MUSIC_MESSAG" +} + +map LEVEL02 lookup "NHUSTR_2" +{ + titlepatch = "NWILV01" + next = "LEVEL03" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 105 + music = "$MUSIC_DDTBLU" +} + +map LEVEL03 lookup "NHUSTR_3" +{ + titlepatch = "NWILV02" + next = "LEVEL04" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 120 + music = "$MUSIC_DOOM" +} + +map LEVEL04 lookup "NHUSTR_4" +{ + titlepatch = "NWILV03" + next = "LEVEL05" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 105 + music = "$MUSIC_SHAWN" +} + +map LEVEL05 lookup "NHUSTR_5" +{ + titlepatch = "NWILV04" + next = "LEVEL06" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 210 + music = "$MUSIC_IN_CIT" +} + +map LEVEL06 lookup "NHUSTR_6" +{ + titlepatch = "NWILV05" + next = "LEVEL07" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 105 + sucktime = 1 + music = "$MUSIC_THE_DA" +} + +map LEVEL07 lookup "NHUSTR_7" +{ + titlepatch = "NWILV06" + next = "LEVEL08" + secretnext = "LEVEL09" + sky1 = "SKY1" + cluster = 11 + par = 165 + map07special + music = "$MUSIC_IN_CIT" +} + +map LEVEL08 lookup "NHUSTR_8" +{ + titlepatch = "NWILV07" + next = "EndGameC" + secretnext = "EndGameC" + sky1 = "SKY1" + cluster = 11 + par = 105 + music = "$MUSIC_SHAWN" +} + +map LEVEL09 lookup "NHUSTR_9" +{ + titlepatch = "NWILV08" + next = "LEVEL05" + secretnext = "LEVEL05" + sky1 = "SKY1" + cluster = 11 + par = 135 + music = "$MUSIC_DDTBLU" +} + +cluster 11 +{ + flat = "RROCK19" + music = "$MUSIC_READ_M" + exittext = lookup, "NERVETEXT" +} + diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt new file mode 100644 index 000000000..cc82c4e19 --- /dev/null +++ b/wadsrc/static/mapinfo/doom2bfg.txt @@ -0,0 +1,67 @@ +// MAPINFO for Doom 2: BFG Edition +include "mapinfo/doom2.txt" + +gameinfo +{ + titlepage = "INTERPIC" +} + +clearepisodes +episode map01 +{ + name = "Hell On Earth" + picname = "M_EPI1" + key = "h" +} + +episode level01 +{ + name = "No Rest for the Living" + picname = "M_EPI2" + key = "n" + optional +} + +map MAP02 lookup "HUSTR_2" +{ + titlepatch = "CWILV01" + next = "MAP03" + secretnext = "MAP33" + sky1 = "SKY1" + cluster = 5 + par = 90 + music = "$MUSIC_STALKS" +} + +map MAP33 lookup "HUSTR_33" +{ + titlepatch = "CWILV32" + next = "MAP03" + secretnext = "MAP03" + sky1 = "SKY3" + cluster = 5 + music = "$MUSIC_READ_M" +} + +// Wolfenstein 3D censorship +map MAP31 lookup "HUSTR_31B" +{ + titlepatch = "CWILV30" + next = "MAP16" + secretnext = "MAP32" + sky1 = "SKY3" + cluster = 9 + par = 120 + music = "$MUSIC_EVIL" +} + +map MAP32 lookup "HUSTR_32B" +{ + titlepatch = "CWILV31" + next = "MAP16" + secretnext = "MAP16" + sky1 = "SKY3" + cluster = 10 + par = 30 + music = "$MUSIC_ULTIMA" +} From 4f71176ed6fb343d02e841b8e7f9efd721b53897 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 1 Nov 2012 03:01:04 +0000 Subject: [PATCH 010/387] - Support loading either fluidsynth.dll or libfluidsynth.dll on Windows. SVN r3927 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 7914aa256..62225cb46 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -50,9 +50,11 @@ #ifdef _WIN32 #ifndef _M_X64 -#define FLUIDSYNTHLIB "fluidsynth.dll" +#define FLUIDSYNTHLIB1 "fluidsynth.dll" +#define FLUIDSYNTHLIB2 "libfluidsynth.dll" #else -#define FLUIDSYNTHLIB "fluidsynth64.dll" +#define FLUIDSYNTHLIB1 "fluidsynth64.dll" +#define FLUIDSYNTHLIB2 "libfluidsynth64.dll" #endif #else #include @@ -665,16 +667,21 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() { (void **)&fluid_synth_sysex, "fluid_synth_sysex" }, }; int fail = 0; + const char *libname; #ifdef _WIN32 - FluidSynthDLL = LoadLibrary(FLUIDSYNTHLIB); + FluidSynthDLL = LoadLibrary((libname = FLUIDSYNTHLIB1)); if (FluidSynthDLL == NULL) { - Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB "\n"); - return false; + FluidSynthDLL = LoadLibrary((libname = FLUIDSYNTHLIB2)); + if (FluidSynthDLL == NULL) + { + Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n"); + return false; + } } #else - FluidSynthSO = dlopen(FLUIDSYNTHLIB, RTLD_LAZY); + FluidSynthSO = dlopen((libname = FLUIDSYNTHLIB), RTLD_LAZY); if (FluidSynthSO == NULL) { Printf(TEXTCOLOR_RED"Could not load " FLUIDSYNTHLIB ": %s\n", dlerror()); @@ -691,7 +698,7 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() #endif if (proc == NULL) { - Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, FLUIDSYNTHLIB); + Printf(TEXTCOLOR_RED"Failed to find %s in %s\n", imports[i].FuncName, libname); fail++; } *imports[i].FuncPointer = (void *)proc; From 1b5bff96033e3ad351c83e3247f3fc0844f56a3b Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 1 Nov 2012 18:23:39 +0000 Subject: [PATCH 011/387] - Fixed: Solaris compile. SVN r3928 (trunk) --- src/p_setup.h | 2 +- src/sdl/crashcatcher.c | 1 + src/sdl/i_system.cpp | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_setup.h b/src/p_setup.h index dc171e071..b1590e714 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -29,7 +29,7 @@ struct MapData { - struct + struct MapLump { char Name[8]; FileReader *Reader; diff --git a/src/sdl/crashcatcher.c b/src/sdl/crashcatcher.c index 1dfa43af8..37511f63a 100644 --- a/src/sdl/crashcatcher.c +++ b/src/sdl/crashcatcher.c @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef __linux__ #include diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index df15ce774..afabd0d21 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -270,7 +270,14 @@ void I_HandleAlarm (int sig) void I_SelectTimer() { SEMAPHORE_INIT(timerWait, 0, 0) +#ifndef __sun signal(SIGALRM, I_HandleAlarm); +#else + struct sigaction alrmaction; + sigaction(SIGALRM, NULL, &alrmaction); + alrmaction.sa_handler = I_HandleAlarm; + sigaction(SIGALRM, &alrmaction, NULL); +#endif struct itimerval itv; itv.it_interval.tv_sec = itv.it_value.tv_sec = 0; From 3b0ad55285284b80d794b0ec01c1de4839d54b9c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 2 Nov 2012 03:25:50 +0000 Subject: [PATCH 012/387] - Since our OPL chips are emulated, we can give them a feature that real OPL2 chips lacked: Full stereo panning for the MIDI player. (The raw OPL players are unaffected.) To get the mono output back, you can set opl_stereo to false. - Changed SoftSynthMIDIDevice::OpenStream() to allocate the same number of samples for stereo and mono streams. SVN r3929 (trunk) --- src/oplsynth/fmopl.cpp | 63 ++++++++++++++++++++++-- src/oplsynth/fmopl.h | 2 + src/oplsynth/mlopl_io.cpp | 13 ++++- src/oplsynth/music_opl_mididevice.cpp | 7 ++- src/oplsynth/muslib.h | 4 +- src/oplsynth/opl_mus_player.cpp | 15 +++--- src/oplsynth/opl_mus_player.h | 1 + src/sound/music_softsynth_mididevice.cpp | 7 ++- wadsrc/static/menudef.txt | 1 + 9 files changed, 95 insertions(+), 18 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 40efe3164..9fdc36ccb 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -115,6 +115,8 @@ Revision History: #define INLINE __inline #endif +#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ +#define HALF_PI (PI/2) #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */ @@ -246,6 +248,8 @@ typedef struct{ UINT32 fc; /* Freq. Increment base */ UINT32 ksl_base; /* KeyScaleLevel Base step */ UINT8 kcode; /* key code (for key scaling) */ + float LeftVol; /* volumes for stereo panning */ + float RightVol; } OPL_CH; /* OPL state */ @@ -297,6 +301,7 @@ typedef struct fm_opl_f { int rate; /* sampling rate (Hz) */ double freqbase; /* frequency base */ double TimerBase; /* Timer base time (==sampling time)*/ + bool IsStereo; /* Write stereo output */ } FM_OPL; @@ -876,7 +881,7 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign #define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) /* calculate output */ -INLINE void OPL_CALC_CH( OPL_CH *CH, float *buffer ) +INLINE float OPL_CALC_CH( OPL_CH *CH ) { OPL_SLOT *SLOT; unsigned int env; @@ -905,8 +910,9 @@ INLINE void OPL_CALC_CH( OPL_CH *CH, float *buffer ) { output += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); /* [RH] Convert to floating point. */ - *buffer += float(output) / 10240; + return float(output) / 10240; } + return 0; } /* @@ -1282,6 +1288,13 @@ static void OPL_initalize(FM_OPL *OPL) OPL->eg_timer_overflow = UINT32(( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + // [RH] Support full MIDI panning. (But default to mono and center panning.) + OPL->IsStereo = false; + for (int i = 0; i < 9; ++i) + { + OPL->P_CH[i].LeftVol = (float)CENTER_PANNING_POWER; + OPL->P_CH[i].RightVol = (float)CENTER_PANNING_POWER; + } } INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) @@ -1897,6 +1910,28 @@ void YM3812SetUpdateHandler(void *chip,OPL_UPDATEHANDLER UpdateHandler,int param OPLSetUpdateHandler(YM3812, UpdateHandler, param); } +/* [RH] Full support for MIDI panning */ +void YM3812SetStereo(void *chip, bool stereo) +{ + if (chip != NULL) + { + FM_OPL *YM3812 = (FM_OPL *)chip; + YM3812->IsStereo = stereo; + } +} + +void YM3812SetPanning(void *chip, int c, int pan) +{ + if (chip != NULL) + { + FM_OPL *YM3812 = (FM_OPL *)chip; + // This is the MIDI-recommended pan formula. 0 and 1 are + // both hard left so that 64 can be perfectly center. + double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; + YM3812->P_CH[c].LeftVol = (float)cos(HALF_PI * level); + YM3812->P_CH[c].RightVol = (float)sin(HALF_PI * level); + } +} /* ** Generate samples for one of the YM3812's @@ -1969,7 +2004,16 @@ static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length) advance_lfo(OPL); output = 0; - OPL_CALC_CH(CH, buffer + i); + float sample = OPL_CALC_CH(CH); + if (!OPL->IsStereo) + { + buffer[i] += sample; + } + else + { + buffer[i*2] += sample * CH->LeftVol; + buffer[i*2+1] += sample * CH->RightVol; + } advance(OPL, voice, voice); } @@ -1987,7 +2031,18 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length) output = 0; OPL_CALC_RH(&OPL->P_CH[0], OPL->noise_rng & 1); /* [RH] Convert to floating point. */ - buffer[i] += float(output) / 10240; + float sample = float(output) / 10240; + if (!OPL->IsStereo) + { + buffer[i] += sample; + } + else + { + // [RH] Always use center panning for rhythm. + // The MIDI player doesn't use the rhythm section anyway. + buffer[i*2] += sample * CENTER_PANNING_POWER; + buffer[i*2+1] += sample * CENTER_PANNING_POWER; + } advance(OPL, 6, 8); advance_noise(OPL); diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h index 2b3eefb6e..0064f642e 100644 --- a/src/oplsynth/fmopl.h +++ b/src/oplsynth/fmopl.h @@ -32,6 +32,8 @@ int YM3812Write(void *chip, int a, int v); unsigned char YM3812Read(void *chip, int a); int YM3812TimerOver(void *chip, int c); void YM3812UpdateOne(void *chip, float *buffer, int length); +void YM3812SetStereo(void *chip, bool stereo); +void YM3812SetPanning(void *chip, int c, int pan); void YM3812SetTimerHandler(void *chip, OPL_TIMERHANDLER TimerHandler, int channelOffset); void YM3812SetIRQHandler(void *chip, OPL_IRQHANDLER IRQHandler, int param); diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 614c11f59..2c5bbc010 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -252,6 +252,12 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) else bits = 0x30; // both OPLwriteValue(0xC0, channel, instr->feedback | bits); + + // Set real panning if we're using emulated chips. + if (chips[0] != NULL) + { + YM3812SetPanning(chips[channel/9], channel%9, pan+64); + } } } @@ -298,13 +304,14 @@ void OPLio::OPLshutup(void) /* * Initialize hardware upon startup */ -int OPLio::OPLinit(uint numchips) +int OPLio::OPLinit(uint numchips, bool stereo) { assert(numchips >= 1 && numchips <= 2); chips[0] = YM3812Init (3579545, int(OPL_SAMPLE_RATE)); chips[1] = NULL; if (chips[0] != NULL) { + YM3812SetStereo(chips[0], stereo); if (numchips > 1) { chips[1] = YM3812Init (3579545, int(OPL_SAMPLE_RATE)); @@ -314,6 +321,10 @@ int OPLio::OPLinit(uint numchips) chips[0] = NULL; return -1; } + else + { + YM3812SetStereo(chips[1], stereo); + } } } else diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index ade5b5c12..d36bacb54 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -64,6 +64,8 @@ // PUBLIC DATA DEFINITIONS ------------------------------------------------- +CVAR(Bool, opl_stereo, true, CVAR_ARCHIVE); + // CODE -------------------------------------------------------------------- //========================================================================== @@ -74,6 +76,7 @@ OPLMIDIDevice::OPLMIDIDevice() { + IsStereo = opl_stereo; FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); SampleRate = (int)OPL_SAMPLE_RATE; @@ -89,11 +92,11 @@ OPLMIDIDevice::OPLMIDIDevice() int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { - if (io == NULL || io->OPLinit(TwoChips + 1)) + if (io == NULL || io->OPLinit(TwoChips + 1, IsStereo)) { return 1; } - int ret = OpenStream(14, SoundStream::Mono, callback, userdata); + int ret = OpenStream(14, IsStereo ? 0 : SoundStream::Mono, callback, userdata); if (ret == 0) { OPLstopMusic(); diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 7cc533ea5..189649551 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -177,7 +177,7 @@ struct OPLio { void OPLshutup(void); void OPLwriteInitState(); - virtual int OPLinit(uint numchips); + virtual int OPLinit(uint numchips, bool stereo=false); virtual void OPLdeinit(void); virtual void OPLwriteReg(int which, uint reg, uchar data); virtual void SetClockRate(double samples_per_tick); @@ -192,7 +192,7 @@ struct DiskWriterIO : public OPLio DiskWriterIO(const char *filename); ~DiskWriterIO(); - int OPLinit(uint numchips); + int OPLinit(uint numchips, bool notused=false); void OPLdeinit(); void OPLwriteReg(int which, uint reg, uchar data); void SetClockRate(double samples_per_tick); diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index 31eef55fd..6df36e707 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -25,6 +25,7 @@ OPLmusicBlock::OPLmusicBlock() LastOffset = 0; TwoChips = !opl_onechip; Looping = false; + IsStereo = false; io = NULL; io = new OPLio; } @@ -39,7 +40,7 @@ void OPLmusicBlock::ResetChips () TwoChips = !opl_onechip; ChipAccess.Enter(); io->OPLdeinit (); - io->OPLinit (TwoChips + 1); + io->OPLinit (TwoChips + 1, IsStereo); ChipAccess.Leave(); } @@ -222,13 +223,11 @@ void OPLmusicFile::Restart () bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { - float *samples = (float *)buff; - float *samples1; - int numsamples = numbytes / sizeof(float); + float *samples1 = (float *)buff; + int numsamples = numbytes / (sizeof(float) << int(IsStereo)); bool prevEnded = false; bool res = true; - samples1 = samples; memset(buff, 0, numbytes); ChipAccess.Enter(); @@ -242,12 +241,12 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { YM3812UpdateOne (io->chips[0], samples1, samplesleft); YM3812UpdateOne (io->chips[1], samples1, samplesleft); - OffsetSamples(samples1, samplesleft); + OffsetSamples(samples1, samplesleft << int(IsStereo)); assert(NextTickIn == ticky); NextTickIn -= samplesleft; assert (NextTickIn >= 0); numsamples -= samplesleft; - samples1 += samplesleft; + samples1 += samplesleft << int(IsStereo); } if (NextTickIn < 1) @@ -262,7 +261,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { YM3812UpdateOne (io->chips[0], samples1, numsamples); YM3812UpdateOne (io->chips[1], samples1, numsamples); - OffsetSamples(samples1, numsamples); + OffsetSamples(samples1, numsamples << int(IsStereo)); } res = false; break; diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index d1357e0e0..57744ebfc 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -21,6 +21,7 @@ protected: bool TwoChips; bool Looping; double LastOffset; + bool IsStereo; FCriticalSection ChipAccess; }; diff --git a/src/sound/music_softsynth_mididevice.cpp b/src/sound/music_softsynth_mididevice.cpp index 5cb21687a..56d77e735 100644 --- a/src/sound/music_softsynth_mididevice.cpp +++ b/src/sound/music_softsynth_mididevice.cpp @@ -96,7 +96,12 @@ SoftSynthMIDIDevice::~SoftSynthMIDIDevice() 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); + int chunksize = (SampleRate / chunks) * 4; + if (!(flags & SoundStream::Mono)) + { + chunksize *= 2; + } + Stream = GSnd->CreateStream(FillStream, chunksize, SoundStream::Float | flags, SampleRate, this); if (Stream == NULL) { return 2; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 38ac1bd74..c7dd62233 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1409,6 +1409,7 @@ OptionMenu AdvSoundOptions StaticText " " StaticText "OPL Synthesis", 1 Option "Only emulate one OPL chip", "opl_onechip", "OnOff" + Option "Support MIDI stero panning", "opl_stereo", "OnOff" StaticText " " StaticText "GUS Emulation", 1 Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 From b3f68527cf1a1a6f3f5578cb905f09a3d3567cd2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 2 Nov 2012 22:25:05 +0000 Subject: [PATCH 013/387] - It seems I had an unsaved file when I made the last commit, which is strange since I thought I had just done a build before committing. SVN r3930 (trunk) --- src/oplsynth/music_opldumper_mididevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 51e80a801..55c1fdc0c 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -139,7 +139,7 @@ DiskWriterIO::~DiskWriterIO() // //========================================================================== -int DiskWriterIO::OPLinit(uint numchips) +int DiskWriterIO::OPLinit(uint numchips, bool dontcare) { // If the file extension is unknown or not present, the default format // is RAW. Otherwise, you can use DRO. From aab12c6b0ce00b4b0fb0be585b1bc9c134f1d8b6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 00:12:38 +0000 Subject: [PATCH 014/387] - Fixed: Crash when using an inventory bar with the Strife style but no INVCURS graphic. SVN r3931 (trunk) --- src/g_shared/sbarinfo_commands.cpp | 36 +++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 3c8f0e11e..348f97e08 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1960,11 +1960,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { - int spacing = 0; - if(!vertical) - spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; - else - spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + int spacing = GetCounterSpacing(statusBar); int bgalpha = block->Alpha(); if(translucent) @@ -2107,16 +2103,36 @@ class CommandDrawInventoryBar : public SBarInfoCommand } sc.MustGetToken(';'); } + int GetCounterSpacing(const DSBarInfo *statusBar) const + { + FTexture *box = (style != STYLE_Strife) + ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX] + : statusBar->Images[statusBar->invBarOffset + imgCURSOR]; + if (box == NULL) + { // Don't crash without a graphic. + return 32; + } + else + { + int spacing; + if (!vertical) + { + spacing = box->GetScaledWidth(); + } + else + { + spacing = box->GetScaledHeight(); + } + return spacing + ((style != STYLE_Strife) ? 1 : -1); + } + } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { // Make the counters if need be. if(counters == NULL) { - int spacing = 0; - if(!vertical) - spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; - else - spacing = (style != STYLE_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + int spacing = GetCounterSpacing(statusBar); + counters = new CommandDrawNumber*[size]; for(unsigned int i = 0;i < size;i++) From d0c3c924d4cc6428ccbad6606cc47dc7be7ebaf7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 00:38:58 +0000 Subject: [PATCH 015/387] - Initialize the nerve checksum at compile-time instead of run-time. - Fixed: Crash in FWadCollection::RenameNerve() for files without a FileReader object. SVN r3932 (trunk) --- src/w_wad.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index fab0f4c18..b29d02072 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -828,13 +828,17 @@ void FWadCollection::RenameNerve () bool found = false; BYTE cksum[16]; - BYTE nerve[16] = { 0x96, 0x7d, 0x5a, 0xe2, 0x3d, 0xaf, 0x45, 0x19, + static const BYTE nerve[16] = { 0x96, 0x7d, 0x5a, 0xe2, 0x3d, 0xaf, 0x45, 0x19, 0x62, 0x12, 0xae, 0x1b, 0x60, 0x5d, 0xa3, 0xb0 }; size_t nervesize = 3819855; // NERVE.WAD's file size int w = IWAD_FILENUM; while (++w < GetNumWads()) { FileReader *fr = GetFileReader(w); + if (fr == NULL) + { + continue; + } if (fr->GetLength() != nervesize) { // Skip MD5 computation when there is a @@ -855,22 +859,20 @@ void FWadCollection::RenameNerve () if (!found) return; - for (DWORD i = 0; i < LumpInfo.Size(); i++) + for (int i = GetFirstLump(w); i <= GetLastLump(w); i++) { // Only rename the maps from NERVE.WAD - if (LumpInfo[i].wadnum == w) + assert(LumpInfo[i].wadnum == w); + if (LumpInfo[i].lump->dwName == MAKE_ID('C', 'W', 'I', 'L')) { - if (LumpInfo[i].lump->dwName == MAKE_ID('C', 'W', 'I', 'L')) - { - LumpInfo[i].lump->Name[0] = 'N'; - } - else if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'A', 'P', '0')) - { - LumpInfo[i].lump->Name[6] = LumpInfo[i].lump->Name[4]; - LumpInfo[i].lump->Name[5] = '0'; - LumpInfo[i].lump->Name[4] = 'L'; - LumpInfo[i].lump->dwName = MAKE_ID('L', 'E', 'V', 'E'); - } + LumpInfo[i].lump->Name[0] = 'N'; + } + else if (LumpInfo[i].lump->dwName == MAKE_ID('M', 'A', 'P', '0')) + { + LumpInfo[i].lump->Name[6] = LumpInfo[i].lump->Name[4]; + LumpInfo[i].lump->Name[5] = '0'; + LumpInfo[i].lump->Name[4] = 'L'; + LumpInfo[i].lump->dwName = MAKE_ID('L', 'E', 'V', 'E'); } } } From 0f0dcc08a28768134a7747f59532602f0290ce90 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 02:02:42 +0000 Subject: [PATCH 016/387] - Added a new UDMF sidedef flag: lightfog. SVN r3933 (trunk) --- specs/udmf_zdoom.txt | 3 +++ src/namedef.h | 1 + src/p_sectors.cpp | 8 ++++---- src/p_udmf.cpp | 4 ++++ src/r_defs.h | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 9d7bb3caf..bdd70322e 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -141,6 +141,9 @@ Note: All fields default to false unless mentioned otherwise. light = ; // This side's light level. Default is 0. lightabsolute = ; // true = 'light' is an absolute value. Default is // relative to the owning sector's light level. + lightfog = ; // true = This side's relative lighting is used even in + // foggy sectors. Default is to disable relative + // lighting in foggy sectors. nofakecontrast = ; // Disables use of fake contrast on this sidedef. smoothlighting = ; // Use smooth fake contrast. clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. diff --git a/src/namedef.h b/src/namedef.h index 50fa9f292..34f9b7235 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -448,6 +448,7 @@ xx(scalex_bottom) xx(scaley_bottom) xx(light) xx(lightabsolute) +xx(lightfog) xx(nofakecontrast) xx(smoothlighting) xx(blockprojectiles) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 330344679..d90466fec 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -996,10 +996,10 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool noabsolute, int *pfak baselight += rel; } } - if (!(Flags & WALLF_ABSLIGHTING)) - { - baselight += this->Light; - } + } + if (!(Flags & WALLF_ABSLIGHTING) && (!foggy || (Flags & WALLF_LIGHT_FOG))) + { + baselight += this->Light; } return baselight; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 2bc3e0bea..5abe40908 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1053,6 +1053,10 @@ public: Flag(sd->Flags, WALLF_ABSLIGHTING, key); continue; + case NAME_lightfog: + Flag(sd->Flags, WALLF_LIGHT_FOG, key); + continue; + case NAME_nofakecontrast: Flag(sd->Flags, WALLF_NOFAKECONTRAST, key); continue; diff --git a/src/r_defs.h b/src/r_defs.h index 5f8272b3d..87c9e9e4f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -744,6 +744,7 @@ enum WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. + WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. }; struct side_t From ecf700b47b1236e1bef3c68990b817b5910f32ca Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 02:21:55 +0000 Subject: [PATCH 017/387] - Fixed: Corpse queue accounting went awry once things started being kicked out of it. SVN r3934 (trunk) --- src/g_shared/a_action.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index c283b5720..1149bc2c3 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -350,7 +350,6 @@ CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO) while (first != NULL && first->Count > (DWORD)self) { DCorpsePointer *next = iterator.Next (); - next->Count = first->Count; first->Destroy (); first = next; } @@ -373,9 +372,8 @@ DCorpsePointer::DCorpsePointer (AActor *ptr) if (first->Count >= (DWORD)sv_corpsequeuesize) { DCorpsePointer *next = iterator.Next (); - next->Count = first->Count; first->Destroy (); - return; + first = next; } } ++first->Count; From f8c1d5d52050c8879ce171bdd7bf681016db287a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 02:50:33 +0000 Subject: [PATCH 018/387] - Fixed: Masked mid textures should get their light level from the frontsector they reference, not from the sector they appear in. SVN r3935 (trunk) --- src/r_segs.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index bfeab506a..8c22b3e53 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2427,7 +2427,20 @@ void R_StoreWallRange (int start, int stop) } ds_p->light = rw_light; ds_p->lightstep = rw_lightstep; - ds_p->shade = wallshade; + + // Masked midtextures should get the light level from the sector they reference, + // not from the current subsector, which is what the current wallshade value + // comes from. We make an exeption for polyobjects, however, since their "home" + // sector should be whichever one they move into. + if (curline->sidedef->Flags & WALLF_POLYOBJ) + { + ds_p->shade = wallshade; + } + else + { + ds_p->shade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, curline->frontsector->lightlevel) + + r_actualextralight); + } if (ds_p->bFogBoundary || ds_p->maskedtexturecol != -1) { From 65267ec2507d86945ffb9be6aa527d1f20f8df37 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 03:07:46 +0000 Subject: [PATCH 019/387] - Use an FString to store demoname instead of a fixed-size array. Fixes crashes when passing really long names to -record. On the other hand, if it's long enough to overflow the old buffer, it'll probably fail to be created now because the name is too long for the OS functions. SVN r3936 (trunk) --- src/g_game.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 74189eadb..d96e37fcf 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -161,7 +161,7 @@ int consoleplayer; // player taking events int gametic; CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -char demoname[256]; +FString demoname; bool demorecording; bool demoplayback; bool netdemo; @@ -2271,7 +2271,7 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) void G_RecordDemo (const char* name) { usergame = false; - strcpy (demoname, name); + demoname = name; FixPathSeperator (demoname); DefaultExtension (demoname, ".lmp"); maxdemosize = 0x20000; @@ -2710,11 +2710,18 @@ bool G_CheckDemoStatus (void) formlen = demobuffer + 4; WriteLong (int(demo_p - demobuffer - 8), &formlen); - M_WriteFile (demoname, demobuffer, int(demo_p - demobuffer)); + bool saved = M_WriteFile (demoname, demobuffer, int(demo_p - demobuffer)); M_Free (demobuffer); demorecording = false; stoprecording = false; - Printf ("Demo %s recorded\n", demoname); + if (saved) + { + Printf ("Demo %s recorded\n", demoname.GetChars()); + } + else + { + Printf ("Demo %s could not be saved\n", demoname.GetChars()); + } } return false; From 0c7955b550f21ea78017cf6bd738ed7453154ec8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 03:19:10 +0000 Subject: [PATCH 020/387] - Remove deleted file a_macil.cpp from the project file. SVN r3937 (trunk) --- zdoom.vcproj | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/zdoom.vcproj b/zdoom.vcproj index 5ec9fc34f..817f53b70 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -6018,42 +6018,6 @@ /> - - - - - - - - - - - - - - From 971eca7d61ca6f3daf3599f2c609a6a30e4146d0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 3 Nov 2012 03:43:05 +0000 Subject: [PATCH 021/387] - Fixed: Player sounds that explicitly use dsempty will now properly silence the sound instead of looking for a more audible version. SVN r3938 (trunk) --- src/s_advsound.cpp | 13 ++++++++++--- src/s_sound.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index f4c343fac..5c49d69ea 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -519,6 +519,7 @@ int S_AddSoundLump (const char *logicalname, int lump) newsfx.bUsed = false; newsfx.bSingular = false; newsfx.bTentative = false; + newsfx.bPlayerSilent = false; newsfx.link = sfxinfo_t::NO_LINK; newsfx.Rolloff.RolloffType = ROLLOFF_Doom; newsfx.Rolloff.MinDistance = 0; @@ -1110,10 +1111,14 @@ static void S_AddSNDINFO (int lump) case SI_PlayerSound: { // $playersound FString pclass; - int gender, refid; + int gender, refid, sfxnum; S_ParsePlayerSoundCommon (sc, pclass, gender, refid); - S_AddPlayerSound (pclass, gender, refid, sc.String); + sfxnum = S_AddPlayerSound (pclass, gender, refid, sc.String); + if (0 == stricmp(sc.String, "dsempty")) + { + S_sfx[sfxnum].bPlayerSilent = true; + } } break; @@ -1665,7 +1670,9 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) // If we're not done parsing SNDINFO yet, assume that the target sound is valid if (PlayerClassesIsSorted && (sndnum == 0 || - ((S_sfx[sndnum].lumpnum == -1 || S_sfx[sndnum].lumpnum == sfx_empty) && S_sfx[sndnum].link == sfxinfo_t::NO_LINK))) + ((S_sfx[sndnum].lumpnum == -1 || S_sfx[sndnum].lumpnum == sfx_empty) && + S_sfx[sndnum].link == sfxinfo_t::NO_LINK && + !S_sfx[sndnum].bPlayerSilent))) { // This sound is unavailable. if (ingender != 0) { // Try "male" diff --git a/src/s_sound.h b/src/s_sound.h index 8b0e4ddea..2f4f68647 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -57,6 +57,7 @@ struct sfxinfo_t WORD bUsed:1; WORD bSingular:1; WORD bTentative:1; + WORD bPlayerSilent:1; // This player sound is intentionally silent. int LoopStart; // -1 means no specific loop defined From 92c7c06310d75dab72d0669cdcc0cfbaf123cfb8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 04:16:58 +0000 Subject: [PATCH 022/387] - Remove unused cruft from fmopl.cpp. SVN r3939 (trunk) --- src/oplsynth/fmopl.cpp | 77 ------------------------------------------ 1 file changed, 77 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 9fdc36ccb..9d8d82811 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -154,36 +154,6 @@ Revision History: #define EG_REL 1 #define EG_OFF 0 -/* save output as raw 16-bit sample */ - -/*#define SAVE_SAMPLE*/ - -#ifdef SAVE_SAMPLE -static FILE *sample[1]; - #if 1 /*save to MONO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = lt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #else /*save to STEREO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = lt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - pom = rt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #endif -#endif - -/* #define LOG_CYM_FILE */ -#ifdef LOG_CYM_FILE - FILE * cymfile = NULL; -#endif - - #define OPL_TYPE_WAVESEL 0x01 /* waveform select */ #define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ @@ -1215,18 +1185,11 @@ static int init_tables(void) /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ -#ifdef SAVE_SAMPLE - sample[0]=fopen("sampsum.pcm","wb"); -#endif - return 1; } static void OPLCloseTable( void ) { -#ifdef SAVE_SAMPLE - fclose(sample[0]); -#endif } @@ -1427,20 +1390,10 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) int slot; int block_fnum; - /* adjust bus to 8 bits */ r &= 0xff; v &= 0xff; -#ifdef LOG_CYM_FILE - if ((cymfile) && (r!=0) ) - { - fputc( (unsigned char)r, cymfile ); - fputc( (unsigned char)v, cymfile ); - } -#endif - - switch(r&0xe0) { case 0x00: /* 00-1f:control */ @@ -1637,16 +1590,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } } -#ifdef LOG_CYM_FILE -static void cymfile_callback (int n) -{ - if (cymfile) - { - fputc( (unsigned char)0, cymfile ); - } -} -#endif - /* lock/unlock for common table */ static int OPL_LockTable(void) { @@ -1662,14 +1605,6 @@ static int OPL_LockTable(void) return -1; } -#ifdef LOG_CYM_FILE - cymfile = fopen("3812_.cym","wb"); - if (cymfile) - timer_pulse ( TIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/ - else - logerror("Could not create file 3812_.cym\n"); -#endif - return 0; } @@ -1681,12 +1616,6 @@ static void OPL_UnLockTable(void) /* last time */ OPLCloseTable(); - -#ifdef LOG_CYM_FILE - fclose (cymfile); - cymfile = NULL; -#endif - } static void OPLResetChip(FM_OPL *OPL) @@ -1848,12 +1777,6 @@ static int OPLTimerOver(FM_OPL *OPL,int c) } -#define MAX_OPL_CHIPS 2 - - -static FM_OPL *OPL_YM3812[MAX_OPL_CHIPS]; /* array of pointers to the YM3812's */ -static int YM3812NumChips = 0; /* number of chips */ - void *YM3812Init(int clock, int rate) { /* emulator create */ From 1640f841e8ece6789d780f900a7de0f4a52a2d18 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 04:34:44 +0000 Subject: [PATCH 023/387] - More culling from fmopl.cpp; make the rate parameters constants since it sounds bad with anything but the real clock rate. SVN r3940 (trunk) --- src/oplsynth/fmopl.cpp | 111 ++++++-------------------------------- src/oplsynth/fmopl.h | 2 +- src/oplsynth/mlopl_io.cpp | 4 +- 3 files changed, 18 insertions(+), 99 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 9d8d82811..9578aa4e1 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -155,16 +155,10 @@ Revision History: #define EG_OFF 0 -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ - -/* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - +#define OPL_CLOCK 3579545 // master clock (Hz) +#define OPL_RATE 49716 // sampling rate (Hz) +#define OPL_TIMERBASE (OPL_CLOCK / 72.0) // Timer base time (==sampling time) +#define OPL_FREQBASE (OPL_TIMERBASE / OPL_RATE) // frequency base /* Saving is necessary for member of the 'R' mark for suspend/resume */ @@ -261,16 +255,11 @@ typedef struct fm_opl_f { OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ int UpdateParam; /* stream update parameter */ - UINT8 type; /* chip type */ UINT8 address; /* address register */ UINT8 status; /* status flag */ UINT8 statusmask; /* status mask */ UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - double TimerBase; /* Timer base time (==sampling time)*/ bool IsStereo; /* Write stereo output */ } FM_OPL; @@ -1117,15 +1106,7 @@ static int init_tables(void) tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 ]>>i; } - #if 0 - logerror("tl %04i", x*2); - for (i=0; i<12; i++) - logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); - logerror("\n"); - #endif } - /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ - for (i=0; i>1; sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - - /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ } for (i=0; i>2)]; - - /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); - logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); - logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ } - /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ - return 1; } -static void OPLCloseTable( void ) -{ -} - - - static void OPL_initalize(FM_OPL *OPL) { int i; - /* frequency base */ - OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; -#if 0 - OPL->rate = (double)OPL->clock / 72.0; - OPL->freqbase = 1.0; -#endif - - /* Timer base time */ - OPL->TimerBase = 1.0 / ((double)OPL->clock / 72.0 ); - /* make fnumber -> increment counter table */ for( i=0 ; i < 1024 ; i++ ) { /* opn phase increment counter = 20bit */ - OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ -#if 0 - logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", - i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); -#endif + OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ } -#if 0 - for( i=0 ; i < 16 ; i++ ) - { - logerror("FMOPL.C: sl_tab[%i] = %08x\n", - i, sl_tab[i] ); - } - for( i=0 ; i < 8 ; i++ ) - { - int j; - logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); - for (j=0; j<16; j++) - { - logerror("%08x ", ksl_tab[i*16+j] ); - } - logerror("\n"); - } -#endif - - /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ /* One entry from LFO_AM_TABLE lasts for 64 samples */ - OPL->lfo_am_inc = UINT32((1.0 / 64.0 ) * (1<freqbase); + OPL->lfo_am_inc = UINT32((1.0 / 64.0 ) * (1<lfo_pm_inc = UINT32((1.0 / 1024.0) * (1<freqbase); + OPL->lfo_pm_inc = UINT32((1.0 / 1024.0) * (1<lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ - - OPL->eg_timer_add = UINT32((1<freqbase); + OPL->eg_timer_add = UINT32((1<eg_timer_overflow = UINT32(( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ // [RH] Support full MIDI panning. (But default to mono and center panning.) OPL->IsStereo = false; @@ -1400,11 +1331,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) switch(r&0x1f) { case 0x01: /* waveform select enable */ - if(OPL->type&OPL_TYPE_WAVESEL) - { - OPL->wavesel = v&0x20; - /* do not change the waveform previously selected */ - } + OPL->wavesel = v&0x20; break; case 0x02: /* Timer 1 */ OPL->T[0] = (256-v)*4; @@ -1428,14 +1355,14 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) /* timer 2 */ if(OPL->st[1] != st2) { - double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; + double interval = st2 ? (double)OPL->T[1]*OPL_TIMERBASE : 0.0; OPL->st[1] = st2; if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); } /* timer 1 */ if(OPL->st[0] != st1) { - double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; + double interval = st1 ? (double)OPL->T[0]*OPL_TIMERBASE : 0.0; OPL->st[0] = st1; if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); } @@ -1612,10 +1539,6 @@ static void OPL_UnLockTable(void) { if(num_lock) num_lock--; if(num_lock) return; - - /* last time */ - - OPLCloseTable(); } static void OPLResetChip(FM_OPL *OPL) @@ -1654,7 +1577,7 @@ static void OPLResetChip(FM_OPL *OPL) /* Create one of virtual YM3812 */ /* 'clock' is chip clock in Hz */ /* 'rate' is sampling rate */ -static FM_OPL *OPLCreate(int type, int clock, int rate) +static FM_OPL *OPLCreate() { char *ptr; FM_OPL *OPL; @@ -1678,10 +1601,6 @@ static FM_OPL *OPLCreate(int type, int clock, int rate) ptr += sizeof(FM_OPL); - OPL->type = type; - OPL->clock = clock; - OPL->rate = rate; - /* init global tables */ OPL_initalize(OPL); @@ -1772,15 +1691,15 @@ static int OPLTimerOver(FM_OPL *OPL,int c) } } /* reload timer */ - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL_TIMERBASE); return OPL->status>>7; } -void *YM3812Init(int clock, int rate) +void *YM3812Init() { /* emulator create */ - FM_OPL *YM3812 = OPLCreate(OPL_TYPE_YM3812,clock,rate); + FM_OPL *YM3812 = OPLCreate(); if (YM3812) YM3812ResetChip(YM3812); return YM3812; diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h index 0064f642e..0db3a2d53 100644 --- a/src/oplsynth/fmopl.h +++ b/src/oplsynth/fmopl.h @@ -25,7 +25,7 @@ typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); typedef unsigned char (*OPL_PORTHANDLER_R)(int param); -void *YM3812Init(int clock, int rate); +void *YM3812Init(); void YM3812Shutdown(void *chip); void YM3812ResetChip(void *chip); int YM3812Write(void *chip, int a, int v); diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 2c5bbc010..598366717 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -307,14 +307,14 @@ void OPLio::OPLshutup(void) int OPLio::OPLinit(uint numchips, bool stereo) { assert(numchips >= 1 && numchips <= 2); - chips[0] = YM3812Init (3579545, int(OPL_SAMPLE_RATE)); + chips[0] = YM3812Init(); chips[1] = NULL; if (chips[0] != NULL) { YM3812SetStereo(chips[0], stereo); if (numchips > 1) { - chips[1] = YM3812Init (3579545, int(OPL_SAMPLE_RATE)); + chips[1] = YM3812Init(); if (chips[1] == NULL) { YM3812Shutdown(chips[0]); From 47d9859246f34b7e4987602167726d0fe14b2e24 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 04:40:01 +0000 Subject: [PATCH 024/387] - Remove external event callback handlers from fmopl.cpp. SVN r3941 (trunk) --- src/oplsynth/fmopl.cpp | 78 ------------------------------------------ src/oplsynth/fmopl.h | 5 --- 2 files changed, 83 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 9578aa4e1..5f9d99f2f 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -247,14 +247,6 @@ typedef struct fm_opl_f { int T[2]; /* timer counters */ UINT8 st[2]; /* timer enable */ - /* external event callback handlers */ - OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ - int TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - int IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ - int UpdateParam; /* stream update parameter */ - UINT8 address; /* address register */ UINT8 status; /* status flag */ UINT8 statusmask; /* status mask */ @@ -596,8 +588,6 @@ INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) if(OPL->status & OPL->statusmask) { /* IRQ on */ OPL->status |= 0x80; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); } } } @@ -612,8 +602,6 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) if (!(OPL->status & OPL->statusmask) ) { OPL->status &= 0x7f; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); } } } @@ -1357,14 +1345,12 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) { double interval = st2 ? (double)OPL->T[1]*OPL_TIMERBASE : 0.0; OPL->st[1] = st2; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); } /* timer 1 */ if(OPL->st[0] != st1) { double interval = st1 ? (double)OPL->T[0]*OPL_TIMERBASE : 0.0; OPL->st[0] = st1; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); } } break; @@ -1614,24 +1600,6 @@ static void OPLDestroy(FM_OPL *OPL) free(OPL); } -/* Optional handlers */ - -static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) -{ - OPL->TimerHandler = TimerHandler; - OPL->TimerParam = channelOffset; -} -static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} - /* YM3812 I/O interface */ static int OPLWrite(FM_OPL *OPL,int a,int v) { @@ -1641,7 +1609,6 @@ static int OPLWrite(FM_OPL *OPL,int a,int v) } else { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); OPLWriteReg(OPL,OPL->address,v); } return OPL->status>>7; @@ -1672,30 +1639,6 @@ INLINE void CSMKeyControll(OPL_CH *CH) } -static int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL_STATUS_SET(OPL,0x20); - } - else - { /* Timer A */ - OPL_STATUS_SET(OPL,0x40); - /* CSM mode key,TL controll */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0; ch<9; ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL_TIMERBASE); - return OPL->status>>7; -} - - void *YM3812Init() { /* emulator create */ @@ -1730,27 +1673,6 @@ unsigned char YM3812Read(void *chip, int a) /* YM3812 always returns bit2 and bit1 in HIGH state */ return OPLRead(YM3812, a) | 0x06 ; } -int YM3812TimerOver(void *chip, int c) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLTimerOver(YM3812, c); -} - -void YM3812SetTimerHandler(void *chip, OPL_TIMERHANDLER TimerHandler, int channelOffset) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetTimerHandler(YM3812, TimerHandler, channelOffset); -} -void YM3812SetIRQHandler(void *chip,OPL_IRQHANDLER IRQHandler,int param) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetIRQHandler(YM3812, IRQHandler, param); -} -void YM3812SetUpdateHandler(void *chip,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLSetUpdateHandler(YM3812, UpdateHandler, param); -} /* [RH] Full support for MIDI panning */ void YM3812SetStereo(void *chip, bool stereo) diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h index 0db3a2d53..850317a40 100644 --- a/src/oplsynth/fmopl.h +++ b/src/oplsynth/fmopl.h @@ -30,15 +30,10 @@ void YM3812Shutdown(void *chip); void YM3812ResetChip(void *chip); int YM3812Write(void *chip, int a, int v); unsigned char YM3812Read(void *chip, int a); -int YM3812TimerOver(void *chip, int c); void YM3812UpdateOne(void *chip, float *buffer, int length); void YM3812SetStereo(void *chip, bool stereo); void YM3812SetPanning(void *chip, int c, int pan); -void YM3812SetTimerHandler(void *chip, OPL_TIMERHANDLER TimerHandler, int channelOffset); -void YM3812SetIRQHandler(void *chip, OPL_IRQHANDLER IRQHandler, int param); -void YM3812SetUpdateHandler(void *chip, OPL_UPDATEHANDLER UpdateHandler, int param); - FString YM3812GetVoiceString(void *chip); #endif From df1e802412786befdac1f7b5523a1394902a2d08 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 05:21:00 +0000 Subject: [PATCH 025/387] - Make OPL emulation more of a black box. SVN r3942 (trunk) --- src/oplsynth/fmopl.cpp | 315 ++++++++------------ src/oplsynth/fmopl.h | 32 +- src/oplsynth/mlopl_io.cpp | 51 ++-- src/oplsynth/music_opl_mididevice.cpp | 2 +- src/oplsynth/music_opldumper_mididevice.cpp | 4 +- src/oplsynth/muslib.h | 3 +- src/oplsynth/opl.h | 21 ++ src/oplsynth/opl_mus_player.cpp | 17 +- zdoom.vcproj | 4 + 9 files changed, 188 insertions(+), 261 deletions(-) create mode 100644 src/oplsynth/opl.h diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 5f9d99f2f..ea595c01a 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -102,6 +102,17 @@ Revision History: //#include "driver.h" /* use M.A.M.E. */ #include "fmopl.h" +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + #ifndef PI #define PI 3.14159265358979323846 #endif @@ -1343,13 +1354,11 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) /* timer 2 */ if(OPL->st[1] != st2) { - double interval = st2 ? (double)OPL->T[1]*OPL_TIMERBASE : 0.0; OPL->st[1] = st2; } /* timer 1 */ if(OPL->st[0] != st1) { - double interval = st1 ? (double)OPL->T[0]*OPL_TIMERBASE : 0.0; OPL->st[0] = st1; } } @@ -1560,194 +1569,140 @@ static void OPLResetChip(FM_OPL *OPL) } } -/* Create one of virtual YM3812 */ -/* 'clock' is chip clock in Hz */ -/* 'rate' is sampling rate */ -static FM_OPL *OPLCreate() + +class YM3812 : public OPLEmul { - char *ptr; - FM_OPL *OPL; - int state_size; +private: + FM_OPL Chip; - if (OPL_LockTable() ==-1) return NULL; - - /* calculate OPL state size */ - state_size = sizeof(FM_OPL); - - /* allocate memory block */ - ptr = (char *)malloc(state_size); - - if (ptr==NULL) - return NULL; - - /* clear */ - memset(ptr,0,state_size); - - OPL = (FM_OPL *)ptr; - - ptr += sizeof(FM_OPL); - - /* init global tables */ - OPL_initalize(OPL); - - return OPL; -} - -/* Destroy one of virtual YM3812 */ -static void OPLDestroy(FM_OPL *OPL) -{ - OPL_UnLockTable(); - free(OPL); -} - -/* YM3812 I/O interface */ -static int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - OPLWriteReg(OPL,OPL->address,v); - } - return OPL->status>>7; -} - -static unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) +public: + /* Create one of virtual YM3812 */ + YM3812(bool stereo) { - /* status port */ - /* OPL and OPL2 */ - return OPL->status & (OPL->statusmask|0x80); + if (OPL_LockTable() == -1) return; + + /* clear */ + memset(&Chip, 0, sizeof(Chip)); + + /* init global tables */ + OPL_initalize(&Chip); + + Chip.IsStereo = true; + + Reset(); } - return 0xff; -} - -/* CSM Key Controll */ -INLINE void CSMKeyControll(OPL_CH *CH) -{ - FM_KEYON (&CH->SLOT[SLOT1], 4); - FM_KEYON (&CH->SLOT[SLOT2], 4); - - /* The key off should happen exactly one sample later - not implemented correctly yet */ - - FM_KEYOFF(&CH->SLOT[SLOT1], ~4); - FM_KEYOFF(&CH->SLOT[SLOT2], ~4); -} - - -void *YM3812Init() -{ - /* emulator create */ - FM_OPL *YM3812 = OPLCreate(); - if (YM3812) - YM3812ResetChip(YM3812); - return YM3812; -} - -void YM3812Shutdown(void *chip) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - - /* emulator shutdown */ - OPLDestroy(YM3812); -} -void YM3812ResetChip(void *chip) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - OPLResetChip(YM3812); -} - -int YM3812Write(void *chip, int a, int v) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - return OPLWrite(YM3812, a, v); -} - -unsigned char YM3812Read(void *chip, int a) -{ - FM_OPL *YM3812 = (FM_OPL *)chip; - /* YM3812 always returns bit2 and bit1 in HIGH state */ - return OPLRead(YM3812, a) | 0x06 ; -} - -/* [RH] Full support for MIDI panning */ -void YM3812SetStereo(void *chip, bool stereo) -{ - if (chip != NULL) + /* Destroy one of virtual YM3812 */ + ~YM3812() { - FM_OPL *YM3812 = (FM_OPL *)chip; - YM3812->IsStereo = stereo; + OPL_UnLockTable(); } -} -void YM3812SetPanning(void *chip, int c, int pan) -{ - if (chip != NULL) + /* YM3812 I/O interface */ + int Write(int a, int v) + { + if( !(a&1) ) + { /* address port */ + Chip.address = v & 0xff; + } + else + { /* data port */ + OPLWriteReg(&Chip, Chip.address, v); + } + return Chip.status>>7; + } + + void Reset() + { + OPLResetChip(&Chip); + } + + /* [RH] Full support for MIDI panning */ + void SetPanning(int c, int pan) { - FM_OPL *YM3812 = (FM_OPL *)chip; // This is the MIDI-recommended pan formula. 0 and 1 are // both hard left so that 64 can be perfectly center. double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; - YM3812->P_CH[c].LeftVol = (float)cos(HALF_PI * level); - YM3812->P_CH[c].RightVol = (float)sin(HALF_PI * level); - } -} - -/* -** Generate samples for one of the YM3812's -** -** 'which' is the virtual YM3812 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void YM3812UpdateOne(void *chip, float *buffer, int length) -{ - FM_OPL *OPL = (FM_OPL *)chip; - int i; - - if (OPL == NULL) - { - return; + Chip.P_CH[c].LeftVol = (float)cos(HALF_PI * level); + Chip.P_CH[c].RightVol = (float)sin(HALF_PI * level); } - UINT8 rhythm = OPL->rhythm&0x20; - UINT32 lfo_am_cnt_bak = OPL->lfo_am_cnt; - UINT32 eg_timer_bak = OPL->eg_timer; - UINT32 eg_cnt_bak = OPL->eg_cnt; - - UINT32 lfo_am_cnt_out = lfo_am_cnt_bak; - UINT32 eg_timer_out = eg_timer_bak; - UINT32 eg_cnt_out = eg_cnt_bak; - - for (i = 0; i <= (rhythm ? 5 : 8); ++i) + /* + ** Generate samples for one of the YM3812's + ** + ** '*buffer' is the output buffer pointer + ** 'length' is the number of samples that should be generated + */ + void Update(float *buffer, int length) { - OPL->lfo_am_cnt = lfo_am_cnt_bak; - OPL->eg_timer = eg_timer_bak; - OPL->eg_cnt = eg_cnt_bak; - if (CalcVoice (OPL, i, buffer, length)) + int i; + + UINT8 rhythm = Chip.rhythm&0x20; + + UINT32 lfo_am_cnt_bak = Chip.lfo_am_cnt; + UINT32 eg_timer_bak = Chip.eg_timer; + UINT32 eg_cnt_bak = Chip.eg_cnt; + + UINT32 lfo_am_cnt_out = lfo_am_cnt_bak; + UINT32 eg_timer_out = eg_timer_bak; + UINT32 eg_cnt_out = eg_cnt_bak; + + for (i = 0; i <= (rhythm ? 5 : 8); ++i) { - lfo_am_cnt_out = OPL->lfo_am_cnt; - eg_timer_out = OPL->eg_timer; - eg_cnt_out = OPL->eg_cnt; + Chip.lfo_am_cnt = lfo_am_cnt_bak; + Chip.eg_timer = eg_timer_bak; + Chip.eg_cnt = eg_cnt_bak; + if (CalcVoice (&Chip, i, buffer, length)) + { + lfo_am_cnt_out = Chip.lfo_am_cnt; + eg_timer_out = Chip.eg_timer; + eg_cnt_out = Chip.eg_cnt; + } + } + + Chip.lfo_am_cnt = lfo_am_cnt_out; + Chip.eg_timer = eg_timer_out; + Chip.eg_cnt = eg_cnt_out; + + if (rhythm) /* Rhythm part */ + { + Chip.lfo_am_cnt = lfo_am_cnt_bak; + Chip.eg_timer = eg_timer_bak; + Chip.eg_cnt = eg_cnt_bak; + CalcRhythm (&Chip, buffer, length); } } - OPL->lfo_am_cnt = lfo_am_cnt_out; - OPL->eg_timer = eg_timer_out; - OPL->eg_cnt = eg_cnt_out; - - if (rhythm) /* Rhythm part */ + FString GetVoiceString(void *chip) { - OPL->lfo_am_cnt = lfo_am_cnt_bak; - OPL->eg_timer = eg_timer_bak; - OPL->eg_cnt = eg_cnt_bak; - CalcRhythm (OPL, buffer, length); + FM_OPL *OPL = (FM_OPL *)chip; + char out[9*3]; + + for (int i = 0; i <= 8; ++i) + { + int color; + + if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF)) + { + color = 'D'; // Green means in use + } + else + { + color = 'A'; // Brick means free + } + out[i*3+0] = '\x1c'; + out[i*3+1] = color; + out[i*3+2] = '*'; + } + return FString (out, 9*3); } +}; + +OPLEmul *YM3812Init(bool stereo) +{ + /* emulator create */ + return new YM3812(stereo); } // [RH] Render a whole voice at once. If nothing else, it lets us avoid @@ -1813,27 +1768,3 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length) } return true; } - -FString YM3812GetVoiceString(void *chip) -{ - FM_OPL *OPL = (FM_OPL *)chip; - char out[9*3]; - - for (int i = 0; i <= 8; ++i) - { - int color; - - if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF)) - { - color = 'D'; // Green means in use - } - else - { - color = 'A'; // Brick means free - } - out[i*3+0] = '\x1c'; - out[i*3+1] = color; - out[i*3+2] = '*'; - } - return FString (out, 9*3); -} diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h index 850317a40..6a5f65256 100644 --- a/src/oplsynth/fmopl.h +++ b/src/oplsynth/fmopl.h @@ -1,39 +1,11 @@ #ifndef __FMOPL_H_ #define __FMOPL_H_ -#include "zstring.h" +#include "opl.h" // Multiplying OPL_SAMPLE_RATE by ADLIB_CLOCK_MUL gives the number // Adlib clocks per second, as used by the RAWADATA file format. -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif - - -typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); -typedef void (*OPL_IRQHANDLER)(int param,int irq); -typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); -typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); -typedef unsigned char (*OPL_PORTHANDLER_R)(int param); - - -void *YM3812Init(); -void YM3812Shutdown(void *chip); -void YM3812ResetChip(void *chip); -int YM3812Write(void *chip, int a, int v); -unsigned char YM3812Read(void *chip, int a); -void YM3812UpdateOne(void *chip, float *buffer, int length); -void YM3812SetStereo(void *chip, bool stereo); -void YM3812SetPanning(void *chip, int c, int pan); - -FString YM3812GetVoiceString(void *chip); +OPLEmul *YM3812Init(bool stereo); #endif diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 598366717..8ec6f49f7 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -58,8 +58,8 @@ void OPLio::WriteDelay(int ticks) void OPLio::OPLwriteReg(int which, uint reg, uchar data) { - YM3812Write (chips[which], 0, reg); - YM3812Write (chips[which], 1, data); + chips[which]->Write(0, reg); + chips[which]->Write(1, data); } /* @@ -256,7 +256,7 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) // Set real panning if we're using emulated chips. if (chips[0] != NULL) { - YM3812SetPanning(chips[channel/9], channel%9, pan+64); + chips[channel/9]->SetPanning(channel%9, pan+64); } } } @@ -307,33 +307,22 @@ void OPLio::OPLshutup(void) int OPLio::OPLinit(uint numchips, bool stereo) { assert(numchips >= 1 && numchips <= 2); - chips[0] = YM3812Init(); - chips[1] = NULL; - if (chips[0] != NULL) + uint i; + memset(chips, 0, sizeof(chips)); + for (i = 0; i < numchips; ++i) { - YM3812SetStereo(chips[0], stereo); - if (numchips > 1) + OPLEmul *chip = YM3812Init(stereo); + + if (chip == NULL) { - chips[1] = YM3812Init(); - if (chips[1] == NULL) - { - YM3812Shutdown(chips[0]); - chips[0] = NULL; - return -1; - } - else - { - YM3812SetStereo(chips[1], stereo); - } + break; } + chips[i] = chip; } - else - { - return -1; - } - OPLchannels = OPL2CHANNELS * numchips; + NumChips = i; + OPLchannels = OPL2CHANNELS * i; OPLwriteInitState(); - return 0; + return i; } void OPLio::OPLwriteInitState() @@ -352,8 +341,12 @@ void OPLio::OPLwriteInitState() */ void OPLio::OPLdeinit(void) { - YM3812Shutdown (chips[0]); - chips[0] = NULL; - YM3812Shutdown (chips[1]); - chips[1] = NULL; + for (size_t i = 0; i < countof(chips); ++i) + { + if (chips[i] != NULL) + { + delete chips[i]; + chips[i] = NULL; + } + } } diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index d36bacb54..bd3736fe9 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -92,7 +92,7 @@ OPLMIDIDevice::OPLMIDIDevice() int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { - if (io == NULL || io->OPLinit(TwoChips + 1, IsStereo)) + if (io == NULL || 0 == io->OPLinit(TwoChips + 1, IsStereo)) { return 1; } diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 55c1fdc0c..bfd0f212d 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -155,7 +155,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare) if (File == NULL) { Printf("Could not open %s for writing.\n", Filename.GetChars()); - return -1; + return 0; } if (Format == FMT_RDOS) @@ -189,7 +189,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare) CurChip = 0; OPLchannels = OPL2CHANNELS * numchips; OPLwriteInitState(); - return 0; + return 1; } //========================================================================== diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 189649551..75539b2f6 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -183,8 +183,9 @@ struct OPLio { virtual void SetClockRate(double samples_per_tick); virtual void WriteDelay(int ticks); + class OPLEmul *chips[2]; uint OPLchannels; - void *chips[2]; + uint NumChips; }; struct DiskWriterIO : public OPLio diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h new file mode 100644 index 000000000..fbb7c412c --- /dev/null +++ b/src/oplsynth/opl.h @@ -0,0 +1,21 @@ +#ifndef OPL_H +#define OPL_H + +#include "zstring.h" + +// Abstract base class for OPL emulators + +class OPLEmul +{ +public: + OPLEmul() {} + virtual ~OPLEmul() {} + + virtual void Reset() = 0; + virtual int Write(int a, int v) = 0; + virtual void Update(float *buffer, int length) = 0; + virtual void SetPanning(int c, int pan) = 0; + virtual FString GetVoiceString() { return FString(); } +}; + +#endif \ No newline at end of file diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index 6df36e707..6be111430 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -40,7 +40,7 @@ void OPLmusicBlock::ResetChips () TwoChips = !opl_onechip; ChipAccess.Enter(); io->OPLdeinit (); - io->OPLinit (TwoChips + 1, IsStereo); + TwoChips = io->OPLinit(TwoChips + 1, IsStereo) == 2; ChipAccess.Leave(); } @@ -77,7 +77,7 @@ fail: delete[] scoredata; memcpy(scoredata, &musiccache[0], len); } - if (io->OPLinit (TwoChips + 1)) + if (0 == io->OPLinit (TwoChips + 1)) { goto fail; } @@ -236,11 +236,14 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) double ticky = NextTickIn; int tick_in = int(NextTickIn); int samplesleft = MIN(numsamples, tick_in); + size_t i; if (samplesleft > 0) { - YM3812UpdateOne (io->chips[0], samples1, samplesleft); - YM3812UpdateOne (io->chips[1], samples1, samplesleft); + for (i = 0; i < io->NumChips; ++i) + { + io->chips[i]->Update(samples1, samplesleft); + } OffsetSamples(samples1, samplesleft << int(IsStereo)); assert(NextTickIn == ticky); NextTickIn -= samplesleft; @@ -259,8 +262,10 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { if (numsamples > 0) { - YM3812UpdateOne (io->chips[0], samples1, numsamples); - YM3812UpdateOne (io->chips[1], samples1, numsamples); + for (i = 0; i < io->NumChips; ++i) + { + io->chips[i]->Update(samples1, samplesleft); + } OffsetSamples(samples1, numsamples << int(IsStereo)); } res = false; diff --git a/zdoom.vcproj b/zdoom.vcproj index 817f53b70..0b144ce26 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2618,6 +2618,10 @@ RelativePath=".\src\oplsynth\muslib.h" > + + From 1d81162d8fb3cb8cd84ec9ffa2af7ab4c25e0351 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 05:29:44 +0000 Subject: [PATCH 026/387] - Fix bug from preceding commit: OPL chips were forced stereo. Also, DiskWriterIO::OPLinit() should return the number of initialized chips, not just 0 and 1. SVN r3943 (trunk) --- src/oplsynth/fmopl.cpp | 2 +- src/oplsynth/music_opldumper_mididevice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index ea595c01a..1bfe1dd5f 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -1587,7 +1587,7 @@ public: /* init global tables */ OPL_initalize(&Chip); - Chip.IsStereo = true; + Chip.IsStereo = stereo; Reset(); } diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index bfd0f212d..f8fe6089f 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -189,7 +189,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare) CurChip = 0; OPLchannels = OPL2CHANNELS * numchips; OPLwriteInitState(); - return 1; + return numchips; } //========================================================================== From 54ad69ebad78f2d9fcc65ab898fb83973b3633ed Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 05:35:43 +0000 Subject: [PATCH 027/387] - Call init_tables() directly from the YM3812 constructor. SVN r3944 (trunk) --- src/oplsynth/fmopl.cpp | 43 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 1bfe1dd5f..e1ade9e43 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -1077,12 +1077,19 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) /* generic table initialize */ -static int init_tables(void) +static void init_tables(void) { signed int i,x; signed int n; double o,m; + /* We only need to do this once. */ + static bool did_init = false; + + if (did_init) + { + return; + } for (x=0; x>2)]; } - return 1; + did_init = true; } static void OPL_initalize(FM_OPL *OPL) @@ -1512,30 +1519,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } } -/* lock/unlock for common table */ -static int OPL_LockTable(void) -{ - num_lock++; - if(num_lock>1) return 0; - - /* first time */ - - /* allocate total level table (128kb space) */ - if( !init_tables() ) - { - num_lock--; - return -1; - } - - return 0; -} - -static void OPL_UnLockTable(void) -{ - if(num_lock) num_lock--; - if(num_lock) return; -} - static void OPLResetChip(FM_OPL *OPL) { int c,s; @@ -1579,7 +1562,7 @@ public: /* Create one of virtual YM3812 */ YM3812(bool stereo) { - if (OPL_LockTable() == -1) return; + init_tables(); /* clear */ memset(&Chip, 0, sizeof(Chip)); @@ -1592,12 +1575,6 @@ public: Reset(); } - /* Destroy one of virtual YM3812 */ - ~YM3812() - { - OPL_UnLockTable(); - } - /* YM3812 I/O interface */ int Write(int a, int v) { From 12ee3271c4bbf0f740dc98e036a56f5554e18816 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 6 Nov 2012 06:10:04 +0000 Subject: [PATCH 028/387] - Replaced the opl_onechip cvar with opl_numchips. You can now emulate up to 8 of them for MIDI playback. (Raw OPL playback will still clamp it to 2, since there's no use for more than that with any of the raw OPL formats.) SVN r3945 (trunk) --- src/oplsynth/mlopl_io.cpp | 24 ++++++++++-------------- src/oplsynth/music_opl_mididevice.cpp | 4 +++- src/oplsynth/muslib.h | 5 +++-- src/oplsynth/opl_mus_player.cpp | 19 +++++++++---------- src/oplsynth/opl_mus_player.h | 2 +- src/sound/music_mus_opl.cpp | 13 +++++++++++-- wadsrc/static/menudef.txt | 2 +- 7 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 8ec6f49f7..6f33fa7f7 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -68,12 +68,11 @@ void OPLio::OPLwriteReg(int which, uint reg, uchar data) */ void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2) { - static const uint op_num[] = { - 0x000, 0x001, 0x002, 0x008, 0x009, 0x00A, 0x010, 0x011, 0x012, - 0x100, 0x101, 0x102, 0x108, 0x109, 0x10A, 0x110, 0x111, 0x112}; + static const uint op_num[OPL2CHANNELS] = { + 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12}; - uint reg = regbase+op_num[channel]; - uint which = reg>>8; + uint which = channel / OPL2CHANNELS; + uint reg = regbase + op_num[channel % OPL2CHANNELS]; OPLwriteReg (which, reg, data1); OPLwriteReg (which, reg+3, data2); } @@ -84,12 +83,8 @@ void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2 */ void OPLio::OPLwriteValue(uint regbase, uint channel, uchar value) { - static const uint reg_num[] = { - 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, - 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108}; - - uint reg = regbase+reg_num[channel]; - uint which = reg>>8; + uint which = channel / OPL2CHANNELS; + uint reg = regbase + (channel % OPL2CHANNELS); OPLwriteReg (which, reg, value); } @@ -254,9 +249,10 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) OPLwriteValue(0xC0, channel, instr->feedback | bits); // Set real panning if we're using emulated chips. - if (chips[0] != NULL) + int which = channel / OPL2CHANNELS; + if (chips[which] != NULL) { - chips[channel/9]->SetPanning(channel%9, pan+64); + chips[which]->SetPanning(channel % OPL2CHANNELS, pan + 64); } } } @@ -306,7 +302,7 @@ void OPLio::OPLshutup(void) */ int OPLio::OPLinit(uint numchips, bool stereo) { - assert(numchips >= 1 && numchips <= 2); + assert(numchips >= 1 && numchips <= countof(chips)); uint i; memset(chips, 0, sizeof(chips)); for (i = 0; i < numchips; ++i) diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index bd3736fe9..f9c28d0cc 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -60,6 +60,8 @@ // EXTERNAL DATA DECLARATIONS ---------------------------------------------- +EXTERN_CVAR(Int, opl_numchips) + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -92,7 +94,7 @@ OPLMIDIDevice::OPLMIDIDevice() int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { - if (io == NULL || 0 == io->OPLinit(TwoChips + 1, IsStereo)) + if (io == NULL || 0 == (NumChips = io->OPLinit(opl_numchips, IsStereo))) { return 1; } diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 75539b2f6..4c4bd6e88 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -141,7 +141,8 @@ struct OP2instrEntry { /* From MLOPL_IO.CPP */ #define OPL2CHANNELS 9 #define OPL3CHANNELS 18 -#define MAXCHANNELS 18 +#define MAXOPL2CHIPS 8 +#define MAXCHANNELS (OPL2CHANNELS * MAXOPL2CHIPS) /* Channel Flags: */ @@ -183,7 +184,7 @@ struct OPLio { virtual void SetClockRate(double samples_per_tick); virtual void WriteDelay(int ticks); - class OPLEmul *chips[2]; + class OPLEmul *chips[MAXOPL2CHIPS]; uint OPLchannels; uint NumChips; }; diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index 6be111430..6140d327e 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -16,14 +16,14 @@ #define IMF_RATE 700.0 -EXTERN_CVAR (Bool, opl_onechip) +EXTERN_CVAR (Int, opl_numchips) OPLmusicBlock::OPLmusicBlock() { scoredata = NULL; NextTickIn = 0; LastOffset = 0; - TwoChips = !opl_onechip; + NumChips = MIN(*opl_numchips, 2); Looping = false; IsStereo = false; io = NULL; @@ -37,10 +37,9 @@ OPLmusicBlock::~OPLmusicBlock() void OPLmusicBlock::ResetChips () { - TwoChips = !opl_onechip; ChipAccess.Enter(); io->OPLdeinit (); - TwoChips = io->OPLinit(TwoChips + 1, IsStereo) == 2; + NumChips = io->OPLinit(MIN(*opl_numchips, 2), IsStereo); ChipAccess.Leave(); } @@ -77,7 +76,7 @@ fail: delete[] scoredata; memcpy(scoredata, &musiccache[0], len); } - if (0 == io->OPLinit (TwoChips + 1)) + if (0 == (NumChips = io->OPLinit(NumChips))) { goto fail; } @@ -411,7 +410,7 @@ int OPLmusicFile::PlayTick () break; default: // It's something to stuff into the OPL chip - if (WhichChip == 0 || TwoChips) + if (WhichChip < NumChips) { io->OPLwriteReg(WhichChip, reg, data); } @@ -454,7 +453,7 @@ int OPLmusicFile::PlayTick () { data = *score++; } - if (WhichChip == 0 || TwoChips) + if (WhichChip < NumChips) { io->OPLwriteReg(WhichChip, reg, data); } @@ -485,7 +484,7 @@ int OPLmusicFile::PlayTick () { return (data + 1) << 8; } - else if (code < to_reg_size && (which = 0 || TwoChips)) + else if (code < to_reg_size && which < NumChips) { io->OPLwriteReg(which, to_reg[code], data); } @@ -527,14 +526,14 @@ OPLmusicFile::OPLmusicFile(const OPLmusicFile *source, const char *filename) SamplesPerTick = source->SamplesPerTick; RawPlayer = source->RawPlayer; score = source->score; - TwoChips = source->TwoChips; + NumChips = source->NumChips; WhichChip = 0; if (io != NULL) { delete io; } io = new DiskWriterIO(filename); - io->OPLinit(TwoChips + 1); + NumChips = io->OPLinit(NumChips); Restart(); } diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index 57744ebfc..03765c10a 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -18,7 +18,7 @@ protected: double NextTickIn; double SamplesPerTick; - bool TwoChips; + int NumChips; bool Looping; double LastOffset; bool IsStereo; diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 8f5d430ba..0d9c35bb2 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -1,10 +1,19 @@ #include "i_musicinterns.h" +#include "oplsynth/muslib.h" static bool OPL_Active; -CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { - if (OPL_Active && currSong != NULL) + if (*self <= 0) + { + self = 1; + } + else if (*self > MAXOPL2CHIPS) + { + self = MAXOPL2CHIPS; + } + else if (OPL_Active && currSong != NULL) { static_cast(currSong)->ResetChips (); } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c7dd62233..80e4ad0e0 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1408,7 +1408,7 @@ OptionMenu AdvSoundOptions Option "Buffer count", "snd_buffercount", "BufferCounts" StaticText " " StaticText "OPL Synthesis", 1 - Option "Only emulate one OPL chip", "opl_onechip", "OnOff" + Slider "Number of emulated OPL chips", "opl_numchips", 1, 8, 1, 0 Option "Support MIDI stero panning", "opl_stereo", "OnOff" StaticText " " StaticText "GUS Emulation", 1 From 3ec387ac320f5f938c2a7ef763654a72e12f4e12 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 8 Nov 2012 05:45:58 +0000 Subject: [PATCH 029/387] - Renamed opl_stereo to opl_fullpan, since DOSBox's core is emulating an OPL3, which is stereo but only supports three pan positions and not the full 127 MIDI pan positions. - Added opl_core cvar to select emulator core. 0 is MAME and 1 is DOSBox. - Added DOSBox's LGPL OPL core, distantly related to one adlibemu.c written by Ken Silverman (not to be confused with the ancient MAME-derived and GPL-licensed core also found in DOSBox). I believe this corresponds to their "compat" emulator, but I'm not sure. SVN r3946 (trunk) --- src/CMakeLists.txt | 6 +-- src/oplsynth/fmopl.cpp | 16 ++----- src/oplsynth/fmopl.h | 11 ----- src/oplsynth/mlopl_io.cpp | 49 ++++++++++++++------- src/oplsynth/music_opl_mididevice.cpp | 10 ++--- src/oplsynth/music_opldumper_mididevice.cpp | 4 +- src/oplsynth/muslib.h | 5 ++- src/oplsynth/opl.h | 5 ++- src/oplsynth/opl_mus_player.cpp | 15 ++++--- src/oplsynth/opl_mus_player.h | 2 +- src/sound/music_mus_opl.cpp | 4 +- wadsrc/static/menudef.txt | 9 +++- zdoom.vcproj | 44 ++++++++++++++++-- zlib/CMakeLists.txt | 2 +- 14 files changed, 114 insertions(+), 68 deletions(-) delete mode 100644 src/oplsynth/fmopl.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1b0e0603..b6dd26f28 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -566,11 +566,6 @@ else( NO_ASM ) ADD_ASM_FILE( asm_ia32 tmap2 ) ADD_ASM_FILE( asm_ia32 tmap3 ) endif( X64 ) - if( WIN32 ) - if( NOT X64 ) - ADD_ASM_FILE( win32 wrappers ) - endif( NOT X64 ) - endif( WIN32 ) endif( NO_ASM ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h @@ -817,6 +812,7 @@ add_executable( zdoom WIN32 oplsynth/music_opldumper_mididevice.cpp oplsynth/music_opl_mididevice.cpp oplsynth/opl_mus_player.cpp + oplsynth/dosbox/opl.cpp resourcefiles/ancientzip.cpp resourcefiles/file_7z.cpp resourcefiles/file_grp.cpp diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index e1ade9e43..c4fe1a282 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -100,7 +100,7 @@ Revision History: #include #include //#include "driver.h" /* use M.A.M.E. */ -#include "fmopl.h" +#include "opl.h" /* compiler dependence */ #ifndef OSD_CPU_H @@ -1576,17 +1576,9 @@ public: } /* YM3812 I/O interface */ - int Write(int a, int v) + void WriteReg(int reg, int v) { - if( !(a&1) ) - { /* address port */ - Chip.address = v & 0xff; - } - else - { /* data port */ - OPLWriteReg(&Chip, Chip.address, v); - } - return Chip.status>>7; + OPLWriteReg(&Chip, reg & 0xff, v); } void Reset() @@ -1676,7 +1668,7 @@ public: } }; -OPLEmul *YM3812Init(bool stereo) +OPLEmul *YM3812Create(bool stereo) { /* emulator create */ return new YM3812(stereo); diff --git a/src/oplsynth/fmopl.h b/src/oplsynth/fmopl.h deleted file mode 100644 index 6a5f65256..000000000 --- a/src/oplsynth/fmopl.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __FMOPL_H_ -#define __FMOPL_H_ - -#include "opl.h" - -// Multiplying OPL_SAMPLE_RATE by ADLIB_CLOCK_MUL gives the number -// Adlib clocks per second, as used by the RAWADATA file format. - -OPLEmul *YM3812Init(bool stereo); - -#endif diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 6f33fa7f7..cfc29f7c9 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -42,7 +42,10 @@ #include #endif #include "muslib.h" -#include "fmopl.h" +#include "opl.h" +#include "c_cvars.h" + +EXTERN_CVAR(Int, opl_core) OPLio::~OPLio() { @@ -58,8 +61,12 @@ void OPLio::WriteDelay(int ticks) void OPLio::OPLwriteReg(int which, uint reg, uchar data) { - chips[which]->Write(0, reg); - chips[which]->Write(1, data); + if (IsOPL3) + { + reg |= (which & 1) << 8; + which >>= 1; + } + chips[which]->WriteReg(reg, data); } /* @@ -249,10 +256,11 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) OPLwriteValue(0xC0, channel, instr->feedback | bits); // Set real panning if we're using emulated chips. - int which = channel / OPL2CHANNELS; + int chanper = IsOPL3 ? OPL3CHANNELS : OPL2CHANNELS; + int which = channel / chanper; if (chips[which] != NULL) { - chips[which]->SetPanning(channel % OPL2CHANNELS, pan + 64); + chips[which]->SetPanning(channel % chanper, pan + 64); } } } @@ -300,15 +308,20 @@ void OPLio::OPLshutup(void) /* * Initialize hardware upon startup */ -int OPLio::OPLinit(uint numchips, bool stereo) +int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); uint i; + IsOPL3 = (opl_core == 1); + memset(chips, 0, sizeof(chips)); + if (IsOPL3) + { + numchips = (numchips + 1) >> 1; + } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = YM3812Init(stereo); - + OPLEmul *chip = IsOPL3 ? DBOPLCreate(stereo) : YM3812Create(stereo); if (chip == NULL) { break; @@ -316,18 +329,24 @@ int OPLio::OPLinit(uint numchips, bool stereo) chips[i] = chip; } NumChips = i; - OPLchannels = OPL2CHANNELS * i; - OPLwriteInitState(); + OPLchannels = i * (IsOPL3 ? OPL3CHANNELS : OPL2CHANNELS); + OPLwriteInitState(initopl3); return i; } -void OPLio::OPLwriteInitState() +void OPLio::OPLwriteInitState(bool initopl3) { - for (uint i = 0; i < OPLchannels / OPL2CHANNELS; ++i) + for (uint i = 0; i < NumChips; ++i) { - OPLwriteReg (i, 0x01, 0x20); // enable Waveform Select - OPLwriteReg (i, 0x0B, 0x40); // turn off CSW mode - OPLwriteReg (i, 0xBD, 0x00); // set vibrato/tremolo depth to low, set melodic mode + int chip = i << (int)IsOPL3; + if (IsOPL3 && initopl3) + { + OPLwriteReg(chip, 0x105, 0x01); // enable YMF262/OPL3 mode + OPLwriteReg(chip, 0x104, 0x00); // disable 4-operator mode + } + OPLwriteReg(chip, 0x01, 0x20); // enable Waveform Select + OPLwriteReg(chip, 0x0B, 0x40); // turn off CSW mode + OPLwriteReg(chip, 0xBD, 0x00); // set vibrato/tremolo depth to low, set melodic mode } OPLshutup(); } diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index f9c28d0cc..79bb10226 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -41,7 +41,7 @@ #include "m_swap.h" #include "w_wad.h" #include "v_text.h" -#include "fmopl.h" +#include "opl.h" // MACROS ------------------------------------------------------------------ @@ -66,7 +66,7 @@ EXTERN_CVAR(Int, opl_numchips) // PUBLIC DATA DEFINITIONS ------------------------------------------------- -CVAR(Bool, opl_stereo, true, CVAR_ARCHIVE); +CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // CODE -------------------------------------------------------------------- @@ -78,7 +78,7 @@ CVAR(Bool, opl_stereo, true, CVAR_ARCHIVE); OPLMIDIDevice::OPLMIDIDevice() { - IsStereo = opl_stereo; + FullPan = opl_fullpan; FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); SampleRate = (int)OPL_SAMPLE_RATE; @@ -94,11 +94,11 @@ OPLMIDIDevice::OPLMIDIDevice() int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { - if (io == NULL || 0 == (NumChips = io->OPLinit(opl_numchips, IsStereo))) + if (io == NULL || 0 == (NumChips = io->OPLinit(opl_numchips, FullPan, true))) { return 1; } - int ret = OpenStream(14, IsStereo ? 0 : SoundStream::Mono, callback, userdata); + int ret = OpenStream(14, (FullPan || io->IsOPL3) ? 0 : SoundStream::Mono, callback, userdata); if (ret == 0) { OPLstopMusic(); diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index f8fe6089f..0bb9ac14d 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -39,7 +39,7 @@ #include "doomdef.h" #include "m_swap.h" #include "w_wad.h" -#include "fmopl.h" +#include "opl.h" // MACROS ------------------------------------------------------------------ @@ -188,7 +188,7 @@ int DiskWriterIO::OPLinit(uint numchips, bool dontcare) CurIntTime = 0; CurChip = 0; OPLchannels = OPL2CHANNELS * numchips; - OPLwriteInitState(); + OPLwriteInitState(false); return numchips; } diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 4c4bd6e88..1746ea02b 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -176,9 +176,9 @@ struct OPLio { void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan); void OPLwriteInstrument(uint channel, struct OPL2instrument *instr); void OPLshutup(void); - void OPLwriteInitState(); + void OPLwriteInitState(bool initopl3); - virtual int OPLinit(uint numchips, bool stereo=false); + virtual int OPLinit(uint numchips, bool stereo=false, bool initopl3=false); virtual void OPLdeinit(void); virtual void OPLwriteReg(int which, uint reg, uchar data); virtual void SetClockRate(double samples_per_tick); @@ -187,6 +187,7 @@ struct OPLio { class OPLEmul *chips[MAXOPL2CHIPS]; uint OPLchannels; uint NumChips; + bool IsOPL3; }; struct DiskWriterIO : public OPLio diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h index fbb7c412c..6a8e42e27 100644 --- a/src/oplsynth/opl.h +++ b/src/oplsynth/opl.h @@ -12,10 +12,13 @@ public: virtual ~OPLEmul() {} virtual void Reset() = 0; - virtual int Write(int a, int v) = 0; + virtual void WriteReg(int reg, int v) = 0; virtual void Update(float *buffer, int length) = 0; virtual void SetPanning(int c, int pan) = 0; virtual FString GetVoiceString() { return FString(); } }; +OPLEmul *YM3812Create(bool stereo); +OPLEmul *DBOPLCreate(bool stereo); + #endif \ No newline at end of file diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index 6140d327e..df4b3c88e 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -7,7 +7,7 @@ #include "opl_mus_player.h" #include "doomtype.h" -#include "fmopl.h" +#include "opl.h" #include "w_wad.h" #include "templates.h" #include "c_cvars.h" @@ -25,7 +25,7 @@ OPLmusicBlock::OPLmusicBlock() LastOffset = 0; NumChips = MIN(*opl_numchips, 2); Looping = false; - IsStereo = false; + FullPan = false; io = NULL; io = new OPLio; } @@ -39,7 +39,7 @@ void OPLmusicBlock::ResetChips () { ChipAccess.Enter(); io->OPLdeinit (); - NumChips = io->OPLinit(MIN(*opl_numchips, 2), IsStereo); + NumChips = io->OPLinit(MIN(*opl_numchips, 2), FullPan); ChipAccess.Leave(); } @@ -223,7 +223,8 @@ void OPLmusicFile::Restart () bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { float *samples1 = (float *)buff; - int numsamples = numbytes / (sizeof(float) << int(IsStereo)); + int stereoshift = (int)(FullPan | io->IsOPL3); + int numsamples = numbytes / (sizeof(float) << stereoshift); bool prevEnded = false; bool res = true; @@ -243,12 +244,12 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { io->chips[i]->Update(samples1, samplesleft); } - OffsetSamples(samples1, samplesleft << int(IsStereo)); + OffsetSamples(samples1, samplesleft << stereoshift); assert(NextTickIn == ticky); NextTickIn -= samplesleft; assert (NextTickIn >= 0); numsamples -= samplesleft; - samples1 += samplesleft << int(IsStereo); + samples1 += samplesleft << stereoshift; } if (NextTickIn < 1) @@ -265,7 +266,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { io->chips[i]->Update(samples1, samplesleft); } - OffsetSamples(samples1, numsamples << int(IsStereo)); + OffsetSamples(samples1, numsamples << stereoshift); } res = false; break; diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index 03765c10a..b0eb4b6c8 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -21,7 +21,7 @@ protected: int NumChips; bool Looping; double LastOffset; - bool IsStereo; + bool FullPan; FCriticalSection ChipAccess; }; diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 0d9c35bb2..fe3463386 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -19,6 +19,8 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } +CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len) { int samples = int(OPL_SAMPLE_RATE / 14); @@ -26,7 +28,7 @@ OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len) Music = new OPLmusicFile (file, musiccache, len); m_Stream = GSnd->CreateStream (FillStream, samples*4, - SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this); + (opl_core != 1 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 80e4ad0e0..49bbfd91c 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1400,6 +1400,12 @@ OptionValue GusMemory 4, "1024K" } +OptionValue OplCores +{ + 0, "MAME" + 1, "DOSBox" +} + OptionMenu AdvSoundOptions { Title "ADVANCED SOUND OPTIONS" @@ -1409,7 +1415,8 @@ OptionMenu AdvSoundOptions StaticText " " StaticText "OPL Synthesis", 1 Slider "Number of emulated OPL chips", "opl_numchips", 1, 8, 1, 0 - Option "Support MIDI stero panning", "opl_stereo", "OnOff" + Option "Full MIDI stereo panning", "opl_fullpan", "OnOff" + Option "OPL Emulator Core", "opl_core", "OplCores" StaticText " " StaticText "GUS Emulation", 1 Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 diff --git a/zdoom.vcproj b/zdoom.vcproj index 0b144ce26..fb5e5b1f5 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2602,10 +2602,6 @@ /> - - @@ -2630,6 +2626,46 @@ RelativePath=".\src\oplsynth\opl_mus_player.h" > + + + + + + + + + + + + + + + + + + Date: Thu, 8 Nov 2012 23:13:51 +0000 Subject: [PATCH 030/387] - It seems I forgot to add this stuff to the repository. SVN r3947 (trunk) --- src/oplsynth/dosbox/opl.cpp | 1453 +++++++++++++++++++++++++++++++++++ src/oplsynth/dosbox/opl.h | 231 ++++++ 2 files changed, 1684 insertions(+) create mode 100644 src/oplsynth/dosbox/opl.cpp create mode 100644 src/oplsynth/dosbox/opl.h diff --git a/src/oplsynth/dosbox/opl.cpp b/src/oplsynth/dosbox/opl.cpp new file mode 100644 index 000000000..535128aaf --- /dev/null +++ b/src/oplsynth/dosbox/opl.cpp @@ -0,0 +1,1453 @@ +/* + * Copyright (C) 2002-2011 The DOSBox Team + * OPL2/OPL3 emulation library + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + */ + +#include "doomtype.h" +#include "../opl.h" +#include "../muslib.h" +#include +#include "m_random.h" + +static FRandom pr_opl; + +typedef uintptr_t Bitu; +typedef intptr_t Bits; +typedef DWORD Bit32u; +typedef SDWORD Bit32s; +typedef WORD Bit16u; +typedef SWORD Bit16s; +typedef BYTE Bit8u; +typedef SBYTE Bit8s; + +#define OPLTYPE_IS_OPL3 +#undef PI + +#include "opl.h" + +#define HALF_PI (PI*0.5) +#define CENTER_PANNING_POWER 0.70710678118f + +static Bit16s wavtable[WAVEPREC*3]; // wave form table + +// key scale levels +static Bit8u kslev[8][16]; + +// key scale level lookup table +static const fltype kslmul[4] = { + 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct +}; + +// frequency multiplicator lookup table +static const fltype frqmul_tab[16] = { + 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 +}; + +// map a channel number to the register offset of the modulator (=register base) +static const Bit8u modulatorbase[9] = { + 0,1,2, + 8,9,10, + 16,17,18 +}; + +// map a register base to a modulator operator number or operator number +#if defined(OPLTYPE_IS_OPL3) +static const Bit8u regbase2modop[44] = { + 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set + 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set +}; +static const Bit8u regbase2op[44] = { + 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set + 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set +}; +#else +static const Bit8u regbase2modop[22] = { + 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8 +}; +static const Bit8u regbase2op[22] = { + 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17 +}; +#endif + + +// start of the waveform +static const Bit32u waveform[8] = { + WAVEPREC, + WAVEPREC>>1, + WAVEPREC, + (WAVEPREC*3)>>2, + 0, + 0, + (WAVEPREC*5)>>2, + WAVEPREC<<1 +}; + +// length of the waveform as mask +static const Bit32u wavemask[8] = { + WAVEPREC-1, + WAVEPREC-1, + (WAVEPREC>>1)-1, + (WAVEPREC>>1)-1, + WAVEPREC-1, + ((WAVEPREC*3)>>2)-1, + WAVEPREC>>1, + WAVEPREC-1 +}; + +// where the first entry resides +static const Bit32u wavestart[8] = { + 0, + WAVEPREC>>1, + 0, + WAVEPREC>>2, + 0, + 0, + 0, + WAVEPREC>>3 +}; + +// envelope generator function constants +static const fltype attackconst[4] = { + (fltype)(1/2.82624), + (fltype)(1/2.25280), + (fltype)(1/1.88416), + (fltype)(1/1.59744) +}; +static const fltype decrelconst[4] = { + (fltype)(1/39.28064), + (fltype)(1/31.41608), + (fltype)(1/26.17344), + (fltype)(1/22.44608) +}; + + +void operator_advance(op_type* op_pt, Bit32s vib) { + op_pt->wfpos = op_pt->tcount; // waveform position + + // advance waveform time + op_pt->tcount += op_pt->tinc; + op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT; + + op_pt->generator_pos += generator_add; +} + +void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) { + Bit32u c1 = op_pt1->tcount/FIXEDPT; + Bit32u c3 = op_pt3->tcount/FIXEDPT; + Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00; + + Bit32u noisebit = pr_opl.GenRand32() & 1; + + Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1); + + //Hihat + Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1))); + op_pt1->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt1->tcount += op_pt1->tinc; + op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT; + op_pt1->generator_pos += generator_add; + + //Snare + inttm = ((1+snare_phase_bit) ^ noisebit)<<8; + op_pt2->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt2->tcount += op_pt2->tinc; + op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT; + op_pt2->generator_pos += generator_add; + + //Cymbal + inttm = (1+phasebit)<<8; + op_pt3->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt3->tcount += op_pt3->tinc; + op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT; + op_pt3->generator_pos += generator_add; +} + + +// output level is sustained, mode changes only when operator is turned off (->release) +// or when the keep-sustained bit is turned off (->sustain_nokeep) +void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) { + if (op_pt->op_state != OF_TYPE_OFF) { + op_pt->lastcval = op_pt->cval; + Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT); + + // wform: -16384 to 16383 (0x4000) + // trem : 32768 to 65535 (0x10000) + // step_amp: 0.0 to 1.0 + // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000) + + op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0); + } +} + + +// no action, operator is off +void operator_off(op_type* /*op_pt*/) { +} + +// output level is sustained, mode changes only when operator is turned off (->release) +// or when the keep-sustained bit is turned off (->sustain_nokeep) +void operator_sustain(op_type* op_pt) { + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in release mode, if output level reaches zero the operator is turned off +void operator_release(op_type* op_pt) { + // ??? boundary? + if (op_pt->amp > 0.00000001) { + // release phase + op_pt->amp *= op_pt->releasemul; + } + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; // sample counter + if ((op_pt->cur_env_step & op_pt->env_step_r)==0) { + if (op_pt->amp <= 0.00000001) { + // release phase finished, turn off this operator + op_pt->amp = 0.0; + if (op_pt->op_state == OF_TYPE_REL) { + op_pt->op_state = OF_TYPE_OFF; + } + } + op_pt->step_amp = op_pt->amp; + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in decay mode, if sustain level is reached the output level is either +// kept (sustain level keep enabled) or the operator is switched into release mode +void operator_decay(op_type* op_pt) { + if (op_pt->amp > op_pt->sustain_level) { + // decay phase + op_pt->amp *= op_pt->decaymul; + } + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; + if ((op_pt->cur_env_step & op_pt->env_step_d)==0) { + if (op_pt->amp <= op_pt->sustain_level) { + // decay phase finished, sustain level reached + if (op_pt->sus_keep) { + // keep sustain level (until turned off) + op_pt->op_state = OF_TYPE_SUS; + op_pt->amp = op_pt->sustain_level; + } else { + // next: release phase + op_pt->op_state = OF_TYPE_SUS_NOKEEP; + } + } + op_pt->step_amp = op_pt->amp; + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in attack mode, if full output level is reached, +// the operator is switched into decay mode +void operator_attack(op_type* op_pt) { + op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0; + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; // next sample + if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached + if (op_pt->amp > 1.0) { + // attack phase finished, next: decay + op_pt->op_state = OF_TYPE_DEC; + op_pt->amp = 1.0; + op_pt->step_amp = 1.0; + } + op_pt->step_skip_pos_a <<= 1; + if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1; + if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step + op_pt->step_amp = op_pt->amp; + } + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + + +typedef void (*optype_fptr)(op_type*); + +optype_fptr opfuncs[6] = { + operator_attack, + operator_decay, + operator_release, + operator_sustain, // sustain phase (keeping level) + operator_release, // sustain_nokeep phase (release-style) + operator_off +}; + +void DBOPL::change_attackrate(Bitu regbase, op_type* op_pt) { + Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4; + if (attackrate) { + fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp); + // attack rate coefficients + op_pt->a0 = (fltype)(0.0377*f); + op_pt->a1 = (fltype)(10.73*f+1); + op_pt->a2 = (fltype)(-17.57*f); + op_pt->a3 = (fltype)(7.42*f); + + Bits step_skip = attackrate*4 + op_pt->toff; + Bits steps = step_skip >> 2; + op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1; + + Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0; + static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa}; + op_pt->env_step_skip_a = step_skip_mask[step_num]; + +#if defined(OPLTYPE_IS_OPL3) + if (step_skip>=60) { +#else + if (step_skip>=62) { +#endif + op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0 + op_pt->a1 = (fltype)(0.0); + op_pt->a2 = (fltype)(0.0); + op_pt->a3 = (fltype)(0.0); + } + } else { + // attack disabled + op_pt->a0 = 0.0; + op_pt->a1 = 1.0; + op_pt->a2 = 0.0; + op_pt->a3 = 0.0; + op_pt->env_step_a = 0; + op_pt->env_step_skip_a = 0; + } +} + +void DBOPL::change_decayrate(Bitu regbase, op_type* op_pt) { + Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15; + // decaymul should be 1.0 when decayrate==0 + if (decayrate) { + fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); + op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2))))); + Bits steps = (decayrate*4 + op_pt->toff) >> 2; + op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1; + } else { + op_pt->decaymul = 1.0; + op_pt->env_step_d = 0; + } +} + +void DBOPL::change_releaserate(Bitu regbase, op_type* op_pt) { + Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15; + // releasemul should be 1.0 when releaserate==0 + if (releaserate) { + fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); + op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2))))); + Bits steps = (releaserate*4 + op_pt->toff) >> 2; + op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1; + } else { + op_pt->releasemul = 1.0; + op_pt->env_step_r = 0; + } +} + +void DBOPL::change_sustainlevel(Bitu regbase, op_type* op_pt) { + Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4; + // sustainlevel should be 0.0 when sustainlevel==15 (max) + if (sustainlevel<15) { + op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05))); + } else { + op_pt->sustain_level = 0.0; + } +} + +void DBOPL::change_waveform(Bitu regbase, op_type* op_pt) { +#if defined(OPLTYPE_IS_OPL3) + if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22 +#endif + // waveform selection + op_pt->cur_wmask = wavemask[wave_sel[regbase]]; + op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]]; + // (might need to be adapted to waveform type here...) +} + +void DBOPL::change_keepsustain(Bitu regbase, op_type* op_pt) { + op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0; + if (op_pt->op_state==OF_TYPE_SUS) { + if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP; + } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) { + if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS; + } +} + +// enable/disable vibrato/tremolo LFO effects +void DBOPL::change_vibrato(Bitu regbase, op_type* op_pt) { + op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0; + op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0; +} + +// change amount of self-feedback +void DBOPL::change_feedback(Bitu chanbase, op_type* op_pt) { + Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14; + if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8))); + else op_pt->mfbi = 0; +} + +void DBOPL::change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) { + // frequency + Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase]; + // block number/octave + Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7); + op_pt->freq_high = (Bit32s)((frn>>7)&7); + + // keysplit + Bit32u note_sel = (adlibreg[8]>>6)&1; + op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)¬e_sel); + op_pt->toff += (oct<<1); + + // envelope scaling (KSR) + if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2; + + // 20+a0+b0: + op_pt->tinc = (Bit32u)((((fltype)(frn<>6]*kslev[oct][frn>>6]); + op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14))); + + // operator frequency changed, care about features that depend on it + change_attackrate(regbase,op_pt); + change_decayrate(regbase,op_pt); + change_releaserate(regbase,op_pt); +} + +void DBOPL::enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) { + // check if this is really an off-on transition + if (op_pt->act_state == OP_ACT_OFF) { + Bits wselbase = regbase; + if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22 + + op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT; + + // start with attack mode + op_pt->op_state = OF_TYPE_ATT; + op_pt->act_state |= act_type; + } +} + +void DBOPL::disable_operator(op_type* op_pt, Bit32u act_type) { + // check if this is really an on-off transition + if (op_pt->act_state != OP_ACT_OFF) { + op_pt->act_state &= (~act_type); + if (op_pt->act_state == OP_ACT_OFF) { + if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL; + } + } +} + +void DBOPL::Reset() { + Bit32u samplerate = (Bit32u)OPL_SAMPLE_RATE; + Bits i, j, oct; + + int_samplerate = samplerate; + + generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate); + + + memset((void *)adlibreg,0,sizeof(adlibreg)); + memset((void *)op,0,sizeof(op_type)*MAXOPERATORS); + memset((void *)wave_sel,0,sizeof(wave_sel)); + + for (i=0;i=0;i--) { + frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp); + } + + status = 0; + opl_index = 0; + + + // create vibrato table + vib_table[0] = 8; + vib_table[1] = 4; + vib_table[2] = 0; + vib_table[3] = -4; + for (i=4; i(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate); + vibtab_pos = 0; + + for (i=0; i -0.5/6 to 0) + for (i=14; i<41; i++) trem_table_int[i] = Bit32s(-i+14); // downwards (26 to 0 -> 0 to -1/6) + for (i=41; i<53; i++) trem_table_int[i] = Bit32s(i-40-26); // upwards (1 to 12 -> -1/6 to -0.5/6) + + for (i=0; i>1);i++) { + wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC)); + wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC)); + wavtable[i] = wavtable[(i<<1) +WAVEPREC]; + // alternative: (zero-less) +/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC)); + wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC)); + wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */ + } + for (i=0;i<(WAVEPREC>>3);i++) { + wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384; + wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384; + } + + // key scale level table verified ([table in book]*8/3) + kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37; + kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47; + kslev[7][8] = 48; + for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41); + for (j=6;j>=0;j--) { + for (i=0;i<16;i++) { + oct = (Bits)kslev[j+1][i]-8; + if (oct < 0) oct = 0; + kslev[j][i] = (Bit8u)oct; + } + } + } + +} + + + +void DBOPL::WriteReg(int idx, int val) { + Bit32u second_set = (Bit32u)idx&0x100; + adlibreg[idx] = val; + + switch (idx&0xf0) { + case ARC_CONTROL: + // here we check for the second set registers, too: + switch (idx) { + case 0x02: // timer1 counter + case 0x03: // timer2 counter + break; + case 0x04: + // IRQ reset, timer mask/start + if (val&0x80) { + // clear IRQ bits in status register + status &= ~0x60; + } else { + status = 0; + } + break; +#if defined(OPLTYPE_IS_OPL3) + case 0x04|ARC_SECONDSET: + // 4op enable/disable switches for each possible channel + op[0].is_4op = (val&1)>0; + op[3].is_4op_attached = op[0].is_4op; + op[1].is_4op = (val&2)>0; + op[4].is_4op_attached = op[1].is_4op; + op[2].is_4op = (val&4)>0; + op[5].is_4op_attached = op[2].is_4op; + op[18].is_4op = (val&8)>0; + op[21].is_4op_attached = op[18].is_4op; + op[19].is_4op = (val&16)>0; + op[22].is_4op_attached = op[19].is_4op; + op[20].is_4op = (val&32)>0; + op[23].is_4op_attached = op[20].is_4op; + break; + case 0x05|ARC_SECONDSET: + break; +#endif + case 0x08: + // CSW, note select + break; + default: + break; + } + break; + case ARC_TVS_KSR_MUL: + case ARC_TVS_KSR_MUL+0x10: { + // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication + int num = (int)idx&7; + Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff; + if ((num<6) && (base<22)) { + Bitu modop = regbase2modop[second_set?(base+22):base]; + Bitu regbase = base+second_set; + Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; + + // change tremolo/vibrato and sustain keeping of this operator + op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; + change_keepsustain(regbase,op_ptr); + change_vibrato(regbase,op_ptr); + + // change frequency calculations of this operator as + // key scale rate and frequency multiplicator can be changed +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { + // operator uses frequency of channel + change_frequency(chanbase-3,regbase,op_ptr); + } else { + change_frequency(chanbase,regbase,op_ptr); + } +#else + change_frequency(chanbase,base,op_ptr); +#endif + } + } + break; + case ARC_KSL_OUTLEV: + case ARC_KSL_OUTLEV+0x10: { + // key scale level; output rate + int num = (int)idx&7; + Bitu base = (idx-ARC_KSL_OUTLEV)&0xff; + if ((num<6) && (base<22)) { + Bitu modop = regbase2modop[second_set?(base+22):base]; + Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; + + // change frequency calculations of this operator as + // key scale level and output rate can be changed + op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; +#if defined(OPLTYPE_IS_OPL3) + Bitu regbase = base+second_set; + if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { + // operator uses frequency of channel + change_frequency(chanbase-3,regbase,op_ptr); + } else { + change_frequency(chanbase,regbase,op_ptr); + } +#else + change_frequency(chanbase,base,op_ptr); +#endif + } + } + break; + case ARC_ATTR_DECR: + case ARC_ATTR_DECR+0x10: { + // attack/decay rates + int num = (int)idx&7; + Bitu base = (idx-ARC_ATTR_DECR)&0xff; + if ((num<6) && (base<22)) { + Bitu regbase = base+second_set; + + // change attack rate and decay rate of this operator + op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; + change_attackrate(regbase,op_ptr); + change_decayrate(regbase,op_ptr); + } + } + break; + case ARC_SUSL_RELR: + case ARC_SUSL_RELR+0x10: { + // sustain level; release rate + int num = (int)idx&7; + Bitu base = (idx-ARC_SUSL_RELR)&0xff; + if ((num<6) && (base<22)) { + Bitu regbase = base+second_set; + + // change sustain level and release rate of this operator + op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; + change_releaserate(regbase,op_ptr); + change_sustainlevel(regbase,op_ptr); + } + } + break; + case ARC_FREQ_NUM: { + // 0xa0-0xa8 low8 frequency + Bitu base = (idx-ARC_FREQ_NUM)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; +#endif + // regbase of modulator: + Bits modbase = modulatorbase[base]+second_set; + + Bitu chanbase = base+second_set; + + change_frequency(chanbase,modbase,&op[opbase]); + change_frequency(chanbase,modbase+3,&op[opbase+9]); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are modified to the frequency of the channel + if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { + change_frequency(chanbase,modbase+8,&op[opbase+3]); + change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); + } +#endif + } + } + break; + case ARC_KON_BNUM: { + if (idx == ARC_PERC_MODE) { +#if defined(OPLTYPE_IS_OPL3) + if (second_set) return; +#endif + + if ((val&0x30) == 0x30) { // BassDrum active + enable_operator(16,&op[6],OP_ACT_PERC); + change_frequency(6,16,&op[6]); + enable_operator(16+3,&op[6+9],OP_ACT_PERC); + change_frequency(6,16+3,&op[6+9]); + } else { + disable_operator(&op[6],OP_ACT_PERC); + disable_operator(&op[6+9],OP_ACT_PERC); + } + if ((val&0x28) == 0x28) { // Snare active + enable_operator(17+3,&op[16],OP_ACT_PERC); + change_frequency(7,17+3,&op[16]); + } else { + disable_operator(&op[16],OP_ACT_PERC); + } + if ((val&0x24) == 0x24) { // TomTom active + enable_operator(18,&op[8],OP_ACT_PERC); + change_frequency(8,18,&op[8]); + } else { + disable_operator(&op[8],OP_ACT_PERC); + } + if ((val&0x22) == 0x22) { // Cymbal active + enable_operator(18+3,&op[8+9],OP_ACT_PERC); + change_frequency(8,18+3,&op[8+9]); + } else { + disable_operator(&op[8+9],OP_ACT_PERC); + } + if ((val&0x21) == 0x21) { // Hihat active + enable_operator(17,&op[7],OP_ACT_PERC); + change_frequency(7,17,&op[7]); + } else { + disable_operator(&op[7],OP_ACT_PERC); + } + + break; + } + // regular 0xb0-0xb8 + Bitu base = (idx-ARC_KON_BNUM)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; +#endif + // regbase of modulator: + Bits modbase = modulatorbase[base]+second_set; + + if (val&32) { + // operator switched on + enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op) + enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op) +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are switched on + if ((adlibreg[0x105]&1) && op[opbase].is_4op) { + // turn on chan+3 operators as well + enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL); + enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL); + } +#endif + } else { + // operator switched off + disable_operator(&op[opbase],OP_ACT_NORMAL); + disable_operator(&op[opbase+9],OP_ACT_NORMAL); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are switched off + if ((adlibreg[0x105]&1) && op[opbase].is_4op) { + // turn off chan+3 operators as well + disable_operator(&op[opbase+3],OP_ACT_NORMAL); + disable_operator(&op[opbase+3+9],OP_ACT_NORMAL); + } +#endif + } + + Bitu chanbase = base+second_set; + + // change frequency calculations of modulator and carrier (2op) as + // the frequency of the channel has changed + change_frequency(chanbase,modbase,&op[opbase]); + change_frequency(chanbase,modbase+3,&op[opbase+9]); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are modified to the frequency of the channel + if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { + // change frequency calculations of chan+3 operators as well + change_frequency(chanbase,modbase+8,&op[opbase+3]); + change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); + } +#endif + } + } + break; + case ARC_FEEDBACK: { + // 0xc0-0xc8 feedback/modulation type (AM/FM) + Bitu base = (idx-ARC_FEEDBACK)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; + Bitu chanbase = base+second_set; + change_feedback(chanbase,&op[opbase]); +#if defined(OPLTYPE_IS_OPL3) + // OPL3 panning + if (!FullPan) + { + op[opbase].left_pan = (float)((val&0x10)>>4); + op[opbase].right_pan = (float)((val&0x20)>>5); + } +#endif + } + } + break; + case ARC_WAVE_SEL: + case ARC_WAVE_SEL+0x10: { + int num = (int)idx&7; + Bitu base = (idx-ARC_WAVE_SEL)&0xff; + if ((num<6) && (base<22)) { +#if defined(OPLTYPE_IS_OPL3) + Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[] + // change waveform + if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible + else wave_sel[wselbase] = val&3; + op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)]; + change_waveform(wselbase,op_ptr); +#else + if (adlibreg[0x01]&0x20) { + // wave selection enabled, change waveform + wave_sel[base] = val&3; + op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)]; + change_waveform(base,op_ptr); + } +#endif + } + } + break; + default: + break; + } +} + +static void OPL_INLINE clipit16(float ival, float* outval) { + *outval += ival / 10240.f; +} + + + +// be careful with this +// uses cptr and chanval, outputs into outbufl(/outbufr) +// for opl3 check if opl3-mode is enabled (which uses stereo panning) +#undef CHANVAL_OUT +#if defined(OPLTYPE_IS_OPL3) +#define CHANVAL_OUT \ + if (adlibreg[0x105]&1) { \ + outbufl[i] += chanval*cptr[0].left_pan; \ + outbufr[i] += chanval*cptr[0].right_pan; \ + } else { \ + outbufl[i] += chanval; \ + } +#else +#define CHANVAL_OUT \ + outbufl[i] += chanval; +#endif + +void DBOPL::Update(float* sndptr, int numsamples) { + Bits i, endsamples; + op_type* cptr; + + float outbufl[BLOCKBUF_SIZE]; +#if defined(OPLTYPE_IS_OPL3) + // second output buffer (right channel for opl3 stereo) + float outbufr[BLOCKBUF_SIZE]; +#endif + + // vibrato/tremolo lookup tables (global, to possibly be used by all operators) + Bit32s vib_lut[BLOCKBUF_SIZE]; + Bit32s trem_lut[BLOCKBUF_SIZE]; + + Bits samples_to_process = numsamples; + + for (Bits cursmp=0; cursmpBLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE; + + memset((void*)&outbufl,0,endsamples*sizeof(Bit32s)); +#if defined(OPLTYPE_IS_OPL3) + // clear second output buffer (opl3 stereo) + if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s)); +#endif + + // calculate vibrato/tremolo lookup tables + Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching + for (i=0;i=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO; + vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents + + // cycle through tremolo table + tremtab_pos += tremtab_add; + if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO; + if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO]; + else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO]; + } + + if (adlibreg[ARC_PERC_MODE]&0x20) { + //BassDrum + cptr = &op[6]; + if (adlibreg[ARC_FEEDBACK+6]&1) { + // additive synthesis + if (cptr[9].op_state != OF_TYPE_OFF) { + if (cptr[9].vibrato) { + vibval1 = vibval_var1; + for (i=0;i=0; cur_ch--) { + // skip drum/percussion operators + if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue; + + Bitu k = cur_ch; +#if defined(OPLTYPE_IS_OPL3) + if (cur_ch < 9) { + cptr = &op[cur_ch]; + } else { + cptr = &op[cur_ch+9]; // second set is operator18-operator35 + k += (-9+256); // second set uses registers 0x100 onwards + } + // check if this operator is part of a 4-op + if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue; +#else + cptr = &op[cur_ch]; +#endif + + // check for FM/AM + if (adlibreg[ARC_FEEDBACK+k]&1) { +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && cptr->is_4op) { + if (adlibreg[ARC_FEEDBACK+k+3]&1) { + // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4) + if (cptr[0].op_state != OF_TYPE_OFF) { + if (cptr[0].vibrato) { + vibval1 = vibval_var1; + for (i=0;iis_4op) { + if (adlibreg[ARC_FEEDBACK+k+3]&1) { + // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4)) + if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) { + if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) { + vibval1 = vibval_var1; + for (i=0;istereo) + for (i=0;istereo) + for (i=0;i= 9) + { + c += 9; + } + // This is the MIDI-recommended pan formula. 0 and 1 are + // both hard left so that 64 can be perfectly center. + double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; + op[c].left_pan = (float)cos(HALF_PI * level); + op[c].right_pan = (float)sin(HALF_PI * level); + } +} + +DBOPL::DBOPL(bool fullpan) +{ + FullPan = fullpan; + Reset(); +} + +OPLEmul *DBOPLCreate(bool fullpan) +{ + return new DBOPL(fullpan); +} diff --git a/src/oplsynth/dosbox/opl.h b/src/oplsynth/dosbox/opl.h new file mode 100644 index 000000000..ab42c54ff --- /dev/null +++ b/src/oplsynth/dosbox/opl.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2002-2011 The DOSBox Team + * OPL2/OPL3 emulation library + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + */ + + +#define fltype double + +/* + define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here +*/ +/* +#include +typedef uintptr_t Bitu; +typedef intptr_t Bits; +typedef uint32_t Bit32u; +typedef int32_t Bit32s; +typedef uint16_t Bit16u; +typedef int16_t Bit16s; +typedef uint8_t Bit8u; +typedef int8_t Bit8s; +*/ + + +/* + define attribution that inlines/forces inlining of a function (optional) +*/ +#define OPL_INLINE inline + + +#undef NUM_CHANNELS +#if defined(OPLTYPE_IS_OPL3) +#define NUM_CHANNELS 18 +#else +#define NUM_CHANNELS 9 +#endif + +#define MAXOPERATORS (NUM_CHANNELS*2) + + +#define FL05 ((fltype)0.5) +#define FL2 ((fltype)2.0) +#define PI ((fltype)3.1415926535897932384626433832795) + + +#define FIXEDPT 0x10000 // fixed-point calculations using 16+16 +#define FIXEDPT_LFO 0x1000000 // fixed-point calculations using 8+24 + +#define WAVEPREC 1024 // waveform precision (10 bits) + +#define INTFREQU ((fltype)(14318180.0 / 288.0)) // clocking of the chip + + +#define OF_TYPE_ATT 0 +#define OF_TYPE_DEC 1 +#define OF_TYPE_REL 2 +#define OF_TYPE_SUS 3 +#define OF_TYPE_SUS_NOKEEP 4 +#define OF_TYPE_OFF 5 + +#define ARC_CONTROL 0x00 +#define ARC_TVS_KSR_MUL 0x20 +#define ARC_KSL_OUTLEV 0x40 +#define ARC_ATTR_DECR 0x60 +#define ARC_SUSL_RELR 0x80 +#define ARC_FREQ_NUM 0xa0 +#define ARC_KON_BNUM 0xb0 +#define ARC_PERC_MODE 0xbd +#define ARC_FEEDBACK 0xc0 +#define ARC_WAVE_SEL 0xe0 + +#define ARC_SECONDSET 0x100 // second operator set for OPL3 + + +#define OP_ACT_OFF 0x00 +#define OP_ACT_NORMAL 0x01 // regular channel activated (bitmasked) +#define OP_ACT_PERC 0x02 // percussion channel activated (bitmasked) + +#define BLOCKBUF_SIZE 512 + + +// vibrato constants +#define VIBTAB_SIZE 8 +#define VIBFAC 70/50000 // no braces, integer mul/div + +// tremolo constants and table +#define TREMTAB_SIZE 53 +#define TREM_FREQ ((fltype)(3.7)) // tremolo at 3.7hz + + +/* operator struct definition + For OPL2 all 9 channels consist of two operators each, carrier and modulator. + Channel x has operators x as modulator and operators (9+x) as carrier. + For OPL3 all 18 channels consist either of two operators (2op mode) or four + operators (4op mode) which is determined through register4 of the second + adlib register set. + Only the channels 0,1,2 (first set) and 9,10,11 (second set) can act as + 4op channels. The two additional operators for a channel y come from the + 2op channel y+3 so the operatorss y, (9+y), y+3, (9+y)+3 make up a 4op + channel. +*/ +typedef struct operator_struct { + Bit32s cval, lastcval; // current output/last output (used for feedback) + Bit32u tcount, wfpos, tinc; // time (position in waveform) and time increment + fltype amp, step_amp; // and amplification (envelope) + fltype vol; // volume + fltype sustain_level; // sustain level + Bit32s mfbi; // feedback amount + fltype a0, a1, a2, a3; // attack rate function coefficients + fltype decaymul, releasemul; // decay/release rate functions + Bit32u op_state; // current state of operator (attack/decay/sustain/release/off) + Bit32u toff; + Bit32s freq_high; // highest three bits of the frequency, used for vibrato calculations + Bit16s* cur_wform; // start of selected waveform + Bit32u cur_wmask; // mask for selected waveform + Bit32u act_state; // activity state (regular, percussion) + bool sus_keep; // keep sustain level when decay finished + bool vibrato,tremolo; // vibrato/tremolo enable bits + + // variables used to provide non-continuous envelopes + Bit32u generator_pos; // for non-standard sample rates we need to determine how many samples have passed + Bits cur_env_step; // current (standardized) sample position + Bits env_step_a,env_step_d,env_step_r; // number of std samples of one step (for attack/decay/release mode) + Bit8u step_skip_pos_a; // position of 8-cyclic step skipping (always 2^x to check against mask) + Bits env_step_skip_a; // bitmask that determines if a step is skipped (respective bit is zero then) + +#if defined(OPLTYPE_IS_OPL3) + bool is_4op,is_4op_attached; // base of a 4op channel/part of a 4op channel + float left_pan,right_pan; // opl3 stereo panning amount +#endif +} op_type; + +// per-chip variables +class DBOPL : public OPLEmul +{ +private: + Bitu chip_num; + op_type op[MAXOPERATORS]; + + Bits int_samplerate; + + Bit8u status; + Bit32u opl_index; +#if defined(OPLTYPE_IS_OPL3) + Bit8u adlibreg[512]; // adlib register set (including second set) + Bit8u wave_sel[44]; // waveform selection +#else + Bit8u adlibreg[256]; // adlib register set + Bit8u wave_sel[22]; // waveform selection +#endif + + fltype recipsamp; // inverse of sampling rate + + // vibrato/tremolo tables + Bit32s vib_table[VIBTAB_SIZE]; + Bit32s trem_table[TREMTAB_SIZE*2]; + + Bit32s vibval_const[BLOCKBUF_SIZE]; + Bit32s tremval_const[BLOCKBUF_SIZE]; + + // vibrato value tables (used per-operator) + Bit32s vibval_var1[BLOCKBUF_SIZE]; + Bit32s vibval_var2[BLOCKBUF_SIZE]; + + // vibrato/trmolo value table pointers + Bit32s *vibval1, *vibval2, *vibval3, *vibval4; + Bit32s *tremval1, *tremval2, *tremval3, *tremval4; + + // calculated frequency multiplication values (depend on sampling rate) + fltype frqmul[16]; + + + // vibrato/tremolo increment/counter + Bit32u vibtab_pos; + Bit32u vibtab_add; + Bit32u tremtab_pos; + Bit32u tremtab_add; + + // Enable full MIDI panning; disable OPL3 panning + bool FullPan; + + + // enable an operator + void enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type); + + void disable_operator(op_type* op_pt, Bit32u act_type); + + // functions to change parameters of an operator + void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt); + + void change_attackrate(Bitu regbase, op_type* op_pt); + void change_decayrate(Bitu regbase, op_type* op_pt); + void change_releaserate(Bitu regbase, op_type* op_pt); + void change_sustainlevel(Bitu regbase, op_type* op_pt); + void change_waveform(Bitu regbase, op_type* op_pt); + void change_keepsustain(Bitu regbase, op_type* op_pt); + void change_vibrato(Bitu regbase, op_type* op_pt); + void change_feedback(Bitu chanbase, op_type* op_pt); + + // general functions +public: + void Reset(); + void Update(float* sndptr, int numsamples); + void WriteReg(int idx, int val); + void SetPanning(int c, int pan); + + DBOPL(bool stereo); +}; + +static Bit32u generator_add; // should be a chip parameter From b51393147302e27e9224dfc3b17ba0184d5a4ca1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 04:53:31 +0000 Subject: [PATCH 031/387] - Move panning volume calculation out of the OPL chips and into the player. SVN r3948 (trunk) --- src/oplsynth/dosbox/opl.cpp | 2884 +++++++++++++++++------------------ src/oplsynth/dosbox/opl.h | 2 +- src/oplsynth/fmopl.cpp | 10 +- src/oplsynth/mlopl_io.cpp | 10 +- src/oplsynth/opl.h | 2 +- 5 files changed, 1454 insertions(+), 1454 deletions(-) diff --git a/src/oplsynth/dosbox/opl.cpp b/src/oplsynth/dosbox/opl.cpp index 535128aaf..cfabbc91b 100644 --- a/src/oplsynth/dosbox/opl.cpp +++ b/src/oplsynth/dosbox/opl.cpp @@ -1,1453 +1,1449 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * OPL2/OPL3 emulation library - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -/* - * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman - * Copyright (C) 1998-2001 Ken Silverman - * Ken Silverman's official web site: "http://www.advsys.net/ken" - */ - +/* + * Copyright (C) 2002-2011 The DOSBox Team + * OPL2/OPL3 emulation library + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + */ + #include "doomtype.h" #include "../opl.h" #include "../muslib.h" -#include -#include "m_random.h" - -static FRandom pr_opl; - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef DWORD Bit32u; -typedef SDWORD Bit32s; -typedef WORD Bit16u; -typedef SWORD Bit16s; -typedef BYTE Bit8u; -typedef SBYTE Bit8s; +#include +#include "m_random.h" + +static FRandom pr_opl; + +typedef uintptr_t Bitu; +typedef intptr_t Bits; +typedef DWORD Bit32u; +typedef SDWORD Bit32s; +typedef WORD Bit16u; +typedef SWORD Bit16s; +typedef BYTE Bit8u; +typedef SBYTE Bit8s; #define OPLTYPE_IS_OPL3 #undef PI -#include "opl.h" - -#define HALF_PI (PI*0.5) +#include "opl.h" + #define CENTER_PANNING_POWER 0.70710678118f - -static Bit16s wavtable[WAVEPREC*3]; // wave form table - -// key scale levels -static Bit8u kslev[8][16]; - -// key scale level lookup table -static const fltype kslmul[4] = { - 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct -}; - -// frequency multiplicator lookup table -static const fltype frqmul_tab[16] = { - 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 -}; - -// map a channel number to the register offset of the modulator (=register base) -static const Bit8u modulatorbase[9] = { - 0,1,2, - 8,9,10, - 16,17,18 -}; - -// map a register base to a modulator operator number or operator number -#if defined(OPLTYPE_IS_OPL3) -static const Bit8u regbase2modop[44] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set - 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set -}; -static const Bit8u regbase2op[44] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set - 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set -}; -#else -static const Bit8u regbase2modop[22] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8 -}; -static const Bit8u regbase2op[22] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17 -}; -#endif - - -// start of the waveform -static const Bit32u waveform[8] = { - WAVEPREC, - WAVEPREC>>1, - WAVEPREC, - (WAVEPREC*3)>>2, - 0, - 0, - (WAVEPREC*5)>>2, - WAVEPREC<<1 -}; - -// length of the waveform as mask -static const Bit32u wavemask[8] = { - WAVEPREC-1, - WAVEPREC-1, - (WAVEPREC>>1)-1, - (WAVEPREC>>1)-1, - WAVEPREC-1, - ((WAVEPREC*3)>>2)-1, - WAVEPREC>>1, - WAVEPREC-1 -}; - -// where the first entry resides -static const Bit32u wavestart[8] = { - 0, - WAVEPREC>>1, - 0, - WAVEPREC>>2, - 0, - 0, - 0, - WAVEPREC>>3 -}; - -// envelope generator function constants -static const fltype attackconst[4] = { - (fltype)(1/2.82624), - (fltype)(1/2.25280), - (fltype)(1/1.88416), - (fltype)(1/1.59744) -}; -static const fltype decrelconst[4] = { - (fltype)(1/39.28064), - (fltype)(1/31.41608), - (fltype)(1/26.17344), - (fltype)(1/22.44608) -}; - - -void operator_advance(op_type* op_pt, Bit32s vib) { - op_pt->wfpos = op_pt->tcount; // waveform position - - // advance waveform time - op_pt->tcount += op_pt->tinc; - op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT; - - op_pt->generator_pos += generator_add; -} - -void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) { - Bit32u c1 = op_pt1->tcount/FIXEDPT; - Bit32u c3 = op_pt3->tcount/FIXEDPT; - Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00; - - Bit32u noisebit = pr_opl.GenRand32() & 1; - - Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1); - - //Hihat - Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1))); - op_pt1->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt1->tcount += op_pt1->tinc; - op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT; - op_pt1->generator_pos += generator_add; - - //Snare - inttm = ((1+snare_phase_bit) ^ noisebit)<<8; - op_pt2->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt2->tcount += op_pt2->tinc; - op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT; - op_pt2->generator_pos += generator_add; - - //Cymbal - inttm = (1+phasebit)<<8; - op_pt3->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt3->tcount += op_pt3->tinc; - op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT; - op_pt3->generator_pos += generator_add; -} - - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) { - if (op_pt->op_state != OF_TYPE_OFF) { - op_pt->lastcval = op_pt->cval; - Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT); - - // wform: -16384 to 16383 (0x4000) - // trem : 32768 to 65535 (0x10000) - // step_amp: 0.0 to 1.0 - // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000) - - op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0); - } -} - - -// no action, operator is off -void operator_off(op_type* /*op_pt*/) { -} - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_sustain(op_type* op_pt) { - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in release mode, if output level reaches zero the operator is turned off -void operator_release(op_type* op_pt) { - // ??? boundary? - if (op_pt->amp > 0.00000001) { - // release phase - op_pt->amp *= op_pt->releasemul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // sample counter - if ((op_pt->cur_env_step & op_pt->env_step_r)==0) { - if (op_pt->amp <= 0.00000001) { - // release phase finished, turn off this operator - op_pt->amp = 0.0; - if (op_pt->op_state == OF_TYPE_REL) { - op_pt->op_state = OF_TYPE_OFF; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in decay mode, if sustain level is reached the output level is either -// kept (sustain level keep enabled) or the operator is switched into release mode -void operator_decay(op_type* op_pt) { - if (op_pt->amp > op_pt->sustain_level) { - // decay phase - op_pt->amp *= op_pt->decaymul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - if ((op_pt->cur_env_step & op_pt->env_step_d)==0) { - if (op_pt->amp <= op_pt->sustain_level) { - // decay phase finished, sustain level reached - if (op_pt->sus_keep) { - // keep sustain level (until turned off) - op_pt->op_state = OF_TYPE_SUS; - op_pt->amp = op_pt->sustain_level; - } else { - // next: release phase - op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in attack mode, if full output level is reached, -// the operator is switched into decay mode -void operator_attack(op_type* op_pt) { - op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0; - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // next sample - if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached - if (op_pt->amp > 1.0) { - // attack phase finished, next: decay - op_pt->op_state = OF_TYPE_DEC; - op_pt->amp = 1.0; - op_pt->step_amp = 1.0; - } - op_pt->step_skip_pos_a <<= 1; - if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1; - if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step - op_pt->step_amp = op_pt->amp; - } - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - - -typedef void (*optype_fptr)(op_type*); - -optype_fptr opfuncs[6] = { - operator_attack, - operator_decay, - operator_release, - operator_sustain, // sustain phase (keeping level) - operator_release, // sustain_nokeep phase (release-style) - operator_off -}; - -void DBOPL::change_attackrate(Bitu regbase, op_type* op_pt) { - Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4; - if (attackrate) { - fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp); - // attack rate coefficients - op_pt->a0 = (fltype)(0.0377*f); - op_pt->a1 = (fltype)(10.73*f+1); - op_pt->a2 = (fltype)(-17.57*f); - op_pt->a3 = (fltype)(7.42*f); - - Bits step_skip = attackrate*4 + op_pt->toff; - Bits steps = step_skip >> 2; - op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1; - - Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0; - static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa}; - op_pt->env_step_skip_a = step_skip_mask[step_num]; - -#if defined(OPLTYPE_IS_OPL3) - if (step_skip>=60) { -#else - if (step_skip>=62) { -#endif - op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0 - op_pt->a1 = (fltype)(0.0); - op_pt->a2 = (fltype)(0.0); - op_pt->a3 = (fltype)(0.0); - } - } else { - // attack disabled - op_pt->a0 = 0.0; - op_pt->a1 = 1.0; - op_pt->a2 = 0.0; - op_pt->a3 = 0.0; - op_pt->env_step_a = 0; - op_pt->env_step_skip_a = 0; - } -} - -void DBOPL::change_decayrate(Bitu regbase, op_type* op_pt) { - Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15; - // decaymul should be 1.0 when decayrate==0 - if (decayrate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2))))); - Bits steps = (decayrate*4 + op_pt->toff) >> 2; - op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->decaymul = 1.0; - op_pt->env_step_d = 0; - } -} - -void DBOPL::change_releaserate(Bitu regbase, op_type* op_pt) { - Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15; - // releasemul should be 1.0 when releaserate==0 - if (releaserate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2))))); - Bits steps = (releaserate*4 + op_pt->toff) >> 2; - op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->releasemul = 1.0; - op_pt->env_step_r = 0; - } -} - -void DBOPL::change_sustainlevel(Bitu regbase, op_type* op_pt) { - Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4; - // sustainlevel should be 0.0 when sustainlevel==15 (max) - if (sustainlevel<15) { - op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05))); - } else { - op_pt->sustain_level = 0.0; - } -} - -void DBOPL::change_waveform(Bitu regbase, op_type* op_pt) { -#if defined(OPLTYPE_IS_OPL3) - if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22 -#endif - // waveform selection - op_pt->cur_wmask = wavemask[wave_sel[regbase]]; - op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]]; - // (might need to be adapted to waveform type here...) -} - -void DBOPL::change_keepsustain(Bitu regbase, op_type* op_pt) { - op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0; - if (op_pt->op_state==OF_TYPE_SUS) { - if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) { - if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS; - } -} - -// enable/disable vibrato/tremolo LFO effects -void DBOPL::change_vibrato(Bitu regbase, op_type* op_pt) { - op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0; - op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0; -} - -// change amount of self-feedback -void DBOPL::change_feedback(Bitu chanbase, op_type* op_pt) { - Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14; - if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8))); - else op_pt->mfbi = 0; -} - -void DBOPL::change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) { - // frequency - Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase]; - // block number/octave - Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7); - op_pt->freq_high = (Bit32s)((frn>>7)&7); - - // keysplit - Bit32u note_sel = (adlibreg[8]>>6)&1; - op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)¬e_sel); - op_pt->toff += (oct<<1); - - // envelope scaling (KSR) - if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2; - - // 20+a0+b0: - op_pt->tinc = (Bit32u)((((fltype)(frn<>6]*kslev[oct][frn>>6]); - op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14))); - - // operator frequency changed, care about features that depend on it - change_attackrate(regbase,op_pt); - change_decayrate(regbase,op_pt); - change_releaserate(regbase,op_pt); -} - -void DBOPL::enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) { - // check if this is really an off-on transition - if (op_pt->act_state == OP_ACT_OFF) { - Bits wselbase = regbase; - if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22 - - op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT; - - // start with attack mode - op_pt->op_state = OF_TYPE_ATT; - op_pt->act_state |= act_type; - } -} - -void DBOPL::disable_operator(op_type* op_pt, Bit32u act_type) { - // check if this is really an on-off transition - if (op_pt->act_state != OP_ACT_OFF) { - op_pt->act_state &= (~act_type); - if (op_pt->act_state == OP_ACT_OFF) { - if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL; - } - } -} - -void DBOPL::Reset() { - Bit32u samplerate = (Bit32u)OPL_SAMPLE_RATE; - Bits i, j, oct; - - int_samplerate = samplerate; - - generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate); - - - memset((void *)adlibreg,0,sizeof(adlibreg)); - memset((void *)op,0,sizeof(op_type)*MAXOPERATORS); - memset((void *)wave_sel,0,sizeof(wave_sel)); - - for (i=0;i=0;i--) { - frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp); - } - - status = 0; - opl_index = 0; - - - // create vibrato table - vib_table[0] = 8; - vib_table[1] = 4; - vib_table[2] = 0; - vib_table[3] = -4; - for (i=4; i(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate); - vibtab_pos = 0; - - for (i=0; i -0.5/6 to 0) - for (i=14; i<41; i++) trem_table_int[i] = Bit32s(-i+14); // downwards (26 to 0 -> 0 to -1/6) - for (i=41; i<53; i++) trem_table_int[i] = Bit32s(i-40-26); // upwards (1 to 12 -> -1/6 to -0.5/6) - - for (i=0; i>1);i++) { - wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC)); - wavtable[i] = wavtable[(i<<1) +WAVEPREC]; - // alternative: (zero-less) -/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC)); - wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */ - } - for (i=0;i<(WAVEPREC>>3);i++) { - wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384; - wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384; - } - - // key scale level table verified ([table in book]*8/3) - kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37; - kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47; - kslev[7][8] = 48; - for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41); - for (j=6;j>=0;j--) { - for (i=0;i<16;i++) { - oct = (Bits)kslev[j+1][i]-8; - if (oct < 0) oct = 0; - kslev[j][i] = (Bit8u)oct; - } - } - } - -} - - - -void DBOPL::WriteReg(int idx, int val) { - Bit32u second_set = (Bit32u)idx&0x100; - adlibreg[idx] = val; - - switch (idx&0xf0) { - case ARC_CONTROL: - // here we check for the second set registers, too: - switch (idx) { - case 0x02: // timer1 counter - case 0x03: // timer2 counter - break; - case 0x04: - // IRQ reset, timer mask/start - if (val&0x80) { - // clear IRQ bits in status register - status &= ~0x60; - } else { - status = 0; - } - break; -#if defined(OPLTYPE_IS_OPL3) - case 0x04|ARC_SECONDSET: - // 4op enable/disable switches for each possible channel - op[0].is_4op = (val&1)>0; - op[3].is_4op_attached = op[0].is_4op; - op[1].is_4op = (val&2)>0; - op[4].is_4op_attached = op[1].is_4op; - op[2].is_4op = (val&4)>0; - op[5].is_4op_attached = op[2].is_4op; - op[18].is_4op = (val&8)>0; - op[21].is_4op_attached = op[18].is_4op; - op[19].is_4op = (val&16)>0; - op[22].is_4op_attached = op[19].is_4op; - op[20].is_4op = (val&32)>0; - op[23].is_4op_attached = op[20].is_4op; - break; - case 0x05|ARC_SECONDSET: - break; -#endif - case 0x08: - // CSW, note select - break; - default: - break; - } - break; - case ARC_TVS_KSR_MUL: - case ARC_TVS_KSR_MUL+0x10: { - // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication - int num = (int)idx&7; - Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu regbase = base+second_set; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change tremolo/vibrato and sustain keeping of this operator - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; - change_keepsustain(regbase,op_ptr); - change_vibrato(regbase,op_ptr); - - // change frequency calculations of this operator as - // key scale rate and frequency multiplicator can be changed -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_KSL_OUTLEV: - case ARC_KSL_OUTLEV+0x10: { - // key scale level; output rate - int num = (int)idx&7; - Bitu base = (idx-ARC_KSL_OUTLEV)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change frequency calculations of this operator as - // key scale level and output rate can be changed - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; -#if defined(OPLTYPE_IS_OPL3) - Bitu regbase = base+second_set; - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_ATTR_DECR: - case ARC_ATTR_DECR+0x10: { - // attack/decay rates - int num = (int)idx&7; - Bitu base = (idx-ARC_ATTR_DECR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change attack rate and decay rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_attackrate(regbase,op_ptr); - change_decayrate(regbase,op_ptr); - } - } - break; - case ARC_SUSL_RELR: - case ARC_SUSL_RELR+0x10: { - // sustain level; release rate - int num = (int)idx&7; - Bitu base = (idx-ARC_SUSL_RELR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change sustain level and release rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_releaserate(regbase,op_ptr); - change_sustainlevel(regbase,op_ptr); - } - } - break; - case ARC_FREQ_NUM: { - // 0xa0-0xa8 low8 frequency - Bitu base = (idx-ARC_FREQ_NUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - Bitu chanbase = base+second_set; - - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_KON_BNUM: { - if (idx == ARC_PERC_MODE) { -#if defined(OPLTYPE_IS_OPL3) - if (second_set) return; -#endif - - if ((val&0x30) == 0x30) { // BassDrum active - enable_operator(16,&op[6],OP_ACT_PERC); - change_frequency(6,16,&op[6]); - enable_operator(16+3,&op[6+9],OP_ACT_PERC); - change_frequency(6,16+3,&op[6+9]); - } else { - disable_operator(&op[6],OP_ACT_PERC); - disable_operator(&op[6+9],OP_ACT_PERC); - } - if ((val&0x28) == 0x28) { // Snare active - enable_operator(17+3,&op[16],OP_ACT_PERC); - change_frequency(7,17+3,&op[16]); - } else { - disable_operator(&op[16],OP_ACT_PERC); - } - if ((val&0x24) == 0x24) { // TomTom active - enable_operator(18,&op[8],OP_ACT_PERC); - change_frequency(8,18,&op[8]); - } else { - disable_operator(&op[8],OP_ACT_PERC); - } - if ((val&0x22) == 0x22) { // Cymbal active - enable_operator(18+3,&op[8+9],OP_ACT_PERC); - change_frequency(8,18+3,&op[8+9]); - } else { - disable_operator(&op[8+9],OP_ACT_PERC); - } - if ((val&0x21) == 0x21) { // Hihat active - enable_operator(17,&op[7],OP_ACT_PERC); - change_frequency(7,17,&op[7]); - } else { - disable_operator(&op[7],OP_ACT_PERC); - } - - break; - } - // regular 0xb0-0xb8 - Bitu base = (idx-ARC_KON_BNUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - if (val&32) { - // operator switched on - enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op) - enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op) -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched on - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn on chan+3 operators as well - enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL); - enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } else { - // operator switched off - disable_operator(&op[opbase],OP_ACT_NORMAL); - disable_operator(&op[opbase+9],OP_ACT_NORMAL); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched off - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn off chan+3 operators as well - disable_operator(&op[opbase+3],OP_ACT_NORMAL); - disable_operator(&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } - - Bitu chanbase = base+second_set; - - // change frequency calculations of modulator and carrier (2op) as - // the frequency of the channel has changed - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - // change frequency calculations of chan+3 operators as well - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_FEEDBACK: { - // 0xc0-0xc8 feedback/modulation type (AM/FM) - Bitu base = (idx-ARC_FEEDBACK)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; - Bitu chanbase = base+second_set; - change_feedback(chanbase,&op[opbase]); -#if defined(OPLTYPE_IS_OPL3) - // OPL3 panning - if (!FullPan) - { - op[opbase].left_pan = (float)((val&0x10)>>4); - op[opbase].right_pan = (float)((val&0x20)>>5); - } -#endif - } - } - break; - case ARC_WAVE_SEL: - case ARC_WAVE_SEL+0x10: { - int num = (int)idx&7; - Bitu base = (idx-ARC_WAVE_SEL)&0xff; - if ((num<6) && (base<22)) { -#if defined(OPLTYPE_IS_OPL3) - Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[] - // change waveform - if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible - else wave_sel[wselbase] = val&3; - op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)]; - change_waveform(wselbase,op_ptr); -#else - if (adlibreg[0x01]&0x20) { - // wave selection enabled, change waveform - wave_sel[base] = val&3; - op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)]; - change_waveform(base,op_ptr); - } -#endif - } - } - break; - default: - break; - } -} - -static void OPL_INLINE clipit16(float ival, float* outval) { - *outval += ival / 10240.f; -} - - - -// be careful with this -// uses cptr and chanval, outputs into outbufl(/outbufr) -// for opl3 check if opl3-mode is enabled (which uses stereo panning) -#undef CHANVAL_OUT -#if defined(OPLTYPE_IS_OPL3) -#define CHANVAL_OUT \ - if (adlibreg[0x105]&1) { \ - outbufl[i] += chanval*cptr[0].left_pan; \ - outbufr[i] += chanval*cptr[0].right_pan; \ - } else { \ - outbufl[i] += chanval; \ - } -#else -#define CHANVAL_OUT \ - outbufl[i] += chanval; -#endif - -void DBOPL::Update(float* sndptr, int numsamples) { - Bits i, endsamples; - op_type* cptr; - - float outbufl[BLOCKBUF_SIZE]; -#if defined(OPLTYPE_IS_OPL3) - // second output buffer (right channel for opl3 stereo) - float outbufr[BLOCKBUF_SIZE]; -#endif - - // vibrato/tremolo lookup tables (global, to possibly be used by all operators) - Bit32s vib_lut[BLOCKBUF_SIZE]; - Bit32s trem_lut[BLOCKBUF_SIZE]; - - Bits samples_to_process = numsamples; - - for (Bits cursmp=0; cursmpBLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE; - - memset((void*)&outbufl,0,endsamples*sizeof(Bit32s)); -#if defined(OPLTYPE_IS_OPL3) - // clear second output buffer (opl3 stereo) - if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s)); -#endif - - // calculate vibrato/tremolo lookup tables - Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching - for (i=0;i=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO; - vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents - - // cycle through tremolo table - tremtab_pos += tremtab_add; - if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO; - if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO]; - else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO]; - } - - if (adlibreg[ARC_PERC_MODE]&0x20) { - //BassDrum - cptr = &op[6]; - if (adlibreg[ARC_FEEDBACK+6]&1) { - // additive synthesis - if (cptr[9].op_state != OF_TYPE_OFF) { - if (cptr[9].vibrato) { - vibval1 = vibval_var1; - for (i=0;i=0; cur_ch--) { - // skip drum/percussion operators - if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue; - - Bitu k = cur_ch; -#if defined(OPLTYPE_IS_OPL3) - if (cur_ch < 9) { - cptr = &op[cur_ch]; - } else { - cptr = &op[cur_ch+9]; // second set is operator18-operator35 - k += (-9+256); // second set uses registers 0x100 onwards - } - // check if this operator is part of a 4-op - if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue; -#else - cptr = &op[cur_ch]; -#endif - - // check for FM/AM - if (adlibreg[ARC_FEEDBACK+k]&1) { -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && cptr->is_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4) - if (cptr[0].op_state != OF_TYPE_OFF) { - if (cptr[0].vibrato) { - vibval1 = vibval_var1; - for (i=0;iis_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4)) - if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) { - if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) { - vibval1 = vibval_var1; - for (i=0;istereo) - for (i=0;istereo) - for (i=0;i= 9) - { - c += 9; - } - // This is the MIDI-recommended pan formula. 0 and 1 are - // both hard left so that 64 can be perfectly center. - double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; - op[c].left_pan = (float)cos(HALF_PI * level); - op[c].right_pan = (float)sin(HALF_PI * level); + +static Bit16s wavtable[WAVEPREC*3]; // wave form table + +// key scale levels +static Bit8u kslev[8][16]; + +// key scale level lookup table +static const fltype kslmul[4] = { + 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct +}; + +// frequency multiplicator lookup table +static const fltype frqmul_tab[16] = { + 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 +}; + +// map a channel number to the register offset of the modulator (=register base) +static const Bit8u modulatorbase[9] = { + 0,1,2, + 8,9,10, + 16,17,18 +}; + +// map a register base to a modulator operator number or operator number +#if defined(OPLTYPE_IS_OPL3) +static const Bit8u regbase2modop[44] = { + 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set + 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set +}; +static const Bit8u regbase2op[44] = { + 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set + 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set +}; +#else +static const Bit8u regbase2modop[22] = { + 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8 +}; +static const Bit8u regbase2op[22] = { + 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17 +}; +#endif + + +// start of the waveform +static const Bit32u waveform[8] = { + WAVEPREC, + WAVEPREC>>1, + WAVEPREC, + (WAVEPREC*3)>>2, + 0, + 0, + (WAVEPREC*5)>>2, + WAVEPREC<<1 +}; + +// length of the waveform as mask +static const Bit32u wavemask[8] = { + WAVEPREC-1, + WAVEPREC-1, + (WAVEPREC>>1)-1, + (WAVEPREC>>1)-1, + WAVEPREC-1, + ((WAVEPREC*3)>>2)-1, + WAVEPREC>>1, + WAVEPREC-1 +}; + +// where the first entry resides +static const Bit32u wavestart[8] = { + 0, + WAVEPREC>>1, + 0, + WAVEPREC>>2, + 0, + 0, + 0, + WAVEPREC>>3 +}; + +// envelope generator function constants +static const fltype attackconst[4] = { + (fltype)(1/2.82624), + (fltype)(1/2.25280), + (fltype)(1/1.88416), + (fltype)(1/1.59744) +}; +static const fltype decrelconst[4] = { + (fltype)(1/39.28064), + (fltype)(1/31.41608), + (fltype)(1/26.17344), + (fltype)(1/22.44608) +}; + + +void operator_advance(op_type* op_pt, Bit32s vib) { + op_pt->wfpos = op_pt->tcount; // waveform position + + // advance waveform time + op_pt->tcount += op_pt->tinc; + op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT; + + op_pt->generator_pos += generator_add; +} + +void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) { + Bit32u c1 = op_pt1->tcount/FIXEDPT; + Bit32u c3 = op_pt3->tcount/FIXEDPT; + Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00; + + Bit32u noisebit = pr_opl.GenRand32() & 1; + + Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1); + + //Hihat + Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1))); + op_pt1->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt1->tcount += op_pt1->tinc; + op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT; + op_pt1->generator_pos += generator_add; + + //Snare + inttm = ((1+snare_phase_bit) ^ noisebit)<<8; + op_pt2->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt2->tcount += op_pt2->tinc; + op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT; + op_pt2->generator_pos += generator_add; + + //Cymbal + inttm = (1+phasebit)<<8; + op_pt3->wfpos = inttm*FIXEDPT; // waveform position + // advance waveform time + op_pt3->tcount += op_pt3->tinc; + op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT; + op_pt3->generator_pos += generator_add; +} + + +// output level is sustained, mode changes only when operator is turned off (->release) +// or when the keep-sustained bit is turned off (->sustain_nokeep) +void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) { + if (op_pt->op_state != OF_TYPE_OFF) { + op_pt->lastcval = op_pt->cval; + Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT); + + // wform: -16384 to 16383 (0x4000) + // trem : 32768 to 65535 (0x10000) + // step_amp: 0.0 to 1.0 + // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000) + + op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0); } -} - -DBOPL::DBOPL(bool fullpan) -{ - FullPan = fullpan; - Reset(); -} - -OPLEmul *DBOPLCreate(bool fullpan) -{ - return new DBOPL(fullpan); -} +} + + +// no action, operator is off +void operator_off(op_type* /*op_pt*/) { +} + +// output level is sustained, mode changes only when operator is turned off (->release) +// or when the keep-sustained bit is turned off (->sustain_nokeep) +void operator_sustain(op_type* op_pt) { + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in release mode, if output level reaches zero the operator is turned off +void operator_release(op_type* op_pt) { + // ??? boundary? + if (op_pt->amp > 0.00000001) { + // release phase + op_pt->amp *= op_pt->releasemul; + } + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; // sample counter + if ((op_pt->cur_env_step & op_pt->env_step_r)==0) { + if (op_pt->amp <= 0.00000001) { + // release phase finished, turn off this operator + op_pt->amp = 0.0; + if (op_pt->op_state == OF_TYPE_REL) { + op_pt->op_state = OF_TYPE_OFF; + } + } + op_pt->step_amp = op_pt->amp; + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in decay mode, if sustain level is reached the output level is either +// kept (sustain level keep enabled) or the operator is switched into release mode +void operator_decay(op_type* op_pt) { + if (op_pt->amp > op_pt->sustain_level) { + // decay phase + op_pt->amp *= op_pt->decaymul; + } + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; + if ((op_pt->cur_env_step & op_pt->env_step_d)==0) { + if (op_pt->amp <= op_pt->sustain_level) { + // decay phase finished, sustain level reached + if (op_pt->sus_keep) { + // keep sustain level (until turned off) + op_pt->op_state = OF_TYPE_SUS; + op_pt->amp = op_pt->sustain_level; + } else { + // next: release phase + op_pt->op_state = OF_TYPE_SUS_NOKEEP; + } + } + op_pt->step_amp = op_pt->amp; + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + +// operator in attack mode, if full output level is reached, +// the operator is switched into decay mode +void operator_attack(op_type* op_pt) { + op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0; + + Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples + for (Bit32u ct=0; ctcur_env_step++; // next sample + if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached + if (op_pt->amp > 1.0) { + // attack phase finished, next: decay + op_pt->op_state = OF_TYPE_DEC; + op_pt->amp = 1.0; + op_pt->step_amp = 1.0; + } + op_pt->step_skip_pos_a <<= 1; + if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1; + if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step + op_pt->step_amp = op_pt->amp; + } + } + } + op_pt->generator_pos -= num_steps_add*FIXEDPT; +} + + +typedef void (*optype_fptr)(op_type*); + +optype_fptr opfuncs[6] = { + operator_attack, + operator_decay, + operator_release, + operator_sustain, // sustain phase (keeping level) + operator_release, // sustain_nokeep phase (release-style) + operator_off +}; + +void DBOPL::change_attackrate(Bitu regbase, op_type* op_pt) { + Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4; + if (attackrate) { + fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp); + // attack rate coefficients + op_pt->a0 = (fltype)(0.0377*f); + op_pt->a1 = (fltype)(10.73*f+1); + op_pt->a2 = (fltype)(-17.57*f); + op_pt->a3 = (fltype)(7.42*f); + + Bits step_skip = attackrate*4 + op_pt->toff; + Bits steps = step_skip >> 2; + op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1; + + Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0; + static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa}; + op_pt->env_step_skip_a = step_skip_mask[step_num]; + +#if defined(OPLTYPE_IS_OPL3) + if (step_skip>=60) { +#else + if (step_skip>=62) { +#endif + op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0 + op_pt->a1 = (fltype)(0.0); + op_pt->a2 = (fltype)(0.0); + op_pt->a3 = (fltype)(0.0); + } + } else { + // attack disabled + op_pt->a0 = 0.0; + op_pt->a1 = 1.0; + op_pt->a2 = 0.0; + op_pt->a3 = 0.0; + op_pt->env_step_a = 0; + op_pt->env_step_skip_a = 0; + } +} + +void DBOPL::change_decayrate(Bitu regbase, op_type* op_pt) { + Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15; + // decaymul should be 1.0 when decayrate==0 + if (decayrate) { + fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); + op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2))))); + Bits steps = (decayrate*4 + op_pt->toff) >> 2; + op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1; + } else { + op_pt->decaymul = 1.0; + op_pt->env_step_d = 0; + } +} + +void DBOPL::change_releaserate(Bitu regbase, op_type* op_pt) { + Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15; + // releasemul should be 1.0 when releaserate==0 + if (releaserate) { + fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); + op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2))))); + Bits steps = (releaserate*4 + op_pt->toff) >> 2; + op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1; + } else { + op_pt->releasemul = 1.0; + op_pt->env_step_r = 0; + } +} + +void DBOPL::change_sustainlevel(Bitu regbase, op_type* op_pt) { + Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4; + // sustainlevel should be 0.0 when sustainlevel==15 (max) + if (sustainlevel<15) { + op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05))); + } else { + op_pt->sustain_level = 0.0; + } +} + +void DBOPL::change_waveform(Bitu regbase, op_type* op_pt) { +#if defined(OPLTYPE_IS_OPL3) + if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22 +#endif + // waveform selection + op_pt->cur_wmask = wavemask[wave_sel[regbase]]; + op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]]; + // (might need to be adapted to waveform type here...) +} + +void DBOPL::change_keepsustain(Bitu regbase, op_type* op_pt) { + op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0; + if (op_pt->op_state==OF_TYPE_SUS) { + if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP; + } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) { + if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS; + } +} + +// enable/disable vibrato/tremolo LFO effects +void DBOPL::change_vibrato(Bitu regbase, op_type* op_pt) { + op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0; + op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0; +} + +// change amount of self-feedback +void DBOPL::change_feedback(Bitu chanbase, op_type* op_pt) { + Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14; + if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8))); + else op_pt->mfbi = 0; +} + +void DBOPL::change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) { + // frequency + Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase]; + // block number/octave + Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7); + op_pt->freq_high = (Bit32s)((frn>>7)&7); + + // keysplit + Bit32u note_sel = (adlibreg[8]>>6)&1; + op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)¬e_sel); + op_pt->toff += (oct<<1); + + // envelope scaling (KSR) + if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2; + + // 20+a0+b0: + op_pt->tinc = (Bit32u)((((fltype)(frn<>6]*kslev[oct][frn>>6]); + op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14))); + + // operator frequency changed, care about features that depend on it + change_attackrate(regbase,op_pt); + change_decayrate(regbase,op_pt); + change_releaserate(regbase,op_pt); +} + +void DBOPL::enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) { + // check if this is really an off-on transition + if (op_pt->act_state == OP_ACT_OFF) { + Bits wselbase = regbase; + if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22 + + op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT; + + // start with attack mode + op_pt->op_state = OF_TYPE_ATT; + op_pt->act_state |= act_type; + } +} + +void DBOPL::disable_operator(op_type* op_pt, Bit32u act_type) { + // check if this is really an on-off transition + if (op_pt->act_state != OP_ACT_OFF) { + op_pt->act_state &= (~act_type); + if (op_pt->act_state == OP_ACT_OFF) { + if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL; + } + } +} + +void DBOPL::Reset() { + Bit32u samplerate = (Bit32u)OPL_SAMPLE_RATE; + Bits i, j, oct; + + int_samplerate = samplerate; + + generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate); + + + memset((void *)adlibreg,0,sizeof(adlibreg)); + memset((void *)op,0,sizeof(op_type)*MAXOPERATORS); + memset((void *)wave_sel,0,sizeof(wave_sel)); + + for (i=0;i=0;i--) { + frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp); + } + + status = 0; + opl_index = 0; + + + // create vibrato table + vib_table[0] = 8; + vib_table[1] = 4; + vib_table[2] = 0; + vib_table[3] = -4; + for (i=4; i(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate); + vibtab_pos = 0; + + for (i=0; i -0.5/6 to 0) + for (i=14; i<41; i++) trem_table_int[i] = Bit32s(-i+14); // downwards (26 to 0 -> 0 to -1/6) + for (i=41; i<53; i++) trem_table_int[i] = Bit32s(i-40-26); // upwards (1 to 12 -> -1/6 to -0.5/6) + + for (i=0; i>1);i++) { + wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC)); + wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC)); + wavtable[i] = wavtable[(i<<1) +WAVEPREC]; + // alternative: (zero-less) +/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC)); + wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC)); + wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */ + } + for (i=0;i<(WAVEPREC>>3);i++) { + wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384; + wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384; + } + + // key scale level table verified ([table in book]*8/3) + kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37; + kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47; + kslev[7][8] = 48; + for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41); + for (j=6;j>=0;j--) { + for (i=0;i<16;i++) { + oct = (Bits)kslev[j+1][i]-8; + if (oct < 0) oct = 0; + kslev[j][i] = (Bit8u)oct; + } + } + } + +} + + + +void DBOPL::WriteReg(int idx, int val) { + Bit32u second_set = (Bit32u)idx&0x100; + adlibreg[idx] = val; + + switch (idx&0xf0) { + case ARC_CONTROL: + // here we check for the second set registers, too: + switch (idx) { + case 0x02: // timer1 counter + case 0x03: // timer2 counter + break; + case 0x04: + // IRQ reset, timer mask/start + if (val&0x80) { + // clear IRQ bits in status register + status &= ~0x60; + } else { + status = 0; + } + break; +#if defined(OPLTYPE_IS_OPL3) + case 0x04|ARC_SECONDSET: + // 4op enable/disable switches for each possible channel + op[0].is_4op = (val&1)>0; + op[3].is_4op_attached = op[0].is_4op; + op[1].is_4op = (val&2)>0; + op[4].is_4op_attached = op[1].is_4op; + op[2].is_4op = (val&4)>0; + op[5].is_4op_attached = op[2].is_4op; + op[18].is_4op = (val&8)>0; + op[21].is_4op_attached = op[18].is_4op; + op[19].is_4op = (val&16)>0; + op[22].is_4op_attached = op[19].is_4op; + op[20].is_4op = (val&32)>0; + op[23].is_4op_attached = op[20].is_4op; + break; + case 0x05|ARC_SECONDSET: + break; +#endif + case 0x08: + // CSW, note select + break; + default: + break; + } + break; + case ARC_TVS_KSR_MUL: + case ARC_TVS_KSR_MUL+0x10: { + // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication + int num = (int)idx&7; + Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff; + if ((num<6) && (base<22)) { + Bitu modop = regbase2modop[second_set?(base+22):base]; + Bitu regbase = base+second_set; + Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; + + // change tremolo/vibrato and sustain keeping of this operator + op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; + change_keepsustain(regbase,op_ptr); + change_vibrato(regbase,op_ptr); + + // change frequency calculations of this operator as + // key scale rate and frequency multiplicator can be changed +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { + // operator uses frequency of channel + change_frequency(chanbase-3,regbase,op_ptr); + } else { + change_frequency(chanbase,regbase,op_ptr); + } +#else + change_frequency(chanbase,base,op_ptr); +#endif + } + } + break; + case ARC_KSL_OUTLEV: + case ARC_KSL_OUTLEV+0x10: { + // key scale level; output rate + int num = (int)idx&7; + Bitu base = (idx-ARC_KSL_OUTLEV)&0xff; + if ((num<6) && (base<22)) { + Bitu modop = regbase2modop[second_set?(base+22):base]; + Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; + + // change frequency calculations of this operator as + // key scale level and output rate can be changed + op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; +#if defined(OPLTYPE_IS_OPL3) + Bitu regbase = base+second_set; + if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { + // operator uses frequency of channel + change_frequency(chanbase-3,regbase,op_ptr); + } else { + change_frequency(chanbase,regbase,op_ptr); + } +#else + change_frequency(chanbase,base,op_ptr); +#endif + } + } + break; + case ARC_ATTR_DECR: + case ARC_ATTR_DECR+0x10: { + // attack/decay rates + int num = (int)idx&7; + Bitu base = (idx-ARC_ATTR_DECR)&0xff; + if ((num<6) && (base<22)) { + Bitu regbase = base+second_set; + + // change attack rate and decay rate of this operator + op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; + change_attackrate(regbase,op_ptr); + change_decayrate(regbase,op_ptr); + } + } + break; + case ARC_SUSL_RELR: + case ARC_SUSL_RELR+0x10: { + // sustain level; release rate + int num = (int)idx&7; + Bitu base = (idx-ARC_SUSL_RELR)&0xff; + if ((num<6) && (base<22)) { + Bitu regbase = base+second_set; + + // change sustain level and release rate of this operator + op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; + change_releaserate(regbase,op_ptr); + change_sustainlevel(regbase,op_ptr); + } + } + break; + case ARC_FREQ_NUM: { + // 0xa0-0xa8 low8 frequency + Bitu base = (idx-ARC_FREQ_NUM)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; +#endif + // regbase of modulator: + Bits modbase = modulatorbase[base]+second_set; + + Bitu chanbase = base+second_set; + + change_frequency(chanbase,modbase,&op[opbase]); + change_frequency(chanbase,modbase+3,&op[opbase+9]); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are modified to the frequency of the channel + if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { + change_frequency(chanbase,modbase+8,&op[opbase+3]); + change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); + } +#endif + } + } + break; + case ARC_KON_BNUM: { + if (idx == ARC_PERC_MODE) { +#if defined(OPLTYPE_IS_OPL3) + if (second_set) return; +#endif + + if ((val&0x30) == 0x30) { // BassDrum active + enable_operator(16,&op[6],OP_ACT_PERC); + change_frequency(6,16,&op[6]); + enable_operator(16+3,&op[6+9],OP_ACT_PERC); + change_frequency(6,16+3,&op[6+9]); + } else { + disable_operator(&op[6],OP_ACT_PERC); + disable_operator(&op[6+9],OP_ACT_PERC); + } + if ((val&0x28) == 0x28) { // Snare active + enable_operator(17+3,&op[16],OP_ACT_PERC); + change_frequency(7,17+3,&op[16]); + } else { + disable_operator(&op[16],OP_ACT_PERC); + } + if ((val&0x24) == 0x24) { // TomTom active + enable_operator(18,&op[8],OP_ACT_PERC); + change_frequency(8,18,&op[8]); + } else { + disable_operator(&op[8],OP_ACT_PERC); + } + if ((val&0x22) == 0x22) { // Cymbal active + enable_operator(18+3,&op[8+9],OP_ACT_PERC); + change_frequency(8,18+3,&op[8+9]); + } else { + disable_operator(&op[8+9],OP_ACT_PERC); + } + if ((val&0x21) == 0x21) { // Hihat active + enable_operator(17,&op[7],OP_ACT_PERC); + change_frequency(7,17,&op[7]); + } else { + disable_operator(&op[7],OP_ACT_PERC); + } + + break; + } + // regular 0xb0-0xb8 + Bitu base = (idx-ARC_KON_BNUM)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; +#endif + // regbase of modulator: + Bits modbase = modulatorbase[base]+second_set; + + if (val&32) { + // operator switched on + enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op) + enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op) +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are switched on + if ((adlibreg[0x105]&1) && op[opbase].is_4op) { + // turn on chan+3 operators as well + enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL); + enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL); + } +#endif + } else { + // operator switched off + disable_operator(&op[opbase],OP_ACT_NORMAL); + disable_operator(&op[opbase+9],OP_ACT_NORMAL); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are switched off + if ((adlibreg[0x105]&1) && op[opbase].is_4op) { + // turn off chan+3 operators as well + disable_operator(&op[opbase+3],OP_ACT_NORMAL); + disable_operator(&op[opbase+3+9],OP_ACT_NORMAL); + } +#endif + } + + Bitu chanbase = base+second_set; + + // change frequency calculations of modulator and carrier (2op) as + // the frequency of the channel has changed + change_frequency(chanbase,modbase,&op[opbase]); + change_frequency(chanbase,modbase+3,&op[opbase+9]); +#if defined(OPLTYPE_IS_OPL3) + // for 4op channels all four operators are modified to the frequency of the channel + if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { + // change frequency calculations of chan+3 operators as well + change_frequency(chanbase,modbase+8,&op[opbase+3]); + change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); + } +#endif + } + } + break; + case ARC_FEEDBACK: { + // 0xc0-0xc8 feedback/modulation type (AM/FM) + Bitu base = (idx-ARC_FEEDBACK)&0xff; + if (base<9) { + Bits opbase = second_set?(base+18):base; + Bitu chanbase = base+second_set; + change_feedback(chanbase,&op[opbase]); +#if defined(OPLTYPE_IS_OPL3) + // OPL3 panning + if (!FullPan) + { + op[opbase].left_pan = (float)((val&0x10)>>4); + op[opbase].right_pan = (float)((val&0x20)>>5); + } +#endif + } + } + break; + case ARC_WAVE_SEL: + case ARC_WAVE_SEL+0x10: { + int num = (int)idx&7; + Bitu base = (idx-ARC_WAVE_SEL)&0xff; + if ((num<6) && (base<22)) { +#if defined(OPLTYPE_IS_OPL3) + Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[] + // change waveform + if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible + else wave_sel[wselbase] = val&3; + op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)]; + change_waveform(wselbase,op_ptr); +#else + if (adlibreg[0x01]&0x20) { + // wave selection enabled, change waveform + wave_sel[base] = val&3; + op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)]; + change_waveform(base,op_ptr); + } +#endif + } + } + break; + default: + break; + } +} + +static void OPL_INLINE clipit16(float ival, float* outval) { + *outval += ival / 10240.f; +} + + + +// be careful with this +// uses cptr and chanval, outputs into outbufl(/outbufr) +// for opl3 check if opl3-mode is enabled (which uses stereo panning) +#undef CHANVAL_OUT +#if defined(OPLTYPE_IS_OPL3) +#define CHANVAL_OUT \ + if (adlibreg[0x105]&1) { \ + outbufl[i] += chanval*cptr[0].left_pan; \ + outbufr[i] += chanval*cptr[0].right_pan; \ + } else { \ + outbufl[i] += chanval; \ + } +#else +#define CHANVAL_OUT \ + outbufl[i] += chanval; +#endif + +void DBOPL::Update(float* sndptr, int numsamples) { + Bits i, endsamples; + op_type* cptr; + + float outbufl[BLOCKBUF_SIZE]; +#if defined(OPLTYPE_IS_OPL3) + // second output buffer (right channel for opl3 stereo) + float outbufr[BLOCKBUF_SIZE]; +#endif + + // vibrato/tremolo lookup tables (global, to possibly be used by all operators) + Bit32s vib_lut[BLOCKBUF_SIZE]; + Bit32s trem_lut[BLOCKBUF_SIZE]; + + Bits samples_to_process = numsamples; + + for (Bits cursmp=0; cursmpBLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE; + + memset((void*)&outbufl,0,endsamples*sizeof(Bit32s)); +#if defined(OPLTYPE_IS_OPL3) + // clear second output buffer (opl3 stereo) + if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s)); +#endif + + // calculate vibrato/tremolo lookup tables + Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching + for (i=0;i=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO; + vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents + + // cycle through tremolo table + tremtab_pos += tremtab_add; + if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO; + if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO]; + else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO]; + } + + if (adlibreg[ARC_PERC_MODE]&0x20) { + //BassDrum + cptr = &op[6]; + if (adlibreg[ARC_FEEDBACK+6]&1) { + // additive synthesis + if (cptr[9].op_state != OF_TYPE_OFF) { + if (cptr[9].vibrato) { + vibval1 = vibval_var1; + for (i=0;i=0; cur_ch--) { + // skip drum/percussion operators + if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue; + + Bitu k = cur_ch; +#if defined(OPLTYPE_IS_OPL3) + if (cur_ch < 9) { + cptr = &op[cur_ch]; + } else { + cptr = &op[cur_ch+9]; // second set is operator18-operator35 + k += (-9+256); // second set uses registers 0x100 onwards + } + // check if this operator is part of a 4-op + if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue; +#else + cptr = &op[cur_ch]; +#endif + + // check for FM/AM + if (adlibreg[ARC_FEEDBACK+k]&1) { +#if defined(OPLTYPE_IS_OPL3) + if ((adlibreg[0x105]&1) && cptr->is_4op) { + if (adlibreg[ARC_FEEDBACK+k+3]&1) { + // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4) + if (cptr[0].op_state != OF_TYPE_OFF) { + if (cptr[0].vibrato) { + vibval1 = vibval_var1; + for (i=0;iis_4op) { + if (adlibreg[ARC_FEEDBACK+k+3]&1) { + // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4)) + if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) { + if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) { + vibval1 = vibval_var1; + for (i=0;istereo) + for (i=0;istereo) + for (i=0;i= 9) + { + c += 9; + } + op[c].left_pan = left; + op[c].right_pan = right; + } +} + +DBOPL::DBOPL(bool fullpan) +{ + FullPan = fullpan; + Reset(); +} + +OPLEmul *DBOPLCreate(bool fullpan) +{ + return new DBOPL(fullpan); +} diff --git a/src/oplsynth/dosbox/opl.h b/src/oplsynth/dosbox/opl.h index ab42c54ff..b4d7548ad 100644 --- a/src/oplsynth/dosbox/opl.h +++ b/src/oplsynth/dosbox/opl.h @@ -223,7 +223,7 @@ public: void Reset(); void Update(float* sndptr, int numsamples); void WriteReg(int idx, int val); - void SetPanning(int c, int pan); + void SetPanning(int c, float left, float right); DBOPL(bool stereo); }; diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index c4fe1a282..719c63178 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -127,7 +127,6 @@ typedef signed int INT32; /* signed 32bit */ #endif #define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ -#define HALF_PI (PI/2) #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */ @@ -1587,13 +1586,10 @@ public: } /* [RH] Full support for MIDI panning */ - void SetPanning(int c, int pan) + void SetPanning(int c, float left, float right) { - // This is the MIDI-recommended pan formula. 0 and 1 are - // both hard left so that 64 can be perfectly center. - double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; - Chip.P_CH[c].LeftVol = (float)cos(HALF_PI * level); - Chip.P_CH[c].RightVol = (float)sin(HALF_PI * level); + Chip.P_CH[c].LeftVol = left; + Chip.P_CH[c].RightVol = right; } diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index cfc29f7c9..5e2f23e93 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -45,6 +45,8 @@ #include "opl.h" #include "c_cvars.h" +#define HALF_PI (PI*0.5) + EXTERN_CVAR(Int, opl_core) OPLio::~OPLio() @@ -260,7 +262,13 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan) int which = channel / chanper; if (chips[which] != NULL) { - chips[which]->SetPanning(channel % chanper, pan + 64); + // This is the MIDI-recommended pan formula. 0 and 1 are + // both hard left so that 64 can be perfectly center. + // (Note that the 'pan' passed to this function is the + // MIDI pan position, subtracted by 64.) + double level = (pan <= -63) ? 0 : (pan + 64 - 1) / 126.0; + chips[which]->SetPanning(channel % chanper, + (float)cos(HALF_PI * level), (float)sin(HALF_PI * level)); } } } diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h index 6a8e42e27..1f1c5e2c1 100644 --- a/src/oplsynth/opl.h +++ b/src/oplsynth/opl.h @@ -14,7 +14,7 @@ public: virtual void Reset() = 0; virtual void WriteReg(int reg, int v) = 0; virtual void Update(float *buffer, int length) = 0; - virtual void SetPanning(int c, int pan) = 0; + virtual void SetPanning(int c, float left, float right) = 0; virtual FString GetVoiceString() { return FString(); } }; From 8670d6e4f464fea9e6b55c48df5103e8904af429 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 04:57:25 +0000 Subject: [PATCH 032/387] - The raw OPL music player no longer checks against the chip count for writing to the second OPL2; OPLwriteReg() will now do nothing when called to act on a chip that doesn't exist. This is so that it can use the second half of a single OPL3. SVN r3949 (trunk) --- src/oplsynth/mlopl_io.cpp | 5 ++++- src/oplsynth/opl_mus_player.cpp | 12 +++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 5e2f23e93..4dc15e39f 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -68,7 +68,10 @@ void OPLio::OPLwriteReg(int which, uint reg, uchar data) reg |= (which & 1) << 8; which >>= 1; } - chips[which]->WriteReg(reg, data); + if (chips[which] != NULL) + { + chips[which]->WriteReg(reg, data); + } } /* diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index df4b3c88e..335e6d66e 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -411,10 +411,7 @@ int OPLmusicFile::PlayTick () break; default: // It's something to stuff into the OPL chip - if (WhichChip < NumChips) - { - io->OPLwriteReg(WhichChip, reg, data); - } + io->OPLwriteReg(WhichChip, reg, data); break; } } @@ -454,10 +451,7 @@ int OPLmusicFile::PlayTick () { data = *score++; } - if (WhichChip < NumChips) - { - io->OPLwriteReg(WhichChip, reg, data); - } + io->OPLwriteReg(WhichChip, reg, data); } break; @@ -485,7 +479,7 @@ int OPLmusicFile::PlayTick () { return (data + 1) << 8; } - else if (code < to_reg_size && which < NumChips) + else if (code < to_reg_size) { io->OPLwriteReg(which, to_reg[code], data); } From 68b3c4860fc8ed159428b99ba2fc67b100e65df4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 05:02:05 +0000 Subject: [PATCH 033/387] - Remove redundant redundancy in the PigPlayer definition. SVN r3950 (trunk) --- wadsrc/static/actors/hexen/pig.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/wadsrc/static/actors/hexen/pig.txt b/wadsrc/static/actors/hexen/pig.txt index 45b649597..a99789b5b 100644 --- a/wadsrc/static/actors/hexen/pig.txt +++ b/wadsrc/static/actors/hexen/pig.txt @@ -73,7 +73,6 @@ ACTOR PigPlayer : PlayerPawn native Player.SoundClass "Pig" Player.DisplayName "Pig" Player.MorphWeapon "Snout" - -PICKUP States { Spawn: From 181cfd80b2a742ff24a00592ce1be6da6bedf3f7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 05:14:47 +0000 Subject: [PATCH 034/387] - Fixed: Monsters stepping down in A_Chase() should trigger SECSPAC_HitFloor actions. SVN r3951 (trunk) --- src/p_enemy.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index a0367123a..3b0e16a3c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -540,7 +540,7 @@ bool P_Move (AActor *actor) !((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { - if (actor->z <= actor->floorz + actor->MaxStepHeight) + if (0 && actor->z <= actor->floorz + actor->MaxStepHeight) { fixed_t savedz = actor->z; actor->z = actor->floorz; @@ -550,6 +550,10 @@ bool P_Move (AActor *actor) { actor->z = savedz; } + else if (actor->floorsector->SecActTarget != NULL) + { // The monster just hit the floor, so trigger any actions. + actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); + } } } From db4d58b2b86a926fc7a9570bba6496217d6205cb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 05:20:15 +0000 Subject: [PATCH 035/387] - Fixed: The resurrect cheat also needs to restore flags6 to their default settings. SVN r3952 (trunk) --- src/m_cheat.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 4249fea5c..a867c77d2 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -310,6 +310,7 @@ void cht_DoCheat (player_t *player, int cheat) player->mo->flags3 = player->mo->GetDefault()->flags3; player->mo->flags4 = player->mo->GetDefault()->flags4; player->mo->flags5 = player->mo->GetDefault()->flags5; + player->mo->flags6 = player->mo->GetDefault()->flags6; player->mo->renderflags &= ~RF_INVISIBLE; player->mo->height = player->mo->GetDefault()->height; player->mo->special1 = 0; // required for the Hexen fighter's fist attack. From 4f811b89e50b363e51ce9be2580d1f35e3a731f2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 17:18:47 +0000 Subject: [PATCH 036/387] - Remove testing bit inadvertently left in for r3951. SVN r3953 (trunk) --- src/p_enemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3b0e16a3c..46104ad18 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -540,7 +540,7 @@ bool P_Move (AActor *actor) !((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP)) && actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ)) { - if (0 && actor->z <= actor->floorz + actor->MaxStepHeight) + if (actor->z <= actor->floorz + actor->MaxStepHeight) { fixed_t savedz = actor->z; actor->z = actor->floorz; From 6c64f19a7e4aa12af5bb7d4f2fa037e548ce473c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 23:03:53 +0000 Subject: [PATCH 037/387] - Enable Doom 1.1 status bar support. SVN r3954 (trunk) --- wadsrc/static/textures.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wadsrc/static/textures.txt b/wadsrc/static/textures.txt index 7ae26ce2f..d54ef32d9 100644 --- a/wadsrc/static/textures.txt +++ b/wadsrc/static/textures.txt @@ -71,3 +71,9 @@ Graphic optional P_MWALK4, 112, 136 Graphic "M_MBOX", 0, 0 Graphic "M_MWALK4", 24, 12 { useoffsets } } + +Graphic optional STBAR, 320, 32 +{ + Graphic "STMBARL", 0, 0 + Graphic "STMBARR", 104, 0 +} From 2ce1debe8d2097587af38f4ee55d26d40953be28 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 23:06:40 +0000 Subject: [PATCH 038/387] - Added FDARI's get actor height and radius patch. SVN r3955 (trunk) --- src/p_acs.cpp | 6 ++++++ src/thingdef/thingdef_expression.cpp | 3 +++ wadsrc/static/actors/actor.txt | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 3feafc99e..ea65f1cca 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2766,6 +2766,8 @@ enum APROP_Mass = 32, APROP_Accuracy = 33, APROP_Stamina = 34, + APROP_Height = 35, + APROP_Radius = 36, }; // These are needed for ACS's APROP_RenderStyle @@ -3045,6 +3047,8 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Mass: return actor->Mass; case APROP_Accuracy: return actor->accuracy; case APROP_Stamina: return actor->stamina; + case APROP_Height: return actor->height; + case APROP_Radius: return actor->radius; default: return 0; } @@ -3085,6 +3089,8 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Mass: case APROP_Accuracy: case APROP_Stamina: + case APROP_Height: + case APROP_Radius: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index af22129a6..a5644b88f 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -84,6 +84,9 @@ DEFINE_MEMBER_VARIABLE(Damage, AActor) DEFINE_MEMBER_VARIABLE(Score, AActor) DEFINE_MEMBER_VARIABLE(accuracy, AActor) DEFINE_MEMBER_VARIABLE(stamina, AActor) +DEFINE_MEMBER_VARIABLE(height, AActor) +DEFINE_MEMBER_VARIABLE(radius, AActor) + //========================================================================== // diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 3b22d5734..f7ee26769 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -56,6 +56,8 @@ ACTOR Actor native //: Thinker native int score; native int accuracy; native int stamina; + native fixed_t height; + native fixed_t radius; // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); From a4312fb106bb46706078d81a44fe8566f5081107 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 23:13:50 +0000 Subject: [PATCH 039/387] - Fix spelling errors spotted by Gez in a few comments. SVN r3957 (trunk) --- src/dobjtype.cpp | 4 ++-- src/r_defs.h | 2 +- src/v_video.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 32df6a537..5798648cd 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -357,8 +357,8 @@ unsigned int PClass::Extend(unsigned int extension) } // Like FindClass but creates a placeholder if no class -// is found. CreateDerivedClass will automatcally fill in -// the placeholder when the actual class is defined. +// is found. CreateDerivedClass will automatically fill +// in the placeholder when the actual class is defined. const PClass *PClass::FindClassTentative (FName name) { if (name == NAME_None) diff --git a/src/r_defs.h b/src/r_defs.h index 87c9e9e4f..02eefcf91 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -904,7 +904,7 @@ struct line_t slopetype_t slopetype; // To aid move clipping. sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked - int locknumber; // [Dusk] lock number for special + int locknumber; // [Dusk] lock number for special }; // phares 3/14/98 diff --git a/src/v_video.cpp b/src/v_video.cpp index e6145cc95..e3a832dde 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -491,7 +491,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr) else { normal: - // Treat it as a space-delemited hexadecimal string + // Treat it as a space-delimited hexadecimal string for (i = 0; i < 3; ++i) { // Skip leading whitespace From 3c54047b9f1d719eafe986ba31639d94836b3226 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 23:25:56 +0000 Subject: [PATCH 040/387] - Added Gez's "Using arg*str instead of SpawnID" patch, with modifications. SVN r3958 (trunk) --- src/g_hexen/a_hexenspecialdecs.cpp | 22 ++++++++++--------- src/namedef.h | 1 + src/p_local.h | 2 +- src/p_things.cpp | 35 ++++++++++++++++++++---------- src/p_udmf.cpp | 31 ++++++++++++++++++++++---- 5 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp index afca4f190..5485d8d1f 100644 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ b/src/g_hexen/a_hexenspecialdecs.cpp @@ -70,13 +70,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) } } S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM); - if (self->args[0]>=0 && self->args[0]<=255 && SpawnableThings[self->args[0]]) - { // Spawn an item + // Spawn an item? + const PClass *type = P_GetSpawnableType(self->args[0]); + if (type != NULL) + { if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (SpawnableThings[self->args[0]])->flags3 & MF3_ISMONSTER)) + || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) { // Only spawn monsters if not -nomonsters - Spawn (SpawnableThings[self->args[0]], - self->x, self->y, self->z, ALLOW_REPLACE); + Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); } } } @@ -288,13 +289,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) mo->vely = pr_soaexplode.Random2()<<(FRACBITS-6); } } - if (self->args[0]>=0 && self->args[0]<=255 && SpawnableThings[self->args[0]]) - { // Spawn an item + // Spawn an item? + const PClass *type = P_GetSpawnableType(self->args[0]); + if (type != NULL) + { if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (SpawnableThings[self->args[0]])->flags3 & MF3_ISMONSTER)) + || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) { // Only spawn monsters if not -nomonsters - Spawn (SpawnableThings[self->args[0]], - self->x, self->y, self->z, ALLOW_REPLACE); + Spawn (type, self->x, self->y, self->z, ALLOW_REPLACE); } } S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); diff --git a/src/namedef.h b/src/namedef.h index 34f9b7235..18fdc0adb 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -299,6 +299,7 @@ xx(Arg2) xx(Arg3) xx(Arg4) xx(Arg0Str) +xx(Arg1Str) xx(Id) xx(V1) xx(V2) diff --git a/src/p_local.h b/src/p_local.h index 4c57ef099..bf7861561 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -168,7 +168,7 @@ int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); void P_RemoveThing(AActor * actor); bool P_Thing_Raise(AActor *thing); - +const PClass *P_GetSpawnableType(int spawnnum); // // P_MAPUTL diff --git a/src/p_things.cpp b/src/p_things.cpp index e0f3936b7..74a6f0bcb 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -58,10 +58,9 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, AActor *spot, *mobj; FActorIterator iterator (tid); - if (type >= MAX_SPAWNABLES) - return false; + kind = P_GetSpawnableType(type); - if ( (kind = SpawnableThings[type]) == NULL) + if (kind == NULL) return false; // Handle decorate replacements. @@ -182,18 +181,16 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam if (type_name == NULL) { - if (type >= MAX_SPAWNABLES) - return false; - - if ((kind = SpawnableThings[type]) == NULL) - return false; + kind = P_GetSpawnableType(type); } else { - if ((kind = PClass::FindClass(type_name)) == NULL || kind->ActorInfo == NULL) - return false; + kind = PClass::FindClass(type_name); + } + if (kind == NULL || kind->ActorInfo == NULL) + { + return false; } - // Handle decorate replacements. kind = kind->GetReplacement(); @@ -487,6 +484,22 @@ void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool } } +const PClass *P_GetSpawnableType(int spawnnum) +{ + if (spawnnum < 0) + { // A named arg from a UDMF map + FName spawnname = FName(ENamedName(-spawnnum)); + if (spawnname.IsValidName()) + { + return PClass::FindClass(spawnname); + } + } + else if (spawnnum < countof(SpawnableThings)) + { // A numbered arg from a Hexen or UDMF map + return SpawnableThings[spawnnum]; + } + return NULL; +} CCMD (dumpspawnables) { diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 5abe40908..e087834b1 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -98,6 +98,11 @@ static char HexenSectorSpecialOk[256]={ 1,1,1,1,1, }; +static inline bool P_IsThingSpecial(int specnum) +{ + return (specnum >= Thing_Projectile && specnum <= Thing_SpawnNoFog) || + specnum == Thing_SpawnFacing || Thing_ProjectileIntercept || Thing_ProjectileAimed; +} enum { @@ -467,7 +472,7 @@ public: void ParseThing(FMapThing *th) { - FString arg0str; + FString arg0str, arg1str; memset(th, 0, sizeof(*th)); sc.MustGetToken('{'); @@ -524,6 +529,11 @@ public: arg0str = CheckString(key); break; + case NAME_Arg1Str: + CHECK_N(Zd); + arg1str = CheckString(key); + break; + case NAME_Skill1: case NAME_Skill2: case NAME_Skill3: @@ -624,10 +634,14 @@ public: break; } } - if (arg0str.IsNotEmpty() && P_IsACSSpecial(th->special)) + if (arg0str.IsNotEmpty() && (P_IsACSSpecial(th->special) || th->special == 0)) { th->args[0] = -FName(arg0str); } + if (arg1str.IsNotEmpty() && (P_IsThingSpecial(th->special) || th->special == 0)) + { + th->args[1] = -FName(arg1str); + } // Thing specials are only valid in namespaces with Hexen-type specials // and in ZDoomTranslated - which will use the translator on them. if (namespc == NAME_ZDoomTranslated) @@ -663,7 +677,7 @@ public: { bool passuse = false; bool strifetrans = false; - FString arg0str; + FString arg0str, arg1str; memset(ld, 0, sizeof(*ld)); ld->Alpha = FRACUNIT; @@ -724,6 +738,11 @@ public: arg0str = CheckString(key); continue; + case NAME_Arg1Str: + CHECK_N(Zd); + arg1str = CheckString(key); + continue; + case NAME_Blocking: Flag(ld->flags, ML_BLOCKING, key); continue; @@ -938,10 +957,14 @@ public: ld->sidedef[0] = (side_t*)(intptr_t)(1); Printf("Line %d has no first side.\n", index); } - if (arg0str.IsNotEmpty() && P_IsACSSpecial(ld->special)) + if (arg0str.IsNotEmpty() && (P_IsACSSpecial(ld->special) || ld->special == 0)) { ld->args[0] = -FName(arg0str); } + if (arg1str.IsNotEmpty() && (P_IsThingSpecial(ld->special) || ld->special == 0)) + { + ld->args[1] = -FName(arg1str); + } } //=========================================================================== From 955d929d5e7ecd694c47b63883148a95cdc1b7d9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 9 Nov 2012 23:53:58 +0000 Subject: [PATCH 041/387] - Ensure that only actor with positive SpawnIDs get added to the SpawnableThings map, so there will be no conflicts with recently-added named arguments for spawnable things on UDMF maps. - Change the SpawnableThings array into a map, so there is no longer any particular upper limit on an actor's SpawnID. Also fixes a possible exploit, since an actor's SpawnID was never checked to make sure it was within range. SVN r3959 (trunk) --- src/info.cpp | 4 ++-- src/p_acs.cpp | 8 ++------ src/p_local.h | 3 +-- src/p_teleport.cpp | 7 +------ src/p_things.cpp | 48 ++++++++++++++++++++++++++++++++-------------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 4d3225344..e6bb0da03 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -141,7 +141,7 @@ void FActorInfo::StaticInit () void FActorInfo::StaticSetActorNums () { - memset (SpawnableThings, 0, sizeof(SpawnableThings)); + SpawnableThings.Clear(); DoomEdMap.Empty (); for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) @@ -162,7 +162,7 @@ void FActorInfo::RegisterIDs () if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype)) { - if (SpawnID != 0) + if (SpawnID > 0) { SpawnableThings[SpawnID] = cls; if (cls != Class) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ea65f1cca..c87f41816 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2283,13 +2283,9 @@ int DLevelScript::ThingCount (int type, int stringid, int tid, int tag) int count = 0; bool replacemented = false; - if (type >= MAX_SPAWNABLES) + if (type > 0) { - return 0; - } - else if (type > 0) - { - kind = SpawnableThings[type]; + kind = P_GetSpawnableType(type); if (kind == NULL) return 0; } diff --git a/src/p_local.h b/src/p_local.h index bf7861561..a045f897b 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -155,8 +155,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheigh // // [RH] P_THINGS // -#define MAX_SPAWNABLES (256) -extern const PClass *SpawnableThings[MAX_SPAWNABLES]; +extern TMap SpawnableThings; bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index cc31358a8..79dd105f9 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -76,12 +76,7 @@ void ATeleportFog::PostBeginPlay () void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid) { - const PClass *fog=NULL; - - if (spawnid > 0 && spawnid < MAX_SPAWNABLES && SpawnableThings[spawnid] != NULL) - { - fog = SpawnableThings[spawnid]; - } + const PClass *fog = P_GetSpawnableType(spawnid); if (fog == NULL) { diff --git a/src/p_things.cpp b/src/p_things.cpp index 74a6f0bcb..289e8835a 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -46,8 +46,8 @@ #include "templates.h" #include "g_level.h" -// List of spawnable things for the Thing_Spawn and Thing_Projectile specials. -const PClass *SpawnableThings[MAX_SPAWNABLES]; +// Set of spawnable things for the Thing_Spawn and Thing_Projectile specials. +TMap SpawnableThings; static FRandom pr_leadtarget ("LeadTarget"); @@ -494,23 +494,43 @@ const PClass *P_GetSpawnableType(int spawnnum) return PClass::FindClass(spawnname); } } - else if (spawnnum < countof(SpawnableThings)) + else { // A numbered arg from a Hexen or UDMF map - return SpawnableThings[spawnnum]; + const PClass **type = SpawnableThings.CheckKey(spawnnum); + if (type != NULL) + { + return *type; + } } return NULL; } -CCMD (dumpspawnables) -{ - int i; +typedef TMap::Pair SpawnablePair; - for (i = 0; i < MAX_SPAWNABLES; i++) - { - if (SpawnableThings[i] != NULL) - { - Printf ("%d %s\n", i, SpawnableThings[i]->TypeName.GetChars()); - } - } +static int STACK_ARGS SpawnableSort(const void *a, const void *b) +{ + return (*((SpawnablePair **)a))->Key - (*((SpawnablePair **)b))->Key; +} + +CCMD (dumpspawnables) +{ + TMapIterator it(SpawnableThings); + SpawnablePair *pair, **allpairs; + int i = 0; + + // Sort into numerical order, since their arrangement in the map can + // be in an unspecified order. + allpairs = new TMap::Pair *[SpawnableThings.CountUsed()]; + while (it.NextPair(pair)) + { + allpairs[i++] = pair; + } + qsort(allpairs, i, sizeof(*allpairs), SpawnableSort); + for (int j = 0; j < i; ++j) + { + pair = allpairs[j]; + Printf ("%d %s\n", pair->Key, pair->Value->TypeName.GetChars()); + } + delete[] allpairs; } From e398957a4c96b0f3f52ba02b2abba29ccf5a4408 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Nov 2012 03:18:52 +0000 Subject: [PATCH 042/387] - Added cybermind's HUD message clipping patch, with numerous changes. There is a new flag and two new functions, both of which are intended for use in conjunction with SetHUDSize: * SetHUDClipRect(x, y, width, height[, wrapwidth]) - Set the clipping rectangle for future HUD messages. If you do not specify , the HUD message will be layed out as normal, but pixels outside the rectangle will not be drawn. If you specify , then the message will be wrapped to that width. Use SetHUDClipRect(0, 0, 0, 0[, 0]) to reset everything back to normal. * SetHUDWrapWidth(wrapwidth) - Sets the wrapping width for future HUD messages without altering the clipping rectangle. If you set the wrapping width to 0, messages will wrap to the full width of the HUD, as normal. * HUDMSG_NOWRAP - A HUDMessage() flag that disables wrapping for one message. It is functionally equivalent to SetHUDWrapWidth(0x7FFFFFFF), except that it only affects the message it's attached to. SVN r3960 (trunk) --- src/g_shared/hudmessages.cpp | 74 ++++++++++++++++++++++++++++++++---- src/g_shared/sbar.h | 22 ++++++++++- src/p_acs.cpp | 41 ++++++++++++++++++-- src/p_acs.h | 2 + 4 files changed, 127 insertions(+), 12 deletions(-) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 76eaedcec..21b5e2c4d 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -131,6 +131,9 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h Left = intpart - (float)(fracpart & 3) / 10.f; } } + NoWrap = false; + ClipX = ClipY = ClipWidth = ClipHeight = 0; + WrapWidth = 0; Top = y; Next = NULL; Lines = NULL; @@ -182,6 +185,17 @@ void DHUDMessage::Serialize (FArchive &arc) << Tics << State << TextColor << SBarID << SourceText << Font << Next << HUDWidth << HUDHeight; + if (SaveVersion >= 3960) + { + arc << NoWrap; + arc << ClipX << ClipY << ClipWidth << ClipHeight; + arc << WrapWidth; + } + else + { + NoWrap = false; + ClipX = ClipY = ClipWidth = ClipHeight = WrapWidth = 0; + } if (arc.IsLoading ()) { Lines = NULL; @@ -220,6 +234,37 @@ void DHUDMessage::ScreenSizeChanged () } } +//============================================================================ +// +// DHUDMessage :: CalcClipCoords +// +// Take the clip rectangle in HUD coordinates (set via SetHudSize in ACS) +// and convert them to screen coordinates. +// +//============================================================================ + +void DHUDMessage::CalcClipCoords(int hudheight) +{ + int x = ClipX, y = ClipY, w = ClipWidth, h = ClipHeight; + + if ((x | y | w | h) == 0) + { // No clipping rectangle set; use the full screen. + ClipLeft = 0; + ClipTop = 0; + ClipRight = screen->GetWidth(); + ClipBot = screen->GetHeight(); + } + else + { + screen->VirtualToRealCoordsInt(x, y, w, h, + HUDWidth, hudheight, false, true); + ClipLeft = x; + ClipTop = y; + ClipRight = x + w; + ClipBot = y + h; + } +} + //============================================================================ // // DHUDMessage :: ResetText @@ -232,11 +277,11 @@ void DHUDMessage::ResetText (const char *text) if (HUDWidth != 0) { - width = HUDWidth; + width = ClipWidth == 0 ? HUDWidth : ClipWidth; } else { - width = con_scaletext >=2 ? SCREENWIDTH/2 : (con_scaletext ? SCREENWIDTH / CleanXfac : SCREENWIDTH); + width = con_scaletext >= 2 ? SCREENWIDTH/2 : (con_scaletext ? SCREENWIDTH / CleanXfac : SCREENWIDTH); } if (Lines != NULL) @@ -244,7 +289,7 @@ void DHUDMessage::ResetText (const char *text) V_FreeBrokenLines (Lines); } - Lines = V_BreakLines (Font, width, (BYTE *)text); + Lines = V_BreakLines (Font, NoWrap ? INT_MAX : width, (BYTE *)text); NumLines = 0; Width = 0; @@ -377,15 +422,14 @@ void DHUDMessage::Draw (int bottom, int visibility) ystep = Font->GetHeight() * yscale; if (HUDHeight < 0) - { - // A negative height means the HUD size covers the status bar + { // A negative height means the HUD size covers the status bar hudheight = -HUDHeight; } else - { - // A positive height means the HUD size does not cover the status bar + { // A positive height means the HUD size does not cover the status bar hudheight = Scale (HUDHeight, screen_height, bottom); } + CalcClipCoords(hudheight); for (i = 0; i < NumLines; i++) { @@ -441,6 +485,10 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_ClipLeft, ClipLeft, + DTA_ClipRight, ClipRight, + DTA_ClipTop, ClipTop, + DTA_ClipBottom, ClipBot, DTA_Alpha, Alpha, DTA_RenderStyle, Style, TAG_DONE); @@ -541,6 +589,10 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_ClipLeft, ClipLeft, + DTA_ClipRight, ClipRight, + DTA_ClipTop, ClipTop, + DTA_ClipBottom, ClipBot, DTA_Alpha, trans, DTA_RenderStyle, Style, TAG_DONE); @@ -638,6 +690,10 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_ClipLeft, ClipLeft, + DTA_ClipRight, ClipRight, + DTA_ClipTop, ClipTop, + DTA_ClipBottom, ClipBot, DTA_Alpha, trans, DTA_RenderStyle, Style, TAG_DONE); @@ -814,6 +870,10 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, DTA_VirtualWidth, HUDWidth, DTA_VirtualHeight, hudheight, + DTA_ClipLeft, ClipLeft, + DTA_ClipRight, ClipRight, + DTA_ClipTop, ClipTop, + DTA_ClipBottom, ClipBot, DTA_Alpha, Alpha, DTA_TextLen, LineVisible, DTA_RenderStyle, Style, diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index df3daf597..d45f88cdf 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -85,22 +85,42 @@ public: { Alpha = alpha; } + void SetNoWrap(bool nowrap) + { + NoWrap = nowrap; + ResetText(SourceText); + } + void SetClipRect(int x, int y, int width, int height) + { + ClipX = x; + ClipY = y; + ClipWidth = width; + ClipHeight = height; + } + void SetWrapWidth(int wrap) + { + WrapWidth = wrap; + ResetText(SourceText); + } protected: FBrokenLines *Lines; int Width, Height, NumLines; float Left, Top; - bool CenterX; + bool CenterX, NoWrap; int HoldTics; int Tics; int State; int VisibilityFlags; int HUDWidth, HUDHeight; + int ClipX, ClipY, ClipWidth, ClipHeight, WrapWidth; // in HUD coords + int ClipLeft, ClipTop, ClipRight, ClipBot; // in screen coords EColorRange TextColor; FFont *Font; FRenderStyle Style; fixed_t Alpha; + void CalcClipCoords(int hudheight); DHUDMessage () : SourceText(NULL) {} private: diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c87f41816..607b68265 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -93,6 +93,7 @@ FRandom pr_acs ("ACS"); #define HUDMSG_COLORSTRING (0x40000000) #define HUDMSG_ADDBLEND (0x20000000) #define HUDMSG_ALPHA (0x10000000) +#define HUDMSG_NOWRAP (0x08000000) // HUD message layers; these are not flags #define HUDMSG_LAYER_SHIFT 12 @@ -2169,6 +2170,15 @@ void DLevelScript::Serialize (FArchive &arc) arc << activefont << hudwidth << hudheight; + if (SaveVersion >= 3960) + { + arc << ClipRectLeft << ClipRectTop << ClipRectWidth << ClipRectHeight + << WrapWidth; + } + else + { + ClipRectLeft = ClipRectTop = ClipRectWidth = ClipRectHeight = WrapWidth = 0; + } } DLevelScript::DLevelScript () @@ -3382,10 +3392,12 @@ enum EACSFunctions ACSF_Sqrt, ACSF_FixedSqrt, ACSF_VectorLength, + ACSF_SetHUDClipRect, + ACSF_SetHUDWrapWidth, // ZDaemon - ACSF_GetTeamScore = 19620, - ACSF_SetTeamScore, + ACSF_GetTeamScore = 19620, // (int team) + ACSF_SetTeamScore, // (int team, int value) }; int DLevelScript::SideFromID(int id, int side) @@ -3900,11 +3912,9 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_UniqueTID: return P_FindUniqueTID(argCount > 0 ? args[0] : 0, argCount > 1 ? args[1] : 0); - break; case ACSF_IsTIDUsed: return P_IsTIDUsed(args[0]); - break; case ACSF_Sqrt: return xs_FloorToInt(sqrt(double(args[0]))); @@ -3915,6 +3925,18 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_VectorLength: return FLOAT2FIXED(TVector2(FIXED2DBL(args[0]), FIXED2DBL(args[1])).Length()); + case ACSF_SetHUDClipRect: + ClipRectLeft = argCount > 0 ? args[0] : 0; + ClipRectTop = argCount > 1 ? args[1] : 0; + ClipRectWidth = argCount > 2 ? args[2] : 0; + ClipRectHeight = argCount > 3 ? args[3] : 0; + WrapWidth = argCount > 4 ? args[4] : 0; + break; + + case ACSF_SetHUDWrapWidth: + WrapWidth = argCount > 0 ? args[0] : 0; + break; + default: break; } @@ -5737,7 +5759,16 @@ scriptwait: } break; } + msg->SetClipRect(ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight); + if (WrapWidth != 0) + { + msg->SetWrapWidth(WrapWidth); + } msg->SetVisibility((type & HUDMSG_VISIBILITY_MASK) >> HUDMSG_VISIBILITY_SHIFT); + if (type & HUDMSG_NOWRAP) + { + msg->SetNoWrap(true); + } if (type & HUDMSG_ALPHA) { msg->SetAlpha(alpha); @@ -7351,7 +7382,9 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr backSide = flags & ACS_BACKSIDE; activefont = SmallFont; hudwidth = hudheight = 0; + ClipRectLeft = ClipRectTop = ClipRectWidth = ClipRectHeight = WrapWidth = 0; state = SCRIPT_Running; + // Hexen waited one second before executing any open scripts. I didn't realize // this when I wrote my ACS implementation. Now that I know, it's still best to // run them right away because there are several map properties that can't be diff --git a/src/p_acs.h b/src/p_acs.h index d2ae2038b..44786e260 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -707,6 +707,8 @@ protected: bool backSide; FFont *activefont; int hudwidth, hudheight; + int ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight; + int WrapWidth; FBehavior *activeBehavior; void Link (); From f4e108552eef23969afd4237ec8c0fcdf0cdfed3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Nov 2012 03:36:30 +0000 Subject: [PATCH 043/387] - Fixed: pr_statetics must be named, since it's critical to sync. SVN r3962 (trunk) --- src/info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.cpp b/src/info.cpp index e6bb0da03..0a8d92217 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -55,7 +55,7 @@ extern void LoadActors (); extern void InitBotStuff(); extern void ClearStrifeTypes(); -FRandom FState::pr_statetics; +FRandom FState::pr_statetics("StateTics"); //========================================================================== // From a71736b59886d8204162da176c89f61d6d23f4f8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Nov 2012 03:38:52 +0000 Subject: [PATCH 044/387] - Fixed: If there are not enough states for a spawned debris chunk, A_SpawnDebris should still fling it somewhere. SVN r3963 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c55cd32ac..597ba48d4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2299,15 +2299,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) for (i = 0; i < GetDefaultByType(debris)->health; i++) { mo = Spawn(debris, self->x+((pr_spawndebris()-128)<<12), - self->y+((pr_spawndebris()-128)<<12), - self->z+(pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE); - if (mo && transfer_translation) + self->y + ((pr_spawndebris()-128)<<12), + self->z + (pr_spawndebris()*self->height/256+self->GetBobOffset()), ALLOW_REPLACE); + if (mo) { - mo->Translation = self->Translation; - } - if (mo && i < mo->GetClass()->ActorInfo->NumOwnedStates) - { - mo->SetState (mo->GetClass()->ActorInfo->OwnedStates + i); + if (transfer_translation) + { + mo->Translation = self->Translation; + } + if (i < mo->GetClass()->ActorInfo->NumOwnedStates) + { + mo->SetState(mo->GetClass()->ActorInfo->OwnedStates + i); + } mo->velz = FixedMul(mult_v, ((pr_spawndebris()&7)+5)*FRACUNIT); mo->velx = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); mo->vely = FixedMul(mult_h, pr_spawndebris.Random2()<<(FRACBITS-6)); From e3b95a99e9327c24d5059ae80c1d59b7b303a0d4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 10 Nov 2012 22:45:15 +0000 Subject: [PATCH 045/387] - Fixed: Having a WrapWidth doesn't do much good if you never use it. SVN r3964 (trunk) --- src/g_shared/hudmessages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 21b5e2c4d..adc375c24 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -277,7 +277,7 @@ void DHUDMessage::ResetText (const char *text) if (HUDWidth != 0) { - width = ClipWidth == 0 ? HUDWidth : ClipWidth; + width = WrapWidth == 0 ? HUDWidth : WrapWidth; } else { From b0e70f8f87f60202fb14ab4929cf22c8746b3c01 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 13 Nov 2012 04:55:03 +0000 Subject: [PATCH 046/387] - Added compatibility kludge for Khorus map08. SVN r3965 (trunk) --- wadsrc/static/compatibility.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index e6b3af2fb..6b352c7ef 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -284,3 +284,20 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 clearlinespecial 1107 clearlinespecial 1108 } + +D41D8CD98F00B204E9800998ECF8427E // Khorus, map08 +{ + // This map uses a voodoo conveyor with slanted walls to shunt the + // voodoo doll into side areas. For some reason, this voodoo doll + // is unable to slide on them, because the slide calculation gets + // them slightly inside the walls and thinks they are stuck. I could + // not reproduce this with the real player, which is what has me + // stumped. So, help them out be attaching some ThrustThing specials + // to the walls. + setlinespecial 443 ThrustThing 96 4 0 0 0 + setlineflags 443 0x200 // repeatable + setactivation 443 16 // SPAC_Push + setlinespecial 455 ThrustThing 96 4 0 0 0 + setlineflags 455 0x200 // repeatable + setactivation 455 16 // SPAC_Push +} From 3f02444ffe13f076e4e6cfe95e4e9af163de9250 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 13 Nov 2012 04:59:38 +0000 Subject: [PATCH 047/387] - Fixed: ArtiTeleport was missing its SpawnID. SVN r3966 (trunk) --- wadsrc/static/actors/raven/artitele.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/raven/artitele.txt b/wadsrc/static/actors/raven/artitele.txt index 1f0fe73d2..79811fd53 100644 --- a/wadsrc/static/actors/raven/artitele.txt +++ b/wadsrc/static/actors/raven/artitele.txt @@ -4,6 +4,7 @@ ACTOR ArtiTeleport : Inventory 36 native { Game Raven + SpawnID 18 +COUNTITEM +FLOATBOB +INVENTORY.INVBAR From e59d7bc8b8c629cbdaa3fc1e10fcabee87b2b18f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 15 Nov 2012 05:23:24 +0000 Subject: [PATCH 048/387] - Since we have two OPL cores now, what's one more? Added a straight, (highly) unoptimized port of the Java OPL3 emulator. SVN r3967 (trunk) --- src/CMakeLists.txt | 1 + src/oplsynth/OPL3.cpp | 1783 +++++++++++++++++++++++++++++++++++ src/oplsynth/mlopl_io.cpp | 4 +- src/oplsynth/opl.h | 1 + src/sound/music_mus_opl.cpp | 2 +- zdoom.vcproj | 32 +- 6 files changed, 1792 insertions(+), 31 deletions(-) create mode 100644 src/oplsynth/OPL3.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6dd26f28..056b65937 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -813,6 +813,7 @@ add_executable( zdoom WIN32 oplsynth/music_opl_mididevice.cpp oplsynth/opl_mus_player.cpp oplsynth/dosbox/opl.cpp + oplsynth/OPL3.cpp resourcefiles/ancientzip.cpp resourcefiles/file_7z.cpp resourcefiles/file_grp.cpp diff --git a/src/oplsynth/OPL3.cpp b/src/oplsynth/OPL3.cpp new file mode 100644 index 000000000..2e86f2be5 --- /dev/null +++ b/src/oplsynth/OPL3.cpp @@ -0,0 +1,1783 @@ +/* + * File: OPL3.java + * Software implementation of the Yamaha YMF262 sound generator. + * Copyright (C) 2008 Robson Cozendey + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * One of the objectives of this emulator is to stimulate further research in the + * OPL3 chip emulation. There was an explicit effort in making no optimizations, + * and making the code as legible as possible, so that a new programmer + * interested in modify and improve upon it could do so more easily. + * This emulator's main body of information was taken from reverse engineering of + * the OPL3 chip, from the YMF262 Datasheet and from the OPL3 section in the + * YMF278b Application's Manual, + * together with the vibrato table information, eighth waveform parameter + * information and feedback averaging information provided in MAME's YMF262 and + * YM3812 emulators, by Jarek Burczynski and Tatsuyuki Satoh. + * This emulator has a high degree of accuracy, and most of music files sound + * almost identical, exception made in some games which uses specific parts of + * the rhythm section. In this respect, some parts of the rhythm mode are still + * only an approximation of the real chip. + * The other thing to note is that this emulator was done through recordings of + * the SB16 DAC, so it has not bitwise precision. Additional equipment should be + * used to verify the samples directly from the chip, and allow this exact + * per-sample correspondence. As a good side-effect, since this emulator uses + * floating point and has a more fine-grained envelope generator, it can produce + * sometimes a crystal-clear, denser kind of OPL3 sound that, because of that, + * may be useful for creating new music. + * + * Version 1.0.6 + * + */ + +#include +#include + +#include "doomtype.h" +#include "opl.h" +#include "m_random.h" + +static FRandom pr_opl3; + +class Operator; + +// +// Channels +// + + +class Channel +{ +protected: + double feedback[2]; + + int fnuml, fnumh, kon, block, cha, chb, chc, chd, fb, cnt; + + // Factor to convert between normalized amplitude to normalized + // radians. The amplitude maximum is equivalent to 8*Pi radians. +#define toPhase (4.f) + +public: + int channelBaseAddress; + + Channel (int baseAddress); + void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); + void update_FNUML8(class OPL3 *OPL3); + void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); + void updateChannel(class OPL3 *OPL3); + virtual void getChannelOutput(class OPL3 *OPL3, double output[4]) = 0; + + virtual void keyOn() = 0; + virtual void keyOff() = 0; + virtual void updateOperators(class OPL3 *OPL3) = 0; + +protected: + void getInFourChannels(class OPL3 *OPL3, double channelOutput, double output[4]); +}; + + +class Channel2op : public Channel +{ +public: + Operator *op1, *op2; + + Channel2op (int baseAddress, Operator *o1, Operator *o2); + void getChannelOutput(class OPL3 *OPL3, double output[4]); + + void keyOn(); + void keyOff(); + void updateOperators(class OPL3 *OPL3); +}; + + +class Channel4op : public Channel +{ +public: + Operator *op1, *op2, *op3, *op4; + + Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4); + void getChannelOutput(class OPL3 *OPL3, double output[4]); + + void keyOn(); + void keyOff(); + void updateOperators(class OPL3 *OPL3); +}; + +// There's just one instance of this class, that fills the eventual gaps in the Channel array; +class DisabledChannel : public Channel +{ +public: + DisabledChannel() : Channel(0) { } + void getChannelOutput(class OPL3 *OPL3, double output[4]) { return getInFourChannels(OPL3, 0, output); } + void keyOn() { } + void keyOff() { } + void updateOperators(class OPL3 *OPL3) { } +}; + + + +// +// Envelope Generator +// + + +class EnvelopeGenerator +{ +public: + //static const double *INFINITY = NULL; + enum Stage {ATTACK,DECAY,SUSTAIN,RELEASE,OFF}; + Stage stage; + int actualAttackRate, actualDecayRate, actualReleaseRate; + double xAttackIncrement, xMinimumInAttack; + double dBdecayIncrement; + double dBreleaseIncrement; + double attenuation, totalLevel, sustainLevel; + double x, envelope; + +public: + EnvelopeGenerator(); + void setActualSustainLevel(int sl); + void setTotalLevel(int tl); + void setAtennuation(int f_number, int block, int ksl); + void setActualAttackRate(int attackRate, int ksr, int keyScaleNumber); + void setActualDecayRate(int decayRate, int ksr, int keyScaleNumber); + void setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber); +private: + int calculateActualRate(int rate, int ksr, int keyScaleNumber); +public: + double getEnvelope(OPL3 *OPL3, int egt, int am); + void keyOn(); + void keyOff(); + +private: + static double dBtoX(double dB); + static double percentageToDB(double percentage); + static double percentageToX(double percentage); +}; + + +// +// Phase Generator +// + + +class PhaseGenerator { + double phase, phaseIncrement; + +public: + PhaseGenerator(); + void setFrequency(int f_number, int block, int mult); + double getPhase(class OPL3 *OPL3, int vib); + void keyOn(); +}; + + +// +// Operators +// + + +class Operator +{ +public: + PhaseGenerator phaseGenerator; + EnvelopeGenerator envelopeGenerator; + + double envelope, phase; + + int operatorBaseAddress; + int am, vib, ksr, egt, mult, ksl, tl, ar, dr, sl, rr, ws; + int keyScaleNumber, f_number, block; + + static const double noModulator; + +public: + Operator(int baseAddress); + void update_AM1_VIB1_EGT1_KSR1_MULT4(class OPL3 *OPL3); + void update_KSL2_TL6(class OPL3 *OPL3); + void update_AR4_DR4(class OPL3 *OPL3); + void update_SL4_RR4(class OPL3 *OPL3); + void update_5_WS3(class OPL3 *OPL3); + double getOperatorOutput(class OPL3 *OPL3, double modulator); + + void keyOn(); + void keyOff(); + void updateOperator(class OPL3 *OPL3, int ksn, int f_num, int blk); +protected: + double getOutput(double modulator, double outputPhase, double *waveform); +}; + + +// +// Rhythm +// + +// The getOperatorOutput() method in TopCymbalOperator, HighHatOperator and SnareDrumOperator +// were made through purely empyrical reverse engineering of the OPL3 output. + +class RhythmChannel : public Channel2op +{ +public: + RhythmChannel(int baseAddress, Operator *o1, Operator *o2) + : Channel2op(baseAddress, o1, o2) + { } + void getChannelOutput(class OPL3 *OPL3, double output[4]); + + // Rhythm channels are always running, + // only the envelope is activated by the user. + void keyOn() { } + void keyOff() { } +}; + +class HighHatSnareDrumChannel : public RhythmChannel { + static const int highHatSnareDrumChannelBaseAddress = 7; +public: + HighHatSnareDrumChannel(Operator *o1, Operator *o2) + : RhythmChannel(highHatSnareDrumChannelBaseAddress, o1, o2) + { } +}; + +class TomTomTopCymbalChannel : public RhythmChannel { + static const int tomTomTopCymbalChannelBaseAddress = 8; +public: + TomTomTopCymbalChannel(Operator *o1, Operator *o2) + : RhythmChannel(tomTomTopCymbalChannelBaseAddress, o1, o2) + { } +}; + +class TopCymbalOperator : public Operator { + static const int topCymbalOperatorBaseAddress = 0x15; +public: + TopCymbalOperator(int baseAddress); + TopCymbalOperator(); + double getOperatorOutput(class OPL3 *OPL3, double modulator); + double getOperatorOutput(class OPL3 *OPL3, double modulator, double externalPhase); +}; + +class HighHatOperator : public TopCymbalOperator { + static const int highHatOperatorBaseAddress = 0x11; +public: + HighHatOperator(); + double getOperatorOutput(class OPL3 *OPL3, double modulator); +}; + +class SnareDrumOperator : public Operator { + static const int snareDrumOperatorBaseAddress = 0x14; +public: + SnareDrumOperator(); + double getOperatorOutput(class OPL3 *OPL3, double modulator); +}; + +class TomTomOperator : public Operator { + static const int tomTomOperatorBaseAddress = 0x12; +public: + TomTomOperator() : Operator(tomTomOperatorBaseAddress) { } +}; + +class BassDrumChannel : public Channel2op { + static const int bassDrumChannelBaseAddress = 6; + static const int op1BaseAddress = 0x10; + static const int op2BaseAddress = 0x13; + + Operator my_op1, my_op2; + +public: + BassDrumChannel(); + void getChannelOutput(class OPL3 *OPL3, double output[4]); + + // Key ON and OFF are unused in rhythm channels. + void keyOn() { } + void keyOff() { } +}; + + +// +// OPl3 Data +// + + +struct OPL3Data +{ +public: + // OPL3-wide registers offsets: + static const int + _1_NTS1_6_Offset = 0x08, + DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset = 0xBD, + _7_NEW1_Offset = 0x105, + _2_CONNECTIONSEL6_Offset = 0x104; + + #define sampleRate (49700.0) + + // The OPL3 tremolo repetition rate is 3.7 Hz. + #define tremoloFrequency (3.7) + + static const int tremoloTableLength = (int)(sampleRate/tremoloFrequency); + static const int vibratoTableLength = 8192; + + OPL3Data::OPL3Data() + { + loadVibratoTable(); + loadTremoloTable(); + } + + // The first array is used when DVB=0 and the second array is used when DVB=1. + double vibratoTable[2][vibratoTableLength]; + + // First array used when AM = 0 and second array used when AM = 1. + double tremoloTable[2][tremoloTableLength]; + + static double calculateIncrement(double begin, double end, double period) { + return (end-begin)/sampleRate * (1/period); + } + +private: + void loadVibratoTable(); + void loadTremoloTable(); +}; + + +// +// Channel Data +// + + +struct ChannelData +{ + static const int + _2_KON1_BLOCK3_FNUMH2_Offset = 0xB0, + FNUML8_Offset = 0xA0, + CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset = 0xC0; + + // Feedback rate in fractions of 2*Pi, normalized to (0,1): + // 0, Pi/16, Pi/8, Pi/4, Pi/2, Pi, 2*Pi, 4*Pi turns to be: + static const float feedback[8]; +}; +const float ChannelData::feedback[8] = {0,1/32.f,1/16.f,1/8.f,1/4.f,1/2.f,1,2}; + + +// +// Operator Data +// + + +struct OperatorData +{ + static const int + AM1_VIB1_EGT1_KSR1_MULT4_Offset = 0x20, + KSL2_TL6_Offset = 0x40, + AR4_DR4_Offset = 0x60, + SL4_RR4_Offset = 0x80, + _5_WS3_Offset = 0xE0; + + enum type {NO_MODULATION, CARRIER, FEEDBACK}; + + static const int waveLength = 1024; + + static const float multTable[16]; + static const float ksl3dBtable[16][8]; + + //OPL3 has eight waveforms: + double waveforms[8][waveLength]; + + OperatorData() + { + loadWaveforms(); + } + + static double log2(double x) { + return log(x)/log(2.0); + } +private: + void loadWaveforms(); +}; +const float OperatorData::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; + +const float OperatorData::ksl3dBtable[16][8] = { + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,-3,-6,-9}, + {0,0,0,0,-3,-6,-9,-12}, + {0,0,0, -1.875, -4.875, -7.875, -10.875, -13.875}, + + {0,0,0,-3,-6,-9,-12,-15}, + {0,0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125}, + {0,0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875}, + {0,0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625}, + + {0,0,-3,-6,-9,-12,-15,-18}, + {0, -0.750, -3.750, -6.750, -9.750, -12.750, -15.750, -18.750}, + {0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125, -19.125}, + {0, -1.500, -4.500, -7.500, -10.500, -13.500, -16.500, -19.500}, + + {0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875, -19.875}, + {0, -2.250, -5.250, -8.250, -11.250, -14.250, -17.250, -20.250}, + {0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625, -20.625}, + {0,-3,-6,-9,-12,-15,-18,-21} +}; + +// +// Envelope Generator Data +// + + +namespace EnvelopeGeneratorData +{ + static const double INFINITY = std::numeric_limits::infinity(); + // This table is indexed by the value of Operator.ksr + // and the value of ChannelRegister.keyScaleNumber. + static const int rateOffset[2][16] = { + {0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3}, + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} + }; + // These attack periods in miliseconds were taken from the YMF278B manual. + // The attack actual rates range from 0 to 63, with different data for + // 0%-100% and for 10%-90%: + static const double attackTimeValuesTable[64][2] = { + {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, + {2826.24,1482.75}, {2252.80,1155.07}, {1884.16,991.23}, {1597.44,868.35}, + {1413.12,741.38}, {1126.40,577.54}, {942.08,495.62}, {798.72,434.18}, + {706.56,370.69}, {563.20,288.77}, {471.04,247.81}, {399.36,217.09}, + + {353.28,185.34}, {281.60,144.38}, {235.52,123.90}, {199.68,108.54}, + {176.76,92.67}, {140.80,72.19}, {117.76,61.95}, {99.84,54.27}, + {88.32,46.34}, {70.40,36.10}, {58.88,30.98}, {49.92,27.14}, + {44.16,23.17}, {35.20,18.05}, {29.44,15.49}, {24.96,13.57}, + + {22.08,11.58}, {17.60,9.02}, {14.72,7.74}, {12.48,6.78}, + {11.04,5.79}, {8.80,4.51}, {7.36,3.87}, {6.24,3.39}, + {5.52,2.90}, {4.40,2.26}, {3.68,1.94}, {3.12,1.70}, + {2.76,1.45}, {2.20,1.13}, {1.84,0.97}, {1.56,0.85}, + + {1.40,0.73}, {1.12,0.61}, {0.92,0.49}, {0.80,0.43}, + {0.70,0.37}, {0.56,0.31}, {0.46,0.26}, {0.42,0.22}, + {0.38,0.19}, {0.30,0.14}, {0.24,0.11}, {0.20,0.11}, + {0.00,0.00}, {0.00,0.00}, {0.00,0.00}, {0.00,0.00} + }; + + // These decay and release periods in miliseconds were taken from the YMF278B manual. + // The rate index range from 0 to 63, with different data for + // 0%-100% and for 10%-90%: + static const double decayAndReleaseTimeValuesTable[64][2] = { + {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, + {39280.64,8212.48}, {31416.32,6574.08}, {26173.44,5509.12}, {22446.08,4730.88}, + {19640.32,4106.24}, {15708.16,3287.04}, {13086.72,2754.56}, {11223.04,2365.44}, + {9820.16,2053.12}, {7854.08,1643.52}, {6543.36,1377.28}, {5611.52,1182.72}, + + {4910.08,1026.56}, {3927.04,821.76}, {3271.68,688.64}, {2805.76,591.36}, + {2455.04,513.28}, {1936.52,410.88}, {1635.84,344.34}, {1402.88,295.68}, + {1227.52,256.64}, {981.76,205.44}, {817.92,172.16}, {701.44,147.84}, + {613.76,128.32}, {490.88,102.72}, {488.96,86.08}, {350.72,73.92}, + + {306.88,64.16}, {245.44,51.36}, {204.48,43.04}, {175.36,36.96}, + {153.44,32.08}, {122.72,25.68}, {102.24,21.52}, {87.68,18.48}, + {76.72,16.04}, {61.36,12.84}, {51.12,10.76}, {43.84,9.24}, + {38.36,8.02}, {30.68,6.42}, {25.56,5.38}, {21.92,4.62}, + + {19.20,4.02}, {15.36,3.22}, {12.80,2.68}, {10.96,2.32}, + {9.60,2.02}, {7.68,1.62}, {6.40,1.35}, {5.48,1.15}, + {4.80,1.01}, {3.84,0.81}, {3.20,0.69}, {2.74,0.58}, + {2.40,0.51}, {2.40,0.51}, {2.40,0.51}, {2.40,0.51} + }; +}; + +class OPL3 : public OPLEmul +{ +public: + BYTE registers[0x200]; + + Operator *operators[2][0x20]; + Channel2op *channels2op[2][9]; + Channel4op *channels4op[2][3]; + Channel *channels[2][9]; + + // Unique instance to fill future gaps in the Channel array, + // when there will be switches between 2op and 4op mode. + DisabledChannel disabledChannel; + + // Specific operators to switch when in rhythm mode: + HighHatOperator highHatOperator; + SnareDrumOperator snareDrumOperator; + TomTomOperator tomTomOperator; + TomTomTopCymbalChannel tomTomTopCymbalChannel; + + // Rhythm channels + BassDrumChannel bassDrumChannel; + HighHatSnareDrumChannel highHatSnareDrumChannel; + TopCymbalOperator topCymbalOperator; + + Operator *highHatOperatorInNonRhythmMode; + Operator *snareDrumOperatorInNonRhythmMode; + Operator *tomTomOperatorInNonRhythmMode; + Operator *topCymbalOperatorInNonRhythmMode; + + int nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel; + int vibratoIndex, tremoloIndex; + + static OperatorData *OperatorData; + static OPL3Data *OPL3Data; + + // The methods read() and write() are the only + // ones needed by the user to interface with the emulator. + // read() returns one frame at a time, to be played at 49700 Hz, + // with each frame being four 16-bit samples, + // corresponding to the OPL3 four output channels CHA...CHD. +public: + void read(double output[4]); + void write(int array, int address, int data); + + OPL3(); + ~OPL3(); + +private: + void initOperators(); + void initChannels2op(); + void initChannels4op(); + void initRhythmChannels(); + void initChannels(); + void update_1_NTS1_6(); + void update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); + void update_7_NEW1(); + void setEnabledChannels(); + void update_2_CONNECTIONSEL6(); + void set4opConnections(); + void setRhythmMode(); + + static int InstanceCount; + + // OPLEmul interface +public: + void Reset(); + void WriteReg(int reg, int v); + void Update(float *buffer, int length); + void SetPanning(int c, float left, float right); +}; + +OperatorData *OPL3::OperatorData; +OPL3Data *OPL3::OPL3Data; +int OPL3::InstanceCount; + +void OPL3::read(double output[4]) { + double channelOutput[4]; + + for(int outputChannelNumber=0; outputChannelNumber<4; outputChannelNumber++) + output[outputChannelNumber] = 0; + + // If _new = 0, use OPL2 mode with 9 channels. If _new = 1, use OPL3 18 channels; + for(int array=0; array < (_new + 1); array++) + for(int channelNumber=0; channelNumber < 9; channelNumber++) { + // Reads output from each OPL3 channel, and accumulates it in the output buffer: + channels[array][channelNumber]->getChannelOutput(this, channelOutput); + for(int outputChannelNumber=0; outputChannelNumber<4; outputChannelNumber++) + output[outputChannelNumber] += channelOutput[outputChannelNumber]; + } + + // Advances the OPL3-wide vibrato index, which is used by + // PhaseGenerator.getPhase() in each Operator. + vibratoIndex++; + if(vibratoIndex >= OPL3Data::vibratoTableLength) vibratoIndex = 0; + // Advances the OPL3-wide tremolo index, which is used by + // EnvelopeGenerator.getEnvelope() in each Operator. + tremoloIndex++; + if(tremoloIndex >= OPL3Data::tremoloTableLength) tremoloIndex = 0; +} + +void OPL3::write(int array, int address, int data) { + // The OPL3 has two registers arrays, each with adresses ranging + // from 0x00 to 0xF5. + // This emulator uses one array, with the two original register arrays + // starting at 0x00 and at 0x100. + int registerAddress = (array<<8) | address; + // If the address is out of the OPL3 memory map, returns. + if(registerAddress<0 || registerAddress>=0x200) return; + + registers[registerAddress] = data; + switch(address&0xE0) { + // The first 3 bits masking gives the type of the register by using its base address: + // 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 + // When it is needed, we further separate the register type inside each base address, + // which is the case of 0x00 and 0xA0. + + // Through out this emulator we will use the same name convention to + // reference a byte with several bit registers. + // The name of each bit register will be followed by the number of bits + // it occupies inside the byte. + // Numbers without accompanying names are unused bits. + case 0x00: + // Unique registers for the entire OPL3: + if(array==1) { + if(address==0x04) + update_2_CONNECTIONSEL6(); + else if(address==0x05) + update_7_NEW1(); + } + else if(address==0x08) update_1_NTS1_6(); + break; + + case 0xA0: + // 0xBD is a control register for the entire OPL3: + if(address==0xBD) { + if(array==0) + update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); + break; + } + // Registers for each channel are in A0-A8, B0-B8, C0-C8, in both register arrays. + // 0xB0...0xB8 keeps kon,block,fnum(h) for each channel. + if( (address&0xF0) == 0xB0 && address <= 0xB8) { + // If the address is in the second register array, adds 9 to the channel number. + // The channel number is given by the last four bits, like in A0,...,A8. + channels[array][address&0x0F]->update_2_KON1_BLOCK3_FNUMH2(this); + break; + } + // 0xA0...0xA8 keeps fnum(l) for each channel. + if( (address&0xF0) == 0xA0 && address <= 0xA8) + channels[array][address&0x0F]->update_FNUML8(this); + break; + // 0xC0...0xC8 keeps cha,chb,chc,chd,fb,cnt for each channel: + case 0xC0: + if(address <= 0xC8) + channels[array][address&0x0F]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); + break; + + // Registers for each of the 36 Operators: + default: + int operatorOffset = address&0x1F; + if(operators[array][operatorOffset] == NULL) break; + switch(address&0xE0) { + // 0x20...0x35 keeps am,vib,egt,ksr,mult for each operator: + case 0x20: + operators[array][operatorOffset]->update_AM1_VIB1_EGT1_KSR1_MULT4(this); + break; + // 0x40...0x55 keeps ksl,tl for each operator: + case 0x40: + operators[array][operatorOffset]->update_KSL2_TL6(this); + break; + // 0x60...0x75 keeps ar,dr for each operator: + case 0x60: + operators[array][operatorOffset]->update_AR4_DR4(this); + break; + // 0x80...0x95 keeps sl,rr for each operator: + case 0x80: + operators[array][operatorOffset]->update_SL4_RR4(this); + break; + // 0xE0...0xF5 keeps ws for each operator: + case 0xE0: + operators[array][operatorOffset]->update_5_WS3(this); + } + } +} + +OPL3::OPL3() +: highHatSnareDrumChannel(&highHatOperator, &snareDrumOperator), + tomTomTopCymbalChannel(&tomTomOperator, &topCymbalOperator) +{ + nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0; + vibratoIndex = tremoloIndex = 0; + + if (InstanceCount++ == 0) + { + OPL3Data = new struct OPL3Data; + OperatorData = new struct OperatorData; + } + + initOperators(); + initChannels2op(); + initChannels4op(); + initRhythmChannels(); + initChannels(); +} + +OPL3::~OPL3() +{ + ryt = 0; + setRhythmMode(); // Make sure all operators point to the dynamically allocated ones. + for (int array = 0; array < 2; array++) + { + for (int operatorNumber = 0; operatorNumber < 0x20; operatorNumber++) + { + if (operators[array][operatorNumber] != NULL) + { + delete operators[array][operatorNumber]; + } + } + for (int channelNumber = 0; channelNumber < 9; channelNumber++) + { + delete channels2op[array][channelNumber]; + } + for (int channelNumber = 0; channelNumber < 3; channelNumber++) + { + delete channels4op[array][channelNumber]; + } + } + if (--InstanceCount == 0) + { + delete OPL3Data; + OPL3Data = NULL; + delete OperatorData; + OperatorData = NULL; + } +} + +void OPL3::initOperators() { + int baseAddress; + // The YMF262 has 36 operators: + memset(operators, 0, sizeof(operators)); + for(int array=0; array<2; array++) + for(int group = 0; group<=0x10; group+=8) + for(int offset=0; offset<6; offset++) { + baseAddress = (array<<8) | (group+offset); + operators[array][group+offset] = new Operator(baseAddress); + } + + // Save operators when they are in non-rhythm mode: + // Channel 7: + highHatOperatorInNonRhythmMode = operators[0][0x11]; + snareDrumOperatorInNonRhythmMode = operators[0][0x14]; + // Channel 8: + tomTomOperatorInNonRhythmMode = operators[0][0x12]; + topCymbalOperatorInNonRhythmMode = operators[0][0x15]; + +} + +void OPL3::initChannels2op() { + // The YMF262 has 18 2-op channels. + // Each 2-op channel can be at a serial or parallel operator configuration: + memset(channels2op, 0, sizeof(channels2op)); + + for(int array=0; array<2; array++) + for(int channelNumber=0; channelNumber<3; channelNumber++) { + int baseAddress = (array<<8) | channelNumber; + // Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5 + channels2op[array][channelNumber] = new Channel2op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3]); + // Channels 4, 5, 6 -> Operator offsets 0x8,0xB; 0x9,0xC; 0xA,0xD + channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); + // Channels 7, 8, 9 -> Operators 0x10,0x13; 0x11,0x14; 0x12,0x15 + channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]); + } +} + +void OPL3::initChannels4op() { + // The YMF262 has 3 4-op channels in each array: + memset(channels4op, 0, sizeof(channels4op)); + for(int array=0; array<2; array++) + for(int channelNumber=0; channelNumber<3; channelNumber++) { + int baseAddress = (array<<8) | channelNumber; + // Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD; + channels4op[array][channelNumber] = new Channel4op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); + } +} + +void OPL3::initRhythmChannels() { +} + +void OPL3::initChannels() { + // Channel is an abstract class that can be a 2-op, 4-op, rhythm or disabled channel, + // depending on the OPL3 configuration at the time. + // channels[] inits as a 2-op serial channel array: + for(int array=0; array<2; array++) + for(int i=0; i<9; i++) channels[array][i] = channels2op[array][i]; +} + +void OPL3::update_1_NTS1_6() { + int _1_nts1_6 = registers[OPL3Data::_1_NTS1_6_Offset]; + // Note Selection. This register is used in Channel.updateOperators() implementations, + // to calculate the channel´s Key Scale Number. + // The value of the actual envelope rate follows the value of + // OPL3.nts,Operator.keyScaleNumber and Operator.ksr + nts = (_1_nts1_6 & 0x40) >> 6; +} + +void OPL3::update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1() { + int dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 = registers[OPL3Data::DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset]; + // Depth of amplitude. This register is used in EnvelopeGenerator.getEnvelope(); + dam = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x80) >> 7; + + // Depth of vibrato. This register is used in PhaseGenerator.getPhase(); + dvb = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x40) >> 6; + + int new_ryt = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x20) >> 5; + if(new_ryt != ryt) { + ryt = new_ryt; + setRhythmMode(); + } + + int new_bd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x10) >> 4; + if(new_bd != bd) { + bd = new_bd; + if(bd==1) { + bassDrumChannel.op1->keyOn(); + bassDrumChannel.op2->keyOn(); + } + } + + int new_sd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x08) >> 3; + if(new_sd != sd) { + sd = new_sd; + if(sd==1) snareDrumOperator.keyOn(); + } + + int new_tom = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x04) >> 2; + if(new_tom != tom) { + tom = new_tom; + if(tom==1) tomTomOperator.keyOn(); + } + + int new_tc = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x02) >> 1; + if(new_tc != tc) { + tc = new_tc; + if(tc==1) topCymbalOperator.keyOn(); + } + + int new_hh = dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x01; + if(new_hh != hh) { + hh = new_hh; + if(hh==1) highHatOperator.keyOn(); + } + +} + +void OPL3::update_7_NEW1() { + int _7_new1 = registers[OPL3Data::_7_NEW1_Offset]; + // OPL2/OPL3 mode selection. This register is used in + // OPL3.read(), OPL3.write() and Operator.getOperatorOutput(); + _new = (_7_new1 & 0x01); + if(_new==1) setEnabledChannels(); + set4opConnections(); +} + +void OPL3::setEnabledChannels() { + for(int array=0; array<2; array++) + for(int i=0; i<9; i++) { + int baseAddress = channels[array][i]->channelBaseAddress; + registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; + channels[array][i]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); + } +} + +void OPL3::update_2_CONNECTIONSEL6() { + // This method is called only if _new is set. + int _2_connectionsel6 = registers[OPL3Data::_2_CONNECTIONSEL6_Offset]; + // 2-op/4-op channel selection. This register is used here to configure the OPL3.channels[] array. + connectionsel = (_2_connectionsel6 & 0x3F); + set4opConnections(); +} + +void OPL3::set4opConnections() { + // bits 0, 1, 2 sets respectively 2-op channels (1,4), (2,5), (3,6) to 4-op operation. + // bits 3, 4, 5 sets respectively 2-op channels (10,13), (11,14), (12,15) to 4-op operation. + for(int array=0; array<2; array++) + for(int i=0; i<3; i++) { + if(_new == 1) { + int shift = array*3 + i; + int connectionBit = (connectionsel >> shift) & 0x01; + if(connectionBit == 1) { + channels[array][i] = channels4op[array][i]; + channels[array][i+3] = &disabledChannel; + channels[array][i]->updateChannel(this); + continue; + } + } + channels[array][i] = channels2op[array][i]; + channels[array][i+3] = channels2op[array][i+3]; + channels[array][i]->updateChannel(this); + channels[array][i+3]->updateChannel(this); + } +} + +void OPL3::setRhythmMode() { + if(ryt==1) { + channels[0][6] = &bassDrumChannel; + channels[0][7] = &highHatSnareDrumChannel; + channels[0][8] = &tomTomTopCymbalChannel; + operators[0][0x11] = &highHatOperator; + operators[0][0x14] = &snareDrumOperator; + operators[0][0x12] = &tomTomOperator; + operators[0][0x15] = &topCymbalOperator; + } + else { + for(int i=6; i<=8; i++) channels[0][i] = channels2op[0][i]; + operators[0][0x11] = highHatOperatorInNonRhythmMode; + operators[0][0x14] = snareDrumOperatorInNonRhythmMode; + operators[0][0x12] = tomTomOperatorInNonRhythmMode; + operators[0][0x15] = topCymbalOperatorInNonRhythmMode; + } + for(int i=6; i<=8; i++) channels[0][i]->updateChannel(this); +} + +Channel::Channel (int baseAddress) { + channelBaseAddress = baseAddress; + fnuml = fnumh = kon = block = cha = chb = chc = chd = fb = cnt = 0; + feedback[0] = feedback[1] = 0; +} + +void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) { + + int _2_kon1_block3_fnumh2 = OPL3->registers[channelBaseAddress+ChannelData::_2_KON1_BLOCK3_FNUMH2_Offset]; + + // Frequency Number (hi-register) and Block. These two registers, together with fnuml, + // sets the Channel´s base frequency; + block = (_2_kon1_block3_fnumh2 & 0x1C) >> 2; + fnumh = _2_kon1_block3_fnumh2 & 0x03; + updateOperators(OPL3); + + // Key On. If changed, calls Channel.keyOn() / keyOff(). + int newKon = (_2_kon1_block3_fnumh2 & 0x20) >> 5; + if(newKon != kon) { + if(newKon == 1) keyOn(); + else keyOff(); + kon = newKon; + } +} + +void Channel::update_FNUML8(OPL3 *OPL3) { + int fnuml8 = OPL3->registers[channelBaseAddress+ChannelData::FNUML8_Offset]; + // Frequency Number, low register. + fnuml = fnuml8&0xFF; + updateOperators(OPL3); +} + +void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) { + int chd1_chc1_chb1_cha1_fb3_cnt1 = OPL3->registers[channelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset]; + chd = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x80) >> 7; + chc = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x40) >> 6; + chb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x20) >> 5; + cha = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x10) >> 4; + fb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x0E) >> 1; + cnt = chd1_chc1_chb1_cha1_fb3_cnt1 & 0x01; + updateOperators(OPL3); +} + +void Channel::updateChannel(OPL3 *OPL3) { + update_2_KON1_BLOCK3_FNUMH2(OPL3); + update_FNUML8(OPL3); + update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3); +} + +void Channel::getInFourChannels(OPL3 *OPL3, double channelOutput, double output[4]) { + if( OPL3->_new==0) + output[0] = output[1] = output[2] = output[3] = channelOutput; + else { + output[0] = (cha==1) ? channelOutput : 0; + output[1] = (chb==1) ? channelOutput : 0; + output[2] = (chc==1) ? channelOutput : 0; + output[3] = (chd==1) ? channelOutput : 0; + } +} + +Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2) +: Channel(baseAddress) +{ + op1 = o1; + op2 = o2; +} + +void Channel2op::getChannelOutput(OPL3 *OPL3, double output[4]) { + double channelOutput = 0, op1Output = 0, op2Output = 0; + // The feedback uses the last two outputs from + // the first operator, instead of just the last one. + double feedbackOutput = (feedback[0] + feedback[1]) / 2; + double dontcare; + + switch(cnt) { + // CNT = 0, the operators are in series, with the first in feedback. + case 0: + if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + channelOutput = op2->getOperatorOutput(OPL3, op1Output*toPhase); + break; + // CNT = 1, the operators are in parallel, with the first in feedback. + case 1: + if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && + op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); + channelOutput = (op1Output + op2Output) / 2; + } + + feedback[0] = feedback[1]; + feedback[1] = modf(op1Output * ChannelData::feedback[fb], &dontcare); + getInFourChannels(OPL3, channelOutput, output); +} + +void Channel2op::keyOn() { + op1->keyOn(); + op2->keyOn(); + feedback[0] = feedback[1] = 0; +} + +void Channel2op::keyOff() { + op1->keyOff(); + op2->keyOff(); +} + +void Channel2op::updateOperators(OPL3 *OPL3) { + // Key Scale Number, used in EnvelopeGenerator.setActualRates(). + int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); + int f_number = (fnumh<<8) | fnuml; + op1->updateOperator(OPL3, keyScaleNumber, f_number, block); + op2->updateOperator(OPL3, keyScaleNumber, f_number, block); +} + +Channel4op::Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4) +: Channel(baseAddress) +{ + op1 = o1; + op2 = o2; + op3 = o3; + op4 = o4; +} + +void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { + double channelOutput = 0, + op1Output = 0, op2Output = 0, op3Output = 0, op4Output = 0; + double dontcare; + + int secondChannelBaseAddress = channelBaseAddress+3; + int secondCnt = OPL3->registers[secondChannelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] & 0x1; + int cnt4op = (cnt << 1) | secondCnt; + + double feedbackOutput = (feedback[0] + feedback[1]) / 2; + + switch(cnt4op) { + case 0: + if(op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); + op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); + channelOutput = op4->getOperatorOutput(OPL3, op3Output*toPhase); + + break; + case 1: + if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF && + op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); + + op3Output = op3->getOperatorOutput(OPL3, Operator::noModulator); + op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); + + channelOutput = (op2Output + op4Output) / 2; + break; + case 2: + if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && + op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + + op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); + op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); + op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); + + channelOutput = (op1Output + op4Output) / 2; + break; + case 3: + if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && + op3->envelopeGenerator.stage==EnvelopeGenerator::OFF && + op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) + return getInFourChannels(OPL3, 0, output); + + op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); + + op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); + op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); + + op4Output = op4->getOperatorOutput(OPL3, Operator::noModulator); + + channelOutput = (op1Output + op3Output + op4Output) / 3; + } + + feedback[0] = feedback[1]; + feedback[1] = modf(op1Output * ChannelData::feedback[fb], &dontcare); + + getInFourChannels(OPL3, channelOutput, output); +} + +void Channel4op::keyOn() { + op1->keyOn(); + op2->keyOn(); + op3->keyOn(); + op4->keyOn(); + feedback[0] = feedback[1] = 0; +} + +void Channel4op::keyOff() { + op1->keyOff(); + op2->keyOff(); + op3->keyOff(); + op4->keyOff(); +} + +void Channel4op::updateOperators(OPL3 *OPL3) { + // Key Scale Number, used in EnvelopeGenerator.setActualRates(). + int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); + int f_number = (fnumh<<8) | fnuml; + op1->updateOperator(OPL3, keyScaleNumber, f_number, block); + op2->updateOperator(OPL3, keyScaleNumber, f_number, block); + op3->updateOperator(OPL3, keyScaleNumber, f_number, block); + op4->updateOperator(OPL3, keyScaleNumber, f_number, block); +} + +const double Operator::noModulator = 0; + +Operator::Operator(int baseAddress) { + operatorBaseAddress = baseAddress; + + envelope = 0; + am = vib = ksr = egt = mult = ksl = tl = ar = dr = sl = rr = ws = 0; + keyScaleNumber = f_number = block = 0; +} + +void Operator::update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3 *OPL3) { + + int am1_vib1_egt1_ksr1_mult4 = OPL3->registers[operatorBaseAddress+OperatorData::AM1_VIB1_EGT1_KSR1_MULT4_Offset]; + + // Amplitude Modulation. This register is used int EnvelopeGenerator.getEnvelope(); + am = (am1_vib1_egt1_ksr1_mult4 & 0x80) >> 7; + // Vibrato. This register is used in PhaseGenerator.getPhase(); + vib = (am1_vib1_egt1_ksr1_mult4 & 0x40) >> 6; + // Envelope Generator Type. This register is used in EnvelopeGenerator.getEnvelope(); + egt = (am1_vib1_egt1_ksr1_mult4 & 0x20) >> 5; + // Key Scale Rate. Sets the actual envelope rate together with rate and keyScaleNumber. + // This register os used in EnvelopeGenerator.setActualAttackRate(). + ksr = (am1_vib1_egt1_ksr1_mult4 & 0x10) >> 4; + // Multiple. Multiplies the Channel.baseFrequency to get the Operator.operatorFrequency. + // This register is used in PhaseGenerator.setFrequency(). + mult = am1_vib1_egt1_ksr1_mult4 & 0x0F; + + phaseGenerator.setFrequency(f_number, block, mult); + envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); + envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); + envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); +} + +void Operator::update_KSL2_TL6(OPL3 *OPL3) { + + int ksl2_tl6 = OPL3->registers[operatorBaseAddress+OperatorData::KSL2_TL6_Offset]; + + // Key Scale Level. Sets the attenuation in accordance with the octave. + ksl = (ksl2_tl6 & 0xC0) >> 6; + // Total Level. Sets the overall damping for the envelope. + tl = ksl2_tl6 & 0x3F; + + envelopeGenerator.setAtennuation(f_number, block, ksl); + envelopeGenerator.setTotalLevel(tl); +} + +void Operator::update_AR4_DR4(OPL3 *OPL3) { + + int ar4_dr4 = OPL3->registers[operatorBaseAddress+OperatorData::AR4_DR4_Offset]; + + // Attack Rate. + ar = (ar4_dr4 & 0xF0) >> 4; + // Decay Rate. + dr = ar4_dr4 & 0x0F; + + envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); + envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); +} + +void Operator::update_SL4_RR4(OPL3 *OPL3) { + + int sl4_rr4 = OPL3->registers[operatorBaseAddress+OperatorData::SL4_RR4_Offset]; + + // Sustain Level. + sl = (sl4_rr4 & 0xF0) >> 4; + // Release Rate. + rr = sl4_rr4 & 0x0F; + + envelopeGenerator.setActualSustainLevel(sl); + envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); +} + +void Operator::update_5_WS3(OPL3 *OPL3) { + int _5_ws3 = OPL3->registers[operatorBaseAddress+OperatorData::_5_WS3_Offset]; + ws = _5_ws3 & 0x07; +} + +double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { + if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; + + double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); + envelope = pow(10, envelopeInDB/10.0); + + // If it is in OPL2 mode, use first four waveforms only: + ws &= ((OPL3->_new<<2) + 3); + double *waveform = OPL3::OperatorData->waveforms[ws]; + + phase = phaseGenerator.getPhase(OPL3, vib); + + double operatorOutput = getOutput(modulator, phase, waveform); + return operatorOutput; +} + +double Operator::getOutput(double modulator, double outputPhase, double *waveform) { + double dontcare; + outputPhase = modf(outputPhase + modulator, &dontcare); + if(outputPhase<0) { + outputPhase++; + // If the double could not afford to be less than 1: + outputPhase = modf(outputPhase, &dontcare); + } + int sampleIndex = (int) (outputPhase * OperatorData::waveLength); + return waveform[sampleIndex] * envelope; +} + +void Operator::keyOn() { + if(ar > 0) { + envelopeGenerator.keyOn(); + phaseGenerator.keyOn(); + } + else envelopeGenerator.stage = EnvelopeGenerator::OFF; +} + +void Operator::keyOff() { + envelopeGenerator.keyOff(); +} + +void Operator::updateOperator(OPL3 *OPL3, int ksn, int f_num, int blk) { + keyScaleNumber = ksn; + f_number = f_num; + block = blk; + update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3); + update_KSL2_TL6(OPL3); + update_AR4_DR4(OPL3); + update_SL4_RR4(OPL3); + update_5_WS3(OPL3); +} + +EnvelopeGenerator::EnvelopeGenerator() { + stage = OFF; + actualAttackRate = actualDecayRate = actualReleaseRate = 0; + xAttackIncrement = xMinimumInAttack = 0; + dBdecayIncrement = 0; + dBreleaseIncrement = 0; + attenuation = totalLevel = sustainLevel = 0; + x = dBtoX(-96); + envelope = -96; +} + +void EnvelopeGenerator::setActualSustainLevel(int sl) { + // If all SL bits are 1, sustain level is set to -93 dB: + if(sl == 0x0F) { + sustainLevel = -93; + return; + } + // The datasheet states that the SL formula is + // sustainLevel = -24*d7 -12*d6 -6*d5 -3*d4, + // translated as: + sustainLevel = -3*sl; +} + +void EnvelopeGenerator::setTotalLevel(int tl) { + // The datasheet states that the TL formula is + // TL = -(24*d5 + 12*d4 + 6*d3 + 3*d2 + 1.5*d1 + 0.75*d0), + // translated as: + totalLevel = tl*-0.75; +} + +void EnvelopeGenerator::setAtennuation(int f_number, int block, int ksl) { + int hi4bits = (f_number>>6)&0x0F; + switch(ksl) { + case 0: + attenuation = 0; + break; + case 1: + // ~3 dB/Octave + attenuation = OperatorData::ksl3dBtable[hi4bits][block]; + break; + case 2: + // ~1.5 dB/Octave + attenuation = OperatorData::ksl3dBtable[hi4bits][block]/2; + break; + case 3: + // ~6 dB/Octave + attenuation = OperatorData::ksl3dBtable[hi4bits][block]*2; + } +} + +void EnvelopeGenerator::setActualAttackRate(int attackRate, int ksr, int keyScaleNumber) { + // According to the YMF278B manual's OPL3 section, the attack curve is exponential, + // with a dynamic range from -96 dB to 0 dB and a resolution of 0.1875 dB + // per level. + // + // This method sets an attack increment and attack minimum value + // that creates a exponential dB curve with 'period0to100' seconds in length + // and 'period10to90' seconds between 10% and 90% of the curve total level. + actualAttackRate = calculateActualRate(attackRate, ksr, keyScaleNumber); + double period0to100inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][0]/1000.0; + int period0to100inSamples = (int)(period0to100inSeconds*sampleRate); + double period10to90inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][1]/1000.0; + int period10to90inSamples = (int)(period10to90inSeconds*sampleRate); + // The x increment is dictated by the period between 10% and 90%: + xAttackIncrement = OPL3Data::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); + // Discover how many samples are still from the top. + // It cannot reach 0 dB, since x is a logarithmic parameter and would be + // negative infinity. So we will use -0.1875 dB as the resolution + // maximum. + // + // percentageToX(0.9) + samplesToTheTop*xAttackIncrement = dBToX(-0.1875); -> + // samplesToTheTop = (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); -> + // period10to100InSamples = period10to90InSamples + samplesToTheTop; -> + int period10to100inSamples = (int) (period10to90inSamples + (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); + // Discover the minimum x that, through the attackIncrement value, keeps + // the 10%-90% period, and reaches 0 dB at the total period: + xMinimumInAttack = percentageToX(0.1) - (period0to100inSamples-period10to100inSamples)*xAttackIncrement; +} + + +void EnvelopeGenerator::setActualDecayRate(int decayRate, int ksr, int keyScaleNumber) { + actualDecayRate = calculateActualRate(decayRate, ksr, keyScaleNumber); + double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualDecayRate][1]/1000.0; + // Differently from the attack curve, the decay/release curve is linear. + // The dB increment is dictated by the period between 10% and 90%: + dBdecayIncrement = OPL3Data::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); +} + +void EnvelopeGenerator::setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber) { + actualReleaseRate = calculateActualRate(releaseRate, ksr, keyScaleNumber); + double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualReleaseRate][1]/1000.0; + dBreleaseIncrement = OPL3Data::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); +} + +int EnvelopeGenerator::calculateActualRate(int rate, int ksr, int keyScaleNumber) { + int rof = EnvelopeGeneratorData::rateOffset[ksr][keyScaleNumber]; + int actualRate = rate*4 + rof; + // If, as an example at the maximum, rate is 15 and the rate offset is 15, + // the value would + // be 75, but the maximum allowed is 63: + if(actualRate > 63) actualRate = 63; + return actualRate; +} + +double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { + // The datasheets attenuation values + // must be halved to match the real OPL3 output. + double envelopeSustainLevel = sustainLevel / 2; + double envelopeTremolo = + OPL3::OPL3Data->tremoloTable[OPL3->dam][OPL3->tremoloIndex] / 2; + double envelopeAttenuation = attenuation / 2; + double envelopeTotalLevel = totalLevel / 2; + + double envelopeMinimum = -96; + double envelopeResolution = 0.1875; + + double outputEnvelope; + // + // Envelope Generation + // + switch(stage) { + case ATTACK: + // Since the attack is exponential, it will never reach 0 dB, so + // we´ll work with the next to maximum in the envelope resolution. + if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::INFINITY) { + // The attack is exponential. + envelope = -pow(2.0,x); + x += xAttackIncrement; + break; + } + else { + // It is needed here to explicitly set envelope = 0, since + // only the attack can have a period of + // 0 seconds and produce an infinity envelope increment. + envelope = 0; + stage = DECAY; + } + case DECAY: + // The decay and release are linear. + if(envelope>envelopeSustainLevel) { + envelope -= dBdecayIncrement; + break; + } + else + stage = SUSTAIN; + case SUSTAIN: + // The Sustain stage is mantained all the time of the Key ON, + // even if we are in non-sustaining mode. + // This is necessary because, if the key is still pressed, we can + // change back and forth the state of EGT, and it will release and + // hold again accordingly. + if(egt==1) break; + else { + if(envelope > envelopeMinimum) + envelope -= dBreleaseIncrement; + else stage = OFF; + } + break; + case RELEASE: + // If we have Key OFF, only here we are in the Release stage. + // Now, we can turn EGT back and forth and it will have no effect,i.e., + // it will release inexorably to the Off stage. + if(envelope > envelopeMinimum) + envelope -= dBreleaseIncrement; + else stage = OFF; + } + + // Ongoing original envelope + outputEnvelope = envelope; + + //Tremolo + if(am == 1) outputEnvelope += envelopeTremolo; + + //Attenuation + outputEnvelope += envelopeAttenuation; + + //Total Level + outputEnvelope += envelopeTotalLevel; + + return outputEnvelope; +} + +void EnvelopeGenerator::keyOn() { + // If we are taking it in the middle of a previous envelope, + // start to rise from the current level: + // envelope = - (2 ^ x); -> + // 2 ^ x = -envelope -> + // x = log2(-envelope); -> + double xCurrent = OperatorData::log2(-envelope); + x = xCurrent < xMinimumInAttack ? xCurrent : xMinimumInAttack; + stage = ATTACK; +} + +void EnvelopeGenerator::keyOff() { + if(stage != OFF) stage = RELEASE; +} + +double EnvelopeGenerator::dBtoX(double dB) { + return OperatorData::log2(-dB); +} + +double EnvelopeGenerator::percentageToDB(double percentage) { + return log10(percentage) * 10.0; +} + +double EnvelopeGenerator::percentageToX(double percentage) { + return dBtoX(percentageToDB(percentage)); +} + +PhaseGenerator::PhaseGenerator() { + phase = phaseIncrement = 0; +} + +void PhaseGenerator::setFrequency(int f_number, int block, int mult) { + // This frequency formula is derived from the following equation: + // f_number = baseFrequency * pow(2,19) / sampleRate / pow(2,block-1); + double baseFrequency = + f_number * pow(2.0, block-1) * sampleRate / pow(2.0,19); + double operatorFrequency = baseFrequency*OperatorData::multTable[mult]; + + // phase goes from 0 to 1 at + // period = (1/frequency) seconds -> + // Samples in each period is (1/frequency)*sampleRate = + // = sampleRate/frequency -> + // So the increment in each sample, to go from 0 to 1, is: + // increment = (1-0) / samples in the period -> + // increment = 1 / (OPL3Data.sampleRate/operatorFrequency) -> + phaseIncrement = operatorFrequency/sampleRate; +} + +double PhaseGenerator::getPhase(OPL3 *OPL3, int vib) { + if(vib==1) + // phaseIncrement = (operatorFrequency * vibrato) / sampleRate + phase += phaseIncrement*OPL3::OPL3Data->vibratoTable[OPL3->dvb][OPL3->vibratoIndex]; + else + // phaseIncrement = operatorFrequency / sampleRate + phase += phaseIncrement; + double dontcare; + phase = modf(phase, &dontcare); + return phase; +} + +void PhaseGenerator::keyOn() { + phase = 0; +} + +void RhythmChannel::getChannelOutput(OPL3 *OPL3, double output[4]) { + double channelOutput = 0, op1Output = 0, op2Output = 0; + + // Note that, different from the common channel, + // we do not check to see if the Operator's envelopes are Off. + // Instead, we always do the calculations, + // to update the publicly available phase. + op1Output = op1->getOperatorOutput(OPL3, Operator::noModulator); + op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); + channelOutput = (op1Output + op2Output) / 2; + + getInFourChannels(OPL3, channelOutput, output); +}; + +TopCymbalOperator::TopCymbalOperator(int baseAddress) +: Operator(baseAddress) +{ } + +TopCymbalOperator::TopCymbalOperator() +: Operator(topCymbalOperatorBaseAddress) +{ } + +double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { + double highHatOperatorPhase = + OPL3->highHatOperator.phase * OperatorData::multTable[OPL3->highHatOperator.mult]; + // The Top Cymbal operator uses his own phase together with the High Hat phase. + return getOperatorOutput(OPL3, modulator, highHatOperatorPhase); +} + +// This method is used here with the HighHatOperator phase +// as the externalPhase. +// Conversely, this method is also used through inheritance by the HighHatOperator, +// now with the TopCymbalOperator phase as the externalPhase. +double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator, double externalPhase) { + double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); + envelope = pow(10.0, envelopeInDB/10.0); + + phase = phaseGenerator.getPhase(OPL3, vib); + + int waveIndex = ws & ((OPL3->_new<<2) + 3); + double *waveform = OPL3::OperatorData->waveforms[waveIndex]; + + // Empirically tested multiplied phase for the Top Cymbal: + double dontcare; + double carrierPhase = modf(8 * phase, &dontcare); + double modulatorPhase = externalPhase; + double modulatorOutput = getOutput(Operator::noModulator, modulatorPhase, waveform); + double carrierOutput = getOutput(modulatorOutput,carrierPhase, waveform); + + int cycles = 4; + double chopped = (carrierPhase * cycles) /* %cycles */; + chopped = chopped - floor(chopped / cycles) * cycles; + if( chopped > 0.1) carrierOutput = 0; + + return carrierOutput*2; +} + +HighHatOperator::HighHatOperator() +: TopCymbalOperator(highHatOperatorBaseAddress) +{ } + +double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { + double topCymbalOperatorPhase = + OPL3->topCymbalOperator.phase * OperatorData::multTable[OPL3->topCymbalOperator.mult]; + // The sound output from the High Hat resembles the one from + // Top Cymbal, so we use the parent method and modify its output + // accordingly afterwards. + double operatorOutput = TopCymbalOperator::getOperatorOutput(OPL3, modulator, topCymbalOperatorPhase); + if(operatorOutput == 0) operatorOutput = pr_opl3.GenRand_Real1()*envelope; + return operatorOutput; +} + +SnareDrumOperator::SnareDrumOperator() +: Operator(snareDrumOperatorBaseAddress) +{ } + +double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { + if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; + + double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); + envelope = pow(10.0, envelopeInDB/10.0); + + // If it is in OPL2 mode, use first four waveforms only: + int waveIndex = ws & ((OPL3->_new<<2) + 3); + double *waveform = OPL3::OperatorData->waveforms[waveIndex]; + + phase = OPL3->highHatOperator.phase * 2; + + double operatorOutput = getOutput(modulator, phase, waveform); + + double noise = pr_opl3.GenRand_Real1() * envelope; + + if(operatorOutput/envelope != 1 && operatorOutput/envelope != -1) { + if(operatorOutput > 0) operatorOutput = noise; + else if(operatorOutput < 0) operatorOutput = -noise; + else operatorOutput = 0; + } + + return operatorOutput*2; +} + +BassDrumChannel::BassDrumChannel() +: Channel2op(bassDrumChannelBaseAddress, &my_op1, &my_op2), + my_op1(op1BaseAddress), my_op2(op2BaseAddress) +{ } + +void BassDrumChannel::getChannelOutput(OPL3 *OPL3, double output[4]) { + // Bass Drum ignores first operator, when it is in series. + if(cnt == 1) op1->ar=0; + return Channel2op::getChannelOutput(OPL3, output); +} + +void OPL3Data::loadVibratoTable() { + + // According to the YMF262 datasheet, the OPL3 vibrato repetition rate is 6.1 Hz. + // According to the YMF278B manual, it is 6.0 Hz. + // The information that the vibrato table has 8 levels standing 1024 samples each + // was taken from the emulator by Jarek Burczynski and Tatsuyuki Satoh, + // with a frequency of 6,06689453125 Hz, what makes sense with the difference + // in the information on the datasheets. + + const double semitone = pow(2.0,1/12.0); + // A cent is 1/100 of a semitone: + const double cent = pow(semitone, 1/100.0); + + // When dvb=0, the depth is 7 cents, when it is 1, the depth is 14 cents. + const double DVB0 = pow(cent,7.0); + const double DVB1 = pow(cent,14.0); + int i; + for(i = 0; i<1024; i++) + vibratoTable[0][i] = vibratoTable[1][i] = 1; + for(;i<2048; i++) { + vibratoTable[0][i] = sqrt(DVB0); + vibratoTable[1][i] = sqrt(DVB1); + } + for(;i<3072; i++) { + vibratoTable[0][i] = DVB0; + vibratoTable[1][i] = DVB1; + } + for(;i<4096; i++) { + vibratoTable[0][i] = sqrt(DVB0); + vibratoTable[1][i] = sqrt(DVB1); + } + for(; i<5120; i++) + vibratoTable[0][i] = vibratoTable[1][i] = 1; + for(;i<6144; i++) { + vibratoTable[0][i] = 1/sqrt(DVB0); + vibratoTable[1][i] = 1/sqrt(DVB1); + } + for(;i<7168; i++) { + vibratoTable[0][i] = 1/DVB0; + vibratoTable[1][i] = 1/DVB1; + } + for(;i<8192; i++) { + vibratoTable[0][i] = 1/sqrt(DVB0); + vibratoTable[1][i] = 1/sqrt(DVB1); + } + +} + +void OPL3Data::loadTremoloTable() +{ + // The tremolo depth is -1 dB when DAM = 0, and -4.8 dB when DAM = 1. + static const double tremoloDepth[] = {-1, -4.8}; + + // According to the YMF278B manual's OPL3 section graph, + // the tremolo waveform is not + // \ / a sine wave, but a single triangle waveform. + // \ / Thus, the period to achieve the tremolo depth is T/2, and + // \ / the increment in each T/2 section uses a frequency of 2*f. + // \/ Tremolo varies from 0 dB to depth, to 0 dB again, at frequency*2: + const double tremoloIncrement[] = { + calculateIncrement(tremoloDepth[0],0,1/(2*tremoloFrequency)), + calculateIncrement(tremoloDepth[1],0,1/(2*tremoloFrequency)) + }; + + int tremoloTableLength = (int)(sampleRate/tremoloFrequency); + + // This is undocumented. The tremolo starts at the maximum attenuation, + // instead of at 0 dB: + tremoloTable[0][0] = tremoloDepth[0]; + tremoloTable[1][0] = tremoloDepth[1]; + int counter = 0; + // The first half of the triangle waveform: + while(tremoloTable[0][counter]<0) { + counter++; + tremoloTable[0][counter] = tremoloTable[0][counter-1] + tremoloIncrement[0]; + tremoloTable[1][counter] = tremoloTable[1][counter-1] + tremoloIncrement[1]; + } + // The second half of the triangle waveform: + while(tremoloTable[0][counter]>tremoloDepth[0] && counter> 8, reg & 0xFF, v); +} + +void OPL3::Update(float *buffer, int length) +{ + double output[4]; + + for (int i = 0; i < length; ++i) + { + read(output); + buffer[i*2 ] += float(output[0] * 0.25f); + buffer[i*2+1] += float(output[1] * 0.25f); + } +} + +void OPL3::SetPanning(int c, float left, float right) +{ +} + +OPLEmul *JavaOPLCreate(bool stereo) +{ + return new OPL3; +} diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 4dc15e39f..b9d06629f 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -323,7 +323,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); uint i; - IsOPL3 = (opl_core == 1); + IsOPL3 = (opl_core == 1 || opl_core == 2); memset(chips, 0, sizeof(chips)); if (IsOPL3) @@ -332,7 +332,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = IsOPL3 ? DBOPLCreate(stereo) : YM3812Create(stereo); + OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : JavaOPLCreate(stereo)) : YM3812Create(stereo); if (chip == NULL) { break; diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h index 1f1c5e2c1..12556647f 100644 --- a/src/oplsynth/opl.h +++ b/src/oplsynth/opl.h @@ -20,5 +20,6 @@ public: OPLEmul *YM3812Create(bool stereo); OPLEmul *DBOPLCreate(bool stereo); +OPLEmul *JavaOPLCreate(bool stereo); #endif \ No newline at end of file diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index fe3463386..fd3480a39 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -28,7 +28,7 @@ OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len) Music = new OPLmusicFile (file, musiccache, len); m_Stream = GSnd->CreateStream (FillStream, samples*4, - (opl_core != 1 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); + (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); diff --git a/zdoom.vcproj b/zdoom.vcproj index fb5e5b1f5..43efc9bd5 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -2618,6 +2618,10 @@ RelativePath=".\src\oplsynth\opl.h" > + + @@ -2632,34 +2636,6 @@ - - - - - - - - - - - - Date: Fri, 16 Nov 2012 06:27:03 +0000 Subject: [PATCH 049/387] - Optimize the Java-based OPL3 emulator some by not calling expensive math functions liberally during the rendering loop. SVN r3968 (trunk) --- src/oplsynth/OPL3.cpp | 283 ++++++++++++++++++++++-------------- src/oplsynth/muslib.h | 1 - src/oplsynth/opl.h | 2 + src/sound/music_mus_opl.cpp | 1 + 4 files changed, 174 insertions(+), 113 deletions(-) diff --git a/src/oplsynth/OPL3.cpp b/src/oplsynth/OPL3.cpp index 2e86f2be5..cc4876187 100644 --- a/src/oplsynth/OPL3.cpp +++ b/src/oplsynth/OPL3.cpp @@ -49,11 +49,24 @@ #include "doomtype.h" #include "opl.h" #include "m_random.h" +#include "xs_Float.h" static FRandom pr_opl3; +#define VOLUME_MUL 0.25 + class Operator; +static inline double StripIntPart(double num) +{ +#if 0 + double dontcare; + return modf(num, &dontcare); +#else + return num - xs_RoundToInt(num); +#endif +} + // // Channels // @@ -64,7 +77,7 @@ class Channel protected: double feedback[2]; - int fnuml, fnumh, kon, block, cha, chb, chc, chd, fb, cnt; + int fnuml, fnumh, kon, block, fb, cha, chb, cnt; // Factor to convert between normalized amplitude to normalized // radians. The amplitude maximum is equivalent to 8*Pi radians. @@ -72,20 +85,20 @@ protected: public: int channelBaseAddress; + + double leftPan, rightPan; Channel (int baseAddress); void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); void update_FNUML8(class OPL3 *OPL3); void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); void updateChannel(class OPL3 *OPL3); - virtual void getChannelOutput(class OPL3 *OPL3, double output[4]) = 0; + void updatePan(class OPL3 *OPL3); + virtual double getChannelOutput(class OPL3 *OPL3) = 0; virtual void keyOn() = 0; virtual void keyOff() = 0; virtual void updateOperators(class OPL3 *OPL3) = 0; - -protected: - void getInFourChannels(class OPL3 *OPL3, double channelOutput, double output[4]); }; @@ -95,7 +108,7 @@ public: Operator *op1, *op2; Channel2op (int baseAddress, Operator *o1, Operator *o2); - void getChannelOutput(class OPL3 *OPL3, double output[4]); + double getChannelOutput(class OPL3 *OPL3); void keyOn(); void keyOff(); @@ -109,7 +122,7 @@ public: Operator *op1, *op2, *op3, *op4; Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4); - void getChannelOutput(class OPL3 *OPL3, double output[4]); + double getChannelOutput(class OPL3 *OPL3); void keyOn(); void keyOff(); @@ -121,7 +134,7 @@ class DisabledChannel : public Channel { public: DisabledChannel() : Channel(0) { } - void getChannelOutput(class OPL3 *OPL3, double output[4]) { return getInFourChannels(OPL3, 0, output); } + double getChannelOutput(class OPL3 *OPL3) { return 0; } void keyOn() { } void keyOff() { } void updateOperators(class OPL3 *OPL3) { } @@ -234,7 +247,7 @@ public: RhythmChannel(int baseAddress, Operator *o1, Operator *o2) : Channel2op(baseAddress, o1, o2) { } - void getChannelOutput(class OPL3 *OPL3, double output[4]); + double getChannelOutput(class OPL3 *OPL3); // Rhythm channels are always running, // only the envelope is activated by the user. @@ -296,7 +309,7 @@ class BassDrumChannel : public Channel2op { public: BassDrumChannel(); - void getChannelOutput(class OPL3 *OPL3, double output[4]); + double getChannelOutput(class OPL3 *OPL3); // Key ON and OFF are unused in rhythm channels. void keyOn() { } @@ -319,12 +332,10 @@ public: _7_NEW1_Offset = 0x105, _2_CONNECTIONSEL6_Offset = 0x104; - #define sampleRate (49700.0) - // The OPL3 tremolo repetition rate is 3.7 Hz. #define tremoloFrequency (3.7) - static const int tremoloTableLength = (int)(sampleRate/tremoloFrequency); + static const int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); static const int vibratoTableLength = 8192; OPL3Data::OPL3Data() @@ -340,7 +351,7 @@ public: double tremoloTable[2][tremoloTableLength]; static double calculateIncrement(double begin, double end, double period) { - return (end-begin)/sampleRate * (1/period); + return (end-begin)/OPL_SAMPLE_RATE * (1/period); } private: @@ -391,10 +402,25 @@ struct OperatorData //OPL3 has eight waveforms: double waveforms[8][waveLength]; - + +#define MIN_DB (-120.0) +#define DB_TABLE_RES (4.0) +#define DB_TABLE_SIZE (int)(-MIN_DB * DB_TABLE_RES) + + double dbpow[DB_TABLE_SIZE]; + +#define ATTACK_MIN (-5.0) +#define ATTACK_MAX (8.0) +#define ATTACK_RES (0.03125) +#define ATTACK_TABLE_SIZE (int)((ATTACK_MAX - ATTACK_MIN) / ATTACK_RES) + + double attackTable[ATTACK_TABLE_SIZE]; + OperatorData() { loadWaveforms(); + loaddBPowTable(); + loadAttackTable(); } static double log2(double x) { @@ -402,6 +428,8 @@ struct OperatorData } private: void loadWaveforms(); + void loaddBPowTable(); + void loadAttackTable(); }; const float OperatorData::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; @@ -466,7 +494,7 @@ namespace EnvelopeGeneratorData {0.00,0.00}, {0.00,0.00}, {0.00,0.00}, {0.00,0.00} }; - // These decay and release periods in miliseconds were taken from the YMF278B manual. + // These decay and release periods in milliseconds were taken from the YMF278B manual. // The rate index range from 0 to 63, with different data for // 0%-100% and for 10%-90%: static const double decayAndReleaseTimeValuesTable[64][2] = { @@ -534,7 +562,7 @@ public: // with each frame being four 16-bit samples, // corresponding to the OPL3 four output channels CHA...CHD. public: - void read(double output[4]); + //void read(float output[2]); void write(int array, int address, int data); OPL3(); @@ -550,6 +578,7 @@ private: void update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); void update_7_NEW1(); void setEnabledChannels(); + void updateChannelPans(); void update_2_CONNECTIONSEL6(); void set4opConnections(); void setRhythmMode(); @@ -568,29 +597,30 @@ OperatorData *OPL3::OperatorData; OPL3Data *OPL3::OPL3Data; int OPL3::InstanceCount; -void OPL3::read(double output[4]) { - double channelOutput[4]; +void OPL3::Update(float *output, int numsamples) { + while (numsamples--) { + // If _new = 0, use OPL2 mode with 9 channels. If _new = 1, use OPL3 18 channels; + for(int array=0; array < (_new + 1); array++) + for(int channelNumber=0; channelNumber < 9; channelNumber++) { + // Reads output from each OPL3 channel, and accumulates it in the output buffer: + Channel *channel = channels[array][channelNumber]; + if (channel != &disabledChannel) + { + double channelOutput = channel->getChannelOutput(this); + output[0] += float(channelOutput * channel->leftPan); + output[1] += float(channelOutput * channel->rightPan); + } + } - for(int outputChannelNumber=0; outputChannelNumber<4; outputChannelNumber++) - output[outputChannelNumber] = 0; - - // If _new = 0, use OPL2 mode with 9 channels. If _new = 1, use OPL3 18 channels; - for(int array=0; array < (_new + 1); array++) - for(int channelNumber=0; channelNumber < 9; channelNumber++) { - // Reads output from each OPL3 channel, and accumulates it in the output buffer: - channels[array][channelNumber]->getChannelOutput(this, channelOutput); - for(int outputChannelNumber=0; outputChannelNumber<4; outputChannelNumber++) - output[outputChannelNumber] += channelOutput[outputChannelNumber]; - } - - // Advances the OPL3-wide vibrato index, which is used by - // PhaseGenerator.getPhase() in each Operator. - vibratoIndex++; - if(vibratoIndex >= OPL3Data::vibratoTableLength) vibratoIndex = 0; - // Advances the OPL3-wide tremolo index, which is used by - // EnvelopeGenerator.getEnvelope() in each Operator. - tremoloIndex++; - if(tremoloIndex >= OPL3Data::tremoloTableLength) tremoloIndex = 0; + // Advances the OPL3-wide vibrato index, which is used by + // PhaseGenerator.getPhase() in each Operator. + vibratoIndex = (vibratoIndex + 1) & (OPL3Data::vibratoTableLength - 1); + // Advances the OPL3-wide tremolo index, which is used by + // EnvelopeGenerator.getEnvelope() in each Operator. + tremoloIndex++; + if(tremoloIndex >= OPL3Data::tremoloTableLength) tremoloIndex = 0; + output += 2; + } } void OPL3::write(int array, int address, int data) { @@ -854,6 +884,7 @@ void OPL3::update_7_NEW1() { _new = (_7_new1 & 0x01); if(_new==1) setEnabledChannels(); set4opConnections(); + updateChannelPans(); } void OPL3::setEnabledChannels() { @@ -862,7 +893,17 @@ void OPL3::setEnabledChannels() { int baseAddress = channels[array][i]->channelBaseAddress; registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; channels[array][i]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); - } + } +} + +void OPL3::updateChannelPans() { + for(int array=0; array<2; array++) + for(int i=0; i<9; i++) { + int baseAddress = channels[array][i]->channelBaseAddress; + registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; + channels[array][i]->updatePan(this); + } + } void OPL3::update_2_CONNECTIONSEL6() { @@ -915,10 +956,22 @@ void OPL3::setRhythmMode() { for(int i=6; i<=8; i++) channels[0][i]->updateChannel(this); } +static double EnvelopeFromDB(double db) +{ +#if 0 + return pow(10.0, db/10); +#else + if (db < MIN_DB) + return 0; + return OPL3::OperatorData->dbpow[xs_FloorToInt(-db * DB_TABLE_RES)]; +#endif +} + Channel::Channel (int baseAddress) { channelBaseAddress = baseAddress; - fnuml = fnumh = kon = block = cha = chb = chc = chd = fb = cnt = 0; + fnuml = fnumh = kon = block = fb = cnt = 0; feedback[0] = feedback[1] = 0; + leftPan = rightPan = 1; } void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) { @@ -949,32 +1002,35 @@ void Channel::update_FNUML8(OPL3 *OPL3) { void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) { int chd1_chc1_chb1_cha1_fb3_cnt1 = OPL3->registers[channelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset]; - chd = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x80) >> 7; - chc = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x40) >> 6; +// chd = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x80) >> 7; +// chc = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x40) >> 6; chb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x20) >> 5; cha = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x10) >> 4; fb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x0E) >> 1; cnt = chd1_chc1_chb1_cha1_fb3_cnt1 & 0x01; + updatePan(OPL3); updateOperators(OPL3); } +void Channel::updatePan(OPL3 *OPL3) { + if (OPL3->_new == 0) + { + leftPan = VOLUME_MUL; + rightPan = VOLUME_MUL; + } + else + { + leftPan = cha * VOLUME_MUL; + rightPan = chb * VOLUME_MUL; + } +} + void Channel::updateChannel(OPL3 *OPL3) { update_2_KON1_BLOCK3_FNUMH2(OPL3); update_FNUML8(OPL3); update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3); } -void Channel::getInFourChannels(OPL3 *OPL3, double channelOutput, double output[4]) { - if( OPL3->_new==0) - output[0] = output[1] = output[2] = output[3] = channelOutput; - else { - output[0] = (cha==1) ? channelOutput : 0; - output[1] = (chb==1) ? channelOutput : 0; - output[2] = (chc==1) ? channelOutput : 0; - output[3] = (chd==1) ? channelOutput : 0; - } -} - Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2) : Channel(baseAddress) { @@ -982,18 +1038,17 @@ Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2) op2 = o2; } -void Channel2op::getChannelOutput(OPL3 *OPL3, double output[4]) { +double Channel2op::getChannelOutput(OPL3 *OPL3) { double channelOutput = 0, op1Output = 0, op2Output = 0; // The feedback uses the last two outputs from // the first operator, instead of just the last one. double feedbackOutput = (feedback[0] + feedback[1]) / 2; - double dontcare; switch(cnt) { // CNT = 0, the operators are in series, with the first in feedback. case 0: if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); channelOutput = op2->getOperatorOutput(OPL3, op1Output*toPhase); break; @@ -1001,15 +1056,15 @@ void Channel2op::getChannelOutput(OPL3 *OPL3, double output[4]) { case 1: if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); channelOutput = (op1Output + op2Output) / 2; } feedback[0] = feedback[1]; - feedback[1] = modf(op1Output * ChannelData::feedback[fb], &dontcare); - getInFourChannels(OPL3, channelOutput, output); + feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); + return channelOutput; } void Channel2op::keyOn() { @@ -1040,10 +1095,9 @@ Channel4op::Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o op4 = o4; } -void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { +double Channel4op::getChannelOutput(OPL3 *OPL3) { double channelOutput = 0, op1Output = 0, op2Output = 0, op3Output = 0, op4Output = 0; - double dontcare; int secondChannelBaseAddress = channelBaseAddress+3; int secondCnt = OPL3->registers[secondChannelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] & 0x1; @@ -1054,7 +1108,7 @@ void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { switch(cnt4op) { case 0: if(op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); @@ -1065,7 +1119,7 @@ void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { case 1: if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF && op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); @@ -1078,7 +1132,7 @@ void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { case 2: if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); @@ -1092,7 +1146,7 @@ void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && op3->envelopeGenerator.stage==EnvelopeGenerator::OFF && op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return getInFourChannels(OPL3, 0, output); + return 0; op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); @@ -1105,9 +1159,9 @@ void Channel4op::getChannelOutput(OPL3 *OPL3, double output[4]) { } feedback[0] = feedback[1]; - feedback[1] = modf(op1Output * ChannelData::feedback[fb], &dontcare); + feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); - getInFourChannels(OPL3, channelOutput, output); + return channelOutput; } void Channel4op::keyOn() { @@ -1216,7 +1270,7 @@ double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = pow(10, envelopeInDB/10.0); + envelope = EnvelopeFromDB(envelopeInDB); // If it is in OPL2 mode, use first four waveforms only: ws &= ((OPL3->_new<<2) + 3); @@ -1229,14 +1283,7 @@ double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { } double Operator::getOutput(double modulator, double outputPhase, double *waveform) { - double dontcare; - outputPhase = modf(outputPhase + modulator, &dontcare); - if(outputPhase<0) { - outputPhase++; - // If the double could not afford to be less than 1: - outputPhase = modf(outputPhase, &dontcare); - } - int sampleIndex = (int) (outputPhase * OperatorData::waveLength); + int sampleIndex = xs_FloorToInt((outputPhase + modulator) * OperatorData::waveLength) & (OperatorData::waveLength - 1); return waveform[sampleIndex] * envelope; } @@ -1323,9 +1370,9 @@ void EnvelopeGenerator::setActualAttackRate(int attackRate, int ksr, int keyScal // and 'period10to90' seconds between 10% and 90% of the curve total level. actualAttackRate = calculateActualRate(attackRate, ksr, keyScaleNumber); double period0to100inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][0]/1000.0; - int period0to100inSamples = (int)(period0to100inSeconds*sampleRate); + int period0to100inSamples = (int)(period0to100inSeconds*OPL_SAMPLE_RATE); double period10to90inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][1]/1000.0; - int period10to90inSamples = (int)(period10to90inSeconds*sampleRate); + int period10to90inSamples = (int)(period10to90inSeconds*OPL_SAMPLE_RATE); // The x increment is dictated by the period between 10% and 90%: xAttackIncrement = OPL3Data::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); // Discover how many samples are still from the top. @@ -1389,7 +1436,17 @@ double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { // we´ll work with the next to maximum in the envelope resolution. if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::INFINITY) { // The attack is exponential. +#if 0 envelope = -pow(2.0,x); +#else + int index = xs_FloorToInt((x - ATTACK_MIN) / ATTACK_RES); + if (index < 0) + envelope = OPL3::OperatorData->attackTable[0]; + else if (index >= ATTACK_TABLE_SIZE) + envelope = OPL3::OperatorData->attackTable[ATTACK_TABLE_SIZE-1]; + else + envelope = OPL3::OperatorData->attackTable[index]; +#endif x += xAttackIncrement; break; } @@ -1478,30 +1535,29 @@ PhaseGenerator::PhaseGenerator() { void PhaseGenerator::setFrequency(int f_number, int block, int mult) { // This frequency formula is derived from the following equation: - // f_number = baseFrequency * pow(2,19) / sampleRate / pow(2,block-1); + // f_number = baseFrequency * pow(2,19) / OPL_SAMPLE_RATE / pow(2,block-1); double baseFrequency = - f_number * pow(2.0, block-1) * sampleRate / pow(2.0,19); + f_number * pow(2.0, block-1) * OPL_SAMPLE_RATE / pow(2.0,19); double operatorFrequency = baseFrequency*OperatorData::multTable[mult]; // phase goes from 0 to 1 at // period = (1/frequency) seconds -> - // Samples in each period is (1/frequency)*sampleRate = - // = sampleRate/frequency -> + // Samples in each period is (1/frequency)*OPL_SAMPLE_RATE = + // = OPL_SAMPLE_RATE/frequency -> // So the increment in each sample, to go from 0 to 1, is: // increment = (1-0) / samples in the period -> - // increment = 1 / (OPL3Data.sampleRate/operatorFrequency) -> - phaseIncrement = operatorFrequency/sampleRate; + // increment = 1 / (OPL_SAMPLE_RATE/operatorFrequency) -> + phaseIncrement = operatorFrequency/OPL_SAMPLE_RATE; } double PhaseGenerator::getPhase(OPL3 *OPL3, int vib) { if(vib==1) - // phaseIncrement = (operatorFrequency * vibrato) / sampleRate + // phaseIncrement = (operatorFrequency * vibrato) / OPL_SAMPLE_RATE phase += phaseIncrement*OPL3::OPL3Data->vibratoTable[OPL3->dvb][OPL3->vibratoIndex]; else - // phaseIncrement = operatorFrequency / sampleRate + // phaseIncrement = operatorFrequency / OPL_SAMPLE_RATE phase += phaseIncrement; - double dontcare; - phase = modf(phase, &dontcare); + // Originally clamped phase to [0,1), but that's not needed return phase; } @@ -1509,7 +1565,7 @@ void PhaseGenerator::keyOn() { phase = 0; } -void RhythmChannel::getChannelOutput(OPL3 *OPL3, double output[4]) { +double RhythmChannel::getChannelOutput(OPL3 *OPL3) { double channelOutput = 0, op1Output = 0, op2Output = 0; // Note that, different from the common channel, @@ -1520,7 +1576,7 @@ void RhythmChannel::getChannelOutput(OPL3 *OPL3, double output[4]) { op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); channelOutput = (op1Output + op2Output) / 2; - getInFourChannels(OPL3, channelOutput, output); + return channelOutput; }; TopCymbalOperator::TopCymbalOperator(int baseAddress) @@ -1534,7 +1590,7 @@ TopCymbalOperator::TopCymbalOperator() double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { double highHatOperatorPhase = OPL3->highHatOperator.phase * OperatorData::multTable[OPL3->highHatOperator.mult]; - // The Top Cymbal operator uses his own phase together with the High Hat phase. + // The Top Cymbal operator uses its own phase together with the High Hat phase. return getOperatorOutput(OPL3, modulator, highHatOperatorPhase); } @@ -1544,7 +1600,7 @@ double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { // now with the TopCymbalOperator phase as the externalPhase. double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator, double externalPhase) { double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = pow(10.0, envelopeInDB/10.0); + envelope = EnvelopeFromDB(envelopeInDB); phase = phaseGenerator.getPhase(OPL3, vib); @@ -1552,11 +1608,10 @@ double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator, double double *waveform = OPL3::OperatorData->waveforms[waveIndex]; // Empirically tested multiplied phase for the Top Cymbal: - double dontcare; - double carrierPhase = modf(8 * phase, &dontcare); + double carrierPhase = 8 * phase; double modulatorPhase = externalPhase; double modulatorOutput = getOutput(Operator::noModulator, modulatorPhase, waveform); - double carrierOutput = getOutput(modulatorOutput,carrierPhase, waveform); + double carrierOutput = getOutput(modulatorOutput, carrierPhase, waveform); int cycles = 4; double chopped = (carrierPhase * cycles) /* %cycles */; @@ -1589,7 +1644,7 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = pow(10.0, envelopeInDB/10.0); + envelope = EnvelopeFromDB(envelopeInDB); // If it is in OPL2 mode, use first four waveforms only: int waveIndex = ws & ((OPL3->_new<<2) + 3); @@ -1615,10 +1670,10 @@ BassDrumChannel::BassDrumChannel() my_op1(op1BaseAddress), my_op2(op2BaseAddress) { } -void BassDrumChannel::getChannelOutput(OPL3 *OPL3, double output[4]) { +double BassDrumChannel::getChannelOutput(OPL3 *OPL3) { // Bass Drum ignores first operator, when it is in series. if(cnt == 1) op1->ar=0; - return Channel2op::getChannelOutput(OPL3, output); + return Channel2op::getChannelOutput(OPL3); } void OPL3Data::loadVibratoTable() { @@ -1685,7 +1740,7 @@ void OPL3Data::loadTremoloTable() calculateIncrement(tremoloDepth[1],0,1/(2*tremoloFrequency)) }; - int tremoloTableLength = (int)(sampleRate/tremoloFrequency); + int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); // This is undocumented. The tremolo starts at the maximum attenuation, // instead of at 0 dB: @@ -1752,6 +1807,22 @@ void OperatorData::loadWaveforms() { } } +void OperatorData::loaddBPowTable() +{ + for (int i = 0; i < DB_TABLE_SIZE; ++i) + { + dbpow[i] = pow(10.0, -(i / DB_TABLE_RES) / 10.0); + } +} + +void OperatorData::loadAttackTable() +{ + for (int i = 0; i < ATTACK_TABLE_SIZE; ++i) + { + attackTable[i] = -pow(2.0, ATTACK_MIN + i * ATTACK_RES); + } +} + void OPL3::Reset() { } @@ -1761,18 +1832,6 @@ void OPL3::WriteReg(int reg, int v) write(reg >> 8, reg & 0xFF, v); } -void OPL3::Update(float *buffer, int length) -{ - double output[4]; - - for (int i = 0; i < length; ++i) - { - read(output); - buffer[i*2 ] += float(output[0] * 0.25f); - buffer[i*2+1] += float(output[1] * 0.25f); - } -} - void OPL3::SetPanning(int c, float left, float right) { } diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index 1746ea02b..404ce1e63 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -294,7 +294,6 @@ enum MUSctrl { ctrlPoly, }; -#define OPL_SAMPLE_RATE 49716.0 #define ADLIB_CLOCK_MUL 24.0 #endif // __MUSLIB_H_ diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h index 12556647f..d406a6b69 100644 --- a/src/oplsynth/opl.h +++ b/src/oplsynth/opl.h @@ -22,4 +22,6 @@ OPLEmul *YM3812Create(bool stereo); OPLEmul *DBOPLCreate(bool stereo); OPLEmul *JavaOPLCreate(bool stereo); +#define OPL_SAMPLE_RATE 49716.0 + #endif \ No newline at end of file diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index fd3480a39..156094e1b 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -1,5 +1,6 @@ #include "i_musicinterns.h" #include "oplsynth/muslib.h" +#include "oplsynth/opl.h" static bool OPL_Active; From 5627a7ebd74dc4d381f08e56ea24b95840ed29f8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 17 Nov 2012 05:26:03 +0000 Subject: [PATCH 050/387] - Added the Java OPL3 emulator to the menu. - Added full panning support to the Java OPL3 emulator. SVN r3969 (trunk) --- src/oplsynth/OPL3.cpp | 99 +++++++++++++++++++++++-------------- src/oplsynth/dosbox/opl.cpp | 4 +- src/oplsynth/fmopl.cpp | 2 - src/oplsynth/opl.h | 2 + wadsrc/static/menudef.txt | 5 +- 5 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/oplsynth/OPL3.cpp b/src/oplsynth/OPL3.cpp index cc4876187..8e506c8d9 100644 --- a/src/oplsynth/OPL3.cpp +++ b/src/oplsynth/OPL3.cpp @@ -53,7 +53,7 @@ static FRandom pr_opl3; -#define VOLUME_MUL 0.25 +#define VOLUME_MUL 0.3333 class Operator; @@ -88,7 +88,7 @@ public: double leftPan, rightPan; - Channel (int baseAddress); + Channel (int baseAddress, double startvol); void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); void update_FNUML8(class OPL3 *OPL3); void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); @@ -107,7 +107,7 @@ class Channel2op : public Channel public: Operator *op1, *op2; - Channel2op (int baseAddress, Operator *o1, Operator *o2); + Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2); double getChannelOutput(class OPL3 *OPL3); void keyOn(); @@ -121,7 +121,7 @@ class Channel4op : public Channel public: Operator *op1, *op2, *op3, *op4; - Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4); + Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4); double getChannelOutput(class OPL3 *OPL3); void keyOn(); @@ -133,7 +133,7 @@ public: class DisabledChannel : public Channel { public: - DisabledChannel() : Channel(0) { } + DisabledChannel() : Channel(0, 0) { } double getChannelOutput(class OPL3 *OPL3) { return 0; } void keyOn() { } void keyOff() { } @@ -244,8 +244,8 @@ protected: class RhythmChannel : public Channel2op { public: - RhythmChannel(int baseAddress, Operator *o1, Operator *o2) - : Channel2op(baseAddress, o1, o2) + RhythmChannel(int baseAddress, double startvol, Operator *o1, Operator *o2) + : Channel2op(baseAddress, startvol, o1, o2) { } double getChannelOutput(class OPL3 *OPL3); @@ -258,16 +258,16 @@ public: class HighHatSnareDrumChannel : public RhythmChannel { static const int highHatSnareDrumChannelBaseAddress = 7; public: - HighHatSnareDrumChannel(Operator *o1, Operator *o2) - : RhythmChannel(highHatSnareDrumChannelBaseAddress, o1, o2) + HighHatSnareDrumChannel(double startvol, Operator *o1, Operator *o2) + : RhythmChannel(highHatSnareDrumChannelBaseAddress, startvol, o1, o2) { } }; class TomTomTopCymbalChannel : public RhythmChannel { static const int tomTomTopCymbalChannelBaseAddress = 8; public: - TomTomTopCymbalChannel(Operator *o1, Operator *o2) - : RhythmChannel(tomTomTopCymbalChannelBaseAddress, o1, o2) + TomTomTopCymbalChannel(double startvol, Operator *o1, Operator *o2) + : RhythmChannel(tomTomTopCymbalChannelBaseAddress, startvol, o1, o2) { } }; @@ -308,7 +308,7 @@ class BassDrumChannel : public Channel2op { Operator my_op1, my_op2; public: - BassDrumChannel(); + BassDrumChannel(double startvol); double getChannelOutput(class OPL3 *OPL3); // Key ON and OFF are unused in rhythm channels. @@ -552,6 +552,8 @@ public: int nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel; int vibratoIndex, tremoloIndex; + + bool FullPan; static OperatorData *OperatorData; static OPL3Data *OPL3Data; @@ -565,7 +567,7 @@ public: //void read(float output[2]); void write(int array, int address, int data); - OPL3(); + OPL3(bool fullpan); ~OPL3(); private: @@ -708,10 +710,12 @@ void OPL3::write(int array, int address, int data) { } } -OPL3::OPL3() -: highHatSnareDrumChannel(&highHatOperator, &snareDrumOperator), - tomTomTopCymbalChannel(&tomTomOperator, &topCymbalOperator) +OPL3::OPL3(bool fullpan) +: bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1), + highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator), + tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator) { + FullPan = fullpan; nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0; vibratoIndex = tremoloIndex = 0; @@ -784,27 +788,28 @@ void OPL3::initChannels2op() { // The YMF262 has 18 2-op channels. // Each 2-op channel can be at a serial or parallel operator configuration: memset(channels2op, 0, sizeof(channels2op)); - + double startvol = FullPan ? CENTER_PANNING_POWER : 1; for(int array=0; array<2; array++) for(int channelNumber=0; channelNumber<3; channelNumber++) { int baseAddress = (array<<8) | channelNumber; // Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5 - channels2op[array][channelNumber] = new Channel2op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3]); + channels2op[array][channelNumber] = new Channel2op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3]); // Channels 4, 5, 6 -> Operator offsets 0x8,0xB; 0x9,0xC; 0xA,0xD - channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); + channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, startvol, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); // Channels 7, 8, 9 -> Operators 0x10,0x13; 0x11,0x14; 0x12,0x15 - channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]); + channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, startvol, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]); } } void OPL3::initChannels4op() { // The YMF262 has 3 4-op channels in each array: memset(channels4op, 0, sizeof(channels4op)); + double startvol = FullPan ? CENTER_PANNING_POWER : 1; for(int array=0; array<2; array++) for(int channelNumber=0; channelNumber<3; channelNumber++) { int baseAddress = (array<<8) | channelNumber; // Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD; - channels4op[array][channelNumber] = new Channel4op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); + channels4op[array][channelNumber] = new Channel4op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); } } @@ -967,11 +972,11 @@ static double EnvelopeFromDB(double db) #endif } -Channel::Channel (int baseAddress) { +Channel::Channel (int baseAddress, double startvol) { channelBaseAddress = baseAddress; fnuml = fnumh = kon = block = fb = cnt = 0; feedback[0] = feedback[1] = 0; - leftPan = rightPan = 1; + leftPan = rightPan = startvol; } void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) { @@ -1013,15 +1018,18 @@ void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) { } void Channel::updatePan(OPL3 *OPL3) { - if (OPL3->_new == 0) + if (!OPL3->FullPan) { - leftPan = VOLUME_MUL; - rightPan = VOLUME_MUL; - } - else - { - leftPan = cha * VOLUME_MUL; - rightPan = chb * VOLUME_MUL; + if (OPL3->_new == 0) + { + leftPan = VOLUME_MUL; + rightPan = VOLUME_MUL; + } + else + { + leftPan = cha * VOLUME_MUL; + rightPan = chb * VOLUME_MUL; + } } } @@ -1031,8 +1039,8 @@ void Channel::updateChannel(OPL3 *OPL3) { update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3); } -Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2) -: Channel(baseAddress) +Channel2op::Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2) +: Channel(baseAddress, startvol) { op1 = o1; op2 = o2; @@ -1086,8 +1094,8 @@ void Channel2op::updateOperators(OPL3 *OPL3) { op2->updateOperator(OPL3, keyScaleNumber, f_number, block); } -Channel4op::Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4) -: Channel(baseAddress) +Channel4op::Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4) +: Channel(baseAddress, startvol) { op1 = o1; op2 = o2; @@ -1665,8 +1673,8 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { return operatorOutput*2; } -BassDrumChannel::BassDrumChannel() -: Channel2op(bassDrumChannelBaseAddress, &my_op1, &my_op2), +BassDrumChannel::BassDrumChannel(double startvol) +: Channel2op(bassDrumChannelBaseAddress, startvol, &my_op1, &my_op2), my_op1(op1BaseAddress), my_op2(op2BaseAddress) { } @@ -1834,9 +1842,24 @@ void OPL3::WriteReg(int reg, int v) void OPL3::SetPanning(int c, float left, float right) { + if (FullPan) + { + Channel *channel; + + if (c < 9) + { + channel = channels[0][c]; + } + else + { + channel = channels[1][c - 9]; + } + channel->leftPan = left; + channel->rightPan = right; + } } OPLEmul *JavaOPLCreate(bool stereo) { - return new OPL3; + return new OPL3(stereo); } diff --git a/src/oplsynth/dosbox/opl.cpp b/src/oplsynth/dosbox/opl.cpp index cfabbc91b..643414413 100644 --- a/src/oplsynth/dosbox/opl.cpp +++ b/src/oplsynth/dosbox/opl.cpp @@ -46,8 +46,6 @@ typedef SBYTE Bit8s; #include "opl.h" -#define CENTER_PANNING_POWER 0.70710678118f - static Bit16s wavtable[WAVEPREC*3]; // wave form table // key scale levels @@ -506,7 +504,7 @@ void DBOPL::Reset() { #if defined(OPLTYPE_IS_OPL3) op[i].is_4op = false; op[i].is_4op_attached = false; - op[i].right_pan = op[i].left_pan = FullPan ? CENTER_PANNING_POWER : 1; + op[i].right_pan = op[i].left_pan = FullPan ? (float)CENTER_PANNING_POWER : 1; #endif } diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 719c63178..4ecd03b14 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -126,8 +126,6 @@ typedef signed int INT32; /* signed 32bit */ #define INLINE __inline #endif -#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ - #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ diff --git a/src/oplsynth/opl.h b/src/oplsynth/opl.h index d406a6b69..eb46c9955 100644 --- a/src/oplsynth/opl.h +++ b/src/oplsynth/opl.h @@ -23,5 +23,7 @@ OPLEmul *DBOPLCreate(bool stereo); OPLEmul *JavaOPLCreate(bool stereo); #define OPL_SAMPLE_RATE 49716.0 +#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ + #endif \ No newline at end of file diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 49bbfd91c..8f22fdfb2 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1402,8 +1402,9 @@ OptionValue GusMemory OptionValue OplCores { - 0, "MAME" - 1, "DOSBox" + 0, "MAME OPL2" + 1, "DOSBox OPL3" + 2, "Java OPL3" } OptionMenu AdvSoundOptions From 7aa4c55bfc4d09f34e01f1efba4d0e8cbe10452b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 19 Nov 2012 00:43:45 +0000 Subject: [PATCH 051/387] - added Gez's patch to fix map checksum calculation. SVN r3970 (trunk) --- src/p_setup.cpp | 2 +- wadsrc/static/compatibility.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index d3c43723f..6a300f4d7 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -302,7 +302,7 @@ MapData *P_OpenMapData(const char * mapname) // This case can only happen if the lump is inside a real WAD file. // As such any special handling for other types of lumps is skipped. - map->MapLumps[0].Reader = Wads.ReopenLumpNum(lump_name); + map->MapLumps[0].Reader = map->file = Wads.ReopenLumpNum(lump_name); map->Encrypted = Wads.IsEncryptedFile(lump_name); if (map->Encrypted) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 6b352c7ef..d87f593f0 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -285,7 +285,7 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 clearlinespecial 1108 } -D41D8CD98F00B204E9800998ECF8427E // Khorus, map08 +5B862477519B21B30059A466F2FF6460 // Khorus, map08 { // This map uses a voodoo conveyor with slanted walls to shunt the // voodoo doll into side areas. For some reason, this voodoo doll From 26c702ada5f2a3d5afae318438db379ac22a2c2b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 19 Nov 2012 02:16:34 +0000 Subject: [PATCH 052/387] - Fixed: Intermission text could run off the bottom of the screen at some resolutions. SVN r3971 (trunk) --- src/intermission/intermission.cpp | 69 +++++++++++++++++++------------ 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 1b4a260be..5d4ca5c06 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -328,15 +328,42 @@ void DIntermissionScreenText::Drawer () size_t count; int c; const FRemapTable *range; - - // draw some of the text onto the screen - int rowheight = SmallFont->GetHeight () + (gameinfo.gametype & (GAME_DoomStrifeChex) ? 3 : -1); - bool scale = (CleanXfac != 1 || CleanYfac != 1); - - int cx = mTextX; - int cy = mTextY; const char *ch = mText; + // Count number of rows in this text. Since it does not word-wrap, we just count + // line feed characters. + int numrows; + + for (numrows = 1, c = 0; ch[c] != '\0'; ++c) + { + numrows += (ch[c] == '\n'); + } + + int rowheight = SmallFont->GetHeight() * CleanYfac; + int rowpadding = (gameinfo.gametype & (GAME_DoomStrifeChex) ? 3 : -1) * CleanYfac; + + int cx = (mTextX - 160)*CleanXfac + screen->GetWidth() / 2; + int cy = (mTextY - 100)*CleanYfac + screen->GetHeight() / 2; + int startx = cx; + + // Does this text fall off the end of the screen? If so, try to eliminate some margins first. + while (rowpadding > 0 && cy + numrows * (rowheight + rowpadding) - rowpadding > screen->GetHeight()) + { + rowpadding--; + } + // If it's still off the bottom, try to center it vertically. + if (cy + numrows * (rowheight + rowpadding) - rowpadding > screen->GetHeight()) + { + cy = (screen->GetHeight() - (numrows * (rowheight + rowpadding) - rowpadding)) / 2; + // If it's off the top now, you're screwed. It's too tall to fit. + if (cy < 0) + { + cy = 0; + } + } + rowheight += rowpadding; + + // draw some of the text onto the screen count = (mTicker - mTextDelay) / mTextSpeed; range = SmallFont->GetColorTranslation (mTextColor); @@ -347,33 +374,23 @@ void DIntermissionScreenText::Drawer () break; if (c == '\n') { - cx = mTextX; + cx = startx; cy += rowheight; continue; } pic = SmallFont->GetChar (c, &w); - if (cx+w > SCREENWIDTH) + w *= CleanXfac; + if (cx + w > SCREENWIDTH) continue; if (pic != NULL) { - if (scale) - { - screen->DrawTexture (pic, - cx,// + 320 / 2, - cy,// + 200 / 2, - DTA_Translation, range, - DTA_Clean, true, - TAG_DONE); - } - else - { - screen->DrawTexture (pic, - cx,// + 320 / 2, - cy,// + 200 / 2, - DTA_Translation, range, - TAG_DONE); - } + screen->DrawTexture (pic, + cx, + cy, + DTA_Translation, range, + DTA_CleanNoMove, true, + TAG_DONE); } cx += w; } From c5ffb499eeb7ec1d60522364a6b05a3dddbdc62c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 20 Nov 2012 02:16:08 +0000 Subject: [PATCH 053/387] - Massage the Java-basd OPL3 emulator so that it can compile with GCC. SVN r3972 (trunk) --- src/oplsynth/OPL3.cpp | 98 ++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/oplsynth/OPL3.cpp b/src/oplsynth/OPL3.cpp index 8e506c8d9..80caffcdf 100644 --- a/src/oplsynth/OPL3.cpp +++ b/src/oplsynth/OPL3.cpp @@ -150,7 +150,6 @@ public: class EnvelopeGenerator { public: - //static const double *INFINITY = NULL; enum Stage {ATTACK,DECAY,SUSTAIN,RELEASE,OFF}; Stage stage; int actualAttackRate, actualDecayRate, actualReleaseRate; @@ -322,7 +321,7 @@ public: // -struct OPL3Data +struct OPL3DataStruct { public: // OPL3-wide registers offsets: @@ -338,7 +337,7 @@ public: static const int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); static const int vibratoTableLength = 8192; - OPL3Data::OPL3Data() + OPL3DataStruct() { loadVibratoTable(); loadTremoloTable(); @@ -384,7 +383,7 @@ const float ChannelData::feedback[8] = {0,1/32.f,1/16.f,1/8.f,1/4.f,1/2.f,1,2}; // -struct OperatorData +struct OperatorDataStruct { static const int AM1_VIB1_EGT1_KSR1_MULT4_Offset = 0x20, @@ -416,7 +415,7 @@ struct OperatorData double attackTable[ATTACK_TABLE_SIZE]; - OperatorData() + OperatorDataStruct() { loadWaveforms(); loaddBPowTable(); @@ -431,9 +430,9 @@ private: void loaddBPowTable(); void loadAttackTable(); }; -const float OperatorData::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; +const float OperatorDataStruct::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; -const float OperatorData::ksl3dBtable[16][8] = { +const float OperatorDataStruct::ksl3dBtable[16][8] = { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,-3,-6,-9}, {0,0,0,0,-3,-6,-9,-12}, @@ -462,7 +461,7 @@ const float OperatorData::ksl3dBtable[16][8] = { namespace EnvelopeGeneratorData { - static const double INFINITY = std::numeric_limits::infinity(); + static const double MUGEN = std::numeric_limits::infinity(); // This table is indexed by the value of Operator.ksr // and the value of ChannelRegister.keyScaleNumber. static const int rateOffset[2][16] = { @@ -473,7 +472,7 @@ namespace EnvelopeGeneratorData // The attack actual rates range from 0 to 63, with different data for // 0%-100% and for 10%-90%: static const double attackTimeValuesTable[64][2] = { - {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, + {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {2826.24,1482.75}, {2252.80,1155.07}, {1884.16,991.23}, {1597.44,868.35}, {1413.12,741.38}, {1126.40,577.54}, {942.08,495.62}, {798.72,434.18}, {706.56,370.69}, {563.20,288.77}, {471.04,247.81}, {399.36,217.09}, @@ -498,7 +497,7 @@ namespace EnvelopeGeneratorData // The rate index range from 0 to 63, with different data for // 0%-100% and for 10%-90%: static const double decayAndReleaseTimeValuesTable[64][2] = { - {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, {INFINITY,INFINITY}, + {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {39280.64,8212.48}, {31416.32,6574.08}, {26173.44,5509.12}, {22446.08,4730.88}, {19640.32,4106.24}, {15708.16,3287.04}, {13086.72,2754.56}, {11223.04,2365.44}, {9820.16,2053.12}, {7854.08,1643.52}, {6543.36,1377.28}, {5611.52,1182.72}, @@ -555,8 +554,8 @@ public: bool FullPan; - static OperatorData *OperatorData; - static OPL3Data *OPL3Data; + static OperatorDataStruct *OperatorData; + static OPL3DataStruct *OPL3Data; // The methods read() and write() are the only // ones needed by the user to interface with the emulator. @@ -595,8 +594,8 @@ public: void SetPanning(int c, float left, float right); }; -OperatorData *OPL3::OperatorData; -OPL3Data *OPL3::OPL3Data; +OperatorDataStruct *OPL3::OperatorData; +OPL3DataStruct *OPL3::OPL3Data; int OPL3::InstanceCount; void OPL3::Update(float *output, int numsamples) { @@ -616,11 +615,11 @@ void OPL3::Update(float *output, int numsamples) { // Advances the OPL3-wide vibrato index, which is used by // PhaseGenerator.getPhase() in each Operator. - vibratoIndex = (vibratoIndex + 1) & (OPL3Data::vibratoTableLength - 1); + vibratoIndex = (vibratoIndex + 1) & (OPL3DataStruct::vibratoTableLength - 1); // Advances the OPL3-wide tremolo index, which is used by // EnvelopeGenerator.getEnvelope() in each Operator. tremoloIndex++; - if(tremoloIndex >= OPL3Data::tremoloTableLength) tremoloIndex = 0; + if(tremoloIndex >= OPL3DataStruct::tremoloTableLength) tremoloIndex = 0; output += 2; } } @@ -711,9 +710,9 @@ void OPL3::write(int array, int address, int data) { } OPL3::OPL3(bool fullpan) -: bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1), - highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator), - tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator) +: tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator), + bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1), + highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator) { FullPan = fullpan; nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0; @@ -721,8 +720,8 @@ OPL3::OPL3(bool fullpan) if (InstanceCount++ == 0) { - OPL3Data = new struct OPL3Data; - OperatorData = new struct OperatorData; + OPL3Data = new struct OPL3DataStruct; + OperatorData = new struct OperatorDataStruct; } initOperators(); @@ -763,6 +762,7 @@ OPL3::~OPL3() } } + void OPL3::initOperators() { int baseAddress; // The YMF262 has 36 operators: @@ -825,7 +825,7 @@ void OPL3::initChannels() { } void OPL3::update_1_NTS1_6() { - int _1_nts1_6 = registers[OPL3Data::_1_NTS1_6_Offset]; + int _1_nts1_6 = registers[OPL3DataStruct::_1_NTS1_6_Offset]; // Note Selection. This register is used in Channel.updateOperators() implementations, // to calculate the channel´s Key Scale Number. // The value of the actual envelope rate follows the value of @@ -834,7 +834,7 @@ void OPL3::update_1_NTS1_6() { } void OPL3::update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1() { - int dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 = registers[OPL3Data::DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset]; + int dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 = registers[OPL3DataStruct::DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset]; // Depth of amplitude. This register is used in EnvelopeGenerator.getEnvelope(); dam = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x80) >> 7; @@ -883,7 +883,7 @@ void OPL3::update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1() { } void OPL3::update_7_NEW1() { - int _7_new1 = registers[OPL3Data::_7_NEW1_Offset]; + int _7_new1 = registers[OPL3DataStruct::_7_NEW1_Offset]; // OPL2/OPL3 mode selection. This register is used in // OPL3.read(), OPL3.write() and Operator.getOperatorOutput(); _new = (_7_new1 & 0x01); @@ -913,7 +913,7 @@ void OPL3::updateChannelPans() { void OPL3::update_2_CONNECTIONSEL6() { // This method is called only if _new is set. - int _2_connectionsel6 = registers[OPL3Data::_2_CONNECTIONSEL6_Offset]; + int _2_connectionsel6 = registers[OPL3DataStruct::_2_CONNECTIONSEL6_Offset]; // 2-op/4-op channel selection. This register is used here to configure the OPL3.channels[] array. connectionsel = (_2_connectionsel6 & 0x3F); set4opConnections(); @@ -1209,7 +1209,7 @@ Operator::Operator(int baseAddress) { void Operator::update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3 *OPL3) { - int am1_vib1_egt1_ksr1_mult4 = OPL3->registers[operatorBaseAddress+OperatorData::AM1_VIB1_EGT1_KSR1_MULT4_Offset]; + int am1_vib1_egt1_ksr1_mult4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AM1_VIB1_EGT1_KSR1_MULT4_Offset]; // Amplitude Modulation. This register is used int EnvelopeGenerator.getEnvelope(); am = (am1_vib1_egt1_ksr1_mult4 & 0x80) >> 7; @@ -1232,7 +1232,7 @@ void Operator::update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3 *OPL3) { void Operator::update_KSL2_TL6(OPL3 *OPL3) { - int ksl2_tl6 = OPL3->registers[operatorBaseAddress+OperatorData::KSL2_TL6_Offset]; + int ksl2_tl6 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::KSL2_TL6_Offset]; // Key Scale Level. Sets the attenuation in accordance with the octave. ksl = (ksl2_tl6 & 0xC0) >> 6; @@ -1245,7 +1245,7 @@ void Operator::update_KSL2_TL6(OPL3 *OPL3) { void Operator::update_AR4_DR4(OPL3 *OPL3) { - int ar4_dr4 = OPL3->registers[operatorBaseAddress+OperatorData::AR4_DR4_Offset]; + int ar4_dr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AR4_DR4_Offset]; // Attack Rate. ar = (ar4_dr4 & 0xF0) >> 4; @@ -1258,7 +1258,7 @@ void Operator::update_AR4_DR4(OPL3 *OPL3) { void Operator::update_SL4_RR4(OPL3 *OPL3) { - int sl4_rr4 = OPL3->registers[operatorBaseAddress+OperatorData::SL4_RR4_Offset]; + int sl4_rr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::SL4_RR4_Offset]; // Sustain Level. sl = (sl4_rr4 & 0xF0) >> 4; @@ -1270,7 +1270,7 @@ void Operator::update_SL4_RR4(OPL3 *OPL3) { } void Operator::update_5_WS3(OPL3 *OPL3) { - int _5_ws3 = OPL3->registers[operatorBaseAddress+OperatorData::_5_WS3_Offset]; + int _5_ws3 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::_5_WS3_Offset]; ws = _5_ws3 & 0x07; } @@ -1291,7 +1291,7 @@ double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { } double Operator::getOutput(double modulator, double outputPhase, double *waveform) { - int sampleIndex = xs_FloorToInt((outputPhase + modulator) * OperatorData::waveLength) & (OperatorData::waveLength - 1); + int sampleIndex = xs_FloorToInt((outputPhase + modulator) * OperatorDataStruct::waveLength) & (OperatorDataStruct::waveLength - 1); return waveform[sampleIndex] * envelope; } @@ -1356,15 +1356,15 @@ void EnvelopeGenerator::setAtennuation(int f_number, int block, int ksl) { break; case 1: // ~3 dB/Octave - attenuation = OperatorData::ksl3dBtable[hi4bits][block]; + attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]; break; case 2: // ~1.5 dB/Octave - attenuation = OperatorData::ksl3dBtable[hi4bits][block]/2; + attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]/2; break; case 3: // ~6 dB/Octave - attenuation = OperatorData::ksl3dBtable[hi4bits][block]*2; + attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]*2; } } @@ -1382,7 +1382,7 @@ void EnvelopeGenerator::setActualAttackRate(int attackRate, int ksr, int keyScal double period10to90inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][1]/1000.0; int period10to90inSamples = (int)(period10to90inSeconds*OPL_SAMPLE_RATE); // The x increment is dictated by the period between 10% and 90%: - xAttackIncrement = OPL3Data::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); + xAttackIncrement = OPL3DataStruct::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); // Discover how many samples are still from the top. // It cannot reach 0 dB, since x is a logarithmic parameter and would be // negative infinity. So we will use -0.1875 dB as the resolution @@ -1403,13 +1403,13 @@ void EnvelopeGenerator::setActualDecayRate(int decayRate, int ksr, int keyScaleN double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualDecayRate][1]/1000.0; // Differently from the attack curve, the decay/release curve is linear. // The dB increment is dictated by the period between 10% and 90%: - dBdecayIncrement = OPL3Data::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); + dBdecayIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); } void EnvelopeGenerator::setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber) { actualReleaseRate = calculateActualRate(releaseRate, ksr, keyScaleNumber); double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualReleaseRate][1]/1000.0; - dBreleaseIncrement = OPL3Data::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); + dBreleaseIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); } int EnvelopeGenerator::calculateActualRate(int rate, int ksr, int keyScaleNumber) { @@ -1442,7 +1442,7 @@ double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { case ATTACK: // Since the attack is exponential, it will never reach 0 dB, so // we´ll work with the next to maximum in the envelope resolution. - if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::INFINITY) { + if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::MUGEN) { // The attack is exponential. #if 0 envelope = -pow(2.0,x); @@ -1493,6 +1493,8 @@ double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { if(envelope > envelopeMinimum) envelope -= dBreleaseIncrement; else stage = OFF; + case OFF: + break; } // Ongoing original envelope @@ -1516,7 +1518,7 @@ void EnvelopeGenerator::keyOn() { // envelope = - (2 ^ x); -> // 2 ^ x = -envelope -> // x = log2(-envelope); -> - double xCurrent = OperatorData::log2(-envelope); + double xCurrent = OperatorDataStruct::log2(-envelope); x = xCurrent < xMinimumInAttack ? xCurrent : xMinimumInAttack; stage = ATTACK; } @@ -1526,7 +1528,7 @@ void EnvelopeGenerator::keyOff() { } double EnvelopeGenerator::dBtoX(double dB) { - return OperatorData::log2(-dB); + return OperatorDataStruct::log2(-dB); } double EnvelopeGenerator::percentageToDB(double percentage) { @@ -1546,7 +1548,7 @@ void PhaseGenerator::setFrequency(int f_number, int block, int mult) { // f_number = baseFrequency * pow(2,19) / OPL_SAMPLE_RATE / pow(2,block-1); double baseFrequency = f_number * pow(2.0, block-1) * OPL_SAMPLE_RATE / pow(2.0,19); - double operatorFrequency = baseFrequency*OperatorData::multTable[mult]; + double operatorFrequency = baseFrequency*OperatorDataStruct::multTable[mult]; // phase goes from 0 to 1 at // period = (1/frequency) seconds -> @@ -1597,7 +1599,7 @@ TopCymbalOperator::TopCymbalOperator() double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { double highHatOperatorPhase = - OPL3->highHatOperator.phase * OperatorData::multTable[OPL3->highHatOperator.mult]; + OPL3->highHatOperator.phase * OperatorDataStruct::multTable[OPL3->highHatOperator.mult]; // The Top Cymbal operator uses its own phase together with the High Hat phase. return getOperatorOutput(OPL3, modulator, highHatOperatorPhase); } @@ -1635,7 +1637,7 @@ HighHatOperator::HighHatOperator() double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { double topCymbalOperatorPhase = - OPL3->topCymbalOperator.phase * OperatorData::multTable[OPL3->topCymbalOperator.mult]; + OPL3->topCymbalOperator.phase * OperatorDataStruct::multTable[OPL3->topCymbalOperator.mult]; // The sound output from the High Hat resembles the one from // Top Cymbal, so we use the parent method and modify its output // accordingly afterwards. @@ -1684,7 +1686,7 @@ double BassDrumChannel::getChannelOutput(OPL3 *OPL3) { return Channel2op::getChannelOutput(OPL3); } -void OPL3Data::loadVibratoTable() { +void OPL3DataStruct::loadVibratoTable() { // According to the YMF262 datasheet, the OPL3 vibrato repetition rate is 6.1 Hz. // According to the YMF278B manual, it is 6.0 Hz. @@ -1732,7 +1734,7 @@ void OPL3Data::loadVibratoTable() { } -void OPL3Data::loadTremoloTable() +void OPL3DataStruct::loadTremoloTable() { // The tremolo depth is -1 dB when DAM = 0, and -4.8 dB when DAM = 1. static const double tremoloDepth[] = {-1, -4.8}; @@ -1769,7 +1771,7 @@ void OPL3Data::loadTremoloTable() } } -void OperatorData::loadWaveforms() { +void OperatorDataStruct::loadWaveforms() { int i; // 1st waveform: sinusoid. double theta = 0, thetaIncrement = 2*M_PI / 1024; @@ -1815,7 +1817,7 @@ void OperatorData::loadWaveforms() { } } -void OperatorData::loaddBPowTable() +void OperatorDataStruct::loaddBPowTable() { for (int i = 0; i < DB_TABLE_SIZE; ++i) { @@ -1823,7 +1825,7 @@ void OperatorData::loaddBPowTable() } } -void OperatorData::loadAttackTable() +void OperatorDataStruct::loadAttackTable() { for (int i = 0; i < ATTACK_TABLE_SIZE; ++i) { From c845675b9b0ba0334fe172fb5a314e341afb64b7 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 30 Nov 2012 23:36:02 +0000 Subject: [PATCH 054/387] - Fixed: When using PALVERS on the sky, it used the scaling from the true color version. (Side Note: I changed a line that scales the sky position according to the y scaling factor. This is because a 2x high resolution sky at 2048x256 wasn't positioned the same as a 1024x128 unscaled version. I moved the expression to the > 200 height path only, but I'm not sure if it's even still needed.) - Fixed: PALVERS crashed with unknown textures since a value was never given for %s. - Fixed: FON2 loader didn't set ActiveColors correctly. SVN r3973 (trunk) --- src/r_sky.cpp | 7 +++---- src/textures/texturemanager.cpp | 11 ++++++++--- src/v_font.cpp | 6 +++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/r_sky.cpp b/src/r_sky.cpp index d93ee59f2..993456a66 100644 --- a/src/r_sky.cpp +++ b/src/r_sky.cpp @@ -69,8 +69,8 @@ void R_InitSkyMap () int skyheight; FTexture *skytex1, *skytex2; - skytex1 = TexMan[sky1texture]; - skytex2 = TexMan[sky2texture]; + skytex1 = TexMan(sky1texture, true); + skytex2 = TexMan(sky2texture, true); if (skytex1 == NULL) return; @@ -107,9 +107,8 @@ void R_InitSkyMap () } else if (skyheight > 200) { - skytexturemid = (200 - skyheight) << FRACBITS; + skytexturemid = FixedMul((200 - skyheight) << FRACBITS, skytex1->yScale); } - skytexturemid = FixedMul(skytexturemid, skytex1->yScale); if (viewwidth != 0 && viewheight != 0) { diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 1abbab29f..6fdac54c2 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -51,11 +51,16 @@ #include "farchive.h" #include "v_video.h" #include "r_renderer.h" +#include "r_sky.h" #include "textures/textures.h" FTextureManager TexMan; -CVAR(Bool, vid_nopalsubstitutions, false, CVAR_ARCHIVE) +CUSTOM_CVAR(Bool, vid_nopalsubstitutions, false, CVAR_ARCHIVE) +{ + // This is in case the sky texture has been substituted. + R_InitSkyMap (); +} //========================================================================== // @@ -1026,13 +1031,13 @@ void FTextureManager::InitPalettedVersions() FTextureID pic1 = CheckForTexture(sc.String, FTexture::TEX_Any); if (!pic1.isValid()) { - sc.ScriptMessage("Unknown texture %s to replace"); + sc.ScriptMessage("Unknown texture %s to replace", sc.String); } sc.MustGetString(); FTextureID pic2 = CheckForTexture(sc.String, FTexture::TEX_Any); if (!pic2.isValid()) { - sc.ScriptMessage("Unknown texture %s to use as replacement"); + sc.ScriptMessage("Unknown texture %s to use as replacement", sc.String); } if (pic1.isValid() && pic2.isValid()) { diff --git a/src/v_font.cpp b/src/v_font.cpp index c1923e4ac..6bb130716 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -1073,7 +1073,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) FontHeight = data[4] + data[5]*256; FirstChar = data[6]; LastChar = data[7]; - ActiveColors = data[10]; + ActiveColors = data[10]+1; PatchRemap = NULL; RescalePalette = data[9] == 0; @@ -1125,9 +1125,9 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) SpaceWidth = totalwidth * 2 / (3 * count); } - memcpy(PaletteData, palette, (ActiveColors+1)*3); + memcpy(PaletteData, palette, ActiveColors*3); - data_p = palette + (ActiveColors+1)*3; + data_p = palette + ActiveColors*3; for (i = 0; i < count; ++i) { From a57c22981e051850f31841b2dc68b79c7ca1ea89 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Dec 2012 02:42:53 +0000 Subject: [PATCH 055/387] - Fix positioning of upside-down textures. Note that wallscan_np2() still needs to be modified to understand negative yrepeats. SVN r3974 (trunk) --- src/r_segs.cpp | 97 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 8c22b3e53..e93ee4437 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1951,16 +1951,31 @@ void R_NewWall (bool needlights) rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid); rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid); yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley); - if (linedef->flags & ML_DONTPEGBOTTOM) - { // bottom of texture at bottom - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); + if (yrepeat >= 0) + { // normal orientation + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); + } + else + { // top of texture at top + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); + if (rowoffset < 0 && midtexture != NULL) + { + rowoffset += midtexture->GetHeight() << FRACBITS; + } + } } else - { // top of texture at top - rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); - if (rowoffset < 0 && midtexture != NULL) - { - rowoffset += midtexture->GetHeight() << FRACBITS; + { // upside down + rowoffset = -rowoffset; + if (linedef->flags & ML_DONTPEGBOTTOM) + { // top of texture at bottom + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat); + } + else + { // bottom of texture at top + rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS); } } if (midtexture->bWorldPanning) @@ -2096,17 +2111,32 @@ void R_NewWall (bool needlights) rw_toptexturescalex = sidedef->GetTextureXScale(side_t::top); rw_toptexturescaley = sidedef->GetTextureYScale(side_t::top); yrepeat = FixedMul(toptexture->yScale, rw_toptexturescaley); - if (linedef->flags & ML_DONTPEGTOP) - { // top of texture at top - rw_toptexturemid = MulScale16 (frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); - if (rowoffset < 0 && toptexture != NULL) - { - rowoffset += toptexture->GetHeight() << FRACBITS; + if (yrepeat >= 0) + { // normal orientation + if (linedef->flags & ML_DONTPEGTOP) + { // top of texture at top + rw_toptexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); + if (rowoffset < 0 && toptexture != NULL) + { + rowoffset += toptexture->GetHeight() << FRACBITS; + } + } + else + { // bottom of texture at bottom + rw_toptexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (toptexture->GetHeight() << FRACBITS); } } else - { // bottom of texture at bottom - rw_toptexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (toptexture->GetHeight() << FRACBITS); + { // upside down + rowoffset = -rowoffset; + if (linedef->flags & ML_DONTPEGTOP) + { // bottom of texture at top + rw_toptexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (toptexture->GetHeight() << FRACBITS); + } + else + { // top of texture at bottom + rw_toptexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat); + } } if (toptexture->bWorldPanning) { @@ -2126,25 +2156,40 @@ void R_NewWall (bool needlights) rw_bottomtexturescalex = sidedef->GetTextureXScale(side_t::bottom); rw_bottomtexturescaley = sidedef->GetTextureYScale(side_t::bottom); yrepeat = FixedMul(bottomtexture->yScale, rw_bottomtexturescaley); - if (linedef->flags & ML_DONTPEGBOTTOM) - { // bottom of texture at bottom - rw_bottomtexturemid = rw_frontlowertop; + if (yrepeat >= 0) + { // normal orientation + if (linedef->flags & ML_DONTPEGBOTTOM) + { // bottom of texture at bottom + rw_bottomtexturemid = MulScale16(rw_frontlowertop - viewz, yrepeat); + } + else + { // top of texture at top + rw_bottomtexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat); + if (rowoffset < 0 && bottomtexture != NULL) + { + rowoffset += bottomtexture->GetHeight() << FRACBITS; + } + } } else - { // top of texture at top - rw_bottomtexturemid = backsector->GetPlaneTexZ(sector_t::floor); - if (rowoffset < 0 && bottomtexture != NULL) - { - rowoffset += bottomtexture->GetHeight() << FRACBITS; + { // upside down + rowoffset = -rowoffset; + if (linedef->flags & ML_DONTPEGBOTTOM) + { // top of texture at bottom + rw_bottomtexturemid = MulScale16(rw_frontlowertop - viewz, yrepeat); + } + else + { // bottom of texture at top + rw_bottomtexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (bottomtexture->GetHeight() << FRACBITS); } } if (bottomtexture->bWorldPanning) { - rw_bottomtexturemid = MulScale16(rw_bottomtexturemid - viewz + rowoffset, yrepeat); + rw_bottomtexturemid += MulScale16(rowoffset, yrepeat); } else { - rw_bottomtexturemid = MulScale16(rw_bottomtexturemid - viewz, yrepeat) + rowoffset; + rw_bottomtexturemid += rowoffset; } } } From ea5d2346bf8c65c42425f05e429f7f108df918c2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Dec 2012 03:14:02 +0000 Subject: [PATCH 056/387] - Added a negative yrepeat case to wallscan_np2() for upside-down non-power-of-2 textures. SVN r3975 (trunk) --- src/r_segs.cpp | 74 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index e93ee4437..07cd48691 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1295,37 +1295,67 @@ static void call_wallscan(int x1, int x2, short *uwal, short *dwal, fixed_t *swa void wallscan_np2(int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat, fixed_t top, fixed_t bot, bool mask) { - short *up = uwal; - - if (r_np2) + if (!r_np2) + { + call_wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, mask); + } + else { short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH]; - short *down; + short *up, *down; fixed_t texheight = rw_pic->GetHeight() << FRACBITS; fixed_t scaledtexheight = FixedDiv(texheight, yrepeat); - fixed_t partition = top - (top - FixedDiv(dc_texturemid, yrepeat) - viewz) % scaledtexheight; + fixed_t partition; - down = most1; - - dc_texturemid = FixedMul(partition - viewz, yrepeat) + texheight; - while (partition > bot) - { - int j = OWallMost(most3, partition - viewz); - if (j != 3) + if (yrepeat >= 0) + { // normal orientation: draw strips from top to bottom + partition = top - (top - FixedDiv(dc_texturemid, yrepeat) - viewz) % scaledtexheight; + up = uwal; + down = most1; + dc_texturemid = FixedMul(partition - viewz, yrepeat) + texheight; + while (partition > bot) { - for (int j = x1; j <= x2; ++j) + int j = OWallMost(most3, partition - viewz); + if (j != 3) { - down[j] = clamp (most3[j], up[j], dwal[j]); + for (int j = x1; j <= x2; ++j) + { + down[j] = clamp(most3[j], up[j], dwal[j]); + } + call_wallscan(x1, x2, up, down, swal, lwal, yrepeat, mask); + up = down; + down = (down == most1) ? most2 : most1; } - call_wallscan(x1, x2, up, down, swal, lwal, yrepeat, mask); - up = down; - down = (down == most1) ? most2 : most1; - } - partition -= scaledtexheight; - dc_texturemid -= texheight; - } + partition -= scaledtexheight; + dc_texturemid -= texheight; + } + call_wallscan(x1, x2, up, dwal, swal, lwal, yrepeat, mask); + } + else + { // upside down: draw strips from bottom to top + partition = bot - (bot - FixedDiv(dc_texturemid, yrepeat) - viewz) % scaledtexheight; + up = most1; + down = dwal; + dc_texturemid = FixedMul(partition - viewz, yrepeat) + texheight; + while (partition < top) + { + int j = OWallMost(most3, partition - viewz); + if (j != 12) + { + for (int j = x1; j <= x2; ++j) + { + up[j] = clamp(most3[j], uwal[j], down[j]); + } + call_wallscan(x1, x2, up, down, swal, lwal, yrepeat, mask); + down = up; + up = (up == most1) ? most2 : most1; + } + partition -= scaledtexheight; + dc_texturemid -= texheight; + } + call_wallscan(x1, x2, uwal, down, swal, lwal, yrepeat, mask); + } } - call_wallscan(x1, x2, up, dwal, swal, lwal, yrepeat, mask); } static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat) From 3a3e9c70638cba077d337acf48e0995baa4fc2a9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Dec 2012 03:24:25 +0000 Subject: [PATCH 057/387] - Fixed: Flipping textures horizontally also flipped the scrolling direction. SVN r3976 (trunk) --- src/r_segs.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 07cd48691..62c3e678a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1850,6 +1850,10 @@ void R_RenderSegLoop () { rw_offset = rw_offset_mid; } + if (xscale < 0) + { + rw_offset = -rw_offset; + } if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) { wallscan_np2(x1, x2-1, walltop, wallbottom, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_frontfz1, rw_frontfz2), false); @@ -1889,6 +1893,10 @@ void R_RenderSegLoop () { rw_offset = rw_offset_top; } + if (xscale < 0) + { + rw_offset = -rw_offset; + } if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) { wallscan_np2(x1, x2-1, walltop, wallupper, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_backcz1, rw_backcz2), false); @@ -1931,6 +1939,10 @@ void R_RenderSegLoop () { rw_offset = rw_offset_bottom; } + if (xscale < 0) + { + rw_offset = -rw_offset; + } if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) { wallscan_np2(x1, x2-1, walllower, wallbottom, swall, lwall, yscale, MAX(rw_backfz1, rw_backfz2), MIN(rw_frontfz1, rw_frontfz2), false); From 736c7f093a3f6b6e7c05cf9aadec003e1e6e4d1c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Dec 2012 03:37:52 +0000 Subject: [PATCH 058/387] - Fixed: The textured automap used the main sector's floor's rotation and scaling when drawing 3D floors. SVN r3977 (trunk) --- src/am_map.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index bb0215242..a091cfc29 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1611,10 +1611,10 @@ void AM_drawSubsectors() angle_t rotation; sector_t tempsec; int floorlight, ceilinglight; + fixed_t scalex, scaley; double originx, originy; FDynamicColormap *colormap; - for (int i = 0; i < numsubsectors; ++i) { if (subsectors[i].flags & SSECF_POLYORG) @@ -1645,17 +1645,6 @@ void AM_drawSubsectors() 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 @@ -1663,6 +1652,9 @@ void AM_drawSubsectors() FTextureID maptex = sec->GetTexture(sector_t::floor); + scalex = sec->GetXScale(sector_t::floor); + scaley = sec->GetYScale(sector_t::floor); + #ifdef _3DFLOORS if (sec->e->XFloor.ffloors.Size()) @@ -1709,6 +1701,9 @@ void AM_drawSubsectors() { maptex = *(rover->top.texture); floorplane = rover->top.plane; + rotation = 0 - rover->top.model->GetAngle(sector_t::ceiling); + scalex = rover->top.model->GetXScale(sector_t::ceiling); + scaley = rover->top.model->GetYScale(sector_t::ceiling); break; } } @@ -1718,6 +1713,17 @@ void AM_drawSubsectors() colormap = light->extra_colormap; } #endif + // 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); + } // If this subsector has not actually been seen yet (because you are cheating // to see it on the map), tint and desaturate it. @@ -1740,8 +1746,8 @@ void AM_drawSubsectors() screen->FillSimplePoly(TexMan(maptex), &points[0], points.Size(), originx, originy, - scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)), - scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)), + scale / (FIXED2DBL(scalex) * float(1 << MAPBITS)), + scale / (FIXED2DBL(scaley) * float(1 << MAPBITS)), rotation, colormap, floorlight From b1543fdc0853640b8471f688c72f16f708ba57b2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Dec 2012 03:47:10 +0000 Subject: [PATCH 059/387] - Skip 3D floors in the textured automap that are not set to draw their planes. - Fixed: The textured automap also needs to take the texture origin for 3D floors from the control sector. SVN r3978 (trunk) --- src/am_map.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index a091cfc29..126ab733a 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1614,6 +1614,7 @@ void AM_drawSubsectors() fixed_t scalex, scaley; double originx, originy; FDynamicColormap *colormap; + mpoint_t originpt; for (int i = 0; i < numsubsectors; ++i) { @@ -1642,11 +1643,9 @@ void AM_drawSubsectors() // For lighting and texture determination sector_t *sec = Renderer->FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight, &ceilinglight, false); // Find texture origin. - mpoint_t originpt = { -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS, - sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS }; + originpt.x = -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS; + originpt.y = sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS; rotation = 0 - sec->GetAngle(sector_t::floor); - 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; @@ -1690,6 +1689,7 @@ void AM_drawSubsectors() F3DFloor *rover = sec->e->XFloor.ffloors[i]; if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & FF_FOG) continue; + if (!(rover->flags & FF_RENDERPLANES)) continue; if (rover->alpha == 0) continue; double roverz = rover->top.plane->ZatPoint(secx, secy); // Ignore 3D floors that are above or below the sector itself: @@ -1701,9 +1701,13 @@ void AM_drawSubsectors() { maptex = *(rover->top.texture); floorplane = rover->top.plane; - rotation = 0 - rover->top.model->GetAngle(sector_t::ceiling); - scalex = rover->top.model->GetXScale(sector_t::ceiling); - scaley = rover->top.model->GetYScale(sector_t::ceiling); + sector_t *model = rover->top.model; + int selector = (rover->flags & FF_INVERTPLANES) ? sector_t::floor : sector_t::ceiling; + rotation = 0 - model->GetAngle(selector); + scalex = model->GetXScale(selector); + scaley = model->GetYScale(selector); + originpt.x = -model->GetXOffset(selector) >> FRACTOMAPBITS; + originpt.y = model->GetYOffset(selector) >> FRACTOMAPBITS; break; } } @@ -1713,6 +1717,8 @@ void AM_drawSubsectors() colormap = light->extra_colormap; } #endif + originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24)); + originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24)); // Apply the floor's rotation to the texture origin. if (rotation != 0) { From d77297e969f138ed1249589b15f1833bce2bdc77 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 7 Dec 2012 06:16:07 +0000 Subject: [PATCH 060/387] - Added support for loading ZGL3/XGL3 nodes. - Added additional debug spew for the nodebuilder. - Restore the nodebuilder's debug spew that was present in ZDBSP but not the internal version. Use the CRT's printf for this output to ensure that it is identical to ZDBSP's output for the same input. SVN r3980 (trunk) --- src/nodebuild.cpp | 11 ++++++++--- src/nodebuild.h | 4 ++++ src/nodebuild_events.cpp | 14 ++++++++++++++ src/nodebuild_extract.cpp | 17 ++++++++++++----- src/nodebuild_gl.cpp | 14 ++++++++++++++ src/nodebuild_utility.cpp | 3 +++ src/p_glnodes.cpp | 13 ++++++++----- src/p_setup.cpp | 39 +++++++++++++++++++++++++++++---------- 8 files changed, 92 insertions(+), 23 deletions(-) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 5ac860bef..a4b568683 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -243,12 +243,16 @@ void FNodeBuilder::CreateSubsectorsForReal () D(Printf (PRINT_LOG, "Output subsector %d:\n", Subsectors.Size())); 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], + D(Printf (PRINT_LOG, " Seg %5d%c%d(%5d,%5d)-%d(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", SegList[i].SegPtr - &Segs[0], SegList[i].SegPtr->linedef == -1 ? '+' : ' ', + SegList[i].SegPtr->v1, Vertices[SegList[i].SegPtr->v1].x>>16, Vertices[SegList[i].SegPtr->v1].y>>16, + SegList[i].SegPtr->v2, Vertices[SegList[i].SegPtr->v2].x>>16, - Vertices[SegList[i].SegPtr->v2].y>>16)); + Vertices[SegList[i].SegPtr->v2].y>>16, + Vertices[SegList[i].SegPtr->v1].x, Vertices[SegList[i].SegPtr->v1].y, + Vertices[SegList[i].SegPtr->v2].x, Vertices[SegList[i].SegPtr->v2].y)); SegList[i].SegNum = DWORD(SegList[i].SegPtr - &Segs[0]); } Subsectors.Push (sub); @@ -330,7 +334,8 @@ bool FNodeBuilder::CheckSubsector (DWORD set, node_t &node, DWORD &splitseg) do { - D(Printf (PRINT_LOG, " - seg %d(%d,%d)-(%d,%d) line %d front %d back %d\n", seg, + D(Printf (PRINT_LOG, " - seg %d%c(%d,%d)-(%d,%d) line %d front %d back %d\n", seg, + Segs[seg].linedef == -1 ? '+' : ' ', 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, diff --git a/src/nodebuild.h b/src/nodebuild.h index a6f0459a0..81c7b1345 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -34,6 +34,8 @@ public: FEvent *FindEvent (double distance) const; void DeleteAll (); + void PrintTree () const { PrintTree (Root); } + private: FEvent Nil; FEvent *Root; @@ -42,6 +44,8 @@ private: void DeletionTraverser (FEvent *event); FEvent *Successor (FEvent *event) const; FEvent *Predecessor (FEvent *event) const; + + void PrintTree (const FEvent *event) const; }; struct FSimpleVert diff --git a/src/nodebuild_events.cpp b/src/nodebuild_events.cpp index d7660f588..2b71e01c7 100644 --- a/src/nodebuild_events.cpp +++ b/src/nodebuild_events.cpp @@ -210,3 +210,17 @@ FEvent *FEventTree::GetMinimum () } return node; } + +void FEventTree::PrintTree (const FEvent *event) const +{ + // Use the CRT's sprintf so that it shares the same formatting as ZDBSP's output. + char buff[100]; + if (event != &Nil) + { + PrintTree(event->Left); + sprintf(buff, " Distance %g, vertex %d, seg %u\n", + sqrt(event->Distance/4294967296.0), event->Info.Vertex, (unsigned)event->Info.FrontSeg); + Printf(PRINT_LOG, "%s", buff); + PrintTree(event->Right); + } +} diff --git a/src/nodebuild_extract.cpp b/src/nodebuild_extract.cpp index 6260ac2f0..c0f769873 100644 --- a/src/nodebuild_extract.cpp +++ b/src/nodebuild_extract.cpp @@ -78,7 +78,8 @@ 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)); + D(Printf(PRINT_LOG, "Node %d: Splitter[%08x,%08x] [%08x,%08x]\n", i, + outNodes[i].x, outNodes[i].y, outNodes[i].dx, outNodes[i].dy)); // 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) @@ -296,12 +297,14 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t { 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, + Printf(PRINT_LOG, "%d%c %5d(%5d,%5d)->%5d(%5d,%5d) - %3.5f %d,%d [%08x,%08x]-[%08x,%08x]\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); + seg->planenum, seg->planefront, + Vertices[seg->v1].x, Vertices[seg->v1].y, + Vertices[seg->v2].x, Vertices[seg->v2].y); } #endif @@ -395,12 +398,16 @@ int FNodeBuilder::CloseSubsector (TArray &segs, int subsector, vertex_t 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, + Printf(PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\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); + segs[i].v2->y>>16, + segs[i].v1->x, + segs[i].v1->y, + segs[i].v2->x, + segs[i].v2->y); } #endif diff --git a/src/nodebuild_gl.cpp b/src/nodebuild_gl.cpp index add4f7123..d029e7f69 100644 --- a/src/nodebuild_gl.cpp +++ b/src/nodebuild_gl.cpp @@ -83,6 +83,8 @@ double FNodeBuilder::AddIntersection (const node_t &node, int vertex) // seg information will be messed up in the generated tree. void FNodeBuilder::FixSplitSharers (const node_t &node) { + D(Printf(PRINT_LOG, "events:\n")); + D(Events.PrintTree()); for (unsigned int i = 0; i < SplitSharers.Size(); ++i) { DWORD seg = SplitSharers[i].Seg; @@ -95,6 +97,18 @@ void FNodeBuilder::FixSplitSharers (const node_t &node) continue; } + // Use the CRT's printf so the formatting matches ZDBSP's + D(char buff[200]); + D(sprintf(buff, "Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg, + Segs[seg].v1, + Vertices[Segs[seg].v1].x>>16, + Vertices[Segs[seg].v1].y>>16, + Segs[seg].v2, + Vertices[Segs[seg].v2].x>>16, + Vertices[Segs[seg].v2].y>>16, + SplitSharers[i].Distance, event->Distance)); + D(Printf(PRINT_LOG, "%s", buff)); + if (SplitSharers[i].Forward) { event = Events.GetSuccessor (event); diff --git a/src/nodebuild_utility.cpp b/src/nodebuild_utility.cpp index b37533921..e7d5865d5 100644 --- a/src/nodebuild_utility.cpp +++ b/src/nodebuild_utility.cpp @@ -185,6 +185,9 @@ int FNodeBuilder::CreateSeg (int linenum, int sidenum) segnum = (int)Segs.Push (seg); Vertices[seg.v1].segs = segnum; Vertices[seg.v2].segs2 = segnum; + D(Printf(PRINT_LOG, "Seg %4d: From line %d, side %s (%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", segnum, linenum, sidenum ? "back " : "front", + Vertices[seg.v1].x>>16, Vertices[seg.v1].y>>16, Vertices[seg.v2].x>>16, Vertices[seg.v2].y>>16, + Vertices[seg.v1].x, Vertices[seg.v1].y, Vertices[seg.v2].x, Vertices[seg.v2].y)); return segnum; } diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index a139f7a69..22bf18e26 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -853,15 +853,18 @@ bool P_LoadGLNodes(MapData * map) { if (map->MapLumps[ML_GLZNODES].Reader && map->MapLumps[ML_GLZNODES].Reader->GetLength() != 0) { - const int idcheck = MAKE_ID('Z','G','L','N'); - const int idcheck2 = MAKE_ID('Z','G','L','2'); - const int idcheck3 = MAKE_ID('X','G','L','N'); - const int idcheck4 = MAKE_ID('X','G','L','2'); + const int idcheck1a = MAKE_ID('Z','G','L','N'); + const int idcheck2a = MAKE_ID('Z','G','L','2'); + const int idcheck3a = MAKE_ID('Z','G','L','3'); + const int idcheck1b = MAKE_ID('X','G','L','N'); + const int idcheck2b = MAKE_ID('X','G','L','2'); + const int idcheck3b = MAKE_ID('X','G','L','3'); int id; map->Seek(ML_GLZNODES); map->file->Read (&id, 4); - if (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4) + if (id == idcheck1a || id == idcheck2a || id == idcheck3a || + id == idcheck1b || id == idcheck2b || id == idcheck3b) { try { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 6a300f4d7..70f63e218 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -892,7 +892,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type) BYTE side; data >> v1 >> partner; - if (type == 2) + if (type >= 2) { data >> line; } @@ -1045,13 +1045,20 @@ void LoadZNodes(FileReaderBase &data, int glnodes) for (i = 0; i < numNodes; ++i) { - SWORD x, y, dx, dy; + if (glnodes < 3) + { + SWORD x, y, dx, dy; - data >> x >> y >> dx >> dy; - nodes[i].x = x << FRACBITS; - nodes[i].y = y << FRACBITS; - nodes[i].dx = dx << FRACBITS; - nodes[i].dy = dy << FRACBITS; + data >> x >> y >> dx >> dy; + nodes[i].x = x << FRACBITS; + nodes[i].y = y << FRACBITS; + nodes[i].dx = dx << FRACBITS; + nodes[i].dy = dy << FRACBITS; + } + else + { + data >> nodes[i].x >> nodes[i].y >> nodes[i].dx >> nodes[i].dy; + } for (int j = 0; j < 2; ++j) { for (int k = 0; k < 4; ++k) @@ -1100,6 +1107,11 @@ void P_LoadZNodes (FileReader &dalump, DWORD id) compressed = true; break; + case MAKE_ID('Z','G','L','3'): + type = 3; + compressed = true; + break; + case MAKE_ID('X','N','O','D'): type = 0; compressed = false; @@ -1115,6 +1127,11 @@ void P_LoadZNodes (FileReader &dalump, DWORD id) compressed = false; break; + case MAKE_ID('X','G','L','3'): + type = 3; + compressed = false; + break; + default: return; } @@ -3680,7 +3697,7 @@ 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, idcheck3 = 0, idcheck4 = 0; + DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0, idcheck5 = 0, idcheck6 = 0; if (map->Size(ML_ZNODES) != 0) { @@ -3694,8 +3711,10 @@ 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'); + idcheck3 = MAKE_ID('Z','G','L','3'); + idcheck4 = MAKE_ID('X','G','L','N'); + idcheck5 = MAKE_ID('X','G','L','2'); + idcheck6 = MAKE_ID('X','G','L','3'); } map->file->Read (&id, 4); From deff47ea181a87ff560e7acd4e4318cd6ba9e931 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 7 Dec 2012 07:40:41 +0000 Subject: [PATCH 061/387] - fixed: The map loader did not check for the new node formats. SVN r3982 (trunk) --- src/p_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 70f63e218..1edbb181f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3718,7 +3718,7 @@ void P_SetupLevel (char *lumpname, int position) } map->file->Read (&id, 4); - if (id != 0 && (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4)) + if (id != 0 && (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4 || id == idcheck5 || id == idcheck6)) { try { From 86291fcd9668fbdab8b513eb1a4807e8acae5ec3 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 17 Dec 2012 19:17:02 +0000 Subject: [PATCH 062/387] - Added support for Eternity's ATAG chunk (mixed-type arrays). Requires a structure aware compiler (not ACC). SVN r3989 (trunk) --- src/p_acs.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 607b68265..905ed1a49 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1242,6 +1242,34 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) } } } + + // [BL] Newer version of ASTR for structure aware compilers although we only have one array per chunk + chunk = (DWORD *)FindChunk (MAKE_ID('A','T','A','G')); + while (chunk != NULL) + { + const BYTE* chunkData = (const BYTE*)(chunk + 2); + // First byte is version, it should be 0 + if(*chunkData++ == 0) + { + int arraynum = MapVarStore[LittleLong(*(const DWORD*)(chunkData))]; + chunkData += 4; + if ((unsigned)arraynum < (unsigned)NumArrays) + { + SDWORD *elems = ArrayStore[arraynum].Elements; + // Ending zeros may be left out. + for (int j = MIN(chunk[1]-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData) + { + // For ATAG, a value of 0 = Integer, 1 = String, 2 = FunctionPtr + // Our implementation uses the same tags for both String and FunctionPtr + if(*chunkData) + *elems |= LibraryID; + } + i += 4+ArrayStore[arraynum].ArraySize; + } + } + + chunk = (DWORD *)NextChunk ((BYTE *)chunk); + } } // Load required libraries. @@ -5381,7 +5409,7 @@ scriptwait: if (activationline != NULL) { activationline->special = 0; - DPrintf("Cleared line special on line %d\n", activationline - lines); + DPrintf("Cleared line special on line %d\n", (int)(activationline - lines)); } break; From e8731c7571804419eb6b21b8377be72f27de9aaf Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 20 Dec 2012 04:17:18 +0000 Subject: [PATCH 063/387] - Added support for Eternity's JUMP table and PCD_GOTOSTACK (again, requires advanced compiler). SVN r3990 (trunk) --- src/p_acs.cpp | 13 +++++++++++++ src/p_acs.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 905ed1a49..437a9cfe8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1144,6 +1144,14 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) Functions += 8; } + // Load JUMP points + chunk = (DWORD *)FindChunk (MAKE_ID('J','U','M','P')); + if (chunk != NULL) + { + for (i = 0;i < (int)LittleLong(chunk[1]);i += 4) + JumpPoints.Push(LittleLong(chunk[2 + i/4])); + } + // Initialize this object's map variables memset (MapVarStore, 0, sizeof(MapVarStore)); chunk = (DWORD *)FindChunk (MAKE_ID('M','I','N','I')); @@ -5188,6 +5196,11 @@ int DLevelScript::RunScript () pc = activeBehavior->Ofs2PC (LittleLong(*pc)); break; + case PCD_GOTOSTACK: + pc = activeBehavior->Jump2PC (STACK(1)); + sp--; + break; + case PCD_IFGOTO: if (STACK(1)) pc = activeBehavior->Ofs2PC (LittleLong(*pc)); diff --git a/src/p_acs.h b/src/p_acs.h index 44786e260..999dda7a5 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -165,6 +165,7 @@ public: void StartTypedScripts (WORD type, AActor *activator, bool always, int arg1, bool runNow); DWORD PC2Ofs (int *pc) const { return (DWORD)((BYTE *)pc - Data); } int *Ofs2PC (DWORD ofs) const { return (int *)(Data + ofs); } + int *Jump2PC (DWORD jumpPoint) const { return Ofs2PC(JumpPoints[jumpPoint]); } ACSFormat GetFormat() const { return Format; } ScriptFunction *GetFunction (int funcnum, FBehavior *&module) const; int GetArrayVal (int arraynum, int index) const; @@ -213,6 +214,7 @@ private: TArray Imports; DWORD LibraryID; char ModuleName[9]; + TArray JumpPoints; static TArray StaticModules; @@ -602,6 +604,7 @@ public: /*360*/ PCD_CALLSTACK, // from Eternity PCD_SCRIPTWAITNAMED, PCD_TRANSLATIONRANGE3, + PCD_GOTOSTACK, /*363*/ PCODE_COMMAND_COUNT }; From 2022d64ee2a39be538b029dd3da1d121d5d1a942 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 21 Dec 2012 22:47:55 +0000 Subject: [PATCH 064/387] - Do not crash when reading ATAG chunks on processors that don't like unaligned accesses. SVN r3991 (trunk) --- src/p_acs.cpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 437a9cfe8..ead7b198a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -173,6 +173,27 @@ TArray #define STRINGBUILDER_START(Builder) if (Builder.IsNotEmpty() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; } #define STRINGBUILDER_FINISH(Builder) if (!ACS_StringBuilderStack.Pop(Builder)) { Builder = ""; } +//============================================================================ +// +// uallong +// +// Read a possibly unaligned four-byte little endian integer from memory. +// +//============================================================================ + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) +inline int uallong(const int &foo) +{ + return foo; +} +#else +inline int uallong(const int &foo) +{ + const unsigned char *bar = (const unsigned char *)&foo; + return bar[0] | (bar[1] << 8) | (bar[2] << 16) | (bar[3] << 24); +} +#endif + //============================================================================ // // ScriptPresentation @@ -1259,7 +1280,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) // First byte is version, it should be 0 if(*chunkData++ == 0) { - int arraynum = MapVarStore[LittleLong(*(const DWORD*)(chunkData))]; + int arraynum = MapVarStore[uallong(*(const int*)(chunkData))]; chunkData += 4; if ((unsigned)arraynum < (unsigned)NumArrays) { @@ -4010,20 +4031,6 @@ 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; From 3eb9953930df32809c43deb20d7c5513818fc006 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 21 Dec 2012 22:48:40 +0000 Subject: [PATCH 065/387] - Fix type conversion warning in file_wad.cpp. SVN r3992 (trunk) --- src/resourcefiles/file_wad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index ea9ea77fd..ea8cac15b 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -220,7 +220,7 @@ public: while(AvailOut && Stream.State != STREAM_FINAL); assert(AvailOut == 0); - return Out - (BYTE*)buffer; + return (long)(Out - (BYTE*)buffer); } }; From 849f30daab75db22dc97322faae97377869016f0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 21 Dec 2012 23:22:59 +0000 Subject: [PATCH 066/387] - Changed synth.chorus.active and synth.reverb.active settings to use fluid_settings_setint(), since they're int and not string settings. - Fixed: FluidSynthMIDIDevice::FluidSettingInt() interpreted the return value from fluid_settings_setint() wrongly. SVN r3993 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 62225cb46..77b830cc3 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -107,13 +107,13 @@ CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR(Bool, fluid_reverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (currSong != NULL) - currSong->FluidSettingStr("synth.reverb.active", self ? "yes" : "no"); + currSong->FluidSettingInt("synth.reverb.active", self); } CUSTOM_CVAR(Bool, fluid_chorus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (currSong != NULL) - currSong->FluidSettingStr("synth.chorus.active", self ? "yes" : "no"); + currSong->FluidSettingInt("synth.chorus.active", self); } CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -278,8 +278,8 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() } 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.reverb.active", fluid_reverb); + fluid_settings_setint(FluidSettings, "synth.chorus.active", fluid_chorus); fluid_settings_setint(FluidSettings, "synth.polyphony", fluid_voices); fluid_settings_setint(FluidSettings, "synth.cpu-cores", fluid_threads); FluidSynth = new_fluid_synth(FluidSettings); @@ -542,7 +542,7 @@ void FluidSynthMIDIDevice::FluidSettingInt(const char *setting, int value) 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)) + else if (0 == fluid_settings_setint(FluidSettings, setting, value)) { Printf("Faild to set %s to %d.\n", setting, value); } @@ -560,7 +560,7 @@ void FluidSynthMIDIDevice::FluidSettingNum(const char *setting, double value) { if (FluidSettings != NULL) { - if (!fluid_settings_setnum(FluidSettings, setting, value)) + if (0 == fluid_settings_setnum(FluidSettings, setting, value)) { Printf("Failed to set %s to %g.\n", setting, value); } @@ -579,7 +579,7 @@ void FluidSynthMIDIDevice::FluidSettingStr(const char *setting, const char *valu { if (FluidSettings != NULL) { - if (!fluid_settings_setstr(FluidSettings, setting, value)) + if (0 == fluid_settings_setstr(FluidSettings, setting, value)) { Printf("Failed to set %s to %s.\n", setting, value); } From 3123925fa86c6963ae2471f1fd8a05b45202bff7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 21 Dec 2012 23:58:33 +0000 Subject: [PATCH 067/387] - Fixed: Changing fluid_chorus and fluid_reverb did not take effect until the next song started. SVN r3994 (trunk) --- src/sound/i_musicinterns.h | 2 ++ src/sound/music_fluidsynth_mididevice.cpp | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 576597dc2..3c1134c63 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -373,6 +373,8 @@ protected: 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 *); + void (STACK_ARGS *fluid_synth_set_reverb_on)(fluid_synth_t *, int); + void (STACK_ARGS *fluid_synth_set_chorus_on)(fluid_synth_t *, 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 *); diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 77b830cc3..b9143d140 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -544,7 +544,16 @@ void FluidSynthMIDIDevice::FluidSettingInt(const char *setting, int value) } else if (0 == fluid_settings_setint(FluidSettings, setting, value)) { - Printf("Faild to set %s to %d.\n", setting, value); + Printf("Failed to set %s to %d.\n", setting, value); + } + // fluid_settings_setint succeeded; update these settings in the running synth, too + else if (strcmp(setting, "synth.reverb.active") == 0) + { + fluid_synth_set_reverb_on(FluidSynth, value); + } + else if (strcmp(setting, "synth.chorus.active") == 0) + { + fluid_synth_set_chorus_on(FluidSynth, value); } } @@ -648,6 +657,8 @@ bool FluidSynthMIDIDevice::LoadFluidSynth() { (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_reverb_on, "fluid_synth_set_reverb_on" }, + { (void **)&fluid_synth_set_chorus_on, "fluid_synth_set_chorus_on" }, { (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" }, From f45c6247693e735298e6b5657ae8f15ed794055f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 21 Dec 2012 23:59:55 +0000 Subject: [PATCH 068/387] - Changed default FluidSynth reverb and chorus parameters to the ones suggested here: http://forums.scummvm.org/viewtopic.php?p=72972&sid=d139e99a13359541ead07073112e3888#72972 SVN r3995 (trunk) --- src/sound/music_fluidsynth_mididevice.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index b9143d140..2e86cb2ee 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -158,7 +158,7 @@ CUSTOM_CVAR(Int, fluid_threads, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) self = 256; } -CUSTOM_CVAR(Float, fluid_reverb_roomsize, FLUID_REVERB_DEFAULT_ROOMSIZE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_reverb_roomsize, 0.61f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -168,7 +168,7 @@ CUSTOM_CVAR(Float, fluid_reverb_roomsize, FLUID_REVERB_DEFAULT_ROOMSIZE, CVAR_AR currSong->FluidSettingInt("z.reverb-changed", 0); } -CUSTOM_CVAR(Float, fluid_reverb_damping, FLUID_REVERB_DEFAULT_DAMP, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_reverb_damping, 0.23f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -178,7 +178,7 @@ CUSTOM_CVAR(Float, fluid_reverb_damping, FLUID_REVERB_DEFAULT_DAMP, CVAR_ARCHIVE currSong->FluidSettingInt("z.reverb-changed", 0); } -CUSTOM_CVAR(Float, fluid_reverb_width, FLUID_REVERB_DEFAULT_WIDTH, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_reverb_width, 0.76f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -188,7 +188,7 @@ CUSTOM_CVAR(Float, fluid_reverb_width, FLUID_REVERB_DEFAULT_WIDTH, CVAR_ARCHIVE| currSong->FluidSettingInt("z.reverb-changed", 0); } -CUSTOM_CVAR(Float, fluid_reverb_level, FLUID_REVERB_DEFAULT_LEVEL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_reverb_level, 0.57f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -198,7 +198,7 @@ CUSTOM_CVAR(Float, fluid_reverb_level, FLUID_REVERB_DEFAULT_LEVEL, CVAR_ARCHIVE| currSong->FluidSettingInt("z.reverb-changed", 0); } -CUSTOM_CVAR(Int, fluid_chorus_voices, FLUID_CHORUS_DEFAULT_N, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, fluid_chorus_voices, 3, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -208,7 +208,7 @@ CUSTOM_CVAR(Int, fluid_chorus_voices, FLUID_CHORUS_DEFAULT_N, CVAR_ARCHIVE|CVAR_ currSong->FluidSettingInt("z.chorus-changed", 0); } -CUSTOM_CVAR(Float, fluid_chorus_level, FLUID_CHORUS_DEFAULT_LEVEL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_chorus_level, 1.2f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; @@ -218,7 +218,7 @@ CUSTOM_CVAR(Float, fluid_chorus_level, FLUID_CHORUS_DEFAULT_LEVEL, CVAR_ARCHIVE| currSong->FluidSettingInt("z.chorus-changed", 0); } -CUSTOM_CVAR(Float, fluid_chorus_speed, FLUID_CHORUS_DEFAULT_SPEED, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, fluid_chorus_speed, 0.3f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0.29f) self = 0.29f; @@ -229,7 +229,7 @@ CUSTOM_CVAR(Float, fluid_chorus_speed, FLUID_CHORUS_DEFAULT_SPEED, CVAR_ARCHIVE| } // 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) +CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (self < 0) self = 0; From 92a07ab8b4aefb84a92de262452ab2285bc29d87 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 22 Dec 2012 00:21:18 +0000 Subject: [PATCH 069/387] - Fixed: The Fist had the wrong Tag string. SVN r3996 (trunk) --- wadsrc/static/actors/doom/doomweapons.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/doomweapons.txt b/wadsrc/static/actors/doom/doomweapons.txt index 4b0386524..8be33c0ca 100644 --- a/wadsrc/static/actors/doom/doomweapons.txt +++ b/wadsrc/static/actors/doom/doomweapons.txt @@ -21,7 +21,7 @@ ACTOR Fist : Weapon Weapon.SelectionOrder 3700 Weapon.Kickback 100 Obituary "$OB_MPFIST" - Tag "$FIST" + Tag "$TAG_FIST" +WEAPON.WIMPY_WEAPON +WEAPON.MELEEWEAPON States From c114113fe8afc9638cf8d10decb049a740ba5825 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 22 Dec 2012 00:26:26 +0000 Subject: [PATCH 070/387] - Fixed: Sky floors should not be drawn in the textured automap. SVN r3997 (trunk) --- src/am_map.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/am_map.cpp b/src/am_map.cpp index 126ab733a..335644b86 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -40,6 +40,7 @@ #include "c_bind.h" #include "farchive.h" #include "r_renderer.h" +#include "r_sky.h" #include "m_cheat.h" #include "i_system.h" @@ -1717,6 +1718,11 @@ void AM_drawSubsectors() colormap = light->extra_colormap; } #endif + if (maptex == skyflatnum) + { + continue; + } + originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24)); originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24)); // Apply the floor's rotation to the texture origin. From 682c7d2a8a026d5627aa0235534b7320ec4e2145 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 22 Dec 2012 00:55:27 +0000 Subject: [PATCH 071/387] - Fixed: The originx and originy for the textured automap is supposed to be calculated after rotating originpt by the automap, not before. SVN r3998 (trunk) --- src/am_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 335644b86..246adcc9b 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1723,8 +1723,6 @@ void AM_drawSubsectors() continue; } - originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24)); - originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24)); // Apply the floor's rotation to the texture origin. if (rotation != 0) { @@ -1736,6 +1734,8 @@ void AM_drawSubsectors() rotation += ANG90 - players[consoleplayer].camera->angle; AM_rotatePoint(&originpt.x, &originpt.y); } + originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24)); + originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24)); // If this subsector has not actually been seen yet (because you are cheating // to see it on the map), tint and desaturate it. From 21ada0b3f6a03ac23a7e307a508ba8bdde925ad3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 22 Dec 2012 02:57:35 +0000 Subject: [PATCH 072/387] - Fixed: When the player sprite is being drawn with a fixed colormap, hardware acceleration should not be disabled when the regular colormap has lights that stay bright throughout. SVN r4001 (trunk) --- src/r_things.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 459ebdbce..386ef8139 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1104,7 +1104,7 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, fixed_t sx, fixed_ } // If the main colormap has fixed lights, and this sprite is being drawn with that // colormap, disable acceleration so that the lights can remain fixed. - if (!noaccel && + if (!noaccel && realfixedcolormap == NULL && NormalLightHasFixedLights && mybasecolormap == &NormalLight && vis->pic->UseBasePalette()) { From b3ada01bbdf5a697471dbd1ed75086d8df4a347d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 22 Dec 2012 22:37:58 +0000 Subject: [PATCH 073/387] - Added Gez's patch to show the berserk icon on the alt. HUD and added a menu option for this setting. SVN r4002 (trunk) --- src/g_shared/shared_hud.cpp | 26 +++++++++++++++++++++----- wadsrc/static/menudef.txt | 1 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 1c98b1808..5bdca34e7 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -78,13 +78,15 @@ CVAR (Int, hud_armor_red, 25, CVAR_ARCHIVE) // armor amount less than which CVAR (Int, hud_armor_yellow, 50, CVAR_ARCHIVE) // armor amount less than which status is yellow CVAR (Int, hud_armor_green, 100, CVAR_ARCHIVE) // armor amount above is blue, below is green +CVAR (Bool, hud_berserk_health, true, CVAR_ARCHIVE); // when found berserk pack instead of health box + CVAR (Int, hudcolor_titl, CR_YELLOW, CVAR_ARCHIVE) // color of automap title CVAR (Int, hudcolor_time, CR_RED, CVAR_ARCHIVE) // color of level/hub time CVAR (Int, hudcolor_ltim, CR_ORANGE, CVAR_ARCHIVE) // color of single level time CVAR (Int, hudcolor_ttim, CR_GOLD, CVAR_ARCHIVE) // color of total time CVAR (Int, hudcolor_xyco, CR_GREEN, CVAR_ARCHIVE) // color of coordinates -CVAR (Int, hudcolor_statnames, CR_RED, CVAR_ARCHIVE) // For the letters befóre the stats +CVAR (Int, hudcolor_statnames, CR_RED, CVAR_ARCHIVE) // For the letters before the stats CVAR (Int, hudcolor_stats, CR_GREEN, CVAR_ARCHIVE) // For the stats values themselves @@ -95,6 +97,7 @@ static FFont * IndexFont; // The font for the inventory indices // Icons static FTexture * healthpic; // Health icon +static FTexture * berserkpic; // Berserk icon (Doom only) static FTexture * fragpic; // Frags icon static FTexture * invgems[4]; // Inventory arrows @@ -267,16 +270,22 @@ static void DrawStatus(player_t * CPlayer, int x, int y) // //=========================================================================== -static void DrawHealth(int health, int x, int y) +static void DrawHealth(player_t *CPlayer, int x, int y) { + int health = CPlayer->health; + // decide on the color first int fontcolor = health < hud_health_red ? CR_RED : health < hud_health_yellow ? CR_GOLD : health <= hud_health_green ? CR_GREEN : CR_BLUE; - - DrawImageToBox(healthpic, x, y, 31, 17); + + const bool haveBerserk = hud_berserk_health + && NULL != berserkpic + && NULL != CPlayer->mo->FindInventory< APowerStrength >(); + + DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 17); DrawHudNumber(HudFont, fontcolor, health, x + 33, y + 17); } @@ -858,7 +867,7 @@ void DrawHUD() DrawStatus(CPlayer, 5, hudheight-75); DrawFrags(CPlayer, 5, hudheight-70); } - DrawHealth(CPlayer->health, 5, hudheight-45); + DrawHealth(CPlayer, 5, hudheight-45); DrawArmor(CPlayer->mo->FindInventory(), CPlayer->mo->FindInventory(), 5, hudheight-20); i=DrawKeys(CPlayer, hudwidth-4, hudheight-10); @@ -936,6 +945,7 @@ void HUD_InitHud() default: healthpic = TexMan.FindTexture("MEDIA0"); + berserkpic = TexMan.FindTexture("PSTRA0"); HudFont=FFont::FindFont("HUDFONT_DOOM"); break; } @@ -973,6 +983,12 @@ void HUD_InitHud() FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); if (tex.isValid()) healthpic = TexMan[tex]; } + else if (sc.Compare("Berserk")) + { + sc.MustGetString(); + FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); + if (tex.isValid()) berserkpic = TexMan[tex]; + } else { const PClass * ti = PClass::FindClass(sc.String); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 8f22fdfb2..55332c595 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -790,6 +790,7 @@ OptionMenu "AltHUDOptions" Option "Show monster count", "hud_showmonsters", "OnOff" Option "Show item count", "hud_showitems", "OnOff" Option "Show stamina and accuracy", "hud_showstats", "OnOff" + Option "Show berserk", "hud_berserk_health", "OnOff" Slider "Red ammo display below %", "hud_ammo_red", 0, 100, 1, 0 Slider "Yellow ammo display below %", "hud_ammo_yellow", 0, 100, 1, 0 Slider "Red health display below", "hud_health_red", 0, 100, 1, 0 From db018325198e9eddcaea461d78b360c52440e72a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 01:34:27 +0000 Subject: [PATCH 074/387] - Fixed: The resurrect cheat also needs to restore the player's radius. SVN r4003 (trunk) --- src/m_cheat.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index a867c77d2..b6bd24ae3 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -313,6 +313,7 @@ void cht_DoCheat (player_t *player, int cheat) player->mo->flags6 = player->mo->GetDefault()->flags6; player->mo->renderflags &= ~RF_INVISIBLE; player->mo->height = player->mo->GetDefault()->height; + player->mo->radius = player->mo->GetDefault()->radius; player->mo->special1 = 0; // required for the Hexen fighter's fist attack. // This gets set by AActor::Die as flag for the wimpy death and must be reset here. player->mo->SetState (player->mo->SpawnState); From 67eda6b1ad57971fc4e01d91f4963ec9c43e4e63 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 02:10:26 +0000 Subject: [PATCH 075/387] - Changed P_CheckPlayerSprites() so that it does not alter any actor data. It is now called by R_ProjectSprite() to modify the appropriate data right before it is needed for rendering. SVN r4004 (trunk) --- src/d_main.cpp | 1 - src/d_player.h | 2 +- src/g_game.cpp | 1 - src/p_user.cpp | 100 ++++++++++++++++++----------------------------- src/r_things.cpp | 28 ++++++++----- 5 files changed, 58 insertions(+), 74 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index ae28f15d8..afda957af 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -775,7 +775,6 @@ void D_Display () } screen->SetBlendingRect(viewwindowx, viewwindowy, viewwindowx + viewwidth, viewwindowy + viewheight); - P_CheckPlayerSprites(); P_PredictPlayer(&players[consoleplayer]); Renderer->RenderView(&players[consoleplayer]); P_UnPredictPlayer(); diff --git a/src/d_player.h b/src/d_player.h index fa14c49a9..bb6e87e7b 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -427,7 +427,7 @@ extern player_t players[MAXPLAYERS]; FArchive &operator<< (FArchive &arc, player_t *&p); -void P_CheckPlayerSprites(); +void P_CheckPlayerSprite(AActor *mo, unsigned &spritenum, fixed_t &scalex, fixed_t &scaley); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/g_game.cpp b/src/g_game.cpp index d96e37fcf..6163ee0d6 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2049,7 +2049,6 @@ static void PutSavePic (FILE *file, int width, int height) } else { - P_CheckPlayerSprites(); Renderer->WriteSavePic(&players[consoleplayer], file, width, height); } } diff --git a/src/p_user.cpp b/src/p_user.cpp index 8339262b7..2a8e76099 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1483,77 +1483,55 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) // // P_CheckPlayerSprites // -// Here's the place where crouching sprites are handled -// This must be called each frame before rendering +// Here's the place where crouching sprites are handled. +// R_ProjectSprite() calls this for any players. // //=========================================================================== -void P_CheckPlayerSprites() +void P_CheckPlayerSprite(AActor *actor, unsigned &spritenum, fixed_t &scalex, fixed_t &scaley) { - for(int i=0; iplayer; + fixed_t defscaleY = actor->GetDefault()->scaleY; + fixed_t defscaleX = actor->GetDefault()->scaleX; + int crouchspriteno; + + if (player->userinfo.skin != 0 && !(actor->flags4 & MF4_NOSKIN)) { - player_t * player = &players[i]; - APlayerPawn * mo = player->mo; + defscaleY = skins[player->userinfo.skin].ScaleY; + defscaleX = skins[player->userinfo.skin].ScaleX; + } - if (playeringame[i] && mo != NULL) + // Set the crouch sprite? + if (player->crouchfactor < FRACUNIT*3/4) + { + if (spritenum == actor->SpawnState->sprite || spritenum == player->mo->crouchsprite) { - int crouchspriteno; - fixed_t defscaleY = mo->GetDefault()->scaleY; - fixed_t defscaleX = mo->GetDefault()->scaleX; - - if (player->userinfo.skin != 0 && !(player->mo->flags4 & MF4_NOSKIN)) - { - defscaleY = skins[player->userinfo.skin].ScaleY; - defscaleX = skins[player->userinfo.skin].ScaleX; - } - - // Set the crouch sprite - if (player->crouchfactor < FRACUNIT*3/4) - { - if (mo->sprite == mo->SpawnState->sprite || mo->sprite == mo->crouchsprite) - { - crouchspriteno = mo->crouchsprite; - } - else if (!(player->mo->flags4 & MF4_NOSKIN) && - (mo->sprite == skins[player->userinfo.skin].sprite || - mo->sprite == skins[player->userinfo.skin].crouchsprite)) - { - crouchspriteno = skins[player->userinfo.skin].crouchsprite; - } - else - { - // no sprite -> squash the existing one - crouchspriteno = -1; - } + crouchspriteno = player->mo->crouchsprite; + } + else if (!(actor->flags4 & MF4_NOSKIN) && + (spritenum == skins[player->userinfo.skin].sprite || + spritenum == skins[player->userinfo.skin].crouchsprite)) + { + crouchspriteno = skins[player->userinfo.skin].crouchsprite; + } + else + { // no sprite -> squash the existing one + crouchspriteno = -1; + } - if (crouchspriteno > 0) - { - mo->sprite = crouchspriteno; - mo->scaleY = defscaleY; - } - else if (player->playerstate != PST_DEAD) - { - mo->scaleY = player->crouchfactor < FRACUNIT*3/4 ? defscaleY/2 : defscaleY; - } - } - else // Set the normal sprite - { - if (mo->sprite != 0) - { - if (mo->sprite == mo->crouchsprite) - { - mo->sprite = mo->SpawnState->sprite; - } - else if (mo->sprite != 0 && mo->sprite == skins[player->userinfo.skin].crouchsprite) - { - mo->sprite = skins[player->userinfo.skin].sprite; - } - } - mo->scaleY = defscaleY; - } - mo->scaleX = defscaleX; + if (crouchspriteno > 0) + { + spritenum = crouchspriteno; + } + else if (player->playerstate != PST_DEAD) + { + if (player->crouchfactor < FRACUNIT*3/4) + defscaleY /= 2; } } + // Scale the sprite by the actor, skin, and crouch values + scalex = FixedMul(scalex, defscaleX); + scaley = FixedMul(scaley, defscaleY); } /* diff --git a/src/r_things.cpp b/src/r_things.cpp index 386ef8139..82edfed78 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -523,6 +523,14 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor tex = NULL; voxel = NULL; + unsigned spritenum = thing->sprite; + fixed_t spritescaleX = thing->scaleX; + fixed_t spritescaleY = thing->scaleY; + if (thing->player != NULL) + { + P_CheckPlayerSprite(thing, spritenum, spritescaleX, spritescaleY); + } + if (thing->picnum.isValid()) { picnum = thing->picnum; @@ -557,13 +565,13 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor { // decide which texture to use for the sprite #ifdef RANGECHECK - if ((unsigned)thing->sprite >= (unsigned)sprites.Size ()) + if (spritenum >= (unsigned)sprites.Size ()) { - DPrintf ("R_ProjectSprite: invalid sprite number %i\n", thing->sprite); + DPrintf ("R_ProjectSprite: invalid sprite number %u\n", spritenum); return; } #endif - spritedef_t *sprdef = &sprites[thing->sprite]; + spritedef_t *sprdef = &sprites[spritenum]; if (thing->frame >= sprdef->numframes) { // If there are no frames at all for this sprite, don't draw it. @@ -624,13 +632,13 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor // [RH] Added scaling int scaled_to = tex->GetScaledTopOffset(); int scaled_bo = scaled_to - tex->GetScaledHeight(); - gzt = fz + thing->scaleY * scaled_to; - gzb = fz + thing->scaleY * scaled_bo; + gzt = fz + spritescaleY * scaled_to; + gzb = fz + spritescaleY * scaled_bo; } else { - xscale = FixedMul(thing->scaleX, voxel->Scale); - yscale = FixedMul(thing->scaleY, voxel->Scale); + xscale = FixedMul(spritescaleX, voxel->Scale); + yscale = FixedMul(spritescaleY, voxel->Scale); gzt = fz + MulScale8(yscale, voxel->Voxel->Mips[0].PivotZ) - thing->floorclip; gzb = fz + MulScale8(yscale, voxel->Voxel->Mips[0].PivotZ - (voxel->Voxel->Mips[0].SizeZ << 8)); if (gzt <= gzb) @@ -682,7 +690,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor } // calculate edges of the shape - const fixed_t thingxscalemul = DivScale16(thing->scaleX, tex->xScale); + const fixed_t thingxscalemul = DivScale16(spritescaleX, tex->xScale); tx -= (flip ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul; x1 = centerx + MulScale32 (tx, xscale); @@ -698,11 +706,11 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor if ((x2 < WindowLeft || x2 <= x1)) return; - xscale = FixedDiv(FixedMul(thing->scaleX, xscale), tex->xScale); + xscale = FixedDiv(FixedMul(spritescaleX, xscale), tex->xScale); iscale = (tex->GetWidth() << FRACBITS) / (x2 - x1); x2--; - fixed_t yscale = SafeDivScale16(thing->scaleY, tex->yScale); + fixed_t yscale = SafeDivScale16(spritescaleY, tex->yScale); // store information in a vissprite vis = R_NewVisSprite(); From efbaab3440ba0d32ed22a8361c11d2e3565a9f6f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 02:26:22 +0000 Subject: [PATCH 076/387] - Never set the player actor's scale to the skin's directly. Only do it indirectly through P_CheckPlayerSprite(). SVN r4005 (trunk) --- src/d_netinfo.cpp | 2 -- src/p_mobj.cpp | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 9d0d63f81..ed6a4f7fc 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -770,8 +770,6 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) GetDefaultByType (players[i].cls)->SpawnState->sprite) { // Only change the sprite if the player is using a standard one players[i].mo->sprite = skins[info->skin].sprite; - players[i].mo->scaleX = skins[info->skin].ScaleX; - players[i].mo->scaleY = skins[info->skin].ScaleY; } } // Rebuild translation in case the new skin uses a different range diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4198069b6..de97f89ee 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -328,8 +328,6 @@ void AActor::Serialize (FArchive &arc) state->sprite == GetDefaultByType (player->cls)->SpawnState->sprite) { // Give player back the skin sprite = skins[player->userinfo.skin].sprite; - scaleX = skins[player->userinfo.skin].ScaleX; - scaleY = skins[player->userinfo.skin].ScaleY; } if (Speed == 0) { @@ -4272,8 +4270,6 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, bool tempplayer if (!(mobj->flags4 & MF4_NOSKIN)) { mobj->sprite = skins[p->userinfo.skin].sprite; - mobj->scaleX = skins[p->userinfo.skin].ScaleX; - mobj->scaleY = skins[p->userinfo.skin].ScaleY; } p->DesiredFOV = p->FOV = 90.f; From 4228386837f3413521e29a47f9101bc5ad56f631 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:01:03 +0000 Subject: [PATCH 077/387] - Fixed: When P_Add3DFloor() adds the "inside" plane, it needs to copy the translucency flags from the original plane. SVN r4006 (trunk) --- src/p_3dfloors.cpp | 12 ++++++++---- src/p_3dfloors.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 02c2702ff..56b34ca0f 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -108,7 +108,7 @@ void F3DFloor::UpdateColormap(FDynamicColormap *&map) // Add one 3D floor to the sector // //========================================================================== -static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags,int transluc) +static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int alpha) { F3DFloor* ffloor; unsigned i; @@ -179,7 +179,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag ffloor->flags = flags; ffloor->master = master; - ffloor->alpha = transluc; + ffloor->alpha = alpha; ffloor->top.vindex = ffloor->bottom.vindex = -1; // The engine cannot handle sloped translucent floors. Sorry @@ -200,7 +200,11 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag // kg3D - software renderer only hack // this is really required because of ceilingclip and floorclip - if(flags & FF_BOTHPLANES) P_Add3DFloor(sec, sec2, master, FF_EXISTS | FF_THISINSIDE | FF_RENDERPLANES | FF_NOSHADE | FF_SEETHROUGH | FF_SHOOTTHROUGH | (flags & FF_INVERTSECTOR), transluc); + if(flags & FF_BOTHPLANES) + { + P_Add3DFloor(sec, sec2, master, FF_EXISTS | FF_THISINSIDE | FF_RENDERPLANES | FF_NOSHADE | FF_SEETHROUGH | FF_SHOOTTHROUGH | + (flags & (FF_INVERTSECTOR | FF_TRANSLUCENT | FF_ADDITIVETRANS)), alpha); + } } //========================================================================== @@ -208,7 +212,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag // Creates all 3D floors defined by one linedef // //========================================================================== -static int P_Set3DFloor(line_t * line, int param,int param2, int alpha) +static int P_Set3DFloor(line_t * line, int param, int param2, int alpha) { int s,i; int flags; diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index f9915348e..d0bca5e8f 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -36,7 +36,7 @@ typedef enum FF_FADEWALLS = 0x8000000, // Applies real fog to walls and doesn't blend the view FF_ADDITIVETRANS = 0x10000000, // Render this floor with additive translucency FF_FLOOD = 0x20000000, // extends towards the next lowest flooding or solid 3D floor or the bottom of the sector - FF_THISINSIDE = 0x40000000, // hack for software 3D with FF_BOTHPLANES + FF_THISINSIDE = 0x40000000, // hack for software 3D with FF_BOTHPLANES } ffloortype_e; // This is for the purpose of Sector_SetContents: From dfe470e5f254b2eb60c41bad91fe4cc3b2e9b456 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:17:52 +0000 Subject: [PATCH 078/387] - Added JLOSF_NOAUTOAIM flag for when you want to use A_JumpIfTargetInLOS in conjunction with something that never autoaims, such as a railgun. - Fixed: A_JumpIfTargetInLOS should use P_AimLineAttack() instead of P_BulletSlope(), because the latter intentionally checks to the sides of the aimed line. SVN r4007 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 5 +++-- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 597ba48d4..36efe7e8f 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2866,7 +2866,8 @@ enum JLOS_flags JLOSF_TARGETLOS=128, JLOSF_FLIPFOV=256, JLOSF_ALLYNOJUMP=512, - JLOSF_COMBATANTONLY=1024 + JLOSF_COMBATANTONLY=1024, + JLOSF_NOAUTOAIM=2048, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) @@ -2912,7 +2913,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { // Does the player aim at something that can be shot? - P_BulletSlope(self, &target); + P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0); if (!target) return; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 761664308..a8bcf26b8 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -84,6 +84,7 @@ const int JLOSF_TARGETLOS = 128; const int JLOSF_FLIPFOV = 256; const int JLOSF_ALLYNOJUMP = 512; const int JLOSF_COMBATANTONLY = 1024; +const int JLOSF_NOAUTOAIM = 2048; // Flags for A_ChangeVelocity const int CVF_RELATIVE = 1; From 115b70f6d83debbb968740628666967742edb9fc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:27:12 +0000 Subject: [PATCH 079/387] - Do not wake Oracle spectres that are dead. SVN r4008 (trunk) --- src/g_strife/a_oracle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp index 0eb3f1ac6..efa09b84d 100644 --- a/src/g_strife/a_oracle.cpp +++ b/src/g_strife/a_oracle.cpp @@ -13,7 +13,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) TThinkerIterator it(NAME_AlienSpectre3); AActor *spectre = it.Next(); - if (spectre != NULL) + if (spectre != NULL && spectre->health > 0) { spectre->Sector->SoundTarget = spectre->LastHeard = self->LastHeard; spectre->target = self->target; From ca2d75307c3d89a7061fe8bce26726c7f2892a70 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:35:08 +0000 Subject: [PATCH 080/387] - Do not "wake" Oracle spectres that killed an Oracle. (Because if they killed it, they're obviously already awake. Also, we don't want them to end up targeting themselves.) SVN r4009 (trunk) --- src/g_strife/a_oracle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp index efa09b84d..bdfc52dfa 100644 --- a/src/g_strife/a_oracle.cpp +++ b/src/g_strife/a_oracle.cpp @@ -13,7 +13,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) TThinkerIterator it(NAME_AlienSpectre3); AActor *spectre = it.Next(); - if (spectre != NULL && spectre->health > 0) + if (spectre != NULL && spectre->health > 0 && self->target != spectre) { spectre->Sector->SoundTarget = spectre->LastHeard = self->LastHeard; spectre->target = self->target; From 002aa807c55f6d28bbe36ed09bbc55d4dc6ce3ce Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:44:42 +0000 Subject: [PATCH 081/387] - Fixed: Don't use the player skin in the cast call if the class being shown has been removed from the PlayerClasses array (and therefore does not have a valid default skin). SVN r4010 (trunk) --- src/intermission/intermission.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 5d4ca5c06..4ac79f36e 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -589,18 +589,22 @@ void DIntermissionScreenCast::Drawer () // draw the current frame in the middle of the screen if (caststate != NULL) { - int castsprite; + int castsprite = caststate->sprite; if (!(mDefaults->flags4 & MF4_NOSKIN) && mDefaults->SpawnState != NULL && caststate->sprite == mDefaults->SpawnState->sprite && mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)) && skins != NULL) { - castsprite = skins[players[consoleplayer].userinfo.skin].sprite; - } - else - { - castsprite = caststate->sprite; + // Only use the skin sprite if this class has not been removed from the + // PlayerClasses list. + for (unsigned i = 0; i < PlayerClasses.Size(); ++i) + { + if (PlayerClasses[i].Type == mClass) + { + castsprite = skins[players[consoleplayer].userinfo.skin].sprite; + } + } } sprframe = &SpriteFrames[sprites[castsprite].spriteframes + caststate->GetFrame()]; From 60fb004a789b5f424f370cd2acb71854df7cfaa4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 03:52:58 +0000 Subject: [PATCH 082/387] - Do not double-scale player classes that use non-1.0 default scales. SVN r4011 (trunk) --- src/p_user.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 2a8e76099..d718b084e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1491,14 +1491,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) void P_CheckPlayerSprite(AActor *actor, unsigned &spritenum, fixed_t &scalex, fixed_t &scaley) { player_t *player = actor->player; - fixed_t defscaleY = actor->GetDefault()->scaleY; - fixed_t defscaleX = actor->GetDefault()->scaleX; int crouchspriteno; if (player->userinfo.skin != 0 && !(actor->flags4 & MF4_NOSKIN)) { - defscaleY = skins[player->userinfo.skin].ScaleY; - defscaleX = skins[player->userinfo.skin].ScaleX; + // Convert from default scale to skin scale. + fixed_t defscaleY = actor->GetDefault()->scaleY; + fixed_t defscaleX = actor->GetDefault()->scaleX; + scaley = Scale(scaley, skins[player->userinfo.skin].ScaleY, defscaleY); + scalex = Scale(scalex, skins[player->userinfo.skin].ScaleX, defscaleX); } // Set the crouch sprite? @@ -1523,15 +1524,11 @@ void P_CheckPlayerSprite(AActor *actor, unsigned &spritenum, fixed_t &scalex, fi { spritenum = crouchspriteno; } - else if (player->playerstate != PST_DEAD) + else if (player->playerstate != PST_DEAD && player->crouchfactor < FRACUNIT*3/4) { - if (player->crouchfactor < FRACUNIT*3/4) - defscaleY /= 2; + scaley /= 2; } } - // Scale the sprite by the actor, skin, and crouch values - scalex = FixedMul(scalex, defscaleX); - scaley = FixedMul(scaley, defscaleY); } /* From 549712e719d843a9ca7c2f20360efe3f2674201b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jan 2013 04:39:59 +0000 Subject: [PATCH 083/387] - P_DamageMobj() now returns the amount of damage actually done so that the bleed functions can perform based on the amount of damage actually taken after all modifications are done to it. However, if the damage is canceled away, blood will still spawn for the original damage amount rather than the modified amount. SVN r4012 (trunk) --- src/g_doom/a_archvile.cpp | 4 +- src/g_doom/a_bruiser.cpp | 4 +- src/g_doom/a_cacodemon.cpp | 4 +- src/g_doom/a_demon.cpp | 4 +- src/g_doom/a_doomimp.cpp | 4 +- src/g_doom/a_doomweaps.cpp | 4 +- src/g_doom/a_revenant.cpp | 4 +- src/g_heretic/a_chicken.cpp | 4 +- src/g_heretic/a_dsparil.cpp | 8 +-- src/g_heretic/a_ironlich.cpp | 4 +- src/g_heretic/a_knight.cpp | 4 +- src/g_heretic/a_wizard.cpp | 4 +- src/g_hexen/a_bishop.cpp | 4 +- src/g_hexen/a_dragon.cpp | 8 +-- src/g_hexen/a_serpent.cpp | 4 +- src/g_hexen/a_spike.cpp | 4 +- src/g_raven/a_minotaur.cpp | 16 ++--- src/g_shared/a_artifacts.cpp | 2 +- src/g_strife/a_programmer.cpp | 4 +- src/g_strife/a_stalker.cpp | 4 +- src/p_interaction.cpp | 56 ++++++++-------- src/p_local.h | 2 +- src/p_map.cpp | 102 ++++++++++++++++-------------- src/p_mobj.cpp | 4 +- src/po_man.cpp | 4 +- src/thingdef/thingdef_codeptr.cpp | 18 +++--- 26 files changed, 148 insertions(+), 136 deletions(-) diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 2bd65b7a0..e2fb689c2 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -123,8 +123,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) return; S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM); - P_TraceBleed (dmg, target); - P_DamageMobj (target, self, self, dmg, NAME_None); + int newdam = P_DamageMobj (target, self, self, dmg, NAME_None); + P_TraceBleed (newdam > 0 ? newdam : dmg, target); an = self->angle >> ANGLETOFINESHIFT; fire = self->tracer; diff --git a/src/g_doom/a_bruiser.cpp b/src/g_doom/a_bruiser.cpp index 24c6c48eb..ba1d92bc1 100644 --- a/src/g_doom/a_bruiser.cpp +++ b/src/g_doom/a_bruiser.cpp @@ -10,8 +10,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack) { int damage = (pr_bruisattack()%8+1)*10; S_Sound (self, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } diff --git a/src/g_doom/a_cacodemon.cpp b/src/g_doom/a_cacodemon.cpp index 0eb923890..856360a13 100644 --- a/src/g_doom/a_cacodemon.cpp +++ b/src/g_doom/a_cacodemon.cpp @@ -22,8 +22,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack) { int damage = (pr_headattack()%6+1)*10; S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } diff --git a/src/g_doom/a_demon.cpp b/src/g_doom/a_demon.cpp index c890c32b0..f4a9f461f 100644 --- a/src/g_doom/a_demon.cpp +++ b/src/g_doom/a_demon.cpp @@ -20,7 +20,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SargAttack) if (self->CheckMeleeRange ()) { int damage = ((pr_sargattack()%10)+1)*4; - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } } diff --git a/src/g_doom/a_doomimp.cpp b/src/g_doom/a_doomimp.cpp index 401fa4577..4c607f6e1 100644 --- a/src/g_doom/a_doomimp.cpp +++ b/src/g_doom/a_doomimp.cpp @@ -25,8 +25,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack) { int damage = (pr_troopattack()%8+1)*3; S_Sound (self, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 8cb3739f6..642c319ec 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -584,8 +584,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) damage += (pr_bfgspray() & 7) + 1; thingToHit = linetarget; - P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash)); - P_TraceBleed (damage, thingToHit, self->target); + int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash)); + P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target); } } diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 92a3dc13f..0600a59eb 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -146,7 +146,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelFist) { int damage = ((pr_skelfist()%10)+1)*6; S_Sound (self, CHAN_WEAPON, "skeleton/melee", 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } } diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index a8b8c98d3..082774a3d 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -73,8 +73,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) if (self->CheckMeleeRange()) { int damage = 1 + (pr_chicattack() & 1); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } } diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp index 080deb8d7..e4d86c83a 100644 --- a/src/g_heretic/a_dsparil.cpp +++ b/src/g_heretic/a_dsparil.cpp @@ -70,8 +70,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack) if (self->CheckMeleeRange ()) { int damage = pr_scrc1atk.HitDice (8); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } @@ -203,8 +203,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack) if (self->CheckMeleeRange()) { int damage = pr_s2a.HitDice (20); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } chance = self->health < self->SpawnHealth()/2 ? 96 : 48; diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 8efa08273..8efaa8d82 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -83,8 +83,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) if (self->CheckMeleeRange ()) { int damage = pr_atk.HitDice (6); - P_DamageMobj (target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, target, self); + int newdam = P_DamageMobj (target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, target, self); return; } dist = P_AproxDistance (self->x-target->x, self->y-target->y) diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp index 2fb8a0ef4..18280326a 100644 --- a/src/g_heretic/a_knight.cpp +++ b/src/g_heretic/a_knight.cpp @@ -47,8 +47,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack) if (self->CheckMeleeRange ()) { int damage = pr_knightatk.HitDice (3); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); S_Sound (self, CHAN_BODY, "hknight/melee", 1, ATTN_NORM); return; } diff --git a/src/g_heretic/a_wizard.cpp b/src/g_heretic/a_wizard.cpp index 119a1b1ef..ea5e6559b 100644 --- a/src/g_heretic/a_wizard.cpp +++ b/src/g_heretic/a_wizard.cpp @@ -69,8 +69,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) if (self->CheckMeleeRange()) { int damage = pr_wizatk3.HitDice (4); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } const PClass *fx = PClass::FindClass("WizardFX1"); diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp index f80b91cbd..08faee955 100644 --- a/src/g_hexen/a_bishop.cpp +++ b/src/g_hexen/a_bishop.cpp @@ -32,8 +32,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack) if (self->CheckMeleeRange()) { int damage = pr_atk.HitDice (4); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } self->special1 = (pr_atk() & 3) + 5; diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp index 0c5ea81b5..22c92b4d7 100644 --- a/src/g_hexen/a_dragon.cpp +++ b/src/g_hexen/a_dragon.cpp @@ -87,8 +87,8 @@ static void DragonSeek (AActor *actor, angle_t thresh, angle_t turnMax) if (actor->CheckMeleeRange ()) { int damage = pr_dragonseek.HitDice (10); - P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee); - P_TraceBleed (damage, actor->target, actor); + int newdam = P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, actor->target, actor); S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM); } else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor)) @@ -201,8 +201,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight) if (abs(self->angle-angle) < ANGLE_45/2 && self->CheckMeleeRange()) { int damage = pr_dragonflight.HitDice (8); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); } else if (abs(self->angle-angle) <= ANGLE_1*20) diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp index b44a6175d..cf552897f 100644 --- a/src/g_hexen/a_serpent.cpp +++ b/src/g_hexen/a_serpent.cpp @@ -174,8 +174,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) if (self->CheckMeleeRange ()) { int damage = pr_serpentmeattack.HitDice (5); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM); } if (pr_serpentmeattack() < 96) diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index f7269c40c..9c9f9ab20 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -154,8 +154,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) if (thing == self) continue; // don't clip against self - P_DamageMobj (thing, self, self, 10001, NAME_Crush); - P_TraceBleed (10001, thing); + int newdam = P_DamageMobj (thing, self, self, 10001, NAME_Crush); + P_TraceBleed (newdam > 0 ? newdam : 10001, thing); self->args[1] = 1; // Mark thrust thing as bloody } } diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 36a5537bc..949e38d01 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -149,8 +149,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) if (self->CheckMeleeRange()) { int damage = pr_minotauratk1.HitDice (4); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); if ((player = self->target->player) != NULL && player->mo == self->target) { // Squish the player @@ -281,8 +281,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) { int damage; damage = pr_atk.HitDice (friendly ? 3 : 5); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } z = self->z + 40*FRACUNIT; @@ -327,8 +327,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) int damage; damage = pr_minotauratk3.HitDice (friendly ? 3 : 5); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); if ((player = self->target->player) != NULL && player->mo == self->target) { // Squish the player @@ -396,8 +396,8 @@ void P_MinotaurSlam (AActor *source, AActor *target) target->velx += FixedMul (thrust, finecosine[angle]); target->vely += FixedMul (thrust, finesine[angle]); damage = pr_minotaurslam.HitDice (static_cast(source) ? 4 : 6); - P_DamageMobj (target, NULL, NULL, damage, NAME_Melee); - P_TraceBleed (damage, target, angle, 0); + int newdam = P_DamageMobj (target, NULL, NULL, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, target, angle, 0); if (target->player) { target->reactiontime = 14+(pr_minotaurslam()&7); diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 114c4832d..4f44cfc20 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1503,7 +1503,7 @@ void APowerDamage::EndEffect( ) //=========================================================================== // -// APowerDamage :: AbsorbDamage +// APowerDamage :: ModifyDamage // //=========================================================================== diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp index 0f843c55c..78689468b 100644 --- a/src/g_strife/a_programmer.cpp +++ b/src/g_strife/a_programmer.cpp @@ -87,8 +87,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) S_Sound (self, CHAN_WEAPON, "programmer/clank", 1, ATTN_NORM); damage = ((pr_prog() % 10) + 1) * 6; - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } //============================================================================ diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp index 67cbd3282..258cbef3f 100644 --- a/src/g_strife/a_stalker.cpp +++ b/src/g_strife/a_stalker.cpp @@ -59,8 +59,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) { int damage = (pr_stalker() & 7) * 2 + 2; - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } } } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 3ad2770e9..b98c1d3cf 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -888,7 +888,9 @@ static inline bool MustForcePain(AActor *target, AActor *inflictor) } -void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags) +// Returns the amount of damage actually inflicted upon the target, or -1 if +// the damage was cancelled. +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags) { unsigned ang; player_t *player = NULL; @@ -901,7 +903,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) { // Shouldn't happen - return; + return -1; } // Spectral targets only take damage from spectral projectiles. @@ -909,14 +911,14 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL)) { - return; + return -1; } } if (target->health <= 0) { if (inflictor && mod == NAME_Ice) { - return; + return -1; } else if (target->flags & MF_ICECORPSE) // frozen { @@ -924,7 +926,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage target->flags6 |= MF6_SHATTERING; target->velx = target->vely = target->velz = 0; } - return; + return -1; } if ((target->flags2 & MF2_INVULNERABLE) && damage < TELEFRAG_DAMAGE && !(flags & DMG_FORCED)) { // actor is invulnerable @@ -932,7 +934,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { if (inflictor == NULL || !(inflictor->flags3 & MF3_FOILINVUL)) { - return; + return -1; } } else @@ -940,7 +942,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage // Players are optionally excluded from getting thrust by damage. if (static_cast(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL) { - return; + return -1; } } @@ -968,7 +970,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (target->flags2 & MF2_DORMANT) { // Invulnerable, and won't wake up - return; + return -1; } player = target->player; if (player && damage > 1 && damage < TELEFRAG_DAMAGE) @@ -984,19 +986,19 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (player != NULL) { if (!deathmatch && inflictor->FriendPlayer > 0) - return; + return -1; } else if (target->flags4 & MF4_SPECTRAL) { if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor)) - return; + return -1; } } damage = inflictor->DoSpecialDamage (target, damage, mod); if (damage == -1) { - return; + return -1; } } // Handle active damage modifiers (e.g. PowerDamage) @@ -1010,7 +1012,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { goto dopain; } - return; + return -1; } } // Handle passive damage modifiers (e.g. PowerProtection) @@ -1024,7 +1026,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { goto dopain; } - return; + return -1; } } @@ -1041,7 +1043,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { goto dopain; } - return; + return -1; } } @@ -1049,7 +1051,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage } if (damage == -1) { - return; + return -1; } // Push the target unless the source's weapon's kickback is 0. // (i.e. Gauntlets/Chainsaw) @@ -1133,7 +1135,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage { // Still allow telefragging :-( damage = (int)((float)damage * level.teamdamage); if (damage <= 0) - return; + return damage; } } @@ -1162,7 +1164,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (damage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) || (player->cheats & CF_GODMODE))) { // player is invulnerable, so don't hurt him - return; + return -1; } if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) @@ -1173,12 +1175,12 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (damage <= 0) { // If MF6_FORCEPAIN is set, make the player enter the pain state. - if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && - (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)) - { - goto dopain; - } - return; + if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && + (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)) + { + goto dopain; + } + return damage; } } @@ -1237,7 +1239,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage damage = newdam; if (damage <= 0) { - return; + return damage; } } @@ -1296,7 +1298,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage } } target->Die (source, inflictor, flags); - return; + return damage; } woundstate = target->FindState(NAME_Wound, mod); @@ -1307,7 +1309,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage if (target->health <= woundhealth) { target->SetState (woundstate); - return; + return damage; } } @@ -1401,6 +1403,8 @@ dopain: // killough 11/98: Don't attack a friend, unless hit by that friend. if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target))) target->flags |= MF_JUSTHIT; // fight back! + + return damage; } void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type) diff --git a/src/p_local.h b/src/p_local.h index a045f897b..eb6690726 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -530,7 +530,7 @@ extern FBlockNode** blocklinks; // for thing chains // P_INTER // void P_TouchSpecialThing (AActor *special, AActor *toucher); -void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); +int 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, FName type); bool P_GiveBody (AActor *actor, int num, int max=0); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); diff --git a/src/p_map.cpp b/src/p_map.cpp index 830c7b9d8..289f146bb 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -966,12 +966,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) thing->vely += tm.thing->vely; if ((thing->velx + thing->vely) > 3*FRACUNIT) { + int newdam; damage = (tm.thing->Mass / 100) + 1; - P_DamageMobj (thing, tm.thing, tm.thing, damage, tm.thing->DamageType); - P_TraceBleed (damage, thing, tm.thing); + newdam = P_DamageMobj (thing, tm.thing, tm.thing, damage, tm.thing->DamageType); + P_TraceBleed (newdam > 0 ? newdam : damage, thing, tm.thing); damage = (thing->Mass / 100) + 1; - P_DamageMobj (tm.thing, thing, thing, damage >> 2, tm.thing->DamageType); - P_TraceBleed (damage, tm.thing, thing); + newdam = P_DamageMobj (tm.thing, thing, thing, damage >> 2, tm.thing->DamageType); + P_TraceBleed (newdam > 0 ? newdam : damage, tm.thing, thing); } return false; } @@ -1149,10 +1150,10 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) } damage = tm.thing->GetMissileDamage (3, 2); - P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); + int newdam = P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) { - P_TraceBleed (damage, thing, tm.thing); + P_TraceBleed (newdam > 0 ? newdam : damage, thing, tm.thing); } if (thing->flags2 & MF2_PUSHABLE && !(tm.thing->flags2 & MF2_CANNOTPUSH)) @@ -1180,7 +1181,7 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) damage = tm.thing->GetMissileDamage ((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN)) { - P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); + int newdam = P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); if (damage > 0) { if ((tm.thing->flags5 & MF5_BLOODSPLATTER) && @@ -1194,7 +1195,7 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) } if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) { - P_TraceBleed (damage, thing, tm.thing); + P_TraceBleed (newdam > 0 ? newdam : damage, thing, tm.thing); } } } @@ -3612,13 +3613,42 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, // We must pass the unreplaced puff type here puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING); } + + // Allow puffs to inflict poison damage, so that hitscans can poison, too. + if (puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) + { + P_PoisonMobj(trace.Actor, puff ? puff : t1, t1, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); + } + + // [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. + int newdam = damage; + if (damage || (puffDefaults->flags6 & MF6_FORCEPAIN)) + { + int dmgflags = DMG_INFLICTOR_IS_PUFF | pflag; + // Allow MF5_PIERCEARMOR on a weapon as well. + if (t1->player != NULL && (dmgflags & DMG_PLAYERATTACK) && t1->player->ReadyWeapon != NULL && + t1->player->ReadyWeapon->flags5 & MF5_PIERCEARMOR) + { + dmgflags |= DMG_NO_ARMOR; + } + + if (puff == NULL) + { + // Since the puff is the damage inflictor we need it here + // regardless of whether it is displayed or not. + puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY); + killPuff = true; + } + newdam = P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); + } if (!(puffDefaults->flags3&MF3_BLOODLESSIMPACT)) { if (!bloodsplatter && !axeBlood && !(trace.Actor->flags & MF_NOBLOOD) && !(trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) { - P_SpawnBlood (hitx, hity, hitz, angle - ANG180, damage, trace.Actor); + P_SpawnBlood (hitx, hity, hitz, angle - ANG180, newdam > 0 ? newdam : damage, trace.Actor); } if (damage) @@ -3639,38 +3669,10 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } } // [RH] Stick blood to walls - P_TraceBleed (damage, trace.X, trace.Y, trace.Z, + P_TraceBleed (newdam > 0 ? newdam : damage, trace.X, trace.Y, trace.Z, trace.Actor, srcangle, srcpitch); } } - - // Allow puffs to inflict poison damage, so that hitscans can poison, too. - if (puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) - { - P_PoisonMobj(trace.Actor, puff ? puff : t1, t1, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); - } - - // [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)) - { - int dmgflags = DMG_INFLICTOR_IS_PUFF | pflag; - // Allow MF5_PIERCEARMOR on a weapon as well. - if (t1->player != NULL && (dmgflags & DMG_PLAYERATTACK) && t1->player->ReadyWeapon != NULL && - t1->player->ReadyWeapon->flags5 & MF5_PIERCEARMOR) - { - dmgflags |= DMG_NO_ARMOR; - } - - if (puff == NULL) - { - // Since the puff is the damage inflictor we need it here - // regardless of whether it is displayed or not. - 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, dmgflags); - } if (victim != NULL) { *victim = trace.Actor; @@ -3995,6 +3997,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color { fixed_t x, y, z; bool spawnpuff; + bool bleed = false; int puffflags = PF_HITTHING; x = x1 + FixedMul (RailHits[i].Distance, vx); @@ -4012,8 +4015,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color puffflags |= PF_HITTHINGBLEED; // [XA] Allow for puffs to jump to XDeath state. if(!(puffDefaults->flags3 & MF3_BLOODLESSIMPACT)) { - 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); + bleed = true; } } if (spawnpuff) @@ -4021,7 +4023,12 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) P_PoisonMobj(RailHits[i].HitActor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); - P_DamageMobj (RailHits[i].HitActor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); + int newdam = P_DamageMobj (RailHits[i].HitActor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); + if (bleed) + { + P_SpawnBlood (x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, RailHits[i].HitActor); + P_TraceBleed (newdam > 0 ? newdam : damage, x, y, z, RailHits[i].HitActor, source->angle, pitch); + } } // Spawn a decal or puff at the point where the trace ended. @@ -4551,16 +4558,17 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b double velz; double thrust; int damage = (int)points; + int newdam = damage; if (!(flags & RADF_NODAMAGE)) - P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); + newdam = P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); else if (thing->player == NULL && !(flags & RADF_NOIMPACTDAMAGE)) thing->flags2 |= MF2_BLASTED; if (!(thing->flags & MF_ICECORPSE)) { if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) - P_TraceBleed (damage, thing, bombspot); + P_TraceBleed (newdam > 0 ? newdam : damage, thing, bombspot); if (!(flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) { @@ -4616,8 +4624,8 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); if (damage > 0) { - P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); - P_TraceBleed (damage, thing, bombspot); + int newdam = P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); + P_TraceBleed (newdam > 0 ? newdam : damage, thing, bombspot); } } } @@ -4819,7 +4827,7 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos) if ((cpos->crushchange > 0) && !(level.maptime & 3)) { - P_DamageMobj (thing, NULL, NULL, cpos->crushchange, NAME_Crush); + int newdam = P_DamageMobj (thing, NULL, NULL, cpos->crushchange, NAME_Crush); // spray blood in a random direction if (!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT))) @@ -4829,7 +4837,7 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos) PalEntry bloodcolor = thing->GetBloodColor(); const PClass *bloodcls = thing->GetBloodType(); - P_TraceBleed (cpos->crushchange, thing); + P_TraceBleed (newdam > 0 ? newdam : cpos->crushchange, thing); if (cl_bloodtype <= 1 && bloodcls != NULL) { AActor *mo; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index de97f89ee..cfb909a01 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2806,8 +2806,8 @@ bool AActor::Slam (AActor *thing) if (!(flags2 & MF2_DORMANT)) { int dam = GetMissileDamage (7, 1); - P_DamageMobj (thing, this, this, dam, NAME_Melee); - P_TraceBleed (dam, thing, this); + int newdam = P_DamageMobj (thing, this, this, dam, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : dam, thing, this); // The charging monster may have died by the target's actions here. if (health > 0) { diff --git a/src/po_man.cpp b/src/po_man.cpp index 6e301377e..3355b6ca1 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -907,8 +907,8 @@ void FPolyObj::ThrustMobj (AActor *actor, side_t *side) { if (bHurtOnTouch || !P_CheckMove (actor, actor->x + thrustX, actor->y + thrustY)) { - P_DamageMobj (actor, NULL, NULL, crush, NAME_Crush); - P_TraceBleed (crush, actor); + int newdam = P_DamageMobj (actor, NULL, NULL, crush, NAME_Crush); + P_TraceBleed (newdam > 0 ? newdam : crush, actor); } } if (level.flags2 & LEVEL2_POLYGRIND) actor->Grind(false); // crush corpses that get caught in a polyobject's way diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 36efe7e8f..efba0cb4a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -315,8 +315,8 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, { int damage = pr_camelee.HitDice(MeleeDamage); if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); + P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } else if (domissile && MissileType != NULL) { @@ -1119,8 +1119,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) if (self->CheckMeleeRange ()) { if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, DamageType); + if (bleed) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } else { @@ -1151,8 +1151,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) { if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - P_DamageMobj (self->target, self, self, damage, DamageType); - if (bleed) P_TraceBleed (damage, self->target, self); + int newdam = P_DamageMobj (self->target, self, self, damage, DamageType); + if (bleed) P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); } else if (ti) { @@ -4053,11 +4053,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) damage >>= 2; if (damage) { - P_DamageMobj(self->target, self, self, damage, mod, DMG_THRUSTLESS); + int newdam = P_DamageMobj(self->target, self, self, damage, mod, DMG_THRUSTLESS); if (spawnblood) { - P_SpawnBlood(dx, dy, dz, angle, damage, self->target); - P_TraceBleed(damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0); + P_SpawnBlood(dx, dy, dz, angle, newdam > 0 ? newdam : damage, self->target); + P_TraceBleed(newdam > 0 ? newdam : damage, self->target, R_PointToAngle2(self->x, self->y, dx, dy), 0); } } } From 787c3388715ac37bb217ebfa43f9ae9fabeb5dfc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 02:08:08 +0000 Subject: [PATCH 084/387] - Added MAPINFO flag "SpawnWithWeaponRaised". SVN r4013 (trunk) --- src/g_level.cpp | 2 +- src/g_level.h | 2 +- src/g_mapinfo.cpp | 1 + src/p_local.h | 7 +++++-- src/p_mobj.cpp | 16 +++++++--------- src/p_pspr.cpp | 4 ++-- src/p_saveg.cpp | 2 +- src/p_setup.cpp | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 32acf14cb..ebd19074a 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1128,7 +1128,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], int(pawn->player - players), true); + pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], int(pawn->player - players), SPF_TEMPPLAYER); if (!(changeflags & CHANGELEVEL_KEEPFACING)) { pawn->angle = pawndup->angle; diff --git a/src/g_level.h b/src/g_level.h index 105b07100..53b7cbf59 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -181,7 +181,7 @@ enum ELevelFlags LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1 - /* = 0x00000080, */ + LEVEL2_PRERAISEWEAPON = 0x00000080, // players should spawn with their weapons fully raised (but not when respawning it multiplayer) LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100, LEVEL2_CLIPMIDTEX = 0x00000200, LEVEL2_WRAPMIDTEX = 0x00000400, diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 9df7b39eb..adfd626c3 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1271,6 +1271,7 @@ MapFlagHandlers[] = { "forgetstate", MITYPE_SETFLAG2, LEVEL2_FORGETSTATE, 0 }, { "rememberstate", MITYPE_CLRFLAG2, LEVEL2_FORGETSTATE, 0 }, { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 }, + { "spawnwithweaponraised", MITYPE_SETFLAG2, LEVEL2_PRERAISEWEAPON, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 }, { "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 }, diff --git a/src/p_local.h b/src/p_local.h index eb6690726..f1dd56f19 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -93,7 +93,7 @@ inline int GetSafeBlockY(long long blocky) // // P_PSPR // -void P_SetupPsprites (player_t* curplayer); +void P_SetupPsprites (player_t* curplayer, bool startweaponup); void P_MovePsprites (player_t* curplayer); void P_DropWeapon (player_t* player); @@ -114,7 +114,10 @@ void P_UnPredictPlayer (); #define ONCEILINGZ FIXED_MAX #define FLOATRANDZ (FIXED_MAX-1) -APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, bool tempplayer=false); +#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player +#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised + +APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, int flags=0); void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index cfb909a01..5d05b8c80 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4138,7 +4138,7 @@ EXTERN_CVAR (Bool, chasedemo) extern bool demonew; -APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, bool tempplayer) +APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { player_t *p; APlayerPawn *mobj, *oldactor; @@ -4239,7 +4239,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, bool tempplayer { G_PlayerReborn (playernum); } - else if (oldactor != NULL && oldactor->player == p && !tempplayer) + else if (oldactor != NULL && oldactor->player == p && !(flags & SPF_TEMPPLAYER)) { // Move the voodoo doll's inventory to the new player. mobj->ObtainInventory (oldactor); @@ -4312,11 +4312,9 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, bool tempplayer p->cheats = CF_CHASECAM; // setup gun psprite - if (!tempplayer) - { - // This can also start a script so don't do it for - // the dummy player. - P_SetupPsprites (p); + if (!(flags & SPF_TEMPPLAYER)) + { // This can also start a script so don't do it for the dummy player. + P_SetupPsprites (p, !!(flags & SPF_WEAPONFULLYUP)); } if (deathmatch) @@ -4362,7 +4360,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, bool tempplayer } // [BC] Do script stuff - if (!tempplayer) + if (!(flags & SPF_TEMPPLAYER)) { if (state == PST_ENTER || (state == PST_LIVE && !savegamerestore)) { @@ -4548,7 +4546,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) AllPlayerStarts.Push(start); if (!deathmatch && !(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS)) { - return P_SpawnPlayer(&start, pnum); + return P_SpawnPlayer(&start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); } return NULL; } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index fb3cf68d4..f5a1c45db 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -989,7 +989,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) // //------------------------------------------------------------------------ -void P_SetupPsprites(player_t *player) +void P_SetupPsprites(player_t *player, bool startweaponup) { int i; @@ -999,7 +999,7 @@ void P_SetupPsprites(player_t *player) player->psprites[i].state = NULL; } // Spawn the ready weapon - player->PendingWeapon = player->ReadyWeapon; + player->PendingWeapon = !startweaponup ? player->ReadyWeapon : WP_NOCHANGE; P_BringUpWeapon (player); } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 205e91443..5fa41da99 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -310,7 +310,7 @@ static void SpawnExtraPlayers () if (playeringame[i] && players[i].mo == NULL) { players[i].playerstate = PST_ENTER; - P_SpawnPlayer(&playerstarts[i], i); + P_SpawnPlayer(&playerstarts[i], i, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); } } } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 1edbb181f..ee596a74c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3986,7 +3986,7 @@ void P_SetupLevel (char *lumpname, int position) { players[i].mo = NULL; FPlayerStart *mthing = G_PickPlayerStart(i); - P_SpawnPlayer(mthing, i); + P_SpawnPlayer(mthing, i, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); } } } From 460195424807f78a704483efba0e59149addd38c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 02:18:19 +0000 Subject: [PATCH 085/387] - Added CHANGELEVEL_PRERAISEWEAPON flag for use with ACS's ChangeLevel. SVN r4014 (trunk) --- src/g_level.cpp | 4 ++++ src/g_level.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/g_level.cpp b/src/g_level.cpp index ebd19074a..24c43defd 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -882,6 +882,10 @@ void G_DoLoadLevel (int position, bool autosave) { level.flags2 &= ~LEVEL2_NOMONSTERS; } + if (changeflags & CHANGELEVEL_PRERAISEWEAPON) + { + level.flags2 |= LEVEL2_PRERAISEWEAPON; + } level.maptime = 0; P_SetupLevel (level.mapname, position); diff --git a/src/g_level.h b/src/g_level.h index 53b7cbf59..cdac4b862 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -500,6 +500,7 @@ enum CHANGELEVEL_CHANGESKILL = 8, CHANGELEVEL_NOINTERMISSION = 16, CHANGELEVEL_RESETHEALTH = 32, + CHANGELEVEL_PRERAISEWEAPON = 64, }; void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1); From 814cb4d13553530f1a3c41d39abc40c988d5b42a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 03:05:44 +0000 Subject: [PATCH 086/387] - Move NULL player check earlier in P_PoisonDamage, before player is accessed. SVN r4016 (trunk) --- src/p_interaction.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b98c1d3cf..66bdbe2a2 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1556,6 +1556,10 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, AActor *target; AActor *inflictor; + if (player == NULL) + { + return; + } target = player->mo; inflictor = source; if (target->health <= 0) @@ -1567,11 +1571,8 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, { // target is invulnerable return; } - if (player) - { - // Take half damage in trainer mode - damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); - } + // Take half damage in trainer mode + damage = FixedMul(damage, G_SkillProperty(SKILLP_DamageFactor)); // Handle passive damage modifiers (e.g. PowerProtection) if (target->Inventory != NULL) { From 6b67cd560a617803f173fc60b3ea5cc2045cebcd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 03:07:18 +0000 Subject: [PATCH 087/387] - Add NULL decal check to FDecalLib::ParseGenerator(). SVN r4017 (trunk) --- src/decallib.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/decallib.cpp b/src/decallib.cpp index 56705c903..c8fe6c593 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -631,7 +631,10 @@ void FDecalLib::ParseGenerator (FScanner &sc) } actor->DecalGenerator = decal; - decal->Users.Push (type); + if (decal != NULL) + { + decal->Users.Push (type); + } } void FDecalLib::ParseFader (FScanner &sc) From 424fcb4cba460ddc58a74ec9784a86f1813f066e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 03:08:45 +0000 Subject: [PATCH 088/387] - Initialize sprframe to NULL in FListMenuItemPlayerDisplay::Drawer(). SVN r4018 (trunk) --- src/menu/playerdisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index c0f353675..b3795b60b 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -563,7 +563,7 @@ void FListMenuItemPlayerDisplay::Drawer(bool selected) V_DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1); - spriteframe_t *sprframe; + spriteframe_t *sprframe = NULL; fixed_t scaleX, scaleY; if (mPlayerState != NULL) From 22e52776e336141e23a32d64ad9ab80bb4fc8308 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 3 Jan 2013 03:12:07 +0000 Subject: [PATCH 089/387] - In UpdateJoystickConfigMenu(), do not access joy before checking if it's NULL. SVN r4019 (trunk) --- src/menu/joystickmenu.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index 19f87e158..6be728865 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -280,15 +280,16 @@ FOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy) delete opt->mItems[i]; opt->mItems.Clear(); } - opt->mTitle.Format("Configure %s", joy->GetName().GetChars()); - if (joy == NULL) { + opt->mTitle = "Configure Controller"; it = new FOptionMenuItemStaticText("Invalid controller specified for menu", false); opt->mItems.Push(it); } else { + opt->mTitle.Format("Configure %s", joy->GetName().GetChars()); + SELECTED_JOYSTICK = joy; it = new FOptionMenuSliderJoySensitivity("Overall sensitivity", 0, 2, 0.1, 3); From 0d47c6cbc868a18f5acb1d4beb15405d75f53342 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jan 2013 04:06:19 +0000 Subject: [PATCH 090/387] - Added bright flags to the scripted marines' BFG and railgun attacks. SVN r4020 (trunk) --- wadsrc/static/actors/doom/scriptedmarine.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/actors/doom/scriptedmarine.txt b/wadsrc/static/actors/doom/scriptedmarine.txt index 820499557..f855fcc52 100644 --- a/wadsrc/static/actors/doom/scriptedmarine.txt +++ b/wadsrc/static/actors/doom/scriptedmarine.txt @@ -129,12 +129,12 @@ ACTOR ScriptedMarine 9100 native Goto See Missile.Railgun: PLAY E 4 A_M_CheckAttack - PLAY F 6 A_M_FireRailgun + PLAY F 6 BRIGHT A_M_FireRailgun Goto See Missile.BFG: PLAY E 5 A_M_BFGSound PLAY EEEEE 5 A_FaceTarget - PLAY F 6 A_M_FireBFG + PLAY F 6 BRIGHT A_M_FireBFG PLAY A 4 A_FaceTarget PLAY A 0 A_M_Refire Loop From 7fb0d37d99d90792f3e106db6ac4ffead2dfc914 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jan 2013 04:15:28 +0000 Subject: [PATCH 091/387] - Added a flag to A_M_Refire to ignore the actor's missile state, so the rocket marine will not continue to punch air if it starts attacking while its target is in melee range and then moves out of it. SVN r4021 (trunk) --- src/g_doom/a_scriptedmarine.cpp | 7 +++++-- wadsrc/static/actors/doom/scriptedmarine.txt | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp index 3d994f502..be39b545b 100644 --- a/src/g_doom/a_scriptedmarine.cpp +++ b/src/g_doom/a_scriptedmarine.cpp @@ -153,8 +153,11 @@ void AScriptedMarine::Tick () // //============================================================================ -DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) { + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(ignoremissile, 0); + if (self->target == NULL || self->target->health <= 0) { if (self->MissileState && pr_m_refire() < 160) @@ -167,7 +170,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) self->SetState (self->state + 1); return; } - if ((self->MissileState == NULL && !self->CheckMeleeRange ()) || + if (((ignoremissile || self->MissileState == NULL) && !self->CheckMeleeRange ()) || !P_CheckSight (self, self->target) || pr_m_refire() < 4) // Small chance of stopping even when target not dead { diff --git a/wadsrc/static/actors/doom/scriptedmarine.txt b/wadsrc/static/actors/doom/scriptedmarine.txt index f855fcc52..7602405c7 100644 --- a/wadsrc/static/actors/doom/scriptedmarine.txt +++ b/wadsrc/static/actors/doom/scriptedmarine.txt @@ -18,7 +18,7 @@ ACTOR ScriptedMarine 9100 native DeathSound "*death" PainSound "*pain50" - action native A_M_Refire (); + action native A_M_Refire (bool ignoremissile=false); action native A_M_CheckAttack (); action native A_MarineChase (); action native A_MarineLook (); @@ -57,7 +57,7 @@ ACTOR ScriptedMarine 9100 native PLAY E 4 A_FaceTarget PLAY F 4 A_M_Punch(1) PLAY A 9 - PLAY A 0 A_M_Refire + PLAY A 0 A_M_Refire(1) Loop PLAY A 5 A_FaceTarget Goto See @@ -65,7 +65,7 @@ ACTOR ScriptedMarine 9100 native PLAY E 4 A_FaceTarget PLAY F 4 A_M_Punch(10) PLAY A 9 - PLAY A 0 A_M_Refire + PLAY A 0 A_M_Refire(1) Loop PLAY A 5 A_FaceTarget Goto See From 7f74d2863866d8471154ee31aad5dfa163f5d797 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jan 2013 04:20:37 +0000 Subject: [PATCH 092/387] - Do not use the muzzle flash player sprites for the scripted marines' melee attacks. SVN r4022 (trunk) --- wadsrc/static/actors/doom/scriptedmarine.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wadsrc/static/actors/doom/scriptedmarine.txt b/wadsrc/static/actors/doom/scriptedmarine.txt index 7602405c7..e241ae195 100644 --- a/wadsrc/static/actors/doom/scriptedmarine.txt +++ b/wadsrc/static/actors/doom/scriptedmarine.txt @@ -55,7 +55,7 @@ ACTOR ScriptedMarine 9100 native Melee.Fist: PLAY E 4 A_FaceTarget - PLAY F 4 A_M_Punch(1) + PLAY E 4 A_M_Punch(1) PLAY A 9 PLAY A 0 A_M_Refire(1) Loop @@ -63,7 +63,7 @@ ACTOR ScriptedMarine 9100 native Goto See Melee.Berserk: PLAY E 4 A_FaceTarget - PLAY F 4 A_M_Punch(10) + PLAY E 4 A_M_Punch(10) PLAY A 9 PLAY A 0 A_M_Refire(1) Loop @@ -71,8 +71,8 @@ ACTOR ScriptedMarine 9100 native Goto See Melee.Chainsaw: PLAY E 4 A_MarineNoise - PLAY F 4 BRIGHT A_M_Saw - PLAY F 0 A_M_SawRefire + PLAY E 4 A_M_Saw + PLAY E 0 A_M_SawRefire goto Melee.Chainsaw+1 PLAY A 0 Goto See From 5cbdc3382d63781d849992926fd6b47c5b0bee28 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Jan 2013 04:32:27 +0000 Subject: [PATCH 093/387] - Slow down the scripted marines' rocket attack and speed up the plasma attack to better reflect the speeds of the equivalent player weapons. SVN r4023 (trunk) --- wadsrc/static/actors/doom/scriptedmarine.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/scriptedmarine.txt b/wadsrc/static/actors/doom/scriptedmarine.txt index e241ae195..fecd0ac0d 100644 --- a/wadsrc/static/actors/doom/scriptedmarine.txt +++ b/wadsrc/static/actors/doom/scriptedmarine.txt @@ -116,15 +116,17 @@ ACTOR ScriptedMarine 9100 native Missile.Rocket: PLAY E 8 PLAY F 6 BRIGHT A_M_FireMissile + PLAY E 6 PLAY A 0 A_M_Refire Loop PLAY A 0 Goto See Missile.Plasma: PLAY E 2 A_FaceTarget + PLAY E 0 A_FaceTarget PLAY F 3 BRIGHT A_M_FirePlasma PLAY A 0 A_M_Refire - Loop + Goto Missile.Plasma+1 PLAY A 0 Goto See Missile.Railgun: From 3111b6e7b09209b144747346d0ba21e8a400b05f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 11 Jan 2013 02:53:11 +0000 Subject: [PATCH 094/387] - Do not clear the CF_WEAPONSWITCHOK flag each tic, so that the last setting from A_WeaponReady will carry over until the next A_WeaponReady. Changed P_CheckWeaponSwitch() to clear any pending weapon requests while weapon switching is disabled. SVN r4024 (trunk) --- src/p_pspr.cpp | 54 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index f5a1c45db..5f0943ca0 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -95,7 +95,7 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK); + player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK); } psp = &player->psprites[position]; @@ -565,12 +565,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) ACTION_PARAM_START(1); ACTION_PARAM_INT(paramflags, 0); - if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); - if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, - (!(paramflags & WRF_NoPrimary)), (!(paramflags & WRF_NoSecondary))); - if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); - if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); + if (!(paramflags & WRF_NoSwitch)) + { + DoReadyWeaponToSwitch(self); + } + else if (self->player != NULL) + { + self->player->cheats &= ~CF_WEAPONSWITCHOK; + } + if ((paramflags & WRF_NoFire) != WRF_NoFire) + { + DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); + } + if (!(paramflags & WRF_NoBob)) + { + DoReadyWeaponToBob(self); + } + if ((paramflags & WRF_AllowReload)) + { + DoReadyWeaponToReload(self); + } + if ((paramflags & WRF_AllowZoom)) + { + DoReadyWeaponToZoom(self); + } } //--------------------------------------------------------------------------- @@ -631,15 +649,20 @@ void P_CheckWeaponSwitch (player_t *player) if (!player || !(weapon = player->ReadyWeapon)) return; - // Put the weapon away if the player has a pending weapon or has died. - if ((player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) || player->health <= 0) - { + if (player->health <= 0) + { // Dead, so put the weapon away. + P_SetPsprite(player, ps_weapon, weapon->GetDownState()); + } + else if (!(player->cheats & CF_WEAPONSWITCHOK)) + { // Weapon changing has been disabled. + player->PendingWeapon = WP_NOCHANGE; + } + else if (player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) + { // Put the weapon away if the player has a pending weapon P_SetPsprite (player, ps_weapon, weapon->GetDownState()); - return; } else if (player->morphTics != 0) - { - // morphed classes cannot change weapons so don't even try again. + { // Morphed classes cannot change weapons, so don't even try again. player->PendingWeapon = WP_NOCHANGE; } } @@ -1052,10 +1075,7 @@ void P_MovePsprites (player_t *player) } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - if (player->cheats & CF_WEAPONSWITCHOK) - { - P_CheckWeaponSwitch (player); - } + P_CheckWeaponSwitch (player); if (player->cheats & (CF_WEAPONREADY | CF_WEAPONREADYALT)) { P_CheckWeaponFire (player); From 6a3b07c4415751bd35438266a20506e27d3ad728 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 11 Jan 2013 03:21:46 +0000 Subject: [PATCH 095/387] - Removed the BuildString() override that took a char** argv, because it was used nowhere. - Fixed: BuildString() failed to properly generate command lines for arguments with embedded " characters. SVN r4025 (trunk) --- src/c_dispatch.cpp | 46 ++++++++++++++++++---------------------------- src/c_dispatch.h | 1 - 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 83c6ae37d..7b701bd53 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -1019,32 +1019,7 @@ FConsoleAlias::~FConsoleAlias () m_Command[1] = m_Command[0] = FString(); } -FString BuildString (int argc, char **argv) -{ - if (argc == 1) - { - return *argv; - } - else - { - FString buf; - int arg; - - for (arg = 0; arg < argc; arg++) - { - if (strchr (argv[arg], ' ')) - { - buf.AppendFormat ("\"%s\" ", argv[arg]); - } - else - { - buf.AppendFormat ("%s ", argv[arg]); - } - } - return buf; - } -} - +// Given an argument vector, reconstitute the command line it could have been produced from. FString BuildString (int argc, FString *argv) { if (argc == 1) @@ -1058,8 +1033,23 @@ FString BuildString (int argc, FString *argv) for (arg = 0; arg < argc; arg++) { - if (strchr (argv[arg], ' ')) - { + if (strchr(argv[arg], '"')) + { // If it contains one or more quotes, we need to escape them. + buf << '"'; + long substr_start = 0, quotepos; + while ((quotepos = argv[arg].IndexOf('"', substr_start)) >= 0) + { + if (substr_start < quotepos) + { + buf << argv[arg].Mid(substr_start, quotepos - substr_start); + } + buf << "\\\""; + substr_start = quotepos + 1; + } + buf << argv[arg].Mid(substr_start) << "\" "; + } + else if (strchr(argv[arg], ' ')) + { // If it contains a space, it needs to be quoted. buf << '"' << argv[arg] << "\" "; } else diff --git a/src/c_dispatch.h b/src/c_dispatch.h index 5aa3f9870..12ea559de 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -61,7 +61,6 @@ void C_SetAlias (const char *name, const char *cmd); void C_ClearAliases (); // build a single string out of multiple strings -FString BuildString (int argc, char **argv); FString BuildString (int argc, FString *argv); // Class that can parse command lines From c7a008f99d0e3b29f8406b880ac43ff5ae2795fc Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 17 Jan 2013 16:28:02 +0000 Subject: [PATCH 096/387] - Updated USDF spec to version 2.1 SVN r4026 (trunk) --- specs/usdf.txt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/specs/usdf.txt b/specs/usdf.txt index fc955f02d..52b418d46 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Strife Dialog Format Specification v2.0 - 08/20/10 +Universal Strife Dialog Format Specification v2.1 - 01/06/13 Written by Braden "Blzut3" Obrzut - admin@maniacsvault.net @@ -11,7 +11,7 @@ Graf Zahl Quasar et al. - Copyright (c) 2010 Braden Obrzut. + Copyright (c) 2013 Braden Obrzut. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; @@ -19,6 +19,14 @@ et al. =============================================================================== +======================================= +Changes in v2.1 +======================================= + +* Pages are specified as starting as being indexed from 1 instead of 0. While + this technically renders the spec incompatible, all known implementations + used this convention as it was inline with the binary format. + ======================================= I. Grammar / Syntax ======================================= @@ -77,7 +85,7 @@ conversation // Starts a dialog. actor = ; // mobj for this conversation's actor. If previously // used, this will override the previous conversation. - page // Starts a new page. Pages are automatically numbered starting at 0. + page // Starts a new page. Pages are automatically numbered starting at 1. { name = ; // Name that goes in the upper left hand corner panel = ; // Name of lump to render as the background. From de65ae809fc10fcbbd9b932ec337288a900a1678 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 17 Jan 2013 19:25:22 +0000 Subject: [PATCH 097/387] - Fixed: BobStyle was assigned as if they were flags. SVN r4027 (trunk) --- src/thingdef/thingdef_properties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index f5dc0d91f..5fc607ca4 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1772,7 +1772,7 @@ DEFINE_CLASS_PROPERTY(yadjust, F, Weapon) DEFINE_CLASS_PROPERTY(bobstyle, S, Weapon) { static const char *names[] = { "Normal", "Inverse", "Alpha", "InverseAlpha", "Smooth", "InverseSmooth", NULL }; - static const int flags[] = { AWeapon::BobNormal, + static const int styles[] = { AWeapon::BobNormal, AWeapon::BobInverse, AWeapon::BobAlpha, AWeapon::BobInverseAlpha, AWeapon::BobSmooth, AWeapon::BobInverseSmooth, }; PROP_STRING_PARM(id, 0); @@ -1782,7 +1782,7 @@ DEFINE_CLASS_PROPERTY(bobstyle, S, Weapon) I_Error("Unknown bobstyle %s", id); match = 0; } - defaults->BobStyle |= flags[match]; + defaults->BobStyle = styles[match]; } //========================================================================== From 3e1aa40461fac188e5525d6fc52d32a6dcc176a1 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 17 Jan 2013 19:42:52 +0000 Subject: [PATCH 098/387] - Fixed: If AInventory::SpecialDropAction returns true the item should be destroyed. - Fixed: Building with SSE disabled triggered an error. SVN r4028 (trunk) --- src/nodebuild.cpp | 2 ++ src/p_enemy.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index a4b568683..c13527d87 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -1116,12 +1116,14 @@ int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVe #endif // printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset); +#ifndef DISABLE_SSE if (CPU.bSSE2) { func = ClassifyLineSSE2; diff = int((char *)ClassifyLineSSE2 - (char *)calleroffset); } else +#endif { func = ClassifyLine2; diff = int((char *)ClassifyLine2 - (char *)calleroffset); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 46104ad18..6cf7d7be6 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3069,6 +3069,8 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int dropamount, int ModifyDropAmount(inv, dropamount); if (inv->SpecialDropAction (source)) { + // The special action indicates that the item should not spawn + inv->Destroy(); return NULL; } return inv; From 76b5757dabb1e0b99304c830c31e79973f9f8244 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 18 Jan 2013 18:19:05 +0000 Subject: [PATCH 099/387] - Fixed: 0 duration A_Lower loops could cause an infinite loop since A_Lower checked if the player was dead in two different ways and returned before the second one. SVN r4029 (trunk) --- src/p_pspr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 5f0943ca0..8d901ec2e 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -818,10 +818,8 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon psp->sy = WEAPONBOTTOM; - return; - } - if (player->health <= 0) - { // Player is dead, so keep the weapon off screen + + // Player is dead, so keep the weapon off screen P_SetPsprite (player, ps_weapon, NULL); return; } From e86f27a7a6542c43a1853b6b27b9db343e92d3df Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 21 Jan 2013 21:02:14 +0000 Subject: [PATCH 100/387] - Fixed: Popups weren't shown on the alt hud. SVN r4030 (trunk) --- src/d_main.cpp | 5 ++-- src/g_shared/sbar.h | 4 ++- src/g_shared/sbarinfo.cpp | 56 +++++++++++++++++++----------------- src/g_strife/strife_sbar.cpp | 29 ++++++++++--------- 4 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index afda957af..2670dcf4e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -803,9 +803,10 @@ void D_Display () if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10) { - StatusBar->DrawBottomStuff (HUD_None); + StatusBar->DrawBottomStuff (HUD_AltHud); if (DrawFSHUD || automapactive) DrawHUD(); - StatusBar->DrawTopStuff (HUD_None); + StatusBar->Draw (HUD_AltHud); + StatusBar->DrawTopStuff (HUD_AltHud); } else if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10) diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index d45f88cdf..fcba22fa9 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -48,7 +48,9 @@ enum EHudState { HUD_StatusBar, HUD_Fullscreen, - HUD_None + HUD_None, + + HUD_AltHud // Used for passing through popups to the alt hud }; class AWeapon; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 7e0667062..6530c6adf 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1040,37 +1040,41 @@ public: //prepare ammo counts GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2); armor = CPlayer->mo->FindInventory(); - if(hud != lastHud) - { - script->huds[hud]->Tick(NULL, this, true); - // Restore scaling if need be. - if(scalingWasForced) + if(state != HUD_AltHud) + { + if(hud != lastHud) { - scalingWasForced = false; - SetScaled(false); - setsizeneeded = true; + script->huds[hud]->Tick(NULL, this, true); + + // Restore scaling if need be. + if(scalingWasForced) + { + scalingWasForced = false; + SetScaled(false); + setsizeneeded = true; + } } - } - 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; - - // Handle inventory bar drawing - 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]; - if(inventoryBar != lastInventoryBar) - inventoryBar->Tick(NULL, this, true); - - // No overlay? Lets cancel it. - if(inventoryBar->NumCommands() == 0) - CPlayer->inventorytics = 0; + 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 - inventoryBar->DrawAux(NULL, this, 0, 0, FRACUNIT); + script->huds[hud]->Draw(NULL, this, 0, 0, FRACUNIT); + lastHud = hud; + + // Handle inventory bar drawing + 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]; + if(inventoryBar != lastInventoryBar) + inventoryBar->Tick(NULL, this, true); + + // No overlay? Lets cancel it. + if(inventoryBar->NumCommands() == 0) + CPlayer->inventorytics = 0; + else + inventoryBar->DrawAux(NULL, this, 0, 0, FRACUNIT); + } } // Handle popups diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 4792065f4..0a986495c 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -222,12 +222,7 @@ public: { DBaseStatusBar::Draw (state); - if (state == HUD_Fullscreen) - { - SB_state = screen->GetPageCount (); - DrawFullScreenStuff (); - } - else if (state == HUD_StatusBar) + if (state == HUD_StatusBar) { if (SB_state != 0) { @@ -235,6 +230,20 @@ public: } DrawMainBar (); } + else + { + if (state == HUD_Fullscreen) + { + SB_state = screen->GetPageCount (); + DrawFullScreenStuff (); + } + + // Draw pop screen (log, keys, and status) + if (CurrentPop != POP_None && PopHeight < 0) + { + DrawPopScreen (screen->GetHeight()); + } + } } void ShowPop (int popnum) @@ -279,7 +288,7 @@ public: bool MustDrawLog(EHudState state) { // Tell the base class to draw the log if the pop screen won't be displayed. - return (state == HUD_None); + return false; } private: @@ -554,12 +563,6 @@ private: } } } - - // Draw pop screen (log, keys, and status) - if (CurrentPop != POP_None && PopHeight < 0) - { - DrawPopScreen (screen->GetHeight()); - } } void DrawPopScreen (int bottom) From dcb1a3c8bd4eb6ffdbeccb89dc0f24617868224a Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 21 Jan 2013 22:30:30 +0000 Subject: [PATCH 101/387] - GCC warning cleanup SVN r4031 (trunk) --- src/compatibility.cpp | 2 +- src/d_player.h | 2 +- src/doomdef.h | 2 +- src/oplsynth/OPL3.cpp | 1 + src/p_mobj.cpp | 14 +++++++------- src/p_user.cpp | 2 +- src/r_things.cpp | 4 ++-- src/thingdef/thingdef.h | 4 ++-- src/thingdef/thingdef_data.cpp | 2 +- src/w_wad.cpp | 2 +- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ddbe8b3e8..25bf0f5d3 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -59,7 +59,7 @@ struct FCompatOption { const char *Name; - int CompatFlags; + DWORD CompatFlags; int WhichSlot; }; diff --git a/src/d_player.h b/src/d_player.h index bb6e87e7b..d1f564470 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -427,7 +427,7 @@ extern player_t players[MAXPLAYERS]; FArchive &operator<< (FArchive &arc, player_t *&p); -void P_CheckPlayerSprite(AActor *mo, unsigned &spritenum, fixed_t &scalex, fixed_t &scaley); +void P_CheckPlayerSprite(AActor *mo, int &spritenum, fixed_t &scalex, fixed_t &scaley); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/doomdef.h b/src/doomdef.h index 114f8c701..f7e6c959e 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -333,7 +333,7 @@ enum COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code. COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way - COMPATF_MASKEDMIDTEX = 1 << 31, // Ignore compositing when drawing masked midtextures + COMPATF_MASKEDMIDTEX = 1u << 31, // Ignore compositing when drawing masked midtextures COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW. COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom. diff --git a/src/oplsynth/OPL3.cpp b/src/oplsynth/OPL3.cpp index 80caffcdf..c4806a694 100644 --- a/src/oplsynth/OPL3.cpp +++ b/src/oplsynth/OPL3.cpp @@ -89,6 +89,7 @@ public: double leftPan, rightPan; Channel (int baseAddress, double startvol); + virtual ~Channel() {} void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); void update_FNUML8(class OPL3 *OPL3); void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5d05b8c80..35d3c4718 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2618,7 +2618,7 @@ AActor *AActor::TIDHash[128]; void AActor::ClearTIDHashes () { - memset(TIDHash, NULL, sizeof(TIDHash)); + memset(TIDHash, 0, sizeof(TIDHash)); } // @@ -6083,22 +6083,22 @@ void PrintMiscActorInfo(AActor *query) "OptFuzzy", "Stencil", "Translucent", "Add", "Shaded", "TranslucentStencil"}; Printf("%s @ %p has the following flags:\n\tflags: %x", query->GetTag(), query, query->flags); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags & 1<flags2); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags2 & 1<flags3); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags3 & 1<flags4); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags4 & 1<flags5); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags5 & 1<flags6); - for (flagi = 0; flagi < 31; flagi++) + for (flagi = 0; flagi <= 31; flagi++) if (query->flags6 & 1<BounceFlags, FIXED2FLOAT(query->bouncefactor), diff --git a/src/p_user.cpp b/src/p_user.cpp index d718b084e..0060641db 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1488,7 +1488,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) // //=========================================================================== -void P_CheckPlayerSprite(AActor *actor, unsigned &spritenum, fixed_t &scalex, fixed_t &scaley) +void P_CheckPlayerSprite(AActor *actor, int &spritenum, fixed_t &scalex, fixed_t &scaley) { player_t *player = actor->player; int crouchspriteno; diff --git a/src/r_things.cpp b/src/r_things.cpp index 82edfed78..dae30ae1c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -523,7 +523,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor tex = NULL; voxel = NULL; - unsigned spritenum = thing->sprite; + int spritenum = thing->sprite; fixed_t spritescaleX = thing->scaleX; fixed_t spritescaleY = thing->scaleY; if (thing->player != NULL) @@ -565,7 +565,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor { // decide which texture to use for the sprite #ifdef RANGECHECK - if (spritenum >= (unsigned)sprites.Size ()) + if (spritenum >= (signed)sprites.Size () || spritenum < 0) { DPrintf ("R_ProjectSprite: invalid sprite number %u\n", spritenum); return; diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index e8d0f0a55..d1519a260 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -19,7 +19,7 @@ class FScanner; struct FFlagDef { - int flagbit; + unsigned int flagbit; const char *name; int structoffset; }; @@ -27,7 +27,7 @@ struct FFlagDef FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); bool CheckDeprecatedFlags(AActor *actor, FActorInfo *info, int index); -const char *GetFlagName(int flagnum, int flagoffset); +const char *GetFlagName(unsigned int flagnum, int flagoffset); #define FLAG_NAME(flagnum, flagvar) GetFlagName(flagnum, myoffsetof(AActor, flagvar)) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index bc75c2105..16028d249 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -428,7 +428,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) // //========================================================================== -const char *GetFlagName(int flagnum, int flagoffset) +const char *GetFlagName(unsigned int flagnum, int flagoffset) { for(unsigned i = 0; i < countof(ActorFlags); i++) { diff --git a/src/w_wad.cpp b/src/w_wad.cpp index b29d02072..11a9b4213 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -839,7 +839,7 @@ void FWadCollection::RenameNerve () { continue; } - if (fr->GetLength() != nervesize) + if (fr->GetLength() != (long)nervesize) { // Skip MD5 computation when there is a // cheaper way to know this is not the file From 7f81d881f8a32b4840ae3a9b07fde17f95679890 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 23 Jan 2013 01:47:06 +0000 Subject: [PATCH 102/387] - Fixed: DBaseStatusBar::Draw shouldn't run for the AltHud. SVN r4032 (trunk) --- src/g_shared/shared_sbar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 5c0ba7ae1..eb739e6c2 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1227,6 +1227,10 @@ void DBaseStatusBar::DrawMessages (int layer, int bottom) void DBaseStatusBar::Draw (EHudState state) { + // HUD_AltHud state is for popups only + if (state == HUD_AltHud) + return; + char line[64+10]; if ((SB_state != 0 || BorderNeedRefresh) && state == HUD_StatusBar) From 5f4bcaac3d1edd695d1f03c46d8d0318c09728d8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 03:38:13 +0000 Subject: [PATCH 103/387] - Added A_UnSetInvulnerable() to the FireDemon (aka Afrit)'s Pain state, in case it gets pained before entering its Chase state. SVN r4033 (trunk) --- wadsrc/static/actors/hexen/firedemon.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/hexen/firedemon.txt b/wadsrc/static/actors/hexen/firedemon.txt index cb29cdb07..4873e2609 100644 --- a/wadsrc/static/actors/hexen/firedemon.txt +++ b/wadsrc/static/actors/hexen/firedemon.txt @@ -46,6 +46,7 @@ ACTOR FireDemon 10060 FDMN ABC 5 Bright A_FiredChase Loop Pain: + FDMN D 0 Bright A_UnSetInvulnerable FDMN D 6 Bright A_Pain Goto Chase Missile: From 8b6b55ce40db4700eaf272abc0b1dcaa8387b228 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 03:46:12 +0000 Subject: [PATCH 104/387] - P_DaggerAlert() now puts the emitter into its Pain.Dagger state if it has one, but will still use the regular Pain state if not. SVN r4034 (trunk) --- src/g_strife/a_strifeweapons.cpp | 2 +- src/namedef.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 8fa71304b..5ac40b82e 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -53,7 +53,7 @@ void P_DaggerAlert (AActor *target, AActor *emitter) emitter->flags4 |= MF4_INCOMBAT; emitter->target = target; - FState * painstate = emitter->FindState(NAME_Pain); + FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger); if (painstate != NULL) { emitter->SetState (painstate); diff --git a/src/namedef.h b/src/namedef.h index 18fdc0adb..f3ac248bf 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -221,6 +221,7 @@ xx(Rocket) xx(Plasma) xx(BFG) //xx(Railgun) +xx(Dagger) // Damage types //xx(Fire) already defined above From 7291a5633501e5f476fd6435e4b2057259b788e2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 03:54:14 +0000 Subject: [PATCH 105/387] - Shorten text of the longest lines in the gameplay options menu. SVN r4035 (trunk) --- wadsrc/static/menudef.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 55332c595..dffce3d55 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1140,8 +1140,8 @@ OptionMenu GameplayOptions Option "Allow spying", "sv_disallowspying", "NoYes" Option "Chasecam cheat", "sv_chasecam", "YesNo" Option "Check ammo for weapon switch", "sv_dontcheckammo", "NoYes" - Option "Killing Romero kills all his spawns", "sv_killbossmonst", "YesNo" - Option "Count monsters in end level sectors", "sv_nocountendmonst", "NoYes" + Option "Icon's death kills its spawns", "sv_killbossmonst", "YesNo" + Option "End sector counts for kill %", "sv_nocountendmonst", "NoYes" StaticText " " StaticText "Deathmatch Settings",1 From 11862ac06ba673e52f8306596fd661042355d5c9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 04:04:21 +0000 Subject: [PATCH 106/387] - Sync A_LookEx with A_Look, with regards to COMPATF_SOUNDTARGET. SVN r4036 (trunk) --- src/p_enemy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 6cf7d7be6..0961e8671 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1868,7 +1868,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) { if (!(flags & LOF_NOSOUNDCHECK)) { - targ = (self->flags & MF_NOSECTOR)? self->Sector->SoundTarget : self->LastHeard; + targ = (i_compatflags & COMPATF_SOUNDTARGET || self->flags & MF_NOSECTOR)? + self->Sector->SoundTarget : self->LastHeard; if (targ != NULL) { // [RH] If the soundtarget is dead, don't chase it From 10e185a6e329b70d51ce9ac5bef940cfc4c36d01 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 04:11:19 +0000 Subject: [PATCH 107/387] - Retain the Scroll_Texture_(Left|Right|Up|Down) specials on lines for the sake of compat_useblocking. This is not going to be extended to all specials that spawn a thinker at load time, because some of them can be placed on a line later using SetLineSpecial and used directly. SVN r4037 (trunk) --- src/p_spec.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e27e49df0..3eb6c422a 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1837,24 +1837,28 @@ static void P_SpawnScrollers(void) break; case Scroll_Texture_Left: + l->special = special; // Restore the special, for compat_useblocking's benefit. s = int(lines[i].sidedef[0] - sides); new DScroller (DScroller::sc_side, l->args[0] * (FRACUNIT/64), 0, -1, s, accel, SCROLLTYPE(l->args[1])); break; case Scroll_Texture_Right: + l->special = special; s = int(lines[i].sidedef[0] - sides); new DScroller (DScroller::sc_side, l->args[0] * (-FRACUNIT/64), 0, -1, s, accel, SCROLLTYPE(l->args[1])); break; case Scroll_Texture_Up: + l->special = special; s = int(lines[i].sidedef[0] - sides); new DScroller (DScroller::sc_side, 0, l->args[0] * (FRACUNIT/64), -1, s, accel, SCROLLTYPE(l->args[1])); break; case Scroll_Texture_Down: + l->special = special; s = int(lines[i].sidedef[0] - sides); new DScroller (DScroller::sc_side, 0, l->args[0] * (-FRACUNIT/64), -1, s, accel, SCROLLTYPE(l->args[1])); From 9b5232a4102ef95a17db407f8a54aad870619720 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 23 Jan 2013 04:48:33 +0000 Subject: [PATCH 108/387] - Fixed: The health bonuses atop the pillars in the starting room of Void could not be picked up because they no longer physically clip through the floor. SVN r4038 (trunk) --- src/compatibility.cpp | 60 ++++++++++++++++++++++++++++++++- wadsrc/static/compatibility.txt | 29 ++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 25bf0f5d3..f145b5ad9 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -77,7 +77,9 @@ enum CP_SETFLAGS, CP_SETSPECIAL, CP_CLEARSPECIAL, - CP_SETACTIVATION + CP_SETACTIVATION, + CP_SECTORFLOOROFFSET, + CP_SETWALLYSCALE, }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -137,6 +139,16 @@ static FCompatOption Options[] = { NULL, 0, 0 } }; +static const char *const LineSides[] = +{ + "Front", "Back", NULL +}; + +static const char *const WallTiers[] = +{ + "Top", "Mid", "Bot", NULL +}; + static TArray CompatParams; static int ii_compatparams; @@ -259,6 +271,28 @@ void ParseCompatibility() sc.MustGetNumber(); CompatParams.Push(sc.Number); } + else if (sc.Compare("sectorflooroffset")) + { + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SECTORFLOOROFFSET); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetFloat(); + CompatParams.Push(FLOAT2FIXED(sc.Float)); + } + else if (sc.Compare("setwallyscale")) + { + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SETWALLYSCALE); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetString(); + CompatParams.Push(sc.MustMatchString(LineSides)); + sc.MustGetString(); + CompatParams.Push(sc.MustMatchString(WallTiers)); + sc.MustGetFloat(); + CompatParams.Push(FLOAT2FIXED(sc.Float)); + } else { sc.UnGet(); @@ -438,6 +472,30 @@ void SetCompatibilityParams() i += 3; break; } + case CP_SECTORFLOOROFFSET: + { + if (CompatParams[i+1] < numsectors) + { + sector_t *sec = §ors[CompatParams[i+1]]; + sec->floorplane.ChangeHeight(CompatParams[i+2]); + sec->ChangePlaneTexZ(sector_t::floor, CompatParams[i+2]); + } + i += 3; + break; + } + case CP_SETWALLYSCALE: + { + if (CompatParams[i+1] < numlines) + { + side_t *side = lines[CompatParams[i+1]].sidedef[CompatParams[i+2]]; + if (side != NULL) + { + side->SetTextureYScale(CompatParams[i+3], CompatParams[i+4]); + } + } + i += 5; + break; + } } } } diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index d87f593f0..f381155bd 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -301,3 +301,32 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 setlineflags 455 0x200 // repeatable setactivation 455 16 // SPAC_Push } + +6DC9F6CCEAE7A91AEC48EBE506F22BC4 // Void +{ + // Slightly squash the pillars in the starting room with "stimpacks" + // floating on them so that they can be obtained. + sectorflooroffset 62 -8 + setwallyscale 286 front bot 1.090909 + setwallyscale 287 front bot 1.090909 + setwallyscale 288 front bot 1.090909 + setwallyscale 289 front bot 1.090909 + + sectorflooroffset 63 -8 + setwallyscale 290 front bot 1.090909 + setwallyscale 291 front bot 1.090909 + setwallyscale 292 front bot 1.090909 + setwallyscale 293 front bot 1.090909 + + sectorflooroffset 118 -8 + setwallyscale 710 front bot 1.090909 + setwallyscale 711 front bot 1.090909 + setwallyscale 712 front bot 1.090909 + setwallyscale 713 front bot 1.090909 + + sectorflooroffset 119 -8 + setwallyscale 714 front bot 1.090909 + setwallyscale 715 front bot 1.090909 + setwallyscale 716 front bot 1.090909 + setwallyscale 717 front bot 1.090909 +} From ea81d3638d40d43da770c59e00039627f87e13ea Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 02:05:48 +0000 Subject: [PATCH 109/387] - Revert WRF_NOSWITCH changes from r4024. SVN r4039 (trunk) --- src/p_pspr.cpp | 54 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 8d901ec2e..4056794a4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -95,7 +95,7 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK); + player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK); } psp = &player->psprites[position]; @@ -565,30 +565,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) ACTION_PARAM_START(1); ACTION_PARAM_INT(paramflags, 0); - if (!(paramflags & WRF_NoSwitch)) - { - DoReadyWeaponToSwitch(self); - } - else if (self->player != NULL) - { - self->player->cheats &= ~CF_WEAPONSWITCHOK; - } - if ((paramflags & WRF_NoFire) != WRF_NoFire) - { - DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); - } - if (!(paramflags & WRF_NoBob)) - { - DoReadyWeaponToBob(self); - } - if ((paramflags & WRF_AllowReload)) - { - DoReadyWeaponToReload(self); - } - if ((paramflags & WRF_AllowZoom)) - { - DoReadyWeaponToZoom(self); - } + if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); + if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, + (!(paramflags & WRF_NoPrimary)), (!(paramflags & WRF_NoSecondary))); + if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); + if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); + if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); } //--------------------------------------------------------------------------- @@ -649,20 +631,15 @@ void P_CheckWeaponSwitch (player_t *player) if (!player || !(weapon = player->ReadyWeapon)) return; - if (player->health <= 0) - { // Dead, so put the weapon away. - P_SetPsprite(player, ps_weapon, weapon->GetDownState()); - } - else if (!(player->cheats & CF_WEAPONSWITCHOK)) - { // Weapon changing has been disabled. - player->PendingWeapon = WP_NOCHANGE; - } - else if (player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) - { // Put the weapon away if the player has a pending weapon + // Put the weapon away if the player has a pending weapon or has died. + if ((player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) || player->health <= 0) + { P_SetPsprite (player, ps_weapon, weapon->GetDownState()); + return; } else if (player->morphTics != 0) - { // Morphed classes cannot change weapons, so don't even try again. + { + // morphed classes cannot change weapons so don't even try again. player->PendingWeapon = WP_NOCHANGE; } } @@ -1073,7 +1050,10 @@ void P_MovePsprites (player_t *player) } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - P_CheckWeaponSwitch (player); + if (player->cheats & CF_WEAPONSWITCHOK) + { + P_CheckWeaponSwitch (player); + } if (player->cheats & (CF_WEAPONREADY | CF_WEAPONREADYALT)) { P_CheckWeaponFire (player); From 47cb2ad6bc14709d16c1b72d8c14a10b1e65ee25 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 02:35:11 +0000 Subject: [PATCH 110/387] - In P_PoisonPlayer(), keep track of the source as the poisoner, so you can get accurate kill accounting. Also, if the poisoner is a missile, remembering it is pretty pointless, since it's likely to be gone before the player ever dies from the poison. SVN r4040 (trunk) --- src/p_interaction.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 66bdbe2a2..3004022e4 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1511,6 +1511,10 @@ bool AActor::OkayToSwitchTarget (AActor *other) // // P_PoisonPlayer - Sets up all data concerning poisoning // +// poisoner is the object directly responsible for poisoning the player, +// such as a missile. source is the actor responsible for creating the +// poisoner. +// //========================================================================== bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison) @@ -1526,7 +1530,7 @@ bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poi if (poison > 0) { player->poisoncount += poison; - player->poisoner = poisoner; + player->poisoner = source; if (poisoner == NULL) { player->poisontype = player->poisonpaintype = NAME_None; From 281ac3a49a9ccca6803f7517ff02a9ef91a2138d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 03:09:17 +0000 Subject: [PATCH 111/387] - Separate the player weapon state flags from the other player "cheat" flags. SVN r4041 (trunk) --- src/d_player.h | 17 +++++++++++------ src/p_pspr.cpp | 30 +++++++++++++++--------------- src/p_user.cpp | 11 +++++++++++ 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d1f564470..1b26bb776 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -195,7 +195,6 @@ typedef enum CF_INSTANTWEAPSWITCH= 1 << 11, // [RH] Switch weapons instantly CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted - CF_WEAPONREADY = 1 << 14, // [RH] Weapon is in the ready state and can fire its primary attack CF_DRAIN = 1 << 16, // Player owns a drain powerup CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) CF_REFLECTION = 1 << 19, @@ -203,15 +202,20 @@ typedef enum CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact - CF_WEAPONBOBBING = 1 << 24, // [HW] Bob weapon while the player is moving - CF_WEAPONREADYALT = 1 << 25, // Weapon can fire its secondary attack - CF_WEAPONSWITCHOK = 1 << 26, // It is okay to switch away from this weapon CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die - CF_WEAPONRELOADOK = 1 << 28, // [XA] Okay to reload this weapon. - CF_WEAPONZOOMOK = 1 << 29, // [XA] Okay to use weapon zoom function. CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip } cheat_t; +enum +{ + WF_WEAPONREADY = 1 << 0, // [RH] Weapon is in the ready state and can fire its primary attack + WF_WEAPONBOBBING = 1 << 1, // [HW] Bob weapon while the player is moving + WF_WEAPONREADYALT = 1 << 2, // Weapon can fire its secondary attack + WF_WEAPONSWITCHOK = 1 << 3, // It is okay to switch away from this weapon + WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. + WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. +}; + #define WPIECE1 1 #define WPIECE2 2 #define WPIECE3 4 @@ -305,6 +309,7 @@ public: int lastkilltime; // [RH] For multikills BYTE multicount; BYTE spreecount; // [RH] Keep track of killing sprees + BYTE WeaponState; AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 4056794a4..15e60863e 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -95,7 +95,7 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->cheats &= ~(CF_WEAPONREADY | CF_WEAPONREADYALT | CF_WEAPONBOBBING | CF_WEAPONSWITCHOK | CF_WEAPONRELOADOK | CF_WEAPONZOOMOK); + player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK); } psp = &player->psprites[position]; @@ -397,7 +397,7 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y) // [RH] Smooth transitions between bobbing and not-bobbing frames. // This also fixes the bug where you can "stick" a weapon off-center by // shooting it when it's at the peak of its swing. - bobtarget = (player->cheats & CF_WEAPONBOBBING) ? player->bob : 0; + bobtarget = (player->cheats & WF_WEAPONBOBBING) ? player->bob : 0; if (curbob != bobtarget) { if (abs (bobtarget - curbob) <= 1*FRACUNIT) @@ -476,7 +476,7 @@ void DoReadyWeaponToSwitch (AActor * self) // Prepare for switching action. player_t *player; if (self && (player = self->player)) - player->cheats |= CF_WEAPONSWITCHOK; + player->cheats |= WF_WEAPONSWITCHOK; } void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) @@ -506,7 +506,7 @@ void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) } // Prepare for firing action. - player->cheats |= ((prim ? CF_WEAPONREADY : 0) | (alt ? CF_WEAPONREADYALT : 0)); + player->cheats |= ((prim ? WF_WEAPONREADY : 0) | (alt ? WF_WEAPONREADYALT : 0)); return; } @@ -515,7 +515,7 @@ void DoReadyWeaponToBob (AActor * self) if (self && self->player && self->player->ReadyWeapon) { // Prepare for bobbing action. - self->player->cheats |= CF_WEAPONBOBBING; + self->player->cheats |= WF_WEAPONBOBBING; self->player->psprites[ps_weapon].sx = 0; self->player->psprites[ps_weapon].sy = WEAPONTOP; } @@ -526,7 +526,7 @@ void DoReadyWeaponToReload (AActor * self) // Prepare for reload action. player_t *player; if (self && (player = self->player)) - player->cheats |= CF_WEAPONRELOADOK; + player->cheats |= WF_WEAPONRELOADOK; return; } @@ -535,7 +535,7 @@ void DoReadyWeaponToZoom (AActor * self) // Prepare for reload action. player_t *player; if (self && (player = self->player)) - player->cheats |= CF_WEAPONZOOMOK; + player->cheats |= WF_WEAPONZOOMOK; return; } @@ -591,7 +591,7 @@ void P_CheckWeaponFire (player_t *player) return; // Check for fire. Some weapons do not auto fire. - if ((player->cheats & CF_WEAPONREADY) && (player->cmd.ucmd.buttons & BT_ATTACK)) + if ((player->cheats & WF_WEAPONREADY) && (player->cmd.ucmd.buttons & BT_ATTACK)) { if (!player->attackdown || !(weapon->WeaponFlags & WIF_NOAUTOFIRE)) { @@ -600,7 +600,7 @@ void P_CheckWeaponFire (player_t *player) return; } } - else if ((player->cheats & CF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) + else if ((player->cheats & WF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) { if (!player->attackdown || !(weapon->WeaponFlags & WIF_NOAUTOFIRE)) { @@ -660,7 +660,7 @@ void P_CheckWeaponReload (player_t *player) return; // Check for reload. - if ((player->cheats & CF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) + if ((player->cheats & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) { P_ReloadWeapon (player, NULL); } @@ -682,7 +682,7 @@ void P_CheckWeaponZoom (player_t *player) return; // Check for zoom. - if ((player->cheats & CF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) + if ((player->cheats & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) { P_ZoomWeapon (player, NULL); } @@ -1050,19 +1050,19 @@ void P_MovePsprites (player_t *player) } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - if (player->cheats & CF_WEAPONSWITCHOK) + if (player->cheats & WF_WEAPONSWITCHOK) { P_CheckWeaponSwitch (player); } - if (player->cheats & (CF_WEAPONREADY | CF_WEAPONREADYALT)) + if (player->cheats & (WF_WEAPONREADY | WF_WEAPONREADYALT)) { P_CheckWeaponFire (player); } - if (player->cheats & CF_WEAPONRELOADOK) + if (player->cheats & WF_WEAPONRELOADOK) { P_CheckWeaponReload (player); } - if (player->cheats & CF_WEAPONZOOMOK) + if (player->cheats & WF_WEAPONZOOMOK) { P_CheckWeaponZoom (player); } diff --git a/src/p_user.cpp b/src/p_user.cpp index 0060641db..c936ea47e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -247,6 +247,7 @@ player_t::player_t() ReadyWeapon(0), PendingWeapon(0), cheats(0), + WeaponState(0), timefreezer(0), refire(0), inconsistant(0), @@ -2670,6 +2671,16 @@ void player_t::Serialize (FArchive &arc) mo->stamina = oldstamina; } } + if (SaveVersion < 4041) + { + // Move weapon state flags from cheats and into WeaponState. + WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); + cheats &= ~((1 << 14) | (0x37 << 24)); + } + else + { + arc << WeaponState; + } arc << LogText << ConversationNPC << ConversationPC From 9d43ba39fc1860ed15c09d5b25428d57238c5aab Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 03:18:45 +0000 Subject: [PATCH 112/387] - Using the proper container for weapon state flags would be good. SVN r4042 (trunk) --- src/p_pspr.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 15e60863e..24f202a57 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -397,7 +397,7 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y) // [RH] Smooth transitions between bobbing and not-bobbing frames. // This also fixes the bug where you can "stick" a weapon off-center by // shooting it when it's at the peak of its swing. - bobtarget = (player->cheats & WF_WEAPONBOBBING) ? player->bob : 0; + bobtarget = (player->WeaponState & WF_WEAPONBOBBING) ? player->bob : 0; if (curbob != bobtarget) { if (abs (bobtarget - curbob) <= 1*FRACUNIT) @@ -476,7 +476,7 @@ void DoReadyWeaponToSwitch (AActor * self) // Prepare for switching action. player_t *player; if (self && (player = self->player)) - player->cheats |= WF_WEAPONSWITCHOK; + player->WeaponState |= WF_WEAPONSWITCHOK; } void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) @@ -506,7 +506,7 @@ void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) } // Prepare for firing action. - player->cheats |= ((prim ? WF_WEAPONREADY : 0) | (alt ? WF_WEAPONREADYALT : 0)); + player->WeaponState |= ((prim ? WF_WEAPONREADY : 0) | (alt ? WF_WEAPONREADYALT : 0)); return; } @@ -515,7 +515,7 @@ void DoReadyWeaponToBob (AActor * self) if (self && self->player && self->player->ReadyWeapon) { // Prepare for bobbing action. - self->player->cheats |= WF_WEAPONBOBBING; + self->player->WeaponState |= WF_WEAPONBOBBING; self->player->psprites[ps_weapon].sx = 0; self->player->psprites[ps_weapon].sy = WEAPONTOP; } @@ -526,7 +526,7 @@ void DoReadyWeaponToReload (AActor * self) // Prepare for reload action. player_t *player; if (self && (player = self->player)) - player->cheats |= WF_WEAPONRELOADOK; + player->WeaponState |= WF_WEAPONRELOADOK; return; } @@ -535,7 +535,7 @@ void DoReadyWeaponToZoom (AActor * self) // Prepare for reload action. player_t *player; if (self && (player = self->player)) - player->cheats |= WF_WEAPONZOOMOK; + player->WeaponState |= WF_WEAPONZOOMOK; return; } @@ -591,7 +591,7 @@ void P_CheckWeaponFire (player_t *player) return; // Check for fire. Some weapons do not auto fire. - if ((player->cheats & WF_WEAPONREADY) && (player->cmd.ucmd.buttons & BT_ATTACK)) + if ((player->WeaponState & WF_WEAPONREADY) && (player->cmd.ucmd.buttons & BT_ATTACK)) { if (!player->attackdown || !(weapon->WeaponFlags & WIF_NOAUTOFIRE)) { @@ -600,7 +600,7 @@ void P_CheckWeaponFire (player_t *player) return; } } - else if ((player->cheats & WF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) + else if ((player->WeaponStat & WF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) { if (!player->attackdown || !(weapon->WeaponFlags & WIF_NOAUTOFIRE)) { @@ -660,7 +660,7 @@ void P_CheckWeaponReload (player_t *player) return; // Check for reload. - if ((player->cheats & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) + if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) { P_ReloadWeapon (player, NULL); } @@ -682,7 +682,7 @@ void P_CheckWeaponZoom (player_t *player) return; // Check for zoom. - if ((player->cheats & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) + if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) { P_ZoomWeapon (player, NULL); } @@ -780,7 +780,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) return; } psp = &player->psprites[ps_weapon]; - if (player->morphTics || player->cheats & CF_INSTANTWEAPSWITCH) + if (player->morphTics || player->WeaponState & CF_INSTANTWEAPSWITCH) { psp->sy = WEAPONBOTTOM; } @@ -1038,7 +1038,7 @@ void P_MovePsprites (player_t *player) psp->tics--; // [BC] Apply double firing speed. - if ( psp->tics && ( player->cheats & CF_DOUBLEFIRINGSPEED )) + if ( psp->tics && (player->WeaponState & CF_DOUBLEFIRINGSPEED)) psp->tics--; if(!psp->tics) @@ -1050,19 +1050,19 @@ void P_MovePsprites (player_t *player) } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - if (player->cheats & WF_WEAPONSWITCHOK) + if (player->WeaponState & WF_WEAPONSWITCHOK) { P_CheckWeaponSwitch (player); } - if (player->cheats & (WF_WEAPONREADY | WF_WEAPONREADYALT)) + if (player->WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) { P_CheckWeaponFire (player); } - if (player->cheats & WF_WEAPONRELOADOK) + if (player->WeaponState & WF_WEAPONRELOADOK) { P_CheckWeaponReload (player); } - if (player->cheats & WF_WEAPONZOOMOK) + if (player->WeaponState & WF_WEAPONZOOMOK) { P_CheckWeaponZoom (player); } From 1c999d9d55d97457886d8dd66f179345be27a653 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 03:25:32 +0000 Subject: [PATCH 113/387] - Be more concise for WRF_NoFire in A_WeaponReady. SVN r4043 (trunk) --- src/p_pspr.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 24f202a57..46d31ab39 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -566,9 +566,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) ACTION_PARAM_INT(paramflags, 0); if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); - if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, - (!(paramflags & WRF_NoPrimary)), (!(paramflags & WRF_NoSecondary))); - if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); + if (!(paramflags & WRF_NoFire)) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); + if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); } From 5dca935305ef5c7a4626e11e892d17742f1164f0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 03:32:20 +0000 Subject: [PATCH 114/387] - If this was a git repository, I wouldn't have needed to just make three broken commits in a row. SVN r4044 (trunk) --- src/p_pspr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 46d31ab39..38e89a678 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -599,7 +599,7 @@ void P_CheckWeaponFire (player_t *player) return; } } - else if ((player->WeaponStat & WF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) + else if ((player->WeaponState & WF_WEAPONREADYALT) && (player->cmd.ucmd.buttons & BT_ALTATTACK)) { if (!player->attackdown || !(weapon->WeaponFlags & WIF_NOAUTOFIRE)) { From ed8a33aeaf538d54ba16c429ecd69258a81e417f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 25 Jan 2013 03:32:49 +0000 Subject: [PATCH 115/387] - Use P_DropWeapon() everywhere it makes sense. SVN r4045 (trunk) --- src/p_pspr.cpp | 4 ++-- src/p_user.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 38e89a678..25c3e9645 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -633,7 +633,7 @@ void P_CheckWeaponSwitch (player_t *player) // Put the weapon away if the player has a pending weapon or has died. if ((player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) || player->health <= 0) { - P_SetPsprite (player, ps_weapon, weapon->GetDownState()); + P_DropWeapon(player); return; } else if (player->morphTics != 0) @@ -829,7 +829,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) } if (player->PendingWeapon != WP_NOCHANGE) { - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetDownState()); + P_DropWeapon(player); return; } psp = &player->psprites[ps_weapon]; diff --git a/src/p_user.cpp b/src/p_user.cpp index c936ea47e..cb15b18f9 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -792,7 +792,7 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) player->PendingWeapon = best; if (player->ReadyWeapon != NULL) { - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetDownState()); + P_DropWeapon(player); } else if (player->PendingWeapon != WP_NOCHANGE) { From 6a1f28e400c7c39bf00da01f9604de9b106a63cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Jan 2013 14:50:09 +0000 Subject: [PATCH 116/387] - fixed some issues in the alternate HUD menu. SVN r4046 (trunk) --- wadsrc/static/menudef.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index dffce3d55..7e809085a 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -804,10 +804,9 @@ OptionMenu "AltHUDOptions" option "Map title color", "hudcolor_titl", "TextColors" option "Hub time color", "hudcolor_time", "TextColors" option "Map time color", "hudcolor_ltim", "TextColors" - option "Total title color", "hudcolor_ttim", "TextColors" + option "Total time color", "hudcolor_ttim", "TextColors" option "Coordinate color", "hudcolor_xyco", "TextColors" option "Coordinate mode", "map_point_coordinates", "AMCoordinates" - option "Map title color", "hudcolor_titl", "TextColors" option "Statistics name color", "hudcolor_statnames", "TextColors" option "Statistics color", "hudcolor_stats", "TextColors" } From 9cca4ff71d59f59cf86979cd9e7c6f975a9c3692 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 02:54:09 +0000 Subject: [PATCH 117/387] - Fixed: Lost Souls spawned by Pain Elementals were not killed by DF2_KILLBOSSMONST. SVN r4047 (trunk) --- src/g_doom/a_bossbrain.cpp | 20 +++++++++++++------- src/g_doom/a_painelemental.cpp | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index f0263f5bc..873b5c6dc 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -79,16 +79,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_BrainDie) // New dmflag: Kill all boss spawned monsters before ending the level. if (dmflags2 & DF2_KILLBOSSMONST) { - TThinkerIterator it; - AActor *mo; - while ((mo = it.Next())) + int count; // Repeat until we have no more boss-spawned monsters. + do // (e.g. Pain Elementals can spawn more to kill upon death.) { - if (mo->flags4 & MF4_BOSSSPAWNED) + TThinkerIterator it; + AActor *mo; + count = 0; + while ((mo = it.Next())) { - P_DamageMobj(mo, self, self, mo->health, NAME_None, - DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR); + if (mo->health > 0 && mo->flags4 & MF4_BOSSSPAWNED) + { + P_DamageMobj(mo, self, self, mo->health, NAME_None, + DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR); + count++; + } } - } + } while (count != 0); } G_ExitLevel (0, false); diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index 55451a892..db7d83021 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -111,6 +111,8 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int other = Spawn (spawntype, x, y, z, ALLOW_REPLACE); + // Transfer boss-spawned flag + other->flags4 |= self->flags4 & MF4_BOSSSPAWNED; // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. From 931357358d3aecc34779d2865ca33109bb454508 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 03:19:27 +0000 Subject: [PATCH 118/387] - Reorder the althud level time map entries to match their displayed order. SVN r4048 (trunk) --- wadsrc/static/menudef.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 7e809085a..52cee7f46 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -802,8 +802,8 @@ OptionMenu "AltHUDOptions" StaticText " " StaticText "Alternative Automap HUD", 1 option "Map title color", "hudcolor_titl", "TextColors" - option "Hub time color", "hudcolor_time", "TextColors" option "Map time color", "hudcolor_ltim", "TextColors" + option "Hub time color", "hudcolor_time", "TextColors" option "Total time color", "hudcolor_ttim", "TextColors" option "Coordinate color", "hudcolor_xyco", "TextColors" option "Coordinate mode", "map_point_coordinates", "AMCoordinates" From 83320626e5f8df9ab838a5fe3453d632baae8def Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 03:21:09 +0000 Subject: [PATCH 119/387] - Use "Map time color" for single maps, whether in a hub or not. Only use "Hub time color" for hub times. SVN r4049 (trunk) --- src/g_shared/shared_hud.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 5bdca34e7..051aae14c 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -899,18 +899,18 @@ void DrawHUD() if (am_showtime) { - seconds = level.time /TICRATE; - mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60); - DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT); - bottom -= fonth; - - // Single level time for hubs if (level.clusterflags&CLUSTER_HUB) { - seconds= level.maptime /TICRATE; + seconds = level.time /TICRATE; mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60); - DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT); + DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT); + bottom -= fonth; } + + // Single level time for hubs + seconds= level.maptime /TICRATE; + mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60); + DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT); } ST_FormatMapName(mapname); From e0a137b72565ee1d42f27c1f421c81f11ef0263d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 03:28:54 +0000 Subject: [PATCH 120/387] - Removed the netdemo flag, because it's redundant with (netgame && demoplayback). SVN r4050 (trunk) --- src/d_main.cpp | 1 - src/g_game.cpp | 6 ++---- src/g_level.cpp | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2670dcf4e..50311c826 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -158,7 +158,6 @@ EXTERN_CVAR (Bool, sv_unlimited_pickup) extern int testingmode; extern bool setmodeneeded; -extern bool netdemo; extern int NewWidth, NewHeight, NewBits, DisplayBits; EXTERN_CVAR (Bool, st_scale) extern bool gameisdead; diff --git a/src/g_game.cpp b/src/g_game.cpp index 6163ee0d6..fd8489f9a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,7 +164,6 @@ CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); FString demoname; bool demorecording; bool demoplayback; -bool netdemo; bool demonew; // [RH] Only used around G_InitNew for demos int demover; BYTE* demobuffer; @@ -1131,7 +1130,7 @@ void G_Ticker () Printf ("%s is turbo!\n", players[i].userinfo.netname); } - if (netgame && !players[i].isbot && !netdemo && (gametic%ticdup) == 0) + if (netgame && !players[i].isbot && !demoplayback && (gametic%ticdup) == 0) { //players[i].inconsistant = 0; if (gametic > BACKUPTICS*ticdup && consistancy[i][buf] != cmd->consistancy) @@ -2503,7 +2502,7 @@ bool G_ProcessIFFDemo (char *mapname) } if (numPlayers > 1) - multiplayer = netgame = netdemo = true; + multiplayer = netgame = true; if (uncompSize > 0) { @@ -2641,7 +2640,6 @@ bool G_CheckDemoStatus (void) P_SetupWeapons_ntohton(); demoplayback = false; - netdemo = false; netgame = false; multiplayer = false; singletics = false; diff --git a/src/g_level.cpp b/src/g_level.cpp index 24c43defd..27be03b08 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -114,7 +114,6 @@ extern bool timingdemo; int starttime; -extern bool netdemo; extern FString BackupSaveName; bool savegamerestore; @@ -230,7 +229,6 @@ void G_NewInit () G_ClearSnapshots (); SB_state = screen->GetPageCount (); netgame = false; - netdemo = false; multiplayer = false; if (demoplayback) { From 5b97bf47de720e83cba5d5df430e022762835fea Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 03:39:43 +0000 Subject: [PATCH 121/387] - Fixed: The string displayed when attempting to start a new game during a netgame is "NEWGAME", not "NETGAME". SVN r4051 (trunk) --- src/menu/menudef.cpp | 2 +- wadsrc/static/menudef.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 98b1dc34b..0d9b89989 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -1135,7 +1135,7 @@ static void BuildPlayerclassMenu() od->mScrollTop = 0; od->mIndent = 160; od->mDontDim = false; - od->mNetgameMessage = "$NETGAME"; + od->mNetgameMessage = "$NEWGAME"; for (unsigned i = 0; i < PlayerClasses.Size (); i++) { diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 52cee7f46..a87932413 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -117,11 +117,11 @@ ListMenu "PlayerclassMenu" { IfGame(Doom, Heretic, Hexen, Strife) { - NetgameMessage "$NETGAME" + NetgameMessage "$NEWGAME" } IfGame(Chex) { - NetgameMessage "$CNETGAME" + NetgameMessage "$CNEWGAME" } IfGame(Doom, Strife, Chex) @@ -159,11 +159,11 @@ ListMenu "EpisodeMenu" { IfGame(Doom, Heretic, Hexen, Strife) { - NetgameMessage "$NETGAME" + NetgameMessage "$NEWGAME" } IfGame(Chex) { - NetgameMessage "$CNETGAME" + NetgameMessage "$CNEWGAME" } IfGame(Doom, Chex) From c4a4b9821d52b63f605d321465b3806dfee2724f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 26 Jan 2013 03:41:06 +0000 Subject: [PATCH 122/387] - Fixed: The menu treated netdemos as actual netgames. SVN r4052 (trunk) --- src/menu/menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index dec0a4241..e07bc142f 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -409,7 +409,7 @@ void M_SetMenu(FName menu, int param) FMenuDescriptor **desc = MenuDescriptors.CheckKey(menu); if (desc != NULL) { - if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame) + if ((*desc)->mNetgameMessage.IsNotEmpty() && netgame && !demoplayback) { M_StartMessage((*desc)->mNetgameMessage, 1); return; From 15497b4a24b294f841f5052a406778f17d0226cf Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Jan 2013 02:57:17 +0000 Subject: [PATCH 123/387] - Fixed: Floor_RaiseAndCrush is not Floor_RaiseToLowestCeilingAndCrush. SVN r4053 (trunk) --- src/p_floor.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index d88886b14..ea2551dfd 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -375,18 +375,13 @@ manual_floor: floor->m_Direction = (floor->m_FloorDestDist > sec->floorplane.d) ? -1 : 1; break; - case DFloor::floorRaiseAndCrush: - floor->m_Crush = crush; case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; newheight = sec->FindLowestCeilingSurrounding (&spot); - if (floortype == DFloor::floorRaiseAndCrush) - newheight -= 8 * FRACUNIT; ceilingheight = sec->FindLowestCeilingPoint (&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); if (sec->floorplane.ZatPointDist (spot2, floor->m_FloorDestDist) > ceilingheight) - floor->m_FloorDestDist = sec->floorplane.PointToDist (spot2, - floortype == DFloor::floorRaiseAndCrush ? ceilingheight - 8*FRACUNIT : ceilingheight); + floor->m_FloorDestDist = sec->floorplane.PointToDist (spot2, ceilingheight); break; case DFloor::floorRaiseToHighest: @@ -407,6 +402,13 @@ manual_floor: floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); break; + case DFloor::floorRaiseAndCrush: + floor->m_Crush = crush; + floor->m_Direction = 1; + newheight = sec->FindLowestCeilingPoint (&spot) - 8*FRACUNIT; + floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); + break; + case DFloor::floorRaiseToCeiling: floor->m_Direction = 1; newheight = sec->FindLowestCeilingPoint (&spot); From a2f55c8067ef989149908bddd2d2e734aa6b9505 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Jan 2013 03:02:00 +0000 Subject: [PATCH 124/387] - Well, poo. WRF_NoFire is two bits, not just one. SVN r4054 (trunk) --- src/p_pspr.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 25c3e9645..8321daf28 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -552,10 +552,10 @@ void DoReadyWeapon(AActor * self) enum EWRF_Options { WRF_NoBob = 1, - WRF_NoFire = 12, WRF_NoSwitch = 2, WRF_NoPrimary = 4, WRF_NoSecondary = 8, + WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, WRF_AllowReload = 16, WRF_AllowZoom = 32, }; @@ -565,11 +565,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) ACTION_PARAM_START(1); ACTION_PARAM_INT(paramflags, 0); - if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); - if (!(paramflags & WRF_NoFire)) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); - if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); - if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); + if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); + if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); + if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); + if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); + if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); } //--------------------------------------------------------------------------- From 61322cc33b8534e2cd3cc5c4b6bf1b2d7d76b058 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 27 Jan 2013 04:08:00 +0000 Subject: [PATCH 125/387] - Fixed: A_Lower needs to check player->cheats for WF_INSTANTWEAPSWITCH, not player->WeaponState. SVN r4055 (trunk) --- src/p_pspr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 8321daf28..54b56937d 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -779,7 +779,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) return; } psp = &player->psprites[ps_weapon]; - if (player->morphTics || player->WeaponState & CF_INSTANTWEAPSWITCH) + if (player->morphTics || player->cheats & CF_INSTANTWEAPSWITCH) { psp->sy = WEAPONBOTTOM; } From b958215b50894aa08055ae42f2127151b0e17076 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 30 Jan 2013 00:56:24 +0000 Subject: [PATCH 126/387] - Fixed: DrawBar's clipping didn't take the texture offset into account. SVN r4056 (trunk) --- src/g_shared/sbarinfo.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 6530c6adf..a94d041a7 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1203,8 +1203,8 @@ public: 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); - double dcb = cb == 0 ? INT_MAX : dy + h - ((double) cb / FRACUNIT); + double dcr = cr == 0 ? INT_MAX : dx + w - ((double) cr / FRACUNIT) - texture->GetScaledLeftOffsetDouble(); + double dcb = cb == 0 ? INT_MAX : dy + h - ((double) cb / FRACUNIT) - texture->GetScaledTopOffsetDouble(); if(Scaled) { @@ -1292,10 +1292,10 @@ public: // Check for clipping if(cx != 0 || cy != 0 || cr != 0 || cb != 0) { - 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); + rcx = cx == 0 ? 0 : rx+(((double) cx/FRACUNIT)*xScale) - texture->GetScaledLeftOffsetDouble(); + rcy = cy == 0 ? 0 : ry+(((double) cy/FRACUNIT)*yScale) - texture->GetScaledTopOffsetDouble(); + rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale) - texture->GetScaledLeftOffsetDouble(); + rcb = cb == 0 ? INT_MAX : ry+h-(((double) cb/FRACUNIT)*yScale) - texture->GetScaledTopOffsetDouble(); } if(clearDontDraw) From 5965c45932df5cf81c199a1b44ca84afaa0d6788 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 1 Feb 2013 02:16:02 +0000 Subject: [PATCH 127/387] - Fixed: Using interpolation on drawbar would sometimes result in the last pixel hanging longer than it should. - Improved draw bar clipping fix from last commit. SVN r4057 (trunk) --- src/g_shared/sbarinfo.cpp | 8 ++++---- src/g_shared/sbarinfo_commands.cpp | 13 +++++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index a94d041a7..09be47363 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1292,10 +1292,10 @@ public: // Check for clipping if(cx != 0 || cy != 0 || cr != 0 || cb != 0) { - rcx = cx == 0 ? 0 : rx+(((double) cx/FRACUNIT)*xScale) - texture->GetScaledLeftOffsetDouble(); - rcy = cy == 0 ? 0 : ry+(((double) cy/FRACUNIT)*yScale) - texture->GetScaledTopOffsetDouble(); - rcr = cr == 0 ? INT_MAX : rx+w-(((double) cr/FRACUNIT)*xScale) - texture->GetScaledLeftOffsetDouble(); - rcb = cb == 0 ? INT_MAX : ry+h-(((double) cb/FRACUNIT)*yScale) - texture->GetScaledTopOffsetDouble(); + rcx = cx == 0 ? 0 : rx+((((double) cx/FRACUNIT) - texture->GetScaledLeftOffsetDouble())*xScale); + rcy = cy == 0 ? 0 : ry+((((double) cy/FRACUNIT) - texture->GetScaledTopOffsetDouble())*yScale); + rcr = cr == 0 ? INT_MAX : rx+w-((((double) cr/FRACUNIT) + texture->GetScaledLeftOffsetDouble())*xScale); + rcb = cb == 0 ? INT_MAX : ry+h-((((double) cb/FRACUNIT) + texture->GetScaledTopOffsetDouble())*yScale); } if(clearDontDraw) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 348f97e08..25ea27283 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2330,7 +2330,8 @@ class CommandDrawBar : public SBarInfoCommand public: CommandDrawBar(SBarInfo *script) : SBarInfoCommand(script), border(0), horizontal(false), reverse(false), foreground(-1), - background(-1), type(HEALTH), interpolationSpeed(0), drawValue(0) + background(-1), type(HEALTH), interpolationSpeed(0), drawValue(0), + pixel(-1) { } @@ -2649,7 +2650,14 @@ class CommandDrawBar : public SBarInfoCommand value = 0; if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) { - if(value < drawValue) + // [BL] Since we used a percentage (in order to get the most fluid animation) + // we need to establish a cut off point so the last pixel won't hang as the animation slows + if(pixel == -1 && statusBar->Images[foreground]) + pixel = MAX(1, FRACUNIT/statusBar->Images[foreground]->GetWidth()); + + if(abs(drawValue - value) < pixel) + drawValue = value; + else if(value < drawValue) drawValue -= clamp((drawValue - value) >> 2, 1, FixedDiv(interpolationSpeed<((value - drawValue) >> 2, 1, FixedDiv(interpolationSpeed< Date: Sat, 2 Feb 2013 05:54:15 +0000 Subject: [PATCH 128/387] - Added ACS profiling information. SVN r4058 (trunk) --- src/p_acs.cpp | 193 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/p_acs.h | 32 ++++++++- 2 files changed, 219 insertions(+), 6 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ead7b198a..95899a599 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -114,12 +114,13 @@ FRandom pr_acs ("ACS"); struct CallReturn { - CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard) + CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard, unsigned int runaway) : ReturnFunction(func), ReturnModule(module), ReturnLocals(locals), ReturnAddress(pc), - bDiscardResult(discard) + bDiscardResult(discard), + EntryInstrCount(runaway) {} ScriptFunction *ReturnFunction; @@ -127,6 +128,7 @@ struct CallReturn SDWORD *ReturnLocals; int ReturnAddress; int bDiscardResult; + unsigned int EntryInstrCount; }; static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module, @@ -1028,7 +1030,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) LumpNum = lumpnum; memset (MapVarStore, 0, sizeof(MapVarStore)); ModuleName[0] = 0; - + FunctionProfileData = NULL; // Now that everything is set up, record this module as being among the loaded modules. // We need to do this before resolving any imports, because an import might (indirectly) @@ -1163,6 +1165,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) { NumFunctions = LittleLong(((DWORD *)Functions)[1]) / 8; Functions += 8; + FunctionProfileData = new ACSProfileInfo[NumFunctions]; } // Load JUMP points @@ -1450,6 +1453,11 @@ FBehavior::~FBehavior () delete[] ArrayStore; ArrayStore = NULL; } + if (FunctionProfileData != NULL) + { + delete[] FunctionProfileData; + FunctionProfileData = NULL; + } if (Data != NULL) { delete[] Data; @@ -2236,6 +2244,14 @@ void DLevelScript::Serialize (FArchive &arc) { ClipRectLeft = ClipRectTop = ClipRectWidth = ClipRectHeight = WrapWidth = 0; } + if (SaveVersion >= 4058) + { + arc << InModuleScriptNumber; + } + else + { // Don't worry about locating profiling info for old saves. + InModuleScriptNumber = -1; + } } DLevelScript::DLevelScript () @@ -4097,7 +4113,7 @@ int DLevelScript::RunScript () int sp = 0; int *pc = this->pc; ACSFormat fmt = activeBehavior->GetFormat(); - int runaway = 0; // used to prevent infinite loops + unsigned int runaway = 0; // used to prevent infinite loops int pcd; FString work; const char *lookup; @@ -4401,7 +4417,7 @@ int DLevelScript::RunScript () } sp += i; ::new(&Stack[sp]) CallReturn(activeBehavior->PC2Ofs(pc), activeFunction, - activeBehavior, mylocals, pcd == PCD_CALLDISCARD); + activeBehavior, mylocals, pcd == PCD_CALLDISCARD, runaway); sp += (sizeof(CallReturn) + sizeof(int) - 1) / sizeof(int); pc = module->Ofs2PC (func->Address); activeFunction = func; @@ -4430,6 +4446,7 @@ int DLevelScript::RunScript () } sp -= sizeof(CallReturn)/sizeof(int); retsp = &Stack[sp]; + activeBehavior->GetFunctionProfileData(activeFunction)->AddRun(runaway - ret->EntryInstrCount); sp = int(locals - Stack); pc = ret->ReturnModule->Ofs2PC(ret->ReturnAddress); activeFunction = ret->ReturnFunction; @@ -7359,6 +7376,11 @@ scriptwait: } } + if (runaway != 0 && InModuleScriptNumber >= 0) + { + activeBehavior->GetScriptPtr(InModuleScriptNumber)->ProfileData.AddRun(runaway); + } + if (state == SCRIPT_DivideBy0) { Printf ("Divide by zero in %s\n", ScriptPresentation(script).GetChars()); @@ -7425,6 +7447,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr localvars[i] = args[i]; } pc = module->GetScriptAddress(code); + InModuleScriptNumber = module->GetScriptIndex(code); activator = who; activationline = where; backSide = flags & ACS_BACKSIDE; @@ -7688,3 +7711,163 @@ void DACSThinker::DumpScriptStatus () script = script->next; } } + +// Profiling support -------------------------------------------------------- + +ACSProfileInfo::ACSProfileInfo() +{ + TotalInstr = 0; + NumRuns = 0; + MinInstrPerRun = UINT_MAX; + MaxInstrPerRun = 0; +} + +void ACSProfileInfo::AddRun(unsigned int num_instr) +{ + TotalInstr += num_instr; + NumRuns++; + if (num_instr < MinInstrPerRun) + { + MinInstrPerRun = num_instr; + } + if (num_instr > MaxInstrPerRun) + { + MaxInstrPerRun = num_instr; + } +} + +void ArrangeScriptProfiles(TArray &profiles) +{ + for (unsigned int mod_num = 0; mod_num < FBehavior::StaticModules.Size(); ++mod_num) + { + FBehavior *module = FBehavior::StaticModules[mod_num]; + ProfileCollector prof; + prof.Module = module; + for (int i = 0; i < module->NumScripts; ++i) + { + prof.Index = i; + prof.ProfileData = &module->Scripts[i].ProfileData; + profiles.Push(prof); + } + } +} + +void ArrangeFunctionProfiles(TArray &profiles) +{ + for (unsigned int mod_num = 0; mod_num < FBehavior::StaticModules.Size(); ++mod_num) + { + FBehavior *module = FBehavior::StaticModules[mod_num]; + ProfileCollector prof; + prof.Module = module; + for (int i = 0; i < module->NumFunctions; ++i) + { + prof.Index = i; + prof.ProfileData = module->FunctionProfileData + i; + profiles.Push(prof); + } + } +} + +static int STACK_ARGS sort_by_total_instr(const void *a_, const void *b_) +{ + const ProfileCollector *a = (const ProfileCollector *)a_; + const ProfileCollector *b = (const ProfileCollector *)b_; + + assert(a != NULL && a->ProfileData != NULL); + assert(b != NULL && b->ProfileData != NULL); + return (int)(b->ProfileData->TotalInstr - a->ProfileData->TotalInstr); +} + +static void ShowProfileData(TArray &profiles, long ilimit, bool functions) +{ + static const char *const typelabels[2] = { "script", "function" }; + + if (profiles.Size() == 0) + { + return; + } + + unsigned int limit; + char modname[13]; + char scriptname[21]; + + qsort(&profiles[0], profiles.Size(), sizeof(ProfileCollector), sort_by_total_instr); + + if (ilimit > 0) + { + Printf(TEXTCOLOR_ORANGE "Top %ld %ss:\n", ilimit, typelabels[functions]); + limit = (unsigned int)ilimit; + } + else + { + Printf(TEXTCOLOR_ORANGE "All %ss:\n", typelabels[functions]); + limit = UINT_MAX; + } + + Printf(TEXTCOLOR_YELLOW "Module %-20s Total NumRuns Min Max Avg\n", typelabels[functions]); + Printf(TEXTCOLOR_YELLOW "------------ -------------------- ---------- ------- ------- ------- -------\n"); + for (unsigned int i = 0; i < limit && i < profiles.Size(); ++i) + { + ProfileCollector *prof = &profiles[i]; + if (prof->ProfileData->NumRuns == 0) + { // Don't list ones that haven't run. + continue; + } + + // Module name + mysnprintf(modname, sizeof(modname), prof->Module->GetModuleName()); +#if 0 + if (prof->Module == FBehavior::StaticGetModule(0)) + { + mysnprintf(modname, sizeof(modname), ""); + } + else + { + mysnprintf(modname, sizeof(modname), Wads.GetLumpFullName(prof->Module->GetLumpNum())); + } +#endif + // Script/function name + if (functions) + { + DWORD *fnames = (DWORD *)prof->Module->FindChunk(MAKE_ID('F','N','A','M')); + if (prof->Index >= 0 && prof->Index < (int)LittleLong(fnames[2])) + { + mysnprintf(scriptname, sizeof(scriptname), "%s", + (char *)(fnames + 2) + LittleLong(fnames[3+prof->Index])); + } + else + { + mysnprintf(scriptname, sizeof(scriptname), "Function %d", prof->Index); + } + } + else + { + mysnprintf(scriptname, sizeof(scriptname), "%s", + ScriptPresentation(prof->Module->GetScriptPtr(prof->Index)->Number).GetChars() + 7); + } + Printf("%-12s %-20s%11llu%8u%8u%8u%8u\n", + modname, scriptname, + prof->ProfileData->TotalInstr, + prof->ProfileData->NumRuns, + prof->ProfileData->MinInstrPerRun, + prof->ProfileData->MaxInstrPerRun, + prof->ProfileData->TotalInstr / prof->ProfileData->NumRuns); + } +} + +CCMD(acsprofile) +{ + TArray ScriptProfiles, FuncProfiles; + long limit = 10; + + ArrangeScriptProfiles(ScriptProfiles); + ArrangeFunctionProfiles(FuncProfiles); + + if (argv.argc() > 1) + { + limit = strtol(argv[1], NULL, 0); + } + + ShowProfileData(ScriptProfiles, limit, false); + ShowProfileData(FuncProfiles, limit, true); +} diff --git a/src/p_acs.h b/src/p_acs.h index 999dda7a5..ee1d09c4c 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -74,6 +74,24 @@ void P_WriteACSVars(FILE*); void P_ClearACSVars(bool); void P_SerializeACSScriptNumber(FArchive &arc, int &scriptnum, bool was2byte); +struct ACSProfileInfo +{ + unsigned long long TotalInstr; + unsigned int NumRuns; + unsigned int MinInstrPerRun; + unsigned int MaxInstrPerRun; + + ACSProfileInfo(); + void AddRun(unsigned int num_instr); +}; + +struct ProfileCollector +{ + ACSProfileInfo *ProfileData; + class FBehavior *Module; + int Index; +}; + // The in-memory version struct ScriptPtr { @@ -83,6 +101,8 @@ struct ScriptPtr BYTE ArgCount; WORD VarCount; WORD Flags; + + ACSProfileInfo ProfileData; }; // The present ZDoom version @@ -177,7 +197,12 @@ public: int FindMapArray (const char *arrayname) const; int GetLibraryID () const { return LibraryID; } int *GetScriptAddress (const ScriptPtr *ptr) const { return (int *)(ptr->Address + Data); } - + int GetScriptIndex (const ScriptPtr *ptr) const { ptrdiff_t index = ptr - Scripts; return index >= NumScripts ? -1 : (int)index; } + ScriptPtr *GetScriptPtr(int index) const { return index >= 0 && index < NumScripts ? &Scripts[index] : NULL; } + int GetLumpNum() const { return LumpNum; } + const char *GetModuleName() const { return ModuleName; } + ACSProfileInfo *GetFunctionProfileData(int index) { return index >= 0 && index < NumFunctions ? &FunctionProfileData[index] : NULL; } + ACSProfileInfo *GetFunctionProfileData(ScriptFunction *func) { return GetFunctionProfileData((int)(func - (ScriptFunction *)Functions)); } SDWORD *MapVars[NUM_MAPVARS]; static FBehavior *StaticLoadModule (int lumpnum, FileReader * fr=NULL, int len=0); @@ -204,6 +229,7 @@ private: ScriptPtr *Scripts; int NumScripts; BYTE *Functions; + ACSProfileInfo *FunctionProfileData; int NumFunctions; ArrayInfo *ArrayStore; int NumArrays; @@ -228,6 +254,9 @@ private: void SerializeVars (FArchive &arc); void SerializeVarSet (FArchive &arc, SDWORD *vars, int max); + + friend void ArrangeScriptProfiles(TArray &profiles); + friend void ArrangeFunctionProfiles(TArray &profiles); }; class DLevelScript : public DObject @@ -713,6 +742,7 @@ protected: int ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight; int WrapWidth; FBehavior *activeBehavior; + int InModuleScriptNumber; void Link (); void Unlink (); From b971714e7f11687870ecdda8bb04d75b90d5ceb9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 3 Feb 2013 03:54:31 +0000 Subject: [PATCH 129/387] - Do not print imported functions in the profile list. SVN r4059 (trunk) --- src/p_acs.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 95899a599..bac4c0092 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7761,9 +7761,13 @@ void ArrangeFunctionProfiles(TArray &profiles) prof.Module = module; for (int i = 0; i < module->NumFunctions; ++i) { - prof.Index = i; - prof.ProfileData = module->FunctionProfileData + i; - profiles.Push(prof); + ScriptFunction *func = (ScriptFunction *)module->Functions + i; + if (func->ImportNum == 0) + { + prof.Index = i; + prof.ProfileData = module->FunctionProfileData + i; + profiles.Push(prof); + } } } } From f68d5a484586893ba3b9bcd8ca447ce79d51521b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 3 Feb 2013 04:30:20 +0000 Subject: [PATCH 130/387] - More options for acsprofile command: * acsprofile clear - Resets all profiling statistics to 0. * acsprofile [] []: * is an optional argument that specifies which column to sort on (total, min, max, avg, or runs). The default is total. * is an optional argument that specifies how many rows to limit the output to. The default is 10. 0 or less will print every script or function that has at least one run. SVN r4060 (trunk) --- src/p_acs.cpp | 130 +++++++++++++++++++++++++++++++++++++++++++------- src/p_acs.h | 1 + 2 files changed, 113 insertions(+), 18 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bac4c0092..3e4f349dc 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7715,6 +7715,11 @@ void DACSThinker::DumpScriptStatus () // Profiling support -------------------------------------------------------- ACSProfileInfo::ACSProfileInfo() +{ + Reset(); +} + +void ACSProfileInfo::Reset() { TotalInstr = 0; NumRuns = 0; @@ -7772,6 +7777,14 @@ void ArrangeFunctionProfiles(TArray &profiles) } } +void ClearProfiles(TArray &profiles) +{ + for (unsigned int i = 0; i < profiles.Size(); ++i) + { + profiles[i].ProfileData->Reset(); + } +} + static int STACK_ARGS sort_by_total_instr(const void *a_, const void *b_) { const ProfileCollector *a = (const ProfileCollector *)a_; @@ -7782,7 +7795,42 @@ static int STACK_ARGS sort_by_total_instr(const void *a_, const void *b_) return (int)(b->ProfileData->TotalInstr - a->ProfileData->TotalInstr); } -static void ShowProfileData(TArray &profiles, long ilimit, bool functions) +static int STACK_ARGS sort_by_min(const void *a_, const void *b_) +{ + const ProfileCollector *a = (const ProfileCollector *)a_; + const ProfileCollector *b = (const ProfileCollector *)b_; + + return b->ProfileData->MinInstrPerRun - a->ProfileData->MinInstrPerRun; +} + +static int STACK_ARGS sort_by_max(const void *a_, const void *b_) +{ + const ProfileCollector *a = (const ProfileCollector *)a_; + const ProfileCollector *b = (const ProfileCollector *)b_; + + return b->ProfileData->MaxInstrPerRun - a->ProfileData->MaxInstrPerRun; +} + +static int STACK_ARGS sort_by_avg(const void *a_, const void *b_) +{ + const ProfileCollector *a = (const ProfileCollector *)a_; + const ProfileCollector *b = (const ProfileCollector *)b_; + + int a_avg = a->ProfileData->NumRuns == 0 ? 0 : int(a->ProfileData->TotalInstr / a->ProfileData->NumRuns); + int b_avg = b->ProfileData->NumRuns == 0 ? 0 : int(b->ProfileData->TotalInstr / b->ProfileData->NumRuns); + return b_avg - a_avg; +} + +static int STACK_ARGS sort_by_runs(const void *a_, const void *b_) +{ + const ProfileCollector *a = (const ProfileCollector *)a_; + const ProfileCollector *b = (const ProfileCollector *)b_; + + return b->ProfileData->NumRuns - a->ProfileData->NumRuns; +} + +static void ShowProfileData(TArray &profiles, long ilimit, + int (STACK_ARGS *sorter)(const void *, const void *), bool functions) { static const char *const typelabels[2] = { "script", "function" }; @@ -7795,7 +7843,7 @@ static void ShowProfileData(TArray &profiles, long ilimit, boo char modname[13]; char scriptname[21]; - qsort(&profiles[0], profiles.Size(), sizeof(ProfileCollector), sort_by_total_instr); + qsort(&profiles[0], profiles.Size(), sizeof(ProfileCollector), sorter); if (ilimit > 0) { @@ -7808,7 +7856,7 @@ static void ShowProfileData(TArray &profiles, long ilimit, boo limit = UINT_MAX; } - Printf(TEXTCOLOR_YELLOW "Module %-20s Total NumRuns Min Max Avg\n", typelabels[functions]); + Printf(TEXTCOLOR_YELLOW "Module %-20s Total Runs Avg Min Max\n", typelabels[functions]); Printf(TEXTCOLOR_YELLOW "------------ -------------------- ---------- ------- ------- ------- -------\n"); for (unsigned int i = 0; i < limit && i < profiles.Size(); ++i) { @@ -7820,16 +7868,7 @@ static void ShowProfileData(TArray &profiles, long ilimit, boo // Module name mysnprintf(modname, sizeof(modname), prof->Module->GetModuleName()); -#if 0 - if (prof->Module == FBehavior::StaticGetModule(0)) - { - mysnprintf(modname, sizeof(modname), ""); - } - else - { - mysnprintf(modname, sizeof(modname), Wads.GetLumpFullName(prof->Module->GetLumpNum())); - } -#endif + // Script/function name if (functions) { @@ -7853,25 +7892,80 @@ static void ShowProfileData(TArray &profiles, long ilimit, boo modname, scriptname, prof->ProfileData->TotalInstr, prof->ProfileData->NumRuns, + unsigned(prof->ProfileData->TotalInstr / prof->ProfileData->NumRuns), prof->ProfileData->MinInstrPerRun, - prof->ProfileData->MaxInstrPerRun, - prof->ProfileData->TotalInstr / prof->ProfileData->NumRuns); + prof->ProfileData->MaxInstrPerRun + ); } } CCMD(acsprofile) { + static int (STACK_ARGS *sort_funcs[])(const void*, const void *) = + { + sort_by_total_instr, + sort_by_min, + sort_by_max, + sort_by_avg, + sort_by_runs + }; + static const char *sort_names[] = { "total", "min", "max", "avg", "runs" }; + static const BYTE sort_match_len[] = { 1, 2, 2, 1, 1 }; + TArray ScriptProfiles, FuncProfiles; long limit = 10; + int (STACK_ARGS *sorter)(const void *, const void *) = sort_by_total_instr; + + assert(countof(sort_names) == countof(sort_match_len)); ArrangeScriptProfiles(ScriptProfiles); ArrangeFunctionProfiles(FuncProfiles); if (argv.argc() > 1) { - limit = strtol(argv[1], NULL, 0); + // `acsprofile clear` will zero all profiling information collected so far. + if (stricmp(argv[1], "clear") == 0) + { + ClearProfiles(ScriptProfiles); + ClearProfiles(FuncProfiles); + return; + } + for (int i = 1; i < argv.argc(); ++i) + { + // If it's a number, set the display limit. + char *endptr; + long num = strtol(argv[i], &endptr, 0); + if (endptr != argv[i]) + { + limit = num; + continue; + } + // If it's a name, set the sort method. We accept partial matches for + // options that are shorter than the sort name. + size_t optlen = strlen(argv[i]); + int j; + for (j = 0; j < countof(sort_names); ++j) + { + if (optlen < sort_match_len[j] || optlen > strlen(sort_names[j])) + { // Too short or long to match. + continue; + } + if (strnicmp(argv[i], sort_names[j], optlen) == 0) + { + sorter = sort_funcs[j]; + break; + } + } + if (j == countof(sort_names)) + { + Printf("Unknown option '%s'\n", argv[i]); + Printf("acsprofile clear : Reset profiling information\n"); + Printf("acsprofile [total|min|max|avg|runs] []\n"); + return; + } + } } - ShowProfileData(ScriptProfiles, limit, false); - ShowProfileData(FuncProfiles, limit, true); + ShowProfileData(ScriptProfiles, limit, sorter, false); + ShowProfileData(FuncProfiles, limit, sorter, true); } diff --git a/src/p_acs.h b/src/p_acs.h index ee1d09c4c..e4eadf3b0 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -83,6 +83,7 @@ struct ACSProfileInfo ACSProfileInfo(); void AddRun(unsigned int num_instr); + void Reset(); }; struct ProfileCollector From f0bc2fdc536fd2518792db693ce99321c74f5e51 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 5 Feb 2013 01:45:23 +0000 Subject: [PATCH 131/387] - Fixed CF_DOUBLEFIRINGSPEED is in player->cheats, not player->WeaponState. SVN r4061 (trunk) --- src/p_pspr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 54b56937d..a4310efd4 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1037,7 +1037,7 @@ void P_MovePsprites (player_t *player) psp->tics--; // [BC] Apply double firing speed. - if ( psp->tics && (player->WeaponState & CF_DOUBLEFIRINGSPEED)) + if ( psp->tics && (player->cheats & CF_DOUBLEFIRINGSPEED)) psp->tics--; if(!psp->tics) From 87b8b6201cfce58b88cdf01f3354946d5fba37da Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 5 Feb 2013 02:27:35 +0000 Subject: [PATCH 132/387] - Added WRF_DISABLESWITCH flag for A_WeaponReady to indicate that any attempts to switch the weapon should be discarded. SVN r4062 (trunk) --- src/d_player.h | 1 + src/p_pspr.cpp | 61 +++++++++++++++++++++--------- wadsrc/static/actors/constants.txt | 3 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 1b26bb776..76c70819d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -212,6 +212,7 @@ enum WF_WEAPONBOBBING = 1 << 1, // [HW] Bob weapon while the player is moving WF_WEAPONREADYALT = 1 << 2, // Weapon can fire its secondary attack WF_WEAPONSWITCHOK = 1 << 3, // It is okay to switch away from this weapon + WF_DISABLESWITCH = 1 << 4, // Disable weapon switching completely WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. }; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index a4310efd4..192514058 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -352,6 +352,12 @@ void P_ZoomWeapon (player_t *player, FState *state) void P_DropWeapon (player_t *player) { + if (player == NULL) + { + return; + } + // Since the weapon is dropping, stop blocking switching. + player->WeaponState &= ~WF_DISABLESWITCH; if (player->ReadyWeapon != NULL) { P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetDownState()); @@ -471,7 +477,7 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y) // //============================================================================ -void DoReadyWeaponToSwitch (AActor * self) +void DoReadyWeaponToSwitch (AActor *self) { // Prepare for switching action. player_t *player; @@ -479,7 +485,24 @@ void DoReadyWeaponToSwitch (AActor * self) player->WeaponState |= WF_WEAPONSWITCHOK; } -void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) +void DoReadyWeaponDisableSwitch (AActor *self, INTBOOL disable) +{ + // Discard all switch attempts? + player_t *player; + if (self && (player = self->player)) + { + if (disable) + { + player->WeaponState |= WF_DISABLESWITCH; + } + else + { + player->WeaponState &= ~WF_DISABLESWITCH; + } + } +} + +void DoReadyWeaponToFire (AActor *self, bool prim, bool alt) { player_t *player; AWeapon *weapon; @@ -510,7 +533,7 @@ void DoReadyWeaponToFire (AActor * self, bool prim, bool alt) return; } -void DoReadyWeaponToBob (AActor * self) +void DoReadyWeaponToBob (AActor *self) { if (self && self->player && self->player->ReadyWeapon) { @@ -521,7 +544,7 @@ void DoReadyWeaponToBob (AActor * self) } } -void DoReadyWeaponToReload (AActor * self) +void DoReadyWeaponToReload (AActor *self) { // Prepare for reload action. player_t *player; @@ -530,7 +553,7 @@ void DoReadyWeaponToReload (AActor * self) return; } -void DoReadyWeaponToZoom (AActor * self) +void DoReadyWeaponToZoom (AActor *self) { // Prepare for reload action. player_t *player; @@ -540,7 +563,7 @@ void DoReadyWeaponToZoom (AActor * self) } // This function replaces calls to A_WeaponReady in other codepointers. -void DoReadyWeapon(AActor * self) +void DoReadyWeapon(AActor *self) { DoReadyWeaponToBob(self); DoReadyWeaponToFire(self); @@ -558,6 +581,7 @@ enum EWRF_Options WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, WRF_AllowReload = 16, WRF_AllowZoom = 32, + WRF_DisableSwitch = 64, }; DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) @@ -570,6 +594,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); + + DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); } //--------------------------------------------------------------------------- @@ -625,22 +651,23 @@ void P_CheckWeaponFire (player_t *player) void P_CheckWeaponSwitch (player_t *player) { - AWeapon *weapon; - - if (!player || !(weapon = player->ReadyWeapon)) - return; - - // Put the weapon away if the player has a pending weapon or has died. - if ((player->morphTics == 0 && player->PendingWeapon != WP_NOCHANGE) || player->health <= 0) + if (player == NULL) { - P_DropWeapon(player); return; } - else if (player->morphTics != 0) - { - // morphed classes cannot change weapons so don't even try again. + if ((player->WeaponState & WF_DISABLESWITCH) || // Weapon changing has been disabled. + player->morphTics != 0) // Morphed classes cannot change weapons. + { // ...so throw away any pending weapon requests. player->PendingWeapon = WP_NOCHANGE; } + + // Put the weapon away if the player has a pending weapon or has died, and + // we're at a place in the state sequence where dropping the weapon is okay. + if ((player->PendingWeapon != WP_NOCHANGE || player->health <= 0) && + player->WeaponState & WF_WEAPONSWITCHOK) + { + P_DropWeapon(player); + } } //--------------------------------------------------------------------------- diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index a8bcf26b8..3280f53d2 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -92,12 +92,13 @@ const int CVF_REPLACE = 2; // Flags for A_WeaponReady const int WRF_NOBOB = 1; -const int WRF_NOFIRE = 12; const int WRF_NOSWITCH = 2; const int WRF_NOPRIMARY = 4; const int WRF_NOSECONDARY = 8; +const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWZOOM = 32; +const int WRF_DISABLESWITCH = 64; // Morph constants const int MRF_ADDSTAMINA = 1; From 2f3dd8d959a9e5e8793aad7f44a840783d152dae Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 5 Feb 2013 02:33:11 +0000 Subject: [PATCH 133/387] - Moved MF4_BOSSSPAWNED flag copying from A_PainShootSkull to AActor::CopyFriendliness(). SVN r4063 (trunk) --- src/g_doom/a_painelemental.cpp | 3 --- src/p_mobj.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp index db7d83021..b52224c0c 100644 --- a/src/g_doom/a_painelemental.cpp +++ b/src/g_doom/a_painelemental.cpp @@ -111,9 +111,6 @@ void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int other = Spawn (spawntype, x, y, z, ALLOW_REPLACE); - // Transfer boss-spawned flag - other->flags4 |= self->flags4 & MF4_BOSSSPAWNED; - // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 35d3c4718..f2a974e82 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -820,7 +820,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt LastLookPlayerNumber = other->LastLookPlayerNumber; flags = (flags & ~MF_FRIENDLY) | (other->flags & MF_FRIENDLY); flags3 = (flags3 & ~(MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)) | (other->flags3 & (MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)); - flags4 = (flags4 & ~MF4_NOHATEPLAYERS) | (other->flags4 & MF4_NOHATEPLAYERS); + flags4 = (flags4 & ~(MF4_NOHATEPLAYERS | MF4_BOSSSPAWNED)) | (other->flags4 & (MF4_NOHATEPLAYERS | MF4_BOSSSPAWNED)); FriendPlayer = other->FriendPlayer; DesignatedTeam = other->DesignatedTeam; if (changeTarget && other->target != NULL && !(other->target->flags3 & MF3_NOTARGET)) From 995d6f52e73135ad2be21899c1f9b69aac175eb8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 5 Feb 2013 02:39:47 +0000 Subject: [PATCH 134/387] - Allow terrain definitions to work with overrides and non-flats. SVN r4064 (trunk) --- src/p_terrain.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index c3df86b27..fdd98c96a 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -631,7 +631,8 @@ static void ParseFloor (FScanner &sc) int terrain; sc.MustGetString (); - picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Flat); + picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Flat, + FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny); if (!picnum.Exists()) { Printf ("Unknown flat %s\n", sc.String); @@ -650,7 +651,7 @@ static void ParseFloor (FScanner &sc) //========================================================================== // -// ParseFloor +// ParseDefault // //========================================================================== From 8874cb140bf08d354f4978ce50fafc453469148c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 20:17:50 +0000 Subject: [PATCH 135/387] - Don't use the global numsectors variable when testing if a map is a Build map in P_IsBuildMap() and P_LoadBuildMap(). SVN r4065 (trunk) --- src/p_buildmap.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index af0819764..417343f21 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -175,12 +175,12 @@ bool P_IsBuildMap(MapData *map) return true; } - numsectors = LittleShort(*(WORD *)(data + 20)); + const int numsec = LittleShort(*(WORD *)(data + 20)); int numwalls; - if (len < 26 + numsectors*sizeof(sectortype) || - (numwalls = LittleShort(*(WORD *)(data + 22 + numsectors*sizeof(sectortype))), - len < 24 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)) || + if (len < 26 + numsec*sizeof(sectortype) || + (numwalls = LittleShort(*(WORD *)(data + 22 + numsec*sizeof(sectortype))), + len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) || LittleLong(*(DWORD *)data) != 7 || LittleShort(*(WORD *)(data + 16)) >= 2048) { // Can't possibly be a version 7 BUILD map @@ -210,19 +210,20 @@ bool P_LoadBuildMap (BYTE *data, size_t len, FMapThing **sprites, int *numspr) return P_LoadBloodMap (data, len, sprites, numspr); } - numsectors = LittleShort(*(WORD *)(data + 20)); + const int numsec = LittleShort(*(WORD *)(data + 20)); int numwalls; int numsprites; - if (len < 26 + numsectors*sizeof(sectortype) || - (numwalls = LittleShort(*(WORD *)(data + 22 + numsectors*sizeof(sectortype))), - len < 24 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)) || + if (len < 26 + numsec*sizeof(sectortype) || + (numwalls = LittleShort(*(WORD *)(data + 22 + numsec*sizeof(sectortype))), + len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) || LittleLong(*(DWORD *)data) != 7 || LittleShort(*(WORD *)(data + 16)) >= 2048) { // Can't possibly be a version 7 BUILD map return false; } + numsectors = numsec; LoadSectors ((sectortype *)(data + 22)); LoadWalls ((walltype *)(data + 24 + numsectors*sizeof(sectortype)), numwalls, (sectortype *)(data + 22)); From 522a940ccf06d99ac8cf22717d4bc6e7ab86cd83 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 20:29:48 +0000 Subject: [PATCH 136/387] - In P_SetSafeFlash(), check the requested state against every actor when Dehacked moves the flash to some other class's states instead of just assuming it's good. SVN r4066 (trunk) --- src/g_doom/a_doomweaps.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 642c319ec..0063e72c9 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -308,7 +308,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2) // //------------------------------------------------------------------------------------ -void P_SetSafeFlash(AWeapon * weapon, player_t * player, FState * flashstate, int index) +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) { const PClass * cls = weapon->GetClass(); @@ -337,9 +337,13 @@ void P_SetSafeFlash(AWeapon * weapon, player_t * player, FState * flashstate, in } // if we get here the state doesn't seem to belong to any class in the inheritance chain // This can happen with Dehacked if the flash states are remapped. - // The only way to check this would be to go through all Dehacked modifiable actors and - // find the correct one. - // For now let's assume that it will work. + // The only way to check this would be to go through all Dehacked modifiable actors, convert + // their states into a single flat array and find the correct one. + // Rather than that, just check to make sure it belongs to something. + if (FState::StaticFindStateOwner(flashstate + index) == NULL) + { // Invalid state. With no index offset, it should at least be valid. + index = 0; + } P_SetPsprite (player, ps_flash, flashstate + index); } From 2cf141e914a43d09b8a7eb195cef82614c78c4f2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 20:38:41 +0000 Subject: [PATCH 137/387] - In A_ReFire, allow refiring when a weapon is pending, but weapon switching is not okay at this time. SVN r4067 (trunk) --- src/p_pspr.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 192514058..1b4e0b55a 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -733,21 +733,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_ReFire) void A_ReFire(AActor *self, FState *state) { player_t *player = self->player; + bool pending; if (NULL == player) { return; } - if ((player->cmd.ucmd.buttons&BT_ATTACK) - && !player->ReadyWeapon->bAltFire - && player->PendingWeapon == WP_NOCHANGE && player->health) + pending = player->PendingWeapon == WP_NOCHANGE && (player->WeaponState & WF_WEAPONSWITCHOK); + if ((player->cmd.ucmd.buttons & BT_ATTACK) + && !player->ReadyWeapon->bAltFire && !pending && player->health > 0) { player->refire++; P_FireWeapon (player, state); } - else if ((player->cmd.ucmd.buttons&BT_ALTATTACK) - && player->ReadyWeapon->bAltFire - && player->PendingWeapon == WP_NOCHANGE && player->health) + else if ((player->cmd.ucmd.buttons & BT_ALTATTACK) + && player->ReadyWeapon->bAltFire && !pending && player->health > 0) { player->refire++; P_FireWeaponAlt (player, state); @@ -826,10 +826,6 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) P_SetPsprite (player, ps_weapon, NULL); return; } -/* if (player->PendingWeapon != WP_NOCHANGE) - { // [RH] Make sure we're actually changing weapons. - player->ReadyWeapon = player->PendingWeapon; - } */ // [RH] Clear the flash state. Only needed for Strife. P_SetPsprite (player, ps_flash, NULL); P_BringUpWeapon (player); From cdfd671dffc7b3941ad5bae3f83e7c35caf6e2b0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 20:42:24 +0000 Subject: [PATCH 138/387] - P_MovePsprites() should now always call P_CheckWeaponSwitch(), because the latter function now has its own WF_WEAPONSWITCHOK check in the correct place. SVN r4068 (trunk) --- src/p_pspr.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 1b4e0b55a..6a2176458 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1072,10 +1072,7 @@ void P_MovePsprites (player_t *player) } player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - if (player->WeaponState & WF_WEAPONSWITCHOK) - { - P_CheckWeaponSwitch (player); - } + P_CheckWeaponSwitch (player); if (player->WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) { P_CheckWeaponFire (player); From c11645315860c53faf3646f1fc24f1aad4886939 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 21:02:26 +0000 Subject: [PATCH 139/387] - When doing kickback in P_DamageMobj(), choose a random direction if the target and origin are in the exact same spot. SVN r4069 (trunk) --- src/p_interaction.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 3004022e4..51527a266 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -66,6 +66,7 @@ static FRandom pr_damagemobj ("ActorTakeDamage"); static FRandom pr_lightning ("LightningDamage"); static FRandom pr_poison ("PoisonDamage"); static FRandom pr_switcher ("SwitchTarget"); +static FRandom pr_kickbackdir ("KickbackDir"); CVAR (Bool, cl_showsprees, true, CVAR_ARCHIVE) CVAR (Bool, cl_showmultikills, true, CVAR_ARCHIVE) @@ -1073,9 +1074,18 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (kickback) { AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; - - ang = R_PointToAngle2 (origin->x, origin->y, - target->x, target->y); + + // If the origin and target are in exactly the same spot, choose a random direction. + // (Most likely cause is from telefragging somebody during spawning because they + // haven't moved from their spawn spot at all.) + if (origin->x == target->x && origin->y == target->y) + { + ang = pr_kickbackdir.GenRand32(); + } + else + { + ang = R_PointToAngle2 (origin->x, origin->y, target->x, target->y); + } // Calculate this as float to avoid overflows so that the // clamping that had to be done here can be removed. From 6e3d784c507864fe6a7c1d54b3b130b516c59e47 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 21:09:55 +0000 Subject: [PATCH 140/387] - Fixed: G_CheckSpot() should not use the player start's z position unless LEVEL_USEPLAYERSTARTZ is set. SVN r4070 (trunk) --- src/g_game.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index fd8489f9a..48c4a3b7a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1385,6 +1385,10 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) y = mthing->y; z = mthing->z; + if (!(level.flags & LEVEL_USEPLAYERSTARTZ)) + { + z = 0; + } z += P_PointInSector (x, y)->floorplane.ZatPoint (x, y); if (!players[playernum].mo) From afabf7e018ad369d3bc9294ec595e9ff351100a6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 21:32:06 +0000 Subject: [PATCH 141/387] - Force node building for garrison.wad from The Master Levels so that the teleporter to the red key won't leave you in the ground. SVN r4071 (trunk) --- src/compatibility.cpp | 1 + src/doomdef.h | 1 + src/p_setup.cpp | 4 ++++ wadsrc/static/compatibility.txt | 5 +++++ 4 files changed, 11 insertions(+) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index f145b5ad9..839d60dc5 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -102,6 +102,7 @@ static FCompatOption Options[] = { "resetplayerspeed", BCOMPATF_RESETPLAYERSPEED, SLOT_BCOMPAT }, { "vileghosts", BCOMPATF_VILEGHOSTS, SLOT_BCOMPAT }, { "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT }, + { "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT }, // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT }, diff --git a/src/doomdef.h b/src/doomdef.h index f7e6c959e..3a3c31e6a 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -348,6 +348,7 @@ enum BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected. BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior + BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild }; // phares 3/20/98: diff --git a/src/p_setup.cpp b/src/p_setup.cpp index ee596a74c..4cd337ca5 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3607,6 +3607,10 @@ void P_SetupLevel (char *lumpname, int position) level.maptype = MAPTYPE_UDMF; } CheckCompatibility(map); + if (ib_compatflags & BCOMPATF_REBUILDNODES) + { + ForceNodeBuild = true; + } T_LoadScripts(map); if (!map->HasBehavior || map->isText) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index f381155bd..c6c682f21 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -330,3 +330,8 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 setwallyscale 716 front bot 1.090909 setwallyscale 717 front bot 1.090909 } + +65A1EB4C87386F290816660A52932FF1 // Master Levels, garrison.wad +{ + rebuildnodes +} From 1e04a8821a27bb18417da5f414f4b286e3843383 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 22:22:07 +0000 Subject: [PATCH 142/387] Update DUMB to 6e159ab89b5df27acf8a182a1ea5bf307ba8ff95 - Fixed two bugs with pattern loops causing songs to loop forever SVN r4072 (trunk) --- dumb/src/it/itrender.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 6ea048278..2ae54f3fc 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1211,6 +1211,8 @@ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY * if (!channel->played_patjump) channel->played_patjump = bit_array_create(256); else { + if ( channel->played_patjump_order != 0xFFFE && channel->played_patjump_order != sigrenderer->order ) + bit_array_merge(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); //if (channel->played_patjump_order != sigrenderer->order) bit_array_reset(channel->played_patjump); } @@ -1225,13 +1227,13 @@ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY * int n; bit_array_destroy(channel->played_patjump); channel->played_patjump = bit_array_create(256); - for (n = 0; n < 256; n++) + for (n = channel->pat_loop_row; n <= sigrenderer->row; n++) bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + n); channel->played_patjump_order = sigrenderer->order; } else if (channel->played_patjump_order == sigrenderer->order) { bit_array_set(channel->played_patjump, sigrenderer->row); bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); - bit_array_reset(channel->played_patjump); + //bit_array_reset(channel->played_patjump); } #endif channel->pat_loop_count = v; @@ -1258,7 +1260,7 @@ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY * if (channel->played_patjump_order == sigrenderer->order) { bit_array_set(channel->played_patjump, sigrenderer->row); bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); - bit_array_reset(channel->played_patjump); + //bit_array_reset(channel->played_patjump); } #endif sigrenderer->breakrow = channel->pat_loop_row; From 492caf6ceb33e7769bde2124c861bcc6d5e02a2e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 22:23:55 +0000 Subject: [PATCH 143/387] Update DUMB to revision ca554279a235b23c7f5f6ff9ce478a7aa7250dfe - Fixed channel muting when switching or restarting songs, or when seeking SVN r4073 (trunk) --- dumb/src/it/itrender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 2ae54f3fc..ac5345d8d 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -5063,7 +5063,7 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_ } } - while (pos >= sigrenderer->time_left) { + while (pos > 0 && pos >= sigrenderer->time_left) { render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL); pos -= sigrenderer->time_left; From aad103c8d5ff2cb2673fca5e046787cc0b47863d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 22:24:45 +0000 Subject: [PATCH 144/387] Update DUMB to revision 1a9e0d4fd889dc9d17a5ebe97825be0cb2b7a273 - Added range checking for XM global volume command SVN r4074 (trunk) --- dumb/src/it/xmeffect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dumb/src/it/xmeffect.c b/dumb/src/it/xmeffect.c index 2187a0b3f..f0f8820ff 100644 --- a/dumb/src/it/xmeffect.c +++ b/dumb/src/it/xmeffect.c @@ -167,6 +167,7 @@ if (log) printf(" - %2d %02X", effect, value); case XM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; value *= 2; + if (value > 128) value = 128; break; case XM_KEY_OFF: From 13ffa8a1b88453d9d3719e1ac7fbb06d454f5e5a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 22:25:58 +0000 Subject: [PATCH 145/387] Update DUMB to revision a9176165a2ccc56410b2004d2f5dd40b2052453a - Changed a break to row behavior in DUMB, hopefully it doesn't break anything SVN r4075 (trunk) --- dumb/src/it/itrender.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index ac5345d8d..24530156d 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1292,8 +1292,8 @@ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY * - If we jump, then effect a loop using an old E60, and then the pattern ends, the next pattern starts on the row corresponding to the E60. - Theory: breakrow is not cleared when it's a pattern loop effect! */ - //if (sigrenderer->processrow < 0xFFFE) // I have no idea if this is correct or not - FT2 is so weird :( - // sigrenderer->breakrow = channel->pat_loop_row; /* emulate bug in FT2 */ + if ((sigrenderer->processrow | 0xC00) < 0xFFFE) // I have no idea if this is correct or not - FT2 is so weird :( + sigrenderer->breakrow = channel->pat_loop_row; /* emulate bug in FT2 */ } else channel->pat_loop_row = sigrenderer->processrow + 1; #ifdef BIT_ARRAY_BULLSHIT @@ -3832,8 +3832,10 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) sigrenderer->processrow = sigrenderer->breakrow; sigrenderer->breakrow = 0; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) sigrenderer->channel[n].pat_loop_end_row = 0; - } else + } else { sigrenderer->processrow = sigrenderer->breakrow; + sigrenderer->breakrow = 0; // XXX lolwut + } if (sigrenderer->processorder == 0xFFFF) sigrenderer->processorder = sigrenderer->order - 1; From 401ee8fafba7019d9ae08d927b7b05a7b57ef4df Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 23:21:36 +0000 Subject: [PATCH 146/387] Update DUMB to revision 9ac6cf69758fe0db6d6e654f298cd36efdb73366 - Replaced old aliased resampling mode with a 65536x oversampling sinc resampler SVN r4076 (trunk) --- dumb/CMakeLists.txt | 1 + dumb/include/dumb.h | 5 + dumb/include/internal/blip_buf.h | 77 ++++++ dumb/src/helpers/blip_buf.c | 354 ++++++++++++++++++++++++ dumb/src/helpers/resamp2.inc | 9 +- dumb/src/helpers/resamp3.inc | 85 +++--- dumb/src/helpers/resample.c | 6 +- dumb/src/helpers/resample.inc | 116 ++++++-- dumb/src/it/itrender.c | 106 +++++-- dumb/vc6/dumb_static/dumb_static.vcproj | 8 + 10 files changed, 682 insertions(+), 85 deletions(-) create mode 100644 dumb/include/internal/blip_buf.h create mode 100644 dumb/src/helpers/blip_buf.c diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index c2cbe8d1b..c35dc7da0 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -36,6 +36,7 @@ add_library( dumb src/core/rendsig.c src/core/unload.c src/helpers/barray.c + src/helpers/blip_buf.c src/helpers/clickrem.c src/helpers/memfile.c src/helpers/resample.c diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index 09041ce3c..0b42b4d6d 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -662,6 +662,8 @@ typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO; typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data); +#include "internal/blip_buf.h" + struct DUMB_RESAMPLER { void *src; @@ -679,6 +681,9 @@ struct DUMB_RESAMPLER signed char x8[3*2]; } x; int overshot; + int last_clock; + int last_amp[2]; + blip_t* blip_buffer[2]; }; struct DUMB_VOLUME_RAMP_INFO diff --git a/dumb/include/internal/blip_buf.h b/dumb/include/internal/blip_buf.h new file mode 100644 index 000000000..7f687c3e9 --- /dev/null +++ b/dumb/include/internal/blip_buf.h @@ -0,0 +1,77 @@ +/** \file +Sample buffer that resamples from input clock rate to output sample rate */ + +/* blip_buf 1.1.0 */ +#ifndef BLIP_BUF_H +#define BLIP_BUF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** First parameter of most functions is blip_t*, or const blip_t* if nothing +is changed. */ +typedef struct blip_t blip_t; + +/** Creates new buffer that can hold at most sample_count samples. Sets rates +so that there are blip_max_ratio clocks per sample. Returns pointer to new +buffer, or NULL if insufficient memory. */ +blip_t* blip_new( int sample_count ); + +blip_t* blip_dup( blip_t* ); + +/** Sets approximate input clock rate and output sample rate. For every +clock_rate input clocks, approximately sample_rate samples are generated. */ +void blip_set_rates( blip_t*, double clock_rate, double sample_rate ); + +enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate, +clock_rate must not be greater than sample_rate*blip_max_ratio. */ +blip_max_ratio = 1 << 20 }; + +/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ +void blip_clear( blip_t* ); + +/** Adds positive/negative delta into buffer at specified clock time. */ +void blip_add_delta( blip_t*, unsigned int clock_time, int delta ); + +/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */ +void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta ); + +/** Length of time frame, in clocks, needed to make sample_count additional +samples available. */ +int blip_clocks_needed( const blip_t*, int sample_count ); + +enum { /** Maximum number of samples that can be generated from one time frame. */ +blip_max_frame = 4000 }; + +/** Makes input clocks before clock_duration available for reading as output +samples. Also begins new time frame at clock_duration, so that clock time 0 in +the new time frame specifies the same clock as clock_duration in the old time +frame specified. Deltas can have been added slightly past clock_duration (up to +however many clocks there are in two output samples). */ +void blip_end_frame( blip_t*, unsigned int clock_duration ); + +/** Number of buffered samples available for reading. */ +int blip_samples_avail( const blip_t* ); + +/** Reads and removes at most 'count' samples and writes them to 'out'. If +'stereo' is true, writes output to every other element of 'out', allowing easy +interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed +samples. Returns number of samples actually read. */ +int blip_read_samples( blip_t*, int out [], int count ); + +/** Reads the current integrator and returns it */ +int blip_peek_sample( blip_t* ); + +/** Frees buffer. No effect if NULL is passed. */ +void blip_delete( blip_t* ); + + +/* Deprecated */ +typedef blip_t blip_buffer_t; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/dumb/src/helpers/blip_buf.c b/dumb/src/helpers/blip_buf.c new file mode 100644 index 000000000..03c111198 --- /dev/null +++ b/dumb/src/helpers/blip_buf.c @@ -0,0 +1,354 @@ +/* blip_buf 1.1.0. http://www.slack.net/~ant/ */ + +#include "internal/blip_buf.h" + +#include +#include +#include +#include + +/* Library Copyright (C) 2003-2009 Shay Green. This library is free software; +you can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +library is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#if defined (BLARGG_TEST) && BLARGG_TEST + #include "blargg_test.h" +#endif + +/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000. +Avoids constants that don't fit in 32 bits. */ +#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF + typedef unsigned long fixed_t; + enum { pre_shift = 32 }; + +#elif defined(ULLONG_MAX) + typedef unsigned long long fixed_t; + enum { pre_shift = 32 }; + +#else + typedef unsigned fixed_t; + enum { pre_shift = 0 }; + +#endif + +enum { time_bits = pre_shift + 20 }; + +static fixed_t const time_unit = (fixed_t) 1 << time_bits; + +enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */ +enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */ + +enum { half_width = 8 }; +enum { buf_extra = half_width*2 + end_frame_extra }; +enum { phase_bits = 5 }; +enum { phase_count = 1 << phase_bits }; +enum { delta_bits = 15 }; +enum { delta_unit = 1 << delta_bits }; +enum { frac_bits = time_bits - pre_shift }; + +/* We could eliminate avail and encode whole samples in offset, but that would +limit the total buffered samples to blip_max_frame. That could only be +increased by decreasing time_bits, which would reduce resample ratio accuracy. +*/ + +/** Sample buffer that resamples to output rate and accumulates samples +until they're read out */ +struct blip_t +{ + fixed_t factor; + fixed_t offset; + int avail; + int size; + int integrator; +}; + +typedef int buf_t; + +/* probably not totally portable */ +#define SAMPLES( buf ) ((buf_t*) ((buf) + 1)) + +/* Arithmetic (sign-preserving) right shift */ +#define ARITH_SHIFT( n, shift ) \ + ((n) >> (shift)) + +enum { max_sample = +32767 }; +enum { min_sample = -32768 }; + +#define CLAMP( n ) \ + {\ + if ( (short) n != n )\ + n = ARITH_SHIFT( n, 16 ) ^ max_sample;\ + } + +static void check_assumptions( void ) +{ + int n; + + #if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF + #error "int must be at least 32 bits" + #endif + + assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */ + + n = max_sample * 2; + CLAMP( n ); + assert( n == max_sample ); + + n = min_sample * 2; + CLAMP( n ); + assert( n == min_sample ); + + assert( blip_max_ratio <= time_unit ); + assert( blip_max_frame <= (fixed_t) -1 >> time_bits ); +} + +blip_t* blip_new( int size ) +{ + blip_t* m; + assert( size >= 0 ); + + m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) ); + if ( m ) + { + m->factor = time_unit / blip_max_ratio; + m->size = size; + blip_clear( m ); + check_assumptions(); + } + return m; +} + +blip_t* blip_dup( blip_t* m ) +{ + size_t size = sizeof *m + (m->size + buf_extra) * sizeof(buf_t); + blip_t* r = (blip_t*) malloc( size ); + if ( r ) memcpy( r, m, size ); + return r; +} + +void blip_delete( blip_t* m ) +{ + if ( m != NULL ) + { + /* Clear fields in case user tries to use after freeing */ + memset( m, 0, sizeof *m ); + free( m ); + } +} + +void blip_set_rates( blip_t* m, double clock_rate, double sample_rate ) +{ + double factor = time_unit * sample_rate / clock_rate; + m->factor = (fixed_t) factor; + + /* Fails if clock_rate exceeds maximum, relative to sample_rate */ + assert( 0 <= factor - m->factor && factor - m->factor < 1 ); + + /* Avoid requiring math.h. Equivalent to + m->factor = (int) ceil( factor ) */ + if ( m->factor < factor ) + m->factor++; + + /* At this point, factor is most likely rounded up, but could still + have been rounded down in the floating-point calculation. */ +} + +void blip_clear( blip_t* m ) +{ + /* We could set offset to 0, factor/2, or factor-1. 0 is suitable if + factor is rounded up. factor-1 is suitable if factor is rounded down. + Since we don't know rounding direction, factor/2 accommodates either, + with the slight loss of showing an error in half the time. Since for + a 64-bit factor this is years, the halving isn't a problem. */ + + m->offset = m->factor / 2; + m->avail = 0; + m->integrator = 0; + memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) ); +} + +int blip_clocks_needed( const blip_t* m, int samples ) +{ + fixed_t needed; + + /* Fails if buffer can't hold that many more samples */ + assert( samples >= 0 && m->avail + samples <= m->size ); + + needed = (fixed_t) samples * time_unit; + if ( needed < m->offset ) + return 0; + + return (int)((needed - m->offset + m->factor - 1) / m->factor); +} + +void blip_end_frame( blip_t* m, unsigned t ) +{ + fixed_t off = t * m->factor + m->offset; + m->avail += (int)(off >> time_bits); + m->offset = off & (time_unit - 1); + + /* Fails if buffer size was exceeded */ + assert( m->avail <= m->size ); +} + +int blip_samples_avail( const blip_t* m ) +{ + return m->avail; +} + +static void remove_samples( blip_t* m, int count ) +{ + buf_t* buf = SAMPLES( m ); + int remain = m->avail + buf_extra - count; + m->avail -= count; + + memmove( &buf [0], &buf [count], remain * sizeof buf [0] ); + memset( &buf [remain], 0, count * sizeof buf [0] ); +} + +int blip_read_samples( blip_t* m, int out [], int count ) +{ + assert( count >= 0 ); + + if ( count > m->avail ) + count = m->avail; + + if ( count ) + { + buf_t const* in = SAMPLES( m ); + buf_t const* end = in + count; + int sum = m->integrator; + do + { + /* Eliminate fraction */ + int s = ARITH_SHIFT( sum, delta_bits - 8 ); + + sum += *in++; + + *out = s; + out++; + + /* High-pass filter */ + sum -= s >> (8 - (delta_bits - bass_shift)); //<< (delta_bits - bass_shift - 8); + } + while ( in != end ); + m->integrator = sum; + + remove_samples( m, count ); + } + + return count; +} + +int blip_peek_sample( blip_t* m ) +{ + return ARITH_SHIFT( m->integrator, delta_bits - 8 ); +} + +/* Things that didn't help performance on x86: + __attribute__((aligned(128))) + #define short int + restrict +*/ + +/* Sinc_Generator( 0.9, 0.55, 4.5 ) */ +static short const bl_step [phase_count + 1] [half_width] = +{ +{ 43, -115, 350, -488, 1136, -914, 5861,21022}, +{ 44, -118, 348, -473, 1076, -799, 5274,21001}, +{ 45, -121, 344, -454, 1011, -677, 4706,20936}, +{ 46, -122, 336, -431, 942, -549, 4156,20829}, +{ 47, -123, 327, -404, 868, -418, 3629,20679}, +{ 47, -122, 316, -375, 792, -285, 3124,20488}, +{ 47, -120, 303, -344, 714, -151, 2644,20256}, +{ 46, -117, 289, -310, 634, -17, 2188,19985}, +{ 46, -114, 273, -275, 553, 117, 1758,19675}, +{ 44, -108, 255, -237, 471, 247, 1356,19327}, +{ 43, -103, 237, -199, 390, 373, 981,18944}, +{ 42, -98, 218, -160, 310, 495, 633,18527}, +{ 40, -91, 198, -121, 231, 611, 314,18078}, +{ 38, -84, 178, -81, 153, 722, 22,17599}, +{ 36, -76, 157, -43, 80, 824, -241,17092}, +{ 34, -68, 135, -3, 8, 919, -476,16558}, +{ 32, -61, 115, 34, -60, 1006, -683,16001}, +{ 29, -52, 94, 70, -123, 1083, -862,15422}, +{ 27, -44, 73, 106, -184, 1152,-1015,14824}, +{ 25, -36, 53, 139, -239, 1211,-1142,14210}, +{ 22, -27, 34, 170, -290, 1261,-1244,13582}, +{ 20, -20, 16, 199, -335, 1301,-1322,12942}, +{ 18, -12, -3, 226, -375, 1331,-1376,12293}, +{ 15, -4, -19, 250, -410, 1351,-1408,11638}, +{ 13, 3, -35, 272, -439, 1361,-1419,10979}, +{ 11, 9, -49, 292, -464, 1362,-1410,10319}, +{ 9, 16, -63, 309, -483, 1354,-1383, 9660}, +{ 7, 22, -75, 322, -496, 1337,-1339, 9005}, +{ 6, 26, -85, 333, -504, 1312,-1280, 8355}, +{ 4, 31, -94, 341, -507, 1278,-1205, 7713}, +{ 3, 35, -102, 347, -506, 1238,-1119, 7082}, +{ 1, 40, -110, 350, -499, 1190,-1021, 6464}, +{ 0, 43, -115, 350, -488, 1136, -914, 5861} +}; + +/* Shifting by pre_shift allows calculation using unsigned int rather than +possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient. +And by having pre_shift 32, a 32-bit platform can easily do the shift by +simply ignoring the low half. */ + +void blip_add_delta( blip_t* m, unsigned time, int delta ) +{ + unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); + buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); + + int const phase_shift = frac_bits - phase_bits; + int phase = fixed >> phase_shift & (phase_count - 1); + short const* in = bl_step [phase]; + short const* rev = bl_step [phase_count - phase]; + + int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1); + int delta2 = (delta * interp) >> delta_bits; + delta -= delta2; + + /* Fails if buffer size was exceeded */ + assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); + + out [0] += in[0]*delta + in[half_width+0]*delta2; + out [1] += in[1]*delta + in[half_width+1]*delta2; + out [2] += in[2]*delta + in[half_width+2]*delta2; + out [3] += in[3]*delta + in[half_width+3]*delta2; + out [4] += in[4]*delta + in[half_width+4]*delta2; + out [5] += in[5]*delta + in[half_width+5]*delta2; + out [6] += in[6]*delta + in[half_width+6]*delta2; + out [7] += in[7]*delta + in[half_width+7]*delta2; + + in = rev; + out [ 8] += in[7]*delta + in[7-half_width]*delta2; + out [ 9] += in[6]*delta + in[6-half_width]*delta2; + out [10] += in[5]*delta + in[5-half_width]*delta2; + out [11] += in[4]*delta + in[4-half_width]*delta2; + out [12] += in[3]*delta + in[3-half_width]*delta2; + out [13] += in[2]*delta + in[2-half_width]*delta2; + out [14] += in[1]*delta + in[1-half_width]*delta2; + out [15] += in[0]*delta + in[0-half_width]*delta2; +} + +void blip_add_delta_fast( blip_t* m, unsigned time, int delta ) +{ + unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift); + buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits); + + int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1); + int delta2 = delta * interp; + + /* Fails if buffer size was exceeded */ + assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] ); + + out [7] += delta * delta_unit - delta2; + out [8] += delta2; +} diff --git a/dumb/src/helpers/resamp2.inc b/dumb/src/helpers/resamp2.inc index 84826ce51..de65dfb34 100644 --- a/dumb/src/helpers/resamp2.inc +++ b/dumb/src/helpers/resamp2.inc @@ -95,7 +95,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler) #define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES #define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES #define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO -#define MIX_ALIAS(op, upd, offset) MONO_DEST_MIX_ALIAS(op, upd, offset) +#define MIX_ALIAS(count) MONO_DEST_MIX_ALIAS(count) +#define PEEK_ALIAS MONO_DEST_PEEK_ALIAS #define MIX_LINEAR(op, upd, o0, o1) MONO_DEST_MIX_LINEAR(op, upd, o0, o1) #define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) MONO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) #define MIX_ZEROS(op) *dst++ op 0 @@ -137,7 +138,8 @@ static int process_pickup(DUMB_RESAMPLER *resampler) if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \ } #define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) -#define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset) +#define MIX_ALIAS(count) STEREO_DEST_MIX_ALIAS(count) +#define PEEK_ALIAS STEREO_DEST_PEEK_ALIAS #define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) #define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) #define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; } @@ -157,6 +159,9 @@ static int process_pickup(DUMB_RESAMPLER *resampler) #undef MONO_DEST_VOLUME_ZEROS #undef MONO_DEST_VOLUME_VARIABLES #undef MONO_DEST_VOLUME_PARAMETERS +#undef STEREO_DEST_PEEK_ALIAS +#undef MONO_DEST_PEEK_ALIAS +#undef POKE_ALIAS #undef COPYSRC2 #undef COPYSRC #undef DIVIDE_BY_SRC_CHANNELS diff --git a/dumb/src/helpers/resamp3.inc b/dumb/src/helpers/resamp3.inc index 3d61bfff1..1581e7bfa 100644 --- a/dumb/src/helpers/resamp3.inc +++ b/dumb/src/helpers/resamp3.inc @@ -46,12 +46,13 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta) { - int dt; + int dt, inv_dt; int VOLUME_VARIABLES; long done; long todo; LONG_LONG todo64; int quality; + int blip_samples[256*SRC_CHANNELS]; if (!resampler || resampler->dir == 0) return 0; ASSERT(resampler->dir == -1 || resampler->dir == 1); @@ -59,6 +60,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO done = 0; dt = (int)(delta * 65536.0 + 0.5); if (dt == 0 || dt == 0x80000000) return 0; + inv_dt = (int)(1.0 / delta * 65536.0 + 0.5); SET_VOLUME_VARIABLES; if (VOLUMES_ARE_ZERO) dst = NULL; @@ -104,29 +106,34 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO subpos = (long)new_subpos & 65535; } else if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, backwards */ - SRCTYPE xbuf[2*SRC_CHANNELS]; + int todo_clocks = todo << 16, todo_clocks_set = todo_clocks; + SRCTYPE xbuf[2*SRC_CHANNELS]; SRCTYPE *x = &xbuf[0]; - SRCTYPE *xstart; COPYSRC(xbuf, 0, resampler->X, 1); COPYSRC(xbuf, 1, resampler->X, 2); - while (todo && x < &xbuf[2*SRC_CHANNELS]) { + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) { // TODO: check what happens when multiple tempo slides occur per row HEAVYASSERT(pos >= resampler->start); - MIX_ALIAS(+=, 1, 0); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; + POKE_ALIAS(0); + pos--; + x += SRC_CHANNELS; + } + x = &src[pos*SRC_CHANNELS]; + while ( todo_clocks ) { + todo_clocks_set = todo_clocks; + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + todo_clocks -= todo_clocks_set; + todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt; + if ( todo < 0 ) todo = 0; + LOOP4(todo, + POKE_ALIAS(2); + pos--; + x -= SRC_CHANNELS; + ); + todo = todo_clocks_set >> 16; + MIX_ALIAS( todo ); } - x = xstart = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - MIX_ALIAS(+=, 1, 2); - subpos += dt; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart)); } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, backwards */ SRCTYPE xbuf[3*SRC_CHANNELS]; @@ -205,28 +212,33 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO subpos = (long)new_subpos & 65535; } else if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, forwards */ + int todo_clocks = todo << 16, todo_clocks_set = todo_clocks; SRCTYPE xbuf[2*SRC_CHANNELS]; SRCTYPE *x = &xbuf[0]; - SRCTYPE *xstart; COPYSRC(xbuf, 0, resampler->X, 1); COPYSRC(xbuf, 1, resampler->X, 2); - while (todo && x < &xbuf[2*SRC_CHANNELS]) { + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + while (resampler->last_clock < todo_clocks_set && x < &xbuf[2*SRC_CHANNELS]) { HEAVYASSERT(pos < resampler->end); - MIX_ALIAS(+=, 1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; + POKE_ALIAS(0); + pos++; + x += SRC_CHANNELS; + } + x = &src[pos*SRC_CHANNELS]; + while ( todo_clocks ) { + todo_clocks_set = todo_clocks; + if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; + todo_clocks -= todo_clocks_set; + todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt; + if ( todo < 0 ) todo = 0; + LOOP4(todo, + POKE_ALIAS(-2); + pos++; + x += SRC_CHANNELS; + ); + todo = todo_clocks_set >> 16; + MIX_ALIAS( todo ); } - x = xstart = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - MIX_ALIAS(+=, 1, -2); - subpos += dt; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - pos += DIVIDE_BY_SRC_CHANNELS((long)(x - xstart)); } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, forwards */ SRCTYPE xbuf[3*SRC_CHANNELS]; @@ -339,7 +351,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE HEAVYASSERT(pos >= resampler->start); if (dumb_resampling_quality <= DUMB_RQ_ALIASING) { /* Aliasing, backwards */ - MIX_ALIAS(=, 0, 1); + PEEK_ALIAS; } else if (quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, backwards */ MIX_LINEAR(=, 0, 2, 1); @@ -351,7 +363,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE HEAVYASSERT(pos < resampler->end); if (dumb_resampling_quality <= DUMB_RQ_ALIASING) { /* Aliasing */ - MIX_ALIAS(=, 0, 1); + PEEK_ALIAS; } else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) { /* Linear interpolation, forwards */ MIX_LINEAR(=, 0, 1, 2); @@ -368,6 +380,7 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE #undef MIX_CUBIC #undef MIX_LINEAR #undef MIX_ALIAS +#undef PEEK_ALIAS #undef VOLUMES_ARE_ZERO #undef SET_VOLUME_VARIABLES #undef RETURN_VOLUME_VARIABLES diff --git a/dumb/src/helpers/resample.c b/dumb/src/helpers/resample.c index db42ee7ae..e78d0d39c 100644 --- a/dumb/src/helpers/resample.c +++ b/dumb/src/helpers/resample.c @@ -189,7 +189,7 @@ static void init_cubic(void) #define SRCTYPE sample_t #define SRCBITS 24 -#define ALIAS(x, vol) MULSC(x, vol) +#define ALIAS(x) (x >> 8) #define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos)) /* #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ @@ -225,7 +225,7 @@ static void init_cubic(void) #define SUFFIX _16 #define SRCTYPE short #define SRCBITS 16 -#define ALIAS(x, vol) (x * vol >> 8) +#define ALIAS(x) (x) #define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos)) /* #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ @@ -247,7 +247,7 @@ static void init_cubic(void) #define SUFFIX _8 #define SRCTYPE signed char #define SRCBITS 8 -#define ALIAS(x, vol) (x * vol) +#define ALIAS(x) (x << 8) #define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos) /* #define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ diff --git a/dumb/src/helpers/resample.inc b/dumb/src/helpers/resample.inc index eaef2976c..364e36ccd 100644 --- a/dumb/src/helpers/resample.inc +++ b/dumb/src/helpers/resample.inc @@ -69,6 +69,11 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann } for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0; resampler->overshot = -1; + resampler->last_clock = 0; + resampler->last_amp[0] = 0; + resampler->last_amp[1] = 0; + blip_clear(resampler->blip_buffer[0]); + blip_clear(resampler->blip_buffer[1]); } @@ -77,6 +82,21 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos, { DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler)); if (!resampler) return NULL; + resampler->blip_buffer[0] = blip_new( 256 ); + if (!resampler->blip_buffer[0]) + { + free(resampler); + return NULL; + } + resampler->blip_buffer[1] = blip_new( 256 ); + if (!resampler->blip_buffer[1]) + { + free(resampler->blip_buffer[0]); + free(resampler); + return NULL; + } + blip_set_rates(resampler->blip_buffer[0], 65536, 1); + blip_set_rates(resampler->blip_buffer[1], 65536, 1); dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality); return resampler; } @@ -123,16 +143,41 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos, } #define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f #define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0) -#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \ - *dst++ op ALIAS(x[offset], vol); \ - if ( upd ) UPDATE_VOLUME( volume, vol ); \ +#define POKE_ALIAS(offset) { \ + int delta = ALIAS(x[offset]) - resampler->last_amp[0]; \ + resampler->last_amp[0] += delta; \ + if ( delta ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, delta ); \ + resampler->last_clock += inv_dt; \ } -#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \ - int xm = x[offset]; \ - *dst++ op ALIAS(xm, lvol); \ - *dst++ op ALIAS(xm, rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ +#define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol ) +#define MONO_DEST_MIX_ALIAS(count) { \ + int n = 0; \ + resampler->last_clock -= count * 65536; \ + blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \ + blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \ + LOOP4( count, \ + *dst++ += MULSC( blip_samples[n], vol ); \ + n++; \ + UPDATE_VOLUME( volume, vol ); \ + ); \ +} +#define STEREO_DEST_PEEK_ALIAS { \ + int sample = blip_peek_sample( resampler->blip_buffer[0] ); \ + *dst++ = MULSC( sample, lvol ); \ + *dst++ = MULSC( sample, rvol ); \ +} +#define STEREO_DEST_MIX_ALIAS(count) { \ + int sample, n = 0; \ + resampler->last_clock -= count * 65536; \ + blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \ + blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \ + LOOP4( count, \ + sample = blip_samples[n++]; \ + *dst++ += MULSC( sample, lvol ); \ + *dst++ += MULSC( sample, rvol ); \ + UPDATE_VOLUME( volume_left, lvol ); \ + UPDATE_VOLUME( volume_right, rvol ); \ + ); \ } #define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \ *dst++ op MULSC(LINEAR(x[o0], x[o1]), vol); \ @@ -208,16 +253,51 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos, if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \ } #define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) -#define MONO_DEST_MIX_ALIAS(op, upd, offset) { \ - *dst++ op ALIAS(x[(offset)*2], lvol) + ALIAS(x[(offset)*2+1], rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ +#define POKE_ALIAS(offset) { \ + int deltal = ALIAS(x[(offset)*2+0]) - resampler->last_amp[0]; \ + int deltar = ALIAS(x[(offset)*2+1]) - resampler->last_amp[1]; \ + resampler->last_amp[0] += deltal; \ + resampler->last_amp[1] += deltar; \ + if ( deltal ) blip_add_delta( resampler->blip_buffer[0], resampler->last_clock, deltal ); \ + if ( deltar ) blip_add_delta( resampler->blip_buffer[1], resampler->last_clock, deltar ); \ + resampler->last_clock += inv_dt; \ } -#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \ - *dst++ op ALIAS(x[(offset)*2], lvol); \ - *dst++ op ALIAS(x[(offset)*2+1], rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ +#define MONO_DEST_PEEK_ALIAS { \ + *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \ + MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \ +} +#define MONO_DEST_MIX_ALIAS(count) { \ + int n = 0; \ + resampler->last_clock -= count * 65536; \ + blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \ + blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \ + blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \ + blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \ + LOOP4( count, \ + *dst++ += MULSC( blip_samples[n], lvol ) + MULSC( blip_samples[256+n], rvol ); \ + n++; \ + UPDATE_VOLUME( volume_left, lvol ); \ + UPDATE_VOLUME( volume_right, rvol ); \ + ); \ +} +#define STEREO_DEST_PEEK_ALIAS { \ + *dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ); \ + *dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \ +} +#define STEREO_DEST_MIX_ALIAS(count) { \ + int n = 0; \ + resampler->last_clock -= count * 65536; \ + blip_end_frame( resampler->blip_buffer[0], count * 65536 ); \ + blip_end_frame( resampler->blip_buffer[1], count * 65536 ); \ + blip_read_samples( resampler->blip_buffer[0], blip_samples, count ); \ + blip_read_samples( resampler->blip_buffer[1], blip_samples + 256, count ); \ + LOOP4( count, \ + *dst++ += MULSC( blip_samples[n], lvol); \ + *dst++ += MULSC( blip_samples[256+n], rvol); \ + n++; \ + UPDATE_VOLUME( volume_left, lvol ); \ + UPDATE_VOLUME( volume_right, rvol ); \ + ); \ } #define MONO_DEST_MIX_LINEAR(op, upd, o0, o1) { \ *dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol) + MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \ diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 24530156d..4d188ae6a 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -29,15 +29,38 @@ #define END_RAMPING #define RAMP_DOWN -static IT_PLAYING *alloc_playing(DUMB_IT_SIGRENDERER *itsr) +static IT_PLAYING *new_playing(DUMB_IT_SIGRENDERER *itsr) { + IT_PLAYING *r; + if (itsr->free_playing != NULL) { - IT_PLAYING *pl = itsr->free_playing; - itsr->free_playing = pl->next; - return pl; + r = itsr->free_playing; + itsr->free_playing = r->next; + blip_clear(r->resampler.blip_buffer[0]); + blip_clear(r->resampler.blip_buffer[1]); + return r; } - return (IT_PLAYING *)malloc(sizeof(IT_PLAYING)); + r = (IT_PLAYING *)malloc(sizeof(IT_PLAYING)); + if (r) + { + r->resampler.blip_buffer[0] = blip_new( 256 ); + if ( !r->resampler.blip_buffer[0] ) + { + free( r ); + return NULL; + } + r->resampler.blip_buffer[1] = blip_new( 256 ); + if ( !r->resampler.blip_buffer[1] ) + { + free( r->resampler.blip_buffer[0] ); + free( r ); + return NULL; + } + blip_set_rates(r->resampler.blip_buffer[0], 65536, 1); + blip_set_rates(r->resampler.blip_buffer[1], 65536, 1); + } + return r; } static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing) @@ -46,6 +69,13 @@ static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing) itsr->free_playing = playing; } +static void free_playing_orig(IT_PLAYING * r) +{ + blip_delete( r->resampler.blip_buffer[1] ); + blip_delete( r->resampler.blip_buffer[0] ); + free( r ); +} + static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel) { IT_PLAYING *dst; @@ -135,6 +165,19 @@ static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANN dst->resampler = src->resampler; dst->resampler.pickup_data = dst; + dst->resampler.blip_buffer[0] = blip_dup( dst->resampler.blip_buffer[0] ); + if ( !dst->resampler.blip_buffer[0] ) + { + free( dst ); + return NULL; + } + dst->resampler.blip_buffer[1] = blip_dup( dst->resampler.blip_buffer[1] ); + if ( !dst->resampler.blip_buffer[1] ) + { + blip_delete( dst->resampler.blip_buffer[0] ); + free( dst ); + return NULL; + } dst->time_lost = src->time_lost; //dst->output = src->output; @@ -1582,7 +1625,7 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan if (channel->playing) free_playing(sigrenderer, channel->playing); - channel->playing = alloc_playing(sigrenderer); + channel->playing = new_playing(sigrenderer); if (!channel->playing) return; @@ -2889,9 +2932,7 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - IT_PLAYING playing; - - playing.sample = 0; + IT_PLAYING * playing = NULL; if (entry->mask & IT_ENTRY_INSTRUMENT) { int oldsample = channel->sample; @@ -2901,7 +2942,8 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent if (channel->playing && !((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) && !((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) { - playing = *channel->playing; + playing = dup_playing(channel->playing, channel, channel); + if (!playing) return; if (!(sigdata->flags & IT_WAS_A_MOD)) { /* Retrigger vol/pan envelopes if enabled, and cancel fadeout. * Also reset vol/pan to that of _original_ instrument. @@ -2934,12 +2976,11 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent channel->playing = NULL; } } else { - if (!channel->playing) { - channel->playing = alloc_playing(sigrenderer); - if (!channel->playing) return; + if (channel->playing) { + free_playing(sigrenderer, channel->playing); } - *channel->playing = playing; - playing.sample = (IT_SAMPLE *)-1; + channel->playing = playing; + playing = NULL; channel->playing->declick_stage = 0; channel->playing->declick_volume = 1.f / 256.f; #else @@ -2985,7 +3026,11 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent if (channel->playing) { #ifdef RAMP_DOWN int i; - if (playing.sample) *channel->playing = playing; + if (playing) { + free_playing(sigrenderer, channel->playing); + channel->playing = playing; + playing = NULL; + } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { channel->playing->declick_stage = 2; @@ -3003,6 +3048,7 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent channel->playing = NULL; #endif } + if (playing) free_playing(sigrenderer, playing); return; } else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) { /* Don't retrigger note; portamento in the volume column. */ @@ -3015,20 +3061,26 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent channel->destnote = IT_NOTE_OFF; if (!channel->playing) { - channel->playing = alloc_playing(sigrenderer); - if (!channel->playing) + channel->playing = new_playing(sigrenderer); + if (!channel->playing) { + if (playing) free_playing(sigrenderer, playing); return; + } // Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone. retrigger_xm_envelopes(channel->playing); } #ifdef RAMP_DOWN - else if (playing.sample != (IT_SAMPLE *)-1) { + else if (playing) { /* volume rampy stuff! move note to NNA */ int i; - IT_PLAYING * ptemp = alloc_playing(sigrenderer); - if (!ptemp) return; - if (playing.sample) *ptemp = playing; - else *ptemp = *channel->playing; + IT_PLAYING * ptemp; + if (playing->sample) ptemp = playing; + else ptemp = channel->playing; + if (!ptemp) { + if (playing) free_playing(sigrenderer, playing); + return; + } + playing = NULL; for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { ptemp->declick_stage = 2; @@ -3189,6 +3241,8 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent break; } } + + if (playing) free_playing(sigrenderer, playing); } @@ -5165,7 +5219,7 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { if (sigrenderer->channel[i].playing) - free(sigrenderer->channel[i].playing); + free_playing_orig(sigrenderer->channel[i].playing); #ifdef BIT_ARRAY_BULLSHIT bit_array_destroy(sigrenderer->channel[i].played_patjump); #endif @@ -5173,12 +5227,12 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) if (sigrenderer->playing[i]) - free(sigrenderer->playing[i]); + free_playing_orig(sigrenderer->playing[i]); for (playing = sigrenderer->free_playing; playing != NULL; playing = next) { next = playing->next; - free(playing); + free_playing_orig(playing); } dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover); diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj index 128b3b9d9..896ce8a8f 100644 --- a/dumb/vc6/dumb_static/dumb_static.vcproj +++ b/dumb/vc6/dumb_static/dumb_static.vcproj @@ -877,6 +877,10 @@ RelativePath="..\..\src\helpers\barray.c" > + + @@ -1960,6 +1964,10 @@ + + From 8807330649c8f700d032fd47bdd34ec221c79b50 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 23:30:20 +0000 Subject: [PATCH 147/387] - Update DUMB to revision c0fc19ef2e756ef25aa44ca3775b4afed3f02c9c - Changed aliased resampler loop conditions a bit to fix some bugs - Removed resampler loop unrolling, as it actually made things slightly slower - Fixed a bug with songs triggering notes on the first order with instrument changes before any note commands have been triggered SVN r4077 (trunk) --- dumb/src/helpers/resamp3.inc | 14 ++++++-------- dumb/src/helpers/resample.c | 4 ++-- dumb/src/it/itrender.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/dumb/src/helpers/resamp3.inc b/dumb/src/helpers/resamp3.inc index 1581e7bfa..05c0dfbb7 100644 --- a/dumb/src/helpers/resamp3.inc +++ b/dumb/src/helpers/resamp3.inc @@ -124,13 +124,12 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO todo_clocks_set = todo_clocks; if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; todo_clocks -= todo_clocks_set; - todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt; - if ( todo < 0 ) todo = 0; - LOOP4(todo, + while ( resampler->last_clock < todo_clocks_set ) + { POKE_ALIAS(2); pos--; x -= SRC_CHANNELS; - ); + } todo = todo_clocks_set >> 16; MIX_ALIAS( todo ); } @@ -229,13 +228,12 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO todo_clocks_set = todo_clocks; if ( todo_clocks_set > 256 * 65536 ) todo_clocks_set = 256 * 65536; todo_clocks -= todo_clocks_set; - todo = ( todo_clocks_set - resampler->last_clock + inv_dt - 1 ) / inv_dt; - if ( todo < 0 ) todo = 0; - LOOP4(todo, + while ( resampler->last_clock < todo_clocks_set ) + { POKE_ALIAS(-2); pos++; x += SRC_CHANNELS; - ); + } todo = todo_clocks_set >> 16; MIX_ALIAS( todo ); } diff --git a/dumb/src/helpers/resample.c b/dumb/src/helpers/resample.c index e78d0d39c..4424a4934 100644 --- a/dumb/src/helpers/resample.c +++ b/dumb/src/helpers/resample.c @@ -117,9 +117,9 @@ int dumb_resampling_quality = DUMB_RQ_CUBIC; */ #define LOOP4(iterator, CONTENT) \ { \ - while (iterator) { \ + while ( (iterator)-- ) \ + { \ CONTENT; \ - (iterator)--; \ } \ } #endif diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 4d188ae6a..b8d4b5e92 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -4863,7 +4863,7 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha channel->channelvolume = sigdata->channel_volume[i]; channel->instrument = 0; channel->sample = 0; - channel->note = 0; + channel->note = IT_NOTE_OFF; channel->SFmacro = 0; channel->filter_cutoff = 127; channel->filter_resonance = 0; From e978c7b059dbc25aa3878114fd8282c08a0e8caa Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 7 Feb 2013 23:34:03 +0000 Subject: [PATCH 148/387] - Udate DUMB to revision e34d68685d2e5e8b45f62acdaf8157872624620c 2011-01-13 23:11 UTC - kode54 - Implemented ASYLUM instrument base semitone offset - Fixed ASYLUM effect number translation - Version is now 0.9.9.28 2011-01-13 21:28 UTC - kode54 - Quick fix for PT2 invert loop effect - Version is now 0.9.9.27 2011-01-13 20:37 UTC - kode54 - Implemented PT2 invert loop effect - Version is now 0.9.9.26 SVN r4078 (trunk) --- dumb/include/internal/it.h | 5 +++++ dumb/src/it/itrender.c | 42 +++++++++++++++++++++++++++++++++++++- dumb/src/it/readasy.c | 9 ++++---- dumb/src/it/xmeffect.c | 1 + 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index e248ade79..36b083e0c 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -643,6 +643,10 @@ struct IT_CHANNEL unsigned char xm_lastX1; unsigned char xm_lastX2; + unsigned char inv_loop_delay; + unsigned char inv_loop_speed; + int inv_loop_offset; + IT_PLAYING *playing; #ifdef BIT_ARRAY_BULLSHIT @@ -802,6 +806,7 @@ extern DUH_SIGTYPE_DESC _dumb_sigtype_it; #define XM_E_NOTE_CUT 0xC #define XM_E_NOTE_DELAY 0xD #define XM_E_PATTERN_DELAY 0xE +#define XM_E_SET_MIDI_MACRO 0xF #define XM_X_EXTRAFINE_PORTA_UP 1 #define XM_X_EXTRAFINE_PORTA_DOWN 2 diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index b8d4b5e92..f1ff9721d 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -274,6 +274,10 @@ static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src) dst->xm_lastX1 = src->xm_lastX1; dst->xm_lastX2 = src->xm_lastX2; + dst->inv_loop_delay = src->inv_loop_delay; + dst->inv_loop_speed = src->inv_loop_speed; + dst->inv_loop_offset = src->inv_loop_offset; + dst->playing = dup_playing(src->playing, dst, src); @@ -1045,6 +1049,33 @@ static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) } +static const unsigned char pt_tab_invloop[16] = +{ + 0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, + 0x0F, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80 +}; + +static void update_invert_loop(IT_CHANNEL *channel, IT_SAMPLE *sample) +{ + channel->inv_loop_delay += pt_tab_invloop[channel->inv_loop_speed]; + if (channel->inv_loop_delay >= 0x80) + { + channel->inv_loop_delay = 0; + + if (sample && ((sample->flags & (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) == (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) && !(sample->flags & (IT_SAMPLE_STEREO | IT_SAMPLE_16BIT))) + { + if (sample->loop_end - sample->loop_start >= 4) + { + channel->inv_loop_offset++; + if (channel->inv_loop_offset >= (sample->loop_end - sample->loop_start)) channel->inv_loop_offset = 0; + + ((char *)sample->data)[sample->loop_start + channel->inv_loop_offset] ^= 0xFF; + } + } + } +} + + static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) { @@ -1140,6 +1171,8 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) update_retrig(sigrenderer, channel); + if (channel->inv_loop_speed) update_invert_loop(channel, playing ? playing->sample : NULL); + if (playing) { playing->slide += channel->portamento; @@ -2538,7 +2571,10 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than } break; case IT_S_SET_MIDI_MACRO: - channel->SFmacro = effectvalue & 15; + if ((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == (IT_WAS_AN_XM | IT_WAS_A_MOD)) { + channel->inv_loop_speed = effectvalue & 15; + update_invert_loop(channel, channel->playing ? channel->playing->sample : NULL); + } else channel->SFmacro = effectvalue & 15; break; } } @@ -2937,6 +2973,7 @@ static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *ent if (entry->mask & IT_ENTRY_INSTRUMENT) { int oldsample = channel->sample; int oldvolume = channel->volume; + channel->inv_loop_offset = 0; channel->instrument = entry->instrument; instrument_to_sample(sigdata, channel); if (channel->playing && @@ -4907,6 +4944,9 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha channel->xm_lastEB = 0; channel->xm_lastX1 = 0; channel->xm_lastX2 = 0; + channel->inv_loop_delay = 0; + channel->inv_loop_speed = 0; + channel->inv_loop_offset = 0; channel->playing = NULL; #ifdef BIT_ARRAY_BULLSHIT channel->played_patjump = NULL; diff --git a/dumb/src/it/readasy.c b/dumb/src/it/readasy.c index 9ab5a1f32..3cc89ab17 100644 --- a/dumb/src/it/readasy.c +++ b/dumb/src/it/readasy.c @@ -71,7 +71,7 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char entry->mask |= IT_ENTRY_INSTRUMENT; } - _dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 ); + _dumb_it_xm_convert_effect( buffer[ pos + 2 ], buffer[ pos + 3 ], entry, 1 ); if ( entry->mask ) ++entry; } @@ -90,7 +90,7 @@ static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) { - int finetune; + int finetune, key_offset; /** 21 22 Chars Sample 1 name. If the name is not a full @@ -111,7 +111,7 @@ assumed not to be an instrument name, and is probably a message. sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead? sample->global_volume = 64; if ( sample->default_volume > 64 ) sample->default_volume = 64; - dumbfile_skip( f, 1 ); /* XXX unknown */ + key_offset = ( signed char ) dumbfile_getc( f ); /* base key offset */ sample->length = dumbfile_igetl( f ); sample->loop_start = dumbfile_igetl( f ); sample->loop_end = sample->loop_start + dumbfile_igetl( f ); @@ -124,7 +124,8 @@ assumed not to be an instrument name, and is probably a message. sample->flags = IT_SAMPLE_EXISTS; sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( int32 )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) ); + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, +finetune * 32 ) ); sample->finetune = finetune * 32; // the above line might be wrong diff --git a/dumb/src/it/xmeffect.c b/dumb/src/it/xmeffect.c index f0f8820ff..1aa489222 100644 --- a/dumb/src/it/xmeffect.c +++ b/dumb/src/it/xmeffect.c @@ -188,6 +188,7 @@ if (log) printf(" - %2d %02X", effect, value); case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break; case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break; case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break; + case EBASE+XM_E_SET_MIDI_MACRO: effect = SBASE+IT_S_SET_MIDI_MACRO; break; case EBASE + XM_E_FINE_PORTA_UP: effect = IT_PORTAMENTO_UP; From 6d000a414a1ad8b37fd4119dff3804cf4083d51b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:09:49 +0000 Subject: [PATCH 149/387] Update DUMB to revision e169b25f34ca140da8375a7085791447a5b8e8e8 - Implemented Oktalyzer format loader SVN r4079 (trunk) --- dumb/CMakeLists.txt | 4 + dumb/include/dumb.h | 4 + dumb/include/internal/it.h | 20 +- dumb/src/it/itrender.c | 92 +++- dumb/src/it/loadokt.c | 42 ++ dumb/src/it/loadokt2.c | 29 ++ dumb/src/it/readasy.c | 3 +- dumb/src/it/readokt.c | 542 ++++++++++++++++++++++++ dumb/src/it/readokt2.c | 29 ++ dumb/vc6/dumb_static/dumb_static.vcproj | 16 + 10 files changed, 770 insertions(+), 11 deletions(-) create mode 100644 dumb/src/it/loadokt.c create mode 100644 dumb/src/it/loadokt2.c create mode 100644 dumb/src/it/readokt.c create mode 100644 dumb/src/it/readokt2.c diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index c35dc7da0..591e31400 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -61,6 +61,8 @@ add_library( dumb src/it/loadmod2.c src/it/loadmtm.c src/it/loadmtm2.c + src/it/loadokt.c + src/it/loadokt2.c src/it/loadoldpsm.c src/it/loadoldpsm2.c src/it/loadpsm.c @@ -84,6 +86,8 @@ add_library( dumb src/it/readmod.c src/it/readmod2.c src/it/readmtm.c + src/it/readokt.c + src/it/readokt2.c src/it/readoldpsm.c src/it/readpsm.c src/it/readptm.c diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index 0b42b4d6d..d82afe6f6 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -408,6 +408,7 @@ DUH *DUMBEXPORT dumb_load_old_psm(const char * filename); DUH *DUMBEXPORT dumb_load_mtm(const char *filename); DUH *DUMBEXPORT dumb_load_riff(const char *filename); DUH *DUMBEXPORT dumb_load_asy(const char *filename); +DUH *DUMBEXPORT dumb_load_okt(const char *filename); DUH *DUMBEXPORT dumb_read_it(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_xm(DUMBFILE *f); @@ -421,6 +422,7 @@ DUH *DUMBEXPORT dumb_read_old_psm(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_mtm(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_riff(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_asy(DUMBFILE *f); +DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f); DUH *DUMBEXPORT dumb_load_it_quick(const char *filename); DUH *DUMBEXPORT dumb_load_xm_quick(const char *filename); @@ -434,6 +436,7 @@ DUH *DUMBEXPORT dumb_load_old_psm_quick(const char * filename); DUH *DUMBEXPORT dumb_load_mtm_quick(const char *filename); DUH *DUMBEXPORT dumb_load_riff_quick(const char *filename); DUH *DUMBEXPORT dumb_load_asy_quick(const char *filename); +DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename); DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f); @@ -447,6 +450,7 @@ DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_riff_quick(DUMBFILE *f); DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f); +DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f); int32 DUMBEXPORT dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder); void DUMBEXPORT dumb_it_do_initial_runthrough(DUH *duh); diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 36b083e0c..0c8bf144c 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -300,7 +300,18 @@ struct IT_SAMPLE #define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36 #define IT_PTM_NOTE_SLIDE_UP_RETRIG 37 -#define IT_N_EFFECTS 38 +/* More effects needed for OKT compatibility */ +#define IT_OKT_NOTE_SLIDE_DOWN 38 +#define IT_OKT_NOTE_SLIDE_DOWN_ROW 39 +#define IT_OKT_NOTE_SLIDE_UP 40 +#define IT_OKT_NOTE_SLIDE_UP_ROW 41 +#define IT_OKT_ARPEGGIO_3 42 +#define IT_OKT_ARPEGGIO_4 43 +#define IT_OKT_ARPEGGIO_5 44 +#define IT_OKT_VOLUME_SLIDE_DOWN 45 +#define IT_OKT_VOLUME_SLIDE_UP 46 + +#define IT_N_EFFECTS 47 /* These represent the top nibble of the command value. */ #define IT_S_SET_FILTER 0 /* Greyed out in IT... */ @@ -399,6 +410,8 @@ struct IT_PATTERN #define IT_WAS_A_669 1024 +#define IT_WAS_AN_OKT 2048 + #define IT_ORDER_END 255 #define IT_ORDER_SKIP 254 @@ -586,7 +599,8 @@ struct IT_CHANNEL unsigned char new_note_action; - int arpeggio; + unsigned int arpeggio; + int arpeggio_shift; unsigned char retrig; unsigned char xm_retrig; int retrig_tick; @@ -601,7 +615,7 @@ struct IT_CHANNEL int portamento; int toneporta; int toneslide; - unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide; + unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide, okt_toneslide; unsigned char destnote; unsigned char toneslide_retrig; diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index f1ff9721d..34a698d7f 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -218,6 +218,7 @@ static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src) dst->new_note_action = src->new_note_action; dst->arpeggio = src->arpeggio; + dst->arpeggio_shift = src->arpeggio_shift; dst->retrig = src->retrig; dst->xm_retrig = src->xm_retrig; dst->retrig_tick = src->retrig_tick; @@ -235,6 +236,7 @@ static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src) dst->last_toneslide_tick = src->last_toneslide_tick; dst->ptm_toneslide = src->ptm_toneslide; dst->ptm_last_toneslide = src->ptm_last_toneslide; + dst->okt_toneslide = src->okt_toneslide; dst->destnote = src->destnote; dst->glissando = src->glissando; @@ -807,6 +809,7 @@ static void reset_channel_effects(IT_CHANNEL *channel) channel->panslide = 0; channel->channelvolslide = 0; channel->arpeggio = 0; + channel->arpeggio_shift = 0; channel->retrig = 0; if (channel->xm_retrig) { channel->xm_retrig = 0; @@ -822,6 +825,7 @@ static void reset_channel_effects(IT_CHANNEL *channel) channel->ptm_last_toneslide = 0; channel->ptm_toneslide = 0; channel->toneslide_tick = 0; + channel->okt_toneslide = 0; if (channel->playing) { channel->playing->vibrato_n = 0; channel->playing->tremolo_speed = 0; @@ -1166,8 +1170,7 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) update_tremor(channel); - channel->arpeggio = (channel->arpeggio << 4) | (channel->arpeggio >> 8); - channel->arpeggio &= 0xFFF; + if (channel->arpeggio_shift) channel->arpeggio = (channel->arpeggio << 8) | (channel->arpeggio >> channel->arpeggio_shift); update_retrig(sigrenderer, channel); @@ -1176,7 +1179,15 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) if (playing) { playing->slide += channel->portamento; - if (channel->ptm_toneslide) { + if (channel->okt_toneslide) { + if (channel->okt_toneslide--) { + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + } + } else if (channel->ptm_toneslide) { if (--channel->toneslide_tick == 0) { channel->toneslide_tick = channel->ptm_toneslide; playing->note += channel->toneslide; @@ -2213,7 +2224,8 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastJ; channel->lastJ = v; } - channel->arpeggio = v; + channel->arpeggio = ((v & 0xF0) << 4) | (v & 0x0F); + channel->arpeggio_shift = 16; } break; case IT_SET_CHANNEL_VOLUME: @@ -2787,6 +2799,63 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than channel->toneslide_tick += channel->ptm_toneslide; } break; + + case IT_OKT_NOTE_SLIDE_DOWN: + case IT_OKT_NOTE_SLIDE_DOWN_ROW: + channel->toneslide = -entry->effectvalue; + channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_DOWN) ? 255 : 1; + break; + + case IT_OKT_NOTE_SLIDE_UP: + case IT_OKT_NOTE_SLIDE_UP_ROW: + channel->toneslide = entry->effectvalue; + channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_UP) ? 255 : 1; + break; + + case IT_OKT_ARPEGGIO_3: + case IT_OKT_ARPEGGIO_4: + case IT_OKT_ARPEGGIO_5: + { + unsigned char low = -(entry->effectvalue >> 4); + unsigned char high = entry->effectvalue & 0x0F; + + switch (entry->effect) + { + case IT_OKT_ARPEGGIO_3: + channel->arpeggio = (low << 16) | high; + channel->arpeggio_shift = 16; + break; + + case IT_OKT_ARPEGGIO_4: + channel->arpeggio = (high << 16) | low; + channel->arpeggio_shift = 24; + break; + + case IT_OKT_ARPEGGIO_5: + channel->arpeggio = (high << 16) | (high << 8); + channel->arpeggio_shift = 16; + break; + } + } + break; + + case IT_OKT_VOLUME_SLIDE_DOWN: + if ( entry->effectvalue <= 16 ) channel->volslide = -entry->effectvalue; + else + { + channel->volume -= entry->effectvalue - 16; + if (channel->volume > 64) channel->volume = 0; + } + break; + + case IT_OKT_VOLUME_SLIDE_UP: + if ( entry->effectvalue <= 16 ) channel->volslide = entry->effectvalue; + else + { + channel->volume += entry->effectvalue - 16; + if (channel->volume > 64) channel->volume = 64; + } + break; } } @@ -3806,7 +3875,7 @@ static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer) if ( channel->arpeggio > 0xFF ) playing->delta = playing->sample->C5_speed * (1.f / 65536.f); } - else*/ playing->delta *= (float)pow(DUMB_SEMITONE_BASE, channel->arpeggio >> 8);/* + else*/ playing->delta *= (float)pow(DUMB_SEMITONE_BASE, (signed char)(channel->arpeggio >> channel->arpeggio_shift));/* }*/ playing->filter_cutoff = channel->filter_cutoff; @@ -3941,6 +4010,14 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) sigrenderer->processorder = -1; continue; } + if (sigdata->flags & IT_WAS_AN_OKT) { + /* Reset some things */ + sigrenderer->speed = sigdata->speed; + sigrenderer->tempo = sigdata->tempo; + for (n = 0; n < DUMB_IT_N_CHANNELS; n++) { + xm_note_off(sigdata, &sigrenderer->channel[n]); + } + } } n = sigdata->order[sigrenderer->processorder]; @@ -4038,7 +4115,9 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) return 1; } - if (!(sigdata->flags & IT_OLD_EFFECTS)) + if (sigdata->flags & IT_WAS_AN_OKT) + update_effects(sigrenderer); + else if (!(sigdata->flags & IT_OLD_EFFECTS)) update_smooth_effects(sigrenderer); } else { { @@ -4915,6 +4994,7 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha channel->toneslide = 0; channel->ptm_toneslide = 0; channel->ptm_last_toneslide = 0; + channel->okt_toneslide = 0; channel->midi_state = 0; channel->lastvolslide = 0; channel->lastDKL = 0; diff --git a/dumb/src/it/loadokt.c b/dumb/src/it/loadokt.c new file mode 100644 index 000000000..2139d49e8 --- /dev/null +++ b/dumb/src/it/loadokt.c @@ -0,0 +1,42 @@ +/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadokt.c - Code to read an Oktalyzer module / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_okt_quick(): loads an OKT file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_okt_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_okt_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/dumb/src/it/loadokt2.c b/dumb/src/it/loadokt2.c new file mode 100644 index 000000000..aa752c582 --- /dev/null +++ b/dumb/src/it/loadokt2.c @@ -0,0 +1,29 @@ +/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadokt2.c - Function to read an Oktalyzer / / \ \ + * module file, opening and closing | < / \_ + * it for you, and do an initial run- | \/ /\ / + * through. \_ / > / + * | \ / / + * By Chris Moeller. | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_okt(const char *filename) +{ + DUH *duh = dumb_load_okt_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/dumb/src/it/readasy.c b/dumb/src/it/readasy.c index 3cc89ab17..5738b78a1 100644 --- a/dumb/src/it/readasy.c +++ b/dumb/src/it/readasy.c @@ -124,8 +124,7 @@ assumed not to be an instrument name, and is probably a message. sample->flags = IT_SAMPLE_EXISTS; sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, -finetune * 32 ) ); + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) ); sample->finetune = finetune * 32; // the above line might be wrong diff --git a/dumb/src/it/readokt.c b/dumb/src/it/readokt.c new file mode 100644 index 000000000..cab3c7a05 --- /dev/null +++ b/dumb/src/it/readokt.c @@ -0,0 +1,542 @@ +/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readokt.c - Code to read an Oktalyzer module / / \ \ + * from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include +#include +#include + +#include "dumb.h" +#include "internal/it.h" + + + +static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data, int length, int n_channels) +{ + int pos; + int channel; + int row; + int n_rows; + IT_ENTRY *entry; + + if (length < 2) return -1; + + n_rows = (data[0] << 8) | data[1]; + if (!n_rows) n_rows = 64; + + if (length < 2 + (n_rows * n_channels * 4)) return -1; + + pattern->n_rows = n_rows; + + /* compute number of entries */ + pattern->n_entries = n_rows; /* Account for the row end markers */ + pos = 2; + for (row = 0; row < pattern->n_rows; row++) { + for (channel = 0; channel < n_channels; channel++) { + if (data[pos+0] | data[pos+2]) + pattern->n_entries++; + pos += 4; + } + } + + pattern->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry)); + if (!pattern->entry) + return -1; + + entry = pattern->entry; + pos = 2; + for (row = 0; row < n_rows; row++) { + for (channel = 0; channel < n_channels; channel++) { + if (data[pos+0] | data[pos+2]) { + entry->channel = channel; + entry->mask = 0; + + if (data[pos+0] > 0 && data[pos+0] <= 36) { + entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT; + + entry->note = data[pos+0] + 35; + entry->instrument = data[pos+1] + 1; + } + + entry->effect = 0; + entry->effectvalue = data[pos+3]; + + switch (data[pos+2]) { + case 2: if (data[pos+3]) entry->effect = IT_PORTAMENTO_DOWN; break; // XXX code calls this rs_portu, but it's adding to the period, which decreases the pitch + case 13: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN; break; + case 21: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW; break; + + case 1: if (data[pos+3]) entry->effect = IT_PORTAMENTO_UP; break; // XXX same deal here, increasing the pitch + case 17: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP; break; + case 30: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW; break; + + case 10: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_3; break; + case 11: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_4; break; + case 12: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_5; break; + + case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break; + + case 25: entry->effect = IT_JUMP_TO_ORDER; break; + + case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break; + + case 28: entry->effect = IT_SET_SPEED; break; + + case 31: + if ( data[pos+3] <= 0x40 ) entry->effect = IT_SET_CHANNEL_VOLUME; + else if ( data[pos+3] <= 0x50 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x40; } + else if ( data[pos+3] <= 0x60 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x50; } + else if ( data[pos+3] <= 0x70 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x50; } + else if ( data[pos+3] <= 0x80 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x60; } + break; + } + + if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT; + + entry++; + } + pos += 4; + } + IT_SET_END_ROW(entry); + entry++; + } + + return 0; +} + + + +static void it_okt_read_sample_header(IT_SAMPLE *sample, const unsigned char * data) +{ + int loop_start, loop_length; + + memcpy(sample->name, data, 20); + sample->name[20] = 0; + + sample->filename[0] = 0; + + sample->length = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23]; + sample->global_volume = 64; + sample->default_volume = data[29]; + loop_start = ((data[24] << 8) | data[25]) << 1; + loop_length = ((data[26] << 8) | data[27]) << 1; + sample->sus_loop_start = loop_start; + sample->sus_loop_end = loop_start + loop_length; + + if (sample->length <= 0) { + sample->flags = 0; + return; + } + + sample->flags = IT_SAMPLE_EXISTS; + + sample->default_pan = 0; + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); + sample->finetune = 0; + + if (sample->sus_loop_end > sample->length) + sample->sus_loop_end = sample->length; + + if (loop_length > 2) + sample->flags |= IT_SAMPLE_SUS_LOOP; + + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; // do we have to set _all_ these? + sample->max_resampling_quality = -1; +} + + + +static int it_okt_read_sample_data(IT_SAMPLE *sample, const char * data, int length) +{ + if (length && sample->length) { + if (length < sample->length) { + sample->length = length; + if (length < sample->sus_loop_end) sample->sus_loop_end = length; + } + + sample->data = malloc(length); + + if (!sample->data) + return -1; + + memcpy(sample->data, data, length); + } + + return 0; +} + + + +typedef struct IFF_CHUNK IFF_CHUNK; +typedef struct IFF_CHUNKED IFF_CHUNKED; + +struct IFF_CHUNK +{ + unsigned type; + unsigned char * data; + unsigned size; +}; + +struct IFF_CHUNKED +{ + unsigned chunk_count; + IFF_CHUNK * chunks; +}; + + + +static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) +{ + IFF_CHUNKED *mod = (IFF_CHUNKED *) malloc(sizeof(*mod)); + if (!mod) return NULL; + + mod->chunk_count = 0; + mod->chunks = 0; + + for (;;) + { + long bytes_read; + IFF_CHUNK * chunk = ( IFF_CHUNK * ) realloc( mod->chunks, ( mod->chunk_count + 1 ) * sizeof( IFF_CHUNK ) ); + if ( !chunk ) + { + if ( mod->chunks ) free( mod->chunks ); + free( mod ); + return NULL; + } + mod->chunks = chunk; + chunk += mod->chunk_count; + + bytes_read = dumbfile_mgetl( f ); + if ( bytes_read < 0 ) break; + + chunk->type = bytes_read; + chunk->size = dumbfile_mgetl( f ); + + chunk->data = (unsigned char *) malloc( chunk->size ); + if ( !chunk->data ) + { + free( mod->chunks ); + free( mod ); + return NULL; + } + + bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f ); + if ( bytes_read < (long)chunk->size ) + { + free( mod->chunks ); + free( mod ); + return NULL; + } + + mod->chunk_count++; + } + + return mod; +} + +void free_okt(IFF_CHUNKED * mod) +{ + unsigned i; + if (mod) + { + if (mod->chunks) + { + for (i = 0; i < mod->chunk_count; i++) + { + if (mod->chunks[i].data) free(mod->chunks[i].data); + } + free(mod->chunks); + } + free(mod); + } +} + +const IFF_CHUNK * get_chunk_by_type(IFF_CHUNKED * mod, unsigned type, unsigned offset) +{ + unsigned i; + if (mod) + { + if (mod->chunks) + { + for (i = 0; i < mod->chunk_count; i++) + { + if (mod->chunks[i].type == type) + { + if (!offset) return &mod->chunks[i]; + else offset--; + } + } + } + } + return NULL; +} + +unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type) +{ + unsigned i, count = 0; + if (mod) + { + if (mod->chunks) + { + for (i = 0; i < mod->chunk_count; i++) + { + if (mod->chunks[i].type == type) count++; + } + } + } + return count; +} + + +static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f, int restrict) +{ + DUMB_IT_SIGDATA *sigdata; + unsigned n_channels; + unsigned i, j, k, l; + IFF_CHUNKED *mod; + const IFF_CHUNK *chunk; + + char signature[8]; + + if (dumbfile_getnc(signature, 8, f) < 8 || + memcmp(signature, "OKTASONG", 8)) { + return NULL; + } + + mod = dumbfile_read_okt(f); + if (!mod) + return NULL; + + sigdata = (DUMB_IT_SIGDATA *) malloc(sizeof(*sigdata)); + if (!sigdata) { + free_okt(mod); + return NULL; + } + + sigdata->name[0] = 0; + + chunk = get_chunk_by_type(mod, DUMB_ID('S','P','E','E'), 0); + if (!chunk || chunk->size < 2) { + free(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->speed = (chunk->data[0] << 8) | chunk->data[1]; + + chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); + if (!chunk || chunk->size < 32) { + free(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->n_samples = chunk->size / 32; + + chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); + if (!chunk || chunk->size < 8) { + free(sigdata); + free_okt(mod); + return NULL; + } + + n_channels = 0; + + for (i = 0; i < 4; i++) { + j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1]; + if (!j) n_channels++; + else if (j == 1) n_channels += 2; + } + + if (!n_channels) { + free(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->n_pchannels = n_channels; + + sigdata->sample = (IT_SAMPLE *) malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + free(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + + for (i = 0; i < (unsigned)sigdata->n_samples; i++) + sigdata->sample[i].data = NULL; + + chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); + + for (i = 0; i < (unsigned)sigdata->n_samples; i++) { + it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i); + } + + sigdata->restart_position = 0; + + chunk = get_chunk_by_type(mod, DUMB_ID('P','L','E','N'), 0); + if (!chunk || chunk->size < 2) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1]; + // what if this is > 128? + + if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0); + if (!chunk || chunk->size < (unsigned)sigdata->n_orders) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->order = (unsigned char *) malloc(sigdata->n_orders); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + memcpy(sigdata->order, chunk->data, sigdata->n_orders); + + /* Work out how many patterns there are. */ + chunk = get_chunk_by_type(mod, DUMB_ID('S','L','E','N'), 0); + if (!chunk || chunk->size < 2) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1]; + + j = get_chunk_count(mod, DUMB_ID('P','B','O','D')); + if (sigdata->n_patterns > (int)j) sigdata->n_patterns = (int)j; + + if (!sigdata->n_patterns) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + + sigdata->pattern = (IT_PATTERN *) malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + for (i = 0; i < (unsigned)sigdata->n_patterns; i++) + sigdata->pattern[i].entry = NULL; + + /* Read in the patterns */ + for (i = 0; i < (unsigned)sigdata->n_patterns; i++) { + chunk = get_chunk_by_type(mod, DUMB_ID('P','B','O','D'), i); + if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size, n_channels) != 0) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + } + + /* And finally, the sample data */ + k = get_chunk_count(mod, DUMB_ID('S','B','O','D')); + for (i = 0, j = 0; i < (unsigned)sigdata->n_samples, j < k; i++) { + if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { + chunk = get_chunk_by_type(mod, DUMB_ID('S','B','O','D'), j); + if (it_okt_read_sample_data(&sigdata->sample[i], (const char *)chunk->data, chunk->size)) { + _dumb_it_unload_sigdata(sigdata); + free_okt(mod); + return NULL; + } + j++; + } + } + + chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); + + for (i = 0, j = 0; i < n_channels, j < 4; j++) { + k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1]; + l = (j == 1 || j == 2) ? 48 : 16; + if (k == 0) { + sigdata->channel_pan[i++] = l; + } + else if (k == 1) { + sigdata->channel_pan[i++] = l; + sigdata->channel_pan[i++] = l; + } + } + + free_okt(mod); + + /* Now let's initialise the remaining variables, and we're done! */ + sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + /* We want 50 ticks per second; 50/6 row advances per second; + * 50*10=500 row advances per minute; 500/4=125 beats per minute. + */ + sigdata->tempo = 125; + sigdata->pan_separation = 128; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + memset(sigdata->channel_pan + n_channels, 32, DUMB_IT_N_CHANNELS - n_channels); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + + + +DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_okt_load_sigdata(f, 0); + + if (!sigdata) + return NULL; + + { + const char *tag[1][2]; + tag[0][0] = "FORMAT"; + tag[0][1] = "Oktalyzer"; + return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/dumb/src/it/readokt2.c b/dumb/src/it/readokt2.c new file mode 100644 index 000000000..66dd1f6d4 --- /dev/null +++ b/dumb/src/it/readokt2.c @@ -0,0 +1,29 @@ +/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readokt2.c - Function to read an Oktalyzer / / \ \ + * module from an open file and do | < / \_ + * an initial run-through. | \/ /\ / + * \_ / > / + * | \ / / + * By Chris Moeller. | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f) +{ + DUH *duh = dumb_read_okt_quick(f); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj index 896ce8a8f..3f1373cc3 100644 --- a/dumb/vc6/dumb_static/dumb_static.vcproj +++ b/dumb/vc6/dumb_static/dumb_static.vcproj @@ -1564,6 +1564,14 @@ RelativePath="..\..\src\it\loadmtm2.c" > + + + + @@ -1782,6 +1790,14 @@ RelativePath="..\..\src\it\readmtm.c" > + + + + From d1ada02edbe3b6a6b70322aa7c1286f6a8f20c44 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:11:27 +0000 Subject: [PATCH 150/387] Update DUMB to revision 33cd2c469ae9872dd0710297760bfb1dfe53a56d - Made Oktalyzer reader more tolerant of truncated files SVN r4080 (trunk) --- dumb/src/it/readokt.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dumb/src/it/readokt.c b/dumb/src/it/readokt.c index cab3c7a05..9ae059575 100644 --- a/dumb/src/it/readokt.c +++ b/dumb/src/it/readokt.c @@ -230,6 +230,8 @@ static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) chunk->type = bytes_read; chunk->size = dumbfile_mgetl( f ); + if ( dumbfile_error( f ) ) break; + chunk->data = (unsigned char *) malloc( chunk->size ); if ( !chunk->data ) { @@ -241,14 +243,25 @@ static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f ); if ( bytes_read < (long)chunk->size ) { - free( mod->chunks ); - free( mod ); - return NULL; + if ( bytes_read <= 0 ) { + free( chunk->data ); + break; + } else { + chunk->size = bytes_read; + mod->chunk_count++; + break; + } } mod->chunk_count++; } + if ( !mod->chunk_count ) { + if ( mod->chunks ) free(mod->chunks); + free(mod); + mod = NULL; + } + return mod; } @@ -484,6 +497,9 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f, int restrict) j++; } } + for (; i < sigdata->n_samples; i++) { + sigdata->sample[i].flags = 0; + } chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); From 612d16e11c84be89e4925e5475f462e2ccec13ec Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:25:30 +0000 Subject: [PATCH 151/387] - Added Oktalyzer loading support to ZDoom. SVN r4081 (trunk) --- src/sound/music_dumb.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index d0423e256..8405228a3 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -986,6 +986,15 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) duh = dumb_read_asy_quick(f); } } + else if (size >= 8 && + dstart[0] == MAKE_ID('O','K','T','A') && + dstart[1] == MAKE_ID('S','O','N','G')) + { + if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + { + duh = dumb_read_okt_quick(f); + } + } if ( ! duh ) { From 865a237b2ced42413b1ebbddb50b6e11aa1d3047 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:29:50 +0000 Subject: [PATCH 152/387] Update DUMB to revision c2cb42ff918b398ec8c305ddc6574f9f8f945ad9 - Implemented support for STM 1.x format - Flagged STM files as stereo, as they should be SVN r4082 (trunk) --- dumb/src/it/readstm.c | 45 +++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index 8b8e8c82d..6999d7644 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -192,7 +192,7 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char -static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) +static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) { DUMB_IT_SIGDATA *sigdata; @@ -227,8 +227,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) return NULL; } - /* *version = dumbfile_mgetw(f); */ - dumbfile_skip( f, 2 ); + *version = dumbfile_mgetw(f); sigdata->song_message = NULL; sigdata->order = NULL; @@ -247,7 +246,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) sigdata->pan_separation = 128; /** WARNING: which ones? */ - sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; + sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_STEREO; sigdata->speed = dumbfile_getc(f) >> 4; if ( sigdata->speed < 1 ) sigdata->speed = 1; @@ -300,7 +299,8 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) } /* Orders, byte each, length = sigdata->n_orders (should be even) */ - dumbfile_getnc( sigdata->order, 128, f ); + dumbfile_getnc( sigdata->order, *version >= 0x200 ? 128 : 64, f ); + if (*version < 0x200) memset( sigdata->order + 64, 0xFF, 64 ); sigdata->restart_position = 0; for ( n = 127; n >= 0; --n ) { @@ -344,42 +344,45 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) return sigdata; } -/*static char hexdigit(int in) -{ - if (in < 10) return in + '0'; - else return in + 'A' - 10; -}*/ - DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f) { sigdata_t *sigdata; - /*int ver;*/ + int ver; DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - sigdata = it_stm_load_sigdata(f /*, &ver*/); + sigdata = it_stm_load_sigdata(f , &ver); if (!sigdata) return NULL; { - /*char version[16];*/ + char version[16]; const char *tag[2][2]; tag[0][0] = "TITLE"; tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; tag[1][0] = "FORMAT"; - tag[1][1] = "STM"; - /*version[0] = 'S'; + version[0] = 'S'; version[1] = 'T'; version[2] = 'M'; version[3] = ' '; version[4] = 'v'; - version[5] = hexdigit((ver >> 8) & 15); + version[5] = '0' + ((ver >> 8) & 15); version[6] = '.'; - version[7] = hexdigit((ver >> 4) & 15); - version[8] = hexdigit(ver & 15); - version[9] = 0; - tag[1][1] = (const char *) &version;*/ + if ((ver & 255) > 99) + { + version[7] = '0' + ((ver & 255) / 100 ); + version[8] = '0' + (((ver & 255) / 10) % 10); + version[9] = '0' + ((ver & 255) % 10); + version[10] = 0; + } + else + { + version[7] = '0' + ((ver & 255) / 10); + version[8] = '0' + ((ver & 255) % 10); + version[9] = 0; + } + tag[1][1] = (const char *) &version; return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); } } From 277c233f5d2540081f94ff037048b629f631952a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:32:14 +0000 Subject: [PATCH 153/387] Update DUMB to revision d78c28566689e3fca51f1fbb7208cde8b6e190a6 - Fixed STM sample reading SVN r4083 (trunk) --- dumb/src/it/readstm.c | 70 +++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index 6999d7644..1c9994e4e 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -28,14 +28,16 @@ #define strnicmp strncasecmp #endif -static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) +static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned short *offset ) { dumbfile_getnc( sample->filename, 12, f ); sample->filename[12] = 0; memcpy( sample->name, sample->filename, 13 ); - dumbfile_skip( f, 2 + 2 ); + dumbfile_skip( f, 2 ); + + *offset = dumbfile_igetw( f ); sample->length = dumbfile_igetw( f ); sample->loop_start = dumbfile_igetw( f ); @@ -78,24 +80,15 @@ static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) return dumbfile_error(f); } -static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f ) +static int it_stm_read_sample_data( IT_SAMPLE *sample, void *data_block, long offset ) { - int32 n; - if ( ! sample->length ) return 0; - n = dumbfile_pos( f ); - if ( n & 15 ) { - if ( dumbfile_skip( f, 16 - ( n & 15 ) ) ) - return -1; - } - sample->data = malloc( sample->length ); if (!sample->data) return -1; - if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length ) - return -1; + memcpy( sample->data, (unsigned char*)data_block + offset, sample->length ); return 0; } @@ -198,8 +191,14 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) char tracker_name[ 8 ]; + unsigned short sample_offset[ 31 ]; + + void *data_block; + int n; + long o, p, q; + sigdata = malloc(sizeof(*sigdata)); if (!sigdata) return NULL; @@ -286,7 +285,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) sigdata->channel_pan[ 3 ] = 16; for ( n = 0; n < sigdata->n_samples; ++n ) { - if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) { + if ( it_stm_read_sample_header( &sigdata->sample[ n ], f, &sample_offset[ n ] ) ) { _dumb_it_unload_sigdata( sigdata ); return NULL; } @@ -332,13 +331,54 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) free( buffer ); } + o = LONG_MAX; + p = 0; + for ( n = 0; n < sigdata->n_samples; ++n ) { - if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) { + if ((sigdata->sample[ n ].flags & IT_SAMPLE_EXISTS) && sample_offset[ n ]) { + q = ((long)sample_offset[ n ]) * 16; + if (q < o) { + o = q; + } + if (q + sigdata->sample[ n ].length > p) { + p = q + sigdata->sample[ n ].length; + } + } + else { + sigdata->sample[ n ].flags = 0; + sigdata->sample[ n ].length = 0; + } + } + + data_block = malloc( p - o ); + if ( !data_block ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + + for ( n = 0, q = o / 16; n < sigdata->n_samples; ++n ) { + if ( sample_offset[ n ] ) { + sample_offset[ n ] -= q; + } + } + + dumbfile_skip( f, o - dumbfile_pos( f ) ); + if ( dumbfile_getnc( (char*)data_block, p - o, f ) != p - o ) { + free( data_block ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + + for ( n = 0; n < sigdata->n_samples; ++n ) { + if ( it_stm_read_sample_data( &sigdata->sample[ n ], data_block, ((long)sample_offset[ n ]) * 16 ) ) { + free( data_block ); _dumb_it_unload_sigdata( sigdata ); return NULL; } } + free( data_block ); + _dumb_it_fix_invalid_orders(sigdata); return sigdata; From e66f50fb76ec3c28811827a0a44cd2926e075f62 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:33:10 +0000 Subject: [PATCH 154/387] Update DUMB to revision f5f34570905e87f1933a0220d71d0d48c05b9b49 - Added a workaround for bad sample offsets in STM files - Disabled inserting note cut commands in STM files, as there is no such command in the format SVN r4084 (trunk) --- dumb/src/it/readstm.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index 1c9994e4e..be1b15720 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -134,10 +134,6 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char entry->effectvalue = buffer[ pos + 3 ]; if ( entry->instrument && entry->instrument < 32 ) entry->mask |= IT_ENTRY_INSTRUMENT; - if ( note == 0xFC || note == 0xFE ) { - entry->mask |= IT_ENTRY_NOTE; - entry->note = IT_NOTE_CUT; - } if ( note < 251 ) { entry->mask |= IT_ENTRY_NOTE; entry->note = ( note >> 4 ) * 12 + ( note & 0x0F ); @@ -362,8 +358,15 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) } } - dumbfile_skip( f, o - dumbfile_pos( f ) ); - if ( dumbfile_getnc( (char*)data_block, p - o, f ) != p - o ) { + q = o - dumbfile_pos( f ); + p -= o; + o = 0; + if ( q >= 0 ) dumbfile_skip( f, q ); + else { + o = -q; + memset ( data_block, 0, o ); + } + if ( dumbfile_getnc( (char*)data_block + o, p - o, f ) != p - o ) { free( data_block ); _dumb_it_unload_sigdata( sigdata ); return NULL; From 5490b08c88882eeb4d49252c418d9a797cf97e0e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:34:58 +0000 Subject: [PATCH 155/387] Update DUMB to revision 7def196332594817f94138dce2942007d232d407 - Corrected volume slide behavior for S3M playback, and also adjusted the slide volume level clipping range for S3M to 0-63 - Updated S3M playback to share memory between DEFIJQRS effects - Adjusted S3M reader to a lower master volume level scale SVN r4085 (trunk) --- dumb/src/it/itrender.c | 130 ++++++++++++++++++++++++++++++----------- dumb/src/it/reads3m.c | 4 +- 2 files changed, 98 insertions(+), 36 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 34a698d7f..0b2832c0a 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1120,10 +1120,11 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) } if (channel->volslide) { + int clip = (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; channel->volume += channel->volslide; - if (channel->volume > 64) { + if (channel->volume > clip) { if (channel->volslide >= 0) - channel->volume = 64; + channel->volume = clip; else channel->volume = 0; } @@ -1286,8 +1287,14 @@ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY * case IT_S: { unsigned char effectvalue = entry->effectvalue; - if (effectvalue == 0) - effectvalue = channel->lastS; + if (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) { + if (effectvalue == 0) + effectvalue = channel->lastDKL; + channel->lastDKL = effectvalue; + } else { + if (effectvalue == 0) + effectvalue = channel->lastS; + } channel->lastS = effectvalue; switch (effectvalue >> 4) { case IT_S_PATTERN_LOOP: @@ -2043,24 +2050,43 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastDKL; channel->lastDKL = v; } - if ((v & 0x0F) == 0) { /* Dx0 */ - channel->volslide = v >> 4; - if (channel->volslide == 15 && !(sigdata->flags & IT_WAS_AN_XM)) { - channel->volume += 15; - if (channel->volume > 64) channel->volume = 64; + if (!(sigdata->flags & IT_WAS_AN_XM)) { + int clip = (sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; + if ((v & 0x0F) == 0x0F) { + if (!(v & 0xF0)) { + channel->volslide = -15; + channel->volume -= 15; + if (channel->volume > clip) channel->volume = 0; + } else { + channel->volume += v >> 4; + if (channel->volume > clip) channel->volume = clip; + } + } else if ((v & 0xF0) == 0xF0) { + if (!(v & 0x0F)) { + channel->volslide = 15; + channel->volume += 15; + if (channel->volume > clip) channel->volume = clip; + } else { + channel->volume -= v & 15; + if (channel->volume > clip) channel->volume = 0; + } + } else if (!(v & 0x0F)) { + channel->volslide = v >> 4; + } else { + channel->volslide = -(v & 15); } - } else if ((v & 0xF0) == 0) { /* D0x */ - channel->volslide = -v; - if (channel->volslide == -15 && !(sigdata->flags & IT_WAS_AN_XM)) { - channel->volume -= 15; + } else { + if ((v & 0x0F) == 0) { /* Dx0 */ + channel->volslide = v >> 4; + } else if ((v & 0xF0) == 0) { /* D0x */ + channel->volslide = -v; + } else if ((v & 0x0F) == 0x0F) { /* DxF */ + channel->volume += v >> 4; + if (channel->volume > 64) channel->volume = 64; + } else if ((v & 0xF0) == 0xF0) { /* DFx */ + channel->volume -= v & 15; if (channel->volume > 64) channel->volume = 0; } - } else if ((v & 0x0F) == 0x0F) { /* DxF */ - channel->volume += v >> 4; - if (channel->volume > 64) channel->volume = 64; - } else if ((v & 0xF0) == 0xF0) { /* DFx */ - channel->volume -= v & 15; - if (channel->volume > 64) channel->volume = 0; } } break; @@ -2098,6 +2124,10 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than else channel->xm_lastX2 = v & 15; } + } else if (sigdata->flags & IT_WAS_AN_S3M) { + if (v == 0) + v = channel->lastDKL; + channel->lastDKL = v; } else { if (v == 0) v = channel->lastEF; @@ -2129,6 +2159,10 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than else channel->xm_lastX1 = v & 15; } + } else if (sigdata->flags & IT_WAS_AN_S3M) { + if (v == 0) + v = channel->lastDKL; + channel->lastDKL = v; } else { if (v == 0) v = channel->lastEF; @@ -2202,13 +2236,20 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than case IT_TREMOR: { unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->lastI; + if (v == 0) { + if (sigdata->flags & IT_WAS_AN_S3M) + v = channel->lastDKL; + else + v = channel->lastI; + } else if (!(sigdata->flags & IT_OLD_EFFECTS)) { if (v & 0xF0) v -= 0x10; if (v & 0x0F) v -= 0x01; } - channel->lastI = v; + if (sigdata->flags & IT_WAS_AN_S3M) + channel->lastDKL = v; + else + channel->lastI = v; channel->tremor_time |= 128; } update_tremor(channel); @@ -2220,9 +2261,15 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than * and we use lastJ for portamento down instead. */ if (!(sigdata->flags & IT_WAS_AN_XM)) { - if (v == 0) - v = channel->lastJ; - channel->lastJ = v; + if (sigdata->flags & IT_WAS_AN_S3M) { + if (v == 0) + v = channel->lastDKL; + channel->lastDKL = v; + } else { + if (v == 0) + v = channel->lastJ; + channel->lastJ = v; + } } channel->arpeggio = ((v & 0xF0) << 4) | (v & 0x0F); channel->arpeggio_shift = 16; @@ -2361,11 +2408,16 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than if (sigdata->flags & IT_WAS_AN_XM) { if ((v & 0x0F) == 0) v |= channel->lastQ & 0x0F; if ((v & 0xF0) == 0) v |= channel->lastQ & 0xF0; + channel->lastQ = v; + } else if (sigdata->flags & IT_WAS_AN_S3M) { + if (v == 0) + v = channel->lastDKL; + channel->lastDKL = v; } else { if (v == 0) v = channel->lastQ; + channel->lastQ = v; } - channel->lastQ = v; if ((v & 0x0F) == 0) v |= 0x01; channel->retrig = v; if (entry->mask & IT_ENTRY_NOTE) { @@ -2390,14 +2442,24 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than break; case IT_TREMOLO: { - unsigned char speed = entry->effectvalue >> 4; - unsigned char depth = entry->effectvalue & 15; - if (speed == 0) - speed = channel->lastRspeed; - channel->lastRspeed = speed; - if (depth == 0) - depth = channel->lastRdepth; - channel->lastRdepth = depth; + unsigned char speed, depth; + if (sigdata->flags & IT_WAS_AN_S3M) { + unsigned char v = entry->effectvalue; + if (v == 0) + v = channel->lastDKL; + channel->lastDKL = v; + speed = v >> 4; + depth = v & 15; + } else { + speed = entry->effectvalue >> 4; + depth = entry->effectvalue & 15; + if (speed == 0) + speed = channel->lastRspeed; + channel->lastRspeed = speed; + if (depth == 0) + depth = channel->lastRdepth; + channel->lastRdepth = depth; + } if (channel->playing) { channel->playing->tremolo_speed = speed; channel->playing->tremolo_depth = depth; diff --git a/dumb/src/it/reads3m.c b/dumb/src/it/reads3m.c index c9266ac6c..c55e9f615 100644 --- a/dumb/src/it/reads3m.c +++ b/dumb/src/it/reads3m.c @@ -557,8 +557,8 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv) return NULL; } - sigdata->global_volume = dumbfile_getc(f) << 1; - if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128; + sigdata->global_volume = dumbfile_getc(f) * 16 / 11; + if ( !sigdata->global_volume || sigdata->global_volume > 93 ) sigdata->global_volume = 93; sigdata->speed = dumbfile_getc(f); if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? sigdata->tempo = dumbfile_getc(f); From 13070798128f8fe59cec84379485e6ff195eda18 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:35:42 +0000 Subject: [PATCH 156/387] Update DUMB to revision 07f761e918e8a621f64242dd1a631ceba03cc920 - Fixed IT New Note Action duplicate check types for sample and instrument SVN r4086 (trunk) --- dumb/src/it/itrender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 0b2832c0a..d71bdac70 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1619,7 +1619,7 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING * playing = sigrenderer->playing[i]; if (playing && playing->channel == channel && playing->instrument->dup_check_type) { - int match = 0; + int match = 1; switch (playing->instrument->dup_check_type) { case DCT_NOTE: From 4ce4a05518dc502392b26434b7736b2cc1574a2a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:36:35 +0000 Subject: [PATCH 157/387] Update DUMB to revision 4a268f95b7d2a116e3ea53d297c1d5a29f46bf07 - Added missing song restart position initialization to AM, AMFF, and DSM readers SVN r4087 (trunk) --- dumb/src/it/readam.c | 2 ++ dumb/src/it/readdsmf.c | 1 + 2 files changed, 3 insertions(+) diff --git a/dumb/src/it/readam.c b/dumb/src/it/readam.c index 9910b1d82..6a4994df5 100644 --- a/dumb/src/it/readam.c +++ b/dumb/src/it/readam.c @@ -331,6 +331,7 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream ) sigdata->n_instruments = 0; sigdata->n_orders = 0; + sigdata->restart_position = 0; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); @@ -553,6 +554,7 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream ) sigdata->n_instruments = 0; sigdata->n_orders = 0; + sigdata->restart_position = 0; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); diff --git a/dumb/src/it/readdsmf.c b/dumb/src/it/readdsmf.c index 275f37ffa..5db09a75c 100644 --- a/dumb/src/it/readdsmf.c +++ b/dumb/src/it/readdsmf.c @@ -265,6 +265,7 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream ) sigdata->n_instruments = 0; sigdata->n_orders = 0; + sigdata->restart_position = 0; memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); From 86690be58bfee1d87846a7950fd3cb389989f403 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:37:17 +0000 Subject: [PATCH 158/387] Update DUMB to revision 667b479457fd7c1e9aff4ea8301295c81762bdf5 - Fixed IT envelope reading for node counts over 25, which are invalid SVN r4088 (trunk) --- dumb/src/it/itread.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index b06fbbca5..5b7432060 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -306,6 +306,8 @@ static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) envelope->loop_end = dumbfile_getc(f); envelope->sus_loop_start = dumbfile_getc(f); envelope->sus_loop_end = dumbfile_getc(f); + if (envelope->n_nodes > 25) + envelope->n_nodes = 25; for (n = 0; n < envelope->n_nodes; n++) { envelope->node_y[n] = dumbfile_getc(f); envelope->node_t[n] = dumbfile_igetw(f); From 778bfd679b10fe9fda1845b547dddf0f5ccfd207 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:38:07 +0000 Subject: [PATCH 159/387] Update DUMB to revision 71ecdc7274a7fa33af0a0dea915eb3a294b0b04a - Fixed IT stereo samples SVN r4089 (trunk) --- dumb/include/internal/it.h | 4 +++- dumb/src/it/itread.c | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 0c8bf144c..74a08d567 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -54,7 +54,7 @@ sigdata->flags & IT_COMPATIBLE_GXX * handle ambiguities in the format specification. The correct code in each * case will be determined most likely by experimentation. */ -#define STEREO_SAMPLES_COUNT_AS_TWO +//#define STEREO_SAMPLES_COUNT_AS_TWO #define INVALID_ORDERS_END_SONG #define INVALID_NOTES_CAUSE_NOTE_CUT #define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP @@ -899,4 +899,6 @@ void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry); int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f); +void _dumb_it_interleave_stereo_sample(IT_SAMPLE *sample); + #endif /* INTERNAL_IT_H */ diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index 5b7432060..12cd6828b 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -684,15 +684,36 @@ static int32 it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char conv else decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4))); } else if (sample->flags & IT_SAMPLE_16BIT) { - if (convert & 2) + if (sample->flags & IT_SAMPLE_STEREO) { + if (convert & 2) { + for (n = 0; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_mgetw(f); + for (n = 1; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_mgetw(f); + } else { + for (n = 0; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_igetw(f); + for (n = 1; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_igetw(f); + } + } else { + if (convert & 2) + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] = dumbfile_mgetw(f); + else + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] = dumbfile_igetw(f); + } + } else { + if (sample->flags & IT_SAMPLE_STEREO) { + for (n = 0; n < datasize; n += 2) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + for (n = 1; n < datasize; n += 2) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + } else for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] = dumbfile_mgetw(f); - else - for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] = dumbfile_igetw(f); - } else - for (n = 0; n < datasize; n++) - ((signed char *)sample->data)[n] = dumbfile_getc(f); + ((signed char *)sample->data)[n] = dumbfile_getc(f); + } if (dumbfile_error(f)) return -1; From ab801ffb7657b88708a9449a9c936453b24e409d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:38:54 +0000 Subject: [PATCH 160/387] Update DUMB to revision 8c3e510483ba1fdec19017dad4a5004d694177eb - Corrected old style PSM note data SVN r4090 (trunk) --- dumb/src/it/readoldpsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/readoldpsm.c b/dumb/src/it/readoldpsm.c index 3c764af25..5c0441c78 100644 --- a/dumb/src/it/readoldpsm.c +++ b/dumb/src/it/readoldpsm.c @@ -296,7 +296,7 @@ static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, if (flags & 0x80) { if ((*ptr < 60) && (channel < pchans)) { entry->mask |= IT_ENTRY_NOTE; - entry->note = *ptr + 36; + entry->note = *ptr + 35; } ptr++; if (*ptr) { From 3681a6673f3fbbf069dc91fcb009249df5c6b832 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:40:03 +0000 Subject: [PATCH 161/387] Update DUMB to revision 0e95459562669335f7de543d063cfa57d25a8b77 - Fixed MOD vibrato depth - Fixed XM tremolo ramp and square waveform tracking SVN r4091 (trunk) --- dumb/src/it/itrender.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index d71bdac70..c5b7eac10 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1974,6 +1974,13 @@ static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELO extern const char xm_convert_vibrato[]; +const char mod_convert_vibrato[] = { + IT_VIBRATO_SINE, + IT_VIBRATO_RAMP_UP, /* this will be inverted by IT_OLD_EFFECTS */ + IT_VIBRATO_XM_SQUARE, + IT_VIBRATO_XM_SQUARE +}; + /* Returns 1 if a callback caused termination of playback. */ static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) { @@ -2219,7 +2226,7 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than if (depth == 0) depth = channel->lastHdepth; else { - if (sigdata->flags & IT_OLD_EFFECTS) + if (sigdata->flags & IT_OLD_EFFECTS && !(sigdata->flags & IT_WAS_A_MOD)) depth <<= 3; else depth <<= 2; @@ -2491,7 +2498,8 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than case IT_S_SET_VIBRATO_WAVEFORM: { int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; + if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; + else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->vibrato_waveform = waveform; if (channel->playing) { channel->playing->vibrato_waveform = waveform; @@ -2503,7 +2511,8 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than case IT_S_SET_TREMOLO_WAVEFORM: { int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; + if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; + else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->tremolo_waveform = waveform; if (channel->playing) { channel->playing->tremolo_waveform = waveform; @@ -4287,13 +4296,13 @@ static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *play vol = (rand() % 129) - 64; break; case 4: - vol = it_xm_squarewave[playing->vibrato_time]; + vol = it_xm_squarewave[playing->tremolo_time]; break; case 5: - vol = it_xm_ramp[playing->vibrato_time]; + vol = it_xm_ramp[playing->tremolo_time]; break; case 6: - vol = it_xm_ramp[255-playing->vibrato_time]; + vol = it_xm_ramp[255-((sigrenderer->sigdata->flags & IT_WAS_A_MOD)?playing->vibrato_time:playing->tremolo_time)]; break; } vol *= playing->tremolo_depth; From 4163817edad3cb42c21a525b530484be60523078 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:40:36 +0000 Subject: [PATCH 162/387] Update DUMB to revision 5bee3e5ba3d57d1b16dda6d82c18fb417781625b - Fixed XM reader for files with smaller than expected instrument or sample header sizes SVN r4092 (trunk) --- dumb/src/it/readxm.c | 187 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 11 deletions(-) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 7d1b4657b..4afe36568 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -111,6 +111,7 @@ typedef struct XM_INSTRUMENT_EXTRA int vibrato_sweep; /* 0-0xFF */ int vibrato_depth; /* 0-0x0F */ int vibrato_speed; /* 0-0x3F */ + int sample_header_size; } XM_INSTRUMENT_EXTRA; @@ -359,6 +360,116 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data +typedef struct LIMITED_XM LIMITED_XM; + +struct LIMITED_XM +{ + unsigned char *buffered; + long ptr, limit, allocated; + DUMBFILE *remaining; +}; + +/* XXX */ +struct DUMBFILE +{ + DUMBFILE_SYSTEM *dfs; + void *file; + long pos; +}; + +static int limit_xm_resize(void *f, long n) +{ + DUMBFILE *df = f; + LIMITED_XM *lx = df->file; + if (lx->buffered || n) { + if (n > lx->allocated) { + unsigned char *buffered = realloc( lx->buffered, n ); + if ( !buffered ) return -1; + lx->buffered = buffered; + memset( buffered + lx->allocated, 0, n - lx->allocated ); + lx->allocated = n; + } + if ( dumbfile_getnc( lx->buffered, n, lx->remaining ) < n ) return -1; + } else if (!n) { + if ( lx->buffered ) free( lx->buffered ); + lx->buffered = NULL; + lx->allocated = 0; + } + lx->limit = n; + lx->ptr = 0; + return 0; +} + +static int limit_xm_skip(void *f, long n) +{ + LIMITED_XM *lx = f; + lx->ptr += n; + return 0; +} + + + +static int limit_xm_getc(void *f) +{ + LIMITED_XM *lx = f; + if (lx->ptr >= lx->allocated) { + return 0; + } + return lx->buffered[lx->ptr++]; +} + + + +static long limit_xm_getnc(char *ptr, long n, void *f) +{ + LIMITED_XM *lx = f; + int left; + left = lx->allocated - lx->ptr; + if (n > left) { + if (left > 0) { + memcpy( ptr, lx->buffered + lx->ptr, left ); + memset( ptr + left, 0, n - left ); + } else { + memset( ptr, 0, n ); + } + } else { + memcpy( ptr, lx->buffered + lx->ptr, n ); + } + lx->ptr += n; + return n; +} + + + +static void limit_xm_close(void *f) +{ + LIMITED_XM *lx = f; + if (lx->buffered) free(lx->buffered); + /* Do NOT close lx->remaining */ + free(f); +} + + + +DUMBFILE_SYSTEM limit_xm_dfs = { + NULL, + &limit_xm_skip, + &limit_xm_getc, + &limit_xm_getnc, + &limit_xm_close +}; + +static DUMBFILE *dumbfile_limit_xm(DUMBFILE *f) +{ + LIMITED_XM * lx = malloc(sizeof(*lx)); + lx->remaining = f; + lx->buffered = NULL; + lx->ptr = 0; + lx->limit = 0; + lx->allocated = 0; + return dumbfile_open_ex( lx, &limit_xm_dfs ); +} + static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f) { uint32 size, bytes_read; @@ -370,8 +481,15 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA * So unread bytes must be skipped before reading the first sample * header. */ + + if ( limit_xm_resize( f, 4 ) < 0 ) return -1; + size = dumbfile_igetl(f); + if ( size == 0 ) size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; + + if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1; + dumbfile_getnc(instrument->name, 22, f); instrument->name[22] = 0; instrument->filename[0] = 0; @@ -385,12 +503,9 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA if (extra->n_samples) { /* sample header size */ - dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here - /*i = dumbfile_igetl(f); - if (i && i != 0x28) { // XXX some crap with 0 here - TRACE("XM error: unexpected sample header size\n"); - return -1; - }*/ + i = dumbfile_igetl(f); + if (!i) i = 0x28; + extra->sample_header_size = i; /* sample map */ for (i = 0; i < 96; i++) { @@ -476,7 +591,7 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA for (i = 0; i < 96; i++) instrument->map_sample[i] = 0; - if (dumbfile_skip(f, size - bytes_read)) + if (size > bytes_read && dumbfile_skip(f, size - bytes_read)) return -1; instrument->new_note_action = NNA_NOTE_CUT; @@ -924,16 +1039,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (i = 0; i < sigdata->n_instruments; i++) { XM_INSTRUMENT_EXTRA extra; - if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { + DUMBFILE * lf = dumbfile_limit_xm( f ); + if ( !lf ) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) { // XXX if ( ! i ) { TRACE("XM error: instrument %d\n", i+1); + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } else { + dumbfile_close( lf ); sigdata->n_instruments = i; break; } @@ -948,17 +1071,31 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); if (!sigdata->sample) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } for (j = total_samples; j < total_samples+extra.n_samples; j++) sigdata->sample[j].data = NULL; + if ( limit_xm_resize( lf, 0 ) < 0 ) { + dumbfile_close( lf ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + /* read instrument's samples */ for (j = 0; j < extra.n_samples; j++) { IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; - int b = it_xm_read_sample_header(sample, f); + int b; + if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) { + dumbfile_close( lf ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + b = it_xm_read_sample_header(sample, lf); if (b < 0) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } @@ -975,12 +1112,15 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) } for (j = 0; j < extra.n_samples; j++) { if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } } total_samples += extra.n_samples; } + + dumbfile_close( lf ); } sigdata->n_samples = total_samples; @@ -1012,8 +1152,16 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (i = 0; i < sigdata->n_instruments; i++) { XM_INSTRUMENT_EXTRA extra; - if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { + DUMBFILE * lf = dumbfile_limit_xm( f ); + if ( !lf ) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) { TRACE("XM error: instrument %d\n", i+1); + dumbfile_close(lf); free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; @@ -1026,6 +1174,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); if (!sigdata->sample) { + dumbfile_close( lf ); free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; @@ -1033,10 +1182,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (j = total_samples; j < total_samples+extra.n_samples; j++) sigdata->sample[j].data = NULL; + if ( limit_xm_resize( lf, 0 ) < 0 ) { + dumbfile_close( lf ); + free( roguebytes ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + /* read instrument's samples */ for (j = 0; j < extra.n_samples; j++) { IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; - int b = it_xm_read_sample_header(sample, f); + int b; + if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) { + dumbfile_close( lf ); + free( roguebytes ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + b = it_xm_read_sample_header(sample, lf); if (b < 0) { free(roguebytes); _dumb_it_unload_sigdata(sigdata); @@ -1055,6 +1218,8 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) } total_samples += extra.n_samples; } + + dumbfile_close( lf ); } sigdata->n_samples = total_samples; From b7f4f498ffd8aba8e8785d158cb45186a51d3856 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:41:29 +0000 Subject: [PATCH 163/387] Update DUMB to revision 7ad496ecf2fd658a51de55df0e7f0257025038cc - Added sanity checking to XM reader instrument and sample header sizes - Added footer tag checking to prevent tags from reaching the module reader SVN r4093 (trunk) --- dumb/src/it/readxm.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 4afe36568..0032c5d4d 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -400,6 +400,13 @@ static int limit_xm_resize(void *f, long n) return 0; } +static int limit_xm_skip_end(void *f, long n) +{ + DUMBFILE *df = f; + LIMITED_XM *lx = df->file; + return dumbfile_skip( lx->remaining, n ); +} + static int limit_xm_skip(void *f, long n) { LIMITED_XM *lx = f; @@ -476,6 +483,8 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA unsigned short vol_points[24]; unsigned short pan_points[24]; int i, type; + const unsigned long max_size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; + unsigned long skip_end = 0; /* Header size. Tends to be more than the actual size of the structure. * So unread bytes must be skipped before reading the first sample @@ -486,7 +495,12 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA size = dumbfile_igetl(f); - if ( size == 0 ) size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; + if ( size == 0 ) size = max_size; + else if ( size > max_size ) + { + skip_end = size - max_size; + size = max_size; + } if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1; @@ -504,7 +518,7 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA if (extra->n_samples) { /* sample header size */ i = dumbfile_igetl(f); - if (!i) i = 0x28; + if (!i || i > 0x28) i = 0x28; extra->sample_header_size = i; /* sample map */ @@ -594,6 +608,9 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA if (size > bytes_read && dumbfile_skip(f, size - bytes_read)) return -1; + if (skip_end && limit_xm_skip_end(f, skip_end)) + return -1; + instrument->new_note_action = NNA_NOTE_CUT; instrument->dup_check_type = DCT_OFF; instrument->dup_check_action = DCA_NOTE_CUT; From 25542b11bdff2e16b02d5fe7c89e469d3462bf01 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:42:07 +0000 Subject: [PATCH 164/387] Update DUMB to revision 8d87ab8b9ec398cf3831b87dc969a28e278f3105 - Fixed XM sample header size handling to always assume a size of 0x28 SVN r4094 (trunk) --- dumb/src/it/readxm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 0032c5d4d..4e3dbee0b 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -517,8 +517,10 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA if (extra->n_samples) { /* sample header size */ - i = dumbfile_igetl(f); - if (!i || i > 0x28) i = 0x28; + /*i = dumbfile_igetl(f); + if (!i || i > 0x28) i = 0x28;*/ + dumbfile_skip(f, 4); + i = 0x28; extra->sample_header_size = i; /* sample map */ From e1ec8df32d775f32b8aa269eba164a7da4be5b7e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:43:08 +0000 Subject: [PATCH 165/387] Update DUMB to revision 15b780d08f2ee6f50a9843dc7479349f4deee5a7 - Fixed most effects applying to background voices SVN r4095 (trunk) --- dumb/src/it/itrender.c | 327 ++++++++++++++++++++++++++++------------- 1 file changed, 224 insertions(+), 103 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index c5b7eac10..68eef44f5 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1032,6 +1032,15 @@ static void update_retrig(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) } +static void update_smooth_effects_playing(IT_PLAYING *playing) +{ + playing->vibrato_time += playing->vibrato_n * + (playing->vibrato_speed << 2); + playing->tremolo_time += playing->tremolo_speed << 2; + playing->panbrello_time += playing->panbrello_speed; + if (playing->panbrello_waveform == 3) + playing->panbrello_random = (rand() % 129) - 64; +} static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) { @@ -1042,12 +1051,15 @@ static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) IT_PLAYING *playing = channel->playing; if (playing) { - playing->vibrato_time += playing->vibrato_n * - (playing->vibrato_speed << 2); - playing->tremolo_time += playing->tremolo_speed << 2; - playing->panbrello_time += playing->panbrello_speed; - if (playing->panbrello_waveform == 3) - playing->panbrello_random = (rand() % 129) - 64; + update_smooth_effects_playing(playing); + } + } + + for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { + IT_PLAYING *playing = sigrenderer->playing[i]; + + if (playing) { + update_smooth_effects_playing(playing); } } } @@ -1083,7 +1095,7 @@ static void update_invert_loop(IT_CHANNEL *channel, IT_SAMPLE *sample) static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) { - int i; + int i, j; if (sigrenderer->globalvolslide) { sigrenderer->globalvolume += sigrenderer->globalvolslide; @@ -1167,6 +1179,10 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) } if (channel->playing) channel->playing->channel_volume = channel->channelvolume; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) + sigrenderer->playing[j]->channel_volume = channel->channelvolume; + } } update_tremor(channel); @@ -1177,80 +1193,127 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) if (channel->inv_loop_speed) update_invert_loop(channel, playing ? playing->sample : NULL); - if (playing) { - playing->slide += channel->portamento; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) break; + } + + if (playing || j < DUMB_IT_N_NNA_CHANNELS) { + if (playing) playing->slide += channel->portamento; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) + sigrenderer->playing[j]->slide += channel->portamento; + } if (channel->okt_toneslide) { if (channel->okt_toneslide--) { - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; + if (playing) { + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + } + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) { + IT_PLAYING *playing = sigrenderer->playing[j]; + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + } } } } else if (channel->ptm_toneslide) { if (--channel->toneslide_tick == 0) { channel->toneslide_tick = channel->ptm_toneslide; - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; - } - channel->note = channel->truenote = playing->note; - if (channel->toneslide_retrig) { - it_playing_reset_resamplers(playing, 0); + if (playing) { + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + channel->note = channel->truenote = playing->note; + if (channel->toneslide_retrig) { + it_playing_reset_resamplers(playing, 0); #ifdef END_RAMPING - playing->declick_stage = 0; - playing->declick_volume = 1.f / 256.f; + playing->declick_stage = 0; + playing->declick_volume = 1.f / 256.f; #endif + } + } + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) { + IT_PLAYING *playing = sigrenderer->playing[j]; + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + if (channel->toneslide_retrig) { + it_playing_reset_resamplers(playing, 0); +#ifdef END_RAMPING + playing->declick_stage = 0; + playing->declick_volume = 1.f / 256.f; +#endif + } + } } } } - if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { - if (channel->toneporta && channel->destnote < 120) { - int currpitch = ((playing->note - 60) << 8) + playing->slide; - int destpitch = (channel->destnote - 60) << 8; - if (currpitch > destpitch) { - currpitch -= channel->toneporta; - if (currpitch < destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } else if (currpitch < destpitch) { - currpitch += channel->toneporta; - if (currpitch > destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } - playing->slide = currpitch - ((playing->note - 60) << 8); + for (j = -1; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (j >= 0) { + playing = sigrenderer->playing[j]; + if (!playing || playing->channel != channel) continue; } - } else { - if (channel->toneporta && channel->destnote < 120) { - float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); - - float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); - /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ - - float deltaslid = deltanote - playing->slide * amiga_multiplier; - - float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); - if (deltaslid < destdelta) { - playing->slide -= channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid > destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; + if (playing) { + if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { + if (channel->toneporta && channel->destnote < 120) { + int currpitch = ((playing->note - 60) << 8) + playing->slide; + int destpitch = (channel->destnote - 60) << 8; + if (currpitch > destpitch) { + currpitch -= channel->toneporta; + if (currpitch < destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } else if (currpitch < destpitch) { + currpitch += channel->toneporta; + if (currpitch > destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } + playing->slide = currpitch - ((playing->note - 60) << 8); } } else { - playing->slide += channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid < destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; + if (channel->toneporta && channel->destnote < 120) { + float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); + + float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); + /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ + + float deltaslid = deltanote - playing->slide * amiga_multiplier; + + float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); + if (deltaslid < destdelta) { + playing->slide -= channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid > destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } + } else { + playing->slide += channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid < destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } + } } } } @@ -1985,6 +2048,8 @@ const char mod_convert_vibrato[] = { static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; + IT_PLAYING *playing; + int i; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; @@ -2041,10 +2106,17 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than break; case IT_VOLSLIDE_VIBRATO: - if (channel->playing) { - channel->playing->vibrato_speed = channel->lastHspeed; - channel->playing->vibrato_depth = channel->lastHdepth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = channel->lastHspeed; + playing->vibrato_depth = channel->lastHdepth; + playing->vibrato_n++; + } } /* Fall through and process volume slide. */ case IT_VOLUME_SLIDE: @@ -2140,15 +2212,22 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastEF; channel->lastEF = v; } - if (channel->playing) { - if ((v & 0xF0) == 0xF0) - channel->playing->slide -= (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - channel->playing->slide -= (v & 15) << 2; - else if (sigdata->flags & IT_WAS_A_669) - channel->portamento -= v << 3; - else - channel->portamento -= v << 4; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + if ((v & 0xF0) == 0xF0) + playing->slide -= (v & 15) << 4; + else if ((v & 0xF0) == 0xE0) + playing->slide -= (v & 15) << 2; + else if (i < 0 && sigdata->flags & IT_WAS_A_669) + channel->portamento -= v << 3; + else if (i < 0) + channel->portamento -= v << 4; + } } } break; @@ -2175,15 +2254,22 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastEF; channel->lastEF = v; } - if (channel->playing) { - if ((v & 0xF0) == 0xF0) - channel->playing->slide += (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - channel->playing->slide += (v & 15) << 2; - else if (sigdata->flags & IT_WAS_A_669) - channel->portamento += v << 3; - else - channel->portamento += v << 4; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (channel->playing) { + if ((v & 0xF0) == 0xF0) + channel->playing->slide += (v & 15) << 4; + else if ((v & 0xF0) == 0xE0) + channel->playing->slide += (v & 15) << 2; + else if (i < 0 && sigdata->flags & IT_WAS_A_669) + channel->portamento += v << 3; + else if (i < 0) + channel->portamento += v << 4; + } } } break; @@ -2232,10 +2318,17 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than depth <<= 2; channel->lastHdepth = depth; } - if (channel->playing) { - channel->playing->vibrato_speed = speed; - channel->playing->vibrato_depth = depth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = speed; + playing->vibrato_depth = depth; + playing->vibrato_n++; + } } } } @@ -2291,8 +2384,15 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than else channel->channelvolume = 64; #endif - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) + playing->channel_volume = channel->channelvolume; + } break; case IT_CHANNEL_VOLUME_SLIDE: { @@ -2313,8 +2413,15 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than if (channel->channelvolume > 64) channel->channelvolume = 0; } else break; - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) + playing->channel_volume = channel->channelvolume; + } } } break; @@ -2467,9 +2574,16 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than depth = channel->lastRdepth; channel->lastRdepth = depth; } - if (channel->playing) { - channel->playing->tremolo_speed = speed; - channel->playing->tremolo_depth = depth; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->tremolo_speed = speed; + playing->tremolo_depth = depth; + } } } break; @@ -2690,10 +2804,17 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than depth <<= 1; channel->lastHdepth = depth; } - if (channel->playing) { - channel->playing->vibrato_speed = speed; - channel->playing->vibrato_depth = depth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = speed; + playing->vibrato_depth = depth; + playing->vibrato_n++; + } } } break; @@ -3580,7 +3701,7 @@ static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYIN /* Returns 1 when fading should be initiated for a volume envelope. */ static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe, int flags) { - if (!(playing->enabled_envelopes & flags)) + if (!(playing->enabled_envelopes & flags) || !envelope->n_nodes) return 0; ASSERT(envelope->n_nodes > 0); @@ -4323,7 +4444,7 @@ static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *play volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f); if (volume && playing->instrument) { - if (playing->enabled_envelopes & IT_ENV_VOLUME) { + if (playing->enabled_envelopes & IT_ENV_VOLUME && playing->env_instrument->volume_envelope.n_nodes) { volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope); volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT); } From 61def2eb16abd00409b0d7721215d9ff7ce4ccc6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:45:07 +0000 Subject: [PATCH 166/387] Update DUMB to revision 22e82be0a7b0a915a2669e8f4ff889a938a7bfcb - Fixed IT tone portamento so it can continue without a destination note on every row SVN r4096 (trunk) --- dumb/src/it/itrender.c | 90 +++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 49 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 68eef44f5..921c7f533 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1262,58 +1262,50 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) } } - for (j = -1; j < DUMB_IT_N_NNA_CHANNELS; j++) { - if (j >= 0) { - playing = sigrenderer->playing[j]; - if (!playing || playing->channel != channel) continue; + if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { + if (channel->toneporta && channel->destnote < 120) { + int currpitch = ((playing->note - 60) << 8) + playing->slide; + int destpitch = (channel->destnote - 60) << 8; + if (currpitch > destpitch) { + currpitch -= channel->toneporta; + if (currpitch < destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } else if (currpitch < destpitch) { + currpitch += channel->toneporta; + if (currpitch > destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } + playing->slide = currpitch - ((playing->note - 60) << 8); } - if (playing) { - if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { - if (channel->toneporta && channel->destnote < 120) { - int currpitch = ((playing->note - 60) << 8) + playing->slide; - int destpitch = (channel->destnote - 60) << 8; - if (currpitch > destpitch) { - currpitch -= channel->toneporta; - if (currpitch < destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } else if (currpitch < destpitch) { - currpitch += channel->toneporta; - if (currpitch > destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } - playing->slide = currpitch - ((playing->note - 60) << 8); + } else { + if (channel->toneporta && channel->destnote < 120) { + float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); + + float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); + /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ + + float deltaslid = deltanote - playing->slide * amiga_multiplier; + + float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); + if (deltaslid < destdelta) { + playing->slide -= channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid > destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; } } else { - if (channel->toneporta && channel->destnote < 120) { - float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); - - float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); - /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ - - float deltaslid = deltanote - playing->slide * amiga_multiplier; - - float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); - if (deltaslid < destdelta) { - playing->slide -= channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid > destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } else { - playing->slide += channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid < destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } + playing->slide += channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid < destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; } } } From 36157271fc81b4aa830829d104e14ca8f3d80a12 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:45:50 +0000 Subject: [PATCH 167/387] Update DUMB to revision e84e1824fbd0b2b690bd9beb2e25fd308e661982 - Fixed envelopes so they only carry from the same channel SVN r4097 (trunk) --- dumb/src/it/itrender.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 921c7f533..7fb345c04 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1618,7 +1618,7 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan nna = channel->playing->instrument->new_note_action; #endif - if ((sigdata->flags & IT_USE_INSTRUMENTS) && (channel->playing->enabled_envelopes) && channel->playing->instnum == channel->instrument) { + if (!(channel->playing->flags & IT_PLAYING_DEAD) && (sigdata->flags & IT_USE_INSTRUMENTS) && (channel->playing->enabled_envelopes) && channel->playing->instnum == channel->instrument) { IT_PLAYING * playing = channel->playing; IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1]; if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) { @@ -1739,7 +1739,8 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan if (!flags && sigdata->flags & IT_USE_INSTRUMENTS) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && (playing->enabled_envelopes) && playing->instnum == channel->instrument) { + if (!playing || playing->channel != channel) continue; + if (playing->enabled_envelopes && playing->instnum == channel->instrument) { IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1]; if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) { flags |= 1; From e66024fcbce5bda179aa960a3cf91cf8dbe044a4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:46:27 +0000 Subject: [PATCH 168/387] Update DUMB to revision 9e3012a7ce5fb52383f51c99061bc45921699f63 - Fixed pitch slides on non-playing channels SVN r4098 (trunk) --- dumb/src/it/itrender.c | 76 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 7fb345c04..4211e31f8 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1262,50 +1262,52 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) } } - if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { - if (channel->toneporta && channel->destnote < 120) { - int currpitch = ((playing->note - 60) << 8) + playing->slide; - int destpitch = (channel->destnote - 60) << 8; - if (currpitch > destpitch) { - currpitch -= channel->toneporta; - if (currpitch < destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } else if (currpitch < destpitch) { - currpitch += channel->toneporta; + if (playing) { + if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { + if (channel->toneporta && channel->destnote < 120) { + int currpitch = ((playing->note - 60) << 8) + playing->slide; + int destpitch = (channel->destnote - 60) << 8; if (currpitch > destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; + currpitch -= channel->toneporta; + if (currpitch < destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } else if (currpitch < destpitch) { + currpitch += channel->toneporta; + if (currpitch > destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } } + playing->slide = currpitch - ((playing->note - 60) << 8); } - playing->slide = currpitch - ((playing->note - 60) << 8); - } - } else { - if (channel->toneporta && channel->destnote < 120) { - float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); + } else { + if (channel->toneporta && channel->destnote < 120) { + float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); - float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); - /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ + float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); + /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ - float deltaslid = deltanote - playing->slide * amiga_multiplier; + float deltaslid = deltanote - playing->slide * amiga_multiplier; - float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); - if (deltaslid < destdelta) { - playing->slide -= channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid > destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } else { - playing->slide += channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; + float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); if (deltaslid < destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; + playing->slide -= channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid > destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } + } else { + playing->slide += channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid < destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } } } } From 7cd543c55476dccf449dcd72c8f77e81d7b6418a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:49:27 +0000 Subject: [PATCH 169/387] - Warning fixes for DUMB. SVN r4099 (trunk) --- dumb/src/it/readokt.c | 2 +- dumb/src/it/readstm.c | 2 +- dumb/src/it/readxm.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dumb/src/it/readokt.c b/dumb/src/it/readokt.c index 9ae059575..1f2fa9443 100644 --- a/dumb/src/it/readokt.c +++ b/dumb/src/it/readokt.c @@ -497,7 +497,7 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f, int restrict) j++; } } - for (; i < sigdata->n_samples; i++) { + for (; i < (unsigned)sigdata->n_samples; i++) { sigdata->sample[i].flags = 0; } diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index be1b15720..a4b00f79b 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -354,7 +354,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) for ( n = 0, q = o / 16; n < sigdata->n_samples; ++n ) { if ( sample_offset[ n ] ) { - sample_offset[ n ] -= q; + sample_offset[ n ] = (unsigned short)(sample_offset[ n ] - q); } } diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 4e3dbee0b..1930ba938 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -400,14 +400,14 @@ static int limit_xm_resize(void *f, long n) return 0; } -static int limit_xm_skip_end(void *f, long n) +static int limit_xm_skip_end(void *f, int32 n) { DUMBFILE *df = f; LIMITED_XM *lx = df->file; return dumbfile_skip( lx->remaining, n ); } -static int limit_xm_skip(void *f, long n) +static int limit_xm_skip(void *f, int32 n) { LIMITED_XM *lx = f; lx->ptr += n; @@ -427,7 +427,7 @@ static int limit_xm_getc(void *f) -static long limit_xm_getnc(char *ptr, long n, void *f) +static long limit_xm_getnc(char *ptr, int32 n, void *f) { LIMITED_XM *lx = f; int left; From 1e422f892126004baa47d069f0e07127f96e1f0b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:50:44 +0000 Subject: [PATCH 170/387] Update DUMB to revision 32c9bb420240cac2120e7e01c2683df88d1dc1ac - Corrected MOD reader to only check the known number of orders when calculating the pattern count SVN r4100 (trunk) --- dumb/src/it/readmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 05c1ba86e..6995ffc22 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -631,7 +631,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) /* Work out how many patterns there are. */ sigdata->n_patterns = -1; - for (i = 0; i < 128; i++) + for (i = 0; i < sigdata->n_orders; i++) if (sigdata->n_patterns < sigdata->order[i]) sigdata->n_patterns = sigdata->order[i]; sigdata->n_patterns++; From fb98650e4d2f26dac17fda01486a1a2188c420f2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:51:39 +0000 Subject: [PATCH 171/387] Update DUMB to revision b17c5254eeac1bff7e4b613c151e0232c2cba646 - Remove trailing whitespace from all song, instrument, and sample names SVN r4101 (trunk) --- dumb/src/it/readxm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 1930ba938..b6607a248 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -117,6 +117,14 @@ XM_INSTRUMENT_EXTRA; +/* Trims off trailing white space, usually added by the tracker on file creation + */ +static void trim_whitespace(char *ptr, size_t size) +{ + char *p = ptr + size - 1; + while (p >= ptr && *p <= 0x20) *p-- = '\0'; +} + /* Frees the original block if it can't resize it or if size is 0, and acts * as malloc if ptr is NULL. */ @@ -506,6 +514,7 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA dumbfile_getnc(instrument->name, 22, f); instrument->name[22] = 0; + trim_whitespace(instrument->name, 22); instrument->filename[0] = 0; dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */ extra->n_samples = dumbfile_igetw(f); @@ -665,6 +674,7 @@ static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) dumbfile_getnc(sample->name, 22, f); sample->name[22] = 0; + trim_whitespace(sample->name, 22); sample->filename[0] = 0; @@ -919,6 +929,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) return NULL; } sigdata->name[20] = 0; + trim_whitespace(sigdata->name, 20); if (dumbfile_getc(f) != 0x1A) { TRACE("XM error: 0x1A not found\n"); From b3af94c2a75d524b0b5ffd43193e42f7d4c08095 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:55:22 +0000 Subject: [PATCH 172/387] Update DUMB to revision d2575fcc80abf2f04e702adb60a6265cef0fcabb - Implemented final solution for MOD pattern count calculation - Fixed possible memory leak which only would have occurred with rare MOD files - Fixed a possible memory allocation error or crash with FLT8 MOD files SVN r4102 (trunk) --- dumb/src/it/readmod.c | 78 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 6995ffc22..976a0dc9c 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -629,12 +629,43 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (sigdata->n_samples == 31) dumbfile_skip(f, 4); - /* Work out how many patterns there are. */ sigdata->n_patterns = -1; - for (i = 0; i < sigdata->n_orders; i++) - if (sigdata->n_patterns < sigdata->order[i]) - sigdata->n_patterns = sigdata->order[i]; - sigdata->n_patterns++; + + { + long total_sample_size; + long remain; + rem = f; + f = dumbfile_buffer_mod_2(rem, &remain); + if (!f) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(rem); + return NULL; + } + for (total_sample_size = 0, i = 0; i < sigdata->n_samples; i++) { + if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { + total_sample_size += sigdata->sample[i].length; + } + } + if (remain > total_sample_size) { + sigdata->n_patterns = ( remain - total_sample_size ) / ( 256 * sigdata->n_pchannels ); + if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { + remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels; + if (dumbfile_skip(f, remain - total_sample_size)) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + dumbfile_close(rem); + return NULL; + } + } + } + } + + if ( sigdata->n_patterns <= 0 ) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + dumbfile_close(rem); + return NULL; + } /* May as well try to save a tiny bit of memory. */ if (sigdata->n_orders < 128) { @@ -646,6 +677,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); + dumbfile_close(rem); return NULL; } for (i = 0; i < sigdata->n_patterns; i++) @@ -653,49 +685,23 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) /* Read in the patterns */ { - unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */ + unsigned char *buffer = malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */ if (!buffer) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); + dumbfile_close(rem); return NULL; } for (i = 0; i < sigdata->n_patterns; i++) { if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) { free(buffer); - _dumb_it_unload_sigdata(sigdata); - dumbfile_close(f); - return NULL; - } - } - free(buffer); - } - - rem = NULL; - - /* uggly */ - if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { - int32 skip; - int32 remain; - rem = f; - f = dumbfile_buffer_mod_2(rem, &remain); - if (!f) { - _dumb_it_unload_sigdata(sigdata); - dumbfile_close(rem); - return NULL; - } - for (skip = 0, i = 0; i < sigdata->n_samples; i++) { - if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { - skip += sigdata->sample[i].length; - } - } - if (remain - skip) { - if (dumbfile_skip(f, remain - skip)) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); dumbfile_close(rem); return NULL; } } + free(buffer); } /* And finally, the sample data */ @@ -703,7 +709,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - if (rem) dumbfile_close(rem); + dumbfile_close(rem); return NULL; } } @@ -727,8 +733,8 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) }*/ dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */ + dumbfile_close(rem); /* And the BUFFERED_MOD DUMBFILE used to pre-read the signature. */ /* The DUMBFILE originally passed to our function is intact. */ - if (rem) dumbfile_close(rem); /* Now let's initialise the remaining variables, and we're done! */ sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; From 2b2a86a13e86410dff2e7170a8bd289ee0d880bc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:57:40 +0000 Subject: [PATCH 173/387] Update DUMB to revision 756ecf2ac0a2b70639193aca55627b64dac8d8d5 - Added interface for inserting extra DUH signals, and fixed searching for IT sigdata when more than one signal is present SVN r4103 (trunk) --- dumb/include/dumb.h | 3 ++- dumb/src/core/makeduh.c | 19 +++++++++++++++++++ dumb/src/core/rawsig.c | 22 ++++++++++++++++++---- dumb/src/it/itmisc.c | 2 +- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index d82afe6f6..f0799c7fa 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -233,7 +233,6 @@ int32 DUMBEXPORT duh_get_length(DUH *duh); const char *DUMBEXPORT duh_get_tag(DUH *duh, const char *key); - /* Signal Rendering Functions */ typedef struct DUH_SIGRENDERER DUH_SIGRENDERER; @@ -610,6 +609,8 @@ sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type); DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 pos); sigrenderer_t *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type); +int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata); + /* Standard Signal Types */ diff --git a/dumb/src/core/makeduh.c b/dumb/src/core/makeduh.c index 598b637bc..24f29259b 100644 --- a/dumb/src/core/makeduh.c +++ b/dumb/src/core/makeduh.c @@ -130,3 +130,22 @@ DUH *make_duh( return duh; } + +int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) +{ + DUH_SIGNAL **signal; + + if ( !duh || !desc || !sigdata ) return -1; + + signal = ( DUH_SIGNAL ** ) realloc( duh->signal, ( duh->n_signals + 1 ) * sizeof( *duh->signal ) ); + if ( !signal ) return -1; + duh->signal = signal; + + memmove( signal + 1, signal, duh->n_signals * sizeof( *signal ) ); + duh->n_signals++; + + signal[ 0 ] = make_signal( desc, sigdata ); + if ( !signal[ 0 ] ) return -1; + + return 0; +} diff --git a/dumb/src/core/rawsig.c b/dumb/src/core/rawsig.c index a1edd60d0..2287bb068 100644 --- a/dumb/src/core/rawsig.c +++ b/dumb/src/core/rawsig.c @@ -29,16 +29,30 @@ */ sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type) { + int i; DUH_SIGNAL *signal; if (!duh) return NULL; - if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL; + if ( sig >= 0 ) + { + if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL; - signal = duh->signal[sig]; + signal = duh->signal[sig]; - if (signal && signal->desc->type == type) - return signal->sigdata; + if (signal && signal->desc->type == type) + return signal->sigdata; + } + else + { + for ( i = 0; i < duh->n_signals; i++ ) + { + signal = duh->signal[i]; + + if (signal && signal->desc->type == type) + return signal->sigdata; + } + } return NULL; } diff --git a/dumb/src/it/itmisc.c b/dumb/src/it/itmisc.c index 1045af8fa..5a45d3192 100644 --- a/dumb/src/it/itmisc.c +++ b/dumb/src/it/itmisc.c @@ -24,7 +24,7 @@ DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh) { - return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT); + return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT); } From 5c65f7188e1b11154a7397057fd6b43b295c73ab Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 00:58:50 +0000 Subject: [PATCH 174/387] Update DUMB to revision 02190e007b4967b8a546f64a3934724817ff5c3a - Fixed MOD pattern count calculation in weird cases where the last sample is missing four bytes SVN r4104 (trunk) --- dumb/src/it/readmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 976a0dc9c..6301da4c8 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -647,7 +647,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } } if (remain > total_sample_size) { - sigdata->n_patterns = ( remain - total_sample_size ) / ( 256 * sigdata->n_pchannels ); + sigdata->n_patterns = ( remain - total_sample_size + 4 ) / ( 256 * sigdata->n_pchannels ); if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels; if (dumbfile_skip(f, remain - total_sample_size)) { From a0bc90bbc86f055ce0f069ea61dbdb554ecdb1ed Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:00:53 +0000 Subject: [PATCH 175/387] Update DUMB to revision 30b178af5674b8604306885a693c2a8aa422472f - Fixed ADPCM sample support SVN r4105 (trunk) --- dumb/src/it/readmod.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 6301da4c8..03ff0ff62 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -393,10 +393,12 @@ static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, uint32 *fft) return dumbfile_open_ex(bm, &buffer_mod_dfs); } -static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int32 *remain) +static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int n_samples, IT_SAMPLE *sample, int32 *total_sample_size, int32 *remain) { int32 read; + int sample_number; BUFFERED_MOD *bm = malloc(sizeof(*bm)); + unsigned char *ptr; if (!bm) return NULL; bm->buffered = malloc(32768); @@ -430,6 +432,21 @@ static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, int32 *remain) if (*remain) { bm->ptr = 0; + ptr = bm->buffered + *remain; + sample_number = n_samples - 1; + *total_sample_size = 0; + while (ptr > bm->buffered && sample_number >= 0) { + if (sample[sample_number].flags & IT_SAMPLE_EXISTS) { + ptr -= (sample[sample_number].length + 1) / 2 + 5 + 16; + if (ptr >= bm->buffered && !memcmp(ptr, "ADPCM", 5)) { /* BAH */ + *total_sample_size += (sample[sample_number].length + 1) / 2 + 5 + 16; + } else { + *total_sample_size += sample[sample_number].length; + ptr -= sample[sample_number].length - ((sample[sample_number].length + 1) / 2 + 5 + 16); + } + } + sample_number--; + } } else { free(bm->buffered); bm->buffered = NULL; @@ -635,17 +652,12 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) long total_sample_size; long remain; rem = f; - f = dumbfile_buffer_mod_2(rem, &remain); + f = dumbfile_buffer_mod_2(rem, sigdata->n_samples, sigdata->sample, &total_sample_size, &remain); if (!f) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(rem); return NULL; } - for (total_sample_size = 0, i = 0; i < sigdata->n_samples; i++) { - if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { - total_sample_size += sigdata->sample[i].length; - } - } if (remain > total_sample_size) { sigdata->n_patterns = ( remain - total_sample_size + 4 ) / ( 256 * sigdata->n_pchannels ); if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { From b95e4b971e051837f02a60b4e86d90df4b76ab97 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:04:38 +0000 Subject: [PATCH 176/387] Update DUMB to revision 5b53815e1f271746627bde0bfce7140109b88f14 - Made the new MOD pattern counting system optional SVN r4106 (trunk) --- dumb/include/dumb.h | 2 ++ dumb/src/it/readmod.c | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index f0799c7fa..bcd202298 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -395,6 +395,8 @@ void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sig int DUMBCALLBACK dumb_it_callback_terminate(void *data); int DUMBCALLBACK dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte); +/* dumb_*_mod*: restrict |= 1-Don't read 15 sample files / 2-Use old pattern counting method */ + DUH *DUMBEXPORT dumb_load_it(const char *filename); DUH *DUMBEXPORT dumb_load_xm(const char *filename); DUH *DUMBEXPORT dumb_load_s3m(const char *filename); diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 03ff0ff62..fcfa18824 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -567,7 +567,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } // moo - if ( rstrict && sigdata->n_samples == 15 ) + if ( ( rstrict & 1 ) && sigdata->n_samples == 15 ) { free(sigdata); dumbfile_close(f); @@ -648,6 +648,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) sigdata->n_patterns = -1; + if ( !( rstrict & 2 ) ) { long total_sample_size; long remain; @@ -671,11 +672,21 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } } } + else + { + sigdata->n_patterns = 0; + for (i = 0; i < sigdata->n_orders; i++) + { + if (sigdata->order[i] > sigdata->n_patterns) + sigdata->n_patterns = sigdata->order[i]; + } + sigdata->n_patterns++; + } if ( sigdata->n_patterns <= 0 ) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - dumbfile_close(rem); + if (rem) dumbfile_close(rem); return NULL; } @@ -689,7 +700,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - dumbfile_close(rem); + if (rem) dumbfile_close(rem); return NULL; } for (i = 0; i < sigdata->n_patterns; i++) @@ -701,7 +712,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (!buffer) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - dumbfile_close(rem); + if (rem) dumbfile_close(rem); return NULL; } for (i = 0; i < sigdata->n_patterns; i++) { @@ -709,7 +720,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) free(buffer); _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - dumbfile_close(rem); + if (rem) dumbfile_close(rem); return NULL; } } @@ -721,7 +732,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) { _dumb_it_unload_sigdata(sigdata); dumbfile_close(f); - dumbfile_close(rem); + if (rem) dumbfile_close(rem); return NULL; } } @@ -745,7 +756,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) }*/ dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */ - dumbfile_close(rem); /* And the BUFFERED_MOD DUMBFILE used to pre-read the signature. */ + if (rem) dumbfile_close(rem); /* And the BUFFERED_MOD DUMBFILE used to pre-read the signature. */ /* The DUMBFILE originally passed to our function is intact. */ /* Now let's initialise the remaining variables, and we're done! */ From a793ef11319651d2a5fcfc2144841b41a659bc08 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:06:19 +0000 Subject: [PATCH 177/387] Update DUMB to revision 045efbd6fc579a78e304185e480c8c15b2b932c4 - Fixed older pattern counting mode SVN r4107 (trunk) --- dumb/src/it/readmod.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index fcfa18824..15b871473 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -464,7 +464,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) int n_channels; int i; uint32 fft = 0; - DUMBFILE *rem; + DUMBFILE *rem = NULL; f = dumbfile_buffer_mod(f, &fft); if (!f) @@ -674,7 +674,6 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } else { - sigdata->n_patterns = 0; for (i = 0; i < sigdata->n_orders; i++) { if (sigdata->order[i] > sigdata->n_patterns) From f90607e8abd58d4e5f4b182b7a2d311fc7f150b0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:08:01 +0000 Subject: [PATCH 178/387] Update DUMB to revision 5c9c4359042555c182a4bd52ef212a162e5bbd76 - Removed unused variable from function declarations, a leftover from copying from the MOD reader SVN r4108 (trunk) --- dumb/src/it/readokt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/readokt.c b/dumb/src/it/readokt.c index 1f2fa9443..078929c5c 100644 --- a/dumb/src/it/readokt.c +++ b/dumb/src/it/readokt.c @@ -319,7 +319,7 @@ unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type) } -static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f, int restrict) +static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f) { DUMB_IT_SIGDATA *sigdata; unsigned n_channels; @@ -544,7 +544,7 @@ DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f) DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - sigdata = it_okt_load_sigdata(f, 0); + sigdata = it_okt_load_sigdata(f); if (!sigdata) return NULL; From 566766f041e0b6d3b9f0d7cb11c3db36b58cfaaa Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:15:01 +0000 Subject: [PATCH 179/387] Update DUMB to revision efd9431447a6f686e8212ffc796624ed58b06531 - Added format tag to IT reader SVN r4109 (trunk) --- dumb/src/it/itread.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index 12cd6828b..265bb03a1 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -1350,9 +1350,11 @@ DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f) return NULL; { - const char *tag[1][2]; + const char *tag[2][2]; tag[0][0] = "TITLE"; tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; - return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + tag[1][0] = "FORMAT"; + tag[1][1] = "IT"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); } } From 7787153f51b73424a28993b46768989f34b9aee8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:16:52 +0000 Subject: [PATCH 180/387] Update DUMB to revision 347a1170d6d00ec2ea9db2a3667ee7c8d2ef422b - Fixed envelope handling SVN r4110 (trunk) --- dumb/src/it/itrender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 4211e31f8..e93ea9df6 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -3722,7 +3722,7 @@ static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLA } pe->tick++; - while (pe->tick >= envelope->node_t[pe->next_node]) { + while (pe->tick > envelope->node_t[pe->next_node]) { pe->next_node++; if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { if (pe->next_node > envelope->sus_loop_end) { From ab644a77612d90e9054c0dd116355add57136b0c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:23:37 +0000 Subject: [PATCH 181/387] Update DUMB to revision ad8a234f3c6c9b3e7a2d590c81f297bf20375f6d - Buffer entire file into memory to allow for weird file offsets, and add minimal Open/MPT extension reading SVN r4111 (trunk) --- dumb/src/it/itread.c | 225 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 211 insertions(+), 14 deletions(-) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index 265bb03a1..cb67aaa67 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -31,18 +31,71 @@ //#define INVESTIGATE_OLD_INSTRUMENTS - -static int it_seek(DUMBFILE *f, int32 offset) +typedef struct tdumbfile_mem_status { - int32 pos = dumbfile_pos(f); + const unsigned char * ptr; + unsigned offset, size; +} dumbfile_mem_status; - if (pos > offset) +static int dumbfile_mem_skip(void * f, int32 n) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + s->offset += n; + if (s->offset > s->size) + { + s->offset = s->size; + return 1; + } + + return 0; +} + + + +static int dumbfile_mem_getc(void * f) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + if (s->offset < s->size) + { + return *(s->ptr + s->offset++); + } + return -1; +} + + + +static int32 dumbfile_mem_getnc(char * ptr, int32 n, void * f) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + int32 max = s->size - s->offset; + if (max > n) max = n; + if (max) + { + memcpy(ptr, s->ptr + s->offset, max); + s->offset += max; + } + return max; +} + + + +static DUMBFILE_SYSTEM mem_dfs = { + NULL, // open + &dumbfile_mem_skip, + &dumbfile_mem_getc, + &dumbfile_mem_getnc, + NULL // close +}; + + + +static int it_seek(dumbfile_mem_status * s, int32 offset) +{ + if ( offset > s->size ) return -1; - if (pos < offset) - if (dumbfile_skip(f, offset - pos)) - return -1; - + s->offset = offset; + return 0; } @@ -631,7 +684,7 @@ int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f) signed char * ptr, * end; signed char compression_table[16]; if (dumbfile_getnc(compression_table, 16, f) != 16) - return -1; + return -1; ptr = (signed char *) sample->data; delta = 0; @@ -957,13 +1010,58 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) unsigned char *buffer; + unsigned char *file_buffer = NULL; + unsigned int file_size = 0; + int block_size; + + dumbfile_mem_status memdata; + + do + { + void * temp = realloc( file_buffer, file_size + 32768 ); + if ( !temp ) + { + if ( file_buffer ) free( file_buffer ); + return NULL; + } + file_buffer = temp; + block_size = dumbfile_getnc( file_buffer + file_size, 32768, f ); + if ( block_size < 0 ) + { + free( file_buffer ); + return NULL; + } + file_size += block_size; + } + while ( block_size == 32768 ); + + memdata.ptr = file_buffer; + memdata.offset = 0; + memdata.size = file_size; + + f = dumbfile_open_ex(&memdata, &mem_dfs); + + if ( !f ) + { + free( file_buffer ); + return NULL; + } + if (dumbfile_mgetl(f) != IT_SIGNATURE) + { + dumbfile_close(f); + free(file_buffer); return NULL; + } sigdata = malloc(sizeof(*sigdata)); if (!sigdata) + { + dumbfile_close(f); + free(file_buffer); return NULL; + } sigdata->song_message = NULL; sigdata->order = NULL; @@ -1012,12 +1110,16 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) // XXX sample count if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->order = malloc(sigdata->n_orders); if (!sigdata->order) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1025,6 +1127,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); if (!sigdata->instrument) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } } @@ -1033,6 +1137,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); if (!sigdata->sample) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (n = 0; n < sigdata->n_samples; n++) @@ -1043,6 +1149,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (n = 0; n < sigdata->n_patterns; n++) @@ -1055,6 +1163,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) component = malloc(769 * sizeof(*component)); if (!component) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1099,6 +1209,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_error(f)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1119,6 +1231,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (!sigdata->midi) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; // Should we be happy with this outcome in some situations? } @@ -1127,6 +1241,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } /* Read embedded MIDI configuration */ @@ -1134,6 +1250,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_skip(f, 32*9)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (i = 0; i < 16; i++) { @@ -1142,6 +1260,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_getnc(mididata, 32, f) < 32) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->midi->SFmacroz[i] = 0; @@ -1197,12 +1317,14 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->flags &= IT_REAL_FLAGS; - qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); + qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); buffer = malloc(65536); if (!buffer) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1231,10 +1353,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) continue; } - if (it_seek(f, component[n].offset)) { + if (it_seek(&memdata, component[n].offset)) { free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1250,6 +1374,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->song_message[message_length] = 0; @@ -1266,6 +1392,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } break; @@ -1275,6 +1403,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } break; @@ -1284,6 +1414,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1310,10 +1442,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) m = component[n].sampfirst; while (m >= 0) { - if (it_seek(f, component[m].offset)) { + if (it_seek(&memdata, component[m].offset)) { free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1321,16 +1455,79 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } m = component[m].sampnext; } - } + } - free(buffer); + for ( n = 0; n < 10; n++ ) + { + if ( dumbfile_getc( f ) == 'X' ) + { + if ( dumbfile_getc( f ) == 'T' ) + { + if ( dumbfile_getc( f ) == 'P' ) + { + if ( dumbfile_getc( f ) == 'M' ) + { + break; + } + } + } + } + } + + if ( !dumbfile_error( f ) && n < 10 ) + { + unsigned int mptx_id = dumbfile_igetl( f ); + while ( mptx_id != DUMB_ID('M','P','T','S') ) + { + unsigned int size = dumbfile_igetw( f ); + switch (mptx_id) + { + /* TODO: Add instrument extension readers */ + + default: + dumbfile_skip(f, size * sigdata->n_instruments); + break; + } + + mptx_id = dumbfile_igetl( f ); + } + + mptx_id = dumbfile_igetl( f ); + while ( memdata.offset < file_size ) + { + unsigned int size = dumbfile_igetw( f ); + switch (mptx_id) + { + /* TODO: Add more song extension readers */ + + case DUMB_ID('D','T','.','.'): + if ( size == 2 ) + sigdata->tempo = dumbfile_igetw( f ); + else if ( size == 4 ) + sigdata->tempo = dumbfile_igetl( f ); + break; + + default: + dumbfile_skip(f, size); + break; + } + mptx_id = dumbfile_igetl( f ); + } + } + + free(buffer); free(component); + dumbfile_close(f); + free(file_buffer); + _dumb_it_fix_invalid_orders(sigdata); return sigdata; From 7edd64243b1a9e092b04b001d55b9f4c44b558e7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:25:00 +0000 Subject: [PATCH 182/387] Update DUMB to revision ac46a8b6056cf12bff464407bc1582301051c1f1 - Fixed STM speed handling SVN r4112 (trunk) --- dumb/include/internal/it.h | 2 ++ dumb/src/it/itrender.c | 29 ++++++++++++++++++++++++----- dumb/src/it/readstm.c | 19 ++++++++++--------- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 74a08d567..1ab5d3b27 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -412,6 +412,8 @@ struct IT_PATTERN #define IT_WAS_AN_OKT 2048 +#define IT_WAS_AN_STM 4096 + #define IT_ORDER_END 255 #define IT_ORDER_SKIP 254 diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index e93ea9df6..ecdf9e78c 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -2075,7 +2075,18 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than /*if (entry->effectvalue == 255) if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) return 1;*/ - sigrenderer->tick = sigrenderer->speed = entry->effectvalue; + if (sigdata->flags & IT_WAS_AN_STM) + { + int n = entry->effectvalue; + if (n >= 32) + { + sigrenderer->tick = sigrenderer->speed = n; + } + } + else + { + sigrenderer->tick = sigrenderer->speed = entry->effectvalue; + } } else if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { #ifdef BIT_ARRAY_BULLSHIT @@ -4323,9 +4334,12 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) update_effects(sigrenderer); } } else { - speed0: - update_effects(sigrenderer); - update_tick_counts(sigrenderer); + if ( !(sigdata->flags & IT_WAS_AN_STM) || !(sigrenderer->tick & 15)) + { + speed0: + update_effects(sigrenderer); + update_tick_counts(sigrenderer); + } } if (sigrenderer->globalvolume == 0) { @@ -4348,7 +4362,12 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) process_all_playing(sigrenderer); { - LONG_LONG t = sigrenderer->sub_time_left + ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo; + LONG_LONG t = ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo; + if ( sigrenderer->sigdata->flags & IT_WAS_AN_STM ) + { + t /= 16; + } + t += sigrenderer->sub_time_left; sigrenderer->time_left += (int)(t >> 16); sigrenderer->sub_time_left = (int)t & 65535; } diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index a4b00f79b..89237d6e7 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -142,9 +142,9 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char entry->mask |= IT_ENTRY_VOLPAN; entry->mask |= IT_ENTRY_EFFECT; switch ( entry->effect ) { - case IT_SET_SPEED: - entry->effectvalue >>= 4; - break; + case IT_SET_SPEED: + /* taken care of in the renderer */ + break; case IT_BREAK_TO_ROW: entry->effectvalue -= (entry->effectvalue >> 4) * 6; @@ -236,16 +236,17 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) sigdata->n_samples = 31; sigdata->n_pchannels = 4; - sigdata->tempo = 125; - sigdata->mixing_volume = 48; + sigdata->tempo = 125; + sigdata->mixing_volume = 48; sigdata->pan_separation = 128; /** WARNING: which ones? */ - sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_STEREO; + sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_WAS_AN_STM | IT_STEREO; - sigdata->speed = dumbfile_getc(f) >> 4; - if ( sigdata->speed < 1 ) sigdata->speed = 1; - sigdata->n_patterns = dumbfile_getc(f); + n = dumbfile_getc(f); + if ( n < 32 ) n = 32; + sigdata->speed = n; + sigdata->n_patterns = dumbfile_getc(f); sigdata->global_volume = dumbfile_getc(f) << 1; if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128; From 751983fccd2e32a612a79393f908a3e7acadaa95 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:27:30 +0000 Subject: [PATCH 183/387] Update DUMB to revision b97e36954f873516c31c0a8c24054784f3c9d751 - Fixed portamento up effect when NNA channels are active SVN r4113 (trunk) --- dumb/src/it/itrender.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index ecdf9e78c..11433e192 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -2266,11 +2266,11 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } - if (channel->playing) { + if (playing) { if ((v & 0xF0) == 0xF0) - channel->playing->slide += (v & 15) << 4; + playing->slide += (v & 15) << 4; else if ((v & 0xF0) == 0xE0) - channel->playing->slide += (v & 15) << 2; + playing->slide += (v & 15) << 2; else if (i < 0 && sigdata->flags & IT_WAS_A_669) channel->portamento += v << 3; else if (i < 0) @@ -2593,7 +2593,7 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than } } break; - case IT_S: + case IT_S: { /* channel->lastS was set in update_pattern_variables(). */ unsigned char effectvalue = channel->lastS; From 0d7fc66078e71a3e9ca8162f8e71458c5f4a299a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:28:54 +0000 Subject: [PATCH 184/387] Update DUMB to revision 4df0e8c5be294fa1fe3ea96eff8387c2505912ec - Fixed pattern counting, and swapped pattern counting flag SVN r4114 (trunk) --- dumb/src/it/readmod.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 15b871473..9d105f126 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -648,7 +648,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) sigdata->n_patterns = -1; - if ( !( rstrict & 2 ) ) + if ( ( rstrict & 2 ) ) { long total_sample_size; long remain; @@ -674,7 +674,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } else { - for (i = 0; i < sigdata->n_orders; i++) + for (i = 0; i < 128; i++) { if (sigdata->order[i] > sigdata->n_patterns) sigdata->n_patterns = sigdata->order[i]; From cfaecc12a3088979370dc6c0ca7e90fe805c142c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:33:01 +0000 Subject: [PATCH 185/387] Update DUMB to revision 73da922bddede1f81fffc7e5e895cace755b378d - Implemented support for the obscure S9F sample reverse effect SVN r4115 (trunk) --- dumb/include/internal/it.h | 1 + dumb/src/it/itrender.c | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 1ab5d3b27..922d9bed0 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -467,6 +467,7 @@ struct IT_PLAYING_ENVELOPE #define IT_PLAYING_SUSTAINOFF 2 #define IT_PLAYING_FADING 4 #define IT_PLAYING_DEAD 8 +#define IT_PLAYING_REVERSE 16 struct IT_PLAYING { diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 11433e192..739ced68f 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -905,6 +905,15 @@ static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data) +static void it_pickup_stop_after_reverse(DUMB_RESAMPLER *resampler, void *data) +{ + (void)data; + + resampler->dir = 0; +} + + + static void it_playing_update_resamplers(IT_PLAYING *playing) { if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { @@ -925,8 +934,13 @@ static void it_playing_update_resamplers(IT_PLAYING *playing) playing->resampler.pickup = &it_pickup_pingpong_loop; else playing->resampler.pickup = &it_pickup_loop; - } else { - if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) + } else if (playing->flags & IT_PLAYING_REVERSE) { + playing->resampler.start = 0; + playing->resampler.end = playing->sample->length; + playing->resampler.dir = -1; + playing->resampler.pickup = &it_pickup_stop_after_reverse; + } else { + if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) playing->resampler.start = playing->sample->sus_loop_start; else playing->resampler.start = 0; @@ -2753,7 +2767,13 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than channel->playing->panbrello_depth = 0; break; case IT_S_SET_SURROUND_SOUND: - if ((effectvalue & 15) == 1) { + if ((effectvalue & 15) == 15) { + if (channel->playing && channel->playing->sample && + !(channel->playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP))) { + channel->playing->flags |= IT_PLAYING_REVERSE; + it_playing_reset_resamplers( channel->playing, channel->playing->sample->length - 1 ); + } + } else if ((effectvalue & 15) == 1) { channel->pan = IT_SURROUND; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } From 3c50b1c14b1bfe8d8ed8e990c5cb8598e7c5b6e8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:34:05 +0000 Subject: [PATCH 186/387] - Update DUMB to revision 3aee7f113c66f19e93f9e41a6e280e12dfd9a0e9 - Fixed envelope reading to gracefully handle nodes which are out of range SVN r4116 (trunk) --- dumb/src/it/readxm.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index b6607a248..25ca07108 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -338,7 +338,7 @@ static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset) { - int i, pos; + int i, pos, val; if (envelope->n_nodes > 12) { /* XXX @@ -355,12 +355,13 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data pos = 0; for (i = 0; i < envelope->n_nodes; i++) { envelope->node_t[i] = data[pos++]; - if (data[pos] > 64) { - TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]); - envelope->n_nodes = 0; - return -1; + val = data[pos++]; + if (val > 64) { + TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, val); + /* FT2 seems to simply clip the value */ + val = 64; } - envelope->node_y[i] = (signed char)(data[pos++] + y_offset); + envelope->node_y[i] = (signed char)(val + y_offset); } return 0; From 45e9491ecac49e199016cd0c642c66dd7f246cc6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:35:18 +0000 Subject: [PATCH 187/387] Update DUMB to revision ff84ff32fe1fc82926020feedf894c4fb5c37ccd (This now brings us up to date with the latest version on github, except I left out the any file reader, SSE it filter, and the FIR resampler.) - Fixed serious error with MPT extension reading SVN r4117 (trunk) --- dumb/src/it/itread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index cb67aaa67..8e6b933e4 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -1484,7 +1484,7 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if ( !dumbfile_error( f ) && n < 10 ) { unsigned int mptx_id = dumbfile_igetl( f ); - while ( mptx_id != DUMB_ID('M','P','T','S') ) + while ( !dumbfile_error( f ) && mptx_id != DUMB_ID('M','P','T','S') ) { unsigned int size = dumbfile_igetw( f ); switch (mptx_id) From d1201bb9d144b9b70839382d3b39edb69d2a1a0c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 01:36:14 +0000 Subject: [PATCH 188/387] - DUMB warning fix. SVN r4118 (trunk) --- dumb/src/it/itread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index 8e6b933e4..1f29ad4d9 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -91,7 +91,7 @@ static DUMBFILE_SYSTEM mem_dfs = { static int it_seek(dumbfile_mem_status * s, int32 offset) { - if ( offset > s->size ) + if ( (unsigned)offset > s->size ) return -1; s->offset = offset; From f283e81b81652b067358dff804c7f6ab539dc11f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 02:34:54 +0000 Subject: [PATCH 189/387] - For some reason, I missed this change to xm_note_off(). SVN r4119 (trunk) --- dumb/src/it/itrender.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index 739ced68f..4f3d50dfa 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1586,7 +1586,8 @@ static void it_note_off(IT_PLAYING *playing) static void xm_note_off(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { if (channel->playing) { - if (!(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON)) + if (!channel->instrument || channel->instrument > sigdata->n_instruments || + !(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON)) //if (!(entry->mask & IT_ENTRY_INSTRUMENT)) // dunno what that was there for ... channel->volume = 0; From 8af26bc8e65c501b93864af3e0b08f540292b951 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Feb 2013 02:42:12 +0000 Subject: [PATCH 190/387] - Added limits.h for LONG_MAX SVN r4120 (trunk) --- dumb/src/it/readstm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index 89237d6e7..42f14e532 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -20,6 +20,7 @@ // IT_STEREO... :o #include #include +#include #include "dumb.h" #include "internal/it.h" From 90f51e21e385f62b4d713798f8f6214330720366 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 9 Feb 2013 01:30:09 +0000 Subject: [PATCH 191/387] - Add missing DUMBEXPORT to the dumb_load_okt[_quick] functions to fix building for VC++ release builds. SVN r4121 (trunk) --- dumb/src/it/loadokt.c | 2 +- dumb/src/it/loadokt2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dumb/src/it/loadokt.c b/dumb/src/it/loadokt.c index 2139d49e8..9670714d8 100644 --- a/dumb/src/it/loadokt.c +++ b/dumb/src/it/loadokt.c @@ -26,7 +26,7 @@ * pointer to the DUH struct. When you have finished with it, you must * pass the pointer to unload_duh() so that the memory can be freed. */ -DUH *dumb_load_okt_quick(const char *filename) +DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename) { DUH *duh; DUMBFILE *f = dumbfile_open(filename); diff --git a/dumb/src/it/loadokt2.c b/dumb/src/it/loadokt2.c index aa752c582..3d9ae447b 100644 --- a/dumb/src/it/loadokt2.c +++ b/dumb/src/it/loadokt2.c @@ -21,7 +21,7 @@ -DUH *dumb_load_okt(const char *filename) +DUH *DUMBEXPORT dumb_load_okt(const char *filename) { DUH *duh = dumb_load_okt_quick(filename); dumb_it_do_initial_runthrough(duh); From 65d2d0a5e5a3fd3ff8dc5952dced0ead01439521 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 9 Feb 2013 23:18:34 +0000 Subject: [PATCH 192/387] - Added compatibility option for Claustrophobia 1024, map 01. SVN r4122 (trunk) --- wadsrc/static/compatibility.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index c6c682f21..c699fe61e 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -147,6 +147,7 @@ DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller dependi 8FF30D57F6CE64F085A6567EC302842A // Enjay's test map for this flag 9D7893D09FEE55C31B73C670DF850962 // Memento Mori II, map12 +91E173901E6F3800B81AB646976247CD // Claustrophobia 1024, map01 { badangles } @@ -335,3 +336,4 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 { rebuildnodes } + From 24edfd5c8680db5631fc048c0c063e9122b25e72 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Feb 2013 00:26:47 +0000 Subject: [PATCH 193/387] - Fixed translations of Heretic linetype's that perform Floor_LowerToHighest with an offset. SVN r4123 (trunk) --- wadsrc/static/xlat/heretic.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wadsrc/static/xlat/heretic.txt b/wadsrc/static/xlat/heretic.txt index 8fe344f5b..cfc106d09 100644 --- a/wadsrc/static/xlat/heretic.txt +++ b/wadsrc/static/xlat/heretic.txt @@ -5,7 +5,10 @@ include "xlat/base.txt" 10 = WALK, Plat_DownWaitUpStayLip (tag, P_FAST, PLATWAIT, 0) 36 = WALK, Floor_LowerToHighest (tag, F_FAST, 136, 1) 49 = USE, Ceiling_LowerAndCrush (tag, C_SLOW, 0, 2) + 70 = USE|REP, Floor_LowerToHighest (tag, F_FAST, 136, 1) + 71 = USE, Floor_LowerToHighest (tag, F_FAST, 136, 1) 88 = WALK|REP, Plat_DownWaitUpStayLip (tag, P_FAST, PLATWAIT, 0) + 98 = WALK|REP, Floor_LowerToHighest (tag, F_FAST, 136, 1) 99 = 0, Scroll_Texture_Right (SCROLL_UNIT) 100 = WALK|REP, Door_Raise (tag, D_SLOW*3, VDOORWAIT) 105 = WALK, Exit_Secret (0) From 9af00a22d3479e87d07be41136d583b5f7433d48 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 10 Feb 2013 00:33:22 +0000 Subject: [PATCH 194/387] - Fixed: Strife's slow Ceiling_CrushAndRaise lines do no actual damage. SVN r4124 (trunk) --- wadsrc/static/xlat/strife.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/xlat/strife.txt b/wadsrc/static/xlat/strife.txt index 68887d975..a5aada362 100644 --- a/wadsrc/static/xlat/strife.txt +++ b/wadsrc/static/xlat/strife.txt @@ -99,7 +99,7 @@ RetailOnly = 121 17 = WALK, Light_StrobeDoom (tag, 5, 35) 19 = WALK, Floor_LowerToHighest (tag, F_SLOW, 128) 22 = WALK, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) - 25 = WALK, Ceiling_CrushAndRaiseA (tag, C_SLOW, C_SLOW, 10) + 25 = WALK, Ceiling_CrushAndRaiseA (tag, C_SLOW, C_SLOW, 0) 30 = WALK, Floor_RaiseByTexture (tag, F_SLOW) 35 = WALK, Light_ChangeToValue (tag, 35) 36 = WALK, Floor_LowerToHighest (tag, F_FAST, 128) @@ -128,7 +128,7 @@ RetailOnly = 121 124 = WALK, Teleport_EndGame () 125 = MONWALK, Teleport (0, tag) 130 = WALK, Floor_RaiseToNearest (tag, F_FAST) -141 = WALK, Ceiling_CrushAndRaiseSilentA (tag, C_SLOW, C_SLOW, 10) +141 = WALK, Ceiling_CrushAndRaiseSilentA (tag, C_SLOW, C_SLOW, 0) 174 = WALK, ACS_ExecuteAlways (0, 0, 174, tag) 183 = WALK, ACS_ExecuteAlways (0, 0, 183, tag) 178 = WALK, Generic_Stairs (tag, ST_FAST, 16, 0, 0) @@ -146,7 +146,7 @@ RetailOnly = 121 216 = WALK|REP, ACS_ExecuteAlways (0, 0, 216, tag) 90 = WALK|REP, Door_Raise (tag, D_SLOW, VDOORWAIT) 72 = WALK|REP, Ceiling_LowerAndCrushDist (tag, C_SLOW, 10) - 73 = WALK|REP, Ceiling_CrushAndRaiseA (tag, C_SLOW, C_SLOW, 10) + 73 = WALK|REP, Ceiling_CrushAndRaiseA (tag, C_SLOW, C_SLOW, 0) 74 = WALK|REP, Ceiling_CrushStop (tag) 75 = WALK|REP, Door_Close (tag, D_SLOW) 76 = WALK|REP, Door_CloseWaitOpen (tag, D_SLOW, 240) From 027a99d7728615d7199299fe48b5f8725b5fa8f7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Feb 2013 08:53:03 +0000 Subject: [PATCH 195/387] - fixed: Hexen's Floor_RaiseAndCrush is not the same action as the one used by Doom and which was used by ZDoom before r4053. Restored the old code and gave it a new special 99:Floor_RaiseAndCrushDoom. SVN r4125 (trunk) --- src/actionspecials.h | 2 +- src/p_floor.cpp | 7 ++++++- src/p_lnspec.cpp | 8 +++++++- src/p_spec.h | 1 + wadsrc/static/xlat/base.txt | 8 ++++---- wadsrc/static/xlat/strife.txt | 8 ++++---- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index b894a453a..1377def82 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -97,7 +97,7 @@ DEFINE_SPECIAL(FloorAndCeiling_LowerByValue, 95, 3, 3, 3) DEFINE_SPECIAL(FloorAndCeiling_RaiseByValue, 96, 3, 3, 3) DEFINE_SPECIAL(Ceiling_LowerAndCrushDist, 97, 3, 5, 5) DEFINE_SPECIAL(Sector_SetTranslucent, 98, 3, 4, 4) - +DEFINE_SPECIAL(Floor_RaiseAndCrushDoom, 99, 3, 4, 4) DEFINE_SPECIAL(Scroll_Texture_Left, 100, -1, -1, 2) DEFINE_SPECIAL(Scroll_Texture_Right, 101, -1, -1, 2) DEFINE_SPECIAL(Scroll_Texture_Up, 102, -1, -1, 2) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index ea2551dfd..3e2de1679 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -375,13 +375,18 @@ manual_floor: floor->m_Direction = (floor->m_FloorDestDist > sec->floorplane.d) ? -1 : 1; break; + case DFloor::floorRaiseAndCrushDoom: + floor->m_Crush = crush; case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; newheight = sec->FindLowestCeilingSurrounding (&spot); + if (floortype == DFloor::floorRaiseAndCrush) + newheight -= 8 * FRACUNIT; ceilingheight = sec->FindLowestCeilingPoint (&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); if (sec->floorplane.ZatPointDist (spot2, floor->m_FloorDestDist) > ceilingheight) - floor->m_FloorDestDist = sec->floorplane.PointToDist (spot2, ceilingheight); + floor->m_FloorDestDist = sec->floorplane.PointToDist (spot2, + floortype == DFloor::floorRaiseAndCrush ? ceilingheight - 8*FRACUNIT : ceilingheight); break; case DFloor::floorRaiseToHighest: diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 0c84ca4ee..8b461f9cb 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -326,6 +326,12 @@ FUNC(LS_Floor_RaiseAndCrush) return EV_DoFloor (DFloor::floorRaiseAndCrush, ln, arg0, SPEED(arg1), 0, arg2, 0, CRUSHTYPE(arg3)); } +FUNC(LS_Floor_RaiseAndCrushDoom) +// Floor_RaiseAndCrushDoom (tag, speed, crush, crushmode) +{ + return EV_DoFloor (DFloor::floorRaiseAndCrushDoom, ln, arg0, SPEED(arg1), 0, arg2, 0, CRUSHTYPE(arg3)); +} + FUNC(LS_Floor_RaiseByValueTimes8) // FLoor_RaiseByValueTimes8 (tag, speed, height) { @@ -3232,7 +3238,7 @@ lnSpecFunc LineSpecials[256] = /* 96 */ LS_FloorAndCeiling_RaiseByValue, /* 97 */ LS_Ceiling_LowerAndCrushDist, /* 98 */ LS_Sector_SetTranslucent, - /* 99 */ LS_NOP, + /* 99 */ LS_Floor_RaiseAndCrushDoom, /* 100 */ LS_NOP, // Scroll_Texture_Left /* 101 */ LS_NOP, // Scroll_Texture_Right /* 102 */ LS_NOP, // Scroll_Texture_Up diff --git a/src/p_spec.h b/src/p_spec.h index 81051eb8e..4f67f87ff 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -697,6 +697,7 @@ public: floorRaiseToHighest, floorRaiseToNearest, floorRaiseAndCrush, + floorRaiseAndCrushDoom, floorCrushStop, floorLowerInstant, floorRaiseInstant, diff --git a/wadsrc/static/xlat/base.txt b/wadsrc/static/xlat/base.txt index 44d5457b2..11b9fd315 100644 --- a/wadsrc/static/xlat/base.txt +++ b/wadsrc/static/xlat/base.txt @@ -54,8 +54,8 @@ include "xlat/defines.i" 52 = WALK, Exit_Normal (0) 53 = WALK, Plat_PerpetualRaiseLip (tag, P_SLOW, PLATWAIT, 0) 54 = WALK, Plat_Stop (tag) - 55 = USE, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) - 56 = WALK, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 55 = USE, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) + 56 = WALK, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 57 = WALK, Ceiling_CrushStop (tag) 58 = WALK, Floor_RaiseByValue (tag, F_SLOW, 24) 59 = WALK, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) @@ -64,7 +64,7 @@ include "xlat/defines.i" 62 = USE|REP, Plat_DownWaitUpStayLip (tag, P_FAST, PLATWAIT, 0) 63 = USE|REP, Door_Raise (tag, D_SLOW, VDOORWAIT) 64 = USE|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) - 65 = USE|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 65 = USE|REP, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 66 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 3) 67 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 4) 68 = USE|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) @@ -93,7 +93,7 @@ include "xlat/defines.i" 91 = WALK|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) 92 = WALK|REP, Floor_RaiseByValue (tag, F_SLOW, 24) 93 = WALK|REP, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) - 94 = WALK|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 94 = WALK|REP, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 95 = WALK|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) 96 = WALK|REP, Floor_RaiseByTexture (tag, F_SLOW) 97 = WALK|REP|MONST, Teleport (0, tag) diff --git a/wadsrc/static/xlat/strife.txt b/wadsrc/static/xlat/strife.txt index a5aada362..5666fbeb6 100644 --- a/wadsrc/static/xlat/strife.txt +++ b/wadsrc/static/xlat/strife.txt @@ -113,7 +113,7 @@ RetailOnly = 121 52 = WALK|REP, ACS_ExecuteAlways (0, 0, 52, tag) 53 = WALK, Plat_PerpetualRaiseLip (tag, P_SLOW, PLATWAIT, 0) 54 = WALK, Plat_Stop (tag) - 56 = WALK, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 56 = WALK, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 57 = WALK, Ceiling_CrushStop (tag) 58 = WALK, Floor_RaiseByValue (tag, F_SLOW, 64) 59 = WALK, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) @@ -164,7 +164,7 @@ RetailOnly = 121 91 = WALK|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) 92 = WALK|REP, Floor_RaiseByValue (tag, F_SLOW, 64) 93 = WALK|REP, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) - 94 = WALK|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 94 = WALK|REP, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 95 = WALK|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) 96 = WALK|REP, Floor_RaiseByTexture (tag, F_SLOW) 97 = WALK|REP|MONST, Teleport (0, tag) @@ -247,7 +247,7 @@ RetailOnly = 121 49 = USE, Ceiling_CrushAndRaiseDist (tag, 8, C_SLOW, 0, 2) 50 = USE, Door_Close (tag, D_SLOW) 51 = USE, Teleport_EndGame (0) - 55 = USE, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 55 = USE, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 101 = USE, Floor_RaiseToLowestCeiling (tag, F_SLOW) 102 = USE, Floor_LowerToHighest (tag, F_SLOW, 128) 103 = USE, Door_Open (tag, D_SLOW) @@ -289,7 +289,7 @@ RetailOnly = 121 64 = USE|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) 66 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 3) 67 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 4) - 65 = USE|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 65 = USE|REP, Floor_RaiseAndCrushDoom (tag, F_SLOW, 10, 2) 68 = USE|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) 69 = USE|REP, Floor_RaiseToNearest (tag, F_SLOW) 70 = USE|REP, Floor_LowerToHighest (tag, F_FAST, 128) From 954e9e03f2cb508a321591c5cc9e3f80999139b6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Feb 2013 09:01:15 +0000 Subject: [PATCH 196/387] - removed a few 'GZDoom only' notes that no longer apply. SVN r4128 (trunk) --- src/p_lnspec.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 8b461f9cb..67df3def1 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3297,10 +3297,10 @@ lnSpecFunc LineSpecials[256] = /* 155 */ LS_NOP, /* 156 */ LS_NOP, /* 157 */ LS_NOP, // SetGlobalFogParameter // in GZDoom - /* 158 */ LS_NOP, // FS_Execute in GZDoom + /* 158 */ LS_NOP, // FS_Execute /* 159 */ LS_NOP, // Sector_SetPlaneReflection in GZDoom - /* 160 */ LS_NOP, // Sector_Set3DFloor in GZDoom and Vavoom - /* 161 */ LS_NOP, // Sector_SetContents in GZDoom and Vavoom + /* 160 */ LS_NOP, // Sector_Set3DFloor + /* 161 */ LS_NOP, // Sector_SetContents /* 162 */ LS_NOP, // Reserved Doom64 branch /* 163 */ LS_NOP, // Reserved Doom64 branch /* 164 */ LS_NOP, // Reserved Doom64 branch From 3defad92daa4fe50baa632c32def28baee605dfb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Feb 2013 09:03:56 +0000 Subject: [PATCH 197/387] - missed some changed constants... SVN r4129 (trunk) --- src/p_floor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 3e2de1679..e9768479b 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -380,13 +380,13 @@ manual_floor: case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; newheight = sec->FindLowestCeilingSurrounding (&spot); - if (floortype == DFloor::floorRaiseAndCrush) + if (floortype == DFloor::floorRaiseAndCrushDoom) newheight -= 8 * FRACUNIT; ceilingheight = sec->FindLowestCeilingPoint (&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); if (sec->floorplane.ZatPointDist (spot2, floor->m_FloorDestDist) > ceilingheight) floor->m_FloorDestDist = sec->floorplane.PointToDist (spot2, - floortype == DFloor::floorRaiseAndCrush ? ceilingheight - 8*FRACUNIT : ceilingheight); + floortype == DFloor::floorRaiseAndCrushDoom ? ceilingheight - 8*FRACUNIT : ceilingheight); break; case DFloor::floorRaiseToHighest: From 62b23901eb9ff8c3967b55d3eb814564636cf37c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 12 Feb 2013 23:23:33 +0000 Subject: [PATCH 198/387] - Fixed: spynext/prev were unreliable with player prediction. SVN r4130 (trunk) --- src/p_user.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_user.cpp b/src/p_user.cpp index cb15b18f9..7b332cb0e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2569,9 +2569,14 @@ void P_UnPredictPlayer () if (player->cheats & CF_PREDICTING) { AActor *act = player->mo; + AActor *savedcamera = player->camera; *player = PredictionPlayerBackup; + // Restore the camera instead of using the backup's copy, because spynext/prev + // could cause it to change during prediction. + player->camera = savedcamera; + act->UnlinkFromWorld (); memcpy (&act->x, PredictionActorBackup, sizeof(AActor)-((BYTE *)&act->x-(BYTE *)act)); From 0b9b6dda2ea7830e802d16795753c17801f7c095 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 12 Feb 2013 23:55:28 +0000 Subject: [PATCH 199/387] - Fixed: The changemap CCMD did not work for maps not defined by MAPINFO. SVN r4131 (trunk) --- src/g_level.cpp | 9 +++------ src/g_level.h | 2 +- src/g_mapinfo.cpp | 5 +++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 27be03b08..3fd2bae73 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -489,7 +489,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill } else if (strncmp(levelname, "enDSeQ", 6) != 0) { - nextinfo = FindLevelInfo (levelname); + nextinfo = FindLevelInfo (levelname, false); if (nextinfo != NULL) { level_info_t *nextredir = nextinfo->CheckLevelRedirect(); @@ -655,17 +655,14 @@ void G_DoCompleted (void) } else { - if (strncmp (nextlevel, "enDSeQ", 6) == 0) + level_info_t *nextinfo = FindLevelInfo (nextlevel, false); + if (nextinfo == NULL || strncmp (nextlevel, "enDSeQ", 6) == 0) { wminfo.next = nextlevel; wminfo.LName1 = NULL; } else { - - - - level_info_t *nextinfo = FindLevelInfo (nextlevel); wminfo.next = nextinfo->mapname; wminfo.LName1 = TexMan[TexMan.CheckForTexture(nextinfo->pname, FTexture::TEX_MiscPatch)]; } diff --git a/src/g_level.h b/src/g_level.h index cdac4b862..cd8f6c1f7 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -515,7 +515,7 @@ void G_InitLevelLocals (void); void G_AirControlChanged (); cluster_info_t *FindClusterInfo (int cluster); -level_info_t *FindLevelInfo (const char *mapname); +level_info_t *FindLevelInfo (const char *mapname, bool allowdefault=true); level_info_t *FindLevelByNum (int num); level_info_t *CheckLevelRedirect (level_info_t *info); diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index adfd626c3..cb7b03932 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -82,7 +82,7 @@ static int FindWadLevelInfo (const char *name) // //========================================================================== -level_info_t *FindLevelInfo (const char *mapname) +level_info_t *FindLevelInfo (const char *mapname, bool allowdefault) { int i; @@ -90,7 +90,7 @@ level_info_t *FindLevelInfo (const char *mapname) { return &wadlevelinfos[i]; } - else + else if (allowdefault) { if (TheDefaultLevelInfo.LevelName.IsEmpty()) { @@ -100,6 +100,7 @@ level_info_t *FindLevelInfo (const char *mapname) } return &TheDefaultLevelInfo; } + return NULL; } //========================================================================== From 951adbb21f09062d88298da4951918fff63df0f3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 14 Feb 2013 01:29:53 +0000 Subject: [PATCH 200/387] - Fixed: When adding a forwardmove value, P_Bob() needs to do the same pitch-dependent scaling as P_ForwardThrust(). SVN r4132 (trunk) --- src/p_user.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 7b332cb0e..76aecdc39 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1579,8 +1579,16 @@ void P_ForwardThrust (player_t *player, angle_t angle, fixed_t move) // reduced at a regular rate, even on ice (where the player coasts). // -void P_Bob (player_t *player, angle_t angle, fixed_t move) +void P_Bob (player_t *player, angle_t angle, fixed_t move, bool forward) { + if (forward + && (player->mo->waterlevel || (player->mo->flags & MF_NOGRAVITY)) + && player->mo->pitch != 0) + { + angle_t pitch = (angle_t)player->mo->pitch >> ANGLETOFINESHIFT; + move = FixedMul (move, finecosine[pitch]); + } + angle >>= ANGLETOFINESHIFT; player->velx += FixedMul(move, finecosine[angle]); @@ -1773,8 +1781,8 @@ void P_MovePlayer (player_t *player) fm = FixedMul (fm, player->mo->Speed); sm = FixedMul (sm, player->mo->Speed); - // When crouching speed and bobbing have to be reduced - if (player->morphTics==0 && player->crouchfactor != FRACUNIT) + // When crouching, speed and bobbing have to be reduced + if (player->morphTics == 0 && player->crouchfactor != FRACUNIT) { fm = FixedMul(fm, player->crouchfactor); sm = FixedMul(sm, player->crouchfactor); @@ -1786,12 +1794,12 @@ void P_MovePlayer (player_t *player) if (forwardmove) { - P_Bob (player, mo->angle, (cmd->ucmd.forwardmove * bobfactor) >> 8); + P_Bob (player, mo->angle, (cmd->ucmd.forwardmove * bobfactor) >> 8, true); P_ForwardThrust (player, mo->angle, forwardmove); } if (sidemove) { - P_Bob (player, mo->angle-ANG90, (cmd->ucmd.sidemove * bobfactor) >> 8); + P_Bob (player, mo->angle-ANG90, (cmd->ucmd.sidemove * bobfactor) >> 8, false); P_SideThrust (player, mo->angle, sidemove); } From 94be9df246ae5ac56381d3cc48224e36bdd6250d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 14 Feb 2013 03:24:47 +0000 Subject: [PATCH 201/387] - Changed the "notrelevant" checks in R_RenderMaskedSegRange() to not include equality in their comparison operators. Fixes one map (http://forum.zdoom.org/viewtopic.php?f=2&t=34082); might break others. Maybe. SVN r4133 (trunk) --- src/r_segs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 62c3e678a..e37cbe086 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -378,12 +378,12 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) goto clearfog; } - if ((fake3D & FAKE3D_CLIPBOTTOM) && textop <= sclipBottom - viewz) + if ((fake3D & FAKE3D_CLIPBOTTOM) && textop < sclipBottom - viewz) { notrelevant = true; goto clearfog; } - if ((fake3D & FAKE3D_CLIPTOP) && textop - texheight >= sclipTop - viewz) + if ((fake3D & FAKE3D_CLIPTOP) && textop - texheight > sclipTop - viewz) { notrelevant = true; goto clearfog; From 70fa9e7b84d7bf7c1a47931efae2b6dc5bc41cbb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 14 Feb 2013 03:56:34 +0000 Subject: [PATCH 202/387] - Fixed: info CCMD listed bounce flags twice, under separate names. SVN r4134 (trunk) --- src/p_mobj.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f2a974e82..a1c8cd00c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6100,9 +6100,9 @@ void PrintMiscActorInfo(AActor *query) Printf("\n\tflags6: %x", query->flags6); for (flagi = 0; flagi <= 31; flagi++) if (query->flags6 & 1<BounceFlags, FIXED2FLOAT(query->bouncefactor), - FIXED2FLOAT(query->wallbouncefactor), query->BounceFlags); + FIXED2FLOAT(query->wallbouncefactor)); /*for (flagi = 0; flagi < 31; flagi++) if (query->BounceFlags & 1< Date: Thu, 14 Feb 2013 04:40:29 +0000 Subject: [PATCH 203/387] - Skip the MF2_PASSMOBJ height checks in PIT_CheckThing() for ripper missiles. SVN r4135 (trunk) --- src/p_map.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 289f146bb..7cdf90ee8 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -905,13 +905,17 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) // you can use a scrolling floor to move scenery items underneath a bridge. if ((tm.thing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ)) { // check if a mobj passed over/under another object - if (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP) - { // Some things prefer not to overlap each other, if possible - return unblocking; - } - if ((tm.thing->z >= topz) || (tm.thing->z + tm.thing->height <= thing->z)) + if (!(tm.thing->flags & MF_MISSILE) || + !(tm.thing->flags2 & MF2_RIP) || + (thing->flags5 & MF5_DONTRIP) || + (tm.thing->flags6 & MF6_NOBOSSRIP) && (thing->flags2 & MF2_BOSS)) { - return true; + if (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP) + { // Some things prefer not to overlap each other, if possible + return unblocking; + } + if ((tm.thing->z >= topz) || (tm.thing->z + tm.thing->height <= thing->z)) + return true; } } @@ -2878,7 +2882,7 @@ extern FRandom pr_bounce; bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop) { if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors) - || ((mo->flags & MF_MISSILE) && (BlockingMobj->flags2 & MF2_REFLECTIVE)) + || ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) || (BlockingMobj->flags5 & MF5_DONTRIP) || ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE)) || ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER))) )) { From 7714a45e02876b7b548be4d031a75e329fe7a396 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 14 Feb 2013 05:06:05 +0000 Subject: [PATCH 204/387] - Fixed: Because P_OpenMapData() now reopens the containing file for the map, P_LoadGLNodes() needs a new check for if the map came from a regular wad. SVN r4136 (trunk) --- src/p_glnodes.cpp | 2 +- src/p_setup.cpp | 1 + src/p_setup.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 22bf18e26..48db99b67 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -901,7 +901,7 @@ bool P_LoadGLNodes(MapData * map) char path[256]; int li; int lumpfile = Wads.GetLumpFile(map->lumpnum); - bool mapinwad = map->file == Wads.GetFileReader(lumpfile); + bool mapinwad = map->InWad; FileReader * fr = map->file; FResourceFile * f_gwa = NULL; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 4cd337ca5..261d47ea3 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -304,6 +304,7 @@ MapData *P_OpenMapData(const char * mapname) // As such any special handling for other types of lumps is skipped. map->MapLumps[0].Reader = map->file = Wads.ReopenLumpNum(lump_name); map->Encrypted = Wads.IsEncryptedFile(lump_name); + map->InWad = true; if (map->Encrypted) { // If it's encrypted, then it's a Blood file, presumably a map. diff --git a/src/p_setup.h b/src/p_setup.h index b1590e714..61cda54fe 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -37,6 +37,7 @@ struct MapData bool HasBehavior; bool Encrypted; bool isText; + bool InWad; int lumpnum; FileReader * file; FResourceFile * resource; @@ -50,6 +51,7 @@ struct MapData HasBehavior = false; Encrypted = false; isText = false; + InWad = false; } ~MapData() From facbca36197dc305ab289ea190df5579a8bd8f0f Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 14 Feb 2013 23:27:09 +0000 Subject: [PATCH 205/387] - Fixed: If you hit a wall at the right moment you would some times come out of a teleporter with sliding velocity. SVN r4137 (trunk) --- src/p_map.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7cdf90ee8..ad678b529 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2516,10 +2516,17 @@ void FSlide::SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps) { newx = FixedMul (tryx, bestslidefrac); newy = FixedMul (tryy, bestslidefrac); - + + // [BL] We need to abandon this function if we end up going through a teleporter + const fixed_t startvelx = mo->velx; + const fixed_t startvely = mo->vely; + // killough 3/15/98: Allow objects to drop off ledges if (!P_TryMove (mo, mo->x+newx, mo->y+newy, true)) goto stairstep; + + if (mo->velx != startvelx || mo->vely != startvely) + return; } // Now continue along the wall. From d71b0609f06c12123c1d80447019231d3f51b520 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 16 Feb 2013 09:41:54 +0000 Subject: [PATCH 206/387] - fixed incorrect -= operators in vectors.h SVN r4138 (trunk) --- src/vectors.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vectors.h b/src/vectors.h index c0783e250..e340194da 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -439,7 +439,7 @@ struct TVector3 // Vector subtraction TVector3 &operator-= (const TVector3 &other) { - X -= other.X, Y -= other.Y, Z - other.Z; + X -= other.X, Y -= other.Y, Z -= other.Z; return *this; } @@ -485,7 +485,7 @@ struct TVector3 { return Vector2(v2.X - v3.X, v2.Y - v3.Y); } - +F // Vector length double Length() const { @@ -1166,7 +1166,7 @@ struct TRotator // Vector subtraction TRotator &operator-= (const TRotator &other) { - Pitch -= other.Pitch, Yaw -= other.Yaw, Roll - other.Roll; + Pitch -= other.Pitch, Yaw -= other.Yaw, Roll -= other.Roll; return *this; } From 00d5bee72ff969c40759d69df02cde377e617fde Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 16 Feb 2013 10:48:03 +0000 Subject: [PATCH 207/387] - ...now where did that 'F' come from...? SVN r4139 (trunk) --- src/vectors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vectors.h b/src/vectors.h index e340194da..c1bcf74b9 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -485,7 +485,7 @@ struct TVector3 { return Vector2(v2.X - v3.X, v2.Y - v3.Y); } -F + // Vector length double Length() const { From e434ccc3f61f5607064945c86f38fd3a357f5376 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 17 Feb 2013 00:23:58 +0000 Subject: [PATCH 208/387] - Add support for user variables on things in UDMF maps. If you include an actor's user variable in its UDMF thing definition, that user variable will be set to the desired value for that actor when the map is loaded. SVN r4140 (trunk) --- src/p_setup.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++--- src/p_setup.h | 10 ++++++++++ src/p_udmf.cpp | 19 +++++++++++++++--- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 261d47ea3..dfabd6420 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -142,6 +142,8 @@ int numgamesubsectors; bool hasglnodes; TArray MapThingsConverted; +TMap MapThingsUserDataIndex; // from mapthing idx -> user data idx +TArray MapThingsUserData; int sidecount; sidei_t *sidetemp; @@ -1637,7 +1639,7 @@ void P_LoadNodes (MapData * map) //=========================================================================== CVAR(Bool, dumpspawnedthings, false, 0) -void SpawnMapThing(int index, FMapThing *mt, int position) +AActor *SpawnMapThing(int index, FMapThing *mt, int position) { AActor *spawned = P_SpawnMapThing(mt, position); if (dumpspawnedthings) @@ -1647,6 +1649,42 @@ void SpawnMapThing(int index, FMapThing *mt, int position) spawned? spawned->GetClass()->TypeName.GetChars() : "(none)"); } T_AddSpawnedThing(spawned); + return spawned; +} + +//=========================================================================== +// +// SetMapThingUserData +// +//=========================================================================== + +static void SetMapThingUserData(AActor *actor, unsigned udi) +{ + if (actor == NULL) + { + return; + } + while (MapThingsUserData[udi].Property != NAME_None) + { + FName varname = MapThingsUserData[udi].Property; + int value = MapThingsUserData[udi].Value; + PSymbol *sym = actor->GetClass()->Symbols.FindSymbol(varname, true); + PSymbolVariable *var; + + udi++; + + if (sym == NULL || sym->SymbolType != SYM_Variable || + !(var = static_cast(sym))->bUserVar || + var->ValueType.Type != VAL_Int) + { + DPrintf("%s is not a user variable in class %s\n", varname.GetChars(), + actor->GetClass()->TypeName.GetChars()); + } + else + { // Set the value of the specified user variable. + *(int *)(reinterpret_cast(actor) + var->offset) = value; + } + } } //=========================================================================== @@ -1685,7 +1723,7 @@ void P_LoadThings (MapData * map) for (int i=0 ; i < numthings; i++, mt++) { // [RH] At this point, monsters unique to Doom II were weeded out - // if the IWAD wasn't for Doom II. R_SpawnMapThing() can now + // if the IWAD wasn't for Doom II. P_SpawnMapThing() can now // handle these and more cases better, so we just pass it // everything and let it decide what to do with them. @@ -1780,7 +1818,12 @@ void P_SpawnThings (int position) for (int i=0; i < numthings; i++) { - SpawnMapThing (i, &MapThingsConverted[i], position); + AActor *actor = SpawnMapThing (i, &MapThingsConverted[i], position); + unsigned *udi = MapThingsUserDataIndex.CheckKey((unsigned)i); + if (udi != NULL) + { + SetMapThingUserData(actor, *udi); + } } for(int i=0; i FMissingTextureTracker; +// Record of user data for UDMF maps +struct FMapThingUserData +{ + FName Property; + int Value; +}; +extern TMap MapThingsUserDataIndex; // from mapthing idx -> user data idx +extern TArray MapThingsUserData; + + #endif diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e087834b1..6a38708ea 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -627,9 +627,12 @@ public: break; default: - if (!strnicmp("user_", key.GetChars(), 5)) - { - // Custom user key - handle later + if (0 == strnicmp("user_", key.GetChars(), 5)) + { // Custom user key - Sets an actor's user variable directly + FMapThingUserData ud; + ud.Property = key; + ud.Value = CheckInt(key); + MapThingsUserData.Push(ud); } break; } @@ -1603,8 +1606,18 @@ public: if (sc.Compare("thing")) { FMapThing th; + unsigned userdatastart = MapThingsUserData.Size(); ParseThing(&th); MapThingsConverted.Push(th); + if (userdatastart < MapThingsUserData.Size()) + { // User data added + MapThingsUserDataIndex[MapThingsConverted.Size()-1] = userdatastart; + // Mark end of the user data for this map thing + FMapThingUserData ud; + ud.Property = NAME_None; + ud.Value = 0; + MapThingsUserData.Push(ud); + } } else if (sc.Compare("linedef")) { From 87dbfb68e9de2f6eefea71aa85988b2ab139f713 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 01:51:07 +0000 Subject: [PATCH 209/387] - Fixed: PCD_MORPHACTOR and P_MorphMonster() needed NULL pointer checks. SVN r4141 (trunk) --- src/g_shared/a_morph.cpp | 2 +- src/p_acs.cpp | 23 ++++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 862baa30b..0058c996b 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -366,7 +366,7 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s { AMorphedMonster *morphed; - if (actor->player || spawntype == NULL || + if (actor == NULL || actor->player || spawntype == NULL || actor->flags3 & MF3_DONTMORPH || !(actor->flags3 & MF3_ISMONSTER) || !spawntype->IsDescendantOf (RUNTIME_CLASS(AMorphedMonster))) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 3e4f349dc..1527ba849 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7175,19 +7175,13 @@ scriptwait: if (tag == 0) { - if (activator->player) + if (activator != NULL && activator->player) { - if (P_MorphPlayer(activator->player, activator->player, playerclass, duration, style, morphflash, unmorphflash)) - { - changes++; - } + changes += P_MorphPlayer(activator->player, activator->player, playerclass, duration, style, morphflash, unmorphflash); } else { - if (P_MorphMonster(activator, monsterclass, duration, style, morphflash, unmorphflash)) - { - changes++; - } + changes += P_MorphMonster(activator, monsterclass, duration, style, morphflash, unmorphflash); } } else @@ -7199,17 +7193,12 @@ scriptwait: { if (actor->player) { - if (P_MorphPlayer(activator->player, actor->player, playerclass, duration, style, morphflash, unmorphflash)) - { - changes++; - } + changes += P_MorphPlayer(activator == NULL ? NULL : activator->player, + actor->player, playerclass, duration, style, morphflash, unmorphflash); } else { - if (P_MorphMonster(actor, monsterclass, duration, style, morphflash, unmorphflash)) - { - changes++; - } + changes += P_MorphMonster(actor, monsterclass, duration, style, morphflash, unmorphflash); } } } From b96d305c8754402ea9e6205bae31079be3a2ecec Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 01:55:14 +0000 Subject: [PATCH 210/387] - Make the DOOM 3 BFG Edition the last Steam path checked, so it won't override the regular doom.wad. SVN r4142 (trunk) --- src/d_iwad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index e7d5c30ca..e53a1d362 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -437,12 +437,12 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, static const char *const steam_dirs[] = { "doom 2/base", - "DOOM 3 BFG Edition/base/wads", "final doom/base", "heretic shadow of the serpent riders/base", "hexen/base", "hexen deathkings of the dark citadel/base", - "ultimate doom/base" + "ultimate doom/base", + "DOOM 3 BFG Edition/base/wads" }; steam_path += "/SteamApps/common/"; for (i = 0; i < countof(steam_dirs); ++i) From 619e65ad6f4338a3f2d4969a16ff2693b022d8f7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:25:20 +0000 Subject: [PATCH 211/387] - Allow negative parameters to A_Light. SVN r4144 (trunk) --- src/p_pspr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 6a2176458..d91b2a88d 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -997,7 +997,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) if (self->player != NULL) { - self->player->extralight = clamp(light, 0, 20); + self->player->extralight = clamp(light, -20, 20); } } From ae6b0c621533947b965b2c3d561753e00143f2b6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:27:41 +0000 Subject: [PATCH 212/387] - Added IF_NOSCREENFLASH> SVN r4145 (trunk) --- src/g_shared/a_pickups.cpp | 5 ++++- src/g_shared/a_pickups.h | 1 + src/thingdef/thingdef_data.cpp | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 9465a1c3a..1ed5b4919 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -964,7 +964,10 @@ void AInventory::Touch (AActor *toucher) if (toucher->player != NULL) { PlayPickupSound (toucher->player->mo); - toucher->player->bonuscount = BONUSADD; + if (!(ItemFlags & IF_NOSCREENFLASH)) + { + toucher->player->bonuscount = BONUSADD; + } } else { diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 2358fbe10..631a25181 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -133,6 +133,7 @@ enum IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes IF_NEVERRESPAWN = 1<<20, // Never, ever respawns + IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen }; diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 16028d249..1d828d647 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -299,10 +299,10 @@ static FFlagDef InventoryFlags[] = DEFINE_FLAG(IF, PERSISTENTPOWER, AInventory, ItemFlags), DEFINE_FLAG(IF, RESTRICTABSOLUTELY, AInventory, ItemFlags), DEFINE_FLAG(IF, NEVERRESPAWN, AInventory, ItemFlags), + DEFINE_FLAG(IF, NOSCREENFLASH, AInventory, ItemFlags), DEFINE_DEPRECATED_FLAG(PICKUPFLASH), - DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP), -}; + DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP),}; static FFlagDef WeaponFlags[] = { From bd601a1bc832de1340faf19d2cb5e1398815fb10 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:44:49 +0000 Subject: [PATCH 213/387] - Added NOTRAIL flag for PowerSpeed. SVN r4146 (trunk) --- src/g_shared/a_artifacts.cpp | 40 ++++++++++++++++++++--- src/g_shared/a_artifacts.h | 5 +++ src/thingdef/thingdef_data.cpp | 7 ++++ wadsrc/static/actors/shared/inventory.txt | 2 +- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 4f44cfc20..dc45634df 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1156,6 +1156,24 @@ void APlayerSpeedTrail::Tick () IMPLEMENT_CLASS (APowerSpeed) +//=========================================================================== +// +// APowerSpeed :: Serialize +// +//=========================================================================== + +void APowerSpeed::Serialize(FArchive &arc) +{ + if (SaveVersion < 4146) + { + SpeedFlags = 0; + } + else + { + arc << SpeedFlags; + } +} + //=========================================================================== // // APowerSpeed :: GetSpeedFactor @@ -1164,8 +1182,10 @@ IMPLEMENT_CLASS (APowerSpeed) fixed_t APowerSpeed ::GetSpeedFactor () { - if (Inventory != NULL) return FixedMul(Speed, Inventory->GetSpeedFactor()); - else return Speed; + if (Inventory != NULL) + return FixedMul(Speed, Inventory->GetSpeedFactor()); + else + return Speed; } //=========================================================================== @@ -1184,12 +1204,22 @@ void APowerSpeed::DoEffect () if (Owner->player->cheats & CF_PREDICTING) return; + if (SpeedFlags & PSF_NOTRAIL) + return; + if (level.time & 1) return; - // check if another speed item is present to avoid multiple drawing of the speed trail. - if (Inventory != NULL && Inventory->GetSpeedFactor() > FRACUNIT) - return; + // Check if another speed item is present to avoid multiple drawing of the speed trail. + // Only the last PowerSpeed without PSF_NOTRAIL set will actually draw the trail. + for (AInventory *item = Inventory; item != NULL; item = item->Inventory) + { + if (item->IsKindOf(RUNTIME_CLASS(APowerSpeed)) && + !(static_cast(item)->SpeedFlags & PSF_NOTRAIL)) + { + return; + } + } if (P_AproxDistance (Owner->velx, Owner->vely) <= 12*FRACUNIT) return; diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index f8a806956..b8c66bb40 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -143,9 +143,14 @@ class APowerSpeed : public APowerup DECLARE_CLASS (APowerSpeed, APowerup) protected: void DoEffect (); + void Serialize(FArchive &arc); fixed_t GetSpeedFactor(); +public: + int SpeedFlags; }; +#define PSF_NOTRAIL 1 + class APowerMinotaur : public APowerup { DECLARE_CLASS (APowerMinotaur, APowerup) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 1d828d647..68a17241b 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -338,12 +338,19 @@ static FFlagDef PlayerPawnFlags[] = DEFINE_FLAG(PPF, CANSUPERMORPH, APlayerPawn, PlayerFlags), }; +static FFlagDef PowerSpeedFlags[] = +{ + // PowerSpeed flags + DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), +}; + static const struct FFlagList { const PClass *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { { RUNTIME_CLASS(AActor), ActorFlags, countof(ActorFlags) }, { RUNTIME_CLASS(AInventory), InventoryFlags, countof(InventoryFlags) }, { RUNTIME_CLASS(AWeapon), WeaponFlags, countof(WeaponFlags) }, { RUNTIME_CLASS(APlayerPawn), PlayerPawnFlags,countof(PlayerPawnFlags) }, + { RUNTIME_CLASS(APowerSpeed), PowerSpeedFlags,countof(PowerSpeedFlags) }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 7ed28e22d..0632195c6 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -226,7 +226,7 @@ ACTOR PowerWeaponLevel2 : Powerup native Inventory.Icon "SPINBK0" } -ACTOR PowerSpeed: Powerup native +ACTOR PowerSpeed : Powerup native { Powerup.Duration -45 Speed 1.5 From 602209d4a4f4ffd38f442e8f9e54b1870352619f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:50:47 +0000 Subject: [PATCH 214/387] - Add NoRandomPlayerclass flag for MAPINFO. SVN r4147 (trunk) --- src/gi.cpp | 1 + src/gi.h | 1 + src/menu/menudef.cpp | 2 +- src/menu/playermenu.cpp | 13 ++++++++----- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index 0e010724a..2df1fdde0 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -338,6 +338,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont") GAMEINFOKEY_PATCH(mStatscreenFinishedFont, "statscreen_finishedpatch") GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch") + GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass") else { diff --git a/src/gi.h b/src/gi.h index 647db1a9b..ff678df07 100644 --- a/src/gi.h +++ b/src/gi.h @@ -139,6 +139,7 @@ struct gameinfo_t FGIFont mStatscreenMapNameFont; FGIFont mStatscreenFinishedFont; FGIFont mStatscreenEnteringFont; + bool norandomplayerclass; const char *GetFinalePage(unsigned int num) const; }; diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 0d9b89989..8167f6592 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -1098,7 +1098,7 @@ static void BuildPlayerclassMenu() } } } - if (n > 1) + if (n > 1 && !gameinfo.norandomplayerclass) { FListMenuItemText *it = new FListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r', "$MNU_RANDOM", ld->mFont,ld->mFontColor, NAME_Episodemenu, -1); diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 99eedfe66..a76817055 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -606,13 +606,16 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) } else { - li->SetString(0, "Random"); + // [XA] Remove the "Random" option if the relevant gameinfo flag is set. + if(!gameinfo.norandomplayerclass) + li->SetString(0, "Random"); for(unsigned i=0; i< PlayerClasses.Size(); i++) { const char *cls = GetPrintableDisplayName(PlayerClasses[i].Type); - li->SetString(i+1, cls); + li->SetString(gameinfo.norandomplayerclass ? i : i+1, cls); } - li->SetValue(0, players[consoleplayer].userinfo.PlayerClass + 1); + int pclass = players[consoleplayer].userinfo.PlayerClass; + li->SetValue(0, gameinfo.norandomplayerclass && pclass >= 0 ? pclass : pclass + 1); } } @@ -907,10 +910,10 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) if (li->GetValue(0, &sel)) { - players[consoleplayer].userinfo.PlayerClass = sel-1; + players[consoleplayer].userinfo.PlayerClass = gameinfo.norandomplayerclass ? sel : sel-1; PickPlayerClass(); - cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName)); + cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName)); UpdateSkins(); UpdateColorsets(); From f5891dea253e96a9e1b43452be1ee7e6061bc273 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:58:03 +0000 Subject: [PATCH 215/387] - Added time display for alt hud. SVN r4148 (trunk) --- src/g_shared/shared_hud.cpp | 84 +++++++++++++++++++++++++++++++++++++ wadsrc/static/menudef.txt | 16 +++++++ 2 files changed, 100 insertions(+) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 051aae14c..3416bb82d 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -49,6 +49,8 @@ #include "doomstat.h" #include "g_level.h" +#include + #define HUMETA_AltIcon 0x10f000 @@ -68,6 +70,8 @@ CVAR (Bool, hud_showmonsters, true,CVAR_ARCHIVE); // Show monster stats on HUD CVAR (Bool, hud_showitems, false,CVAR_ARCHIVE); // Show item stats on HUD CVAR (Bool, hud_showstats, false, CVAR_ARCHIVE); // for stamina and accuracy. CVAR (Bool, hud_showscore, false, CVAR_ARCHIVE); // for user maintained score +CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD +CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green @@ -816,6 +820,84 @@ static void DrawCoordinates(player_t * CPlayer) DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); } +//--------------------------------------------------------------------------- +// +// Draw in-game time +// +// Check AltHUDTime option value in wadsrc/static/menudef.txt +// for meaning of all display modes +// +//--------------------------------------------------------------------------- + +static void DrawTime() +{ + if (hud_showtime <= 0 || hud_showtime > 9) + { + return; + } + + int hours = 0; + int minutes = 0; + int seconds = 0; + + if (hud_showtime < 8) + { + const int timeTicks = + hud_showtime < 4 + ? level.maptime + : (hud_showtime < 6 + ? level.time + : level.totaltime); + const int timeSeconds = timeTicks / TICRATE; + + hours = timeSeconds / 3600; + minutes = (timeSeconds % 3600) / 60; + seconds = timeSeconds % 60; + } + else + { + time_t now; + time(&now); + + struct tm* timeinfo = localtime(&now); + + if (NULL != timeinfo) + { + hours = timeinfo->tm_hour; + minutes = timeinfo->tm_min; + seconds = timeinfo->tm_sec; + } + } + + const bool showMillis = 1 == hud_showtime; + const bool showSeconds = showMillis || (0 == hud_showtime % 2); + + char timeString[sizeof "HH:MM:SS.MMM"]; + + if (showMillis) + { + const int millis = (level.time % TICRATE) * (1000 / TICRATE); + + mysnprintf(timeString, sizeof(timeString), "%02i:%02i:%02i.%03i", hours, minutes, seconds, millis); + } + else if (showSeconds) + { + mysnprintf(timeString, sizeof(timeString), "%02i:%02i:%02i", hours, minutes, seconds); + } + else + { + mysnprintf(timeString, sizeof(timeString), "%02i:%02i", hours, minutes); + } + + const int characterCount = static_cast( sizeof "HH:MM" - 1 + + (showSeconds ? sizeof ":SS" - 1 : 0) + + (showMillis ? sizeof ".MMM" - 1 : 0) ); + const int width = SmallFont->GetCharWidth('0') * characterCount + 2; // small offset from screen's border + const int height = SmallFont->GetHeight(); + + DrawHudText(SmallFont, hud_timecolor, timeString, hudwidth - width, height, FRACUNIT); +} + //--------------------------------------------------------------------------- // @@ -879,6 +961,8 @@ void DrawHUD() StatusBar->DrawCrosshair(); } if (idmypos) DrawCoordinates(CPlayer); + + DrawTime(); } else { diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index a87932413..915d08405 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -780,6 +780,20 @@ OptionValue "AltHUDScale" 2, "Pixel double" } +OptionValue "AltHUDTime" +{ + 0, "Off" + 1, "Level, milliseconds" + 2, "Level, seconds" + 3, "Level" + 4, "Hub, seconds" + 5, "Hub" + 6, "Total, seconds" + 7, "Total" + 8, "System, seconds" + 9, "System" +} + OptionMenu "AltHUDOptions" { Title "Alternative HUD" @@ -791,6 +805,8 @@ OptionMenu "AltHUDOptions" Option "Show item count", "hud_showitems", "OnOff" Option "Show stamina and accuracy", "hud_showstats", "OnOff" Option "Show berserk", "hud_berserk_health", "OnOff" + Option "Show time", "hud_showtime", "AltHUDTime" + Option "Time color", "hud_timecolor", "TextColors" Slider "Red ammo display below %", "hud_ammo_red", 0, 100, 1, 0 Slider "Yellow ammo display below %", "hud_ammo_yellow", 0, 100, 1, 0 Slider "Red health display below", "hud_health_red", 0, 100, 1, 0 From 2e7ef2e019361e0c9fe128a88b2fca38223b42dd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 19 Feb 2013 02:59:40 +0000 Subject: [PATCH 216/387] - Added Brazilian Portuguese translation. SVN r4149 (trunk) --- wadsrc/static/language.ptb | 1830 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1830 insertions(+) create mode 100644 wadsrc/static/language.ptb diff --git a/wadsrc/static/language.ptb b/wadsrc/static/language.ptb new file mode 100644 index 000000000..3fff46009 --- /dev/null +++ b/wadsrc/static/language.ptb @@ -0,0 +1,1830 @@ +/* Português Brasileiro. Feito por Patryck Padilha de Oliveira */ +/* Não está totalmente completo */ +/* Doom está traduzido 100% */ +/* Chex(R) Quest traduzido 100% */ +/* Heretic 75% traduzido (algumas telas ainda faltam) */ +/* Hexen ainda não traduzido */ +/* Strife totalmente traduzido neste arquivo, certas partes não serão implementadas no ZDoom */ +/* Plutonia Experiment ainda precisa ser traduzido */ +/* Para atualizações visite: */ +/* http://forum.zdoom.org/viewtopic.php?f=34&t=34682 */ +/* Versão 0.97 - 07/12/2012 */ +/* No final das traduções, tentarei adicionar os outros jogos suportados pelo ZDoom */ + +[ptb] + +D_DEVSTR = "Modo de desenvolvimento ATIVADO.\n"; +D_CDROM = "Rodando do CD/DVD-ROM: zdoom.ini em c:\\zdoomdat\n"; +PRESSKEY = "aperte qualquer tecla."; +PRESSYN = "escolha Sim ou Nao"; + +QUITMSG = "deseja mesmo sair?"; +TXT_YES = "Sim"; +TXT_NO = "Nao"; + +// Mensagens de saída DooM 1 +QUITMSG1 = "por favor, nao saia, \nprecisamos mata-los..."; +QUITMSG2 = "vamo nessa, isso ja esta\nficando insuportavel!"; +QUITMSG3 = "eu nao sairia se fosse voce.\nWindows e muito mais chato."; +QUITMSG4 = "entao voce gosta mais do windows\ndo que de mim, certo?"; +QUITMSG5 = "nao va, eu acho que vi algo\nse mexendo naquele canto!"; +QUITMSG6 = "sabe, na proxima vez,\nvoce ja era."; +QUITMSG7 = "va em frente, saia.\nveja se me preocupo."; + +// Mensagens de saída DooM II +QUITMSG8 = " >sair \n >pedindo permissao para sair\n(tem certeza??)"; +QUITMSG9 = "nao va agora, um \num buraco negro lhe espera\n na saida!"; +QUITMSG10 = "saia daqui e volte\npara seus programas chatos."; +QUITMSG11 = "se fosse seu chefe, \nvoce estaria demitido!"; +QUITMSG12 = "OK, pode ir.\nmas pode esquecer sua pontuacao!"; +QUITMSG13 = "va. \nquando voltar, estarei lhe esperando\ncom meu BFG."; +QUITMSG14 = "tens sorte por nao\nlhe dar um premio por pensar\n em sair."; + +// Mensagens de saída Strife +QUITMSG15 = "aonde pensa que vai?!\n e quanto a nos?"; +QUITMSG16 = "interrompendo carnificina....\n tem certeza disso?"; +QUITMSG17 = "mas voce e a nossa\n unica esperanca!"; +QUITMSG18 = "ninguem vai embora assim.\n"; +QUITMSG19 = "pensei que fosse diferente..."; +QUITMSG20 = "OK! tchau para voce tambem!"; +QUITMSG21 = "pode ir.\nmas sabemos seu esconderijo..."; +QUITMSG22 = "hein? pode repetir?\nvoce deseja sair?"; + +// Mensagens de saída Chex +QUITMSG23 = "Nao saia agora, precisamos\nacabar com eles!"; +QUITMSG24 = "Nao desista --- porque\neles nunca desistirao!"; +QUITMSG25 = "Nao va.\nPrecisamos de sua ajuda!"; +QUITMSG26 = "Espero que tudo isso\nso seja fome."; +QUITMSG27 = "Nao va.\nPrecisamos de sua ajuda!"; +QUITMSG28 = "Nao nos abandone!!!"; +QUITMSG29 = "O verdadeiro Chex(R) Warrior\n nunca desistiria!"; + +LOADNET = "impossivel carregar, porque \n esta em partida online!\naperte uma tecla."; +QLOADNET = "impossivel carregar, porque esta online!\n\naperte uma tecla."; +QSAVESPOT = "escolha um slot antes de fazer isso de novo.\n\naperte uma tecla."; +SAVEDEAD = "precisa estar jogando para faze-lo.\n\naperte uma tecla."; +QSPROMPT = "deseja mesmo salvar aqui?\n\n'%s'\n"; +QLPROMPT = "deseja carregar esse jogo?\n\n'%s'\n"; +NEWGAME = "impossivel iniciar um novo jogo\nenquanto se esta online.\n\naperte uma tecla."; +NIGHTMARE = "tem certeza? nem eu mesmo me\nsujeito a jogar nesse modo.\n"; +SWSTRING = "essa e a versao shareware de doom.\nque contem somente o primeiro episodio.\npara continuar, compre a trilogia.\n\naperte uma tecla."; +MSGOFF = "Messagens DESATIVADO"; +MSGON = "Messagens ATIVADO"; +NETEND = "nao pode desligar esse jogo!\n\naperte uma tecla."; +ENDGAME = "tem certeza que deseja fechar esse jogo?\n"; +DOSY = "tem certeza disso?"; +EMPTYSTRING = "V A Z I O"; +GOTARMOR = "Colete equipado."; +GOTMEGA = "Armadura equipada."; +GOTHTHBONUS = "Pegou bonus de vida"; +GOTARMBONUS = "Pegou bonus de protecao (colete)"; +GOTSTIM = "Pegou um kit de primeiros socorros\npequeno."; +GOTMEDINEED = "Pegou um kit de primeiros socorros\n na HORA CERTA!!"; +GOTMEDIKIT = "Pegou um kit de primeiros socorros\ngrande."; +GOTSUPER = "Supercarga!"; +GOTBLUECARD = "Achou a credencial azul."; +GOTYELWCARD = "Achou a credencial amarela."; +GOTREDCARD = "Achou a credencial vermelha equipada."; +GOTBLUESKUL = "Achou o cranio azul."; +GOTYELWSKUL = "Achou o cranio amarelo."; +GOTREDSKUL = "Achou o cranio vermelho."; +GOTINVUL = "Sou invencivel (30 sec)!"; +GOTBERSERK = "Pilulas de força (30 sec)!"; +GOTINVIS = "Invisibilidade (30 sec)"; +GOTSUIT = "Roupa anti-radiacao (1 min)"; +GOTMAP = "Mapa do nivel"; +GOTVISOR = "Oculos de visao noturna (1 min)"; +GOTMSPHERE = "Megaesfera!"; +GOTCLIP = "Pegou um clipe."; +GOTCLIPBOX = "Caixa de municao equipada."; +GOTROCKET = "Foguete equipado."; +GOTROCKBOX = "Caixa de foguetes equipada."; +GOTCELL = "Pack de energia(pequeno) equipada."; +GOTCELLBOX = "Pack de energia(grande) equipada."; +GOTSHELLS = "Cartuchos de espingarda coletada."; +GOTSHELLBOX = "Caixa de cartuchos de espingarda coletada."; +GOTBACKPACK = "Mochila CHEIA de municao coletada!"; +GOTBFG9000 = "BFG9000 equipado. Uau!"; +GOTCHAINGUN = "Metralhadora equipada!"; +GOTCHAINSAW = "A motoserra, enfim!"; +GOTLAUNCHER = "Lanca-foguetes equipada!"; +GOTPLASMA = "Metralhadora de plasma equipada!"; +GOTSHOTGUN = "Espingarda equipada!"; +GOTSHOTGUN2 = "Espingarda de cano duplo equipada!"; +PD_BLUEO = "Precisa de credencial azul para ativar este objeto"; +PD_REDO = "Precisa de credencial vermelha para ativar este objeto"; +PD_YELLOWO = "Precisa de credencial amarela para ativar este objeto"; +PD_BLUEK = "Precisa de credencial azul para ativar esta porta"; +PD_REDK = "Precisa de credencial vermelha para ativar esta porta"; +PD_YELLOWK = "Precisa de credencial amarela para ativar esta porta"; +PD_BLUECO = "Precisa de credencial azul para ativar este objeto"; +PD_REDCO = "Precisa de credencial vermelha para ativar este objeto"; +PD_YELLOWCO = "Precisa de credencial amarela para ativar este objeto"; +PD_BLUESO = "Precisa de cranio azul para ativar este objeto"; +PD_REDSO = "Precisa de cranio vermelho para ativar este objeto"; +PD_YELLOWSO = "Precisa de cranio amarelo para ativar este objeto"; +GGSAVED = "Jogo salvo."; +HUSTR_MSGU = "[Mensagem nao enviada]"; +PICKUP_PISTOL_DROPPED = "Pistola equipada."; +BETA_BONUS1 = "Voce pegou uma adaga demoniaca."; +BETA_BONUS2 = "Voce pegou um skullchest."; +BETA_BONUS3 = "Voce pegou um cetro maligno."; +BETA_BONUS4 = "Voce pegou uma biblia nao sagrada."; + +// Níveis (preferi deixar original por compatibilidade) +HUSTR_E1M1 = "E1M1: Hangar"; +HUSTR_E1M2 = "E1M2: Nuclear Plant"; +HUSTR_E1M3 = "E1M3: Toxin Refinery"; +HUSTR_E1M4 = "E1M4: Command Control"; +HUSTR_E1M5 = "E1M5: Phobos Lab"; +HUSTR_E1M6 = "E1M6: Central Processing"; +HUSTR_E1M7 = "E1M7: Computer Station"; +HUSTR_E1M8 = "E1M8: Phobos Anomaly"; +HUSTR_E1M9 = "E1M9: Military Base"; +HUSTR_E2M1 = "E2M1: Deimos Anomaly"; +HUSTR_E2M2 = "E2M2: Containment Area"; +HUSTR_E2M3 = "E2M3: Refinery"; +HUSTR_E2M4 = "E2M4: Deimos Lab"; +HUSTR_E2M5 = "E2M5: Command Center"; +HUSTR_E2M6 = "E2M6: Halls of the Damned"; +HUSTR_E2M7 = "E2M7: Spawning Vats"; +HUSTR_E2M8 = "E2M8: Tower of Babel"; +HUSTR_E2M9 = "E2M9: Fortress of Mystery"; +HUSTR_E3M1 = "E3M1: Hell Keep"; +HUSTR_E3M2 = "E3M2: Slough of Despair"; +HUSTR_E3M3 = "E3M3: Pandemonium"; +HUSTR_E3M4 = "E3M4: House of Pain"; +HUSTR_E3M5 = "E3M5: Unholy Cathedral"; +HUSTR_E3M6 = "E3M6: Mt. Erebus"; +HUSTR_E3M7 = "E3M7: Limbo"; +HUSTR_E3M8 = "E3M8: Dis"; +HUSTR_E3M9 = "E3M9: Warrens"; +HUSTR_E4M1 = "E4M1: Hell Beneath"; +HUSTR_E4M2 = "E4M2: Perfect Hatred"; +HUSTR_E4M3 = "E4M3: Sever The Wicked"; +HUSTR_E4M4 = "E4M4: Unruly Evil"; +HUSTR_E4M5 = "E4M5: They Will Repent"; +HUSTR_E4M6 = "E4M6: Against Thee Wickedly"; +HUSTR_E4M7 = "E4M7: And Hell Followed"; +HUSTR_E4M8 = "E4M8: Unto The Cruel"; +HUSTR_E4M9 = "E4M9: Fear"; + +HUSTR_1 = "nivel 1: entryway"; +HUSTR_2 = "nivel 2: underhalls"; +HUSTR_3 = "nivel 3: the gantlet"; +HUSTR_4 = "nivel 4: the focus"; +HUSTR_5 = "nivel 5: the waste tunnels"; +HUSTR_6 = "nivel 6: the crusher"; +HUSTR_7 = "nivel 7: dead simple"; +HUSTR_8 = "nivel 8: tricks and traps"; +HUSTR_9 = "nivel 9: the pit"; +HUSTR_10 = "nivel 10: refueling base"; +HUSTR_11 = "nivel 11: 'o' of destruction!"; +HUSTR_12 = "nivel 12: the factory"; +HUSTR_13 = "nivel 13: downtown"; +HUSTR_14 = "nivel 14: the inmost dens"; +HUSTR_15 = "nivel 15: industrial zone"; +HUSTR_16 = "nivel 16: suburbs"; +HUSTR_17 = "nivel 17: tenements"; +HUSTR_18 = "nivel 18: the courtyard"; +HUSTR_19 = "nivel 19: the citadel"; +HUSTR_20 = "nivel 20: gotcha!"; +HUSTR_21 = "nivel 21: nirvana"; +HUSTR_22 = "nivel 22: the catacombs"; +HUSTR_23 = "nivel 23: barrels o' fun"; +HUSTR_24 = "nivel 24: the chasm"; +HUSTR_25 = "nivel 25: bloodfalls"; +HUSTR_26 = "nivel 26: the abandoned mines"; +HUSTR_27 = "nivel 27: monster condo"; +HUSTR_28 = "nivel 28: the spirit world"; +HUSTR_29 = "nivel 29: the living end"; +HUSTR_30 = "nivel 30: icon of sin"; +HUSTR_31 = "nivel 31: wolfenstein"; +HUSTR_32 = "nivel 32: grosse"; + +PHUSTR_1 = "nivel 1: congo"; +PHUSTR_2 = "nivel 2: well of souls"; +PHUSTR_3 = "nivel 3: aztec"; +PHUSTR_4 = "nivel 4: caged"; +PHUSTR_5 = "nivel 5: ghost town"; +PHUSTR_6 = "nivel 6: baron's lair"; +PHUSTR_7 = "nivel 7: caughtyard"; +PHUSTR_8 = "nivel 8: realm"; +PHUSTR_9 = "nivel 9: abattoire"; +PHUSTR_10 = "nivel 10: onslaught"; +PHUSTR_11 = "nivel 11: hunted"; +PHUSTR_12 = "nivel 12: speed"; +PHUSTR_13 = "nivel 13: the crypt"; +PHUSTR_14 = "nivel 14: genesis"; +PHUSTR_15 = "nivel 15: the twilight"; +PHUSTR_16 = "nivel 16: the omen"; +PHUSTR_17 = "nivel 17: compound"; +PHUSTR_18 = "nivel 18: neurosphere"; +PHUSTR_19 = "nivel 19: nme"; +PHUSTR_20 = "nivel 20: the death domain"; +PHUSTR_21 = "nivel 21: slayer"; +PHUSTR_22 = "nivel 22: impossible mission"; +PHUSTR_23 = "nivel 23: tombstone"; +PHUSTR_24 = "nivel 24: the final frontier"; +PHUSTR_25 = "nivel 25: the temple of darkness"; +PHUSTR_26 = "nivel 26: bunker"; +PHUSTR_27 = "nivel 27: anti-christ"; +PHUSTR_28 = "nivel 28: the sewers"; +PHUSTR_29 = "nivel 29: odyssey of noises"; +PHUSTR_30 = "nivel 30: the gateway of hell"; +PHUSTR_31 = "nivel 31: cyberden"; +PHUSTR_32 = "nivel 32: go 2 it"; + +THUSTR_1 = "nivel 1: system control"; +THUSTR_2 = "nivel 2: human bbq"; +THUSTR_3 = "nivel 3: power control"; +THUSTR_4 = "nivel 4: wormhole"; +THUSTR_5 = "nivel 5: hanger"; +THUSTR_6 = "nivel 6: open season"; +THUSTR_7 = "nivel 7: prison"; +THUSTR_8 = "nivel 8: metal"; +THUSTR_9 = "nivel 9: stronghold"; +THUSTR_10 = "nivel 10: redemption"; +THUSTR_11 = "nivel 11: storage facility"; +THUSTR_12 = "nivel 12: crater"; +THUSTR_13 = "nivel 13: nukage processing"; +THUSTR_14 = "nivel 14: steel works"; +THUSTR_15 = "nivel 15: dead zone"; +THUSTR_16 = "nivel 16: deepest reaches"; +THUSTR_17 = "nivel 17: processing area"; +THUSTR_18 = "nivel 18: mill"; +THUSTR_19 = "nivel 19: shipping/respawning"; +THUSTR_20 = "nivel 20: central processing"; +THUSTR_21 = "nivel 21: administration center"; +THUSTR_22 = "nivel 22: habitat"; +THUSTR_23 = "nivel 23: lunar mining project"; +THUSTR_24 = "nivel 24: quarry"; +THUSTR_25 = "nivel 25: baron's den"; +THUSTR_26 = "nivel 26: ballistyx"; +THUSTR_27 = "nivel 27: mount pain"; +THUSTR_28 = "nivel 28: heck"; +THUSTR_29 = "nivel 29: river styx"; +THUSTR_30 = "nivel 30: last call"; +THUSTR_31 = "nivel 31: pharaoh"; +THUSTR_32 = "nivel 32: caribbean"; + +HUSTR_TALKTOSELF1 = "Voce pensa..."; +HUSTR_TALKTOSELF2 = "Tem alguem ai?"; +HUSTR_TALKTOSELF3 = "Nao tem ninguem que possa responder"; +HUSTR_TALKTOSELF4 = "Voce esta ficando louco..."; +HUSTR_TALKTOSELF5 = "Eu juro que vi alguem..."; +HUSTR_MESSAGESENT = "[Mensagem enviada]"; + +AMSTR_FOLLOWON = "Siga-me ATIVADO"; +AMSTR_FOLLOWOFF = "Siga-me DESATIVADO"; +AMSTR_GRIDON = "Area quad. ATIVADO"; +AMSTR_GRIDOFF = "Area quad. DESATIVADO"; +AMSTR_TEXON = "Modo Textura ATIVADO"; +AMSTR_TEXOFF = "Modo Textura DESATIVADO"; +AMSTR_MARKEDSPOT = "Marcado!"; +AMSTR_MARKSCLEARED = "Marcas retiradas."; +STSTR_MUS = "Trocando musica..."; +STSTR_NOMUS = "IMPOSSIVEL"; +STSTR_DQDON = "Modo DEUS ATIVADO"; +STSTR_DQDOFF = "Modo DEUS DESATIVADO"; +STSTR_KFAADDED = "O Pacote completo... Trapaceiro!"; +STSTR_FAADDED = "Precisa de mais municao?"; +STSTR_NCON = "No Clip ATIVADO"; +STSTR_NCOFF = "No Clip DESATIVADO"; +STSTR_BEHOLD = "Escolha um poder:\nForca-s; invulnerabilidade-v; invisibilidade-i\nantiradiacao-r; mapa-a; oculos-l"; +STSTR_BEHOLDX = "Power-up ATIVADO"; +STSTR_CHOPPERS = "... nao enche."; +STSTR_CLEV = "Pulando para...\n"; +TXT_BUDDHAON = "Modo Buddha ATIVADO"; +TXT_BUDDHAOFF = "Modo Buddha DESATIVADO"; +TXT_DEFAULTPICKUPMSG = "Voce pegou um objeto"; + +E1TEXT = + "Apos todo o esforco limpando \n" + "a base da lua, voce deveria ganhar um premio, \n" + "nao deveria? Hein? Cade o maravilhoso \n" + "presente: voltar para casa? \n" + "Parece que este pesadelo so esta comecando. \n" + "\n" + "Cheira como carne podre, mas e a base Deimos, \n" + "eu acho. Parece que estou preso no meio do \n" + "Inferno... \n" + "\n" + "O unico jeito de sair e passando dentro. \n" + "\n" + "Para continuar, escolha o prox. episodio, \n" + "The Shores of Hell e, na sequencia, \n" + "Inferno!\n"; +E2TEXT = + "Voce conseguiu! O gigante cyber-\n" + "demon que comandava a base lunar\n" + "Deimos foi morto, e voce foi o\n" + "triunfante nessa batalha... E agora?\n" + "Voce olha pelo parapeito da base e\n" + "entao ve a assustadora verdade.\n" + "\n" + "A base esta flutuando em cima do\n" + "que parece um portal para o inferno!\n" + "Voce nunca ouviu falar de alguem que\n" + "escapou de la, mas aqueles que voce\n" + "matou se arrependem de ter lhe conhe-\n" + "cido. Voce toma folego e comeca sua jor-\n" + "nada no ultimo episodio de DooM! \n" + " Inferno\n" + "\n" + " "; +E3TEXT = + "O inigualavel spiderdemon que esque-\n" + "matizou a invasao na lua causou tanta\n" + "destruicao e morte que foi enfim derro-\n" + "tado.\n" + "\n" + "Uma passagem secreta abre e voce entra.\n" + "Voce mostrou que inferno nenhum pode\n" + "conte-lo, pelo menos agora acabou.\n" + "Agora esta na hora de voltar para a Terra,\n" + "para enfim descansar.\n" + "Lar doce lar.\n" + "\n" + "Voce imagina o que aconteceu nesse\n" + "meio tempo enquanto voce batalhava\n" + "contra o mal. Espero que nenhum daque-\n" + "les monstros nao tenham vindo junto com\n" + "voce naquela passagem ..."; +E4TEXT = + "O spider mastermind deve ter sido \n" + "mandado junto com sua legiao de monstros\n" + "para os confins do inferno depois dessa\n" + "batalha. sorte sua que voce se manteve\n" + "vivo para fazer de tudo para limpar\n" + "esse mundo de sofrimento de uma forma que\n" + "so um heroi poderia fazer diante de tanto mal.\n" + "\n" + "alias, alguem teria que pagar pelo que\n" + "aconteceu com daisy, seu coelho de estimacao.\n" + "\n" + "Mas agora, voce ve o que aconteceu no\n" + "planeta enquanto estava fora: dor e sangue\n" + "trazido pelos demonios que estao a solta nas\n" + "cidades. agora e hora de acabar com isso!\n" + "voce recarrega sua pistola e continua seu arduo\n" + "trabalho: acabar com esses monstros!"; +C1TEXT = + "VOCE FOI FUNDO DENTRO DO PORTO\n" + "ESTELAR, MAS ALGO ESTA ERRADO. OS\n" + "MONSTROS TROUXERAM SUA REALIDADE\n" + "COM ELES, E A TECNOLOGIA AQUI CONTIDA\n" + "ESTA SENDO MODIFICADA COM SUA PRESENCA.\n" + "\n" + "ADIANTE, VOCE VE UM POSTO DE GUARDA,\n" + "UMA ZONA FORTIFICADA. SE VOCE PASSAR ALI,\n" + "PODERA ENTRAR DENTRO DO CORACAO DA\n" + "BASE ESTELAR E DESATIVAR O DISPOSITIVO\n" + "QUE MANTEM O QUE SOBROU DA POPULACAO\n" + "DA TERRA REFEM."; +C2TEXT = + "VOCE CONSEGUIU! APOS ESSA VITORIA VOCE SALVA\n" + "A RACA HUMANA DA DIZIMACAO, FAZENDO COM QUE\n" + "ELES EVACUASSEM A TERRA DE VEZ. AGORA VOCE\n" + "E O UNICO HUMANO NA FACE DA TERRA.\n" + "MUTACOES CANIBAIS, ALIENS CARNIVOROS\n" + "E MAUS ESPIRITOS SAO SEUS VIZINHOS.\n" + "VOCE SENTA E ESPERA PELA MORTE, FELIZ\n" + "POR TER SALVADO A POPULACAO.\n" + "\n" + "MAS ELES MANDAM UMA MENSAGEM DO ESPACO:\n" + "\"SENSORES LOCALIZARAM O FOCO DA INVASAO\n" + "SE VOCE FOR LA, PODERA BLOQUEAR SUA ENTRADA.\n" + "A BASE ALIEN FICA NO CORACAO DE SUA CIDADE\n" + "NATAL, NAO MUITO LONGE DO PORTO ESTELAR.\" \n" + "LENTAMENTE E SENTINDO MUITA DOR, VOCE SE\n" + "LEVANTA E DECIDE CONTINUAR A LIMPEZA.\n"; +C3TEXT = + "VOCE CONSEGUE CHEGAR NO CORACAO DA CIDADE,\n" + "CERCADA PELOS CADAVERES DE SEUS INIMIGOS.\n" + "VOCE NAO VE NENHUM JEITO DE DESTRUIR A ENTRADA\n" + "POR ESTE LADO, ENTAO VOCE CERRA OS DENTES\n" + "E MERGULHA ATRAVES DELA.\n" + "\n" + "DEVE HAVER UM JEITO DE FECHA-LA DO OUTRO LADO.\n" + "PRA QUE SE PREOCUPAR SE TEREI QUE ATRAVESSAR O\n" + "INFERNO PARA FECHA-LA?"; +C4TEXT = + "A HORRENDA VISTA DO MAIOR DEMONIO QUE\n" + "VOCE JA VIU DESMORONA NA SUA FRENTE\n" + "DEPOIS DE VOCE LANCAR ALGUNS FOGUETES\n" + "DENTRO DE SEU CEREBRO EXPOSTO. ELE\n" + "MURCHA E MORRE, SEUS MEMBROS ESTAO\n" + "DEVASTANDO MILHAS E MILHAS DA\n" + "SUPERFICIE DO INFERNO.\n" + "\n" + "VOCE CONSEGUIU. A INVASAO ACABOU.\n" + "A TERRA ESTA SALVA. O INFERNO DESTRUIDO.\n" + "VOCE IMAGINA PARA ONDE OS MAUS IRAO\n" + "QUANDO MORREREM AGORA. VOCE SECA O\n" + "SUOR DE SUA TESTA E COMECA A LONGA\n" + "JORNADA DE VOLTA PRA CASA. E PENSA EM\n" + "RECONSTRUIR A TERRA PARA SER MAIS\n" + "DIVERTIDA DO QUE ANTES.\n"; +C5TEXT = + "MEUS PARABENS, VOCE ACHOU O NIVEL SECRETO!\n" + "PARECE TER SIDO CONSTRUIDO POR HUNANOS,\n" + "EM VEZ DE DEMONIOS. VOCE IMAGINA O QUE\n" + "DEVE HABITAR OS CORREDORES DESTE LUGAR.\n"; +C6TEXT = + "MEUS PARABENS, DE NOVO! VOCE ACHOU\n" + "OUTRO NIVEL SECRETO. QUERO VER PASSAR\n" + "ESSE AGORA!\n"; + +// Plutonia and TNT intermission screens (ainda não traduzido) +P1TEXT = + "Voce vangloria sua vitoria em cima da carcaca\n" + "do Guardiao. Apos mata-lo, voce arranca o \n" + "Acelerador das garras fedorentas do Inferno.\n" + "Voce relaxa e olha em volta da sala. Droga!\n" + "Deveria ter pelo menos mais um prototipo\n" + "funcionando, mas voce nao o acha em lugar\n" + "nenhum. Os demonios devem ter levado-o\n" + "\n" + "Voce deve achar o prototipo, ou todos os\n" + "seus esforcos serao em vao. Mexa-se,\n" + "lute, mate. Ah, se mantenha vivo tambem.\n"; +P2TEXT = + "Nem o labirinto mortal do Arch-Vile pode\n" + "para-lo, e agora voce tem o prototipo do\n" + "Acelerador, o qual está com pouca energia\n" + "e logo se desativara permanentemente.\n" + "\n" + "Voce e bom nesse tipo de coisa."; +P3TEXT = + "Voce batalhou e fez de tudo para chegar\n" + "no coracao da colmeia demoniaca. Esta na\n" + "hora de destruir o protetor do portao, cuja\n" + "prole esta vindo aos montes para a Terra.\n" + "E, ele e mau, mas voce sabe quem e pior!\n" + "\n" + "Sorrindo maldosamente, voce checa seu\n" + "equipamento e se prepara para dar ao\n" + "bastardo um pequeno inferno de sua propria\n" + "criacao!"; +P4TEXT = + "A face do protetor do portao esta espalhada\n" + "por todo o lugar. Seu corpo entra em colapso,\n" + "um portao inverso se forma e engole os restos\n" + "do ultimo Acelerador, sem mencionar os poucos\n" + "demonios que restaram. Voce conseguiu.\n" + "O Inferno voltou ao seu lugar, para os vivos\n" + "viverem suas vidas. Lembre-se de pedir aos\n" + "seus netos para colocarem um lanca-foguete\n" + "em seu caixao. Se for para o Inferno, vai precisar\n" + "para poder terminar o que comecou......\n"; +P5TEXT = + "Voce achou o segundo nivel mais dificil que temos.\n" + "Espero que tenha salvo o jogo uns dois niveis atras.\n" + "Para veteranos apenas."; +P6TEXT = + "Estava pensando qual ERA o nivel mais dificil\n" + "que preparamos? Agora voce sabe.\n" + "Ninguem sai vivo."; +T1TEXT = + "You've fought your way out of the infested\n" + "experimental labs. It seems that UAC has\n" + "once again gulped it down. With their\n" + "high turnover, it must be hard for poor\n" + "old UAC to buy corporate health insurance\n" + "nowadays..\n" + "\n" + "Ahead lies the military complex, now\n" + "swarming with diseased horrors hot to get\n" + "their teeth into you. With luck, the\n" + "complex still has some warlike ordnance\n" + "laying around."; +T2TEXT = + "You hear the grinding of heavy machinery\n" + "ahead. You sure hope they're not stamping\n" + "out new hellspawn, but you're ready to\n" + "ream out a whole herd if you have to.\n" + "They might be planning a blood feast, but\n" + "you feel about as mean as two thousand\n" + "maniacs packed into one mad killer.\n" + "\n" + "You don't plan to go down easy."; +T3TEXT = + "The vista opening ahead looks real damn\n" + "familiar. Smells familiar, too -- like\n" + "fried excrement. You didn't like this\n" + "place before, and you sure as hell ain't\n" + "planning to like it now. The more you\n" + "brood on it, the madder you get.\n" + "Hefting your gun, an evil grin trickles\n" + "onto your face. Time to take some names."; +T4TEXT = + "Suddenly, all is silent, from one horizon\n" + "to the other. The agonizing echo of Hell\n" + "fades away, the nightmare sky turns to\n" + "blue, the heaps of monster corpses start \n" + "to evaporate along with the evil stench \n" + "that filled the air. Jeeze, maybe you've\n" + "done it. Have you really won?\n" + "\n" + "Something rumbles in the distance.\n" + "A blue light begins to glow inside the\n" + "ruined skull of the demon-spitter."; +T5TEXT = + "What now? Looks totally different. Kind\n" + "of like King Tut's condo. Well,\n" + "whatever's here can't be any worse\n" + "than usual. Can it? Or maybe it's best\n" + "to let sleeping gods lie.."; +T6TEXT = + "Time for a vacation. You've burst the\n" + "bowels of hell and by golly you're ready\n" + "for a break. You mutter to yourself,\n" + "Maybe someone else can kick Hell's ass\n" + "next time around. Ahead lies a quiet town,\n" + "with peaceful flowing water, quaint\n" + "buildings, and presumably no Hellspawn.\n" + "\n" + "As you step off the transport, you hear\n" + "the stomp of a cyberdemon's iron shoe."; + +// Lista de personagens (ordem deve ser seguida a risca) +CC_ZOMBIE = "ZOMBIEMAN"; +CC_SHOTGUN = "SHOTGUN GUY"; +CC_HEAVY = "HEAVY WEAPON DUDE"; +CC_IMP = "IMP"; +CC_DEMON = "DEMON"; +CC_LOST = "LOST SOUL"; +CC_CACO = "CACODEMON"; +CC_HELL = "HELL KNIGHT"; +CC_BARON = "BARON OF HELL"; +CC_ARACH = "ARACHNOTRON"; +CC_PAIN = "PAIN ELEMENTAL"; +CC_REVEN = "REVENANT"; +CC_MANCU = "MANCUBUS"; +CC_ARCH = "ARCH-VILE"; +CC_SPIDER = "THE SPIDER MASTERMIND"; +CC_CYBER = "THE CYBERDEMON"; +CC_HERO = "OUR HERO"; + +// New strings from BOOM +PD_BLUEC = "Precisa de uma credencial azul para abrir a porta"; +PD_REDC = "Precisa de uma credencial vermelha para abrir a porta"; +PD_YELLOWC = "Precisa de uma credencial amarela para abrir a porta"; +PD_BLUES = "Precisa de um cranio azul para abrir a porta"; +PD_REDS = "Precisa de um cranio vermelho para abrir a porta"; +PD_YELLOWS = "Precisa de um cranio amarelo para abrir a porta"; +PD_ANY = "Qualquer chave abre a porta"; +PD_ANYOBJ = "Qualquer chave ativa este objeto"; +PD_ALL3 = "Precisa das 3 chaves para abrir a porta"; +PD_ALL3O = "Precisa das 3 chaves para ativar este objeto"; +PD_ALL6 = "Precisa das 6 chaves para abrir a porta"; +PD_ALL6O = "Precisa das 6 chaves para ativar este objeto"; +PD_ALLKEYS = "Precisa de todas as chaves"; + +// MBF (BOOM?) narration backgrounds +bgflatE1 = "FLOOR4_8"; +bgflatE2 = "SFLR6_1"; +bgflatE3 = "MFLR8_4"; +bgflatE4 = "MFLR8_3"; +bgflat06 = "SLIME16"; +bgflat11 = "RROCK14"; +bgflat20 = "RROCK07"; +bgflat30 = "RROCK17"; +bgflat15 = "RROCK13"; +bgflat31 = "RROCK19"; +bgcastcall = "BOSSBACK"; + +// Mensagens de fim de partida online +TXT_FRAGLIMIT = "Pontuacao atingida."; +TXT_TIMELIMIT = "Tempo atingido."; + +// Mensagens de pontos cumulativos +SPREEKILLSELF = "%o estava indo bem ate se matar!"; +SPREEOVER = "A matanca de %o foi interrompida por %k"; +SPREE5 = "%k esta indo bem!"; +SPREE10 = "%k continua indo bem!"; +SPREE15 = "%k esta dominando!"; +SPREE20 = "%k nao se cansa por nada!"; +SPREE25 = "%k parece profissional!"; + +// Mensagens de COMBO +MULTI2 = "COMBO 2X!"; +MULTI3 = "COMBO 3X!"; +MULTI4 = "COMBO 4X!"; +MULTI5 = "Santa Mae do Ceu!!!"; + +// Obituario +// Primeiro suicidios, depois as mortes +OB_SUICIDE = "%o suicidou-se."; +OB_FALLING = "%o caiu."; +OB_CRUSH = "%o foi esmagado."; +OB_EXIT = "%o tentou sair."; +OB_WATER = "%o nao sabe nadar."; +OB_SLIME = "%o se entoxicou."; +OB_LAVA = "%o derreteu."; +OB_BARREL = "%o explodiu."; +OB_SPLASH = "%o parou no lugar errado."; +OB_R_SPLASH = "%o deveria ter se afastado."; +OB_ROCKET = "%o deveria ter se afastado."; +OB_KILLEDSELF = "%o se matou."; + +OB_VOODOO = "%o morreu pelo poder do voodoo."; +OB_STEALTHBABY = "%o achou que viu um arachnotron."; +OB_STEALTHVILE = "%o achou que viu um archvile."; +OB_STEALTHBARON = "%o achou que viu um Baron of Hell."; +OB_STEALTHCACO = "%o achou que viu um cacodemon."; +OB_STEALTHCHAINGUY = "%o achou que viu um chaingunner."; +OB_STEALTHDEMON = "%o achou que viu um a demon."; +OB_STEALTHKNIGHT = "%o achou que viu um Hell Knight."; +OB_STEALTHIMP = "%o achou que viu um imp."; +OB_STEALTHFATSO = "%o achou que viu um mancubus."; +OB_STEALTHUNDEAD = "%o achou que viu um revenant."; +OB_STEALTHSHOTGUY = "%o achou que viu um sergeant."; +OB_STEALTHZOMBIE = "%o achou que viu um zombieman."; +OB_UNDEADHIT = "%o foi socado por um revenant."; +OB_IMPHIT = "%o foi dilacerado por um imp."; +OB_CACOHIT = "%o chegu muito perto de um cacodemon."; +OB_DEMONHIT = "%o foi mordido por um demon."; +OB_SPECTREHIT = "%o foi comido vivo por um spectre."; +OB_BARONHIT = "%o foi cortado por um Baron of Hell."; +OB_KNIGHTHIT = "%o foi estripado por um Hell Knight."; +OB_ZOMBIE = "%o foi morto por um zombieman."; +OB_SHOTGUY = "%o levou um tiro de um sergeant."; +OB_VILE = "%o foi incinerado pelo archvile."; +OB_UNDEAD = "%o nao conseguiu desviar da bola de\nfogo do revenant."; +OB_FATSO = "%o foi esmagado por um mancubus."; +OB_CHAINGUY = "%o foi perfurado por um chaingunner."; +OB_SKULL = "%o se assustou com um lost soul."; +OB_IMP = "%o foi queimado por um imp."; +OB_CACO = "%o foi golpeado por um cacodemon."; +OB_BARON = "%o foi ferido por um Baron of Hell."; +OB_KNIGHT = "%o foi espalmado por um Hell Knight."; +OB_SPIDER = "%o se ajoelhou em frente do spider demon."; +OB_BABY = "%o foi pego por um arachnotron."; +OB_CYBORG = "%o foi arrebentado pelo cyberdemon."; +OB_WOLFSS = "%o viu um Nazi."; +OB_DOG = "%o foi atacado por um cachorro."; + +OB_CHICKEN = "%o foi cutucado ate a morte."; +OB_BEAST = "%o foi carbonizado por um weredragon."; +OB_CLINK = "%o foi cortado por um sabreclaw."; +OB_DSPARIL1 = "%o foi escaldado pela serpente de D'Sparil."; +OB_DSPARIL1HIT = "%o foi mastigado pela serpente de D'Sparil."; +OB_DSPARIL2 = "%o nao foi pareo para D'Sparil."; +OB_DSPARIL2HIT = "%o foi morto por D'Sparil."; +OB_HERETICIMP = "%o foi cicatrizado por um gargoyle."; +OB_HERETICIMPHIT = "%o foi cortado por um gargoyle."; +OB_IRONLICH = "%o foi devastado por um ironlich."; +OB_IRONLICHHIT = "%o cheou muito perto de um ironlich."; +OB_BONEKNIGHT = "%o foi decepado por um undead warrior."; +OB_BONEKNIGHTHIT = "%o foi picotado por um undead warrior."; +OB_MUMMY = "%o foi esmagado por um golem."; +OB_MUMMYLEADER = "%o agonizou na frente de um nitrogolem."; +OB_SNAKE = "%o foi sacudido por um ophidian."; +OB_WIZARD = "%o foi amaldicoado por um wizard."; +OB_WIZARDHIT = "%o foi apalpado por um wizard."; + +//Hexen Obituaries (Ainda não traduzido) +OB_FIREDEMON = "%o tasted an Afrit's fire."; +OB_DEMON1 = "%o was scalded by a Serpent."; +OB_DEMON2 = "%o was poisoned by a Serpent."; +OB_ETTIN = "%o was mashed by an Ettin."; +OB_CENTAUR = "%o was cut up by a Centaur."; +OB_SLAUGHTAURHIT = "%o was cut up by a Slaughtaur."; +OB_SLAUGHTAUR = "%o was struck down by a Slaughtaur's fireball."; +OB_BISHOP = "%o succumbed to a Bishop's dark power."; +OB_ICEGUY = "%o was frozen solid by a Wendigo."; +OB_SERPENTHIT = "%o was mauled by a Stalker."; +OB_SERPENT = "%o was melted by a Stalker."; +OB_WRAITH = "%o was charred by a Reiver."; +OB_WRAITHHIT = "%o had %p life stolen by a Reiver."; +OB_DRAGON = "%o was incinerated by the Death Wyvern."; +OB_KORAX = "%o was swept from the board by Korax."; +OB_FBOSS = "%o was slain by Zedek."; +OB_MBOSS = "%o couldn't absorb Menelkir's Mana."; +OB_CBOSS = "%o was baptized by Traductus."; +OB_HERESIARCH = "%o had %p bones rolled by the Heresiarch."; + +//Strife obituaries (ainda não traduzido) +OB_ACOLYTE = "%o was zealously shot down by an Acolyte."; +OB_MACIL = "%o should have never rebelled against Macil."; +OB_REBEL = "%o was gunned down by a Rebel."; +OB_BEGGAR = "%o was beaten to death by the poor."; +OB_PEASANT = "%o should have never picked a fight with a civilian."; +OB_ALIENSPECTE = "%o was struck down by the Spectre."; +OB_ENTITY = "%o felt the wrath of The One God."; +OB_LOREMASTER = "%o couldn't escape from the Lore Master's grasp."; +OB_PROGRAMMER = "%o was deleted by the Programmer."; +OB_STFBISHOP = "%o was blown away by the Bishop."; +OB_SENTINEL = "%o was shot down by a Sentinel."; +OB_CRUSADER = "%o was swept away by a Crusader."; +OB_INQUISITOR = "%o was sentenced by an Inquisitor."; +OB_STALKER = "%o was bugged by a Stalker."; +OB_TURRET = "%o triggered the automatic defenses."; +OB_TEMPLARHIT = "%o was clawed by a Templar."; +OB_TEMPLAR = "%o was vaporized by a Templar."; +OB_REAVERHIT = "%o was sliced open by a Reaver."; +OB_REAVER = "%o was shot down by a Reaver."; +OB_COMMONUS = "%o foi eslameado por um flemoid."; + +// Chex obituaries +OB_BIPEDICUS = "%o foi eslameado por um bipedicus."; +OB_BIPEDICUS2 = "%o foi eslameado por um armored bipedicus."; +OB_CYCLOPTIS = "%o foi eslameado por um cycloptis."; +OB_SUPERCYCLOPTIS = "%o foi eslameado por um super cycloptis."; +OB_FLEMBRANE = "%o foi derrotado pela Flembrane."; +OB_STRIDICUS = "%o foi eslameado por um stridicus."; +OB_LARVA = "%o foi eslameado por uma larva."; +OB_QUADRUMPUS = "%o foi eslameado por um quadrumpus."; +OB_MAXIMUS = "%o foi derrotado por um Maximus."; +// Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde você o baixou +_MAXIMUS = "00"; +OB_FLEMMINE = "%o foi eslameado por um Flem mine."; +OB_SNOTFOLUS = "%o foi derrotado pelo Lord Snotfolus."; + +OB_MPFIST = "%k fez justica com as proprias maos, na cara de %o."; +OB_MPCHAINSAW = "%k usou o poder da motoserra para abrir %o."; +OB_MPPISTOL = "%o foi morto pela pistola de %k."; +OB_MPSHOTGUN = "%o foi morto pela espingarda de %k."; +OB_MPSSHOTGUN = "%o foi morto pela espingarda de cano duplo de %k."; +OB_MPCHAINGUN = "%o foi massacrado pela metralhadora de %k."; +OB_MPROCKET = "%o nao viu o foguete de %k."; +OB_MPR_SPLASH = "%o quase escapou do foguete de %k. Quase..."; +OB_MPPLASMARIFLE = "%o foi torrado pelo rifle de plasma de %k."; +OB_MPBFG_BOOM = "%o foi pego pelo BFG de %k."; +OB_MPBFG_SPLASH = "Ninguem se esconde do BFG de %k, nem mesmo %o."; +OB_MPTELEFRAG = "%o foi "telefragged" por %k."; +OB_RAILGUN = "%o was railed by %k."; +OB_MPBFG_MBF = "%o foi arrebentado pelo BFG de %k."; + +OB_MPSTAFF = "%o levou uma sova do bastão de %k."; +OB_MPGAUNTLETS = "%o tomou um choque das luvas de %k."; +OB_MPGOLDWAND = "%o acenou para o bastao magico de %k."; +OB_MPCROSSBOW = "%o foi esmigalhado pela besta magica de %k."; +OB_MPBLASTER = "%o sentiu o poder da garra de dragao de %k."; +OB_MPSKULLROD = "%o foi mandado bem pra baixo pelo bastao do inferno de %k."; +OB_MPPHOENIXROD = "%o virou cinzas com o bastao da fenix de %k."; +OB_MPMACE = "%o saiu pulando apos ver a clava de fogo de %k."; + +OB_MPPSTAFF = "%o tomou um tapa do bastao de %k."; +OB_MPPGAUNTLETS = "%o sangrou nas luvas de %k."; +OB_MPPGOLDWAND = "%o foi massacrado pelo bastao magico de %k."; +OB_MPPCROSSBOW = "%o foi flechado pela besta magica de %k."; +OB_MPPBLASTER = "%o foi cortado pela garra de dragao de %k."; +OB_MPPSKULLROD = "%k usou seu bastao do inferno para banir %o."; +OB_MPPPHOENIXROD = "%o foi queimado pelo bastao da fenix de %k."; +OB_MPPMACE = "%o foi esmagado pela clava de %k."; + +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 foi pego pela faca de %k."; +OB_MPELECTRICBOLT = "%o recebeu alguns choques de %k."; +OB_MPPOISONBOLT = "%o recebeu uma dose letal da ira de %k."; +OB_MPASSAULTGUN = "%o virou uma peneira diante da metralhadora de %k."; +OB_MPMINIMISSILELAUNCHER = "%o engoliu misseis de %k."; +OB_MPSTRIFEGRENADE = "%o foi pego pelas granadas de %k."; +OB_MPPHOSPHOROUSGRENADE = "%o nao fugiu do fogo causado pelas granadas PH de %k."; +OB_MPFLAMETHROWER = "%o virou churrasco por causa de %k."; +OB_MPMAULER = "%o foi vaporizado por %k."; +OB_MPSIGIL = "%o sentiu o poder de %k:SIGIL."; + +// Same as OB_MPTELEFRAG, but shown when a monster telefrags you +OB_MONTELEFRAG = "%o foi "telefragged" por um monstro."; + +OB_DEFAULT = "%o morreu."; +OB_MPDEFAULT = "%o foi morto por %k."; +OB_FRIENDLY1 = "%k e cego."; +OB_FRIENDLY2 = "%k pensa que sabe o que faz."; +OB_FRIENDLY3 = "%k errou o tiro."; +OB_FRIENDLY4 = "%k perde outro ponto."; + +SAVEGAMENAME = "zdoomsv"; +STARTUP1 = ""; +STARTUP2 = ""; +STARTUP3 = ""; +STARTUP4 = ""; +STARTUP5 = ""; + + +// Item tags: Doom weapons +FIST ="Soco Ingles"; +TAG_CHAINSAW = "Motoserra"; +TAG_PISTOL = "Pistola"; +TAG_SHOTGUN = "Espingarda"; +TAG_SUPERSHOTGUN = "Espingarda de cano duplo"; +TAG_CHAINGUN = "Metralhadora"; +TAG_ROCKETLAUNCHER = "Lanca-foguetes"; +TAG_PLASMARIFLE = "Rifle de Plasma"; +TAG_BFG9000 = "O BFG 9000"; + +// Item tags: Heretic weapons +TAG_STAFF = "Bastao"; +TAG_GAUNTLETS = "Luvas do Necromancer"; +TAG_GOLDWAND = "Bastao magico"; +TAG_CROSSBOW = "Besta magica"; +TAG_BLASTER = "Garras de dragao"; +TAG_SKULLROD = "Bastao do inferno"; +TAG_PHOENIXROD = "Bastao da Fenix"; +TAG_MACE = "Clava de fogo"; + +// Item tags: Heretic artifacts +TAG_ARTIEGG = "Ovo mutante"; +TAG_ARTIFIREBOMB = "Bomba-relogio dos Antigos"; +TAG_ARTIFLY = "Asas de ira"; +TAG_ARTIHEALTH = "Frasco de quartzo"; +TAG_ARTIINVISIBILITY = "Esfera negra"; +TAG_ARTIINVULNERABILITY = "Anel da invencibilidade"; +TAG_ARTISUPERHEALTH = "Urna mistica"; +TAG_ARTITELEPORT = "Dispositivo do caos"; +TAG_ARTITOMEOFPOWER = "Livro do poder"; +TAG_ARTITORCH = "Tocha"; + +// 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 = "Faca"; +TAG_STRIFECROSSBOW1 = "Besta"; +TAG_STRIFECROSSBOW2 = "Besta"; +TAG_ASSAULTGUN = "Metralhadora"; +TAG_MMLAUNCHER = "Mini Lanca-misseis"; +TAG_FLAMER = "Lanca-chamas"; +TAG_MAULER1 = "Mauler"; +TAG_MAULER2 = "Mauler"; +TAG_GLAUNCHER1 = "Lanca-granadas"; +TAG_GLAUNCHER2 = "Lanca-granadas"; +TAG_SIGIL = "SIGIL"; + +// Item tags: Strife artifacts +TAG_COIN = "moeda(s)"; +TAG_MEDPATCH = "Primeiros socorros (pequeno)"; +TAG_MEDICALKIT = "Primeiros socorros (medio)"; +TAG_SURGERYKIT = "Primeiros socorros (grande)"; // "full_health" in the Teaser +TAG_BELDINSRING = "Anel"; +TAG_OFFERINGCHALICE = "Calice de oferenda"; +TAG_EAR = "Orelha"; +TAG_BROKENCOUPLING = "Acoplador de energia quebrado"; +TAG_SHADOWARMOR = "Armadura das sombras"; +TAG_ENVSUIT = "Roupa anti-radiacao"; +TAG_GUARDUNIFORM = "Uniforme - Guarda"; +TAG_OFFICERSUNIFORM = "Uniforme - Oficial"; +TAG_FTHROWERPARTS = "Partes do lanca-chamas"; +TAG_REPORT = "Relatorio"; +TAG_INFO = "Informacao"; +TAG_TARGETER = "Targeter"; +TAG_COMMUNICATOR = "Transmissor"; +TAG_DEGNINORE = "Minerio Degnin"; +TAG_GUNTRAINING = "Precisao"; +TAG_HEALTHTRAINING = "Forca"; +TAG_SCANNER = "Scanner"; +TAG_PRISONPASS = "Credencial - Prisao"; +TAG_ALARM = "Alarme"; +TAG_AMMOFILLUP = "Municao"; +TAG_HEALTHFILLUP = "Saude"; +TAG_TELEPORTERBEACON = "Sinalizador para teletransporte"; +TAG_METALARMOR = "Armadura de metal"; +TAG_LEATHER = "Armadura leve"; +TAG_HEGRENADES = "Municao - Granadas HE"; +TAG_PHGRENADES = "Municao - Granadas PH"; // "Fire-Grenade_Rounds" in the Teaser +TAG_CLIPOFBULLETS = "Clipe de balas"; // "bullets" in the Teaser +TAG_BOXOFBULLETS = "Caixa de balas"; +TAG_MINIMISSILES = "Misseis"; //"rocket" in the Teaser +TAG_CRATEOFMISSILES = "Caixa de Misseis"; //"box_of_rockets" in the Teaser +TAG_ENERGYPOD = "Energia (pequeno)"; +TAG_ENERGYPACK = "Energia (grande)"; +TAG_POISONBOLTS = "Flechas (veneno)"; // "poison_arrows" in the Teaser +TAG_ELECTRICBOLTS = "Flechas (eletricas)"; // "electric_arrows" in the Teaser +TAG_AMMOSATCHEL = "Pacote de municao"; // "Back_pack" in the Teaser + +// Item tags: Strife keys +TAG_BASEKEY = "Chave da Base"; +TAG_GOVSKEY = "Chave do Governador"; // "Rebel_Key" in the Teaser +TAG_PASSCARD = "Cartao de passe"; +TAG_IDBADGE = "Distintivo de Identificacao"; +TAG_PRISONKEY = "Chave da prisao"; +TAG_SEVEREDHAND = "Mao"; +TAG_POWER1KEY = "Chave Power1"; +TAG_POWER2KEY = "Chave Power2"; +TAG_POWER3KEY = "Chave Power3"; +TAG_GOLDKEY = "Chave de ouro"; +TAG_IDCARD = "Cartao de Identificacao"; +TAG_SILVERKEY = "Chave de prata"; +TAG_ORACLEKEY = "Chave do Oraculo"; +TAG_MILITARYID = "ID do militar"; +TAG_ORDERKEY = "Chave da Ordem"; +TAG_WAREHOUSEKEY = "Chave do barracao"; +TAG_BRASSKEY = "Chave de bronze"; +TAG_REDCRYSTALKEY = "Chave - Cristal vermelho"; +TAG_BLUECRYSTALKEY = "Chave - Cristal azul"; +TAG_CHAPELKEY = "Chave da capela"; +TAG_CATACOMBKEY = "Chave da catatumba"; // "Tunnel_Key" in the Teaser +TAG_SECURITYKEY = "Chave de seguranca"; +TAG_COREKEY = "Chave principal"; // "New_Key1" in the Teaser +TAG_MAULERKEY = "Chave - Mauler"; // "New_Key2" in the Teaser +TAG_FACTORYKEY = "Chave da fabrica"; // "New_Key3" in the Teaser +TAG_MINEKEY = "Chave da mina"; // "New_Key4" in the Teaser +TAG_NEWKEY5 = "Chave Nova5"; +TAG_ORACLEPASS = "Passe do Oraculo"; + +// Item tags: misc Strife stuff +TAG_10GOLD = "10 moedas"; +TAG_25GOLD = "25 moedas"; +TAG_50GOLD = "50 moedas"; +TAG_300GOLD = "sortudo! 300 moedas"; +TAG_QUEST4 = "quest4"; +TAG_QUEST5 = "quest5"; +TAG_QUEST6 = "quest6"; + +// Item tags: Strife NPCs +TAG_ACOLYTE = "ACOLYTE"; +TAG_ARMORER = "Armeiro"; +TAG_BARKEEP = "Garcom de bar"; +TAG_BEGGAR = "Pedinte"; +TAG_MACIL1 = "MACIL"; +TAG_MACIL2 = "MACIL"; +TAG_MEDIC = "Medico"; +TAG_ORACLE = "Oraculo"; +TAG_PRIEST = "PRIEST"; +TAG_RATBUDDY = "rat buddy"; +TAG_REBEL = "Rebelde"; +TAG_TEMPLAR = "TEMPLAR"; +TAG_WEAPONSMITH = "Ferreiro"; + +// Item tags: Chex weapons +TAG_SPOON = "Colher"; +TAG_SPORK = "Super garfo"; +TAG_MINIZORCHER = "Mini Zorcher"; +TAG_LARGEZORCHER = "Zorcher grande"; +TAG_SUPERLARGEZORCHER = "Super Zorcher"; +TAG_RAPIDZORCHER = "Zorcher automatico"; +TAG_ZORCHPROPULSOR = "Propulsor Zorch"; +TAG_PHASINGZORCHER = "Mega Zorcher"; +TAG_LAZDEVICE = "LAZ Device"; + +// Heretic strings (ainda não traduzida) +HE1TEXT = + "with the destruction of the iron\n" + "liches and their minions, the last\n" + "of the undead are cleared from this\n" + "plane of existence.\n\n" + "those creatures had to come from\n" + "somewhere, though, and you have the\n" + "sneaky suspicion that the fiery\n" + "portal of hell's maw opens onto\n" + "their home dimension.\n\n" + "to make sure that more undead\n" + "(or even worse things) don't come\n" + "through, you'll have to seal hell's\n" + "maw from the other side. of course\n" + "this means you may get stuck in a\n" + "very unfriendly world, but no one\n" + "ever said being a Heretic was easy!"; +HE2TEXT = + "the mighty maulotaurs have proved\n" + "to be no match for you, and as\n" + "their steaming corpses slide to the\n" + "ground you feel a sense of grim\n" + "satisfaction that they have been\n" + "destroyed.\n\n" + "the gateways which they guarded\n" + "have opened, revealing what you\n" + "hope is the way home. but as you\n" + "step through, mocking laughter\n" + "rings in your ears.\n\n" + "was some other force controlling\n" + "the maulotaurs? could there be even\n" + "more horrific beings through this\n" + "gate? the sweep of a crystal dome\n" + "overhead where the sky should be is\n" + "certainly not a good sign...."; +HE3TEXT = + "the death of d'sparil has loosed\n" + "the magical bonds holding his\n" + "creatures on this plane, their\n" + "dying screams overwhelming his own\n" + "cries of agony.\n\n" + "your oath of vengeance fulfilled,\n" + "you enter the portal to your own\n" + "world, mere moments before the dome\n" + "shatters into a million pieces.\n\n" + "but if d'sparil's power is broken\n" + "forever, why don't you feel safe?\n" + "was it that last shout just before\n" + "his death, the one that sounded\n" + "like a curse? or a summoning? you\n" + "can't really be sure, but it might\n" + "just have been a scream.\n\n" + "then again, what about the other\n" + "serpent riders?"; +HE4TEXT = + "you thought you would return to your\n" + "own world after d'sparil died, but\n" + "his final act banished you to his\n" + "own plane. here you entered the\n" + "shattered remnants of lands\n" + "conquered by d'sparil. you defeated\n" + "the last guardians of these lands,\n" + "but now you stand before the gates\n" + "to d'sparil's stronghold. until this\n" + "moment you had no doubts about your\n" + "ability to face anything you might\n" + "encounter, but beyond this portal\n" + "lies the very heart of the evil\n" + "which invaded your world. d'sparil\n" + "might be dead, but the pit where he\n" + "was spawned remains. now you must\n" + "enter that pit in the hopes of\n" + "finding a way out. and somewhere,\n" + "in the darkest corner of d'sparil's\n" + "demesne, his personal bodyguards\n" + "await your arrival ..."; +HE5TEXT = + "as the final maulotaur bellows his\n" + "death-agony, you realize that you\n" + "have never come so close to your own\n" + "destruction. not even the fight with\n" + "d'sparil and his disciples had been\n" + "this desperate. grimly you stare at\n" + "the gates which open before you,\n" + "wondering if they lead home, or if\n" + "they open onto some undreamed-of\n" + "horror. you find yourself wondering\n" + "if you have the strength to go on,\n" + "if nothing but death and pain await\n" + "you. but what else can you do, if\n" + "the will to fight is gone? can you\n" + "force yourself to continue in the\n" + "face of such despair? do you have\n" + "the courage? you find, in the end,\n" + "that it is not within you to\n" + "surrender without a fight. eyes\n" + "wide, you go to meet your fate."; + +// EPISODE 1 - THE CITY OF THE DAMNED +HHUSTR_E1M1 = "THE DOCKS"; +HHUSTR_E1M2 = "THE DUNGEONS"; +HHUSTR_E1M3 = "THE GATEHOUSE"; +HHUSTR_E1M4 = "THE GUARD TOWER"; +HHUSTR_E1M5 = "THE CITADEL"; +HHUSTR_E1M6 = "THE CATHEDRAL"; +HHUSTR_E1M7 = "THE CRYPTS"; +HHUSTR_E1M8 = "HELL'S MAW"; +HHUSTR_E1M9 = "THE GRAVEYARD"; + +// EPISODE 2 - HELL'S MAW +HHUSTR_E2M1 = "THE CRATER"; +HHUSTR_E2M2 = "THE LAVA PITS"; +HHUSTR_E2M3 = "THE RIVER OF FIRE"; +HHUSTR_E2M4 = "THE ICE GROTTO"; +HHUSTR_E2M5 = "THE CATACOMBS"; +HHUSTR_E2M6 = "THE LABYRINTH"; +HHUSTR_E2M7 = "THE GREAT HALL"; +HHUSTR_E2M8 = "THE PORTALS OF CHAOS"; +HHUSTR_E2M9 = "THE GLACIER"; + +// EPISODE 3 - THE DOME OF D'SPARIL +HHUSTR_E3M1 = "THE STOREHOUSE"; +HHUSTR_E3M2 = "THE CESSPOOL"; +HHUSTR_E3M3 = "THE CONFLUENCE"; +HHUSTR_E3M4 = "THE AZURE FORTRESS"; +HHUSTR_E3M5 = "THE OPHIDIAN LAIR"; +HHUSTR_E3M6 = "THE HALLS OF FEAR"; +HHUSTR_E3M7 = "THE CHASM"; +HHUSTR_E3M8 = "D'SPARIL'S KEEP"; +HHUSTR_E3M9 = "THE AQUIFER"; + +// EPISODE 4: THE OSSUARY +HHUSTR_E4M1 = "CATAFALQUE"; +HHUSTR_E4M2 = "BLOCKHOUSE"; +HHUSTR_E4M3 = "AMBULATORY"; +HHUSTR_E4M4 = "SEPULCHER"; +HHUSTR_E4M5 = "GREAT STAIR"; +HHUSTR_E4M6 = "HALLS OF THE APOSTATE"; +HHUSTR_E4M7 = "RAMPARTS OF PERDITION"; +HHUSTR_E4M8 = "SHATTERED BRIDGE"; +HHUSTR_E4M9 = "MAUSOLEUM"; + +// EPISODE 5: THE STAGNANT DEMESNE +HHUSTR_E5M1 = "OCHRE CLIFFS"; +HHUSTR_E5M2 = "RAPIDS"; +HHUSTR_E5M3 = "QUAY"; +HHUSTR_E5M4 = "COURTYARD"; +HHUSTR_E5M5 = "HYDRATYR"; +HHUSTR_E5M6 = "COLONNADE"; +HHUSTR_E5M7 = "FOETID MANSE"; +HHUSTR_E5M8 = "FIELD OF JUDGEMENT"; +HHUSTR_E5M9 = "SKEIN OF D'SPARIL"; + +// Keys + +TXT_GOTBLUEKEY = "CHAVE AZUL"; +TXT_GOTYELLOWKEY = "CHAVE AMARELA"; +TXT_GOTGREENKEY = "CHAVE AZUL"; + +// Artifacts + +TXT_ARTIHEALTH = "FRASCO DE QUARTZO"; +TXT_ARTIFLY = "ASAS DE IRA"; +TXT_ARTIINVULNERABILITY = "ANEL DE INVENCIBILIDADE"; +TXT_ARTITOMEOFPOWER = "LIVRO DO PODER"; +TXT_ARTIINVISIBILITY = "ESFERA NEGRA"; +TXT_ARTIEGG = "OVO MUTANTE"; +TXT_ARTISUPERHEALTH = "URNA MISTICA"; +TXT_ARTITORCH = "TOCHA"; +TXT_ARTIFIREBOMB = "BOMBA-RELOGIO DOS ANTIGOS"; +TXT_ARTITELEPORT = "DISPOSITIVO DO CAOS"; + +// Items + +TXT_ITEMHEALTH = "AMPOLA DE CRISTAL"; +TXT_ITEMBAGOFHOLDING = "BOLSA DE UTENSILIOS"; +TXT_ITEMSHIELD1 = "ESCUDO DE PRATA"; +TXT_ITEMSHIELD2 = "ESCUDO ENCANTADO"; +TXT_ITEMSUPERMAP = "PERGAMINHO - MAPA"; + +// Ammo + +TXT_AMMOGOLDWAND1 = "CRISTAL MAGICO"; +TXT_AMMOGOLDWAND2 = "GEODO DE CRISTAL"; +TXT_AMMOMACE1 = "ESFERAS PARA CLAVA"; +TXT_AMMOMACE2 = "PILHA DE ESFERAS PARA CLAVA"; +TXT_AMMOCROSSBOW1 = "FLECHAS MAGICAS"; +TXT_AMMOCROSSBOW2 = "MAIS FLECHAS MAGICAS"; +TXT_AMMOBLASTER1 = "ESFERA PARA GARRAS"; +TXT_AMMOBLASTER2 = "ESFERA DE ENERGIA"; +TXT_AMMOSKULLROD1 = "RUNAS PEQUENAS"; +TXT_AMMOSKULLROD2 = "RUNAS GRANDES"; +TXT_AMMOPHOENIXROD1 = "ESFERA DE CHAMAS"; +TXT_AMMOPHOENIXROD2 = "ESFERA DO INFERNO"; + +// Weapons + +TXT_WPNMACE = "CLAVA DE FOGO"; +TXT_WPNCROSSBOW = "BESTA MAGICA"; +TXT_WPNBLASTER = "GARRAS DE DRAGAO"; +TXT_WPNSKULLROD = "BASTAO DO INFERNO"; +TXT_WPNPHOENIXROD = "BASTAO DA FENIX"; +TXT_WPNGAUNTLETS = "LUVAS DO NECROMANCER"; + +TXT_NEEDBLUEKEY = "VOCE PRECISA DA CHAVE AZUL PARA ABRIR A PORTA"; +TXT_NEEDGREENKEY = "VOCE PRECISA DA CHAVE VERDE PARA ABRIR A PORTA"; +TXT_NEEDYELLOWKEY = "VOCE PRECISA DA CHAVE AMARELA PARA ABRIR A PORTA"; + +TXT_CHEATPOWERON = "PODER ATIVADO"; +TXT_CHEATPOWEROFF = "PODER DESATIVADO"; +TXT_CHEATHEALTH = "SAUDE CHEIA"; +TXT_CHEATKEYS = "TODAS AS CHAVES"; +TXT_CHEATSOUNDON = "DEBUG DE SOM ATIVADO"; +TXT_CHEATSOUNDOFF = "DEBUG DE SOM DESATIVADO"; +TXT_CHEATIDDQD = "CODIGO ERRADO, TENTE NOVAMENTE!"; +TXT_CHEATIDKFA = "SO NAO TIRO O BASTAO PORQUE NAO POSSO"; +TXT_CHEATTICKERON = "TICKER ATIVADO"; +TXT_CHEATTICKEROFF = "TICKER DESATIVADO"; +TXT_CHEATARTIFACTS3 = "ESTA FELIZ AGORA?"; +TXT_MIDASTOUCH = "YOU GOT THE MIDAS TOUCH, BABY"; +TXT_GOTSTUFF = "Pegou tudo?"; +TXT_FREEZEON = "modo congelado ATIVADO"; +TXT_FREEZEOFF = "modo congelado DeSaTiVaDo"; +TXT_STRANGE = "Voce se sente estranho"; +TXT_STRANGER = "Voce se sente mais estranho."; +TXT_NOTSTRANGE = "voce se sente melhor agora."; +TXT_LEADBOOTSON = "BOTAS ATIVADAS"; +TXT_LEADBOOTSOFF = "BOTAS DESATIVADAS"; +TXT_LIGHTER = "Voce se sente leve"; +TXT_GRAVITY = "Gravidade volta a funcionar normalmente"; + +RAVENQUITMSG = "DESEJA MESMO SAIR?"; + +// Hexen strings + +// Mana + +TXT_MANA_1 = "MANA AZUL"; +TXT_MANA_2 = "MANA VERDE"; +TXT_MANA_BOTH = "MANA COMBINADA"; + +// Keys + +TXT_KEY_STEEL = "STEEL KEY"; +TXT_KEY_CAVE = "CAVE KEY"; +TXT_KEY_AXE = "AXE KEY"; +TXT_KEY_FIRE = "FIRE KEY"; +TXT_KEY_EMERALD = "EMERALD KEY"; +TXT_KEY_DUNGEON = "DUNGEON KEY"; +TXT_KEY_SILVER = "SILVER KEY"; +TXT_KEY_RUSTED = "RUSTED KEY"; +TXT_KEY_HORN = "HORN KEY"; +TXT_KEY_SWAMP = "SWAMP KEY"; +TXT_KEY_CASTLE = "CASTLE KEY"; + +TXT_NEED_KEY_STEEL = "You need the STEEL KEY"; +TXT_NEED_KEY_CAVE = "You need the CAVE KEY"; +TXT_NEED_KEY_AXE = "You need the AXE KEY"; +TXT_NEED_KEY_FIRE = "You need the FIRE KEY"; +TXT_NEED_KEY_EMERALD = "You need the EMERALD KEY"; +TXT_NEED_KEY_DUNGEON = "You need the DUNGEON KEY"; +TXT_NEED_KEY_SILVER = "You need the SILVER KEY"; +TXT_NEED_KEY_RUSTED = "You need the RUSTED KEY"; +TXT_NEED_KEY_HORN = "You need the HORN KEY"; +TXT_NEED_KEY_SWAMP = "You need the SWAMP KEY"; +TXT_NEED_KEY_CASTLE = "You need the CASTLE KEY"; + +// Artifacts + +TXT_ARTIINVULNERABILITY2 = "ICON OF THE DEFENDER"; +TXT_ARTISUMMON = "DARK SERVANT"; +TXT_ARTIEGG2 = "PORKALATOR"; +TXT_ARTIPOISONBAG = "FLECHETTE"; +TXT_ARTITELEPORTOTHER = "BANISHMENT DEVICE"; +TXT_ARTISPEED = "BOOTS OF SPEED"; +TXT_ARTIBOOSTMANA = "KRATER OF MIGHT"; +TXT_ARTIBOOSTARMOR = "DRAGONSKIN BRACERS"; +TXT_ARTIBLASTRADIUS = "DISC OF REPULSION"; +TXT_ARTIHEALINGRADIUS = "MYSTIC AMBIT INCANT"; + +// Puzzle artifacts + +TXT_ARTIPUZZSKULL = "YORICK'S SKULL"; +TXT_ARTIPUZZGEMBIG = "HEART OF D'SPARIL"; +TXT_ARTIPUZZGEMRED = "RUBY PLANET"; +TXT_ARTIPUZZGEMGREEN1 = "EMERALD PLANET"; +TXT_ARTIPUZZGEMGREEN2 = "EMERALD PLANET"; +TXT_ARTIPUZZGEMBLUE1 = "SAPPHIRE PLANET"; +TXT_ARTIPUZZGEMBLUE2 = "SAPPHIRE PLANET"; +TXT_ARTIPUZZBOOK1 = "DAEMON CODEX"; +TXT_ARTIPUZZBOOK2 = "LIBER OSCURA"; +TXT_ARTIPUZZSKULL2 = "FLAME MASK"; +TXT_ARTIPUZZFWEAPON = "GLAIVE SEAL"; +TXT_ARTIPUZZCWEAPON = "HOLY RELIC"; +TXT_ARTIPUZZMWEAPON = "SIGIL OF THE MAGUS"; +TXT_ARTIPUZZGEAR = "CLOCK GEAR"; +TXT_USEPUZZLEFAILED = "YOU CANNOT USE THIS HERE"; + +// Items + +TXT_ARMOR1 = "MESH ARMOR"; +TXT_ARMOR2 = "FALCON SHIELD"; +TXT_ARMOR3 = "PLATINUM HELMET"; +TXT_ARMOR4 = "AMULET OF WARDING"; + +// Weapons + +TXT_WEAPON_F2 = "TIMON'S AXE"; +TXT_WEAPON_F3 = "HAMMER OF RETRIBUTION"; +TXT_WEAPON_F4 = "QUIETUS ASSEMBLED"; +TXT_WEAPON_C2 = "SERPENT STAFF"; +TXT_WEAPON_C3 = "FIRESTORM"; +TXT_WEAPON_C4 = "WRAITHVERGE ASSEMBLED"; +TXT_WEAPON_M2 = "FROST SHARDS"; +TXT_WEAPON_M3 = "ARC OF DEATH"; +TXT_WEAPON_M4 = "BLOODSCOURGE ASSEMBLED"; +TXT_WEAPONPIECE = "A weapon piece! This is your lucky day!"; +TXT_QUIETUS_PIECE = "SEGMENT OF QUIETUS"; +TXT_WRAITHVERGE_PIECE = "SEGMENT OF WRAITHVERGE"; +TXT_BLOODSCOURGE_PIECE = "SEGMENT OF BLOODSCOURGE"; + +// Strife locks + +TXT_NEEDKEY = "Voce nao possui a chave"; +TXT_NEED_PASSCARD = "Precisa do cartao de passe"; +TXT_NEED_PASSCARD_DOOR = "Precisa do cartao de passe para abrir a porta"; +TXT_NEED_IDCARD = "Precisa do cartao de indentificacao"; +TXT_NEED_PRISONKEY = "Voce nao tem a chave da prisao"; +TXT_NEED_HANDPRINT = "Biometria nao autorizada"; +TXT_NEED_GOLDKEY = "Voce precisa da chave dourada"; +TXT_NEED_IDBADGE = "Voce precisa do distintivo de identificacao"; +TXT_NEED_IDBADGE_DOOR = "Voce precisa do distintivo de identificacao para abrir a porta"; +TXT_NEED_SILVERKEY = "Voce precisa da chave de prata"; +TXT_NEED_BRASSKEY = "Voce precisa da chave de latao"; +TXT_NEED_REDCRYSTAL = "Voce precisa do cristal vermelho"; +TXT_NEED_BLUECRYSTAL = "Voce precisa do cristal azul"; +TXT_RETAIL_ONLY = "AREA DISPONIVEL NA VERSAO REGISTRADA"; +TXT_DOES_NOT_WORK = "Parece que nao funciona"; + +// Strife - mensagens de missoes + +TXT_QUEST_14 = "Voce explodiu o cristal"; +TXT_QUEST_16 = "Voce explodiu as portas"; +TXT_QUEST_27 = "Voce explodiu o computador"; + +TXT_KILLED_BISHOP = "Voce matou o bispo!"; +TXT_KILLED_ORACLE = "Voce matou o Oraculo!"; +TXT_KILLED_MACIL = "Voce matou Macil!"; +TXT_KILLED_LOREMASTER = "Voce matou o Loremaster!"; + +// Strife - mensagens gerais + +TXT_METALARMOR = "Voce pegou a armadura de metal."; +TXT_LEATHERARMOR = "Voce pegou a armadura leve."; +TXT_MEDPATCH = "Voce pegou um pequeno kit de primeiros socorros."; +TXT_MEDICALKIT = "Voce pegou um kit medio de primeiros socorros."; +TXT_SURGERYKIT = "Voce pegou um kit de primeiros socorros grande."; +TXT_STRIFEMAP = "Voce pegou o mapa."; +TXT_BELDINSRING = "Voce pegou o anel."; +TXT_OFFERINGCHALICE = "Voce pegou o calice de oferenda."; +TXT_EAR = "Voce pegou a orelha."; +TXT_BROKENCOUPLING = "Você pegou o acoplador de energia quebrado."; +TXT_SHADOWARMOR = "Voce pegou a armadura das sombras."; +TXT_ENVSUIT = "Voce pegou a roupa anti-radiacao."; +TXT_GUARDUNIFORM = "Voce pegou o uniforme - Guarda."; +TXT_OFFICERSUNIFORM = "Voce pegou o uniforme - Oficial."; +TXT_FTHROWERPARTS = "Voce pegou uma parte do lanca-chamas."; +TXT_REPORT = "Voce pegou o relatorio."; +TXT_INFO = "Voce pegou a informacao."; +TXT_TARGETER = "Voce pegou o Targeter."; +TXT_COMMUNICATOR = "Voce pegou o Transmissor."; +TXT_COIN = "Voce pegou a moeda."; +TXT_XGOLD = "Voce pegou %d moedas."; +TXT_BEACON = "Voce pegou o sinalizador de teletransporte."; +TXT_DEGNINORE = "Voce pegou o minerio Degnin."; +TXT_SCANNER = "Voce pegou o scanner."; +TXT_NEEDMAP = "O scanner nao funciona sem um mapa!\n"; +TXT_PRISONPASS = "Voce pegou o passe da prisao."; + +TXT_STRIFECROSSBOW = "Voce pegou a besta."; +TXT_ASSAULTGUN = "Voce pegou a metralhadora."; +TXT_MMLAUNCHER = "Voce pegou o mini lanca-misseis."; +TXT_FLAMER = "Voce pegou o lanca-chamas."; +TXT_MAULER = "Voce pegou o mauler."; +TXT_GLAUNCHER = "Voce pegou o lanca-granadas."; +TXT_SIGIL = "Voce pegou o SIGIL."; + + +TXT_BASEKEY = "Voce pegou a chave da Base."; +TXT_GOVSKEY = "Voce pegou a chave do Governador."; +TXT_PASSCARD = "Voce pegou o cartao de passe."; +TXT_IDBADGE = "Voce pegou o distintivo de identificacao."; +TXT_PRISONKEY = "Voce pegou a chave da prisao."; +TXT_SEVEREDHAND = "Voce pegou a mao decepada."; +TXT_POWER1KEY = "Voce pegou a chave Power1."; +TXT_POWER2KEY = "Voce pegou a chave Power2."; +TXT_POWER3KEY = "Voce pegou a chave Power3."; +TXT_GOLDKEY = "Voce pegu a chave de ouro."; +TXT_IDCARD = "Voce pegou o cartao de identificacao."; +TXT_SILVERKEY = "Voce pegou a chave de prata."; +TXT_ORACLEKEY = "Voce pegou a chave do Oraculo."; +TXT_MILITARYID = "Voce pegou a ID do militar."; +TXT_ORDERKEY = "Voce pegou a chave da Ordem."; +TXT_WAREHOUSEKEY = "Voce pegou a chave do barracao."; +TXT_BRASSKEY = "Voce pegou a chave de bronze."; +TXT_REDCRYSTAL = "Voce pegou a chave - Cristal Vermelho."; +TXT_BLUECRYSTAL = "Voce pegou a chave - Cristal Azul."; +TXT_CHAPELKEY = "Voce pegou a chave da capela."; +TXT_CATACOMBKEY = "Voce pegou a chave da catatumba."; +TXT_SECURITYKEY = "Voce pegou a chave de seguranca."; +TXT_COREKEY = "Voce pegou a chave principal."; +TXT_MAULERKEY = "Voce pegou a chave do Mauler."; +TXT_FACTORYKEY = "Voce pegou a chave da Fabrica."; +TXT_MINEKEY = "Voce pegou a chave da Mina."; +TXT_NEWKEY5 = "Voce pegou a Chave Nova5."; +TXT_ORACLEPASS = "Voce pegou o passe do Oraculo."; + +TXT_HEGRENADES = "Voce pegou granadas HE."; +TXT_PHGRENADES = "Voce pegou granadas PH."; +TXT_CLIPOFBULLETS = "Voce pegou um clipe."; +TXT_BOXOFBULLETS = "Voce pegou uma caixa de balas."; +TXT_MINIMISSILES = "Voce pegou mini-misseis."; +TXT_CRATEOFMISSILES = "Voce pegou uma caixa de misseis."; +TXT_ENERGYPOD = "Voce pegou uma celula de energia (pequeno)."; +TXT_ENERGYPACK = "Voce pegou uma celula de energia (grande)."; +TXT_POISONBOLTS = "Voce pegou flechas (venenosas)."; +TXT_ELECTRICBOLTS = "Voce pegou flechas (eletricas)."; +TXT_AMMOSATCHEL = "Voce pegou uma mochila de municao."; + +// Diálogos aleatórios + +TXT_RANDOM_PEASANT_01 = "Por favor, nao me machuque."; +TXT_RANDOM_PEASANT_02 = "Se pretende me machucar, te digo que nao valera a pena."; +TXT_RANDOM_PEASANT_03 = "Eu nao sei de nada."; +TXT_RANDOM_PEASANT_04 = "Va embora antes que eu chame os guardas!"; +TXT_RANDOM_PEASANT_05 = "Eu queria que esses rebeldes soubessem se por em seu lugar e parassem com essa maluquice."; +TXT_RANDOM_PEASANT_06 = "So me deixa em paz, OK?"; +TXT_RANDOM_PEASANT_07 = "Eu nao tenho certeza, mas acho que conheco alguns dos acolytes."; +TXT_RANDOM_PEASANT_08 = "A Ordem mantem tudo trancado a sete chaves."; +TXT_RANDOM_PEASANT_09 = "Nao tem como isso ser uma forca de seguranca."; +TXT_RANDOM_PEASANT_10 = "Eu soube que a Ordem esta bem nervosa por causa das acoes dos opositores por aqui."; + +TXT_RANDOM_REBEL_01 = "Nao ha como a Ordem ficar contra a gente."; +TXT_RANDOM_REBEL_02 = "Estamos quase prontos para o ataque. Os planos de Macil estao fazendo efeito."; +TXT_RANDOM_REBEL_03 = "Estamos todos lhe protegendo, nao se preocupe."; +TXT_RANDOM_REBEL_04 = "Nem pense em ficar perto daqueles robos. Te transformam em ferro velho em um instante!"; +TXT_RANDOM_REBEL_05 = "O dia de nossa gloria chegara, e aqueles que se opuserem serao esmagados!"; +TXT_RANDOM_REBEL_06 = "Nao fique muito confortavel. Ainda temos trabalho a fazer."; +TXT_RANDOM_REBEL_07 = "Macil disse que voce e a nova esperanca. Lembre-se disso."; +TXT_RANDOM_REBEL_08 = "Assim que derrubarmos esses charlatas, poderemos reconstruir o mundo do jeito certo."; +TXT_RANDOM_REBEL_09 = "Lembre-se que nao esta lutando por si mesmo, mas por todos nos."; +TXT_RANDOM_REBEL_10 = "Enquanto um de nos ainda estiver em pe, teremos chance de vencer."; + +TXT_RANDOM_AGUARD_01 = "Continue andando."; +TXT_RANDOM_AGUARD_02 = "Siga a verdadeirta fe e entao comecara a entender."; +TXT_RANDOM_AGUARD_03 = "Somente atraves da morte que alguem podera renascer."; +TXT_RANDOM_AGUARD_04 = "Nao estou interessado em lhe ouvir."; +TXT_RANDOM_AGUARD_05 = "Se quisesse falar com voce, eu mesmo teria te dito."; +TXT_RANDOM_AGUARD_06 = "Va pertubar outro!"; +TXT_RANDOM_AGUARD_07 = "Continue andando!"; +TXT_RANDOM_AGUARD_08 = "Se o alarme disparar, nao fique no nosso caminho!"; +TXT_RANDOM_AGUARD_09 = "A Ordem vai limpar o mundo e arruma-lo dentro da nova era."; +TXT_RANDOM_AGUARD_10 = "Algum problema? Eu acho que nao."; + +TXT_RANDOM_BEGGAR_01 = "Uma ajuda para os pobres?"; +TXT_RANDOM_BEGGAR_02 = "O que esta olhando, terrestre?"; +TXT_RANDOM_BEGGAR_03 = "Voce nao tem comida, tem?"; +TXT_RANDOM_BEGGAR_04 = "Voces da superficie nunca nos entenderao."; +TXT_RANDOM_BEGGAR_05 = "Ha, os guardas nunca nos acharao. Estes idiotas nem sabem que existimos."; +TXT_RANDOM_BEGGAR_06 = "Um dia todos, exceto aqueles que servem a Ordem, se juntarao a nos."; +TXT_RANDOM_BEGGAR_07 = "Observe, pois este sera seu futuro um dia."; +TXT_RANDOM_BEGGAR_08 = "Nao ha nada mais irritante do que um da superficie com atitude!"; +TXT_RANDOM_BEGGAR_09 = "A Ordem nao tera muito trabalho com voces, pateticos opositores."; +TXT_RANDOM_BEGGAR_10 = "Cuidado, o da superficie; Nos sabemos quem sao nossos inimigos!"; + +TXT_RANDOM_PGUARD_01 = "Nos somos as maos da fe. Se nos irritar, esqueca da gente!"; +TXT_RANDOM_PGUARD_02 = "A Ordem limpara o mundo dos fracos e corruptos!"; +TXT_RANDOM_PGUARD_03 = "Obedeca a lei dos mestres!"; +TXT_RANDOM_PGUARD_04 = "Vida longa aos irmaos da Ordem!"; +TXT_RANDOM_PGUARD_05 = "Livre arbitrio e uma ideia que passa em mentes fracas."; +TXT_RANDOM_PGUARD_06 = "O poder e o caminho para a gloria. Siga a Ordem e andara por esse caminho!"; +TXT_RANDOM_PGUARD_07 = "Tenha seu lugar junto com os certos, junte-se a nos!"; +TXT_RANDOM_PGUARD_08 = "A Ordem protege a si propria."; +TXT_RANDOM_PGUARD_09 = "Acolytes? Eles ainda tem de ver a gloria total da Ordem."; +TXT_RANDOM_PGUARD_10 = "Se ainda existe honra dentro de seu patetico corpo, voce vai entrar para os bracos da Ordem."; + +TXT_RANDOMGOODBYE_1 = "Fui!"; +TXT_RANDOMGOODBYE_2 = "Muito obrigado."; +TXT_RANDOMGOODBYE_3 = "Ate mais tarde!"; +TXT_HAVEENOUGH = "Voce parece ter bastante!"; +TXT_GOAWAY = "Va embora!"; + +// Skills: (partes não traduzidas ainda) + +SKILL_BABY = "Facil"; +SKILL_EASY = "Medio"; +SKILL_NORMAL = "Dificil"; +SKILL_HARD = "Desafio"; +SKILL_NIGHTMARE = "PESADELO!"; + +$ifgame(chex) SKILL_BABY = "Bem facil"; +$ifgame(chex) SKILL_EASY = "Ainda facil"; +$ifgame(chex) SKILL_NORMAL = "Muita gosma"; +$ifgame(chex) SKILL_HARD = "Gosma extrema"; +$ifgame(chex) SKILL_NIGHTMARE = "So para os melhores!"; + +SSKILL_BABY = "Treino"; +SSKILL_EASY = "Iniciante"; +SSKILL_NORMAL = "Veterano"; +SSKILL_HARD = "Elite"; +SSKILL_NIGHTMARE = "Banho de sangue"; + +// Menu +MNU_NEWGAME = "NOVO JOGO"; +MNU_OPTIONS = "OPCOES"; +MNU_GAMEFILES = "JOGOS SALVOS"; +MNU_INFO = "INFO"; +MNU_QUITGAME = "SAIR"; + +MNU_FIGHTER = "FIGHTER"; +MNU_CLERIC = "CLERIC"; +MNU_MAGE = "MAGE"; +MNU_RANDOM = "RANDOM"; + +MNU_LOADGAME = "CARREGAR"; +MNU_SAVEGAME = "SALVAR"; + +MNU_COTD = "CITY OF THE DAMNED"; +MNU_HELLSMAW = "HELL'S MAW"; +MNU_DOME = "THE DOME OF D'SPARIL"; +MNU_OSSUARY = "THE OSSUARY"; +MNU_DEMESNE = "THE STAGNANT DEMESNE"; + +MNU_WETNURSE = "THOU NEEDETH A WET-NURSE"; +MNU_YELLOWBELLIES = "YELLOWBELLIES-R-US"; +MNU_BRINGEST = "BRINGEST THEM ONETH"; +MNU_SMITE = "THOU ART A SMITE-MEISTER"; +MNU_BLACKPLAGUE = "BLACK PLAGUE POSSESSES THEE"; + +MNU_NOPICTURE = "No Picture"; +MNU_DIFFVERSION = "Versao\nDiferente"; +MNU_NOFILES = "Vazio"; + +MNU_CHOOSECLASS = "Escolha a classe:"; +MNU_CHOOSESKILL = "ESCOLHA A DIFICULDADE:"; + +MNU_SQUIRE = "SQUIRE"; +MNU_KNIGHT = "KNIGHT"; +MNU_WARRIOR = "WARRIOR"; +MNU_BERSERKER = "BERSERKER"; +MNU_TITAN = "TITAN"; + +MNU_ALTARBOY = "ALTAR BOY"; +MNU_ACOLYTE = "ACOLYTE"; +MNU_PRIEST = "PRIEST"; +MNU_CARDINAL = "CARDINAL"; +MNU_POPE = "POPE"; + +MNU_APPRENTICE = "APPRENTICE"; +MNU_ENCHANTER = "ENCHANTER"; +MNU_SORCERER = "SORCERER"; +MNU_WARLOCK = "WARLOCK"; +MNU_ARCHMAGE = "ARCHMAGE"; + +MNU_PLAYERSETUP = "PLAYER SETUP"; + +MNU_DELETESG = "Deseja mesmo deletar:\n"; + +$ifgame(heretic) SWSTRING = "SOMENTE DISPONIVEL NA VERSAO REGISTRADA"; + +MNU_EPISODE = "Selecione um episodio"; + +WI_FINISHED = "finalizado"; +WI_ENTERING = "Entrando:"; + +// Bloodbath announcer (não traduzido ainda) + +BBA_BONED = "%k boned %o like a fish"; +BBA_CASTRA = "%k castrated %o"; +BBA_CREAMED = "%k creamed %o"; +BBA_DECIMAT = "%k decimated %o"; +BBA_DESTRO = "%k destroyed %o"; +BBA_DICED = "%k diced %o"; +BBA_DISEMBO = "%k disembowled %o"; +BBA_FLATTE = "%k flattened %o"; +BBA_JUSTICE = "%k gave %o Anal Justice"; +BBA_MADNESS = "%k gave AnAl MaDnEsS to %o"; +BBA_KILLED = "%k killed %o"; +BBA_MINCMEAT = "%k made mincemeat out of %o"; +BBA_MASSACR = "%k massacred %o"; +BBA_MUTILA = "%k mutilated %o"; +BBA_REAMED = "%k reamed %o"; +BBA_RIPPED = "%k ripped %o a new orifice"; +BBA_SLAUGHT = "%k slaughtered %o"; +BBA_SMASHED = "%k smashed %o"; +BBA_SODOMIZ = "%k sodomized %o"; +BBA_SPLATT = "%k splattered %o"; +BBA_SQUASH = "%k squashed %o"; +BBA_THROTTL = "%k throttled %o"; +BBA_WASTED = "%k wasted %o"; +BBA_BODYBAG = "%k body bagged %o"; +BBA_HELL = "%k sent %o to Hell"; +BBA_TOAST = "%k toasted %o"; +BBA_SNUFF = "%k snuffed %o"; +BBA_HOSED = "%k hosed %o"; +BBA_SPRAYED = "%k sprayed %o"; +BBA_DOGMEAT = "%k made dog meat out of %o"; +BBA_BEATEN = "%k beat %o like a cur"; + +BBA_EXCREMENT = "%o is excrement"; +BBA_HAMBURGER = "%o is hamburger"; +BBA_SCROTUM = "%o suffered scrotum separation"; +BBA_POPULATION = "%o volunteered for population control"; +BBA_SUICIDE = "%o has suicided"; +BBA_DARWIN = "%o received the Darwin Award"; + +// Chex Quest Strings +$ifgame(chex) HUSTR_E1M1 = "E1M1: Landing Zone"; +$ifgame(chex) HUSTR_E1M2 = "E1M2: Storage Facility"; +$ifgame(chex) HUSTR_E1M3 = "E1M3: Experimental Lab"; +$ifgame(chex) HUSTR_E1M4 = "E1M4: Arboretum"; +$ifgame(chex) HUSTR_E1M5 = "E1M5: Caverns of Bazoik"; +$ifgame(chex) HUSTR_E2M1 = "E2M1: Spaceport"; +$ifgame(chex) HUSTR_E2M2 = "E2M2: Cinema"; +$ifgame(chex) HUSTR_E2M3 = "E2M3: Chex Museum"; +$ifgame(chex) HUSTR_E2M4 = "E2M4: City Streets"; +$ifgame(chex) HUSTR_E2M5 = "E2M5: Sewer System"; +$ifgame(chex) HUSTR_E3M1 = "E3M1: Central Command"; +$ifgame(chex) HUSTR_E3M2 = "E3M2: United Cereals"; +$ifgame(chex) HUSTR_E3M3 = "E3M3: Villa Chex"; +$ifgame(chex) HUSTR_E3M4 = "E3M4: Provincial Park"; +$ifgame(chex) HUSTR_E3M5 = "E3M5: Meteor Spaceship"; + +$ifgame(chex) E1TEXT = + "Apos mandar a monstruosa Flembrane.\n" + "de volta a sua dimensao, voce solta os\n" + "prisioneiros. Mas ainda ha flemoids por\n" + "todo canto! Voce e os cativos dao um\n" + "jeito de chegar na sua espaconave. Os\n" + "flemoids eslameiam sua nave, mas voce\n" + "consegue chegar a orbita, escapando deles.\n" + "Enquanto comemoram felizes o resgate\n" + "e fuga, voce percebe uma coisa:\n" + "ainda nao acabou! Chegando ao seu lar, voce\n" + "ve que os flemoids de algum jeito chegaram\n" + "aqui. Prepare-se para\n" + "Chex Quest 2: Terror in Chex City!"; + +$ifgame(chex) E2TEXT = + "Voce zorcheou os flemoids restantes\n" + "que ficaram nos esgotos. Chex City foi\n" + "salva. Parece que a invasao acabou.\n" + "\nDez anos se passam. Mas os flemoids nao\n" + "foram derrotados, e seu desejo de dominar a\n" + "dimensao do cereal rico em nutrientes nao \n" + "diminuiu. Eles juntam todas as suas forcas e \n" + "abrem um buraco inter-dimensional no espaco.\n" + "Agora uma grande bola de muco esta vindo direto\n" + "para o planeta dos cereais!" + "\n Prepare-se para\n" + "Chex Quest 3: Invasion!"; + +$ifgame(chex) E3TEXT = + "Com este ultimo tiro, voce zorcheia Lord\n" + "Snotfolus de volta a sua dimensao! Contra\n" + "tudo e todos, voce conseguiu conter a \n" + "invasao!\n" + "\n" + "Voce espera que esses flemoids tenham \n" + "aprendido a licao e nunca mais retornar ao\n" + "mundo dos cereais.\n" + "\n" + "Mas se eles voltarem, voce sabe que estara\n" + "pronto para lutar!\n"; + +CLOADNET = "impossivel carregar, porque \n esta em partida online!\naperte uma tecla."; +CNEWGAME = "impossivel iniciar um novo jogo\nenquanto se esta online.\n\naperte uma tecla."; + +CNIGHTMARE = "Cuidado, isto vai ser dificil.\nDeseja continuar?\n"; + +CSWSTRING = "este e Chex(R) Quest. procure\npor outros niveis na internet.\n"; + +$ifgame(chex) NETEND = "voce nao pode finalizar uma partida online!\npressione qualquer tecla."; +$ifgame(chex) ENDGAME = "deseja realmente sair?\n"; + +GOTCHEXARMOR = "Pegou a armadura Chex(R)."; +GOTSUPERCHEXARMOR = "Pegou a super armadura Chex(R)!"; +GOTWATER = "Pegou um copo de agua."; +GOTREPELLENT = "Pegou repelente de lesma."; +GOTBREAKFAST = "Um belo cafe da manha!"; +GOTCBLUEKEY = "Pegou a chave azul."; +GOTCYELLOWKEY = "Pegou a chave amarela."; +GOTCREDKEY = "Pegou a chave vermelha."; +GOTFRUIT = "Pegou uma bacia de frutas."; +GOTVEGETABLESNEED = "Vegetais sao REALMENTE bons para voce!"; +GOTVEGETABLES = "Pegou uma bacia de vegetais."; +GOTSLIMESUIT = "Achou roupa anti-radiacao"; +GOTCHEXMAP = "Achou um GPS"; + +GOTZORCHRECHARGE = "Pegou carga para mini zorcher."; +GOTMINIZORCHPACK = "Pegou mais cargas para mini zorcher."; +GOTPROPULSORRECHARGE = "Pegou carga para propulsor zorch."; +GOTPROPULSORPACK = "Pegou mais cargas para propulsor zorch."; +GOTPHASINGZORCHERRECHARGE = "Pegou carga para mega zorcher."; +GOTPHASINGZORCHERPACK = "Pegou mais carga para mega zorcher."; +GOTLARGEZORCHERRECHARGE = "Pegou carga para zorcher grande."; +GOTLARGEZORCHERPACK = "Pegou mais carga para zorcher grande."; +GOTZORCHPACK = "Pegou um Zorchpak!"; + +GOTLAZDEVICE = "Voce achou LAZ Device! Legal!"; +GOTRAPIDZORCHER = "Voce achou Zorcher automatico!"; +GOTSUPERBOOTSPORK = "Voce achou Super garfo!"; +GOTZORCHPROPULSOR = "Voce achou Propulsor Zorch!"; +GOTPHASINGZORCHER = "Voce achou Mega Zorcher!"; +GOTLARGEZORCHER = "Voce achou Zorcher grande!"; +GOTSUPERLARGEZORCHER = "Voce achou Super Zorcher!"; +GOTMINIZORCHER = "Voce achou Mini Zorcher."; + +$ifgame(chex) STSTR_DQDON = "Modo invencivel ATIVADO"; +$ifgame(chex) STSTR_DQDOFF = "Modo invencivel DESATIVADO"; +$ifgame(chex) STSTR_FAADDED = "Zorch adicionado"; +$ifgame(chex) STSTR_KFAADDED = "Super Zorch adicionado"; +$ifgame(chex) STSTR_CHOPPERS = "... coma Chex(R)!"; + +OB_MPSPOON = "%o foi comido de colher por %k."; +OB_MPBOOTSPORK = "%o foi misturado pelo garfo de %k."; +OB_MPZORCH = "%o foi zorcheado por %k."; +OB_MPMEGAZORCH = "%o foi pego pelo zorcher grande de %k."; +OB_MPRAPIDZORCH = "%o foi zorcheado rapidamente por %k."; +OB_MPPROPULSOR = "%o foi zorcheado pelo propulsor de %k."; +OB_MPP_SPLASH = "%o foi pego pelo propulsor de %k."; +OB_MPPHASEZORCH = "%o foi mega zorcheado por %k."; +OB_MPLAZ_BOOM = "%o foi vitima do LAZ device de %k."; +OB_MPLAZ_SPLASH = "%o foi pego pelo LAZ device de %k."; + +// Music names for Doom. These are needed in the string table only so that they can +// be replaced by Dehacked. +// Note that these names are not prefixed with 'd_' because that's how Dehacked patches +// expect them. + +MUSIC_E1M1 = "e1m1"; +MUSIC_E1M2 = "e1m2"; +MUSIC_E1M3 = "e1m3"; +MUSIC_E1M4 = "e1m4"; +MUSIC_E1M5 = "e1m5"; +MUSIC_E1M6 = "e1m6"; +MUSIC_E1M7 = "e1m7"; +MUSIC_E1M8 = "e1m8"; +MUSIC_E1M9 = "e1m9"; +MUSIC_E2M1 = "e2m1"; +MUSIC_E2M2 = "e2m2"; +MUSIC_E2M3 = "e2m3"; +MUSIC_E2M4 = "e2m4"; +MUSIC_E2M5 = "e2m5"; +MUSIC_E2M6 = "e2m6"; +MUSIC_E2M7 = "e2m7"; +MUSIC_E2M8 = "e2m8"; +MUSIC_E2M9 = "e2m9"; +MUSIC_E3M1 = "e3m1"; +MUSIC_E3M2 = "e3m2"; +MUSIC_E3M3 = "e3m3"; +MUSIC_E3M4 = "e3m4"; +MUSIC_E3M5 = "e3m5"; +MUSIC_E3M6 = "e3m6"; +MUSIC_E3M7 = "e3m7"; +MUSIC_E3M8 = "e3m8"; +MUSIC_E3M9 = "e3m9"; +MUSIC_INTER = "inter"; +MUSIC_INTRO = "intro"; +MUSIC_BUNNY = "bunny"; +MUSIC_VICTOR = "victor"; +MUSIC_INTROA = "introa"; +MUSIC_RUNNIN = "runnin"; +MUSIC_STALKS = "stalks"; +MUSIC_COUNTD = "countd"; +MUSIC_BETWEE = "betwee"; +MUSIC_DOOM = "doom"; +MUSIC_THE_DA = "the_da"; +MUSIC_SHAWN = "shawn"; +MUSIC_DDTBLU = "ddtblu"; +MUSIC_IN_CIT = "in_cit"; +MUSIC_DEAD = "dead"; +MUSIC_STLKS2 = "stlks2"; +MUSIC_THEDA2 = "theda2"; +MUSIC_DOOM2 = "doom2"; +MUSIC_DDTBL2 = "ddtbl2"; +MUSIC_RUNNI2 = "runni2"; +MUSIC_DEAD2 = "dead2"; +MUSIC_STLKS3 = "stlks3"; +MUSIC_ROMERO = "romero"; +MUSIC_SHAWN2 = "shawn2"; +MUSIC_MESSAG = "messag"; +MUSIC_COUNT2 = "count2"; +MUSIC_DDTBL3 = "ddtbl3"; +MUSIC_AMPIE = "ampie"; +MUSIC_THEDA3 = "theda3"; +MUSIC_ADRIAN = "adrian"; +MUSIC_MESSG2 = "messg2"; +MUSIC_ROMER2 = "romer2"; +MUSIC_TENSE = "tense"; +MUSIC_SHAWN3 = "shawn3"; +MUSIC_OPENIN = "openin"; +MUSIC_EVIL = "evil"; +MUSIC_ULTIMA = "ultima"; +MUSIC_READ_M = "read_m"; +MUSIC_DM2TTL = "dm2ttl"; +MUSIC_DM2INT = "dm2int"; From e50de1e5fc9f4a0d7d8b231a6be6f05ad3f9f79a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 19 Feb 2013 08:10:33 +0000 Subject: [PATCH 217/387] - fixed: APowerSpeed::Serialize needs to call the super method. SVN r4150 (trunk) --- src/g_shared/a_artifacts.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index dc45634df..ac9ccde8a 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1164,6 +1164,7 @@ IMPLEMENT_CLASS (APowerSpeed) void APowerSpeed::Serialize(FArchive &arc) { + Super::Serialize (arc); if (SaveVersion < 4146) { SpeedFlags = 0; From fef083f59c769264d6f5a3b335ccc61c1ed4f2c1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Feb 2013 01:31:41 +0000 Subject: [PATCH 218/387] - Use a temporary bitmap when when copying true color pixels of a multipatch texture, the blend operation is not BLEND_NONE, and it doesn't just redirect straight to a direct texture. SVN r4151 (trunk) --- src/textures/multipatchtexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 5d5f61062..3083735a9 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -558,7 +558,7 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota return Parts[0].Texture->CopyTrueColorPixels(bmp, x, y, rotate, inf); } - if (rotate != 0 || (inf != NULL && inf->op != OP_OVERWRITE && inf->op != OP_COPY)) + if (rotate != 0 || (inf != NULL && ((inf->op != OP_OVERWRITE && inf->op != OP_COPY) || inf->blend != BLEND_NONE))) { // We are doing some sort of fancy stuff to the destination bitmap, so composite to // a temporary bitmap, and copy that. FBitmap tbmp; From 4fe9b6112a4da2218b74debaa3ee9c2627fcdc0b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Feb 2013 02:26:36 +0000 Subject: [PATCH 219/387] - Fixed: The change in r3951 knew nothing about 3D floors. SVN r4152 (trunk) --- src/p_enemy.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 0961e8671..dd5ab581b 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -550,9 +550,14 @@ bool P_Move (AActor *actor) { actor->z = savedz; } - else if (actor->floorsector->SecActTarget != NULL) + else { // The monster just hit the floor, so trigger any actions. - actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); + if (actor->floorsector->SecActTarget != NULL && + actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->x, actor->y)) + { + actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor); + } + P_CheckFor3DFloorHit(actor); } } } From 7d90117fb9bf11f13d7df82c85df713566ed2624 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Feb 2013 02:47:01 +0000 Subject: [PATCH 220/387] - Fixed: RandomSpawner should observe the nomonsters flags when deciding what to spawn. SVN r4153 (trunk) --- src/g_shared/a_randomspawner.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 5633c7b79..549c957a5 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -31,6 +31,7 @@ class ARandomSpawner : public AActor FDropItem *di; // di will be our drop item list iterator FDropItem *drop; // while drop stays as the reference point. int n=0; + bool nomonsters = (dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS); Super::BeginPlay(); drop = di = GetDropItems(); @@ -40,11 +41,19 @@ class ARandomSpawner : public AActor { if (di->Name != NAME_None) { - if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value. - n += di->amount; // this is how we can weight the list. + if (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER)) + { + if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value. + n += di->amount; // this is how we can weight the list. + } di = di->Next; } } + if (n == 0) + { // Nothing left to spawn. They must have all been monsters, and monsters are disabled. + Destroy(); + return; + } // Then we reset the iterator to the start position... di = drop; // Take a random number... @@ -54,15 +63,22 @@ class ARandomSpawner : public AActor { if (di->Name != NAME_None) { - n -= di->amount; - if ((di->Next != NULL) && (n > -1)) di = di->Next; else n = -1; + if (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER)) + { + n -= di->amount; + if ((di->Next != NULL) && (n > -1)) + di = di->Next; + else + n = -1; + } } } // So now we can spawn the dropped item. if (bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions { Spawn("Unknown", x, y, z, NO_REPLACE); // Show that there's a problem. - Destroy(); return; + Destroy(); + return; } else if (pr_randomspawn() <= di->probability) // prob 255 = always spawn, prob 0 = never spawn. { @@ -167,8 +183,10 @@ class ARandomSpawner : public AActor if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS))) boss = true; } - if (boss) this->tracer = newmobj; - else Destroy(); // "else" because a boss-replacing spawner must wait until it can call A_BossDeath. + if (boss) + this->tracer = newmobj; + else // "else" because a boss-replacing spawner must wait until it can call A_BossDeath. + Destroy(); } void Tick() // This function is needed for handling boss replacers From 071002c02bb5eecb2f139da85fdd43611b69265a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 20 Feb 2013 12:22:04 +0000 Subject: [PATCH 221/387] - add weapon slots to key configuration menu. SVN r4154 (trunk) --- wadsrc/static/menudef.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 915d08405..f50f21a69 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -465,6 +465,16 @@ OptionMenu "CustomizeControls" StaticText "Weapons", 1 Control "Next weapon", "weapnext" Control "Previous weapon", "weapprev" + Control "Weapon Slot 1", "slot 1" + Control "Weapon Slot 2", "slot 2" + Control "Weapon Slot 3", "slot 3" + Control "Weapon Slot 4", "slot 4" + Control "Weapon Slot 5", "slot 5" + Control "Weapon Slot 6", "slot 6" + Control "Weapon Slot 7", "slot 7" + Control "Weapon Slot 8", "slot 8" + Control "Weapon Slot 9", "slot 9" + Control "Weapon Slot 0", "slot 0" StaticText "" StaticText "Inventory", 1 Control "Activate item", "invuse" From e0db52629d9e27d55e8ee386854bb64dd5764ae3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 22 Feb 2013 01:34:16 +0000 Subject: [PATCH 222/387] - Fixed: RandomSpawner could hang on lists with monsters when nomonsters is enabled or with 'None' items. SVN r4155 (trunk) --- src/g_shared/a_randomspawner.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 549c957a5..fc7ca8cf9 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -59,22 +59,24 @@ class ARandomSpawner : public AActor // Take a random number... n = pr_randomspawn(n); // And iterate in the array up to the random number chosen. - while (n > -1) + while (n > -1 && di != NULL) { - if (di->Name != NAME_None) + if (di->Name != NAME_None && + (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER))) { - if (!nomonsters || !(GetDefaultByType(PClass::FindClass(di->Name))->flags3 & MF3_ISMONSTER)) - { - n -= di->amount; - if ((di->Next != NULL) && (n > -1)) - di = di->Next; - else - n = -1; - } + n -= di->amount; + if ((di->Next != NULL) && (n > -1)) + di = di->Next; + else + n = -1; + } + else + { + di = di->Next; } } // So now we can spawn the dropped item. - if (bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions + if (di == NULL || bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions { Spawn("Unknown", x, y, z, NO_REPLACE); // Show that there's a problem. Destroy(); From e0c751114f3f3a1962fb0338875e767d315afc71 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 22 Feb 2013 01:51:35 +0000 Subject: [PATCH 223/387] - Fixed: A TITLEMAP defined with SpawnWithWeaponRaised set caused a crash. SVN r4156 (trunk) --- src/p_pspr.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index d91b2a88d..62874e938 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -170,8 +170,11 @@ void P_BringUpWeapon (player_t *player) if (player->PendingWeapon == WP_NOCHANGE) { - player->psprites[ps_weapon].sy = WEAPONTOP; - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); + if (player->ReadyWeapon != NULL) + { + player->psprites[ps_weapon].sy = WEAPONTOP; + P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); + } return; } From 445bc148b789f92389c30947ccc127d126f58e87 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 22 Feb 2013 02:42:42 +0000 Subject: [PATCH 224/387] - Fixed: r4067 completely disabled weapon switching via A_ReFire. SVN r4157 (trunk) --- src/d_player.h | 1 + src/g_shared/a_artifacts.cpp | 1 - src/p_pspr.cpp | 19 +++++++++++++++---- src/p_pspr.h | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 76c70819d..48c387444 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -215,6 +215,7 @@ enum WF_DISABLESWITCH = 1 << 4, // Disable weapon switching completely WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. + WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire }; #define WPIECE1 1 diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index ac9ccde8a..adad4e2c4 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1107,7 +1107,6 @@ void APowerWeaponLevel2::EndEffect () Super::EndEffect(); if (player != NULL) { - if (player->ReadyWeapon != NULL && player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 62874e938..85830ac55 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -480,12 +480,22 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y) // //============================================================================ -void DoReadyWeaponToSwitch (AActor *self) +void DoReadyWeaponToSwitch (AActor *self, bool switchable) { // Prepare for switching action. player_t *player; if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONSWITCHOK; + { + if (switchable) + { + player->WeaponState |= WF_WEAPONSWITCHOK | WF_REFIRESWITCHOK; + } + else + { + // WF_WEAPONSWITCHOK is automatically cleared every tic by P_SetPsprite(). + player->WeaponState &= ~WF_REFIRESWITCHOK; + } + } } void DoReadyWeaponDisableSwitch (AActor *self, INTBOOL disable) @@ -497,6 +507,7 @@ void DoReadyWeaponDisableSwitch (AActor *self, INTBOOL disable) if (disable) { player->WeaponState |= WF_DISABLESWITCH; + player->WeaponState &= ~WF_REFIRESWITCHOK; } else { @@ -592,7 +603,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) ACTION_PARAM_START(1); ACTION_PARAM_INT(paramflags, 0); - if (!(paramflags & WRF_NoSwitch)) DoReadyWeaponToSwitch(self); + DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); @@ -742,7 +753,7 @@ void A_ReFire(AActor *self, FState *state) { return; } - pending = player->PendingWeapon == WP_NOCHANGE && (player->WeaponState & WF_WEAPONSWITCHOK); + pending = player->PendingWeapon != WP_NOCHANGE && (player->WeaponState & WF_REFIRESWITCHOK); if ((player->cmd.ucmd.buttons & BT_ATTACK) && !player->ReadyWeapon->bAltFire && !pending && player->health > 0) { diff --git a/src/p_pspr.h b/src/p_pspr.h index 83cce732a..ca9b45ee8 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -94,7 +94,7 @@ void P_GunShot (AActor *mo, bool accurate, const PClass *pufftype, angle_t pitch void DoReadyWeapon(AActor * self); void DoReadyWeaponToBob(AActor * self); void DoReadyWeaponToFire(AActor * self, bool primary = true, bool secondary = true); -void DoReadyWeaponToSwitch(AActor * self); +void DoReadyWeaponToSwitch(AActor * self, bool switchable = true); DECLARE_ACTION(A_Raise) void A_ReFire(AActor *self, FState *state = NULL); From 6eb10a8079ec0fca613cf5e2699c88a5b030d567 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 22 Feb 2013 03:06:00 +0000 Subject: [PATCH 225/387] - Fixed: r4160 inadvertently inverted the damage check for thrusting in P_RadiusAttack(). SVN r4158 (trunk) --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index ad678b529..7da07d5eb 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4581,7 +4581,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed (newdam > 0 ? newdam : damage, thing, bombspot); - if (!(flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) + if ((flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { From 356bfe81e3d6f26cc45b5f0ee074f558b50671d2 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 22 Feb 2013 18:16:23 +0000 Subject: [PATCH 226/387] - Cleared GCC warnings. SVN r4159 (trunk) --- src/p_acs.cpp | 4 ++-- src/p_map.cpp | 2 +- src/p_user.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1527ba849..e2a844d61 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7856,7 +7856,7 @@ static void ShowProfileData(TArray &profiles, long ilimit, } // Module name - mysnprintf(modname, sizeof(modname), prof->Module->GetModuleName()); + mysnprintf(modname, sizeof(modname), "%s", prof->Module->GetModuleName()); // Script/function name if (functions) @@ -7932,7 +7932,7 @@ CCMD(acsprofile) // If it's a name, set the sort method. We accept partial matches for // options that are shorter than the sort name. size_t optlen = strlen(argv[i]); - int j; + unsigned int j; for (j = 0; j < countof(sort_names); ++j) { if (optlen < sort_match_len[j] || optlen > strlen(sort_names[j])) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7da07d5eb..233d45285 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -908,7 +908,7 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) if (!(tm.thing->flags & MF_MISSILE) || !(tm.thing->flags2 & MF2_RIP) || (thing->flags5 & MF5_DONTRIP) || - (tm.thing->flags6 & MF6_NOBOSSRIP) && (thing->flags2 & MF2_BOSS)) + ((tm.thing->flags6 & MF6_NOBOSSRIP) && (thing->flags2 & MF2_BOSS))) { if (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP) { // Some things prefer not to overlap each other, if possible diff --git a/src/p_user.cpp b/src/p_user.cpp index 76aecdc39..a3e848fe1 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -244,10 +244,10 @@ player_t::player_t() lastkilltime(0), multicount(0), spreecount(0), + WeaponState(0), ReadyWeapon(0), PendingWeapon(0), cheats(0), - WeaponState(0), timefreezer(0), refire(0), inconsistant(0), From 47e7ab21cc6b64144bd686d475371d50871ebb4d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 22 Feb 2013 18:42:26 +0000 Subject: [PATCH 227/387] - Fixed: strcpy on map arrays didn't properly translate the array number. SVN r4160 (trunk) --- src/p_acs.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e2a844d61..7bfc87f39 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -7327,7 +7327,12 @@ scriptwait: { case PCD_STRCPYTOMAPCHRANGE: { - Stack[sp-6] = activeBehavior->CopyStringToArray(STACK(5), index, capacity, lookup); + int a = STACK(5); + if (a < NUM_MAPVARS && a > 0 && + activeBehavior->MapVars[a]) + { + Stack[sp-6] = activeBehavior->CopyStringToArray(*(activeBehavior->MapVars[a]), index, capacity, lookup); + } } break; case PCD_STRCPYTOWORLDCHRANGE: From 81785124c5353fa1579013200efc289a9d300391 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 22 Feb 2013 21:18:29 +0000 Subject: [PATCH 228/387] - fixed: the ExplosiveBarrel's height was wrong. SVN r4161 (trunk) --- wadsrc/static/actors/doom/doommisc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/doommisc.txt b/wadsrc/static/actors/doom/doommisc.txt index 0b481427f..131bb273d 100644 --- a/wadsrc/static/actors/doom/doommisc.txt +++ b/wadsrc/static/actors/doom/doommisc.txt @@ -6,7 +6,7 @@ ACTOR ExplosiveBarrel 2035 SpawnID 125 Health 20 Radius 10 - Height 34 + Height 42 +SOLID +SHOOTABLE +NOBLOOD From 1c9396cd6c301c44dd1579be795bace19e6f3cfd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Feb 2013 03:25:33 +0000 Subject: [PATCH 229/387] - Properly transfer powerups between morphed and unmorphed actors by calling EndEffect() on the powerups before they transfer ownership, then calling InitEffect() on them after they transfer ownership. SVN r4162 (trunk) --- src/g_shared/a_artifacts.h | 3 +++ src/g_shared/a_morph.cpp | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index b8c66bb40..0efd64ab8 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -30,6 +30,9 @@ protected: virtual void InitEffect (); virtual void DoEffect (); virtual void EndEffect (); + + friend void EndAllPowerupEffects(AInventory *item); + friend void InitAllPowerupEffects(AInventory *item); }; // An artifact is an item that gives the player a powerup when activated. diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 0058c996b..836cf41e7 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -74,6 +74,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i } morphed = static_cast(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE)); + EndAllPowerupEffects(actor->Inventory); DObject::StaticPointerSubstitution (actor, morphed); if ((actor->tid != 0) && (style & MORPH_NEWTIDBEHAVIOUR)) { @@ -144,6 +145,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i } item = next; } + InitAllPowerupEffects(morphed->Inventory); morphed->ActivateMorphWeapon (); if (p->camera == actor) { @@ -201,10 +203,8 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } pmo->player = NULL; - mo->ObtainInventory (pmo); - DObject::StaticPointerSubstitution (pmo, mo); // Remove the morph power if the morph is being undone prematurely. - for (AInventory *item = mo->Inventory, *next = NULL; item != NULL; item = next) + for (AInventory *item = pmo->Inventory, *next = NULL; item != NULL; item = next) { next = item->Inventory; if (item->IsKindOf(RUNTIME_CLASS(APowerMorph))) @@ -213,6 +213,9 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, item->Destroy(); } } + EndAllPowerupEffects(pmo->Inventory); + mo->ObtainInventory (pmo); + DObject::StaticPointerSubstitution (pmo, mo); if ((pmo->tid != 0) && (player->MorphStyle & MORPH_NEWTIDBEHAVIOUR)) { mo->tid = pmo->tid; @@ -235,6 +238,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, mo->flags2 = (mo->flags2 & ~MF2_FLY) | (pmo->flags2 & MF2_FLY); mo->flags3 = (mo->flags3 & ~MF3_GHOST) | (pmo->flags3 & MF3_GHOST); mo->Score = pmo->Score; + InitAllPowerupEffects(mo->Inventory); const PClass *exit_flash = player->MorphExitFlash; bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON); @@ -538,6 +542,46 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor return false; } +//=========================================================================== +// +// EndAllPowerupEffects +// +// Calls EndEffect() on every Powerup in the inventory list. +// +//=========================================================================== + +void EndAllPowerupEffects(AInventory *item) +{ + while (item != NULL) + { + if (item->IsKindOf(RUNTIME_CLASS(APowerup))) + { + static_cast(item)->EndEffect(); + } + item = item->Inventory; + } +} + +//=========================================================================== +// +// InitAllPowerupEffects +// +// Calls InitEffect() on every Powerup in the inventory list. +// +//=========================================================================== + +void InitAllPowerupEffects(AInventory *item) +{ + while (item != NULL) + { + if (item->IsKindOf(RUNTIME_CLASS(APowerup))) + { + static_cast(item)->InitEffect(); + } + item = item->Inventory; + } +} + // Base class for morphing projectiles -------------------------------------- IMPLEMENT_CLASS(AMorphProjectile) From 4f3a03f2f435fab41b68c443494075dbf3244f20 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Feb 2013 04:24:40 +0000 Subject: [PATCH 230/387] - Fixed: stat skyboxes output was broken. SVN r4163 (trunk) --- src/r_plane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 0e8237cb6..75c308b5a 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1335,7 +1335,7 @@ void R_DrawSkyBoxes () ADD_STAT(skyboxes) { FString out; - out.Format (out, "%d skybox planes", numskyboxes); + out.Format ("%d skybox planes", numskyboxes); return out; } From 2919bdf4fe8f01fb43df49087e614d2b0b633405 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Feb 2013 05:15:32 +0000 Subject: [PATCH 231/387] - Fixed: Skyboxes never cleared planes when a 3D floor was in view. SVN r4164 (trunk) --- src/r_3dfloors.cpp | 2 ++ src/r_main.cpp | 2 +- src/r_plane.cpp | 8 ++++---- src/r_plane.h | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/r_3dfloors.cpp b/src/r_3dfloors.cpp index fbdc34edc..412a6057a 100644 --- a/src/r_3dfloors.cpp +++ b/src/r_3dfloors.cpp @@ -140,6 +140,7 @@ void R_3D_EnterSkybox() height_top = NULL; height_cur = NULL; height_max = -1; + fakeActive = 0; CurrentSkybox++; } @@ -157,6 +158,7 @@ void R_3D_LeaveSkybox() height_top = current.height_top; height_cur = current.height_cur; height_max = current.height_max; + fakeActive = height_top != NULL; CurrentSkybox--; } diff --git a/src/r_main.cpp b/src/r_main.cpp index 80edd18d6..f4ba8c6e5 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -762,7 +762,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) MaskedCycles.Reset(); WallScanCycles.Reset(); - fakeActive = 0; // kg3D - reset fake floor idicator + fakeActive = 0; // kg3D - reset fake floor indicator R_3D_ResetClip(); // reset clips (floor/ceiling) R_SetupBuffer (); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 75c308b5a..d3c5f8c94 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1002,15 +1002,15 @@ static void R_DrawSkyStriped (visplane_t *pl) CVAR (Bool, tilt, false, 0); //CVAR (Int, pa, 0, 0) -void R_DrawPlanes () +int R_DrawPlanes () { visplane_t *pl; int i; - int vpcount; + int vpcount = 0; ds_color = 3; - for (i = vpcount = 0; i < MAXVISPLANES; i++) + for (i = 0; i < MAXVISPLANES; i++) { for (pl = visplanes[i]; pl; pl = pl->next) { @@ -1024,6 +1024,7 @@ void R_DrawPlanes () } } } + return vpcount; } // kg3D - draw all visplanes with "height" @@ -1329,7 +1330,6 @@ void R_DrawSkyBoxes () for (*freehead = visplanes[MAXVISPLANES], visplanes[MAXVISPLANES] = NULL; *freehead; ) freehead = &(*freehead)->next; - } ADD_STAT(skyboxes) diff --git a/src/r_plane.h b/src/r_plane.h index 6bcb36a19..7ad711bcc 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -87,7 +87,7 @@ void R_InitPlanes (); void R_DeinitPlanes (); void R_ClearPlanes (bool fullclear); -void R_DrawPlanes (); +int R_DrawPlanes (); void R_DrawSkyBoxes (); void R_DrawSkyPlane (visplane_t *pl); void R_DrawNormalPlane (visplane_t *pl, fixed_t alpha, bool additive, bool masked); From e6f66e3c93e5d82f72edc49bc191e73939bb0046 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 24 Feb 2013 17:17:20 +0000 Subject: [PATCH 232/387] - Fixed: GCC build. SVN r4165 (trunk) --- src/g_shared/a_morph.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 836cf41e7..8b76e2f66 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -15,6 +15,9 @@ static FRandom pr_morphmonst ("MorphMonster"); +void EndAllPowerupEffects(AInventory *item); +void InitAllPowerupEffects(AInventory *item); + //--------------------------------------------------------------------------- // // FUNC P_MorphPlayer From 01fed92920fd5dd0dff739b17535cf84c749cc93 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 25 Feb 2013 00:12:21 +0000 Subject: [PATCH 233/387] - Added support for Visual Studio to the CMake project. SVN r4166 (trunk) --- CMakeLists.txt | 1 + src/CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++++--- tools/lemon/CMakeLists.txt | 7 +++++++ wadsrc/CMakeLists.txt | 9 +++++---- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c67f73aee..6e5d9cc40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required( VERSION 2.4 ) +project(ZDoom) IF( NOT CMAKE_BUILD_TYPE ) SET( CMAKE_BUILD_TYPE Debug CACHE STRING diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 056b65937..67993f4e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -485,8 +485,10 @@ endif( BACKPATCH ) # Update svnrevision.h +get_target_property( UPDATEREVISION_EXE updaterevision LOCATION ) + add_custom_target( revision_check ALL - COMMAND ${CMAKE_BINARY_DIR}/tools/updaterevision/updaterevision . src/svnrevision.h + COMMAND ${UPDATEREVISION_EXE} . src/svnrevision.h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} DEPENDS updaterevision ) @@ -568,14 +570,17 @@ else( NO_ASM ) endif( X64 ) endif( NO_ASM ) +get_target_property( LEMON_EXE lemon LOCATION ) +get_target_property( RE2C_EXE re2c LOCATION ) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y . - COMMAND ${CMAKE_BINARY_DIR}/tools/lemon/lemon xlat_parser.y + COMMAND ${LEMON_EXE} xlat_parser.y WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h - COMMAND ${CMAKE_BINARY_DIR}/tools/re2c/re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re + COMMAND ${RE2C_EXE} --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re ) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) @@ -598,7 +603,37 @@ elseif( FLUIDSYNTH_FOUND ) add_definitions( -DHAVE_FLUIDSYNTH ) endif( DYN_FLUIDSYNTH ) +# Project files should be aware of the header files. We can GLOB these since +# there's generally a new cpp for every header so this file will get changed +if( WIN32 ) + set( EXTRA_HEADER_DIRS win32/*.h ) +else( WIN32 ) + set( EXTRA_HEADER_DIRS sdl/*.h ) +endif( WIN32 ) +file( GLOB HEADER_FILES + ${EXTRA_HEADER_DIRS} + fragglescript/*.h + g_doom/*.h + g_heretic/*.h + g_hexen/*.h + g_raven/*.h + g_shared/*.h + g_strife/*.h + intermission/*.h + menu/*.h + oplsynth/*.h + r_data/*.h + resourcefiles/*.h + sfmt/*.h + sound/*.h + textures/*.h + thingdef/*.h + xlat/*.h + *.h +) + add_executable( zdoom WIN32 + ${HEADER_FILES} autostart.cpp ${ASM_SOURCES} ${SYSTEM_SOURCES} diff --git a/tools/lemon/CMakeLists.txt b/tools/lemon/CMakeLists.txt index 0a6b2319c..91b144575 100644 --- a/tools/lemon/CMakeLists.txt +++ b/tools/lemon/CMakeLists.txt @@ -5,6 +5,13 @@ set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" ) add_executable( lemon lemon.c ) # Lemon wants lempar.c in its directory +if( MSVC ) +add_custom_command( TARGET lemon + POST_BUILD + COMMAND echo $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lempar.c $ ) +else( MSVC ) add_custom_command( TARGET lemon POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lempar.c ${CMAKE_CURRENT_BINARY_DIR} ) +endif( MSVC ) \ No newline at end of file diff --git a/wadsrc/CMakeLists.txt b/wadsrc/CMakeLists.txt index 19a210abc..a24d712e1 100644 --- a/wadsrc/CMakeLists.txt +++ b/wadsrc/CMakeLists.txt @@ -1,9 +1,10 @@ cmake_minimum_required( VERSION 2.4 ) - +get_target_property(ZIPDIR_EXE zipdir LOCATION) + add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 - COMMAND ${CMAKE_BINARY_DIR}/tools/zipdir/zipdir -udf ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static - DEPENDS zipdir ${CMAKE_CURRENT_SOURCE_DIR}/static ) - + COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static + DEPENDS zipdir ${CMAKE_CURRENT_SOURCE_DIR}/static ) + add_custom_target( pk3 ALL DEPENDS ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ) From be0845acf1253858b37fcf294020c3f63dc25300 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 27 Feb 2013 03:10:25 +0000 Subject: [PATCH 234/387] - Moved all BorderNeedRefresh and SB_state updating code into separate functions that won't crash if screen is NULL. SVN r4167 (trunk) --- src/am_map.cpp | 7 ++++--- src/c_console.cpp | 6 +++--- src/d_main.cpp | 14 +++++++------- src/d_net.cpp | 2 +- src/g_level.cpp | 4 ++-- src/g_shared/hudmessages.cpp | 6 +++--- src/g_shared/sbar.h | 2 ++ src/g_shared/shared_sbar.cpp | 25 ++++++++++++++++++------- src/g_strife/strife_sbar.cpp | 4 ++-- src/hu_scores.cpp | 2 +- src/m_cheat.cpp | 2 +- src/menu/loadsavemenu.cpp | 4 ++-- src/menu/menu.cpp | 2 +- src/menu/messagebox.cpp | 4 ++-- src/r_utility.cpp | 2 +- src/s_sound.cpp | 2 +- src/st_stuff.h | 1 - src/stats.cpp | 4 ++-- src/v_draw.cpp | 29 +++++++++++++++++++++++++++-- src/v_video.cpp | 2 +- src/v_video.h | 1 + src/win32/fb_d3d9.cpp | 5 +++-- 22 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 246adcc9b..aa6634127 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -41,6 +41,7 @@ #include "farchive.h" #include "r_renderer.h" #include "r_sky.h" +#include "sbar.h" #include "m_cheat.h" #include "i_system.h" @@ -1081,7 +1082,7 @@ void AM_Stop () { automapactive = false; stopped = true; - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); viewactive = true; } @@ -1180,7 +1181,7 @@ void AM_ToggleMap () if (dmflags2 & DF2_NO_AUTOMAP) return; - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); if (!automapactive) { AM_Start (); @@ -1191,7 +1192,7 @@ void AM_ToggleMap () if (am_overlay==1 && viewactive) { viewactive = false; - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } else { diff --git a/src/c_console.cpp b/src/c_console.cpp index 8e439df6c..3f4ae9e5f 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1134,7 +1134,7 @@ void C_DrawConsole (bool hw2d) (viewwindowx || viewwindowy) && viewactive) { - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } oldbottom = ConBottom; @@ -1224,8 +1224,8 @@ void C_DrawConsole (bool hw2d) { screen->Dim (PalEntry ((unsigned char)(player->BlendR*255), (unsigned char)(player->BlendG*255), (unsigned char)(player->BlendB*255)), player->BlendA, 0, ConBottom, screen->GetWidth(), screen->GetHeight() - ConBottom); - SB_state = screen->GetPageCount (); - BorderNeedRefresh = screen->GetPageCount (); + ST_SetNeedRefresh(); + V_SetBorderNeedRefresh(); } } } diff --git a/src/d_main.cpp b/src/d_main.cpp index 50311c826..aa4abd366 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -697,21 +697,21 @@ void D_Display () if (screen->Lock (false)) { - SB_state = screen->GetPageCount (); - BorderNeedRefresh = screen->GetPageCount (); + ST_SetNeedRefresh(); + V_SetBorderNeedRefresh(); } // [RH] Allow temporarily disabling wipes if (NoWipe) { - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); NoWipe--; wipe = false; wipegamestate = gamestate; } else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL) { // save the current screen if about to wipe - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); switch (wipegamestate) { default: @@ -780,8 +780,8 @@ void D_Display () if ((hw2d = screen->Begin2D(viewactive))) { // Redraw everything every frame when using 2D accel - SB_state = screen->GetPageCount(); - BorderNeedRefresh = screen->GetPageCount(); + ST_SetNeedRefresh(); + V_SetBorderNeedRefresh(); } Renderer->DrawRemainingPlayerSprites(); screen->DrawBlendingRect(); @@ -1278,7 +1278,7 @@ void D_DoAdvanceDemo (void) Advisory = NULL; if (!M_DemoNoPlay) { - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); democount++; mysnprintf (demoname + 4, countof(demoname) - 4, "%d", democount); if (Wads.CheckNumForName (demoname) < 0) diff --git a/src/d_net.cpp b/src/d_net.cpp index 3acee3af4..dff5c948e 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2245,7 +2245,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) paused = player + 1; S_PauseSound (false, false); } - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } break; diff --git a/src/g_level.cpp b/src/g_level.cpp index 3fd2bae73..3e54f5aa3 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -227,7 +227,7 @@ void G_NewInit () int i; G_ClearSnapshots (); - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); netgame = false; multiplayer = false; if (demoplayback) @@ -424,7 +424,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) demoplayback = false; automapactive = false; viewactive = true; - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); //Added by MC: Initialize bots. if (!deathmatch) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index adc375c24..f60c8a84e 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -163,7 +163,7 @@ DHUDMessage::~DHUDMessage () Lines = NULL; if (screen != NULL) { - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } } if (SourceText != NULL) @@ -597,7 +597,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_RenderStyle, Style, TAG_DONE); } - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } } @@ -698,7 +698,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_RenderStyle, Style, TAG_DONE); } - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } else { diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index fcba22fa9..230e457d8 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -55,6 +55,8 @@ enum EHudState class AWeapon; +void ST_SetNeedRefresh(); + // HUD Message base object -------------------------------------------------- class DHUDMessage : public DObject diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index eb739e6c2..471e3047f 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -209,6 +209,17 @@ void ST_Clear() CrosshairNum = 0; } +//--------------------------------------------------------------------------- +// +// ST_SetNeedRefresh +// +//--------------------------------------------------------------------------- + +void ST_SetNeedRefresh() +{ + SB_state = (StatusBar == NULL || screen == NULL) ? 0 : screen->GetPageCount(); +} + //--------------------------------------------------------------------------- // // Constructor @@ -297,7 +308,7 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) Displacement = 0; } ::ST_X = ST_X; - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } //--------------------------------------------------------------------------- @@ -309,7 +320,7 @@ void DBaseStatusBar::SetScaled (bool scale, bool force) void DBaseStatusBar::AttachToPlayer (player_t *player) { CPlayer = player; - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } //--------------------------------------------------------------------------- @@ -331,7 +342,7 @@ int DBaseStatusBar::GetPlayer () void DBaseStatusBar::MultiplayerChanged () { - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } //--------------------------------------------------------------------------- @@ -441,7 +452,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) // Redraw the status bar in case it was covered if (screen != NULL) { - SB_state = screen->GetPageCount(); + ST_SetNeedRefresh(); } return probe; } @@ -468,7 +479,7 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id) // Redraw the status bar in case it was covered if (screen != NULL) { - SB_state = screen->GetPageCount(); + ST_SetNeedRefresh(); } return probe; } @@ -1281,7 +1292,7 @@ void DBaseStatusBar::Draw (EHudState state) DTA_KeepRatio, true, DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight, TAG_DONE); - BorderNeedRefresh = screen->GetPageCount(); + V_SetBorderNeedRefresh(); } } @@ -1641,7 +1652,7 @@ void DBaseStatusBar::Serialize (FArchive &arc) void DBaseStatusBar::ScreenSizeChanged () { st_scale.Callback (); - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); for (unsigned int i = 0; i < countof(Messages); ++i) { diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 0a986495c..02db33d25 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -234,7 +234,7 @@ public: { if (state == HUD_Fullscreen) { - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); DrawFullScreenStuff (); } @@ -311,7 +311,7 @@ private: CursorImage = Images[imgINVCURS] != NULL ? imgINVCURS : imgCURSOR01; - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); CurrentPop = POP_None; PendingPop = POP_NoChange; diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 55d657b7c..a1870b4ae 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -168,7 +168,7 @@ void HU_DrawScores (player_t *player) HU_DoDrawScores (player, sortedplayers); - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } //========================================================================== diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index b6bd24ae3..e717aa3d2 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -88,7 +88,7 @@ void cht_DoCheat (player_t *player, int cheat) msg = GStrings("STSTR_DQDON"); else msg = GStrings("STSTR_DQDOFF"); - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); break; case CHT_BUDDHA: diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 78bdadf59..99ac59938 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -961,7 +961,7 @@ void DSaveMenu::DoSave (FSaveGameNode *node) G_SaveGame (filename, savegamestring); } M_ClearMenus(); - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } //============================================================================= @@ -1100,7 +1100,7 @@ bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller) quickSaveSlot = SaveGames[Selected]; } M_ClearMenus(); - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); LastAccessed = Selected; return true; } diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index e07bc142f..4b4b0c5e8 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -734,7 +734,7 @@ void M_ClearMenus () DMenu::CurrentMenu->Destroy(); DMenu::CurrentMenu = NULL; } - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); menuactive = MENU_Off; } diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index e7b6abcef..b94daae0a 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -179,8 +179,8 @@ void DMessageBoxMenu::Drawer () PalEntry fade = 0; int fontheight = SmallFont->GetHeight(); - //BorderNeedRefresh = screen->GetPageCount (); - //SB_state = screen->GetPageCount (); + //V_SetBorderNeedRefresh(); + //ST_SetNeedRefresh(); y = 100; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 46da3e225..b75811038 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -460,7 +460,7 @@ void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight) void R_ExecuteSetViewSize () { setsizeneeded = false; - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); R_SetWindow (setblocks, SCREENWIDTH, SCREENHEIGHT, ST_Y); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index dc890c12b..2f0c3e44a 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -268,7 +268,7 @@ void S_NoiseDebug (void) } chan = (FSoundChan *)((size_t)chan->PrevChan - myoffsetof(FSoundChan, NextChan)); } - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); } static FString LastLocalSndInfo; diff --git a/src/st_stuff.h b/src/st_stuff.h index bd42c9eda..aaa407585 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -29,7 +29,6 @@ struct event_t; extern int ST_X; extern int ST_Y; -extern int SB_state; bool ST_Responder(event_t* ev); // [RH] Base blending values (for e.g. underwater) diff --git a/src/stats.cpp b/src/stats.cpp index 76fe36c26..61b04f87f 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -94,7 +94,7 @@ void FStat::ToggleStat (const char *name) void FStat::ToggleStat () { m_Active = !m_Active; - SB_state = StatusBar == NULL ? 0 : screen->GetPageCount (); + ST_SetNeedRefresh(); } void FStat::PrintStat () @@ -124,7 +124,7 @@ void FStat::PrintStat () } if (count) { - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 87b4e0842..cd07b44a1 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -53,6 +53,7 @@ #include "gi.h" #include "g_level.h" #include "st_stuff.h" +#include "sbar.h" #include "i_system.h" #include "i_video.h" @@ -1377,8 +1378,32 @@ bool DCanvas::ClipBox (int &x, int &y, int &w, int &h, const BYTE *&src, const i return false; } +//========================================================================== +// +// V_SetBorderNeedRefresh +// +// Flag the border as in need of updating. (Probably because something that +// was on top of it has changed. +// +//========================================================================== + +void V_SetBorderNeedRefresh() +{ + if (screen != NULL) + { + BorderNeedRefresh = screen->GetPageCount(); + } +} + +//========================================================================== +// +// V_DrawFrame +// // Draw a frame around the specified area using the view border // frame graphics. The border is drawn outside the area, not in it. +// +//========================================================================== + void V_DrawFrame (int left, int top, int width, int height) { FTexture *p; @@ -1411,7 +1436,7 @@ void V_DrawFrame (int left, int top, int width, int height) //========================================================================== // -// +// V_DrawBorder // //========================================================================== @@ -1455,7 +1480,7 @@ static void V_DrawViewBorder (void) // Will draw borders around itself, too. if (SCREENWIDTH > 320) { - SB_state = screen->GetPageCount (); + ST_SetNeedRefresh(); } if (viewwidth == SCREENWIDTH) diff --git a/src/v_video.cpp b/src/v_video.cpp index e3a832dde..855b9fda3 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1605,7 +1605,7 @@ void V_Init2() FBaseCVar::ResetColors (); C_NewModeAdjust(); M_InitVideoModesMenu(); - BorderNeedRefresh = screen->GetPageCount (); + V_SetBorderNeedRefresh(); setsizeneeded = true; } diff --git a/src/v_video.h b/src/v_video.h index f6a1caeba..09022d9ff 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -485,6 +485,7 @@ void V_DrawFrame (int left, int top, int width, int height); void V_DrawBorder (int x1, int y1, int x2, int y2); void V_RefreshViewBorder (); +void V_SetBorderNeedRefresh(); #if defined(X86_ASM) || defined(X64_ASM) extern "C" void ASM_PatchPitch (void); diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 3598f52d1..648104271 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -66,7 +66,7 @@ #include "r_main.h" #include "r_data/r_translate.h" #include "f_wipe.h" -#include "st_stuff.h" +#include "sbar.h" #include "win32iface.h" #include "doomstat.h" #include "v_palette.h" @@ -225,7 +225,8 @@ const char *const D3DFB::ShaderNames[D3DFB::NUM_SHADERS] = CUSTOM_CVAR(Bool, vid_hw2d, true, CVAR_NOINITCALL) { - BorderNeedRefresh = SB_state = screen->GetPageCount(); + V_SetBorderNeedRefresh(); + ST_SetNeedRefresh(); } CVAR(Bool, d3d_antilag, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) From b93dfcf3cf676c3fd4e7fdb972a3408932761edd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 27 Feb 2013 03:13:55 +0000 Subject: [PATCH 235/387] - Fixed: G_DoLoadLevel() has a for loop where it resets player cameras that incremented and checked the wrong variable. SVN r4168 (trunk) --- src/g_level.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 3e54f5aa3..e01152924 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -927,7 +927,7 @@ void G_DoLoadLevel (int position, bool autosave) G_UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level. G_FinishTravel (); // For each player, if they are viewing through a player, make sure it is themselves. - for (int ii = 0; i < MAXPLAYERS; ++i) + for (int ii = 0; ii < MAXPLAYERS; ++ii) { if (playeringame[ii] && (players[ii].camera == NULL || players[ii].camera->player != NULL)) { From ce393687963b191b19db0e7080f4fb602c971211 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 27 Feb 2013 03:27:33 +0000 Subject: [PATCH 236/387] - Fixed: Players using colorsets instead of custom colors overrode their team colors. SVN r4169 (trunk) --- src/d_netinfo.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index ed6a4f7fc..ef8984931 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -223,6 +223,9 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet *s = clamp(ts + *s * 0.15f - 0.075f, 0.f, 1.f); *v = clamp(tv + *v * 0.5f - 0.25f, 0.f, 1.f); + + // Make sure not to pass back any colorset in teamplay. + colorset = NULL; } if (set != NULL) { From 33f363f4c672a7cde9a9da9e58573af4198ac2c6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 27 Feb 2013 10:35:44 +0000 Subject: [PATCH 237/387] - added TheFortuneTeller's NORANDOMPUFFZ submission. SVN r4170 (trunk) --- src/p_local.h | 13 ++++++++++--- src/p_map.cpp | 23 +++++++++++++---------- src/p_mobj.cpp | 5 +++-- wadsrc/static/actors/constants.txt | 6 ++++-- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index f1dd56f19..0c16373bc 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -128,7 +128,8 @@ enum EPuffFlags PF_HITTHING = 1, PF_MELEERANGE = 2, PF_TEMPORARY = 4, - PF_HITTHINGBLEED = 8 + PF_HITTHINGBLEED = 8, + PF_NORANDOMZ = 16 }; AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0); @@ -453,8 +454,14 @@ enum // P_AimLineAttack flags ALF_NOFRIENDS = 16, }; -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); +enum // P_LineAttack flags +{ + LAF_ISMELEEATTACK = 1, + LAF_NORANDOMPUFFZ = 2 +}; + +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, 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 233d45285..4777d7e9c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3467,7 +3467,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, AActor **victim) + int pitch, int damage, FName damageType, const PClass *pufftype, int flags, AActor **victim) { fixed_t vx, vy, vz, shootz; FTraceResults trace; @@ -3476,8 +3476,10 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, bool hitGhosts; bool killPuff = false; AActor *puff = NULL; - int flags = ismeleeattack? PF_MELEERANGE : 0; int pflag = 0; + int puffFlags = (flags & LAF_ISMELEEATTACK)? PF_MELEERANGE : 0; + if (flags & LAF_NORANDOMPUFFZ) + puffFlags |= PF_NORANDOMZ; if (victim != NULL) { @@ -3539,7 +3541,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } if (puffDefaults->flags3 & MF3_ALWAYSPUFF) { // Spawn the puff anyway - puff = P_SpawnPuff (t1, pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, flags); + puff = P_SpawnPuff (t1, pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, puffFlags); } else { @@ -3558,7 +3560,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t closer = trace.Distance - 4*FRACUNIT; puff = P_SpawnPuff (t1, pufftype, t1->x + FixedMul (vx, closer), t1->y + FixedMul (vy, closer), - shootz + FixedMul (vz, closer), angle - ANG90, 0, flags); + shootz + FixedMul (vz, closer), angle - ANG90, 0, puffFlags); } // [RH] Spawn a decal @@ -3619,10 +3621,10 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, (trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) { if (!(trace.Actor->flags & MF_NOBLOOD)) - flags |= PF_HITTHINGBLEED; + puffFlags |= PF_HITTHINGBLEED; // We must pass the unreplaced puff type here - puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING); + puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags|PF_HITTHING); } // Allow puffs to inflict poison damage, so that hitscans can poison, too. @@ -3648,7 +3650,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, { // Since the puff is the damage inflictor we need it here // regardless of whether it is displayed or not. - puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY); + puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags|PF_HITTHING|PF_TEMPORARY); killPuff = true; } newdam = P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); @@ -3694,7 +3696,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, if (puff == NULL) { // Spawn puff just to get a mass for the splash - puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY); + puff = P_SpawnPuff (t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags|PF_HITTHING|PF_TEMPORARY); killPuff = true; } SpawnDeepSplash (t1, trace, puff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL); @@ -3709,7 +3711,7 @@ 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, AActor **victim) + int pitch, int damage, FName damageType, FName pufftype, int flags, AActor **victim) { const PClass * type = PClass::FindClass(pufftype); if (victim != NULL) @@ -3722,7 +3724,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } else { - return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack, victim); + return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, flags, victim); } return NULL; } @@ -4009,6 +4011,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color fixed_t x, y, z; bool spawnpuff; bool bleed = false; + int puffflags = PF_HITTHING; x = x1 + FixedMul (RailHits[i].Distance, vx); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a1c8cd00c..075d130c3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4738,8 +4738,9 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags) { AActor *puff; - - z += pr_spawnpuff.Random2 () << 10; + + if (!(flags & PF_NORANDOMZ)) + z += pr_spawnpuff.Random2 () << 10; puff = Spawn (pufftype, x, y, z, ALLOW_REPLACE); if (puff == NULL) return NULL; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 3280f53d2..c7e831a88 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -27,6 +27,7 @@ const int CBAF_AIMFACING = 1; const int CBAF_NORANDOM = 2; const int CBAF_EXPLICITANGLE = 4; const int CBAF_NOPITCH = 8; +const int CBAF_NORANDOMPUFFZ = 16; // Flags for A_GunFlash const int GFF_NOEXTCHANGE = 1; @@ -37,6 +38,7 @@ const int FBF_NORANDOM = 2; const int FBF_EXPLICITANGLE = 4; const int FBF_NOPITCH = 8; const int FBF_NOFLASH = 16; +const int FBF_NORANDOMPUFFZ = 32; // Flags for A_SpawnItemEx const int SXF_TRANSFERTRANSLATION=1; @@ -150,10 +152,10 @@ const int SMF_CURSPEED = 4; const int CPF_USEAMMO = 1; const int CPF_DAGGER = 2; const int CPF_PULLIN = 4; +const int CPF_NORANDOMPUFFZ = 8; // Flags for A_Teleport -const int TF_TELEFRAG = 1; -const int TF_RANDOMDECIDE = 2; +const int TF_TELEFRAG = 1;const int TF_RANDOMDECIDE = 2; // Flags for A_WolfAttack const int WAF_NORANDOM = 1; From 8f7cd73a41ae5d43dbb9e15a89809a03ca4a204e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 2 Mar 2013 01:27:36 +0000 Subject: [PATCH 238/387] - Comment out star and bstar stuff in wi_stuff.cpp. SVN r4171 (trunk) --- src/wi_stuff.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 41981c45f..db462c367 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -253,8 +253,8 @@ static FTexture* sucks; static FTexture* killers; // "killers", "victims" static FTexture* victims; static FTexture* total; // "Total", your face, your dead face -static FTexture* star; -static FTexture* bstar; +//static FTexture* star; +//static FTexture* bstar; static FTexture* p; // Player graphic static FTexture* lnames[2]; // Name graphics of each level (centered) @@ -1995,10 +1995,11 @@ void WI_loadData(void) killers = TexMan["WIKILRS"]; // "killers" (vertical] victims = TexMan["WIVCTMS"]; // "victims" (horiz] total = TexMan["WIMSTT"]; // "total" - star = TexMan["STFST01"]; // your face - bstar = TexMan["STFDEAD0"]; // dead face +// star = TexMan["STFST01"]; // your face +// bstar = TexMan["STFDEAD0"]; // dead face p = TexMan["STPBANY"]; } +#if 0 else if (gameinfo.gametype & GAME_Raven) { if (gameinfo.gametype == GAME_Heretic) @@ -2017,6 +2018,7 @@ void WI_loadData(void) star = BigFont->GetChar('*', NULL); bstar = star; } +#endif // Use the local level structure which can be overridden by hubs lnametexts[0] = level.LevelName; From 1107bebfcfef572f4abf0dd61c3f875790388815 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 2 Mar 2013 01:54:40 +0000 Subject: [PATCH 239/387] - Redo r4164 fix: Don't clear fake planes when clearing skybox planes. SVN r4172 (trunk) --- src/r_3dfloors.cpp | 2 -- src/r_plane.cpp | 42 ++++++++++++++++++++++++++++++++++-------- src/r_polymost.cpp | 2 +- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/r_3dfloors.cpp b/src/r_3dfloors.cpp index 412a6057a..fbdc34edc 100644 --- a/src/r_3dfloors.cpp +++ b/src/r_3dfloors.cpp @@ -140,7 +140,6 @@ void R_3D_EnterSkybox() height_top = NULL; height_cur = NULL; height_max = -1; - fakeActive = 0; CurrentSkybox++; } @@ -158,7 +157,6 @@ void R_3D_LeaveSkybox() height_top = current.height_top; height_cur = current.height_cur; height_max = current.height_max; - fakeActive = height_top != NULL; CurrentSkybox--; } diff --git a/src/r_plane.cpp b/src/r_plane.cpp index d3c5f8c94..16e9b12e2 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -492,13 +492,39 @@ void R_ClearPlanes (bool fullclear) { int i, max; - // kg3D - we can't just clear planes if there are fake planes - if(!fullclear && fakeActive) return; - - max = fullclear ? MAXVISPLANES : MAXVISPLANES-1; - for (i = 0; i <= max; i++) // new code -- killough - for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; ) - freehead = &(*freehead)->next; + // Don't clear fake planes if not doing a full clear. + if (!fullclear) + { + for (i = 0; i <= MAXVISPLANES-1; i++) // new code -- killough + { + for (visplane_t **probe = &visplanes[i]; *probe != NULL; ) + { + if ((*probe)->sky < 0) + { // fake: move past it + probe = &(*probe)->next; + } + else + { // not fake: move to freelist + visplane_t *vis = *probe; + *freehead = vis; + *probe = vis->next; + vis->next = NULL; + freehead = &vis->next; + } + } + } + } + else + { + max = fullclear ? MAXVISPLANES : MAXVISPLANES-1; + for (i = 0; i <= MAXVISPLANES; i++) // new code -- killough + { + for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; ) + { + freehead = &(*freehead)->next; + } + } + } if (fullclear) { @@ -597,7 +623,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl skybox = NULL; alpha = FRACUNIT; } - + // New visplane algorithm uses hash table -- killough hash = isskybox ? MAXVISPLANES : visplane_hash (picnum.GetIndex(), lightlevel, height); diff --git a/src/r_polymost.cpp b/src/r_polymost.cpp index 92cec1a6e..e7963faa2 100644 --- a/src/r_polymost.cpp +++ b/src/r_polymost.cpp @@ -1430,7 +1430,7 @@ void RP_Subsector (subsector_t *sub) frontsector->ceiling_yscale, frontsector->ceiling_angle + frontsector->base_ceiling_angle, frontsector->sky, - frontsector->CeilingSkyBox + frontsector->CeilingSkyBox, ) : NULL;*/ basecolormap = frontsector->ColorMap; From 88a0d22f238637d6673926dbcf49ef7e5860185b Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 3 Mar 2013 19:12:21 +0000 Subject: [PATCH 240/387] - Fixed: Playing strife forced the inventory to be used immediately instead of being determined by the presence of an inventory overlay. SVN r4173 (trunk) --- src/g_game.cpp | 2 +- src/g_strife/strife_sbar.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 48c4a3b7a..1f039763b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -414,7 +414,7 @@ CCMD (invuseall) CCMD (invuse) { - if (players[consoleplayer].inventorytics == 0 || gameinfo.gametype == GAME_Strife) + if (players[consoleplayer].inventorytics == 0) { if (players[consoleplayer].mo) SendItemUse = players[consoleplayer].mo->InvSel; } diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 02db33d25..1a355b90a 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -445,6 +445,7 @@ private: } // Inventory + CPlayer->inventorytics = 0; CPlayer->mo->InvFirst = ValidateInvFirst (6); for (item = CPlayer->mo->InvFirst, i = 0; item != NULL && i < 6; item = item->NextInv(), ++i) { From 478bfa6cf1e34d5bf57a69f847066d441bd477dc Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Thu, 7 Mar 2013 22:16:09 +0000 Subject: [PATCH 241/387] - Fixed: file_directory tried to free it's input parameter. SVN r4174 (trunk) --- src/resourcefiles/file_directory.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 420b7dde3..e9076ae9b 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -118,7 +118,6 @@ FDirectory::FDirectory(const char * directory) dirname = directory; dirname.ReplaceChars('\\', '/'); if (dirname[dirname.Len()-1] != '/') dirname += '/'; - free((void*)directory); Filename = copystring(dirname); } @@ -336,7 +335,6 @@ FileReader *FDirectoryLump::NewReader() { FString fullpath = Owner->Filename; fullpath += FullName; - printf("%s\n", fullpath.GetChars()); return new FileReader(fullpath); } catch (CRecoverableError &) From ba0e0c2914c0b76d4b2e5edf744ba8e949b5cf9a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 8 Mar 2013 02:34:26 +0000 Subject: [PATCH 242/387] - Fixed: Don't start the MAPINFO music just to have it replaced by the saved music when returning to a level in a hub. SVN r4175 (trunk) --- src/s_sound.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 2f0c3e44a..175ea7749 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -446,8 +446,9 @@ void S_Start () // start new music for the level MusicPaused = false; - // [RH] This is a lot simpler now. - if (!savegamerestore) + // Don't start the music if loading a savegame, because the music is stored there. + // Don't start the music if revisiting a level in a hub for the same reason. + if (!savegamerestore && (level.info->snapshot == NULL || !level.info->isValid())) { if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid)) S_ChangeMusic (level.Music, level.musicorder); From 3fe31668a6d80cd622793c7c53fe5615df195b43 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 8 Mar 2013 19:23:06 +0000 Subject: [PATCH 243/387] - More Visual Studio with CMake fixes. SVN r4176 (trunk) --- src/CMakeLists.txt | 4 ++++ wadsrc/CMakeLists.txt | 1 + 2 files changed, 5 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67993f4e0..d53304936 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -989,3 +989,7 @@ if( CMAKE_COMPILER_IS_GNUCXX ) set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" ) endif( SSE_MATTERS ) endif( CMAKE_COMPILER_IS_GNUCXX ) + +if( MSVC ) + set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO") +endif( MSVC ) diff --git a/wadsrc/CMakeLists.txt b/wadsrc/CMakeLists.txt index a24d712e1..422052511 100644 --- a/wadsrc/CMakeLists.txt +++ b/wadsrc/CMakeLists.txt @@ -4,6 +4,7 @@ get_target_property(ZIPDIR_EXE zipdir LOCATION) add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 $ DEPENDS zipdir ${CMAKE_CURRENT_SOURCE_DIR}/static ) add_custom_target( pk3 ALL From c7aa7e2a4ba1bef4c88910a6a212d3f7f5139c75 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Mar 2013 07:09:40 +0000 Subject: [PATCH 244/387] - missing NORANDOMPUFFZ code. SVN r4177 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index efba0cb4a..c86c78a15 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1041,6 +1041,7 @@ enum CBA_Flags CBAF_NORANDOM = 2, CBAF_EXPLICITANGLE = 4, CBAF_NOPITCH = 8, + CBAF_NORANDOMPUFFZ = 16, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) @@ -1059,6 +1060,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) int i; int bangle; int bslope = 0; + int laflags = (Flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; if (self->target || (Flags & CBAF_AIMFACING)) { @@ -1091,7 +1093,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) if (!(Flags & CBAF_NORANDOM)) damage *= ((pr_cabullet()%3)+1); - P_LineAttack(self, angle, Range, slope, damage, NAME_Hitscan, pufftype); + P_LineAttack(self, angle, Range, slope, damage, NAME_Hitscan, pufftype, laflags); } } } @@ -1206,6 +1208,7 @@ enum FB_Flags FBF_EXPLICITANGLE = 4, FBF_NOPITCH = 8, FBF_NOFLASH = 16, + FBF_NORANDOMPUFFZ = 32, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) @@ -1227,6 +1230,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) int i; int bangle; int bslope = 0; + int laflags = (Flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; if ((Flags & FBF_USEAMMO) && weapon) { @@ -1251,7 +1255,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if (!(Flags & FBF_NORANDOM)) damage *= ((pr_cwbullet()%3)+1); - P_LineAttack(self, bangle, Range, bslope, damage, NAME_Hitscan, PuffType); + P_LineAttack(self, bangle, Range, bslope, damage, NAME_Hitscan, PuffType, laflags); } else { @@ -1277,7 +1281,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if (!(Flags & FBF_NORANDOM)) damage *= ((pr_cwbullet()%3)+1); - P_LineAttack(self, angle, Range, slope, damage, NAME_Hitscan, PuffType); + P_LineAttack(self, angle, Range, slope, damage, NAME_Hitscan, PuffType, laflags); } } } @@ -1358,6 +1362,7 @@ enum CPF_USEAMMO = 1, CPF_DAGGER = 2, CPF_PULLIN = 4, + CPF_NORANDOMPUFFZ = 8, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) @@ -1393,8 +1398,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) } if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); + int puffFlags = LAF_ISMELEEATTACK | (flags & CPF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, true, &linetarget); + P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget); // turn to face target if (linetarget) From e240d24abebc21701d7b098ce3700370af63e4de Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 13 Mar 2013 02:56:54 +0000 Subject: [PATCH 245/387] - Fixed: P_SpawnPlayerMissile() should not 0 the pitch for weapons that don't autoaim. This allows A_FireOldBFG to work properly when freelook is disabled. SVN r4178 (trunk) --- src/p_mobj.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 075d130c3..f07ab0ff1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5628,7 +5628,9 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, if (source && source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM)) { // Keep exactly the same angle and pitch as the player's own aim - pitch = source->pitch; linetarget = NULL; + an = angle; + pitch = source->pitch; + linetarget = NULL; } else // see which target is to be aimed at { @@ -5646,14 +5648,14 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, break; } } while (linetarget == NULL && --i >= 0); - } - if (linetarget == NULL) - { - an = angle; - if (nofreeaim || !level.IsFreelookAllowed()) + if (linetarget == NULL) { - pitch = 0; + an = angle; + if (nofreeaim || !level.IsFreelookAllowed()) + { + pitch = 0; + } } } if (pLineTarget) *pLineTarget = linetarget; From fb2f201c8b6a6e70df3f54638940397a3e53f11d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 13 Mar 2013 03:59:57 +0000 Subject: [PATCH 246/387] - Fixed: The sc_man scanner must use an unsigned character type, or it won't properly recognize any unquoted characters with the eighth bit set. SVN r4179 (trunk) --- src/sc_man_scanner.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 66058ac8c..dd90ce1d1 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -1,4 +1,4 @@ -#define YYCTYPE char +#define YYCTYPE unsigned char #define YYCURSOR cursor #define YYLIMIT limit #define YYMARKER marker From 8410ac760aa69239f175d871d1a96bcc2c4aab67 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 13 Mar 2013 04:04:48 +0000 Subject: [PATCH 247/387] - Added A_SetDamageType. SVN r4180 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 16 +++++++++++++++- wadsrc/static/actors/actor.txt | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c86c78a15..e57f58fb2 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4509,4 +4509,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) ACTION_PARAM_INT(tics_to_set, 0); self->tics = tics_to_set; -} \ No newline at end of file +} + +//========================================================================== +// +// A_SetDamageType +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) +{ + ACTION_PARAM_START(1); + ACTION_PARAM_NAME(damagetype, 0); + + self->DamageType = damagetype; +} diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index f7ee26769..b4024878f 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -295,6 +295,7 @@ ACTOR Actor native //: Thinker action native A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); action native A_SetTics(int tics); + action native A_SetDamageType(name damagetype); action native A_CheckSightOrRange(float distance, state label); From b0203c9f1d2ad985f853b6958cbdc068a1b6f80b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 13 Mar 2013 11:27:30 +0000 Subject: [PATCH 248/387] - added Xaser's SXF_USEBLOODCOLOR for A_SpawnItemEx submission SVN r4181 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 15 +++++++++++++-- wadsrc/static/actors/constants.txt | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e57f58fb2..c1ff7853d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -68,6 +68,7 @@ #include "g_shared/a_specialspot.h" #include "actorptrselect.h" #include "m_bbox.h" +#include "r_data/r_translate.h" static FRandom pr_camissile ("CustomActorfire"); @@ -1729,6 +1730,7 @@ enum SIX_Flags SIXF_TRANSFERAMBUSHFLAG=256, SIXF_TRANSFERPITCH=512, SIXF_TRANSFERPOINTERS=1024, + SIXF_USEBLOODCOLOR=2048, }; @@ -1738,9 +1740,18 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) { AActor * originator = self; - if ((flags & SIXF_TRANSFERTRANSLATION) && !(mo->flags2 & MF2_DONTTRANSLATE)) + if (!(mo->flags2 & MF2_DONTTRANSLATE)) { - mo->Translation = self->Translation; + if (flags & SIXF_TRANSFERTRANSLATION) + { + mo->Translation = self->Translation; + } + else if (flags & SIXF_USEBLOODCOLOR) + { + // [XA] Use the spawning actor's BloodColor to translate the newly-spawned object. + PalEntry bloodcolor = self->GetBloodColor(); + mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + } } if (flags & SIXF_TRANSFERPOINTERS) { diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index c7e831a88..07dbeda7d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -53,6 +53,7 @@ const int SXF_CLIENTSIDE=128; // only used by Skulltag const int SXF_TRANSFERAMBUSHFLAG=256; const int SXF_TRANSFERPITCH=512; const int SXF_TRANSFERPOINTERS=1024; +const int SXF_USEBLOODCOLOR=2048; // Flags for A_Chase const int CHF_FASTCHASE = 1; From b096c7a82fc0f02726b5965dcf321915f216d371 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 15 Mar 2013 21:41:01 +0000 Subject: [PATCH 249/387] - Fixed: changemap allowed changing the map in "demo mode." - Fixed: Crash when using the console at the title screen. SVN r4182 (trunk) --- src/c_cmds.cpp | 2 +- src/s_sound.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index f6bd01a20..87f63ead4 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -329,7 +329,7 @@ CCMD (hxvisit) CCMD (changemap) { - if (who == NULL) + if (who == NULL || !usergame) { Printf ("Use the map command when not in a game.\n"); return; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 175ea7749..3da346bf3 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -448,7 +448,7 @@ void S_Start () // Don't start the music if loading a savegame, because the music is stored there. // Don't start the music if revisiting a level in a hub for the same reason. - if (!savegamerestore && (level.info->snapshot == NULL || !level.info->isValid())) + if (!savegamerestore && (level.info == NULL || level.info->snapshot == NULL || !level.info->isValid())) { if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid)) S_ChangeMusic (level.Music, level.musicorder); From 573b6992ce2799758b5014577c25df70a42bc056 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 17 Mar 2013 02:41:45 +0000 Subject: [PATCH 250/387] - Use a TArray for backing up cvars overwritten by a demo. SVN r4184 (trunk) --- src/c_cvars.cpp | 48 ++++++++++++++++-------------------------------- src/c_cvars.h | 4 ---- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 51413c37d..f63b74bd2 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1390,58 +1390,42 @@ void C_ReadCVars (BYTE **demo_p) *demo_p += strlen (*((char **)demo_p)) + 1; } -static struct backup_s +struct FCVarBackup { - char *name, *string; -} CVarBackups[MAX_DEMOCVARS]; - -static int numbackedup = 0; + FString Name, String; +}; +static TArray CVarBackups; void C_BackupCVars (void) { - struct backup_s *backup = CVarBackups; - FBaseCVar *cvar = CVars; + assert(CVarBackups.Size() == 0); + CVarBackups.Clear(); - while (cvar) + FCVarBackup backup; + + for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) - && !(cvar->Flags & CVAR_LATCH)) + if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) && !(cvar->Flags & CVAR_LATCH)) { - if (backup == &CVarBackups[MAX_DEMOCVARS]) - I_Error ("C_BackupDemoCVars: Too many cvars to save (%d)", MAX_DEMOCVARS); - backup->name = copystring (cvar->GetName()); - backup->string = copystring (cvar->GetGenericRep (CVAR_String).String); - backup++; + backup.Name = cvar->GetName(); + backup.String = cvar->GetGenericRep(CVAR_String).String; + CVarBackups.Push(backup); } - cvar = cvar->m_Next; } - numbackedup = int(backup - CVarBackups); } void C_RestoreCVars (void) { - struct backup_s *backup = CVarBackups; - int i; - - for (i = numbackedup; i; i--, backup++) + for (unsigned int i = 0; i < CVarBackups.Size(); ++i) { - cvar_set (backup->name, backup->string); + cvar_set(CVarBackups[i].Name, CVarBackups[i].String); } C_ForgetCVars(); } void C_ForgetCVars (void) { - struct backup_s *backup = CVarBackups; - int i; - - for (i = numbackedup; i; i--, backup++) - { - delete[] backup->name; - delete[] backup->string; - backup->name = backup->string = NULL; - } - numbackedup = 0; + CVarBackups.Clear(); } FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev) diff --git a/src/c_cvars.h b/src/c_cvars.h index d0ac84fe5..b5b0c6ccf 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -404,10 +404,6 @@ inline FBaseCVar *cvar_forceset (const char *var_name, const BYTE *value) { retu -// Maximum number of cvars that can be saved across a demo. If you need -// to save more, bump this up. -#define MAX_DEMOCVARS 32 - // Restore demo cvars. Called after demo playback to restore all cvars // that might possibly have been changed during the course of demo playback. void C_RestoreCVars (void); From 98ea4d3d5182b6de0bafb281e3bd4db23fb15437 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 17 Mar 2013 03:04:17 +0000 Subject: [PATCH 251/387] - Added C_GetMassCVarString(), which C_WriteCVars() is now a wrapper around. (And the latter should probably be factored away eventually.) SVN r4185 (trunk) --- src/c_cvars.cpp | 46 +++++++++++++++++++++++++--------------------- src/c_cvars.h | 6 +++++- src/g_game.cpp | 7 ++----- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index f63b74bd2..b07baa6da 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1274,52 +1274,56 @@ static int STACK_ARGS sortcvars (const void *a, const void *b) void FilterCompactCVars (TArray &cvars, DWORD filter) { - FBaseCVar *cvar = CVars; - while (cvar) + // Accumulate all cvars that match the filter flags. + for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { if (cvar->Flags & filter) - cvars.Push (cvar); - cvar = cvar->m_Next; + cvars.Push(cvar); } - if (cvars.Size () > 0) + // Now sort them, so they're in a deterministic order and not whatever + // order the linker put them in. + if (cvars.Size() > 0) { - cvars.ShrinkToFit (); - qsort (&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); + qsort(&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); } } void C_WriteCVars (BYTE **demo_p, DWORD filter, bool compact) { - FBaseCVar *cvar = CVars; - BYTE *ptr = *demo_p; + FString dump = C_GetMassCVarString(filter, compact); + size_t dumplen = dump.Len() + 1; // include terminating \0 + memcpy(*demo_p, dump.GetChars(), dumplen); + *demo_p += dumplen; +} + +FString C_GetMassCVarString (DWORD filter, bool compact) +{ + FBaseCVar *cvar; + FString dump; if (compact) { TArray cvars; - ptr += sprintf ((char *)ptr, "\\\\%ux", filter); - FilterCompactCVars (cvars, filter); + dump.AppendFormat("\\\\%ux", filter); + FilterCompactCVars(cvars, filter); while (cvars.Pop (cvar)) { - UCVarValue val = cvar->GetGenericRep (CVAR_String); - ptr += sprintf ((char *)ptr, "\\%s", val.String); + UCVarValue val = cvar->GetGenericRep(CVAR_String); + dump << '\\' << val.String; } } else { - cvar = CVars; - while (cvar) + for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSAVE)) { - UCVarValue val = cvar->GetGenericRep (CVAR_String); - ptr += sprintf ((char *)ptr, "\\%s\\%s", - cvar->GetName (), val.String); + UCVarValue val = cvar->GetGenericRep(CVAR_String); + dump << '\\' << cvar->GetName() << '\\' << val.String; } - cvar = cvar->m_Next; } } - - *demo_p = ptr + 1; + return dump; } void C_ReadCVars (BYTE **demo_p) diff --git a/src/c_cvars.h b/src/c_cvars.h index b5b0c6ccf..9c7873802 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -150,7 +150,7 @@ private: static bool m_UseCallback; static bool m_DoNoSet; - friend void C_WriteCVars (BYTE **demo_p, uint32 filter, bool compact); + friend FString C_GetMassCVarString (uint32 filter, bool compact); friend void C_ReadCVars (BYTE **demo_p); friend void C_BackupCVars (void); friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); @@ -162,6 +162,10 @@ private: friend void C_DeinitConsole(); }; +// Returns a string with all cvars whose flags match filter. In compact mode, +// the cvar names are omitted to save space. +FString C_GetMassCVarString (uint32 filter, bool compact=false); + // Writes all cvars that could effect demo sync to *demo_p. These are // cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set. void C_WriteCVars (BYTE **demo_p, uint32 filter, bool compact=false); diff --git a/src/g_game.cpp b/src/g_game.cpp index 1f039763b..e9d11151c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2096,11 +2096,8 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio G_WriteHubInfo(stdfile); { - BYTE vars[4096], *vars_p; - vars_p = vars; - C_WriteCVars (&vars_p, CVAR_SERVERINFO); - *vars_p = 0; - M_AppendPNGText (stdfile, "Important CVARs", (char *)vars); + FString vars = C_GetMassCVarString(CVAR_SERVERINFO); + M_AppendPNGText (stdfile, "Important CVARs", vars.GetChars()); } if (level.time != 0 || level.maptime != 0) From 18bf56d3d72d5d01aeac223f042017e839847b38 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 18 Mar 2013 21:56:15 +0000 Subject: [PATCH 252/387] - Fixed: NULL pointer dereference in DrawGem. SVN r4186 (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 25ea27283..81609865a 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -3046,7 +3046,7 @@ class CommandDrawGem : public SBarInfoCommand } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { - goalValue = armor ? statusBar->armor->Amount : statusBar->CPlayer->mo->health; + goalValue = armor ? (statusBar->armor ? statusBar->armor->Amount : 0) : statusBar->CPlayer->mo->health; int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina; if(max != 0 && goalValue > 0) { From de20936b138f81414064dc2e3ec1d1959df1ecac Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Mar 2013 02:41:59 +0000 Subject: [PATCH 253/387] - Allow negative force for A_RadiusThrust. SVN r4187 (trunk) --- src/p_map.cpp | 7 ++++--- src/thingdef/thingdef_codeptr.cpp | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 4777d7e9c..7d3474cf1 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4478,7 +4478,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b AActor *thing; if (flags & RADF_SOURCEISSPOT) - { // The source is actually the same as the spot, even if that wasn't what we receized. + { // The source is actually the same as the spot, even if that wasn't what we received. bombsource = bombspot; } @@ -4567,11 +4567,12 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b } points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(double)FRACUNIT; - if (points > 0.f && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) + // points and bombdamage should be the same sign + if ((points * bombdamage) > 0 && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path double velz; double thrust; - int damage = (int)points; + int damage = abs((int)points); int newdam = damage; if (!(flags & RADF_NODAMAGE)) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c1ff7853d..542ab1698 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -838,8 +838,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) bool sourcenothrust = false; - if (force <= 0) force = 128; - if (distance <= 0) distance = force; + if (force == 0) force = 128; + if (distance <= 0) distance = abs(force); // Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless. if (!(flags & RTF_NOTMISSILE) && self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST) @@ -847,7 +847,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) sourcenothrust = true; self->target->flags2 &= ~MF2_NODMGTHRUST; } - int sourceflags2 = self->target != NULL ? self->target->flags2 : 0; P_RadiusAttack (self, self->target, force, distance, self->DamageType, flags | RADF_NODAMAGE, fullthrustdistance); P_CheckSplash(self, distance << FRACBITS); From 277d59b2bb7f1d0c503a77f7315670c0add4f2c1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Mar 2013 03:07:45 +0000 Subject: [PATCH 254/387] - Added flags SXF_CLEARCALLERTID, SXF_MULTIPLYSPEED, and SXF_TRANSFERSCALE for A_SpawnItemEx. SVN r4188 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 195 +++++++++++++++++------------ wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 27 ++-- 3 files changed, 133 insertions(+), 91 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 542ab1698..5516202b2 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1716,102 +1716,127 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) // Common code for A_SpawnItem and A_SpawnItemEx // //=========================================================================== + enum SIX_Flags { - SIXF_TRANSFERTRANSLATION=1, - SIXF_ABSOLUTEPOSITION=2, - SIXF_ABSOLUTEANGLE=4, - SIXF_ABSOLUTEVELOCITY=8, - SIXF_SETMASTER=16, - SIXF_NOCHECKPOSITION=32, - SIXF_TELEFRAG=64, - // 128 is used by Skulltag! - SIXF_TRANSFERAMBUSHFLAG=256, - SIXF_TRANSFERPITCH=512, - SIXF_TRANSFERPOINTERS=1024, - SIXF_USEBLOODCOLOR=2048, + SIXF_TRANSFERTRANSLATION = 1 << 0, + SIXF_ABSOLUTEPOSITION = 1 << 1, + SIXF_ABSOLUTEANGLE = 1 << 2, + SIXF_ABSOLUTEVELOCITY = 1 << 3, + SIXF_SETMASTER = 1 << 4, + SIXF_NOCHECKPOSITION = 1 << 5, + SIXF_TELEFRAG = 1 << 6, + SIXF_CLIENTSIDE = 1 << 7, // only used by Skulldronum + SIXF_TRANSFERAMBUSHFLAG = 1 << 8, + SIXF_TRANSFERPITCH = 1 << 9, + SIXF_TRANSFERPOINTERS = 1 << 10, + SIXF_USEBLOODCOLOR = 1 << 11, + SIXF_CLEARCALLERTID = 1 << 12, + SIXF_MULTIPLYSPEED = 1 << 13, + SIXF_TRANSFERSCALE = 1 << 14, }; - static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) { - if (mo) + if (mo == NULL) { - AActor * originator = self; + return false; + } + AActor *originator = self; - if (!(mo->flags2 & MF2_DONTTRANSLATE)) + if (!(mo->flags2 & MF2_DONTTRANSLATE)) + { + if (flags & SIXF_TRANSFERTRANSLATION) { - if (flags & SIXF_TRANSFERTRANSLATION) - { - mo->Translation = self->Translation; - } - else if (flags & SIXF_USEBLOODCOLOR) - { - // [XA] Use the spawning actor's BloodColor to translate the newly-spawned object. - PalEntry bloodcolor = self->GetBloodColor(); - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); - } + mo->Translation = self->Translation; } - if (flags & SIXF_TRANSFERPOINTERS) + else if (flags & SIXF_USEBLOODCOLOR) { - mo->target = self->target; - mo->master = self->master; // This will be overridden later if SIXF_SETMASTER is set - mo->tracer = self->tracer; + // [XA] Use the spawning actor's BloodColor to translate the newly-spawned object. + PalEntry bloodcolor = self->GetBloodColor(); + mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } + } + if (flags & SIXF_TRANSFERPOINTERS) + { + mo->target = self->target; + mo->master = self->master; // This will be overridden later if SIXF_SETMASTER is set + mo->tracer = self->tracer; + } - mo->angle=self->angle; - if (flags & SIXF_TRANSFERPITCH) mo->pitch = self->pitch; - while (originator && originator->isMissile()) originator = originator->target; + mo->angle = self->angle; + if (flags & SIXF_TRANSFERPITCH) + { + mo->pitch = self->pitch; + } + while (originator && originator->isMissile()) + { + originator = originator->target; + } - if (flags & SIXF_TELEFRAG) + if (flags & SIXF_TELEFRAG) + { + P_TeleportMove(mo, mo->x, mo->y, mo->z, true); + // This is needed to ensure consistent behavior. + // Otherwise it will only spawn if nothing gets telefragged + flags |= SIXF_NOCHECKPOSITION; + } + if (mo->flags3 & MF3_ISMONSTER) + { + if (!(flags & SIXF_NOCHECKPOSITION) && !P_TestMobjLocation(mo)) { - P_TeleportMove(mo, mo->x, mo->y, mo->z, true); - // This is needed to ensure consistent behavior. - // Otherwise it will only spawn if nothing gets telefragged - flags |= SIXF_NOCHECKPOSITION; + // The monster is blocked so don't spawn it at all! + mo->ClearCounters(); + mo->Destroy(); + return false; } - if (mo->flags3&MF3_ISMONSTER) + else if (originator) { - if (!(flags&SIXF_NOCHECKPOSITION) && !P_TestMobjLocation(mo)) + if (originator->flags3 & MF3_ISMONSTER) { - // The monster is blocked so don't spawn it at all! - mo->ClearCounters(); - mo->Destroy(); - return false; + // If this is a monster transfer all friendliness information + mo->CopyFriendliness(originator, true); + if (flags & SIXF_SETMASTER) mo->master = originator; // don't let it attack you (optional)! } - else if (originator) + else if (originator->player) { - if (originator->flags3&MF3_ISMONSTER) + // A player always spawns a monster friendly to him + mo->flags |= MF_FRIENDLY; + mo->SetFriendPlayer(originator->player); + + AActor * attacker=originator->player->attacker; + if (attacker) { - // If this is a monster transfer all friendliness information - mo->CopyFriendliness(originator, true); - if (flags&SIXF_SETMASTER) mo->master = originator; // don't let it attack you (optional)! - } - else if (originator->player) - { - // A player always spawns a monster friendly to him - mo->flags |= MF_FRIENDLY; - mo->SetFriendPlayer(originator->player); - - AActor * attacker=originator->player->attacker; - if (attacker) + if (!(attacker->flags&MF_FRIENDLY) || + (deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer)) { - if (!(attacker->flags&MF_FRIENDLY) || - (deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer)) - { - // Target the monster which last attacked the player - mo->LastHeard = mo->target = attacker; - } + // Target the monster which last attacked the player + mo->LastHeard = mo->target = attacker; } } } } - else if (!(flags & SIXF_TRANSFERPOINTERS)) - { - // If this is a missile or something else set the target to the originator - mo->target=originator? originator : self; - } } + else if (!(flags & SIXF_TRANSFERPOINTERS)) + { + // If this is a missile or something else set the target to the originator + mo->target = originator ? originator : self; + } + if (flags & SIXF_TRANSFERSCALE) + { + mo->scaleX = self->scaleX; + mo->scaleY = self->scaleY; + } + if (flags & SIXF_TRANSFERAMBUSHFLAG) + { + mo->flags = (mo->flags & ~MF_AMBUSH) | (self->flags & MF_AMBUSH); + } + if (flags & SIXF_CLEARCALLERTID) + { + self->RemoveFromHash(); + self->tid = 0; + } + return true; } @@ -1861,7 +1886,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]), self->z - self->floorclip + self->GetBobOffset() + zheight, ALLOW_REPLACE); - int flags = (transfer_translation? SIXF_TRANSFERTRANSLATION:0) + (useammo? SIXF_SETMASTER:0); + int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state } @@ -1875,7 +1900,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) { - ACTION_PARAM_START(10); + ACTION_PARAM_START(11); ACTION_PARAM_CLASS(missile, 0); ACTION_PARAM_FIXED(xofs, 1); ACTION_PARAM_FIXED(yofs, 2); @@ -1886,6 +1911,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) ACTION_PARAM_ANGLE(Angle, 7); ACTION_PARAM_INT(flags, 8); ACTION_PARAM_INT(chance, 9); + ACTION_PARAM_INT(tid, 10); if (!missile) { @@ -1928,17 +1954,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) xvel = newxvel; } - AActor * mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE); + AActor *mo = Spawn(missile, x, y, self->z - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE); bool res = InitSpawnedItem(self, mo, flags); ACTION_SET_RESULT(res); // for an inventory item's use state - if (mo) + if (res) { - mo->velx = xvel; - mo->vely = yvel; - mo->velz = zvel; + if (tid != 0) + { + assert(mo->tid == 0); + mo->tid = tid; + mo->AddToHash(); + } + if (flags & SIXF_MULTIPLYSPEED) + { + mo->velx = FixedMul(xvel, mo->Speed); + mo->vely = FixedMul(yvel, mo->Speed); + mo->velz = FixedMul(zvel, mo->Speed); + } + else + { + mo->velx = xvel; + mo->vely = yvel; + mo->velz = zvel; + } mo->angle = Angle; - if (flags & SIXF_TRANSFERAMBUSHFLAG) - mo->flags = (mo->flags&~MF_AMBUSH) | (self->flags & MF_AMBUSH); } } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b4024878f..eefd86545 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -210,7 +210,7 @@ ACTOR Actor native //: Thinker action native A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); action native A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); 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_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, int tid=0); action native A_Print(string whattoprint, float time = 0, string fontname = ""); action native A_PrintBold(string whattoprint, float time = 0, string fontname = ""); action native A_Log(string whattoprint); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 07dbeda7d..db4e9abbe 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -41,19 +41,22 @@ const int FBF_NOFLASH = 16; const int FBF_NORANDOMPUFFZ = 32; // Flags for A_SpawnItemEx -const int SXF_TRANSFERTRANSLATION=1; -const int SXF_ABSOLUTEPOSITION=2; -const int SXF_ABSOLUTEANGLE=4; -const int SXF_ABSOLUTEMOMENTUM=8; -const int SXF_ABSOLUTEVELOCITY=8; -const int SXF_SETMASTER=16; +const int SXF_TRANSFERTRANSLATION = 1; +const int SXF_ABSOLUTEPOSITION = 2; +const int SXF_ABSOLUTEANGLE = 4; +const int SXF_ABSOLUTEMOMENTUM = 8; +const int SXF_ABSOLUTEVELOCITY = 8; +const int SXF_SETMASTER = 16; const int SXF_NOCHECKPOSITION = 32; -const int SXF_TELEFRAG=64; -const int SXF_CLIENTSIDE=128; // only used by Skulltag -const int SXF_TRANSFERAMBUSHFLAG=256; -const int SXF_TRANSFERPITCH=512; -const int SXF_TRANSFERPOINTERS=1024; -const int SXF_USEBLOODCOLOR=2048; +const int SXF_TELEFRAG = 64; +const int SXF_CLIENTSIDE = 128; // only used by Skulltag +const int SXF_TRANSFERAMBUSHFLAG = 256; +const int SXF_TRANSFERPITCH = 512; +const int SXF_TRANSFERPOINTERS = 1024; +const int SXF_USEBLOODCOLOR = 2048; +const int SXF_CLEARCALLERTID = 4096; +const int SXF_MULTIPLYSPEED = 8192; +const int SXF_TRANSFERSCALE = 16384; // Flags for A_Chase const int CHF_FASTCHASE = 1; From fc4b0ffe684f54bdf4634d04c626f44fa2835612 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Mar 2013 03:19:02 +0000 Subject: [PATCH 255/387] - Use a missile's MaxTargetRange property as the range for P_AimLineAttack() inside P_SpawnPlayerMissile(). SVN r4189 (trunk) --- src/p_mobj.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f07ab0ff1..d36c27463 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5619,11 +5619,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, bool nofreeaim) { static const int angdiff[3] = { -1<<26, 1<<26, 0 }; - int i; angle_t an = angle; angle_t pitch; AActor *linetarget; - int vrange = nofreeaim? ANGLE_1*35 : 0; + AActor *defaultobject = GetDefaultByType(type); + int vrange = nofreeaim ? ANGLE_1*35 : 0; if (source && source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM)) { @@ -5634,11 +5634,16 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, } else // see which target is to be aimed at { - i = 2; + // [XA] If MaxTargetRange is defined in the spawned projectile, use this as the + // maximum range for the P_AimLineAttack call later; this allows MaxTargetRange + // to function as a "maximum tracer-acquisition range" for seeker missiles. + fixed_t linetargetrange = defaultobject->maxtargetrange > 0 ? defaultobject->maxtargetrange*64 : 16*64*FRACUNIT; + + int i = 2; do { an = angle + angdiff[i]; - pitch = P_AimLineAttack (source, an, 16*64*FRACUNIT, &linetarget, vrange); + pitch = P_AimLineAttack (source, an, linetargetrange, &linetarget, vrange); if (source->player != NULL && !nofreeaim && @@ -5660,8 +5665,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, } if (pLineTarget) *pLineTarget = linetarget; - i = GetDefaultByType (type)->flags3; - if (z != ONFLOORZ && z != ONCEILINGZ) { // Doom spawns missiles 4 units lower than hitscan attacks for players. From 283ee1a891f34b75d23fb53e14d445a5fca56405 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Mar 2013 03:21:37 +0000 Subject: [PATCH 256/387] - Make teleport fogs target the teleported actor. SVN r4190 (trunk) --- src/p_teleport.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 79dd105f9..50470d9eb 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -184,14 +184,16 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, if (sourceFog) { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; - Spawn (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE); + AActor *fog = Spawn (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE); + fog->target = thing; } if (useFog) { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; an = angle >> ANGLETOFINESHIFT; - Spawn (x + 20*finecosine[an], + AActor *fog = Spawn (x + 20*finecosine[an], y + 20*finesine[an], thing->z + fogDelta, ALLOW_REPLACE); + fog->target = thing; if (thing->player) { // [RH] Zoom player's field of vision From 53e73783e01db94c165e2f8541a2cb9d2b0163ae Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Mar 2013 03:36:45 +0000 Subject: [PATCH 257/387] - Added spawnofs_z parameter to A_RailAttack and A_CustomRailgun. SVN r4191 (trunk) --- src/g_doom/a_doomweaps.cpp | 4 ++-- src/p_local.h | 2 +- src/p_map.cpp | 8 ++++---- src/thingdef/thingdef_codeptr.cpp | 10 ++++++---- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/shared/inventory.txt | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 0063e72c9..07b7c0f56 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -467,7 +467,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma) // // [RH] A_FireRailgun // -static void FireRailgun(AActor *self, int RailOffset) +static void FireRailgun(AActor *self, int offset_xy) { int damage; player_t *player; @@ -492,7 +492,7 @@ static void FireRailgun(AActor *self, int RailOffset) damage = deathmatch ? 100 : 150; - P_RailAttack (self, damage, RailOffset); + P_RailAttack (self, damage, offset_xy); } diff --git a/src/p_local.h b/src/p_local.h index 0c16373bc..fe149d431 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -469,7 +469,7 @@ void P_TraceBleed (int damage, AActor *target); // random direction version 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); -void P_RailAttack (AActor *source, int damage, int offset, int color1 = 0, int color2 = 0, float maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL); // [RH] Shoot a railgun +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, float maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, float sparsity = 1.0, float drift = 1.0, const PClass *spawnclass = NULL); // [RH] Shoot a railgun enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags { diff --git a/src/p_map.cpp b/src/p_map.cpp index 7d3474cf1..c31e66367 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3942,7 +3942,7 @@ static bool ProcessNoPierceRailHit (FTraceResults &res) // // //========================================================================== -void P_RailAttack (AActor *source, int damage, int offset, int color1, int color2, float maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, float sparsity, float drift, const PClass *spawnclass) +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, float maxdiff, int railflags, const PClass *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, float sparsity, float drift, const PClass *spawnclass) { fixed_t vx, vy, vz; angle_t angle, pitch; @@ -3963,7 +3963,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color x1 = source->x; y1 = source->y; - shootz = source->z - source->floorclip + (source->height >> 1); + shootz = source->z - source->floorclip + (source->height >> 1) + offset_z; if (!(railflags & RAF_CENTERZ)) { @@ -3978,8 +3978,8 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color } angle = ((source->angle + angleoffset) - ANG90) >> ANGLETOFINESHIFT; - x1 += offset*finecosine[angle]; - y1 += offset*finesine[angle]; + x1 += offset_xy * finecosine[angle]; + y1 += offset_xy * finesine[angle]; RailHits.Clear (); start.X = FIXED2FLOAT(x1); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 5516202b2..ccb7f5961 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1429,7 +1429,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) //========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) { - ACTION_PARAM_START(15); + ACTION_PARAM_START(16); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_BOOL(UseAmmo, 2); @@ -1445,6 +1445,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) ACTION_PARAM_FLOAT(Sparsity, 12); ACTION_PARAM_FLOAT(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); + ACTION_PARAM_FIXED(Spawnofs_Z, 15); if(Range==0) Range=8192*FRACUNIT; if(Sparsity==0) Sparsity=1.0; @@ -1473,7 +1474,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) slope = pr_crailgun.Random2() * (Spread_Z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, Flags, PuffType, angle, slope, Range, Duration, Sparsity, DriftSpeed, SpawnClass); + P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angle, slope, Range, Duration, Sparsity, DriftSpeed, SpawnClass); } //========================================================================== @@ -1491,7 +1492,7 @@ enum DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) { - ACTION_PARAM_START(15); + ACTION_PARAM_START(16); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_INT(Spawnofs_XY, 1); ACTION_PARAM_COLOR(Color1, 2); @@ -1507,6 +1508,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) ACTION_PARAM_FLOAT(Sparsity, 12); ACTION_PARAM_FLOAT(DriftSpeed, 13); ACTION_PARAM_CLASS(SpawnClass, 14); + ACTION_PARAM_FIXED(Spawnofs_Z, 15); if(Range==0) Range=8192*FRACUNIT; if(Sparsity==0) Sparsity=1.0; @@ -1590,7 +1592,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) slopeoffset = pr_crailgun.Random2() * (Spread_Z / 255); } - P_RailAttack (self, Damage, Spawnofs_XY, Color1, Color2, MaxDiff, Flags, PuffType, angleoffset, slopeoffset, Range, Duration, Sparsity, DriftSpeed, SpawnClass); + P_RailAttack (self, Damage, Spawnofs_XY, Spawnofs_Z, Color1, Color2, MaxDiff, Flags, PuffType, angleoffset, slopeoffset, Range, Duration, Sparsity, DriftSpeed, SpawnClass); self->x = saved_x; self->y = saved_y; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index eefd86545..ab0898fa3 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -198,7 +198,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", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none"); + 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, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_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/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 0632195c6..7b2c3d5ef 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -11,7 +11,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", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none"); + 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, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0); action native A_Light(int extralight); action native A_Light0(); action native A_Light1(); From cb41771342ff4d57d1bec2448ee4b7b641234f94 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 02:07:42 +0000 Subject: [PATCH 258/387] - When moving polyobjects, recalculate the floors and ceilings for the actors in their bounding boxes. (See http://forum.zdoom.org/viewtopic.php?f=2&t=35616) SVN r4192 (trunk) --- src/m_bbox.h | 9 +++++++++ src/po_man.cpp | 24 ++++++++++++++++++++++++ src/po_man.h | 1 + 3 files changed, 34 insertions(+) diff --git a/src/m_bbox.h b/src/m_bbox.h index febf9d2a2..256393d60 100644 --- a/src/m_bbox.h +++ b/src/m_bbox.h @@ -57,6 +57,15 @@ public: m_Box[BOXBOTTOM] = m_Box[BOXLEFT] = FIXED_MAX; } + // Returns a bounding box that encloses both bounding boxes + FBoundingBox operator | (const FBoundingBox &box2) const + { + return FBoundingBox(m_Box[BOXLEFT] < box2.m_Box[BOXLEFT] ? m_Box[BOXLEFT] : box2.m_Box[BOXLEFT], + m_Box[BOXBOTTOM] < box2.m_Box[BOXBOTTOM] ? m_Box[BOXBOTTOM] : box2.m_Box[BOXBOTTOM], + m_Box[BOXRIGHT] > box2.m_Box[BOXRIGHT] ? m_Box[BOXRIGHT] : box2.m_Box[BOXRIGHT], + m_Box[BOXTOP] > box2.m_Box[BOXTOP] ? m_Box[BOXTOP] : box2.m_Box[BOXTOP]); + } + void AddToBox (fixed_t x, fixed_t y); inline fixed_t Top () const { return m_Box[BOXTOP]; } diff --git a/src/po_man.cpp b/src/po_man.cpp index 3355b6ca1..1464f3ee5 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -986,6 +986,7 @@ void FPolyObj::CalcCenter() bool FPolyObj::MovePolyobj (int x, int y, bool force) { + FBoundingBox oldbounds = Bounds; UnLinkPolyobj (); DoMovePolyobj (x, y); @@ -1013,6 +1014,7 @@ bool FPolyObj::MovePolyobj (int x, int y, bool force) CenterSpot.y += y; LinkPolyobj (); ClearSubsectorLinks(); + RecalcActorFloorCeil(Bounds | oldbounds); return true; } @@ -1065,6 +1067,7 @@ bool FPolyObj::RotatePolyobj (angle_t angle) { int an; bool blocked; + FBoundingBox oldbounds = Bounds; an = (this->angle+angle)>>ANGLETOFINESHIFT; @@ -1103,6 +1106,7 @@ bool FPolyObj::RotatePolyobj (angle_t angle) this->angle += angle; LinkPolyobj(); ClearSubsectorLinks(); + RecalcActorFloorCeil(Bounds | oldbounds); return true; } @@ -1338,6 +1342,26 @@ void FPolyObj::LinkPolyobj () } } +//=========================================================================== +// +// FPolyObj :: RecalcActorFloorCeil +// +// For each actor within the bounding box, recalculate its floorz, ceilingz, +// and related values. +// +//=========================================================================== + +void FPolyObj::RecalcActorFloorCeil(FBoundingBox bounds) const +{ + FBlockThingsIterator it(bounds); + AActor *actor; + + while ((actor = it.Next()) != NULL) + { + P_FindFloorCeiling(actor); + } +} + //=========================================================================== // // PO_ClosestPoint diff --git a/src/po_man.h b/src/po_man.h index 5603095d5..35dc2af9c 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -76,6 +76,7 @@ struct FPolyObj 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 RecalcActorFloorCeil(FBoundingBox bounds) const; void CreateSubsectorLinks(); void ClearSubsectorLinks(); void CalcCenter(); From 34b2d0b21a39922b22504371fa633df97286bda0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 02:28:07 +0000 Subject: [PATCH 259/387] - Fixed: Putting a lightlist in a sector caused that sector's floorlight and ceilinglight to be ignored. SVN r4193 (trunk) --- src/r_bsp.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 163b0e296..4fe0ef03b 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1072,7 +1072,12 @@ void R_Subsector (subsector_t *sub) { light = P_GetPlaneLight(frontsector, &frontsector->ceilingplane, false); basecolormap = light->extra_colormap; - ceilinglightlevel = *light->p_lightlevel; + // If this is the real ceiling, don't discard plane lighting R_FakeFlat() + // accounted for. + if (light->p_lightlevel != &frontsector->lightlevel) + { + ceilinglightlevel = *light->p_lightlevel; + } } else { @@ -1103,7 +1108,12 @@ void R_Subsector (subsector_t *sub) { light = P_GetPlaneLight(frontsector, &frontsector->floorplane, false); basecolormap = light->extra_colormap; - floorlightlevel = *light->p_lightlevel; + // If this is the real floor, don't discard plane lighting R_FakeFlat() + // accounted for. + if (light->p_lightlevel != &frontsector->lightlevel) + { + floorlightlevel = *light->p_lightlevel; + } } else { From 2874d927b1ca1c2b258150661414a2586e35b6a2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 03:06:04 +0000 Subject: [PATCH 260/387] - Random spawners no longer move the missile forward when spawning them, because presumably whatever spawned the random spawner already took care of this. - Added a maxdist parameter to P_CheckMissileSpawn() to help ensure that it doesn't completely move the spawned missile outside of its shooter (and potentially beyond a wall the shooter might happen to be standing next to). SVN r4194 (trunk) --- src/fragglescript/t_func.cpp | 2 +- src/g_heretic/a_hereticmisc.cpp | 4 +- src/g_heretic/a_hereticweaps.cpp | 12 +-- src/g_heretic/a_ironlich.cpp | 4 +- src/g_hexen/a_flechette.cpp | 2 +- src/g_hexen/a_korax.cpp | 2 +- src/g_raven/a_minotaur.cpp | 2 +- src/g_shared/a_randomspawner.cpp | 2 +- src/g_strife/a_entityboss.cpp | 2 +- src/g_strife/a_sentinel.cpp | 2 +- src/g_strife/a_strifeweapons.cpp | 2 +- src/p_local.h | 2 +- src/p_mobj.cpp | 120 ++++++++++++++---------------- src/p_things.cpp | 2 +- src/thingdef/thingdef_codeptr.cpp | 10 +-- 15 files changed, 79 insertions(+), 91 deletions(-) diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 946114520..ec083631a 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -4256,7 +4256,7 @@ void FParser::SF_SpawnShot2(void) S_Sound (mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM); mo->target = source; P_ThrustMobj(mo, mo->angle = source->angle, mo->Speed); - if (!P_CheckMissileSpawn(mo)) mo = NULL; + if (!P_CheckMissileSpawn(mo, source->radius)) mo = NULL; } t_return.value.mobj = mo; } diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index a8d4fcb8f..83200068b 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -175,7 +175,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast) blast->vely = FixedMul (1*FRACUNIT, finesine[angle]); blast->velz = (FRACUNIT*5/2) + (pr_blast() << 10); S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM); - P_CheckMissileSpawn (blast); + P_CheckMissileSpawn (blast, self->radius); } } @@ -209,7 +209,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact) tiny->velx = FixedMul (FRACUNIT*7/10, finecosine[angle]); tiny->vely = FixedMul (FRACUNIT*7/10, finesine[angle]); tiny->velz = FRACUNIT + (pr_volcimpact() << 9); - P_CheckMissileSpawn (tiny); + P_CheckMissileSpawn (tiny, self->radius); } } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index e8f287f69..5e1f0647c 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -395,7 +395,7 @@ void FireMacePL1B (AActor *actor) ball->velx = (actor->velx>>1) + FixedMul(ball->Speed, finecosine[angle]); ball->vely = (actor->vely>>1) + FixedMul(ball->Speed, finesine[angle]); S_Sound (ball, CHAN_BODY, "weapons/maceshoot", 1, ATTN_NORM); - P_CheckMissileSpawn (ball); + P_CheckMissileSpawn (ball, actor->radius); } //---------------------------------------------------------------------------- @@ -538,7 +538,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) tiny->velx = (self->velx>>1) + FixedMul(self->velz-FRACUNIT, finecosine[angle]); tiny->vely = (self->vely>>1) + FixedMul(self->velz-FRACUNIT, finesine[angle]); tiny->velz = self->velz; - P_CheckMissileSpawn (tiny); + P_CheckMissileSpawn (tiny, self->radius); tiny = Spawn("MaceFX3", self->x, self->y, self->z, ALLOW_REPLACE); angle = self->angle-ANG90; @@ -548,7 +548,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) tiny->velx = (self->velx>>1) + FixedMul(self->velz-FRACUNIT, finecosine[angle]); tiny->vely = (self->vely>>1) + FixedMul(self->velz-FRACUNIT, finesine[angle]); tiny->velz = self->velz; - P_CheckMissileSpawn (tiny); + P_CheckMissileSpawn (tiny, self->radius); } else { // Explode @@ -809,7 +809,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) angle >>= ANGLETOFINESHIFT; ripper->velx = FixedMul (ripper->Speed, finecosine[angle]); ripper->vely = FixedMul (ripper->Speed, finesine[angle]); - P_CheckMissileSpawn (ripper); + P_CheckMissileSpawn (ripper, self->radius); } } @@ -1064,7 +1064,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) mo->velx = 1; // Force collision detection mo->velz = -mo->Speed; mo->special2 = self->special2; // Transfer player number - P_CheckMissileSpawn (mo); + P_CheckMissileSpawn (mo, self->radius); if (self->special1 != -1 && !S_IsActorPlayingSomething (self, CHAN_BODY, -1)) { S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM); @@ -1314,7 +1314,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) { S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); } - P_CheckMissileSpawn (mo); + P_CheckMissileSpawn (mo, self->radius); } //---------------------------------------------------------------------------- diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index 8efaa8d82..5801e6cac 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) fire->velz = baseFire->velz; fire->Damage = 0; fire->health = (i+1) * 2; - P_CheckMissileSpawn (fire); + P_CheckMissileSpawn (fire, self->radius); } } } @@ -185,7 +185,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact) shard->velx = FixedMul (shard->Speed, finecosine[angle]); shard->vely = FixedMul (shard->Speed, finesine[angle]); shard->velz = -FRACUNIT*6/10; - P_CheckMissileSpawn (shard); + P_CheckMissileSpawn (shard, self->radius); } } diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp index 5c28b8358..1a9461ae8 100644 --- a/src/g_hexen/a_flechette.cpp +++ b/src/g_hexen/a_flechette.cpp @@ -137,7 +137,7 @@ bool AArtiPoisonBag3::Use (bool pickup) mo->target = Owner; mo->tics -= pr_poisonbag()&3; - P_CheckMissileSpawn(mo); + P_CheckMissileSpawn(mo, Owner->radius); return true; } return false; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index a7d8908b2..5323fb851 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -502,5 +502,5 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, dist = 1; } th->velz = (dest->z-z+(30*FRACUNIT))/dist; - return (P_CheckMissileSpawn(th) ? th : NULL); + return (P_CheckMissileSpawn(th, source->radius) ? th : NULL); } diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 949e38d01..ff39bf67c 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -375,7 +375,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) mo = Spawn("MinotaurFX3", x, y, self->floorz, ALLOW_REPLACE); mo->target = self->target; mo->velx = 1; // Force block checking - P_CheckMissileSpawn (mo); + P_CheckMissileSpawn (mo, self->radius); } //--------------------------------------------------------------------------- diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index fc7ca8cf9..293b17d3b 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -173,7 +173,7 @@ class ARandomSpawner : public AActor newmobj->z += SpawnPoint[2]; } if (newmobj->flags & MF_MISSILE) - P_CheckMissileSpawn(newmobj); + P_CheckMissileSpawn(newmobj, 0); // Bouncecount is used to count how many recursions we're in. if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner"))) newmobj->bouncecount = ++bouncecount; diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp index 3dfeb3b5a..58a88121e 100644 --- a/src/g_strife/a_entityboss.cpp +++ b/src/g_strife/a_entityboss.cpp @@ -29,7 +29,7 @@ void A_SpectralMissile (AActor *self, const char *missilename) if (missile != NULL) { missile->tracer = self->target; - P_CheckMissileSpawn(missile); + P_CheckMissileSpawn(missile, self->radius); } } } diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 696858f81..74f0e917f 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -64,7 +64,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) trail->velx = missile->velx; trail->vely = missile->vely; trail->velz = missile->velz; - P_CheckMissileSpawn (trail); + P_CheckMissileSpawn (trail, self->radius); } } missile->z += missile->velz >> 2; diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 5ac40b82e..82560e6f7 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -538,7 +538,7 @@ AActor *P_SpawnSubMissile (AActor *source, const PClass *type, AActor *target) } } - if (P_CheckMissileSpawn (other)) + if (P_CheckMissileSpawn (other, source->radius)) { angle_t pitch = P_AimLineAttack (source, source->angle, 1024*FRACUNIT); other->velz = FixedMul (-finesine[pitch>>ANGLETOFINESHIFT], other->Speed); diff --git a/src/p_local.h b/src/p_local.h index fe149d431..f5e1f44a0 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -481,7 +481,7 @@ enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags }; -bool P_CheckMissileSpawn (AActor *missile); +bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); void P_PlaySpawnSound(AActor *missile, AActor *spawner); // [RH] Position the chasecam diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d36c27463..bf84d3340 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5258,10 +5258,8 @@ void P_CheckSplash(AActor *self, fixed_t distance) // //--------------------------------------------------------------------------- -bool P_CheckMissileSpawn (AActor* th) +bool P_CheckMissileSpawn (AActor* th, fixed_t maxdist) { - int shift, count = 1; - // [RH] Don't decrement tics if they are already less than 1 if ((th->flags4 & MF4_RANDOMIZE) && th->tics > 0) { @@ -5270,76 +5268,66 @@ bool P_CheckMissileSpawn (AActor* th) th->tics = 1; } - // move a little forward so an angle can be computed if it immediately explodes - if (th->Speed >= 100*FRACUNIT) - { // Ultra-fast ripper spawning missile - shift = 3; - } - else - { // Normal missile - shift = 1; - } - - if (th->radius > 0) + if (maxdist > 0) { - while ( ((th->velx >> shift) > th->radius) || ((th->vely >> shift) > th->radius)) + // move a little forward so an angle can be computed if it immediately explodes + TVector3 advance(FIXED2DBL(th->velx), FIXED2DBL(th->vely), FIXED2DBL(th->velz)); + double maxsquared = FIXED2DBL(maxdist); + maxsquared *= maxsquared; + + // Keep halving the advance vector until we get something less than maxdist + // units away, since we still want to spawn the missile inside the shooter. + while (TVector2(advance).LengthSquared() >= maxsquared) { - // we need to take smaller steps but to produce the same end result - // we have to do more of them. - shift++; - count<<=1; + advance *= 0.5f; } + th->x += FLOAT2FIXED(advance.X); + th->y += FLOAT2FIXED(advance.Y); + th->z += FLOAT2FIXED(advance.Z); } FCheckPosition tm(!!(th->flags2 & MF2_RIP)); - for(int i=0; iflags & 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, NULL, tm, true))) { - th->x += th->velx >> shift; - th->y += th->vely >> shift; - th->z += th->velz >> shift; - - // killough 8/12/98: for non-missile objects (e.g. grenades) - // - // [GZ] MBF excludes non-missile objects from the P_TryMove test - // and subsequent potential P_ExplodeMissile call. That is because - // in MBF, a projectile is not an actor with the MF_MISSILE flag - // but an actor with either or both the MF_MISSILE and MF_BOUNCES - // flags, and a grenade is identified by not having MF_MISSILE. - // Killough wanted grenades not to explode directly when spawned, - // therefore they can be fired safely even when humping a wall as - // they will then just drop on the floor at their shooter's feet. - // - // However, ZDoom does allow non-missiles to be shot as well, so - // Killough's check for non-missiles is inadequate here. So let's - // replace it by a check for non-missile and MBF bounce type. - // This should allow MBF behavior where relevant without altering - // established ZDoom behavior for crazy stuff like a cacodemon cannon. - 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, NULL, tm, true))) + // [RH] Don't explode ripping missiles that spawn inside something + if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP)) { - // [RH] Don't explode ripping missiles that spawn inside something - if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP)) + // If this is a monster spawned by A_CustomMissile subtract it from the counter. + th->ClearCounters(); + // [RH] Don't explode missiles that spawn on top of horizon lines + if (th->BlockingLine != NULL && th->BlockingLine->special == Line_Horizon) { - // If this is a monster spawned by A_CustomMissile subtract it from the counter. - th->ClearCounters(); - // [RH] Don't explode missiles that spawn on top of horizon lines - if (th->BlockingLine != NULL && th->BlockingLine->special == Line_Horizon) - { - th->Destroy (); - } - else if (MBFGrenade && th->BlockingLine != NULL ) - { - P_BounceWall(th); - } - else - { - P_ExplodeMissile (th, NULL, th->BlockingMobj); - } - return false; + th->Destroy (); } + else if (MBFGrenade && th->BlockingLine != NULL) + { + P_BounceWall(th); + } + else + { + P_ExplodeMissile (th, NULL, th->BlockingMobj); + } + return false; } } return true; @@ -5473,7 +5461,7 @@ AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, th->SetFriendPlayer(owner->player); } - return (!checkspawn || P_CheckMissileSpawn (th)) ? th : NULL; + return (!checkspawn || P_CheckMissileSpawn (th, source->radius)) ? th : NULL; } AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const PClass *type) @@ -5503,7 +5491,7 @@ AActor * P_OldSpawnMissile(AActor * source, AActor * owner, AActor * dest, const th->SetFriendPlayer(owner->player); } - P_CheckMissileSpawn(th); + P_CheckMissileSpawn(th, source->radius); return th; } @@ -5592,7 +5580,7 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, mo->SetFriendPlayer(owner->player); } - return (!checkspawn || P_CheckMissileSpawn(mo)) ? mo : NULL; + return (!checkspawn || P_CheckMissileSpawn(mo, source->radius)) ? mo : NULL; } /* @@ -5711,7 +5699,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, { MissileActor->SetFriendPlayer(source->player); } - if (P_CheckMissileSpawn (MissileActor)) + if (P_CheckMissileSpawn (MissileActor, source->radius)) { return MissileActor; } diff --git a/src/p_things.cpp b/src/p_things.cpp index 289e8835a..d2d8a963e 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -336,7 +336,7 @@ nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y); } if (mobj->flags & MF_MISSILE) { - if (P_CheckMissileSpawn (mobj)) + if (P_CheckMissileSpawn (mobj, source->radius)) { rtn = true; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ccb7f5961..d201f41a6 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -333,7 +333,7 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, { missile->tracer=self->target; } - P_CheckMissileSpawn(missile); + P_CheckMissileSpawn(missile, self->radius); } } } @@ -1019,7 +1019,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) missile->FriendPlayer = 0; } } - P_CheckMissileSpawn(missile); + P_CheckMissileSpawn(missile, self->radius); } } } @@ -1170,7 +1170,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) { missile->tracer=self->target; } - P_CheckMissileSpawn(missile); + P_CheckMissileSpawn(missile, self->radius); } } } @@ -2045,8 +2045,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) bo->vely = xy_vely + z_vely + (self->vely >> 1); bo->velz = xy_velz + z_velz; - bo->target= self; - P_CheckMissileSpawn (bo); + bo->target = self; + P_CheckMissileSpawn (bo, self->radius); } else ACTION_SET_RESULT(false); } From e4127111b1df229f6730b50079e7a67089e7ef4b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 03:47:39 +0000 Subject: [PATCH 261/387] - A player's Speed is now applied to their upmove as well as their forwardmove and sidemove. SVN r4195 (trunk) --- src/p_user.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index a3e848fe1..132fa4996 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2103,7 +2103,7 @@ void P_PlayerThink (player_t *player) player->ReadyWeapon != NULL && // No adjustment if no weapon. player->ReadyWeapon->FOVScale != 0) // No adjustment if the adjustment is zero. { - // A negative scale is used top prevent G_AddViewAngle/G_AddViewPitch + // A negative scale is used to prevent G_AddViewAngle/G_AddViewPitch // from scaling with the FOV scale. desired *= fabs(player->ReadyWeapon->FOVScale); } @@ -2373,7 +2373,7 @@ void P_PlayerThink (player_t *player) } if (player->mo->waterlevel >= 2 || (player->mo->flags2 & MF2_FLY) || (player->cheats & CF_NOCLIP2)) { - player->mo->velz = cmd->ucmd.upmove << 9; + player->mo->velz = FixedMul(player->mo->Speed, cmd->ucmd.upmove << 9); if (player->mo->waterlevel < 2 && !(player->mo->flags & MF_NOGRAVITY)) { player->mo->flags2 |= MF2_FLY; From 06445e8181881f72652c0935077b9488eeb30718 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 22:21:54 +0000 Subject: [PATCH 262/387] - Fixed: Used the wrong actor's radius in P_Thing_Projectile() to get the maxdist for P_CheckMissileSpawn(). SVN r4196 (trunk) --- src/p_things.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index d2d8a963e..a0f905a7f 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -336,7 +336,7 @@ nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y); } if (mobj->flags & MF_MISSILE) { - if (P_CheckMissileSpawn (mobj, source->radius)) + if (P_CheckMissileSpawn (mobj, spot->radius)) { rtn = true; } From 0c6c78517b3c4bfcb1e5fb8f0c1156944952f144 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 22:23:42 +0000 Subject: [PATCH 263/387] - Always at least halve the advance vector in P_CheckMissileSpawn(). SVN r4197 (trunk) --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bf84d3340..5cc5ecfe1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5277,10 +5277,11 @@ bool P_CheckMissileSpawn (AActor* th, fixed_t maxdist) // Keep halving the advance vector until we get something less than maxdist // units away, since we still want to spawn the missile inside the shooter. - while (TVector2(advance).LengthSquared() >= maxsquared) + do { advance *= 0.5f; } + while (TVector2(advance).LengthSquared() >= maxsquared); th->x += FLOAT2FIXED(advance.X); th->y += FLOAT2FIXED(advance.Y); th->z += FLOAT2FIXED(advance.Z); From 044616a86f30167a5fa18180fecf21252706faed Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 21 Mar 2013 22:58:37 +0000 Subject: [PATCH 264/387] - Fixed: Don't return false from PIT_CheckThing when a shootable missile hits a nonmonster and infighting is disabled; let the normal conditions apply. Otherwise, you end up with situations where monster-fired projectiles can collide with pickups. SVN r4198 (trunk) --- src/p_map.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index c31e66367..7f559fff4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1075,19 +1075,18 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) // friendliness and hate status. if (tm.thing->target->flags & MF_SHOOTABLE) { - if (!(thing->flags3 & MF3_ISMONSTER)) + // Question: Should monsters be allowed to shoot barrels in this mode? + // The old code does not. + if (thing->flags3 & MF3_ISMONSTER) { - return false; // Question: Should monsters be allowed to shoot barrels in this mode? - // The old code does not. - } - - // Monsters that are clearly hostile can always hurt each other - if (!thing->IsHostile (tm.thing->target)) - { - // The same if the shooter hates the target - if (thing->tid == 0 || tm.thing->target->TIDtoHate != thing->tid) + // Monsters that are clearly hostile can always hurt each other + if (!thing->IsHostile (tm.thing->target)) { - return false; + // The same if the shooter hates the target + if (thing->tid == 0 || tm.thing->target->TIDtoHate != thing->tid) + { + return false; + } } } } From c54ea7f6b7efac877ddf3e6d4e3285831153b7b0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Mar 2013 01:22:37 +0000 Subject: [PATCH 265/387] - Added SXF_TRANSFERSPECIAL and SXF_CLEARCALLERSPECIAL flags for A_SpawnItemEx. SVN r4199 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 12 ++++++++++++ wadsrc/static/actors/constants.txt | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d201f41a6..2bbb796d8 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1736,6 +1736,8 @@ enum SIX_Flags SIXF_CLEARCALLERTID = 1 << 12, SIXF_MULTIPLYSPEED = 1 << 13, SIXF_TRANSFERSCALE = 1 << 14, + SIXF_TRANSFERSPECIAL = 1 << 15, + SIXF_CLEARCALLERSPECIAL = 1 << 16, }; static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) @@ -1838,6 +1840,16 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) self->RemoveFromHash(); self->tid = 0; } + if (flags & SIXF_TRANSFERSPECIAL) + { + mo->special = self->special; + memcpy(mo->args, self->args, sizeof(self->args)); + } + if (flags & SIXF_CLEARCALLERSPECIAL) + { + self->special = 0; + memset(self->args, 0, sizeof(self->args)); + } return true; } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index db4e9abbe..b26fae9c7 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -57,6 +57,8 @@ const int SXF_USEBLOODCOLOR = 2048; const int SXF_CLEARCALLERTID = 4096; const int SXF_MULTIPLYSPEED = 8192; const int SXF_TRANSFERSCALE = 16384; +const int SXF_TRANSFERSPECIAL = 32768; +const int SXF_CLEARCALLERSPECIAL = 65536; // Flags for A_Chase const int CHF_FASTCHASE = 1; From dcf50ab6cb37df39886d1a4f1f7c9c2f1a23e761 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Mar 2013 02:54:13 +0000 Subject: [PATCH 266/387] - Added an enum for the values a Trace callback function can return. - Added a userdata parameter to pass to the Trace callback function. SVN r4200 (trunk) --- src/p_map.cpp | 34 ++++++++++++++++------------------ src/p_trace.cpp | 37 ++++++++++++++++++++++++++++--------- src/p_trace.h | 12 +++++++++++- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7f559fff4..55e90dcf6 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3423,38 +3423,36 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p // //========================================================================== -static bool CheckForGhost (FTraceResults &res) +static ETraceStatus CheckForGhost (FTraceResults &res, void *userdata) { if (res.HitType != TRACE_HitActor) { - return false; + return TRACE_Stop; } // check for physical attacks on a ghost if (res.Actor->flags3 & MF3_GHOST || res.Actor->flags4 & MF4_SPECTRAL) { - res.HitType = TRACE_HitNone; - return true; + return TRACE_Skip; } - return false; + return TRACE_Stop; } -static bool CheckForSpectral (FTraceResults &res) +static ETraceStatus CheckForSpectral (FTraceResults &res, void *userdata) { if (res.HitType != TRACE_HitActor) { - return false; + return TRACE_Stop; } // check for physical attacks on spectrals if (res.Actor->flags4 & MF4_SPECTRAL) { - res.HitType = TRACE_HitNone; - return true; + return TRACE_Skip; } - return false; + return TRACE_Stop; } //========================================================================== @@ -3886,17 +3884,17 @@ struct SRailHit }; static TArray RailHits (16); -static bool ProcessRailHit (FTraceResults &res) +static ETraceStatus ProcessRailHit (FTraceResults &res, void *userdata) { if (res.HitType != TRACE_HitActor) { - return false; + return TRACE_Stop; } // Invulnerable things completely block the shot if (res.Actor->flags2 & MF2_INVULNERABLE) { - return false; + return TRACE_Stop; } // Save this thing for damaging later, and continue the trace @@ -3905,7 +3903,7 @@ static bool ProcessRailHit (FTraceResults &res) newhit.Distance = res.Distance - 10*FRACUNIT; // put blood in front RailHits.Push (newhit); - return true; + return TRACE_Continue; } //========================================================================== @@ -3914,17 +3912,17 @@ static bool ProcessRailHit (FTraceResults &res) // //========================================================================== -static bool ProcessNoPierceRailHit (FTraceResults &res) +static ETraceStatus ProcessNoPierceRailHit (FTraceResults &res, void *userdata) { if (res.HitType != TRACE_HitActor) { - return false; + return TRACE_Stop; } // Invulnerable things completely block the shot if (res.Actor->flags2 & MF2_INVULNERABLE) { - return false; + return TRACE_Stop; } // Only process the first hit @@ -3933,7 +3931,7 @@ static bool ProcessNoPierceRailHit (FTraceResults &res) newhit.Distance = res.Distance - 10*FRACUNIT; // put blood in front RailHits.Push (newhit); - return false; + return TRACE_Stop; } //========================================================================== diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 93c347d9f..d1b9f63ac 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -48,7 +48,8 @@ struct FTraceInfo sector_t *CurSector; fixed_t MaxDist; fixed_t EnterDist; - bool (*TraceCallback)(FTraceResults &res); + ETraceStatus (*TraceCallback)(FTraceResults &res, void *data); + void *TraceCallbackData; DWORD TraceFlags; int inshootthrough; @@ -71,7 +72,7 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist, DWORD actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, - DWORD flags, bool (*callback)(FTraceResults &res)) + DWORD flags, ETraceStatus (*callback)(FTraceResults &res, void *), void *callbackdata) { int ptflags; FTraceInfo inf; @@ -91,6 +92,7 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, inf.MaxDist = maxDist; inf.EnterDist = 0; inf.TraceCallback = callback; + inf.TraceCallbackData = callbackdata; inf.TraceFlags = flags; inf.Results = &res; inf.inshootthrough = true; @@ -506,7 +508,13 @@ cont: if (TraceCallback != NULL) { - if (!TraceCallback (*Results)) return false; + switch (TraceCallback(*Results, TraceCallbackData)) + { + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; break; + default: break; + } } else { @@ -515,8 +523,7 @@ cont: } // Encountered an actor - if (!(in->d.thing->flags & ActorMask) || - in->d.thing == IgnoreThis) + if (!(in->d.thing->flags & ActorMask) || in->d.thing == IgnoreThis) { continue; } @@ -583,13 +590,19 @@ cont: // the trace hit a 3D-floor before the thing. // Calculate an intersection and abort. Results->Sector = §ors[CurSector->sectornum]; - if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor)) + if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor)) { - Results->HitType=TRACE_HitNone; + Results->HitType = TRACE_HitNone; } if (TraceCallback != NULL) { - return TraceCallback (*Results); + switch (TraceCallback(*Results, TraceCallbackData)) + { + case TRACE_Continue: return true; + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; return true; + } } else { @@ -608,7 +621,13 @@ cont1: if (TraceCallback != NULL) { - if (!TraceCallback (*Results)) return false; + switch (TraceCallback(*Results, TraceCallbackData)) + { + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; break; + default: break; + } } else { diff --git a/src/p_trace.h b/src/p_trace.h index 8ce905da3..403b1f9cf 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -85,10 +85,20 @@ enum TRACE_Impact = 4, // Trigger SPAC_IMPACT lines }; +// return values from callback +enum ETraceStatus +{ + TRACE_Stop, // stop the trace, returning this hit + TRACE_Continue, // continue the trace, returning this hit if there are none further along + TRACE_Skip, // continue the trace; do not return this hit + TRACE_Abort, // stop the trace, returning no hits +}; + bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist, DWORD ActorMask, DWORD WallMask, AActor *ignore, FTraceResults &res, - DWORD traceFlags=0, bool (*callback)(FTraceResults &res)=NULL); + DWORD traceFlags=0, + ETraceStatus (*callback)(FTraceResults &res, void *)=NULL, void *callbackdata=NULL); #endif //__P_TRACE_H__ From f9915d7cf232eee185eccf5739b595790a06fe68 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Mar 2013 02:55:59 +0000 Subject: [PATCH 267/387] - Added FDARI's A_CheckLOF, modified to use a Trace callback function. SVN r4201 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 278 +++++++++++++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + wadsrc/static/actors/constants.txt | 38 ++++ 3 files changed, 317 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 2bbb796d8..dcfe03dad 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -69,6 +69,7 @@ #include "actorptrselect.h" #include "m_bbox.h" #include "r_data/r_translate.h" +#include "p_trace.h" static FRandom pr_camissile ("CustomActorfire"); @@ -2908,6 +2909,283 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) self->lastenemy = NULL; } +//========================================================================== +// +// A_CheckLOF (state jump, int flags = CRF_AIM_VERT|CRF_AIM_HOR, +// fixed range = 0, angle angle = 0, angle pitch = 0, +// fixed offsetheight = 32, fixed offsetwidth = 0, +// int ptr_target = AAPTR_DEFAULT (target) ) +// +//========================================================================== + +enum CLOF_flags +{ + CLOFF_NOAIM_VERT = 0x1, + CLOFF_NOAIM_HORZ = 0x2, + + CLOFF_JUMPENEMY = 0x4, + CLOFF_JUMPFRIEND = 0x8, + CLOFF_JUMPOBJECT = 0x10, + CLOFF_JUMPNONHOSTILE = 0x20, + + CLOFF_SKIPENEMY = 0x40, + CLOFF_SKIPFRIEND = 0x80, + CLOFF_SKIPOBJECT = 0x100, + CLOFF_SKIPNONHOSTILE = 0x200, + + CLOFF_MUSTBESHOOTABLE = 0x400, + + CLOFF_SKIPTARGET = 0x800, + CLOFF_ALLOWNULL = 0x1000, + CLOFF_CHECKPARTIAL = 0x2000, + + CLOFF_MUSTBEGHOST = 0x4000, + CLOFF_IGNOREGHOST = 0x8000, + + CLOFF_MUSTBESOLID = 0x10000, + CLOFF_BEYONDTARGET = 0x20000, + + CLOFF_FROMBASE = 0x40000, + CLOFF_MUL_HEIGHT = 0x80000, + CLOFF_MUL_WIDTH = 0x100000 +}; + +struct LOFData +{ + AActor *Self; + AActor *Target; + int Flags; +}; + +ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) +{ + LOFData *data = (LOFData *)userdata; + int flags = data->Flags; + + if (trace.HitType != TRACE_HitActor) + { + return TRACE_Stop; + } + if (trace.Actor == data->Target) + { + if (flags & CLOFF_SKIPTARGET) + { + if (flags & CLOFF_BEYONDTARGET) + { + return TRACE_Skip; + } + return TRACE_Abort; + } + return TRACE_Stop; + } + if (flags & CLOFF_MUSTBESHOOTABLE) + { // all shootability checks go here + if (!(trace.Actor->flags & MF_SHOOTABLE)) + { + return TRACE_Skip; + } + if (trace.Actor->flags2 & MF2_NONSHOOTABLE) + { + return TRACE_Skip; + } + } + if ((flags & CLOFF_MUSTBESOLID) && !(trace.Actor->flags & MF_SOLID)) + { + return TRACE_Skip; + } + if (flags & CLOFF_MUSTBEGHOST) + { + if (!(trace.Actor->flags3 & MF3_GHOST)) + { + return TRACE_Skip; + } + } + else if (flags & CLOFF_IGNOREGHOST) + { + if (trace.Actor->flags3 & MF3_GHOST) + { + return TRACE_Skip; + } + } + if ( + ((flags & CLOFF_JUMPENEMY) && data->Self->IsHostile(trace.Actor)) || + ((flags & CLOFF_JUMPFRIEND) && data->Self->IsFriend(trace.Actor)) || + ((flags & CLOFF_JUMPOBJECT) && !(trace.Actor->flags3 & MF3_ISMONSTER)) || + ((flags & CLOFF_JUMPNONHOSTILE) && (trace.Actor->flags3 & MF3_ISMONSTER) && !data->Self->IsHostile(trace.Actor)) + ) + { + return TRACE_Stop; + } + if ( + ((flags & CLOFF_SKIPENEMY) && data->Self->IsHostile(trace.Actor)) || + ((flags & CLOFF_SKIPFRIEND) && data->Self->IsFriend(trace.Actor)) || + ((flags & CLOFF_SKIPOBJECT) && !(trace.Actor->flags3 & MF3_ISMONSTER)) || + ((flags & CLOFF_SKIPNONHOSTILE) && (trace.Actor->flags3 & MF3_ISMONSTER) && !data->Self->IsHostile(trace.Actor)) + ) + { + return TRACE_Skip; + } + return TRACE_Abort; +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) +{ + // Check line of fire + + /* + Not accounted for / I don't know how it works: FLOORCLIP + */ + + AActor *target; + fixed_t + x1, y1, z1, + vx, vy, vz; + + ACTION_PARAM_START(9); + + ACTION_PARAM_STATE(jump, 0); + ACTION_PARAM_INT(flags, 1); + ACTION_PARAM_FIXED(range, 2); + ACTION_PARAM_FIXED(minrange, 3); + { + ACTION_PARAM_ANGLE(angle, 4); + ACTION_PARAM_ANGLE(pitch, 5); + ACTION_PARAM_FIXED(offsetheight, 6); + ACTION_PARAM_FIXED(offsetwidth, 7); + ACTION_PARAM_INT(ptr_target, 8); + + ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + + target = COPY_AAPTR(self, ptr_target == AAPTR_DEFAULT ? AAPTR_TARGET|AAPTR_PLAYER_GETTARGET|AAPTR_NULL : ptr_target); // no player-support by default + + if (flags & CLOFF_MUL_HEIGHT) + { + if (self->player != NULL) + { + // Synced with hitscan: self->player->mo->height is strangely conscientious about getting the right actor for player + offsetheight = FixedMul(offsetheight, FixedMul (self->player->mo->height, self->player->crouchfactor)); + } + else + { + offsetheight = FixedMul(offsetheight, self->height); + } + } + if (flags & CLOFF_MUL_WIDTH) + { + offsetwidth = FixedMul(self->radius, offsetwidth); + } + + x1 = self->x; + y1 = self->y; + z1 = self->z + offsetheight - self->floorclip; + + if (!(flags & CLOFF_FROMBASE)) + { // default to hitscan origin + + // Synced with hitscan: self->height is strangely NON-conscientious about getting the right actor for player + z1 += (self->height >> 1); + if (self->player != NULL) + { + z1 += FixedMul (self->player->mo->AttackZOffset, self->player->crouchfactor); + } + else + { + z1 += 8*FRACUNIT; + } + } + + if (target) + { + FVector2 xyvec(target->x - x1, target->y - y1); + fixed_t distance = P_AproxDistance((fixed_t)xyvec.Length(), target->z - z1); + + if (range && !(flags & CLOFF_CHECKPARTIAL)) + { + if (distance > range) return; + } + + { + angle_t ang; + + if (flags & CLOFF_NOAIM_HORZ) + { + ang = self->angle; + } + else ang = R_PointToAngle2 (x1, y1, target->x, target->y); + + angle += ang; + + ang >>= ANGLETOFINESHIFT; + x1 += FixedMul(offsetwidth, finesine[ang]); + y1 -= FixedMul(offsetwidth, finecosine[ang]); + } + + if (flags & CLOFF_NOAIM_VERT) + { + pitch += self->pitch; + } + else pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + } + else if (flags & CLOFF_ALLOWNULL) + { + angle += self->angle; + pitch += self->pitch; + + angle_t ang = self->angle >> ANGLETOFINESHIFT; + x1 += FixedMul(offsetwidth, finesine[ang]); + y1 -= FixedMul(offsetwidth, finecosine[ang]); + } + else return; + + angle >>= ANGLETOFINESHIFT; + pitch = (0-pitch)>>ANGLETOFINESHIFT; + + vx = FixedMul (finecosine[pitch], finecosine[angle]); + vy = FixedMul (finecosine[pitch], finesine[angle]); + vz = -finesine[pitch]; + } + + /* Variable set: + + jump, flags, target + x1,y1,z1 (trace point of origin) + vx,vy,vz (trace unit vector) + range + */ + + sector_t *sec = P_PointInSector(x1, y1); + + if (range == 0) + { + range = (self->player != NULL) ? PLAYERMISSILERANGE : MISSILERANGE; + } + + FTraceResults trace; + LOFData lof_data; + + lof_data.Self = self; + lof_data.Target = target; + lof_data.Flags = flags; + + Trace(x1, y1, z1, sec, vx, vy, vz, range, 0xFFFFFFFF, ML_BLOCKEVERYTHING, self, trace, 0, + CheckLOFTraceFunc, &lof_data); + + if (trace.HitType == TRACE_HitActor) + { + if (minrange > 0) + { + double dx = trace.Actor->x - x1, + dy = trace.Actor->y - y1, + dz = trace.Actor->z + trace.Actor->height/2 - z1; + if (dx*dx+ dy*dy+ dz*dz < (double)minrange*(double)minrange) + { + return; + } + } + ACTION_JUMP(jump); + } +} + //========================================================================== // // A_JumpIfTargetInLOS (state label, optional fixed fov, optional int flags, diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index ab0898fa3..9ec0e5fe6 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -267,6 +267,7 @@ ACTOR Actor native //: Thinker action native A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = ""); action native A_ClearLastHeard(); action native A_ClearTarget(); + action native A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT); 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"); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index b26fae9c7..587f10d35 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -303,5 +303,43 @@ Const Int WARPF_TESTONLY = 0x200; // flags for A_SetPitch const int SPF_FORCECLAMP = 1; + +// flags for A_CheckLOF + +enum +{ + CLOFF_NOAIM_VERT = 0x1, + CLOFF_NOAIM_HORZ = 0x2, + + CLOFF_JUMPENEMY = 0x4, + CLOFF_JUMPFRIEND = 0x8, + CLOFF_JUMPOBJECT = 0x10, + CLOFF_JUMPNONHOSTILE = 0x20, + + CLOFF_SKIPENEMY = 0x40, + CLOFF_SKIPFRIEND = 0x80, + CLOFF_SKIPOBJECT = 0x100, + CLOFF_SKIPNONHOSTILE = 0x200, + + CLOFF_MUSTBESHOOTABLE = 0x400, + + CLOFF_SKIPTARGET = 0x800, + CLOFF_ALLOWNULL = 0x1000, + CLOFF_CHECKPARTIAL = 0x2000, + + CLOFF_MUSTBEGHOST = 0x4000, + CLOFF_IGNOREGHOST = 0x8000, + + CLOFF_MUSTBESOLID = 0x10000, + CLOFF_BEYONDTARGET = 0x20000, + + CLOFF_FROMBASE = 0x40000, + CLOFF_MUL_HEIGHT = 0x80000, + CLOFF_MUL_WIDTH = 0x100000, + + CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE, + CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ +}; + // This is only here to provide one global variable for testing. native int testglobalvar; From 449bf216fa266bcc93b79ae29ac79f89d94c109a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 23 Mar 2013 03:05:01 +0000 Subject: [PATCH 268/387] - Stop storing rail hits in a global variable, and consolidate the two railgun callbacks into a single function. SVN r4202 (trunk) --- src/p_map.cpp | 76 ++++++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 55e90dcf6..803276d10 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3882,10 +3882,15 @@ struct SRailHit AActor *HitActor; fixed_t Distance; }; -static TArray RailHits (16); +struct RailData +{ + TArray RailHits; + bool StopAtOne; +}; static ETraceStatus ProcessRailHit (FTraceResults &res, void *userdata) { + RailData *data = (RailData *)userdata; if (res.HitType != TRACE_HitActor) { return TRACE_Stop; @@ -3901,37 +3906,9 @@ static ETraceStatus ProcessRailHit (FTraceResults &res, void *userdata) SRailHit newhit; newhit.HitActor = res.Actor; newhit.Distance = res.Distance - 10*FRACUNIT; // put blood in front - RailHits.Push (newhit); + data->RailHits.Push (newhit); - return TRACE_Continue; -} - -//========================================================================== -// -// -// -//========================================================================== - -static ETraceStatus ProcessNoPierceRailHit (FTraceResults &res, void *userdata) -{ - if (res.HitType != TRACE_HitActor) - { - return TRACE_Stop; - } - - // Invulnerable things completely block the shot - if (res.Actor->flags2 & MF2_INVULNERABLE) - { - return TRACE_Stop; - } - - // Only process the first hit - SRailHit newhit; - newhit.HitActor = res.Actor; - newhit.Distance = res.Distance - 10*FRACUNIT; // put blood in front - RailHits.Push (newhit); - - return TRACE_Stop; + return data->StopAtOne ? TRACE_Stop : TRACE_Continue; } //========================================================================== @@ -3978,7 +3955,9 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, x1 += offset_xy * finecosine[angle]; y1 += offset_xy * finesine[angle]; - RailHits.Clear (); + RailData rail_data; + + rail_data.StopAtOne = !!(railflags & RAF_NOPIERCE); start.X = FIXED2FLOAT(x1); start.Y = FIXED2FLOAT(y1); start.Z = FIXED2FLOAT(shootz); @@ -3992,7 +3971,7 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, Trace (x1, y1, shootz, source->Sector, vx, vy, vz, distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, - flags, (railflags & RAF_NOPIERCE) ? ProcessNoPierceRailHit : ProcessRailHit); + flags, ProcessRailHit, &rail_data); // Hurt anything the trace hit unsigned int i; @@ -4003,20 +3982,22 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, if (puffclass != NULL) thepuff = Spawn (puffclass, source->x, source->y, source->z, ALLOW_REPLACE); - for (i = 0; i < RailHits.Size (); i++) + for (i = 0; i < rail_data.RailHits.Size (); i++) { fixed_t x, y, z; bool spawnpuff; bool bleed = false; int puffflags = PF_HITTHING; + AActor *hitactor = rail_data.RailHits[i].HitActor; + fixed_t hitdist = rail_data.RailHits[i].Distance; - x = x1 + FixedMul (RailHits[i].Distance, vx); - y = y1 + FixedMul (RailHits[i].Distance, vy); - z = shootz + FixedMul (RailHits[i].Distance, vz); + x = x1 + FixedMul(hitdist, vx); + y = y1 + FixedMul(hitdist, vy); + z = shootz + FixedMul(hitdist, vz); - if ((RailHits[i].HitActor->flags & MF_NOBLOOD) || - (RailHits[i].HitActor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE))) + if ((hitactor->flags & MF_NOBLOOD) || + (hitactor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE))) { spawnpuff = (puffclass != NULL); } @@ -4024,21 +4005,24 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, { spawnpuff = (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF); puffflags |= PF_HITTHINGBLEED; // [XA] Allow for puffs to jump to XDeath state. - if(!(puffDefaults->flags3 & MF3_BLOODLESSIMPACT)) + if (!(puffDefaults->flags3 & MF3_BLOODLESSIMPACT)) { bleed = true; } } if (spawnpuff) - P_SpawnPuff (source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags); + { + P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags); + } if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) - P_PoisonMobj(RailHits[i].HitActor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); - - int newdam = P_DamageMobj (RailHits[i].HitActor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); + { + P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); + } + int newdam = P_DamageMobj(hitactor, thepuff? thepuff:source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); if (bleed) { - P_SpawnBlood (x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, RailHits[i].HitActor); - P_TraceBleed (newdam > 0 ? newdam : damage, x, y, z, RailHits[i].HitActor, source->angle, pitch); + P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor); + P_TraceBleed(newdam > 0 ? newdam : damage, x, y, z, hitactor, source->angle, pitch); } } From 324b13c89b3e9a26853dc257240ef3a66e26fdd2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 24 Mar 2013 02:25:12 +0000 Subject: [PATCH 269/387] - Added Weapon.MinSelectionAmmo1 and Weapon.MinSelectionAmmo2 to exclude weapons from autoselection even if they have enough ammo to be used. SVN r4203 (trunk) --- src/g_shared/a_pickups.h | 1 + src/g_shared/a_weapons.cpp | 4 ++++ src/p_user.cpp | 6 ++++++ src/thingdef/thingdef_properties.cpp | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 631a25181..b31d4e288 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -264,6 +264,7 @@ public: const PClass *ProjectileType; // Projectile used by primary attack const PClass *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first + int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo fixed_t MoveCombatDist; // Used by bots, but do they *really* need it? int ReloadCounter; // For A_CheckForReload int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index c5035e416..24d6a545d 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -65,6 +65,10 @@ void AWeapon::Serialize (FArchive &arc) } arc << FOVScale << Crosshair; + if (SaveVersion >= 4203) + { + arc << MinSelAmmo1 << MinSelAmmo2; + } } //=========================================================================== diff --git a/src/p_user.cpp b/src/p_user.cpp index 132fa4996..47d9ff2ed 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -766,6 +766,12 @@ AWeapon *APlayerPawn::BestWeapon (const PClass *ammotype) !weap->CheckAmmo (AWeapon::PrimaryFire, false)) continue; + // Don't select if if there isn't enough ammo as determined by the weapon's author. + if (weap->MinSelAmmo1 > 0 && (weap->Ammo1 == NULL || weap->Ammo1->Amount < weap->MinSelAmmo1)) + continue; + if (weap->MinSelAmmo2 > 0 && (weap->Ammo2 == NULL || weap->Ammo2->Amount < weap->MinSelAmmo2)) + continue; + // This weapon is usable! bestOrder = weap->SelectionOrder; bestMatch = weap; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 5fc607ca4..482a841a2 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1739,6 +1739,24 @@ DEFINE_CLASS_PROPERTY(selectionorder, I, Weapon) defaults->SelectionOrder = i; } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(minselectionammo1, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->MinSelAmmo1 = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(minselectionammo2, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->MinSelAmmo2 = i; +} + //========================================================================== // //========================================================================== From 332b1091b402ed18f67ab45e154490ec436dcce5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 24 Mar 2013 02:35:29 +0000 Subject: [PATCH 270/387] - Make FName::NameManager::Inited a static member variable. SVN r4204 (trunk) --- src/name.cpp | 1 + src/name.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/name.cpp b/src/name.cpp index c0d14b51e..36cce2595 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -65,6 +65,7 @@ struct FName::NameManager::NameBlock // PRIVATE DATA DEFINITIONS ------------------------------------------------ FName::NameManager FName::NameData; +bool FName::NameManager::Inited; // Define the predefined names. static const char *PredefinedNames[] = diff --git a/src/name.h b/src/name.h index fa161ab2e..3e2eaf4bb 100644 --- a/src/name.h +++ b/src/name.h @@ -116,7 +116,7 @@ protected: int AddName (const char *text, unsigned int hash, unsigned int bucket); NameBlock *AddBlock (size_t len); void InitBuckets (); - bool Inited; + static bool Inited; }; static NameManager NameData; From 316faf59b4f25810d2b16b45f0ee6fcf8b64e0bd Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 25 Mar 2013 18:20:39 +0000 Subject: [PATCH 271/387] - Fixed: Skin mugshots didn't load. (This adds a texture usetype for skin graphics.) SVN r4205 (trunk) --- src/g_shared/sbar_mugshot.cpp | 2 +- src/textures/texturemanager.cpp | 14 +++++++++++--- src/textures/textures.h | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index 7d4819413..313e2b847 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -98,7 +98,7 @@ FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_f } sprite.UnlockBuffer(); } - return TexMan[TexMan.CheckForTexture(sprite, 0, true)]; + return TexMan[TexMan.CheckForTexture(sprite, 0, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_AllowSkins)]; } //=========================================================================== diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 6fdac54c2..0302ca543 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -176,7 +176,8 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF { // All NULL textures should actually return 0 if (tex->UseType == FTexture::TEX_FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; - return FTextureID(tex->UseType==FTexture::TEX_Null? 0 : i); + if (tex->UseType == FTexture::TEX_SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; + return FTextureID(tex->UseType==FTexture::TEX_Null ? 0 : i); } else if ((flags & TEXMAN_Overridable) && tex->UseType == FTexture::TEX_Override) { @@ -831,6 +832,7 @@ void FTextureManager::AddTexturesForWad(int wadnum) for (int i= firsttx; i <= lasttx; i++) { + bool skin = false; char name[9]; Wads.GetLumpName(name, i); name[8]=0; @@ -869,11 +871,17 @@ void FTextureManager::AddTexturesForWad(int wadnum) // Don't bother looking this lump if something later overrides it. if (Wads.CheckNumForName(name, ns_graphics) != i) continue; } + else if (ns >= ns_firstskin) + { + // Don't bother looking this lump if something later overrides it. + if (Wads.CheckNumForName(name, ns) != i) continue; + skin = true; + } else continue; // Try to create a texture from this lump and add it. // Unfortunately we have to look at everything that comes through here... - FTexture *out = FTexture::CreateTexture(i, FTexture::TEX_MiscPatch); + FTexture *out = FTexture::CreateTexture(i, skin ? FTexture::TEX_SkinGraphic : FTexture::TEX_MiscPatch); if (out != NULL) { @@ -922,7 +930,7 @@ void FTextureManager::SortTexturesByType(int start, int end) static int texturetypes[] = { FTexture::TEX_Sprite, FTexture::TEX_Null, FTexture::TEX_FirstDefined, FTexture::TEX_WallPatch, FTexture::TEX_Wall, FTexture::TEX_Flat, - FTexture::TEX_Override, FTexture::TEX_MiscPatch + FTexture::TEX_Override, FTexture::TEX_MiscPatch, FTexture::TEX_SkinGraphic }; for(unsigned int i=0;i Date: Thu, 28 Mar 2013 01:01:19 +0000 Subject: [PATCH 272/387] - Always spawn RocketSmokeTrail and GrenadeSmokeTrail actors, and make them invisible for players who don't want to see them. This is needed for multiplayer sync between players with different settings for cl_rockettrails. SVN r4206 (trunk) --- src/p_mobj.cpp | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5cc5ecfe1..e0dc45adc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3054,37 +3054,36 @@ void AActor::Tick () } - if (cl_rockettrails & 2) + if (effects & FX_ROCKET) { - if (effects & FX_ROCKET) + if (++smokecounter == 4) { - if (++smokecounter==4) + // add some smoke behind the rocket + smokecounter = 0; + AActor *th = Spawn("RocketSmokeTrail", x-velx, y-vely, z-velz, ALLOW_REPLACE); + if (th) { - // add some smoke behind the rocket - smokecounter = 0; - AActor * th = Spawn("RocketSmokeTrail", x-velx, y-vely, z-velz, ALLOW_REPLACE); - if (th) - { - th->tics -= pr_rockettrail()&3; - if (th->tics < 1) th->tics = 1; - } + th->tics -= pr_rockettrail()&3; + if (th->tics < 1) th->tics = 1; + if (!(cl_rockettrails & 2)) th->renderflags |= RF_INVISIBLE; } } - else if (effects & FX_GRENADE) + } + else if (effects & FX_GRENADE) + { + if (++smokecounter == 8) { - if (++smokecounter==8) + smokecounter = 0; + angle_t moveangle = R_PointToAngle2(0,0,velx,vely); + AActor * th = Spawn("GrenadeSmokeTrail", + x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), + y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), + z - (height>>3) * (velz>>16) + (2*height)/3, ALLOW_REPLACE); + if (th) { - smokecounter = 0; - angle_t moveangle = R_PointToAngle2(0,0,velx,vely); - AActor * th = Spawn("GrenadeSmokeTrail", - x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), - y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10), - z - (height>>3) * (velz>>16) + (2*height)/3, ALLOW_REPLACE); - if (th) - { - th->tics -= pr_rockettrail()&3; - if (th->tics < 1) th->tics = 1; - } + th->tics -= pr_rockettrail()&3; + if (th->tics < 1) th->tics = 1; + if (!(cl_rockettrails & 2)) th->renderflags |= RF_INVISIBLE; } } } From 147da94e2fb9eb108dbd922d73bf19e219156d56 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 28 Mar 2013 01:29:23 +0000 Subject: [PATCH 273/387] - Added FDARI's CLOFF_JUMP_ON_MISS and CLOFF_AIM_VERT_NOOFFSET flags. SVN r4207 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 70 +++++++++++++++++------------- wadsrc/static/actors/constants.txt | 45 ++++++++++--------- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dcfe03dad..e1c7e367c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2920,34 +2920,37 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) enum CLOF_flags { - CLOFF_NOAIM_VERT = 0x1, - CLOFF_NOAIM_HORZ = 0x2, + CLOFF_NOAIM_VERT = 0x1, + CLOFF_NOAIM_HORZ = 0x2, - CLOFF_JUMPENEMY = 0x4, - CLOFF_JUMPFRIEND = 0x8, - CLOFF_JUMPOBJECT = 0x10, - CLOFF_JUMPNONHOSTILE = 0x20, + CLOFF_JUMPENEMY = 0x4, + CLOFF_JUMPFRIEND = 0x8, + CLOFF_JUMPOBJECT = 0x10, + CLOFF_JUMPNONHOSTILE = 0x20, - CLOFF_SKIPENEMY = 0x40, - CLOFF_SKIPFRIEND = 0x80, - CLOFF_SKIPOBJECT = 0x100, - CLOFF_SKIPNONHOSTILE = 0x200, + CLOFF_SKIPENEMY = 0x40, + CLOFF_SKIPFRIEND = 0x80, + CLOFF_SKIPOBJECT = 0x100, + CLOFF_SKIPNONHOSTILE = 0x200, - CLOFF_MUSTBESHOOTABLE = 0x400, + CLOFF_MUSTBESHOOTABLE = 0x400, - CLOFF_SKIPTARGET = 0x800, - CLOFF_ALLOWNULL = 0x1000, - CLOFF_CHECKPARTIAL = 0x2000, + CLOFF_SKIPTARGET = 0x800, + CLOFF_ALLOWNULL = 0x1000, + CLOFF_CHECKPARTIAL = 0x2000, - CLOFF_MUSTBEGHOST = 0x4000, - CLOFF_IGNOREGHOST = 0x8000, + CLOFF_MUSTBEGHOST = 0x4000, + CLOFF_IGNOREGHOST = 0x8000, - CLOFF_MUSTBESOLID = 0x10000, - CLOFF_BEYONDTARGET = 0x20000, + CLOFF_MUSTBESOLID = 0x10000, + CLOFF_BEYONDTARGET = 0x20000, - CLOFF_FROMBASE = 0x40000, - CLOFF_MUL_HEIGHT = 0x80000, - CLOFF_MUL_WIDTH = 0x100000 + CLOFF_FROMBASE = 0x40000, + CLOFF_MUL_HEIGHT = 0x80000, + CLOFF_MUL_WIDTH = 0x100000, + + CLOFF_JUMP_ON_MISS = 0x200000, + CLOFF_AIM_VERT_NOOFFSET = 0x400000, }; struct LOFData @@ -2955,6 +2958,7 @@ struct LOFData AActor *Self; AActor *Target; int Flags; + bool BadActor; }; ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) @@ -3025,6 +3029,7 @@ ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) { return TRACE_Skip; } + data->BadActor = true; return TRACE_Abort; } @@ -3124,7 +3129,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { pitch += self->pitch; } - else pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + else if (flags & CLOFF_AIM_VERT_NOOFFSET) + { + pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + offsetheight + target->height / 2); + } + else + { + pitch += R_PointToAngle2 (0,0, (fixed_t)xyvec.Length(), target->z - z1 + target->height / 2); + } } else if (flags & CLOFF_ALLOWNULL) { @@ -3166,21 +3178,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) lof_data.Self = self; lof_data.Target = target; lof_data.Flags = flags; + lof_data.BadActor = false; Trace(x1, y1, z1, sec, vx, vy, vz, range, 0xFFFFFFFF, ML_BLOCKEVERYTHING, self, trace, 0, CheckLOFTraceFunc, &lof_data); - if (trace.HitType == TRACE_HitActor) + if (trace.HitType == TRACE_HitActor || + ((flags & CLOFF_JUMP_ON_MISS) && !lof_data.BadActor && trace.HitType != TRACE_HitNone)) { - if (minrange > 0) + if (minrange > 0 && trace.Distance < minrange) { - double dx = trace.Actor->x - x1, - dy = trace.Actor->y - y1, - dz = trace.Actor->z + trace.Actor->height/2 - z1; - if (dx*dx+ dy*dy+ dz*dz < (double)minrange*(double)minrange) - { - return; - } + return; } ACTION_JUMP(jump); } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 587f10d35..24736eb3d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -308,34 +308,37 @@ const int SPF_FORCECLAMP = 1; enum { - CLOFF_NOAIM_VERT = 0x1, - CLOFF_NOAIM_HORZ = 0x2, + CLOFF_NOAIM_VERT = 0x1, + CLOFF_NOAIM_HORZ = 0x2, - CLOFF_JUMPENEMY = 0x4, - CLOFF_JUMPFRIEND = 0x8, - CLOFF_JUMPOBJECT = 0x10, - CLOFF_JUMPNONHOSTILE = 0x20, + CLOFF_JUMPENEMY = 0x4, + CLOFF_JUMPFRIEND = 0x8, + CLOFF_JUMPOBJECT = 0x10, + CLOFF_JUMPNONHOSTILE = 0x20, - CLOFF_SKIPENEMY = 0x40, - CLOFF_SKIPFRIEND = 0x80, - CLOFF_SKIPOBJECT = 0x100, - CLOFF_SKIPNONHOSTILE = 0x200, + CLOFF_SKIPENEMY = 0x40, + CLOFF_SKIPFRIEND = 0x80, + CLOFF_SKIPOBJECT = 0x100, + CLOFF_SKIPNONHOSTILE = 0x200, - CLOFF_MUSTBESHOOTABLE = 0x400, + CLOFF_MUSTBESHOOTABLE = 0x400, - CLOFF_SKIPTARGET = 0x800, - CLOFF_ALLOWNULL = 0x1000, - CLOFF_CHECKPARTIAL = 0x2000, + CLOFF_SKIPTARGET = 0x800, + CLOFF_ALLOWNULL = 0x1000, + CLOFF_CHECKPARTIAL = 0x2000, - CLOFF_MUSTBEGHOST = 0x4000, - CLOFF_IGNOREGHOST = 0x8000, + CLOFF_MUSTBEGHOST = 0x4000, + CLOFF_IGNOREGHOST = 0x8000, + + CLOFF_MUSTBESOLID = 0x10000, + CLOFF_BEYONDTARGET = 0x20000, - CLOFF_MUSTBESOLID = 0x10000, - CLOFF_BEYONDTARGET = 0x20000, + CLOFF_FROMBASE = 0x40000, + CLOFF_MUL_HEIGHT = 0x80000, + CLOFF_MUL_WIDTH = 0x100000, - CLOFF_FROMBASE = 0x40000, - CLOFF_MUL_HEIGHT = 0x80000, - CLOFF_MUL_WIDTH = 0x100000, + CLOFF_JUMP_ON_MISS = 0x200000, + CLOFF_AIM_VERT_NOOFFSET = 0x400000, CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE, CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ From 0d89183aa71e21b02dbdeced0d35b1482e993b26 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 2 Apr 2013 19:11:50 +0000 Subject: [PATCH 274/387] - ignoreteleporttags compatibility setting for a few maps. SVN r4208 (trunk) --- wadsrc/static/compatibility.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index c699fe61e..795c7f0b0 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -141,6 +141,9 @@ DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller dependi } 1D9E43988940CCD3555724E15DD8B1AB // Happy Time Circus map01 has bad teleporters +040F83028FFA74456E335ED300BE2C33 // MAP17 (TownInfection.wad) +156FA31F5FF72A87BF345B68029D3051 // MAP02 (nprject5.wad) +AF40D0E49BD1B76D4B1AADD8212ADC46 // MAP01 (the wad that shall not be named =P) { ignoreteleporttags } From 0a9a54fca86950520da12ba62319350470229444 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 9 Apr 2013 21:57:48 +0000 Subject: [PATCH 275/387] - Multiply the resulting velocity by the player's speed when "jumping" underwater. SVN r4209 (trunk) --- src/p_user.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 47d9ff2ed..3763cbe44 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2338,10 +2338,9 @@ void P_PlayerThink (player_t *player) // Jumping while crouching will force an un-crouch but not jump player->crouching = 1; } - else - if (player->mo->waterlevel >= 2) + else if (player->mo->waterlevel >= 2) { - player->mo->velz = 4*FRACUNIT; + player->mo->velz = FixedMul(4*FRACUNIT, player->mo->Speed); } else if (player->mo->flags & MF_NOGRAVITY) { From ec6d522a29b0d59c40898f8033905a389db8efba Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 9 Apr 2013 22:15:41 +0000 Subject: [PATCH 276/387] - Remove the requirement that only action function default parameters can accept a constant expression that evaluates to the class 'None'. (I don't know why that was there to begin with.) SVN r4210 (trunk) --- src/thingdef/thingdef_expression.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index a5644b88f..93dc4086e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2523,9 +2523,9 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) FName clsname = basex->EvalExpression(NULL).GetName(); const PClass *cls = NULL; - if (clsname != NAME_None || !ctx.isconst) + if (clsname != NAME_None) { - cls= PClass::FindClass(clsname); + cls = PClass::FindClass(clsname); if (cls == NULL) { if (!ctx.lax) From 85d4350190f1abdc4d3d05ba155f4070cefac4f7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 9 Apr 2013 22:24:18 +0000 Subject: [PATCH 277/387] - Fixed: AInventory::Touch() should check for a local player view before trying the pickup, because if it's a morph powerup, after being picked up, the toucher this function received will no longer be the active player. SVN r4211 (trunk) --- src/g_shared/a_pickups.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 1ed5b4919..89bfe3086 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -938,6 +938,8 @@ void AInventory::Touch (AActor *toucher) toucher = toucher->player->mo; } + bool localview = toucher->CheckLocalView(consoleplayer); + if (!CallTryPickup (toucher, &toucher)) return; // This is the only situation when a pickup flash should ever play. @@ -950,7 +952,7 @@ void AInventory::Touch (AActor *toucher) { const char * message = PickupMessage (); - if (message != NULL && *message != 0 && toucher->CheckLocalView (consoleplayer) + if (message != NULL && *message != 0 && localview && (StaticLastMessageTic != gametic || StaticLastMessage != message)) { StaticLastMessageTic = gametic; From f7c55c0936246732db3e91a46cc7563f387e34de Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 9 Apr 2013 22:40:27 +0000 Subject: [PATCH 278/387] - Do copy a monster's special to its morphed version so that it can be properly restored when it unmorphs. SVN r4212 (trunk) --- src/g_shared/a_morph.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 8b76e2f66..211718ae8 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -394,8 +394,8 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s morphed->MorphStyle = style; morphed->MorphExitFlash = (exit_flash) ? exit_flash : RUNTIME_CLASS(ATeleportFog); morphed->FlagsSave = actor->flags & ~MF_JUSTHIT; - //morphed->special = actor->special; - //memcpy (morphed->args, actor->args, sizeof(actor->args)); + morphed->special = actor->special; + memcpy (morphed->args, actor->args, sizeof(actor->args)); morphed->CopyFriendliness (actor, true); morphed->flags |= actor->flags & MF_SHADOW; morphed->flags3 |= actor->flags3 & MF3_GHOST; @@ -405,6 +405,7 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s } morphed->AddToHash (); actor->RemoveFromHash (); + actor->special = 0; actor->tid = 0; actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags |= MF_UNMORPHED; From 2fb64108a7dfc6ec96a7ceb757b75d2a4030139f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 9 Apr 2013 22:45:20 +0000 Subject: [PATCH 279/387] - Fixed: Monsters with STAYMORPHED set would still unmorph. SVN r4213 (trunk) --- src/g_shared/a_morph.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 211718ae8..58781f05a 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -428,7 +428,8 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) if (beast->UnmorphTime == 0 || beast->UnmorphedMe == NULL || - beast->flags3 & MF3_STAYMORPHED) + beast->flags3 & MF3_STAYMORPHED || + beast->UnmorphedMe->flags3 & MF3_STAYMORPHED) { return false; } From cbe11657f008e96506ae7a1fa7af633ad8d635fa Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 10 Apr 2013 00:13:55 +0000 Subject: [PATCH 280/387] - Fixed: A_Face should take into account the target's height when aiming pitch. SVN r4214 (trunk) --- src/p_enemy.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index dd5ab581b..dc96eb8ac 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2792,7 +2792,16 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch) // result is only used in a ratio. double dist_x = self->target->x - self->x; double dist_y = self->target->y - self->y; - double dist_z = self->target->z - self->z; + // Positioning ala missile spawning, 32 units above foot level + fixed_t source_z = self->z + 32*FRACUNIT + self->GetBobOffset(); + fixed_t target_z = self->target->z + 32*FRACUNIT + self->target->GetBobOffset(); + // If the target z is above the target's head, reposition to the middle of + // its body. + if (target_z >= self->target->z + self->target->height) + { + target_z = self->target->z + self->target->height / 2; + } + double dist_z = target_z - source_z; double dist = sqrt(dist_x*dist_x + dist_y*dist_y + dist_z*dist_z); int other_pitch = (int)rad2bam(asin(dist_z / dist)); From a5d770b433459dc3cdeabc6158f2949cdc1a8fa8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 16 Apr 2013 17:55:17 +0000 Subject: [PATCH 281/387] - Dropped items with the DONTGIB flag set will no longer be destroyed by crushers. SVN r4215 (trunk) --- src/actor.h | 2 +- src/g_shared/a_pickups.cpp | 27 +++++++++++++++++++++++++++ src/g_shared/a_pickups.h | 1 + src/p_mobj.cpp | 9 +-------- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/actor.h b/src/actor.h index 1b4e5ac91..4bd19f1aa 100644 --- a/src/actor.h +++ b/src/actor.h @@ -700,7 +700,7 @@ public: virtual bool Massacre (); // Transforms the actor into a finely-ground paste - bool Grind(bool items); + virtual bool Grind(bool items); // Is the other actor on my team? bool IsTeammate (AActor *other); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 89bfe3086..bba5cfdc7 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -515,6 +515,33 @@ void AInventory::BeginPlay () flags |= MF_DROPPED; // [RH] Items are dropped by default } +//=========================================================================== +// +// AInventory :: Grind +// +//=========================================================================== + +bool AInventory::Grind(bool items) +{ + // Does this grind request even care about items? + if (!items) + { + return false; + } + // Dropped items are normally destroyed by crushers. Set the DONTGIB flag, + // and they'll act like corpses with it set and be immune to crushers. + if (flags & MF_DROPPED) + { + if (!(flags3 & MF3_DONTGIB)) + { + Destroy(); + } + return false; + } + // Non-dropped items call the super method for compatibility. + return Super::Grind(items); +} + //=========================================================================== // // AInventory :: DoEffect diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index b31d4e288..4be7100a8 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -157,6 +157,7 @@ public: virtual bool SpecialDropAction (AActor *dropper); virtual bool DrawPowerup (int x, int y); virtual void DoEffect (); + virtual bool Grind(bool items); virtual const char *PickupMessage (); virtual void PlayPickupSound (AActor *toucher); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e0dc45adc..9895d7a56 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -998,7 +998,7 @@ bool AActor::Grind(bool items) // ZDoom behavior differs from standard as crushed corpses cannot be raised. // The reason for the change was originally because of a problem with players, // see rh_log entry for February 21, 1999. Don't know if it is still relevant. - if (state == NULL // Only use the default crushed state if: + if (state == NULL // Only use the default crushed state if: && !(flags & MF_NOBLOOD) // 1. the monster bleeeds, && (i_compatflags & COMPATF_CORPSEGIBS) // 2. the compat setting is on, && player == NULL) // 3. and the thing isn't a player. @@ -1086,13 +1086,6 @@ bool AActor::Grind(bool items) return false; // keep checking } - // crunch dropped items - if (flags & MF_DROPPED) - { - if (items) Destroy (); // Only destroy dropped items if wanted - return false; // keep checking - } - // killough 11/98: kill touchy things immediately if (flags6 & MF6_TOUCHY && (flags6 & MF6_ARMED || IsSentient())) { From 6dc21f9a8b27199818c65bb8598c5cfdb4443b34 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 16 Apr 2013 20:17:34 +0000 Subject: [PATCH 282/387] - Fixed: Voxel rendering completely fell apart when a mirror came into view. SVN r4216 (trunk) --- src/r_things.cpp | 55 +++++++++++++++++++++++++++++++++++------------- src/r_things.h | 34 ++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index dae30ae1c..276cbd8b7 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -424,13 +424,18 @@ void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop { R_CheckOffscreenBuffer(RenderTarget->GetWidth(), RenderTarget->GetHeight(), !!(flags & DVF_SPANSONLY)); } + if (spr->bInMirror) + { + flags |= DVF_MIRRORED; + } // Render the voxel, either directly to the screen or offscreen. - R_DrawVoxel(spr->gx, spr->gy, spr->gz, spr->angle, spr->xscale, spr->yscale, spr->voxel, spr->Style.colormap, cliptop, clipbot, + R_DrawVoxel(spr->vx, spr->vy, spr->vz, spr->vang, spr->gx, spr->gy, spr->gz, spr->angle, + spr->xscale, spr->yscale, spr->voxel, spr->Style.colormap, cliptop, clipbot, minslabz, maxslabz, flags); // Blend the voxel, if that's what we need to do. - if (flags != 0) + if ((flags & ~DVF_MIRRORED) != 0) { for (int x = 0; x < viewwidth; ++x) { @@ -760,10 +765,10 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->angle -= angle_t(ang * (4294967296.f / 360)); } - // These are irrelevant for voxels. - vis->texturemid = 0x1CEDBEEF; - vis->startfrac = 0x1CEDBEEF; - vis->xiscale = 0x1CEDBEEF; + vis->vx = viewx; + vis->vy = viewy; + vis->vz = viewz; + vis->vang = viewangle; } // killough 3/27/98: save sector for special clipping later @@ -787,6 +792,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->fakefloor = fakefloor; vis->fakeceiling = fakeceiling; vis->ColormapNum = 0; + vis->bInMirror = MirrorFlags & RF_XFLIP; if (voxel != NULL) { @@ -1897,6 +1903,16 @@ void R_DrawSprite (vissprite_t *spr) return; } } + // Add everything outside the left and right edges to the clipping array + // for R_DrawVisVoxel(). + if (x1 > 0) + { + clearbufshort(cliptop, x1, viewheight); + } + if (x2 < viewwidth - 1) + { + clearbufshort(cliptop + x2 + 1, viewwidth - x2 - 1, viewheight); + } int minvoxely = spr->gzt <= hzt ? 0 : (spr->gzt - hzt) / spr->yscale; int maxvoxely = spr->gzb > hzb ? INT_MAX : (spr->gzt - hzb) / spr->yscale; R_DrawVisVoxel(spr, minvoxely, maxvoxely, cliptop, clipbot); @@ -2228,7 +2244,8 @@ void R_DrawParticle (vissprite_t *vis) extern fixed_t baseyaspectmul; -void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang, +void R_DrawVoxel(fixed_t globalposx, fixed_t globalposy, fixed_t globalposz, angle_t viewang, + fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang, fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj, lighttable_t *colormap, short *daumost, short *dadmost, int minslabz, int maxslabz, int flags) { @@ -2244,12 +2261,14 @@ void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t daspran const int nytooclose = centerxwide * 2100, nytoofar = 32768*32768 - 1048576; const int xdimenscale = Scale(centerxwide, yaspectmul, 160); - const fixed_t globalposx = viewx >> 12; - const fixed_t globalposy = -viewy >> 12; - const fixed_t globalposz = -viewz >> 8; const double centerxwide_f = centerxwide; const double centerxwidebig_f = centerxwide_f * 65536*65536*8; + // Convert to Build's coordinate system. + globalposx = globalposx >> 12; + globalposy = -globalposy >> 12; + globalposz = -globalposz >> 8; + dasprx = dasprx >> 12; daspry = -daspry >> 12; dasprz = -dasprz >> 8; @@ -2259,20 +2278,19 @@ void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t daspran daxscale = daxscale / (0xC000 >> 6); dayscale = dayscale / (0xC000 >> 6); - cosang = viewcos >> 2; - sinang = -viewsin >> 2; + cosang = finecosine[viewang >> ANGLETOFINESHIFT] >> 2; + sinang = -finesine[viewang >> ANGLETOFINESHIFT] >> 2; sprcosang = finecosine[dasprang >> ANGLETOFINESHIFT] >> 2; sprsinang = -finesine[dasprang >> ANGLETOFINESHIFT] >> 2; R_SetupDrawSlab(colormap); // Select mip level - i = abs(DMulScale8(dasprx - globalposx, viewcos, daspry - globalposy, -viewsin)); + i = abs(DMulScale6(dasprx - globalposx, cosang, daspry - globalposy, sinang)); i = DivScale6(i, MIN(daxscale, dayscale)); j = FocalLengthX >> 3; - for (k = 0; k < voxobj->NumMips; ++k) + for (k = 0; i >= j && k < voxobj->NumMips; ++k) { - if (i < j) { break; } i >>= 1; } if (k >= voxobj->NumMips) k = voxobj->NumMips - 1; @@ -2404,6 +2422,13 @@ void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t daspran if (rx > viewwidth) rx = viewwidth; if (rx <= lx) continue; + if (flags & DVF_MIRRORED) + { + int t = viewwidth - lx; + lx = viewwidth - rx; + rx = t; + } + fixed_t l1 = xs_RoundToInt(centerxwidebig_f / (ny - yoff)); fixed_t l2 = xs_RoundToInt(centerxwidebig_f / (ny + yoff)); for (; voxptr < voxend; voxptr = (kvxslab_t *)((BYTE *)voxptr + voxptr->zleng + 3)) diff --git a/src/r_things.h b/src/r_things.h index 92428b639..14ed8afc9 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -35,25 +35,36 @@ struct vissprite_t fixed_t gx, gy, gz; // origin in world coordinates angle_t angle; fixed_t gzb, gzt; // global bottom / top for silhouette clipping - fixed_t startfrac; // horizontal position of x1 fixed_t xscale, yscale; - fixed_t xiscale; // negative if flipped fixed_t depth; fixed_t idepth; // 1/z - fixed_t texturemid; DWORD FillColor; + fixed_t floorclip; + union + { + // Used by regular sprites + struct + { + FTexture *pic; + fixed_t texturemid; + fixed_t startfrac; // horizontal position of x1 + fixed_t xiscale; // negative if flipped + }; + // Used by voxels + struct + { + struct FVoxel *voxel; + fixed_t vx, vy, vz; // view origin + angle_t vang; // view angle + }; + }; sector_t *heightsec; // killough 3/27/98: height sector for underwater/fake ceiling sector_t *sector; // [RH] sector this sprite is in F3DFloor *fakefloor; F3DFloor *fakeceiling; - fixed_t floorclip; - union - { - FTexture *pic; - struct FVoxel *voxel; - }; BYTE bIsVoxel:1; // [RH] Use voxel instead of pic BYTE bSplitSprite:1; // [RH] Sprite was split by a drawseg + BYTE bInMirror:1; // [RH] Sprite is "inside" a mirror BYTE FakeFlatStat; // [RH] which side of fake/floor ceiling sprite is on BYTE ColormapNum; // Which colormap is rendered (needed for shaded drawer) short renderflags; @@ -102,9 +113,10 @@ void R_DrawRemainingPlayerSprites (); void R_CheckOffscreenBuffer(int width, int height, bool spansonly); -enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2 }; +enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2, DVF_MIRRORED = 4 }; -void R_DrawVoxel(fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang, +void R_DrawVoxel(fixed_t viewx, fixed_t viewy, fixed_t viewz, angle_t viewangle, + fixed_t dasprx, fixed_t daspry, fixed_t dasprz, angle_t dasprang, fixed_t daxscale, fixed_t dayscale, FVoxel *voxobj, lighttable_t *colormap, short *daumost, short *dadmost, int minslabz, int maxslabz, int flags); From 865a535af2fb604a5f722e22d1d0ec2793f514c3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 16 Apr 2013 20:22:01 +0000 Subject: [PATCH 283/387] - Force all voxel mip levels so use the same pivot point as the first level. SVN r4217 (trunk) --- src/r_data/voxels.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/r_data/voxels.cpp b/src/r_data/voxels.cpp index eca4c89c4..693986704 100644 --- a/src/r_data/voxels.cpp +++ b/src/r_data/voxels.cpp @@ -296,6 +296,14 @@ FVoxel *R_LoadKVX(int lumpnum) } voxel->NumMips = mip; + // Fix pivot data for submips, since some tools seem to like to just center these. + for (i = 1; i < mip; ++i) + { + voxel->Mips[i].PivotX = voxel->Mips[0].PivotX >> i; + voxel->Mips[i].PivotY = voxel->Mips[0].PivotY >> i; + voxel->Mips[i].PivotZ = voxel->Mips[0].PivotZ >> i; + } + for (i = 0; i < mip; ++i) { if (!CopyVoxelSlabs((kvxslab_t *)voxel->Mips[i].SlabData, slabs[i], voxel->Mips[i].OffsetX[voxel->Mips[i].SizeX])) From d99517292b47d0c2e6451b1e4b26275aa1f5bd6d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 16 Apr 2013 20:26:35 +0000 Subject: [PATCH 284/387] - Added DONTGIB flag to Key, so key-dropping enemies can be used reliably near crushers. SVN r4218 (trunk) --- wadsrc/static/actors/shared/inventory.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 7b2c3d5ef..5f5e20b50 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -142,6 +142,7 @@ Actor HealthPickup : Inventory native Actor Key : Inventory native { + +DONTGIB // Don't disappear due to a crusher +INVENTORY.INTERHUBSTRIP Inventory.PickupSound "misc/k_pkup" } From c069295f1901da57d20e80f556fd48fb231850d6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 16 Apr 2013 20:39:54 +0000 Subject: [PATCH 285/387] - Fixed: When trying to unmorph a monster, make sure the morphed version doesn't have the TOUCHY flag set, or checking the position of the unmorphed version will kill the morphed version, since they will both exist in the same place at the same time, and TOUCHY is really touchy about that. SVN r4219 (trunk) --- src/g_shared/a_morph.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 58781f05a..da4f46918 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -437,10 +437,13 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force) actor->SetOrigin (beast->x, beast->y, beast->z); actor->flags |= MF_SOLID; beast->flags &= ~MF_SOLID; + int beastflags6 = beast->flags6; + beast->flags6 &= ~MF6_TOUCHY; if (!force && !P_TestMobjLocation (actor)) { // Didn't fit actor->flags &= ~MF_SOLID; beast->flags |= MF_SOLID; + beast->flags6 = beastflags6; beast->UnmorphTime = level.time + 5*TICRATE; // Next try in 5 seconds return false; } From a50e670c0c6037b48a5e0365a1a35e974d79bbc9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 17 Apr 2013 01:32:40 +0000 Subject: [PATCH 286/387] - Use tests less prone to overflow on very steep slopes when detecting which side of a plane the camera is on. Mostly, this means testing the distance of the camera to the plane rather than computing the plane's Z at the camera and comparing that with the camera's Z. SVN r4220 (trunk) --- src/p_interaction.cpp | 2 +- src/r_bsp.cpp | 10 ++++------ src/r_defs.h | 8 +++++++- src/r_plane.cpp | 2 +- src/r_segs.cpp | 10 +++++----- src/r_utility.cpp | 22 ++++++++++++---------- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 51527a266..a61c1b9dc 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -348,7 +348,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) int realgibhealth = realthis->GibHealth(); if (realthis->health >= realgibhealth) { - realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed) + realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)l } } realthis->Die(source, inflictor, dmgflags); diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 4fe0ef03b..9ada2fdec 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -346,7 +346,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, { sector_t *heightsec = viewsector->heightsec; bool underwater = r_fakingunderwater || - (heightsec && viewz <= heightsec->floorplane.ZatPoint (viewx, viewy)); + (heightsec && heightsec->floorplane.PointOnSide(viewx, viewy, viewz) <= 0); bool doorunderwater = false; int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES); @@ -405,9 +405,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, } } -// fixed_t refflorz = s->floorplane.ZatPoint (viewx, viewy); fixed_t refceilz = s->ceilingplane.ZatPoint (viewx, viewy); -// fixed_t orgflorz = sec->floorplane.ZatPoint (viewx, viewy); fixed_t orgceilz = sec->ceilingplane.ZatPoint (viewx, viewy); #if 1 @@ -482,7 +480,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, } FakeSide = FAKED_BelowFloor; } - else if (heightsec && viewz >= heightsec->ceilingplane.ZatPoint (viewx, viewy) && + else if (heightsec && heightsec->ceilingplane.PointOnSide(viewx, viewy, viewz) <= 0 && orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY)) { // Above-ceiling hack tempsec->ceilingplane = s->ceilingplane; @@ -1084,7 +1082,7 @@ void R_Subsector (subsector_t *sub) basecolormap = frontsector->ColorMap; } - ceilingplane = frontsector->ceilingplane.ZatPoint (viewx, viewy) > viewz || + ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 || frontsector->GetTexture(sector_t::ceiling) == skyflatnum || (frontsector->CeilingSkyBox != NULL && frontsector->CeilingSkyBox->bAlways) || (frontsector->heightsec && @@ -1123,7 +1121,7 @@ void R_Subsector (subsector_t *sub) // killough 3/7/98: Add (x,y) offsets to flats, add deep water check // killough 3/16/98: add floorlightlevel // killough 10/98: add support for skies transferred from sidedefs - floorplane = frontsector->floorplane.ZatPoint (viewx, viewy) < viewz || // killough 3/7/98 + floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98 frontsector->GetTexture(sector_t::floor) == skyflatnum || (frontsector->FloorSkyBox != NULL && frontsector->FloorSkyBox->bAlways) || (frontsector->heightsec && diff --git a/src/r_defs.h b/src/r_defs.h index 02eefcf91..c2f3e5b34 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -212,10 +212,16 @@ struct secplane_t fixed_t a, b, c, d, ic; + // Returns < 0 : behind; == 0 : on; > 0 : in front + int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const + { + return TMulScale16(a,x, b,y, c,z) + d; + } + // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes fixed_t Zat0 () const { - return ic < 0? d:-d; + return ic < 0 ? d : -d; } // Returns the value of z at (x,y) diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 16e9b12e2..8bf544455 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1697,7 +1697,7 @@ void R_DrawTiltedPlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske plane_sz[0] = -plane_sz[0]; } - planelightfloat = (r_TiltVisibility * lxscale * lyscale) / (float)(abs(pl->height.ZatPoint (viewx, viewy) - viewz)); + planelightfloat = (r_TiltVisibility * lxscale * lyscale) / (fabs(pl->height.ZatPoint(FIXED2DBL(viewx), FIXED2DBL(viewy)) - FIXED2DBL(viewz))) / 65536.0; if (pl->height.c > 0) planelightfloat = -planelightfloat; diff --git a/src/r_segs.cpp b/src/r_segs.cpp index e37cbe086..c4dca60f6 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2242,10 +2242,10 @@ void R_NewWall (bool needlights) // killough 3/7/98: add deep water check if (frontsector->GetHeightSec() == NULL) { - if (frontsector->floorplane.ZatPoint (viewx, viewy) >= viewz) // above view plane + if (frontsector->floorplane.PointOnSide(viewx, viewy, viewz) <= 0) // above view plane markfloor = false; - if (frontsector->ceilingplane.ZatPoint (viewx, viewy) <= viewz && - frontsector->GetTexture(sector_t::ceiling) != skyflatnum) // below view plane + if (frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) <= 0 && + frontsector->GetTexture(sector_t::ceiling) != skyflatnum) // below view plane markceiling = false; } @@ -2394,13 +2394,13 @@ void R_StoreWallRange (int start, int stop) ds_p->silhouette = 0; if (rw_frontfz1 > rw_backfz1 || rw_frontfz2 > rw_backfz2 || - backsector->floorplane.ZatPoint (viewx, viewy) > viewz) + backsector->floorplane.PointOnSide(viewx, viewy, viewz) < 0) { ds_p->silhouette = SIL_BOTTOM; } if (rw_frontcz1 < rw_backcz1 || rw_frontcz2 < rw_backcz2 || - backsector->ceilingplane.ZatPoint (viewx, viewy) < viewz) + backsector->ceilingplane.PointOnSide(viewx, viewy, viewz) < 0) { ds_p->silhouette |= SIL_TOP; } diff --git a/src/r_utility.cpp b/src/r_utility.cpp index b75811038..b5382ccad 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -849,15 +849,17 @@ void R_SetupFrame (AActor *actor) TArray &lightlist = viewsector->e->XFloor.lightlist; if (lightlist.Size() > 0) { - for(unsigned int i=0;ifloorplane.ZatPoint(viewx, viewy); - - if (lightbottom < viewz) + secplane_t *plane; + int viewside; + plane = (i < lightlist.Size()-1) ? &lightlist[i+1].plane : &viewsector->floorplane; + viewside = plane->PointOnSide(viewx, viewy, viewz); + // Reverse the direction of the test if the plane was downward facing. + // We want to know if the view is above it, whatever its orientation may be. + if (plane->c < 0) + viewside = -viewside; + if (viewside > 0) { // 3d floor 'fog' is rendered as a blending value PalEntry blendv = lightlist[i].blend; @@ -874,9 +876,9 @@ void R_SetupFrame (AActor *actor) const sector_t *s = viewsector->GetHeightSec(); if (s != NULL) { - newblend = viewz < s->floorplane.ZatPoint (viewx, viewy) + newblend = s->floorplane.PointOnSide(viewx, viewy, viewz) < 0 ? s->bottommap - : viewz > s->ceilingplane.ZatPoint (viewx, viewy) + : s->ceilingplane.PointOnSide(viewx, viewy, viewz) < 0 ? s->topmap : s->midmap; if (APART(newblend) == 0 && newblend >= numfakecmaps) From cb64014494292b12047de0a559285099dca2527f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 19 Apr 2013 02:24:20 +0000 Subject: [PATCH 287/387] - Added CROUCHABLEMORPH flag for the PlayerPawn class. Use this to indicate that a morphed player class can crouch. (Regular players can always crouch, hence the name CROUCHABLEMORPH and not CANMORPH or ALLOWMORPH.) SVN r4221 (trunk) --- src/d_player.h | 1 + src/p_user.cpp | 7 ++++--- src/thingdef/thingdef_data.cpp | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 48c387444..96fb1399f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -163,6 +163,7 @@ enum { PPF_NOTHRUSTWHENINVUL = 1, // Attacks do not thrust the player if they are invulnerable. PPF_CANSUPERMORPH = 2, // Being remorphed into this class can give you a Tome of Power + PPF_CROUCHABLEMORPH = 4, // This morphed player can crouch }; // diff --git a/src/p_user.cpp b/src/p_user.cpp index 3763cbe44..42031d296 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2204,7 +2204,8 @@ void P_PlayerThink (player_t *player) { player->cmd.ucmd.buttons &= ~BT_CROUCH; } - if (player->morphTics == 0 && player->health > 0 && level.IsCrouchingAllowed()) + if ((player->morphTics == 0 || player->mo->PlayerFlags & PPF_CROUCHABLEMORPH) + && player->health > 0 && level.IsCrouchingAllowed()) { if (!totallyfrozen) { @@ -2212,11 +2213,11 @@ void P_PlayerThink (player_t *player) if (crouchdir == 0) { - crouchdir = (player->cmd.ucmd.buttons & BT_CROUCH)? -1 : 1; + crouchdir = (player->cmd.ucmd.buttons & BT_CROUCH) ? -1 : 1; } else if (player->cmd.ucmd.buttons & BT_CROUCH) { - player->crouching=0; + player->crouching = 0; } if (crouchdir == 1 && player->crouchfactor < FRACUNIT && player->mo->z + player->mo->height < player->mo->ceilingz) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 68a17241b..c542c895d 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -336,6 +336,7 @@ static FFlagDef PlayerPawnFlags[] = // PlayerPawn flags DEFINE_FLAG(PPF, NOTHRUSTWHENINVUL, APlayerPawn, PlayerFlags), DEFINE_FLAG(PPF, CANSUPERMORPH, APlayerPawn, PlayerFlags), + DEFINE_FLAG(PPF, CROUCHABLEMORPH, APlayerPawn, PlayerFlags), }; static FFlagDef PowerSpeedFlags[] = From 9f71c7cb4e07a00e5bec7a82151b37b23e346e72 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 20 Apr 2013 21:32:03 +0000 Subject: [PATCH 288/387] - added Xaser's reactiontime for ACS and DECORATE expression patch. SVN r4222 (trunk) --- src/p_acs.cpp | 7 +++++++ src/thingdef/thingdef_expression.cpp | 1 + wadsrc/static/actors/actor.txt | 1 + 3 files changed, 9 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 7bfc87f39..05e9a34a2 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2847,6 +2847,7 @@ enum APROP_Stamina = 34, APROP_Height = 35, APROP_Radius = 36, + APROP_ReactionTime = 37, }; // These are needed for ACS's APROP_RenderStyle @@ -3058,6 +3059,10 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) actor->stamina = value; break; + case APROP_ReactionTime: + actor->reactiontime = value; + break; + default: // do nothing. break; @@ -3128,6 +3133,7 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Stamina: return actor->stamina; case APROP_Height: return actor->height; case APROP_Radius: return actor->radius; + case APROP_ReactionTime:return actor->reactiontime; default: return 0; } @@ -3170,6 +3176,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Stamina: case APROP_Height: case APROP_Radius: + case APROP_ReactionTime: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 93dc4086e..1e4065d28 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -86,6 +86,7 @@ DEFINE_MEMBER_VARIABLE(accuracy, AActor) DEFINE_MEMBER_VARIABLE(stamina, AActor) DEFINE_MEMBER_VARIABLE(height, AActor) DEFINE_MEMBER_VARIABLE(radius, AActor) +DEFINE_MEMBER_VARIABLE(reactiontime, AActor) //========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 9ec0e5fe6..8e76ca374 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -58,6 +58,7 @@ ACTOR Actor native //: Thinker native int stamina; native fixed_t height; native fixed_t radius; + native int reactiontime; // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); From 92d54ca0fc3e6d5ab870130106dae931b59359b1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 21 Apr 2013 02:22:37 +0000 Subject: [PATCH 289/387] - Instead of setting the default skybox in every sector without an explicit skybox set, set it once in the level struct and then use that for sectors with a NULL skybox. This fixes zpack's E2M3 so that when it removes its sector stacks, you will get the default skybox in their place, since stacked sectors and skyboxes use the same pointers in a sector. SVN r4224 (trunk) --- src/dobjgc.cpp | 1 + src/g_level.cpp | 7 +++++++ src/g_level.h | 2 ++ src/g_shared/a_skies.cpp | 20 ++++++-------------- src/r_bsp.cpp | 11 +++++++---- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index ebf61a698..d52962f11 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -307,6 +307,7 @@ static void MarkRoot() DThinker::MarkRoots(); FCanvasTextureInfo::Mark(); Mark(DACSThinker::ActiveThinker); + Mark(level.DefaultSkybox); // Mark dead bodies. for (i = 0; i < BODYQUESIZE; ++i) { diff --git a/src/g_level.cpp b/src/g_level.cpp index e01152924..3b0c8fe12 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -77,6 +77,7 @@ #include "d_netinf.h" #include "v_palette.h" #include "menu/menu.h" +#include "a_sharedglobal.h" #include "a_strifeglobal.h" #include "r_data/colormaps.h" #include "farchive.h" @@ -1272,6 +1273,7 @@ void G_InitLevelLocals () NormalLight.ChangeFade (level.fadeto); level.DefaultEnvironment = info->DefaultEnvironment; + level.DefaultSkybox = NULL; } //========================================================================== @@ -1435,6 +1437,11 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad) P_SerializeSubsectors(arc); StatusBar->Serialize (arc); + if (SaveVersion >= 4222) + { // This must be done *after* thinkers are serialized. + arc << level.DefaultSkybox; + } + arc << level.total_monsters << level.total_items << level.total_secrets; // Does this level have custom translations? diff --git a/src/g_level.h b/src/g_level.h index cd8f6c1f7..e7d1cbbd2 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -426,6 +426,8 @@ struct FLevelLocals int airsupply; int DefaultEnvironment; // Default sound environment. + TObjPtr DefaultSkybox; + FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level SBYTE WallVertLight; // Light diffs for vert/horiz walls diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 5e894002d..616b87c9e 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -49,21 +49,9 @@ void ASkyViewpoint::BeginPlay () { Super::BeginPlay (); - if (tid == 0) + if (tid == 0 && level.DefaultSkybox == NULL) { - int i; - - for (i = 0; i ColorMap; } + skybox = frontsector->CeilingSkyBox != NULL ? frontsector->CeilingSkyBox : level.DefaultSkybox; ceilingplane = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) > 0 || frontsector->GetTexture(sector_t::ceiling) == skyflatnum || - (frontsector->CeilingSkyBox != NULL && frontsector->CeilingSkyBox->bAlways) || + (skybox != NULL && skybox->bAlways) || (frontsector->heightsec && !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) && frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum) ? @@ -1099,7 +1101,7 @@ void R_Subsector (subsector_t *sub) frontsector->GetYScale(sector_t::ceiling), frontsector->GetAngle(sector_t::ceiling), frontsector->sky, - frontsector->CeilingSkyBox + skybox ) : NULL; if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size()) @@ -1121,9 +1123,10 @@ void R_Subsector (subsector_t *sub) // killough 3/7/98: Add (x,y) offsets to flats, add deep water check // killough 3/16/98: add floorlightlevel // killough 10/98: add support for skies transferred from sidedefs + skybox = frontsector->FloorSkyBox != NULL ? frontsector->FloorSkyBox : level.DefaultSkybox; floorplane = frontsector->floorplane.PointOnSide(viewx, viewy, viewz) > 0 || // killough 3/7/98 frontsector->GetTexture(sector_t::floor) == skyflatnum || - (frontsector->FloorSkyBox != NULL && frontsector->FloorSkyBox->bAlways) || + (skybox != NULL && skybox->bAlways) || (frontsector->heightsec && !(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) && frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum) ? @@ -1138,7 +1141,7 @@ void R_Subsector (subsector_t *sub) frontsector->GetYScale(sector_t::floor), frontsector->GetAngle(sector_t::floor), frontsector->sky, - frontsector->FloorSkyBox + skybox ) : NULL; // kg3D - fake planes rendering From 6921a3edc2dd0f35a498a7f6944c41c2f6f5b4eb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 23 Apr 2013 03:51:51 +0000 Subject: [PATCH 290/387] - Fixed: r4220 broke 3D floor rendering, because 3D floors have the floor and ceiling orientations reversed compared to normal conventions. SVN r4225 (trunk) --- src/r_segs.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index c4dca60f6..9d9f197db 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2242,10 +2242,18 @@ void R_NewWall (bool needlights) // killough 3/7/98: add deep water check if (frontsector->GetHeightSec() == NULL) { - if (frontsector->floorplane.PointOnSide(viewx, viewy, viewz) <= 0) // above view plane + int planeside; + + planeside = frontsector->floorplane.PointOnSide(viewx, viewy, viewz); + if (frontsector->floorplane.c < 0) // 3D floors have the floor backwards + planeside = -planeside; + if (planeside <= 0) // above view plane markfloor = false; - if (frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz) <= 0 && - frontsector->GetTexture(sector_t::ceiling) != skyflatnum) // below view plane + + planeside = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz); + if (frontsector->ceilingplane.c > 0) // 3D floors have the ceiling backwards + planeside = -planeside; + if (planeside <= 0) // below view plane markceiling = false; } From 77b57e2f9818d1eeeab905be505d26c7fc3ca9e6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 01:58:51 +0000 Subject: [PATCH 291/387] - Fixed: Hexen's A_DemonDeath and A_Demon2Death had been converted to incorrect generic Decorate. SVN r4226 (trunk) --- wadsrc/static/actors/hexen/demons.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/wadsrc/static/actors/hexen/demons.txt b/wadsrc/static/actors/hexen/demons.txt index cb1428ee7..80926d7ad 100644 --- a/wadsrc/static/actors/hexen/demons.txt +++ b/wadsrc/static/actors/hexen/demons.txt @@ -20,7 +20,7 @@ ACTOR Demon1 31 DeathSound "DemonDeath" ActiveSound "DemonActive" Obituary "$OB_DEMON1" - const int ChunkFlags = SXF_TRANSFERTRANSLATION|SXF_ABSOLUTEVELOCITY; + const int ChunkFlags = SXF_TRANSFERTRANSLATION | SXF_ABSOLUTEVELOCITY; States { Spawn: @@ -53,11 +53,11 @@ ACTOR Demon1 31 Stop XDeath: DEMN H 6 - DEMN I 0 A_SpawnItemEx("Demon1Chunk1", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 90) - DEMN I 0 A_SpawnItemEx("Demon1Chunk2", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEMN I 0 A_SpawnItemEx("Demon1Chunk3", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEMN I 0 A_SpawnItemEx("Demon1Chunk4", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEMN I 6 A_SpawnItemEx("Demon1Chunk5", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) + DEMN I 0 A_SpawnItemEx("Demon1Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags) + DEMN I 0 A_SpawnItemEx("Demon1Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEMN I 0 A_SpawnItemEx("Demon1Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEMN I 0 A_SpawnItemEx("Demon1Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEMN I 6 A_SpawnItemEx("Demon1Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) Goto Death+2 Ice: DEMN Q 5 A_FreezeDeath @@ -249,11 +249,11 @@ ACTOR Demon2 : Demon1 8080 Stop XDeath: DEM2 H 6 - DEM2 I 0 A_SpawnItemEx("Demon2Chunk1", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 90) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk2", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk3", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk4", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) - DEM2 I 6 A_SpawnItemEx("Demon2Chunk5", 0,0,45, 1+(random[DemonChunks](0,255)*0.015625), 1+(random[DemonChunks](0,255)*0.015625), ChunkFlags, 270) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) + DEM2 I 6 A_SpawnItemEx("Demon2Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) Goto Death+2 } } From 3bbd255b73e06d01761bde480e14a0014744b86e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 02:04:53 +0000 Subject: [PATCH 292/387] - Fixed: A_MinotaurChase should switch to the Idle state, not the Spawn state. SVN r4227 (trunk) --- src/g_raven/a_minotaur.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index ff39bf67c..0f9d9cd55 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -558,7 +558,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) if (!self1->target || (self1->target->health <= 0) || !(self1->target->flags&MF_SHOOTABLE)) { // look for a new target - self1->SetState (self1->FindState ("Spawn")); + self1->SetIdle(); return; } From b845fdb5d5052e9e52eb2e799dc781ac888338db Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 02:31:34 +0000 Subject: [PATCH 293/387] - Fixed: There's more than one place where the CROUCHABLEMORPH flag needs to be checked. SVN r4228 (trunk) --- src/d_player.h | 5 +++++ src/p_user.cpp | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 96fb1399f..3467328f4 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -426,6 +426,11 @@ public: crouching = 0; crouchviewdelta = 0; } + + bool CanCrouch() const + { + return morphTics == 0 || mo->PlayerFlags & PPF_CROUCHABLEMORPH; + } int GetSpawnClass(); }; diff --git a/src/p_user.cpp b/src/p_user.cpp index 42031d296..0816d753b 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -539,7 +539,7 @@ void APlayerPawn::BeginPlay () void APlayerPawn::Tick() { - if (player != NULL && player->mo == this && player->morphTics == 0 && player->playerstate != PST_DEAD) + if (player != NULL && player->mo == this && player->CanCrouch() && player->playerstate != PST_DEAD) { height = FixedMul(GetDefault()->height, player->crouchfactor); } @@ -1788,7 +1788,7 @@ void P_MovePlayer (player_t *player) sm = FixedMul (sm, player->mo->Speed); // When crouching, speed and bobbing have to be reduced - if (player->morphTics == 0 && player->crouchfactor != FRACUNIT) + if (player->CanCrouch() && player->crouchfactor != FRACUNIT) { fm = FixedMul(fm, player->crouchfactor); sm = FixedMul(sm, player->crouchfactor); @@ -2204,8 +2204,7 @@ void P_PlayerThink (player_t *player) { player->cmd.ucmd.buttons &= ~BT_CROUCH; } - if ((player->morphTics == 0 || player->mo->PlayerFlags & PPF_CROUCHABLEMORPH) - && player->health > 0 && level.IsCrouchingAllowed()) + if (player->CanCrouch() && player->health > 0 && level.IsCrouchingAllowed()) { if (!totallyfrozen) { From 2dfb1dd92f648c302fd8d1f290d72fc7ecf1bd48 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 03:31:13 +0000 Subject: [PATCH 294/387] - Added an alternate 2D sprite sorting comparison function which seems to work better with large voxels than the standard 1D sprite sort. SVN r4229 (trunk) --- src/r_things.cpp | 18 +++++++++++++++++- src/r_things.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 276cbd8b7..9bdba99f9 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -139,6 +139,7 @@ vissprite_t **firstvissprite; vissprite_t **vissprite_p; vissprite_t **lastvissprite; int newvissprite; +bool DrewAVoxel; static vissprite_t **spritesorter; static int spritesortersize = 0; @@ -186,6 +187,7 @@ void R_DeinitSprites() void R_ClearSprites (void) { vissprite_p = firstvissprite; + DrewAVoxel = false; } @@ -782,6 +784,8 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->gz = fz; vis->gzb = gzb; // [RH] use gzb, not thing->z vis->gzt = gzt; // killough 3/27/98 + vis->deltax = fx - viewx; + vis->deltay = fy - viewy; vis->renderflags = thing->renderflags; if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D vis->Style.RenderStyle = thing->RenderStyle; @@ -798,6 +802,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor { vis->voxel = voxel->Voxel; vis->bIsVoxel = true; + DrewAVoxel = true; } else { @@ -1330,11 +1335,22 @@ void R_DrawRemainingPlayerSprites() // gain compared to the old function. // // Sort vissprites by depth, far to near + +// This is the standard version, which does a simple test based on depth. static bool sv_compare(vissprite_t *a, vissprite_t *b) { return a->idepth > b->idepth; } +// This is an alternate version, for when one or more voxel is in view. +// It does a 2D distance test based on whichever one is furthest from +// the viewpoint. +static bool sv_compare2d(vissprite_t *a, vissprite_t *b) +{ + return TVector2(a->deltax, a->deltay).LengthSquared() < + TVector2(b->deltax, b->deltay).LengthSquared(); +} + #if 0 static drawseg_t **drawsegsorter; static int drawsegsortersize = 0; @@ -1965,7 +1981,7 @@ void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes void R_DrawMasked (void) { - R_SortVisSprites (sv_compare, firstvissprite - vissprites); + R_SortVisSprites (DrewAVoxel ? sv_compare2d : sv_compare, firstvissprite - vissprites); if (height_top == NULL) { // kg3D - no visible 3D floors, normal rendering diff --git a/src/r_things.h b/src/r_things.h index 14ed8afc9..2219eee20 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -38,6 +38,7 @@ struct vissprite_t fixed_t xscale, yscale; fixed_t depth; fixed_t idepth; // 1/z + fixed_t deltax, deltay; DWORD FillColor; fixed_t floorclip; union From d2ef6d81da1194dd13e72f2df5b0dd0e1fe495a3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 03:45:19 +0000 Subject: [PATCH 295/387] - P_RailAttack() now checks the puff's MF3_FOILINVUL flag. SVN r4230 (trunk) --- src/p_map.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 803276d10..657b90d83 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3886,6 +3886,7 @@ struct RailData { TArray RailHits; bool StopAtOne; + bool StopAtInvul; }; static ETraceStatus ProcessRailHit (FTraceResults &res, void *userdata) @@ -3897,7 +3898,7 @@ static ETraceStatus ProcessRailHit (FTraceResults &res, void *userdata) } // Invulnerable things completely block the shot - if (res.Actor->flags2 & MF2_INVULNERABLE) + if (data->StopAtInvul && res.Actor->flags2 & MF2_INVULNERABLE) { return TRACE_Stop; } @@ -3964,10 +3965,11 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, int flags; - AActor *puffDefaults = puffclass == NULL ? NULL : GetDefaultByType (puffclass->GetReplacement()); + assert(puffclass != NULL); // Because we set it to a default above + AActor *puffDefaults = GetDefaultByType (puffclass->GetReplacement()); - if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) flags = 0; - else flags = TRACE_PCross|TRACE_Impact; + flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross|TRACE_Impact; + rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; Trace (x1, y1, shootz, source->Sector, vx, vy, vz, distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, From 4bc60ec900454d9af511d975033034f1acf8c70f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 28 Apr 2013 03:55:31 +0000 Subject: [PATCH 296/387] - Added Blzut3's noextratic fix. SVN r4231 (trunk) --- src/p_mobj.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9895d7a56..9b697863d 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3498,22 +3498,29 @@ void AActor::Tick () // cycle through states, calling action functions at transitions if (tics != -1) { - tics--; - // you can cycle through multiple states in a tic - // [RH] Use <= 0 instead of == 0 so that spawnstates - // of 0 tics work as expected. - if (tics <= 0) + // [BL] If we reach here with a 0 duration state, we + // have created an extra tic, so account for it. + int newtics; + do { - assert (state != NULL); - if (state == NULL) + newtics = --tics; + + // [RH] Use tics <= 0 instead of == 0 so that spawnstates + // of 0 tics work as expected. + if (tics <= 0) { - Destroy(); - return; + assert (state != NULL); + if (state == NULL) + { + Destroy(); + return; + } + if (!SetState (state->GetNextState())) + return; // freed itself } - if (!SetState (state->GetNextState())) - return; // freed itself } + while (newtics < 0); } else { From 81487f4a691c1e3a99ca6cb4de2720f51ebff936 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 28 Apr 2013 18:00:41 +0000 Subject: [PATCH 297/387] - Fixed: noextratic fix skipped over infinite duration states. SVN r4232 (trunk) --- src/p_mobj.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9b697863d..be73f0951 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3504,7 +3504,7 @@ void AActor::Tick () int newtics; do { - newtics = --tics; + newtics = tics--; // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. @@ -3520,7 +3520,7 @@ void AActor::Tick () return; // freed itself } } - while (newtics < 0); + while (newtics == 0); } else { From 90b4480bcd6a6a15dba047f51b2e8afd90d8b51b Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 28 Apr 2013 18:55:55 +0000 Subject: [PATCH 298/387] - Try that last fix again. This time check to see if we enter an infinite duration state and break out of the loop. SVN r4233 (trunk) --- src/p_mobj.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index be73f0951..70b1a7d13 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3504,7 +3504,7 @@ void AActor::Tick () int newtics; do { - newtics = tics--; + newtics = --tics; // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. @@ -3520,7 +3520,7 @@ void AActor::Tick () return; // freed itself } } - while (newtics == 0); + while (newtics < 0 && tics != -1); } else { From 10934f4d705b97cf90c1c7ad87fb1e790e28226e Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 29 Apr 2013 21:12:57 +0000 Subject: [PATCH 299/387] - Lets try fixing the extra tic issue by evaluating the zero delay states at PostBeginPlay. This requires delaying the state cycling until the next tick. SVN r4234 (trunk) --- src/p_mobj.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 70b1a7d13..4a00a40b6 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3498,29 +3498,21 @@ void AActor::Tick () // cycle through states, calling action functions at transitions if (tics != -1) { - // you can cycle through multiple states in a tic - // [BL] If we reach here with a 0 duration state, we - // have created an extra tic, so account for it. - int newtics; - do + // [RH] Use tics <= 0 instead of == 0 so that spawnstates + // of 0 tics work as expected. + if (tics <= 0) { - newtics = --tics; - - // [RH] Use tics <= 0 instead of == 0 so that spawnstates - // of 0 tics work as expected. - if (tics <= 0) + assert (state != NULL); + if (state == NULL) { - assert (state != NULL); - if (state == NULL) - { - Destroy(); - return; - } - if (!SetState (state->GetNextState())) - return; // freed itself + Destroy(); + return; } + if (!SetState (state->GetNextState())) + return; // freed itself } - while (newtics < 0 && tics != -1); + + tics--; } else { @@ -3991,6 +3983,13 @@ void AActor::PostBeginPlay () Renderer->StateChanged(this); } PrevAngle = angle; + + // [BL] Run zero-delay spawn states now so that we don't create a tic later + if(tics == 0 && state) + { + if (!SetState (state->GetNextState())) + return; // freed itself + } } void AActor::MarkPrecacheSounds() const From e92560b4da5d2fb65d6607b065855c3076ec8fc6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 02:41:59 +0000 Subject: [PATCH 300/387] - Be consistent with whitespace tabs. SVN r4235 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 96 +++++++++++++++---------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e1c7e367c..a75012f61 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3741,10 +3741,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) { - if (self->master != NULL) - { - P_RemoveThing(self->master); - } + if (self->master != NULL) + { + P_RemoveThing(self->master); + } } //=========================================================================== @@ -3754,18 +3754,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { - TThinkerIterator it; - AActor * mo; - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(removeall,0); + TThinkerIterator it; + AActor * mo; + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(removeall,0); - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) ) - { - P_RemoveThing(mo); - } - } + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) ) + { + P_RemoveThing(mo); + } + } } //=========================================================================== @@ -3775,18 +3775,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) //=========================================================================== DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { - TThinkerIterator it; - AActor * mo; - ACTION_PARAM_START(1); - ACTION_PARAM_BOOL(removeall,0); + TThinkerIterator it; + AActor * mo; + ACTION_PARAM_START(1); + ACTION_PARAM_BOOL(removeall,0); - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) ) - { - P_RemoveThing(mo); - } - } + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) ) + { + P_RemoveThing(mo); + } + } } //=========================================================================== @@ -3796,10 +3796,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { - if (self->master != NULL) - { - P_Thing_Raise(self->master); - } + if (self->master != NULL) + { + P_Thing_Raise(self->master); + } } //=========================================================================== @@ -3809,16 +3809,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { - TThinkerIterator it; - AActor * mo; + TThinkerIterator it; + AActor * mo; - while ((mo = it.Next())) - { - if ( mo->master == self ) - { - P_Thing_Raise(mo); - } - } + while ((mo = it.Next())) + { + if ( mo->master == self ) + { + P_Thing_Raise(mo); + } + } } //=========================================================================== @@ -3828,16 +3828,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { - TThinkerIterator it; - AActor * mo; + TThinkerIterator it; + AActor * mo; - while ( (mo = it.Next()) ) - { - if ( ( mo->master == self->master ) && ( mo != self ) ) - { - P_Thing_Raise(mo); - } - } + while ( (mo = it.Next()) ) + { + if ( ( mo->master == self->master ) && ( mo != self ) ) + { + P_Thing_Raise(mo); + } + } } //=========================================================================== From f7aa019f85ae2d0f36b491fb4e1a51fee645c6a6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 02:45:15 +0000 Subject: [PATCH 301/387] - Stylistic changes. SVN r4236 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index a75012f61..d84e647e1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3755,13 +3755,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { TThinkerIterator it; - AActor * mo; + AActor *mo; ACTION_PARAM_START(1); ACTION_PARAM_BOOL(removeall,0); - while ( (mo = it.Next()) ) + while ((mo = it.Next()) != NULL) { - if ( ( mo->master == self ) && ( ( mo->health <= 0 ) || removeall) ) + if (mo->master == self && (mo->health <= 0 || removeall)) { P_RemoveThing(mo); } @@ -3776,13 +3776,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { TThinkerIterator it; - AActor * mo; + AActor *mo; ACTION_PARAM_START(1); ACTION_PARAM_BOOL(removeall,0); - while ( (mo = it.Next()) ) + while ((mo = it.Next()) != NULL) { - if ( ( mo->master == self->master ) && ( mo != self ) && ( ( mo->health <= 0 ) || removeall) ) + if (mo->master == self->master && mo != self && (mo->health <= 0 || removeall)) { P_RemoveThing(mo); } @@ -3810,11 +3810,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { TThinkerIterator it; - AActor * mo; + AActor *mo; - while ((mo = it.Next())) + while ((mo = it.Next()) != NULL) { - if ( mo->master == self ) + if (mo->master == self) { P_Thing_Raise(mo); } @@ -3829,11 +3829,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { TThinkerIterator it; - AActor * mo; + AActor *mo; - while ( (mo = it.Next()) ) + while ((mo = it.Next()) != NULL) { - if ( ( mo->master == self->master ) && ( mo != self ) ) + if (mo->master == self->master && mo != self) { P_Thing_Raise(mo); } From 5dc034c2eda752f0735f084b91b92b41870cb6f2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 02:46:47 +0000 Subject: [PATCH 302/387] - Fixed: A_RemoveSiblings and A_KillSiblings did not check that the caller had a master to deduce siblings from. SVN r4237 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d84e647e1..f17030162 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3780,11 +3780,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) ACTION_PARAM_START(1); ACTION_PARAM_BOOL(removeall,0); - while ((mo = it.Next()) != NULL) + if (self->master != NULL) { - if (mo->master == self->master && mo != self && (mo->health <= 0 || removeall)) + while ((mo = it.Next()) != NULL) { - P_RemoveThing(mo); + if (mo->master == self->master && mo != self && (mo->health <= 0 || removeall)) + { + P_RemoveThing(mo); + } } } } @@ -3831,11 +3834,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) TThinkerIterator it; AActor *mo; - while ((mo = it.Next()) != NULL) + if (self->master != NULL) { - if (mo->master == self->master && mo != self) + while ((mo = it.Next()) != NULL) { - P_Thing_Raise(mo); + if (mo->master == self->master && mo != self) + { + P_Thing_Raise(mo); + } } } } From ecdde24bda45b3f4243224c5c7cd47eec64ead7f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 03:07:39 +0000 Subject: [PATCH 303/387] - Fixed: WeaponGiver did not give half ammo when dropped. SVN r4238 (trunk) --- src/g_shared/a_weapons.cpp | 35 +++++++++++++++++++++++++++++++++-- src/p_enemy.cpp | 4 ++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 24d6a545d..23cc08e82 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -730,10 +730,41 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) master = weap = static_cast(Spawn(di->Name, 0, 0, 0, NO_REPLACE)); if (weap != NULL) { + fixed_t dropammofactor; weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. weap->flags = (weap->flags & ~MF_DROPPED) | (this->flags & MF_DROPPED); - if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1; - if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; + + // If we're not overriding the ammo given amounts, then apply dropped + // item modifications if needed. + if (weap->flags & MF_DROPPED) + { + dropammofactor = G_SkillProperty(SKILLP_DropAmmoFactor); + if (dropammofactor < 0) + { + dropammofactor = FRACUNIT/2; + } + } + else + { + dropammofactor = FRACUNIT; + } + + if (AmmoGive1 < 0) + { + weap->AmmoGive1 = FixedMul(weap->AmmoGive1, dropammofactor); + } + else + { + weap->AmmoGive1 = AmmoGive1; + } + if (AmmoGive2 < 0) + { + weap->AmmoGive2 = FixedMul(weap->AmmoGive2, dropammofactor); + } + else + { + weap->AmmoGive2 = AmmoGive2; + } weap->BecomeItem(); } else return false; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index dc96eb8ac..75453386e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3023,14 +3023,14 @@ void ModifyDropAmount(AInventory *inv, int dropamount) { // Half ammo when dropped by bad guys. inv->Amount = inv->GetClass()->Meta.GetMetaInt (AIMETA_DropAmount, MAX(1, FixedMul(inv->Amount, dropammofactor))); - inv->ItemFlags|=flagmask; + inv->ItemFlags |= flagmask; } else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) { // The same goes for ammo from a weapon. static_cast(inv)->AmmoGive1 = FixedMul(static_cast(inv)->AmmoGive1, dropammofactor); static_cast(inv)->AmmoGive2 = FixedMul(static_cast(inv)->AmmoGive2, dropammofactor); - inv->ItemFlags|=flagmask; + inv->ItemFlags |= flagmask; } else if (inv->IsKindOf (RUNTIME_CLASS(ADehackedPickup))) { From cc5110575fe706f540785d90b6a4d992c364f306 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 03:14:49 +0000 Subject: [PATCH 304/387] - Fixed: The constructor for single-lump fonts did not initialize the Cursor field. SVN r4239 (trunk) --- src/v_font.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v_font.cpp b/src/v_font.cpp index 6bb130716..eb714fb93 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -908,6 +908,7 @@ FFont::FFont (int lump) Chars = NULL; PatchRemap = NULL; Name = NULL; + Cursor = '_'; } //========================================================================== From 0e19a0e330a6ad5bcd34ec95a020b39b1107d4d5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 04:20:09 +0000 Subject: [PATCH 305/387] - Added a NODELAY state flag. This is only valid for a state immediately following a Spawn label. When set, the actor will run this state during its first tick. This means Spawn states may now run an action function if you set this flag. Note that this action function is executed during the actor's first tick, which is not the same as when it is spawned. SVN r4240 (trunk) --- src/dthinker.cpp | 5 +++-- src/info.h | 5 +++++ src/p_mobj.cpp | 26 ++++++++++++++---------- src/p_states.cpp | 34 +++++++++++++++++++++++++------- src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_states.cpp | 15 ++++++++++++-- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 85c5fb4bc..15206dabd 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -448,7 +448,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) NextToThink = node->NextThinker; if (node->ObjectFlags & OF_JustSpawned) { - node->ObjectFlags &= ~OF_JustSpawned; + // Leave OF_JustSpawn set until after Tick() so the ticker can check it. if (dest != NULL) { // Move thinker from this list to the destination list node->Remove(); @@ -463,7 +463,8 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction - node->Tick (); + node->Tick(); + node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } node = NextToThink; diff --git a/src/info.h b/src/info.h index 87e623814..24bbb5fea 100644 --- a/src/info.h +++ b/src/info.h @@ -75,6 +75,7 @@ struct FState BYTE Fullbright:1; // State is fullbright BYTE SameFrame:1; // Ignore Frame (except when spawning actor) BYTE Fast:1; + BYTE NoDelay:1; // Spawn states executes its action normally int ParameterIndex; inline int GetFrame() const @@ -109,6 +110,10 @@ struct FState { return NextState; } + inline bool GetNoDelay() const + { + return NoDelay; + } inline void SetFrame(BYTE frame) { Frame = frame - 'A'; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4a00a40b6..3d8424adc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3496,22 +3496,35 @@ void AActor::Tick () } // cycle through states, calling action functions at transitions + assert (state != NULL); + if (ObjectFlags & OF_JustSpawned && state->GetNoDelay()) + { + // For immediately spawned objects with the NoDelay flag set for their + // Spawn state, explicitly set the current state so that it calls its + // action and chains 0-tic states. + int starttics = tics; + SetState(state); + // If the initial state had a duration of 0 tics, let the next state run + // normally. Otherwise, increment tics by 1 so that we don't double up ticks. + if (starttics > 0 && tics >= 0) + { + tics++; + } + } if (tics != -1) { // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. if (tics <= 0) { - assert (state != NULL); if (state == NULL) { Destroy(); return; } - if (!SetState (state->GetNextState())) + if (!SetState(state->GetNextState())) return; // freed itself } - tics--; } else @@ -3983,13 +3996,6 @@ void AActor::PostBeginPlay () Renderer->StateChanged(this); } PrevAngle = angle; - - // [BL] Run zero-delay spawn states now so that we don't create a tic later - if(tics == 0 && state) - { - if (!SetState (state->GetNextState())) - return; // freed itself - } } void AActor::MarkPrecacheSounds() const diff --git a/src/p_states.cpp b/src/p_states.cpp index aeff2f5b6..cfe455716 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -334,8 +334,8 @@ FStateDefine *FStateDefinitions::FindStateLabelInList(TArray & lis if (create) { FStateDefine def; - def.Label=name; - def.State=NULL; + def.Label = name; + def.State = NULL; def.DefineFlags = SDF_NEXT; return &list[list.Push(def)]; } @@ -351,12 +351,11 @@ FStateDefine *FStateDefinitions::FindStateLabelInList(TArray & lis FStateDefine * FStateDefinitions::FindStateAddress(const char *name) { - FStateDefine * statedef=NULL; - + FStateDefine *statedef = NULL; TArray &namelist = MakeStateNameList(name); + TArray *statelist = &StateLabels; - TArray * statelist = &StateLabels; - for(unsigned i=0;iChildren; @@ -379,7 +378,7 @@ void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYT //========================================================================== // -// Adds a new state to the curremt list +// Adds a new state to the current list // //========================================================================== @@ -393,6 +392,24 @@ void FStateDefinitions::AddStateLabel (const char *statename) lastlabel = index; } +//========================================================================== +// +// Returns the index a state label points to. May only be called before +// installing states. +// +//========================================================================== + +int FStateDefinitions::GetStateLabelIndex (FName statename) +{ + FStateDefine *std = FindStateLabelInList(StateLabels, statename, false); + if (std == NULL) + { + return -1; + } + assert((size_t)std->State <= StateArray.Size() + 1); + return (int)((ptrdiff_t)std->State - 1); +} + //========================================================================== // // Finds the state associated with the given name @@ -863,6 +880,9 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars) state->Frame = frame; state->SameFrame = noframe; StateArray.Push(*state); + + // NODELAY flag is not carried past the first state + state->NoDelay = false; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index d1519a260..e39d12ab0 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -91,6 +91,7 @@ public: void SetStateLabel (const char * statename, FState * state, BYTE defflags = SDF_STATE); void AddStateLabel (const char * statename); + int GetStateLabelIndex (FName statename); void InstallStates(FActorInfo *info, AActor *defaults); int FinishStates (FActorInfo *actor, AActor *defaults); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 5c2d81602..1d643e33c 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -275,6 +275,18 @@ do_stop: state.Fast = true; continue; } + if (sc.Compare("NODELAY")) + { + if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) + { + state.NoDelay = true; + } + else + { + sc.ScriptMessage("NODELAY may only be used immediately after Spawn:"); + } + continue; + } if (sc.Compare("OFFSET")) { // specify a weapon offset @@ -338,8 +350,7 @@ do_stop: int paramindex = PrepareStateParameters(&state, numparams, bag.Info->Class); int paramstart = paramindex; bool varargs = params[numparams - 1] == '+'; - int varargcount=0; - + int varargcount = 0; if (varargs) { From e9cd2777f32d4329329cc3e8fed536f5b4df073a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 30 Apr 2013 04:49:24 +0000 Subject: [PATCH 306/387] - Fixed: r4226 had bad copy-paste angles for Demon2's XDeath. SVN r4241 (trunk) --- wadsrc/static/actors/hexen/demons.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wadsrc/static/actors/hexen/demons.txt b/wadsrc/static/actors/hexen/demons.txt index 80926d7ad..1ecb2222c 100644 --- a/wadsrc/static/actors/hexen/demons.txt +++ b/wadsrc/static/actors/hexen/demons.txt @@ -250,10 +250,10 @@ ACTOR Demon2 : Demon1 8080 XDeath: DEM2 H 6 DEM2 I 0 A_SpawnItemEx("Demon2Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) - DEM2 I 6 A_SpawnItemEx("Demon2Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 90, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEM2 I 0 A_SpawnItemEx("Demon2Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) + DEM2 I 6 A_SpawnItemEx("Demon2Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) Goto Death+2 } } From bed47c6eff1d11b0f9425acca9867f7b0e4a3253 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 30 Apr 2013 06:48:53 +0000 Subject: [PATCH 307/387] - A_KIllSiblings and A_DamageSiblings didn't check for a valid master. SVN r4242 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f17030162..304d57c07 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2608,11 +2608,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) TThinkerIterator it; AActor *mo; - while ( (mo = it.Next()) ) + if (self->master != NULL) { - if (mo->master == self->master && mo != self) + while ( (mo = it.Next()) ) { - P_DamageMobj(mo, self, self, mo->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR); + if (mo->master == self->master && mo != self) + { + P_DamageMobj(mo, self, self, mo->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR); + } } } } @@ -3501,18 +3504,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) ACTION_PARAM_INT(amount, 0); ACTION_PARAM_NAME(DamageType, 1); - while ( (mo = it.Next()) ) + if (self->master != NULL) { - if (mo->master == self->master && mo != self) + while ( (mo = it.Next()) ) { - if (amount > 0) + if (mo->master == self->master && mo != self) { - P_DamageMobj(mo, self, self, amount, DamageType, DMG_NO_ARMOR); - } - else if (amount < 0) - { - amount = -amount; - P_GiveBody(mo, amount); + if (amount > 0) + { + P_DamageMobj(mo, self, self, amount, DamageType, DMG_NO_ARMOR); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(mo, amount); + } } } } From cadc16293e2e9e0952052f0978c04351fd1e732b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 May 2013 02:21:43 +0000 Subject: [PATCH 308/387] - Fixed: r4234 moved tic decrementing to the wrong spot. SVN r4243 (trunk) --- src/p_mobj.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3d8424adc..6ba3c5579 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3495,8 +3495,12 @@ void AActor::Tick () } } - // cycle through states, calling action functions at transitions assert (state != NULL); + if (state == NULL) + { + Destroy(); + return; + } if (ObjectFlags & OF_JustSpawned && state->GetNoDelay()) { // For immediately spawned objects with the NoDelay flag set for their @@ -3511,21 +3515,16 @@ void AActor::Tick () tics++; } } + // cycle through states, calling action functions at transitions if (tics != -1) { // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. - if (tics <= 0) + if (--tics <= 0) { - if (state == NULL) - { - Destroy(); - return; - } if (!SetState(state->GetNextState())) return; // freed itself } - tics--; } else { From 6d6fcbe246e0dae263b8cd35743c3fc429ae2d0d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 May 2013 02:27:07 +0000 Subject: [PATCH 309/387] - For the sake of better testing, use 2D sprite sorting unconditionally and not just when a voxel is in view. Hopefully I'm just being paranoid, but I don't trust it to go well with clipping sprites to walls. SVN r4244 (trunk) --- src/r_things.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/r_things.cpp b/src/r_things.cpp index 9bdba99f9..38c4f1fc1 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1981,6 +1981,7 @@ void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes void R_DrawMasked (void) { + DrewAVoxel = true; // TESTME R_SortVisSprites (DrewAVoxel ? sv_compare2d : sv_compare, firstvissprite - vissprites); if (height_top == NULL) From 163d8ba3e60d245d25d067d710152bb13b5ca5c6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 2 May 2013 00:07:56 +0000 Subject: [PATCH 310/387] - Fixed crash when an actor's spawn state ends by destroying the actor and the first state has NoDelay set and it only consists of 0-tic states. SVN r4245 (trunk) --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6ba3c5579..2c7092da9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3507,7 +3507,8 @@ void AActor::Tick () // Spawn state, explicitly set the current state so that it calls its // action and chains 0-tic states. int starttics = tics; - SetState(state); + if (!SetState(state)) + return; // freed itself // If the initial state had a duration of 0 tics, let the next state run // normally. Otherwise, increment tics by 1 so that we don't double up ticks. if (starttics > 0 && tics >= 0) From d86b16d5407343db2f07b7522b2853cb164c6be5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 2 May 2013 00:24:53 +0000 Subject: [PATCH 311/387] - Added a DropAmmoFactor field to WeaponGiver so that ModifyDropAmount() can record the drop amount modifier into it without fiddling with the actual AmmoGiveX fields. SVN r4246 (trunk) --- src/g_shared/a_pickups.h | 12 ++++++++- src/g_shared/a_weapons.cpp | 52 ++++++++++++-------------------------- src/p_enemy.cpp | 5 ++++ 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 4be7100a8..6c68990d1 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -359,7 +359,17 @@ enum WIF_BOT_BFG = 1<<28, // this is a BFG }; -#define S_LIGHTDONE 0 +class AWeaponGiver : public AWeapon +{ + DECLARE_CLASS(AWeaponGiver, AWeapon) + +public: + bool TryPickup(AActor *&toucher); + void Serialize(FArchive &arc); + + fixed_t DropAmmoFactor; +}; + // Health is some item that gives the player health when picked up. class AHealth : public AInventory diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 23cc08e82..b6c4e1116 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -705,16 +705,17 @@ FState *AWeapon::GetZoomState () /* Weapon giver ***********************************************************/ -class AWeaponGiver : public AWeapon -{ - DECLARE_CLASS(AWeaponGiver, AWeapon) - -public: - bool TryPickup(AActor *&toucher); -}; - IMPLEMENT_CLASS(AWeaponGiver) +void AWeaponGiver::Serialize(FArchive &arc) +{ + Super::Serialize(arc); + if (SaveVersion >= 4246) + { + arc << DropAmmoFactor; + } +} + bool AWeaponGiver::TryPickup(AActor *&toucher) { FDropItem *di = GetDropItems(); @@ -734,36 +735,15 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. weap->flags = (weap->flags & ~MF_DROPPED) | (this->flags & MF_DROPPED); - // If we're not overriding the ammo given amounts, then apply dropped - // item modifications if needed. - if (weap->flags & MF_DROPPED) - { - dropammofactor = G_SkillProperty(SKILLP_DropAmmoFactor); - if (dropammofactor < 0) - { - dropammofactor = FRACUNIT/2; - } - } - else - { - dropammofactor = FRACUNIT; - } + // If our ammo gives are non-negative, transfer them to the real weapon. + if (AmmoGive1 >= 0) weap->AmmoGive1 = AmmoGive1; + if (AmmoGive2 >= 0) weap->AmmoGive2 = AmmoGive2; - if (AmmoGive1 < 0) + // If DropAmmoFactor is non-negative, modify the given ammo amounts. + if (DropAmmoFactor > 0) { - weap->AmmoGive1 = FixedMul(weap->AmmoGive1, dropammofactor); - } - else - { - weap->AmmoGive1 = AmmoGive1; - } - if (AmmoGive2 < 0) - { - weap->AmmoGive2 = FixedMul(weap->AmmoGive2, dropammofactor); - } - else - { - weap->AmmoGive2 = AmmoGive2; + weap->AmmoGive1 = FixedMul(weap->AmmoGive1, DropAmmoFactor); + weap->AmmoGive2 = FixedMul(weap->AmmoGive2, DropAmmoFactor); } weap->BecomeItem(); } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 75453386e..70b80e7fb 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3025,6 +3025,11 @@ void ModifyDropAmount(AInventory *inv, int dropamount) inv->Amount = inv->GetClass()->Meta.GetMetaInt (AIMETA_DropAmount, MAX(1, FixedMul(inv->Amount, dropammofactor))); inv->ItemFlags |= flagmask; } + else if (inv->IsKindOf (RUNTIME_CLASS(AWeaponGiver))) + { + static_cast(inv)->DropAmmoFactor = dropammofactor; + inv->ItemFlags |= flagmask; + } else if (inv->IsKindOf (RUNTIME_CLASS(AWeapon))) { // The same goes for ammo from a weapon. From 63704a8b69c861ffdad4f4f61177a2a75c3344fb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 May 2013 19:08:17 +0000 Subject: [PATCH 312/387] - Fixed: r4225 accidentally removed the sky texture check for markceiling disabling. SVN r4247 (trunk) --- src/r_segs.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 9d9f197db..d050d8c3b 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2250,11 +2250,14 @@ void R_NewWall (bool needlights) if (planeside <= 0) // above view plane markfloor = false; - planeside = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz); - if (frontsector->ceilingplane.c > 0) // 3D floors have the ceiling backwards - planeside = -planeside; - if (planeside <= 0) // below view plane - markceiling = false; + if (frontsector->GetTexture(sector_t::ceiling) != skyflatnum) + { + planeside = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz); + if (frontsector->ceilingplane.c > 0) // 3D floors have the ceiling backwards + planeside = -planeside; + if (planeside <= 0) // below view plane + markceiling = false; + } } FTexture *midtex = TexMan(sidedef->GetTexture(side_t::mid), true); From a5b5172449045c71d6fc2431a9016d21095ff9dc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 May 2013 19:24:24 +0000 Subject: [PATCH 313/387] - Remove now-unused dropammofactor variable from AWeaponGiver::TryPickup(). SVN r4248 (trunk) --- src/g_shared/a_weapons.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index b6c4e1116..8275523ed 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -731,7 +731,6 @@ bool AWeaponGiver::TryPickup(AActor *&toucher) master = weap = static_cast(Spawn(di->Name, 0, 0, 0, NO_REPLACE)); if (weap != NULL) { - fixed_t dropammofactor; weap->ItemFlags &= ~IF_ALWAYSPICKUP; // use the flag of this item only. weap->flags = (weap->flags & ~MF_DROPPED) | (this->flags & MF_DROPPED); From 8830d3a07a08a1efc14a7a975ef23b6c2c1e57a5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 May 2013 19:46:38 +0000 Subject: [PATCH 314/387] - Fixed: Ever since r1078, D'Sparil has been too quiet. SVN r4249 (trunk) --- wadsrc/static/actors/heretic/dsparil.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wadsrc/static/actors/heretic/dsparil.txt b/wadsrc/static/actors/heretic/dsparil.txt index 79d457ae7..6ecef5b5c 100644 --- a/wadsrc/static/actors/heretic/dsparil.txt +++ b/wadsrc/static/actors/heretic/dsparil.txt @@ -68,10 +68,10 @@ ACTOR Sorcerer1 7 SRCR F 7 A_Scream SRCR G 7 SRCR HIJK 6 - SRCR L 25 A_PlaySoundEx("dsparil/zap", "body") + SRCR L 25 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE) SRCR MN 5 SRCR O 4 - SRCR L 20 A_PlaySoundEx("dsparil/zap", "body") + SRCR L 20 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE) SRCR MN 5 SRCR O 4 SRCR L 12 @@ -152,9 +152,9 @@ ACTOR Sorcerer2 Loop Rise: SOR2 AB 4 - SOR2 C 4 A_PlaySoundEx("dsparil/rise", "Body") + SOR2 C 4 A_PlaySound("dsparil/rise", CHAN_BODY, 1, false, ATTN_NONE) SOR2 DEF 4 - SOR2 G 12 A_PlaySoundEx("dsparil/sight", "Body") + SOR2 G 12 A_PlaySound("dsparil/sight", CHAN_BODY, 1, false, ATTN_NONE) Goto See Pain: SOR2 Q 3 @@ -171,15 +171,15 @@ ACTOR Sorcerer2 Death: SDTH A 8 A_Sor2DthInit SDTH B 8 - SDTH C 8 A_PlaySoundEx("dsparil/scream", "Body") + SDTH C 8 A_PlaySound("dsparil/scream", CHAN_BODY, 1, false, ATTN_NONE) DeathLoop: SDTH DE 7 SDTH F 7 A_Sor2DthLoop - SDTH G 6 A_PlaySoundEx("dsparil/explode", "Body") + SDTH G 6 A_PlaySound("dsparil/explode", CHAN_BODY, 1, false, ATTN_NONE) SDTH H 6 SDTH I 18 SDTH J 6 A_NoBlocking - SDTH K 6 A_PlaySoundEx("dsparil/bones", "Body") + SDTH K 6 A_PlaySound("dsparil/bones", CHAN_BODY, 1, false, ATTN_NONE) SDTH LMN 6 SDTH O -1 A_BossDeath Stop From 40f7abb8e94baea77f7ede7f55b50051d0e0661d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 4 May 2013 22:52:37 +0000 Subject: [PATCH 315/387] - Added bounce states. Set the BOUNCE_UseBounceState flag to use them (+USEBOUNCESTATE via DECORATE). Then you can use: * Bounce * Bounce.Floor * Bounce.Ceiling * Bounce.Wall * Bounce.Actor * Bounce.Actor.Creature Partial matches work just like Pain states, so if an actor bounces off a floor and you don't have a Bounce.Floor state, but you do have a Bounce state, it will use the Bounce state. Conversely, if you only have a Bounce.Floor state but no Bounce state, then the actor will only enter the Bounce.Floor state when it bounces on a floor; bouncing off anything else will not cause it to change state. SVN r4250 (trunk) --- src/actor.h | 6 ++++++ src/namedef.h | 7 +++++++ src/p_map.cpp | 24 ++++++++++++++++++++++++ src/p_mobj.cpp | 16 ++++++++++++++++ src/thingdef/thingdef_data.cpp | 1 + 5 files changed, 54 insertions(+) diff --git a/src/actor.h b/src/actor.h index 4bd19f1aa..ab04b176d 100644 --- a/src/actor.h +++ b/src/actor.h @@ -414,6 +414,7 @@ enum EBounceFlags // for them that are not present in ZDoom, so it is necessary to identify it properly. BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors + BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, @@ -1006,6 +1007,11 @@ public: return GetClass()->ActorInfo->FindState(2, names, exact); } + FState *FindState(int numnames, FName *names, bool exact = false) const + { + return GetClass()->ActorInfo->FindState(numnames, names, exact); + } + bool HasSpecialDeathStates () const; }; diff --git a/src/namedef.h b/src/namedef.h index f3ac248bf..22b21c41c 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -181,6 +181,13 @@ xx(Idle) xx(GenericFreezeDeath) xx(GenericCrush) +// Bounce state names +xx(Bounce) +xx(Wall) +xx(Floor) +xx(Ceiling) +xx(Creature) + // Compatible death names for the decorate parser. xx(XDeath) xx(Burn) diff --git a/src/p_map.cpp b/src/p_map.cpp index 657b90d83..618aa81dc 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2869,6 +2869,14 @@ bool FSlide::BounceWall (AActor *mo) } mo->velx = FixedMul(movelen, finecosine[deltaangle]); mo->vely = FixedMul(movelen, finesine[deltaangle]); + if (mo->BounceFlags & BOUNCE_UseBounceState) + { + FState *bouncestate = mo->FindState(NAME_Bounce, NAME_Wall); + if (bouncestate != NULL) + { + mo->SetState(bouncestate); + } + } return true; } @@ -2906,6 +2914,22 @@ bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop) mo->velx = FixedMul (speed, finecosine[angle]); mo->vely = FixedMul (speed, finesine[angle]); mo->PlayBounceSound(true); + if (mo->BounceFlags & BOUNCE_UseBounceState) + { + FName names[] = { NAME_Bounce, NAME_Actor, NAME_Creature }; + FState *bouncestate; + int count = 2; + + if ((BlockingMobj->flags & MF_SHOOTABLE) && !(BlockingMobj->flags & MF_NOBLOOD)) + { + count = 3; + } + bouncestate = mo->FindState(count, names); + if (bouncestate != NULL) + { + mo->SetState(bouncestate); + } + } } else { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2c7092da9..ccc454035 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1383,6 +1383,22 @@ bool AActor::FloorBounceMissile (secplane_t &plane) } PlayBounceSound(true); + + // Set bounce state + if (BounceFlags & BOUNCE_UseBounceState) + { + FName names[2]; + FState *bouncestate; + + names[0] = NAME_Bounce; + names[1] = plane.c < 0 ? NAME_Ceiling : NAME_Floor; + bouncestate = FindState(2, names); + if (bouncestate != NULL) + { + SetState(bouncestate); + } + } + if (BounceFlags & BOUNCE_MBF) // Bring it to rest below a certain speed { if (abs(velz) < (fixed_t)(Mass * GetGravity() / 64)) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index c542c895d..301427ad4 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -255,6 +255,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG2(BOUNCE_ExplodeOnWater, EXPLODEONWATER, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags), + DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags), // Deprecated flags. Handling must be performed in HandleDeprecatedFlags DEFINE_DEPRECATED_FLAG(FIREDAMAGE), From 9072c25e65db296e9c427841bc60fb1ab8a720fe Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 5 May 2013 00:01:51 +0000 Subject: [PATCH 316/387] - Added a big-endian fix for actor flag fields that aren't four bytes wide. SVN r4251 (trunk) --- src/thingdef/thingdef.h | 5 +- src/thingdef/thingdef_codeptr.cpp | 17 +----- src/thingdef/thingdef_data.cpp | 8 +-- src/thingdef/thingdef_parse.cpp | 10 +-- src/thingdef/thingdef_properties.cpp | 91 +++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 32 deletions(-) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index e39d12ab0..08264e0a8 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -22,12 +22,15 @@ struct FFlagDef unsigned int flagbit; const char *name; int structoffset; + int fieldsize; }; FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); -bool CheckDeprecatedFlags(AActor *actor, FActorInfo *info, int index); +bool CheckDeprecatedFlags(const AActor *actor, FActorInfo *info, int index); const char *GetFlagName(unsigned int flagnum, int flagoffset); +void ModActorFlag(AActor *actor, FFlagDef *fd, bool set); +INTBOOL CheckActorFlag(const AActor *actor, FFlagDef *fd); #define FLAG_NAME(flagnum, flagvar) GetFlagName(flagnum, myoffsetof(AActor, flagvar)) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 304d57c07..7ed85a692 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3629,14 +3629,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR); if (linkchange) self->UnlinkFromWorld(); - if (expression) - { - *flagp |= fd->flagbit; - } - else - { - *flagp &= ~fd->flagbit; - } + ModActorFlag(self, fd, expression); if (linkchange) self->LinkToWorld(); } kill_after = self->CountsAsKill(); @@ -3721,13 +3714,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) if (fd != NULL) { - if (fd->structoffset == -1) - { - if (CheckDeprecatedFlags(owner, cls->ActorInfo, fd->flagbit)) { - ACTION_JUMP(jumpto); - } - } - else if ( fd->flagbit & *(DWORD*)(((char*)owner) + fd->structoffset)) + if (CheckActorFlag(owner, fd)) { ACTION_JUMP(jumpto); } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 301427ad4..3dbbacac0 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -55,10 +55,10 @@ static TArray variables; //========================================================================== // [RH] Keep GCC quiet by not using offsetof on Actor types. -#define DEFINE_FLAG(prefix, name, type, variable) { prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1 } -#define DEFINE_FLAG2(symbol, name, type, variable) { symbol, #name, (int)(size_t)&((type*)1)->variable - 1 } -#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1 } -#define DEFINE_DUMMY_FLAG(name) { DEPF_UNUSED, #name, -1 } +#define DEFINE_FLAG(prefix, name, type, variable) { prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable) } +#define DEFINE_FLAG2(symbol, name, type, variable) { symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable) } +#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0 } +#define DEFINE_DUMMY_FLAG(name) { DEPF_UNUSED, #name, -1, 0 } static FFlagDef ActorFlags[]= { diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 11c000102..c065dfbe0 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -441,15 +441,7 @@ void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char * } else { - DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset); - if (mod == '+') - { - *flagvar |= fd->flagbit; - } - else - { - *flagvar &= ~fd->flagbit; - } + ModActorFlag(defaults, fd, mod == '+'); } } else diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 482a841a2..e3461792b 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -95,6 +95,91 @@ static const PClass *FindClassTentative(const char *name, const char *ancestor) return cls; } +//========================================================================== +// +// Sets or clears a flag, taking field width into account. +// +//========================================================================== +void ModActorFlag(AActor *actor, FFlagDef *fd, bool set) +{ + // Little-Endian machines only need one case, because all field sizes + // start at the same address. (Unless the machine has unaligned access + // exceptions, in which case you'll need multiple cases for it too.) +#ifdef __BIG_ENDIAN__ + if (fd->fieldsize == 4) +#endif + { + DWORD *flagvar = (DWORD *)((char *)actor + fd->structoffset); + if (set) + { + *flagvar |= fd->flagbit; + } + else + { + *flagvar &= ~fd->flagbit; + } + } +#ifdef __BIG_ENDIAN__ + else if (fd->fieldsize == 2) + { + WORD *flagvar = (WORD *)((char *)actor + fd->structoffset); + if (set) + { + *flagvar |= fd->flagbit; + } + else + { + *flagvar &= ~fd->flagbit; + } + } + else + { + assert(fd->fieldsize == 1); + BYTE *flagvar = (BYTE *)((char *)actor + fd->structoffset); + if (set) + { + *flagvar |= fd->flagbit; + } + else + { + *flagvar &= ~fd->flagbit; + } + } +#endif +} + +//========================================================================== +// +// Returns whether an actor flag is true or not. +// +//========================================================================== + +INTBOOL CheckActorFlag(const AActor *owner, FFlagDef *fd) +{ + if (fd->structoffset == -1) + { + return CheckDeprecatedFlags(owner, owner->GetClass()->ActorInfo, fd->flagbit); + } + else +#ifdef __BIG_ENDIAN__ + if (fd->fieldsize == 4) +#endif + { + return fd->flagbit & *(DWORD *)(((char*)owner) + fd->structoffset); + } +#ifdef __BID_ENDIAN__ + else if (fd->fieldsize == 2) + { + return fd->flagbit & *(WORD *)(((char*)owner) + fd->structoffset); + } + else + { + assert(fd->fieldsize == 1); + return fd->flagbit & *(BYTE *)(((char*)owner) + fd->structoffset); + } +#endif +} + //=========================================================================== // // HandleDeprecatedFlags @@ -170,7 +255,7 @@ void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int ind // //=========================================================================== -bool CheckDeprecatedFlags(AActor *actor, FActorInfo *info, int index) +bool CheckDeprecatedFlags(const AActor *actor, FActorInfo *info, int index) { // A deprecated flag is false if // a) it hasn't been added here @@ -211,11 +296,11 @@ bool CheckDeprecatedFlags(AActor *actor, FActorInfo *info, int index) return (actor->BounceFlags & (BOUNCE_TypeMask|BOUNCE_UseSeeSound)) == BOUNCE_DoomCompat; case DEPF_PICKUPFLASH: - return static_cast(actor)->PickupFlash == PClass::FindClass("PickupFlash"); + return static_cast(actor)->PickupFlash == PClass::FindClass("PickupFlash"); // A pure name lookup may or may not be more efficient, but I know no static identifier for PickupFlash. case DEPF_INTERHUBSTRIP: - return !(static_cast(actor)->InterHubAmount); + return !(static_cast(actor)->InterHubAmount); } return false; // Any entirely unknown flag is not set From 404df07629e3ed2e2f57fc2c24858c66748d3375 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 7 May 2013 01:57:05 +0000 Subject: [PATCH 317/387] - Fixed: The Ironlich lost its Pain state when it was converted to DECORATE. SVN r4252 (trunk) --- wadsrc/static/actors/heretic/ironlich.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wadsrc/static/actors/heretic/ironlich.txt b/wadsrc/static/actors/heretic/ironlich.txt index 4b7e0ff17..21234cf52 100644 --- a/wadsrc/static/actors/heretic/ironlich.txt +++ b/wadsrc/static/actors/heretic/ironlich.txt @@ -40,6 +40,10 @@ ACTOR Ironlich 6 LICH A 5 A_FaceTarget LICH B 20 A_LichAttack Goto See + Pain: + LICH A 4 + LICH A 4 A_Pain + Goto See Death: LICH C 7 LICH D 7 A_Scream From 2668988870c922d5c0035c462dd673992211b33a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:27:03 +0000 Subject: [PATCH 318/387] - Switched to a genericly extensible representation for userinfo. - Fixed: The playerinfo CCMD did not range check the player number. SVN r4253 (trunk) --- src/b_bot.cpp | 5 +- src/b_game.cpp | 12 +- src/bbannouncer.cpp | 16 +- src/c_cvars.cpp | 23 + src/c_cvars.h | 5 + src/cmdlib.cpp | 3 +- src/cmdlib.h | 2 +- src/d_net.cpp | 28 +- src/d_netinfo.cpp | 700 ++++++++++++++++++----------- src/d_player.h | 129 ++++-- src/fragglescript/t_func.cpp | 2 +- src/g_game.cpp | 8 +- src/g_level.cpp | 7 +- src/g_shared/a_morph.cpp | 6 +- src/g_shared/a_weapons.cpp | 2 +- src/g_shared/sbar_mugshot.cpp | 2 +- src/g_shared/sbarinfo_commands.cpp | 6 +- src/g_shared/shared_sbar.cpp | 2 +- src/hu_scores.cpp | 24 +- src/i_net.cpp | 4 +- src/intermission/intermission.cpp | 2 +- src/m_cheat.cpp | 4 +- src/menu/playerdisplay.cpp | 6 +- src/menu/playermenu.cpp | 52 +-- src/namedef.h | 10 +- src/p_acs.cpp | 18 +- src/p_interaction.cpp | 22 +- src/p_map.cpp | 2 +- src/p_mobj.cpp | 22 +- src/p_saveg.cpp | 8 +- src/p_spec.cpp | 2 +- src/p_user.cpp | 24 +- src/r_data/r_translate.cpp | 2 +- src/s_advsound.cpp | 2 +- src/tarray.h | 31 ++ src/thingdef/thingdef_codeptr.cpp | 2 +- src/wi_stuff.cpp | 2 +- 37 files changed, 756 insertions(+), 441 deletions(-) diff --git a/src/b_bot.cpp b/src/b_bot.cpp index f5235e1cc..26c8f99bd 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -51,15 +51,16 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam) players[i].mo = NULL; } botinfo_t *bot = botinfo; - while (bot && stricmp (players[i].userinfo.netname, bot->name)) + while (bot && stricmp (players[i].userinfo.GetName(), bot->name)) bot = bot->next; if (bot) { bot->inuse = false; - bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_NONE; + bot->lastteam = keepTeam ? players[i].userinfo.GetTeam() : TEAM_NONE; } players[i].~player_t(); ::new(&players[i]) player_t; + players[i].userinfo.Reset(); playeringame[i] = false; } diff --git a/src/b_game.cpp b/src/b_game.cpp index e97253c53..a4c0a1842 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -140,7 +140,7 @@ void FCajunMaster::Main (int buf) //Check if player should go observer. Or un observe if (bot_observer && !observer && !netgame) { - Printf ("%s is now observer\n", players[consoleplayer].userinfo.netname); + Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName()); observer = true; players[consoleplayer].mo->UnlinkFromWorld (); players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY; @@ -149,7 +149,7 @@ void FCajunMaster::Main (int buf) } else if (!bot_observer && observer && !netgame) //Go back { - Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.netname); + Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName()); observer = false; players[consoleplayer].mo->UnlinkFromWorld (); players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY; @@ -218,7 +218,7 @@ void FCajunMaster::End () { if (deathmatch) { - getspawned.Push(players[i].userinfo.netname); + getspawned.Push(players[i].userinfo.GetName()); } CleanBotstuff (&players[i]); } @@ -353,7 +353,7 @@ void FCajunMaster::DoAddBot (int bnum, char *info) if (!deathmatch && playerstarts[bnum].type == 0) { Printf ("%s tried to join, but there was no player %d start\n", - players[bnum].userinfo.netname, bnum+1); + players[bnum].userinfo.GetName(), bnum+1); ClearPlayer (bnum, false); // Make the bot inactive again if (botnum > 0) { @@ -370,9 +370,9 @@ void FCajunMaster::DoAddBot (int bnum, char *info) botingame[bnum] = true; if (teamplay) - Printf ("%s joined the %s team\n", players[bnum].userinfo.netname,Teams[players[bnum].userinfo.team].GetName ()); + Printf ("%s joined the %s team\n", players[bnum].userinfo.GetName(), Teams[players[bnum].userinfo.GetTeam()].GetName()); else - Printf ("%s joined the game\n", players[bnum].userinfo.netname); + Printf ("%s joined the game\n", players[bnum].userinfo.GetName()); G_DoReborn (bnum, true); if (StatusBar != NULL) diff --git a/src/bbannouncer.cpp b/src/bbannouncer.cpp index b65671eaf..91583af8c 100644 --- a/src/bbannouncer.cpp +++ b/src/bbannouncer.cpp @@ -231,7 +231,7 @@ bool AnnounceKill (AActor *killer, AActor *killee) if (killer == NULL) { // The world killed the player - if (killee->player->userinfo.gender == GENDER_MALE) + if (killee->player->userinfo.GetGender() == GENDER_MALE) { // Only males have scrotums to separate choice = &WorldKillSounds[rannum % 3]; } @@ -244,11 +244,11 @@ bool AnnounceKill (AActor *killer, AActor *killee) else if (killer == killee) { // The player killed self choice = &SuicideSounds[rannum & 3]; - killerName = killer->player->userinfo.netname; + killerName = killer->player->userinfo.GetName(); } else { // Another player did the killing - if (killee->player->userinfo.gender == GENDER_MALE) + if (killee->player->userinfo.GetGender() == GENDER_MALE) { // Only males can be castrated choice = &KillSounds[rannum % countof(KillSounds)]; } @@ -256,7 +256,7 @@ bool AnnounceKill (AActor *killer, AActor *killee) { choice = &KillSounds[rannum % (countof(KillSounds) - 1)]; } - killerName = killer->player->userinfo.netname; + killerName = killer->player->userinfo.GetName(); // Blood only plays the announcement sound on the killer's // computer. I think it sounds neater to also hear it on @@ -269,8 +269,8 @@ bool AnnounceKill (AActor *killer, AActor *killee) { char assembled[1024]; - SexMessage (message, assembled, killee->player->userinfo.gender, - killee->player->userinfo.netname, killerName); + SexMessage (message, assembled, killee->player->userinfo.GetGender(), + killee->player->userinfo.GetName(), killerName); Printf (PRINT_MEDIUM, "%s\n", assembled); } if (playSound) @@ -301,8 +301,8 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee) { char assembled[1024]; - SexMessage (message, assembled, killee->player->userinfo.gender, - killee->player->userinfo.netname, killer->player->userinfo.netname); + SexMessage (message, assembled, killee->player->userinfo.GetGender(), + killee->player->userinfo.GetName(), killer->player->userinfo.GetName()); Printf (PRINT_MEDIUM, "%s\n", assembled); } if (killee->CheckLocalView (consoleplayer) || diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index b07baa6da..ba41f8259 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1477,6 +1477,29 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen) return var; } +//=========================================================================== +// +// C_CreateCVar +// +// Create a new cvar with the specified name and type. It should not already +// exist. +// +//=========================================================================== + +FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags) +{ + assert(FindCVar(var_name, NULL) == NULL); + switch (var_type) + { + case CVAR_Bool: return new FBoolCVar(var_name, 0, flags); + case CVAR_Int: return new FIntCVar(var_name, 0, flags); + case CVAR_Float: return new FFloatCVar(var_name, 0, flags); + case CVAR_String: return new FStringCVar(var_name, NULL, flags); + case CVAR_Color: return new FColorCVar(var_name, 0, flags); + default: return NULL; + } +} + void UnlatchCVars (void) { FLatchedValue var; diff --git a/src/c_cvars.h b/src/c_cvars.h index 9c7873802..98539be10 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -96,6 +96,7 @@ public: inline const char *GetName () const { return Name; } inline uint32 GetFlags () const { return Flags; } + inline FBaseCVar *GetNext() const { return m_Next; } void CmdSet (const char *newval); void ForceSet (UCVarValue value, ECVarType type); @@ -181,6 +182,9 @@ void C_BackupCVars (void); FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); FBaseCVar *FindCVarSub (const char *var_name, int namelen); +// Create a new cvar with the specified name and type +FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags); + // Called from G_InitNew() void UnlatchCVars (void); @@ -425,5 +429,6 @@ void C_ForgetCVars (void); #define EXTERN_CVAR(type,name) extern F##type##CVar name; +extern FBaseCVar *CVars; #endif //__C_CVARS_H__ diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index e3766fd02..c33cfdf37 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -755,7 +755,7 @@ FString strbin1 (const char *start) // //========================================================================== -void CleanseString(char *str) +char *CleanseString(char *str) { char *escape = strrchr(str, TEXTCOLOR_ESCAPE); if (escape != NULL) @@ -773,6 +773,7 @@ void CleanseString(char *str) } } } + return str; } //========================================================================== diff --git a/src/cmdlib.h b/src/cmdlib.h index 7c29644d5..e3a9d3d08 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -47,7 +47,7 @@ const char *myasctime (); int strbin (char *str); FString strbin1 (const char *start); -void CleanseString (char *str); +char *CleanseString (char *str); void CreatePath(const char * fn); diff --git a/src/d_net.cpp b/src/d_net.cpp index dff5c948e..902d912bb 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -596,12 +596,12 @@ void PlayerIsGone (int netnode, int netconsole) if (deathmatch) { Printf ("%s left the game with %d frags\n", - players[netconsole].userinfo.netname, - players[netconsole].fragcount); + players[netconsole].userinfo.GetName(), + players[netconsole].fragcount); } else { - Printf ("%s left the game\n", players[netconsole].userinfo.netname); + Printf ("%s left the game\n", players[netconsole].userinfo.GetName()); } // [RH] Revert each player to their own view if spying through the player who left @@ -646,7 +646,7 @@ void PlayerIsGone (int netnode, int netconsole) { Net_Arbitrator = i; players[i].settings_controller = true; - Printf ("%s is the new arbitrator\n", players[i].userinfo.netname); + Printf ("%s is the new arbitrator\n", players[i].userinfo.GetName()); break; } } @@ -1361,7 +1361,7 @@ bool DoArbitrate (void *userdata) data->playersdetected[0] |= 1 << netbuffer[1]; StartScreen->NetMessage ("Found %s (node %d, player %d)", - players[netbuffer[1]].userinfo.netname, + players[netbuffer[1]].userinfo.GetName(), node, netbuffer[1]+1); } } @@ -1968,12 +1968,12 @@ void Net_DoCommand (int type, BYTE **stream, int player) { case DEM_SAY: { - const char *name = players[player].userinfo.netname; + const char *name = players[player].userinfo.GetName(); BYTE who = ReadByte (stream); s = ReadString (stream); CleanseString (s); - if (((who & 1) == 0) || players[player].userinfo.team == TEAM_NONE) + if (((who & 1) == 0) || players[player].userinfo.GetTeam() == TEAM_NONE) { // Said to everyone if (who & 2) { @@ -1985,7 +1985,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.chatSound, 1, ATTN_NONE); } - else if (players[player].userinfo.team == players[consoleplayer].userinfo.team) + else if (players[player].userinfo.GetTeam() == players[consoleplayer].userinfo.GetTeam()) { // Said only to members of the player's team if (who & 2) { @@ -2392,7 +2392,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) players[playernum].settings_controller = true; if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) - Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.netname); + Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.GetName()); } break; @@ -2402,7 +2402,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) players[playernum].settings_controller = false; if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) - Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.netname); + Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.GetName()); } break; @@ -2653,7 +2653,7 @@ CCMD (pings) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], - players[i].userinfo.netname); + players[i].userinfo.GetName()); } //========================================================================== @@ -2675,13 +2675,13 @@ static void Network_Controller (int playernum, bool add) if (players[playernum].settings_controller && add) { - Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.netname); + Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.GetName()); return; } if (!players[playernum].settings_controller && !add) { - Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.netname); + Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.GetName()); return; } @@ -2780,7 +2780,7 @@ CCMD (net_listcontrollers) if (players[i].settings_controller) { - Printf ("- %s\n", players[i].userinfo.netname); + Printf ("- %s\n", players[i].userinfo.GetName()); } } } diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index ef8984931..7f90822a2 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -192,11 +192,12 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet { userinfo_t *info = &players[player].userinfo; FPlayerColorSet *colorset = NULL; - int color; + uint32 color; + int team; if (players[player].mo != NULL) { - colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->colorset); + colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->GetColorSet()); } if (colorset != NULL) { @@ -204,19 +205,19 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet } else { - color = info->color; + color = info->GetColor(); } RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, h, s, v); - if (teamplay && TeamLibrary.IsValidTeam(info->team) && !Teams[info->team].GetAllowCustomPlayerColor ()) + if (teamplay && TeamLibrary.IsValidTeam((team = info->GetTeam())) && !Teams[team].GetAllowCustomPlayerColor()) { // In team play, force the player to use the team's hue // and adjust the saturation and value so that the team // hue is visible in the final color. float ts, tv; - int tcolor = Teams[info->team].GetPlayerColor (); + int tcolor = Teams[team].GetPlayerColor (); RGBtoHSV (RPART(tcolor)/255.f, GPART(tcolor)/255.f, BPART(tcolor)/255.f, h, &ts, &tv); @@ -264,9 +265,10 @@ int D_PickRandomTeam () { if (playeringame[i]) { - if (TeamLibrary.IsValidTeam (players[i].userinfo.team)) + team = players[i].userinfo.GetTeam(); + if (TeamLibrary.IsValidTeam(team)) { - if (Teams[players[i].userinfo.team].m_iPresent++ == 0) + if (Teams[team].m_iPresent++ == 0) { numTeams++; } @@ -278,7 +280,7 @@ int D_PickRandomTeam () { do { - team = pr_pickteam() % Teams.Size (); + team = pr_pickteam() % Teams.Size(); } while (Teams[team].m_iPresent != 0); } else @@ -319,7 +321,7 @@ static void UpdateTeam (int pnum, int team, bool update) { userinfo_t *info = &players[pnum].userinfo; - if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->team)) + if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->GetTeam())) { Printf ("Team changing has been disabled!\n"); return; @@ -331,19 +333,15 @@ static void UpdateTeam (int pnum, int team, bool update) { team = TEAM_NONE; } - oldteam = info->team; - info->team = team; + oldteam = info->GetTeam(); + team = info->TeamChanged(team); - if (teamplay && !TeamLibrary.IsValidTeam (info->team)) - { // Force players onto teams in teamplay mode - info->team = D_PickRandomTeam (); - } - if (update && oldteam != info->team) + if (update && oldteam != team) { - if (TeamLibrary.IsValidTeam (info->team)) - Printf ("%s joined the %s team\n", info->netname, Teams[info->team].GetName ()); + if (TeamLibrary.IsValidTeam (team)) + Printf ("%s joined the %s team\n", info->GetName(), Teams[team].GetName ()); else - Printf ("%s is now a loner\n", info->netname); + Printf ("%s is now a loner\n", info->GetName()); } // Let the player take on the team's color R_BuildPlayerTranslation (pnum); @@ -351,25 +349,28 @@ static void UpdateTeam (int pnum, int team, bool update) { StatusBar->AttachToPlayer (&players[pnum]); } - if (!TeamLibrary.IsValidTeam (info->team)) - info->team = TEAM_NONE; + // Double-check + if (!TeamLibrary.IsValidTeam (team)) + { + *static_cast((*info)[NAME_Team]) = TEAM_NONE; + } } int D_GetFragCount (player_t *player) { - if (!teamplay || !TeamLibrary.IsValidTeam (player->userinfo.team)) + const int team = player->userinfo.GetTeam(); + if (!teamplay || !TeamLibrary.IsValidTeam(team)) { return player->fragcount; } else { // Count total frags for this player's team - const int team = player->userinfo.team; int count = 0; for (int i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[i] && players[i].userinfo.team == team) + if (playeringame[i] && players[i].userinfo.GetTeam() == team) { count += players[i].fragcount; } @@ -381,37 +382,147 @@ int D_GetFragCount (player_t *player) void D_SetupUserInfo () { int i; - userinfo_t *coninfo = &players[consoleplayer].userinfo; + userinfo_t *coninfo; + // Reset everybody's userinfo to a default state. for (i = 0; i < MAXPLAYERS; i++) - memset (&players[i].userinfo, 0, sizeof(userinfo_t)); + { + players[i].userinfo.Reset(); + } + // Initialize the console player's user info + coninfo = &players[consoleplayer].userinfo; - strncpy (coninfo->netname, name, MAXPLAYERNAME); - if (teamplay && !TeamLibrary.IsValidTeam (team)) + for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - coninfo->team = D_PickRandomTeam (); + if (cvar->GetFlags() & CVAR_USERINFO) + { + FBaseCVar **newcvar; + FName cvarname(cvar->GetName()); + ECVarType type; + + switch (cvarname.GetIndex()) + { + // Some cvars don't copy their original value directly. + case NAME_Team: coninfo->TeamChanged(team); break; + case NAME_Skin: coninfo->SkinChanged(skin); break; + case NAME_Gender: coninfo->GenderChanged(gender); break; + case NAME_PlayerClass: coninfo->PlayerClassChanged(playerclass); break; + // The rest do. + default: + newcvar = coninfo->CheckKey(cvarname); + (*newcvar)->SetGenericRep(cvar->GetGenericRep(CVAR_String), CVAR_String); + break; + } + } } - else + R_BuildPlayerTranslation(consoleplayer); +} + +void userinfo_t::Reset() +{ + // Clear this player's userinfo. + TMapIterator it(*this); + TMap::Pair *pair; + + while (it.NextPair(pair)) { - coninfo->team = team; + delete pair->Value; } - if (autoaim > 35.f || autoaim < 0.f) + Clear(); + + // Create userinfo vars for this player, initialized to their defaults. + for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - coninfo->aimdist = ANGLE_1*35; + if (cvar->GetFlags() & CVAR_USERINFO) + { + ECVarType type; + FName cvarname(cvar->GetName()); + FBaseCVar *newcvar; + + // Some cvars have different types for their shadow copies. + switch (cvarname.GetIndex()) + { + case NAME_Skin: type = CVAR_Int; break; + case NAME_Gender: type = CVAR_Int; break; + case NAME_PlayerClass: type = CVAR_Int; break; + default: type = cvar->GetRealType(); break; + } + newcvar = C_CreateCVar(NULL, type, 0); + newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String); + Insert(cvarname, newcvar); + } } - else - { - coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1)); +} + +int userinfo_t::TeamChanged(int team) +{ + if (teamplay && !TeamLibrary.IsValidTeam(team)) + { // Force players onto teams in teamplay mode + team = D_PickRandomTeam(); } - coninfo->color = color; - coninfo->colorset = colorset; - coninfo->skin = R_FindSkin (skin, 0); - coninfo->gender = D_GenderToInt (gender); - coninfo->neverswitch = neverswitchonpickup; - coninfo->MoveBob = (fixed_t)(65536.f * movebob); - coninfo->StillBob = (fixed_t)(65536.f * stillbob); - coninfo->PlayerClass = D_PlayerClassToInt (playerclass); - R_BuildPlayerTranslation (consoleplayer); + *static_cast((*this)[NAME_Team]) = team; + return team; +} + +int userinfo_t::SkinChanged(const char *skinname) +{ + int skinnum = R_FindSkin(skinname, 0); + *static_cast((*this)[NAME_Skin]) = skinnum; + return skinnum; +} + +int userinfo_t::SkinNumChanged(int skinnum) +{ + *static_cast((*this)[NAME_Skin]) = skinnum; + return skinnum; +} + +int userinfo_t::GenderChanged(const char *gendername) +{ + int gendernum = D_GenderToInt(gendername); + *static_cast((*this)[NAME_Gender]) = gendernum; + return gendernum; +} + +int userinfo_t::PlayerClassChanged(const char *classname) +{ + int classnum = D_PlayerClassToInt(classname); + *static_cast((*this)[NAME_PlayerClass]) = classnum; + return classnum; +} + +int userinfo_t::PlayerClassNumChanged(int classnum) +{ + *static_cast((*this)[NAME_PlayerClass]) = classnum; + return classnum; +} + +int userinfo_t::ColorSetChanged(int setnum) +{ + *static_cast((*this)[NAME_ColorSet]) = setnum; + return setnum; +} + +uint32 userinfo_t::ColorChanged(const char *colorname) +{ + FColorCVar *color = static_cast((*this)[NAME_Color]); + assert(color != NULL); + UCVarValue val; + val.String = const_cast(colorname); + color->SetGenericRep(val, CVAR_String); + *static_cast((*this)[NAME_ColorSet]) = -1; + return *color; +} + +uint32 userinfo_t::ColorChanged(uint32 colorval) +{ + FColorCVar *color = static_cast((*this)[NAME_Color]); + assert(color != NULL); + UCVarValue val; + val.Int = colorval; + color->SetGenericRep(val, CVAR_Int); + // This version is called by the menu code. Do not implicitly set colorset. + return colorval; } void D_UserInfoChanged (FBaseCVar *cvar) @@ -503,7 +614,7 @@ static const char *SetServerVar (char *name, ECVarType type, BYTE **stream, bool { if (playeringame[i]) { - UpdateTeam (i, players[i].userinfo.team, true); + UpdateTeam (i, players[i].userinfo.GetTeam(), true); } } } @@ -572,113 +683,131 @@ void D_DoServerInfoChange (BYTE **stream, bool singlebit) } } -void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) +static int STACK_ARGS userinfosortfunc(const void *a, const void *b) { - if (i >= MAXPLAYERS) - { - WriteByte (0, stream); - } - else - { - userinfo_t *info = &players[i].userinfo; - - const PClass *type = PlayerClasses[info->PlayerClass].Type; - - if (!compact) - { - sprintf (*((char **)stream), - "\\name\\%s" - "\\autoaim\\%g" - "\\color\\%x %x %x" - "\\colorset\\%d" - "\\skin\\%s" - "\\team\\%d" - "\\gender\\%s" - "\\neverswitchonpickup\\%d" - "\\movebob\\%g" - "\\stillbob\\%g" - "\\playerclass\\%s" - , - D_EscapeUserInfo(info->netname).GetChars(), - (double)info->aimdist / (float)ANGLE_1, - RPART(info->color), GPART(info->color), BPART(info->color), - info->colorset, - D_EscapeUserInfo(skins[info->skin].name).GetChars(), - info->team, - info->gender == GENDER_FEMALE ? "female" : - info->gender == GENDER_NEUTER ? "other" : "male", - info->neverswitch, - (float)(info->MoveBob) / 65536.f, - (float)(info->StillBob) / 65536.f, - info->PlayerClass == -1 ? "Random" : - D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars() - ); - } - else - { - sprintf (*((char **)stream), - "\\" - "\\%s" // name - "\\%g" // autoaim - "\\%x %x %x" // color - "\\%s" // skin - "\\%d" // team - "\\%s" // gender - "\\%d" // neverswitchonpickup - "\\%g" // movebob - "\\%g" // stillbob - "\\%s" // playerclass - "\\%d" // colorset - , - D_EscapeUserInfo(info->netname).GetChars(), - (double)info->aimdist / (float)ANGLE_1, - RPART(info->color), GPART(info->color), BPART(info->color), - D_EscapeUserInfo(skins[info->skin].name).GetChars(), - info->team, - info->gender == GENDER_FEMALE ? "female" : - info->gender == GENDER_NEUTER ? "other" : "male", - info->neverswitch, - (float)(info->MoveBob) / 65536.f, - (float)(info->StillBob) / 65536.f, - info->PlayerClass == -1 ? "Random" : - D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars(), - info->colorset - ); - } - } - - *stream += strlen (*((char **)stream)) + 1; + TMap::ConstPair *pair1 = *(TMap::ConstPair **)a; + TMap::ConstPair *pair2 = *(TMap::ConstPair **)b; + return stricmp(pair1->Key.GetChars(), pair2->Key.GetChars()); } -void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) +static int STACK_ARGS namesortfunc(const void *a, const void *b) { - userinfo_t *info = &players[i].userinfo; + FName *name1 = (FName *)a; + FName *name2 = (FName *)b; + return stricmp(name1->GetChars(), name2->GetChars()); +} + +void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact) +{ + if (pnum >= MAXPLAYERS) + { + WriteByte (0, stream); + return; + } + + userinfo_t *info = &players[pnum].userinfo; + TArray::Pair *> userinfo_pairs(info->CountUsed()); + TMap::Iterator it(*info); + TMap::Pair *pair; + UCVarValue cval; + + // Create a simple array of all userinfo cvars + while (it.NextPair(pair)) + { + userinfo_pairs.Push(pair); + } + // For compact mode, these need to be sorted. Verbose mode doesn't matter. + if (compact) + { + qsort(&userinfo_pairs[0], userinfo_pairs.Size(), sizeof(pair), userinfosortfunc); + // Compact mode is signified by starting the string with two backslash characters. + // We output one now. The second will be output as part of the first value. + *(*stream)++ = '\\'; + } + for (unsigned int i = 0; i < userinfo_pairs.Size(); ++i) + { + pair = userinfo_pairs[i]; + + if (!compact) + { // In verbose mode, prepend the cvar's name + *stream += sprintf(*((char **)stream), "\\%s\\", pair->Key.GetChars()); + } + // A few of these need special handling for compatibility reasons. + switch (pair->Key.GetIndex()) + { + case NAME_Gender: + *stream += sprintf(*((char **)stream), "\\%s", + *static_cast(pair->Value) == GENDER_FEMALE ? "female" : + *static_cast(pair->Value) == GENDER_NEUTER ? "other" : "male"); + break; + + case NAME_PlayerClass: + *stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" : + D_EscapeUserInfo(info->GetPlayerClassType()->Meta.GetMetaString(APMETA_DisplayName)).GetChars()); + break; + + case NAME_Skin: + *stream += sprintf(*((char **)stream), "\\%s", D_EscapeUserInfo(skins[info->GetSkin()].name).GetChars()); + break; + + default: + cval = pair->Value->GetGenericRep(CVAR_String); + *stream += sprintf(*((char **)stream), "\\%s", cval.String); + break; + } + } + *(*stream)++ = '\0'; +} + +void D_ReadUserInfoStrings (int pnum, BYTE **stream, bool update) +{ + userinfo_t *info = &players[pnum].userinfo; + TArray compact_names(info->CountUsed()); + FBaseCVar **cvar_ptr; const char *ptr = *((const char **)stream); const char *breakpt; FString value; bool compact; - int infotype = -1; + FName keyname; + unsigned int infotype = 0; if (*ptr++ != '\\') return; compact = (*ptr == '\\') ? ptr++, true : false; - if (i < MAXPLAYERS) + // We need the cvar names in sorted order for compact mode + if (compact) { - for (;;) - { - int j; + TMap::Iterator it(*info); + TMap::Pair *pair; - breakpt = strchr (ptr, '\\'); + while (it.NextPair(pair)) + { + compact_names.Push(pair->Key); + } + qsort(&compact_names[0], compact_names.Size(), sizeof(FName), namesortfunc); + } + + if (pnum < MAXPLAYERS) + { + for (breakpt = ptr; breakpt != NULL; ptr = breakpt + 1) + { + breakpt = strchr(ptr, '\\'); if (compact) { + // Compact has just the value. + if (infotype >= compact_names.Size()) + { // Too many entries! OMG! + break; + } + keyname = compact_names[infotype++]; value = D_UnescapeUserInfo(ptr, breakpt != NULL ? breakpt - ptr : strlen(ptr)); - infotype++; } else { + // Verbose has both the key name and its value. assert(breakpt != NULL); // A malicious remote machine could invalidate the above assert. if (breakpt == NULL) @@ -694,154 +823,187 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) { value = D_UnescapeUserInfo(valstart, strlen(valstart)); } - - for (j = 0; - UserInfoStrings[j] && strnicmp (UserInfoStrings[j], ptr, valstart - ptr - 1) != 0; - ++j) - { } - if (UserInfoStrings[j] == NULL) - { - infotype = -1; - } - else - { - infotype = j; - } + keyname = FName(ptr, valstart - ptr - 1, true); } - switch (infotype) + + // A few of these need special handling. + switch (keyname) { - case INFO_Autoaim: { - double angles; - - angles = atof (value); - if (angles > 35.f || angles < 0.f) - { - info->aimdist = ANGLE_1*35; - } - else - { - info->aimdist = abs ((int)(angles * (float)ANGLE_1)); - } - } + case NAME_Gender: + info->GenderChanged(value); break; - case INFO_Name: - { - char oldname[MAXPLAYERNAME+1]; - - strcpy (oldname, info->netname); - strncpy (info->netname, value, MAXPLAYERNAME); - info->netname[MAXPLAYERNAME] = 0; - CleanseString(info->netname); - - if (update && strcmp (oldname, info->netname) != 0) - { - Printf ("%s is now known as %s\n", oldname, info->netname); - } - } + case NAME_PlayerClass: + info->PlayerClassChanged(value); break; - case INFO_Team: - UpdateTeam (i, atoi(value), update); - break; - - case INFO_Color: - case INFO_ColorSet: - if (infotype == INFO_Color) + case NAME_Skin: + info->SkinChanged(value); + if (players[pnum].mo != NULL) { - info->color = V_GetColorFromString (NULL, value); - info->colorset = -1; - } - else - { - info->colorset = atoi(value); - } - R_BuildPlayerTranslation (i); - if (StatusBar != NULL && i == StatusBar->GetPlayer()) - { - StatusBar->AttachToPlayer (&players[i]); - } - break; - - case INFO_Skin: - info->skin = R_FindSkin (value, players[i].CurrentPlayerClass); - if (players[i].mo != NULL) - { - if (players[i].cls != NULL && - !(players[i].mo->flags4 & MF4_NOSKIN) && - players[i].mo->state->sprite == - GetDefaultByType (players[i].cls)->SpawnState->sprite) + if (players[pnum].cls != NULL && + !(players[pnum].mo->flags4 & MF4_NOSKIN) && + players[pnum].mo->state->sprite == + GetDefaultByType (players[pnum].cls)->SpawnState->sprite) { // Only change the sprite if the player is using a standard one - players[i].mo->sprite = skins[info->skin].sprite; + players[pnum].mo->sprite = skins[info->GetSkin()].sprite; } } // Rebuild translation in case the new skin uses a different range // than the old one. - R_BuildPlayerTranslation (i); + R_BuildPlayerTranslation(pnum); break; - case INFO_Gender: - info->gender = D_GenderToInt (value); + case NAME_Team: + UpdateTeam(pnum, atoi(value), update); break; - case INFO_NeverSwitchOnPickup: - if (value[0] >= '0' && value[0] <= '9') - { - info->neverswitch = atoi (value) ? true : false; - } - else if (stricmp (value, "true") == 0) - { - info->neverswitch = 1; - } - else - { - info->neverswitch = 0; - } - break; - - case INFO_MoveBob: - info->MoveBob = (fixed_t)(atof (value) * 65536.f); - break; - - case INFO_StillBob: - info->StillBob = (fixed_t)(atof (value) * 65536.f); - break; - - case INFO_PlayerClass: - info->PlayerClass = D_PlayerClassToInt (value); + case NAME_Color: + info->ColorChanged(value); break; default: + cvar_ptr = info->CheckKey(keyname); + if (cvar_ptr != NULL) + { + assert(*cvar_ptr != NULL); + UCVarValue val; + FString oldname; + + if (keyname == NAME_Name) + { + val = (*cvar_ptr)->GetGenericRep(CVAR_String); + oldname = val.String; + } + val.String = CleanseString(value.LockBuffer()); + (*cvar_ptr)->SetGenericRep(val, CVAR_String); + value.UnlockBuffer(); + if (keyname == NAME_Name && update && oldname != value) + { + Printf("%s is now known as %s\n", oldname.GetChars(), value.GetChars()); + } + } break; } - - if (breakpt) + if (keyname == NAME_Color || keyname == NAME_ColorSet) { - ptr = breakpt + 1; + R_BuildPlayerTranslation(pnum); + if (StatusBar != NULL && pnum == StatusBar->GetPlayer()) + { + StatusBar->AttachToPlayer(&players[pnum]); + } } - else + } + } + *stream += strlen (*((char **)stream)) + 1; +} + +void ReadCompatibleUserInfo(FArchive &arc, userinfo_t &info) +{ + char netname[MAXPLAYERNAME]; + BYTE team; + int aimdist, color, colorset, skin, gender; + bool neverswitch; + //fixed_t movebob, stillbob; These were never serialized! + //int playerclass; " + + info.Reset(); + + arc.Read(&netname, sizeof(netname)); + arc << team << aimdist << color << skin << gender << neverswitch << colorset; + + *static_cast(info[NAME_Name]) = netname; + *static_cast(info[NAME_Team]) = team; + *static_cast(info[NAME_AutoAim]) = (float)aimdist / ANGLE_1; + *static_cast(info[NAME_Skin]) = skin; + *static_cast(info[NAME_Gender]) = gender; + *static_cast(info[NAME_NeverSwitchOnPickup]) = neverswitch; + *static_cast(info[NAME_ColorSet]) = colorset; + + UCVarValue val; + val.Int = color; + static_cast(info[NAME_Color])->SetGenericRep(val, CVAR_Int); +} + +void WriteUserInfo(FArchive &arc, userinfo_t &info) +{ + TMapIterator it(info); + TMap::Pair *pair; + FName name; + UCVarValue val; + int i; + + while (it.NextPair(pair)) + { + name = pair->Key; + arc << name; + switch (name.GetIndex()) + { + case NAME_Skin: + arc.WriteString(skins[info.GetSkin()].name); + break; + + case NAME_PlayerClass: + i = info.GetPlayerClassNum(); + arc.WriteString(i == -1 ? "Random" : PlayerClasses[i].Type->Meta.GetMetaString(APMETA_DisplayName)); + break; + + default: + val = pair->Value->GetGenericRep(CVAR_String); + arc.WriteString(val.String); + break; + } + } + name = NAME_None; + arc << name; +} + +void ReadUserInfo(FArchive &arc, userinfo_t &info) +{ + FName name; + FBaseCVar **cvar; + char *str = NULL; + UCVarValue val; + + info.Reset(); + for (arc << name; name != NAME_None; arc << name) + { + cvar = info.CheckKey(name); + arc << str; + if (cvar != NULL && *cvar != NULL) + { + switch (name) { + case NAME_Team: info.TeamChanged(atoi(str)); break; + case NAME_Skin: info.SkinChanged(str); break; + case NAME_PlayerClass: info.PlayerClassChanged(str); break; + default: + val.String = str; + (*cvar)->SetGenericRep(val, CVAR_String); break; } } } - - *stream += strlen (*((char **)stream)) + 1; + if (str != NULL) + { + delete[] str; + } } FArchive &operator<< (FArchive &arc, userinfo_t &info) { - if (arc.IsStoring ()) + if (SaveVersion < 4253) { - arc.Write (&info.netname, sizeof(info.netname)); + ReadCompatibleUserInfo(arc, info); + } + else if (arc.IsStoring()) + { + WriteUserInfo(arc, info); } else { - arc.Read (&info.netname, sizeof(info.netname)); + ReadUserInfo(arc, info); } - arc << info.team << info.aimdist << info.color - << info.skin << info.gender << info.neverswitch - << info.colorset; return arc; } @@ -855,27 +1017,51 @@ CCMD (playerinfo) { if (playeringame[i]) { - Printf ("%d. %s\n", i, players[i].userinfo.netname); + Printf("%d. %s\n", i, players[i].userinfo.GetName()); } } } else { - int i = atoi (argv[1]); + int i = atoi(argv[1]); + + if (i < 0 || i >= MAXPLAYERS) + { + Printf("Bad player number\n"); + return; + } userinfo_t *ui = &players[i].userinfo; - Printf ("Name: %s\n", ui->netname); - Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team); - Printf ("Aimdist: %d\n", ui->aimdist); - Printf ("Color: %06x\n", ui->color); - Printf ("ColorSet: %d\n", ui->colorset); - Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin); - Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender); - Printf ("NeverSwitch: %d\n", ui->neverswitch); - Printf ("MoveBob: %g\n", ui->MoveBob/65536.f); - Printf ("StillBob: %g\n", ui->StillBob/65536.f); - Printf ("PlayerClass: %s (%d)\n", - ui->PlayerClass == -1 ? "Random" : PlayerClasses[ui->PlayerClass].Type->Meta.GetMetaString (APMETA_DisplayName), - ui->PlayerClass); - if (argv.argc() > 2) PrintMiscActorInfo(players[i].mo); + + if (!playeringame[i]) + { + Printf(TEXTCOLOR_ORANGE "Player %d is not in the game\n", i); + } + + // Print special info + Printf("%20s: %s\n", "Name", ui->GetName()); + Printf("%20s: %s (%d)\n", "Team", ui->GetTeam() == TEAM_NONE ? "None" : Teams[ui->GetTeam()].GetName(), ui->GetTeam()); + Printf("%20s: %s (%d)\n", "Skin", skins[ui->GetSkin()].name, ui->GetSkin()); + Printf("%20s: %s (%d)\n", "Gender", GenderNames[ui->GetGender()], ui->GetGender()); + Printf("%20s: %s (%d)\n", "PlayerClass", + ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->Meta.GetMetaString (APMETA_DisplayName), + ui->GetPlayerClassNum()); + + // Print generic info + TMapIterator it(*ui); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + if (pair->Key != NAME_Name && pair->Key != NAME_Team && pair->Key != NAME_Skin && + pair->Key != NAME_Gender && pair->Key != NAME_PlayerClass) + { + UCVarValue val = pair->Value->GetGenericRep(CVAR_String); + Printf("%20s: %s\n", pair->Key.GetChars(), val.String); + } + } + if (argv.argc() > 2) + { + PrintMiscActorInfo(players[i].mo); + } } } diff --git a/src/d_player.h b/src/d_player.h index 3467328f4..e8c183141 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -228,6 +228,29 @@ enum #define MAXPLAYERNAME 15 +// [GRB] Custom player classes +enum +{ + PCF_NOMENU = 1, // Hide in new game menu +}; + +class FPlayerClass +{ +public: + FPlayerClass (); + FPlayerClass (const FPlayerClass &other); + ~FPlayerClass (); + + bool CheckSkin (int skin); + + const PClass *Type; + DWORD Flags; + TArray Skins; +}; + +extern TArray PlayerClasses; + +// User info (per-player copies of each CVAR_USERINFO cvar) enum { GENDER_MALE, @@ -235,20 +258,80 @@ enum GENDER_NEUTER }; -struct userinfo_t +struct userinfo_t : TMap { - char netname[MAXPLAYERNAME+1]; - BYTE team; - int aimdist; - int color; - int colorset; - int skin; - int gender; - bool neverswitch; - fixed_t MoveBob, StillBob; - int PlayerClass; + int GetAimDist() const + { + if (dmflags2 & DF2_NOAUTOAIM) + { + return 0; + } - int GetAimDist() const { return (dmflags2 & DF2_NOAUTOAIM)? 0 : aimdist; } + float aim = *static_cast(*CheckKey(NAME_Autoaim)); + if (aim > 35 || aim < 0) + { + return ANGLE_1*35; + } + else + { + return xs_RoundToInt(fabs(aim * ANGLE_1)); + } + } + const char *GetName() const + { + return *static_cast(*CheckKey(NAME_Name)); + } + int GetTeam() const + { + return *static_cast(*CheckKey(NAME_Team)); + } + int GetColorSet() const + { + return *static_cast(*CheckKey(NAME_ColorSet)); + } + uint32 GetColor() const + { + return *static_cast(*CheckKey(NAME_Color)); + } + bool GetNeverSwitch() const + { + return *static_cast(*CheckKey(NAME_NeverSwitchOnPickup)); + } + fixed_t GetMoveBob() const + { + return FLOAT2FIXED(*static_cast(*CheckKey(NAME_MoveBob))); + } + fixed_t GetStillBob() const + { + return FLOAT2FIXED(*static_cast(*CheckKey(NAME_StillBob))); + } + int GetPlayerClassNum() const + { + return *static_cast(*CheckKey(NAME_PlayerClass)); + } + const PClass *GetPlayerClassType() const + { + return PlayerClasses[GetPlayerClassNum()].Type; + } + int GetSkin() const + { + return *static_cast(*CheckKey(NAME_Skin)); + } + int GetGender() const + { + return *static_cast(*CheckKey(NAME_Gender)); + } + + void Reset(); + int TeamChanged(int team); + int SkinChanged(const char *skinname); + int SkinNumChanged(int skinnum); + int GenderChanged(const char *gendername); + int PlayerClassChanged(const char *classname); + int PlayerClassNumChanged(int classnum); + uint32 ColorChanged(const char *colorname); + uint32 ColorChanged(uint32 colorval); + int ColorSetChanged(int setnum); }; FArchive &operator<< (FArchive &arc, userinfo_t &info); @@ -467,26 +550,4 @@ inline bool AActor::IsNoClip2() const bool P_IsPlayerTotallyFrozen(const player_t *player); -// [GRB] Custom player classes -enum -{ - PCF_NOMENU = 1, // Hide in new game menu -}; - -class FPlayerClass -{ -public: - FPlayerClass (); - FPlayerClass (const FPlayerClass &other); - ~FPlayerClass (); - - bool CheckSkin (int skin); - - const PClass *Type; - DWORD Flags; - TArray Skins; -}; - -extern TArray PlayerClasses; - #endif // __D_PLAYER_H__ diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index ec083631a..448c200d8 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -774,7 +774,7 @@ void FParser::SF_PlayerName(void) if(plnum !=-1) { t_return.type = svt_string; - t_return.string = players[plnum].userinfo.netname; + t_return.string = players[plnum].userinfo.GetName(); } else { diff --git a/src/g_game.cpp b/src/g_game.cpp index e9d11151c..356bd5967 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1127,7 +1127,7 @@ void G_Ticker () if (cmd->ucmd.forwardmove > TURBOTHRESHOLD && !(gametic&31) && ((gametic>>5)&(MAXPLAYERS-1)) == i ) { - Printf ("%s is turbo!\n", players[i].userinfo.netname); + Printf ("%s is turbo!\n", players[i].userinfo.GetName()); } if (netgame && !players[i].isbot && !demoplayback && (gametic%ticdup) == 0) @@ -1312,7 +1312,7 @@ void G_PlayerReborn (int player) int chasecam; BYTE currclass; userinfo_t userinfo; // [RH] Save userinfo - botskill_t b_skill;//Added by MC: + botskill_t b_skill; //Added by MC: APlayerPawn *actor; const PClass *cls; FString log; @@ -1326,7 +1326,7 @@ void G_PlayerReborn (int player) secretcount = p->secretcount; currclass = p->CurrentPlayerClass; b_skill = p->skill; //Added by MC: - memcpy (&userinfo, &p->userinfo, sizeof(userinfo)); + userinfo.TransferFrom(p->userinfo); actor = p->mo; cls = p->cls; log = p->LogText; @@ -1342,7 +1342,7 @@ void G_PlayerReborn (int player) p->itemcount = itemcount; p->secretcount = secretcount; p->CurrentPlayerClass = currclass; - memcpy (&p->userinfo, &userinfo, sizeof(userinfo)); + p->userinfo.TransferFrom(userinfo); p->mo = actor; p->cls = cls; p->LogText = log; diff --git a/src/g_level.cpp b/src/g_level.cpp index 3b0c8fe12..526ec2a22 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -240,14 +240,15 @@ void G_NewInit () for (i = 0; i < MAXPLAYERS; ++i) { player_t *p = &players[i]; - userinfo_t saved_ui = players[i].userinfo; + userinfo_t saved_ui; + saved_ui.TransferFrom(players[i].userinfo); int chasecam = p->cheats & CF_CHASECAM; p->~player_t(); ::new(p) player_t; players[i].cheats |= chasecam; players[i].playerstate = PST_DEAD; playeringame[i] = 0; - players[i].userinfo = saved_ui; + players[i].userinfo.TransferFrom(saved_ui); } BackupSaveName = ""; consoleplayer = 0; @@ -287,7 +288,7 @@ static void InitPlayerClasses () { for (int i = 0; i < MAXPLAYERS; ++i) { - SinglePlayerClass[i] = players[i].userinfo.PlayerClass; + SinglePlayerClass[i] = players[i].userinfo.GetPlayerClassNum(); if (SinglePlayerClass[i] < 0 || !playeringame[i]) { SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size (); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index da4f46918..2b3a6040d 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -287,11 +287,11 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, size_t skinindex = 0; // If a custom skin was in use, then reload it // or else the base skin for the player class. - if ((unsigned int)player->userinfo.skin >= PlayerClasses.Size () && - (size_t)player->userinfo.skin < numskins) + if ((unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size () && + (size_t)player->userinfo.GetSkin() < numskins) { - skinindex = player->userinfo.skin; + skinindex = player->userinfo.GetSkin(); } else if (PlayerClasses.Size () > 1) { diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 8275523ed..6caf42b7d 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -314,7 +314,7 @@ void AWeapon::AttachToOwner (AActor *other) SisterWeapon = AddWeapon (SisterWeaponType); if (Owner->player != NULL) { - if (!Owner->player->userinfo.neverswitch && !(WeaponFlags & WIF_NO_AUTO_SWITCH)) + if (!Owner->player->userinfo.GetNeverSwitch() && !(WeaponFlags & WIF_NO_AUTO_SWITCH)) { Owner->player->PendingWeapon = this; } diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index 313e2b847..fcadb0d1b 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -505,7 +505,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu } if (CurrentState != NULL) { - const char *skin_face = player->morphTics ? player->MorphedPlayerClass->Meta.GetMetaString(APMETA_Face) : skins[player->userinfo.skin].face; + const char *skin_face = player->morphTics ? player->MorphedPlayerClass->Meta.GetMetaString(APMETA_Face) : skins[player->userinfo.GetSkin()].face; return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 81609865a..6d0b77177 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -736,9 +736,9 @@ class CommandDrawString : public SBarInfoCommand } break; case PLAYERCLASS: - if(statusBar->CPlayer->userinfo.PlayerClass != cache) + if(statusBar->CPlayer->userinfo.GetPlayerClassNum() != cache) { - cache = statusBar->CPlayer->userinfo.PlayerClass; + cache = statusBar->CPlayer->userinfo.GetPlayerClassNum(); str = GetPrintableDisplayName(statusBar->CPlayer->cls); RealignString(); } @@ -758,7 +758,7 @@ class CommandDrawString : public SBarInfoCommand 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; + str = statusBar->CPlayer->userinfo.GetName(); RealignString(); break; case GLOBALVAR: diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 471e3047f..fd543f194 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -520,7 +520,7 @@ void DBaseStatusBar::ShowPlayerName () EColorRange color; color = (CPlayer == &players[consoleplayer]) ? CR_GOLD : CR_GREEN; - AttachMessage (new DHUDMessageFadeOut (SmallFont, CPlayer->userinfo.netname, + AttachMessage (new DHUDMessageFadeOut (SmallFont, CPlayer->userinfo.GetName(), 1.5f, 0.92f, 0, 0, color, 2.f, 0.35f), MAKE_ID('P','N','A','M')); } diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index a1870b4ae..afbb7a35d 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -94,7 +94,7 @@ static int STACK_ARGS comparepoints (const void *arg1, const void *arg2) diff = deathmatch ? p2->fragcount - p1->fragcount : p2->killcount - p1->killcount; if (diff == 0) { - diff = stricmp (p1->userinfo.netname, p2->userinfo.netname); + diff = stricmp(p1->userinfo.GetName(), p2->userinfo.GetName()); } return diff; } @@ -106,13 +106,13 @@ static int STACK_ARGS compareteams (const void *arg1, const void *arg2) player_t *p2 = *(player_t **)arg2; int diff; - diff = p1->userinfo.team - p2->userinfo.team; + diff = p1->userinfo.GetTeam() - p2->userinfo.GetTeam(); if (diff == 0) { diff = p2->fragcount - p1->fragcount; if (diff == 0) { - diff = stricmp (p1->userinfo.netname, p2->userinfo.netname); + diff = stricmp (p1->userinfo.GetName(), p2->userinfo.GetName()); } } return diff; @@ -189,7 +189,7 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh { if (playeringame[i]) { - int width = SmallFont->StringWidth(players[i].userinfo.netname); + int width = SmallFont->StringWidth(players[i].userinfo.GetName()); if (width > maxnamewidth) { maxnamewidth = width; @@ -268,14 +268,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER for (i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[sortedplayers[i]-players] && TeamLibrary.IsValidTeam (sortedplayers[i]->userinfo.team)) + if (playeringame[sortedplayers[i]-players] && TeamLibrary.IsValidTeam (sortedplayers[i]->userinfo.GetTeam())) { - if (Teams[sortedplayers[i]->userinfo.team].m_iPlayerCount++ == 0) + if (Teams[sortedplayers[i]->userinfo.GetTeam()].m_iPlayerCount++ == 0) { numTeams++; } - Teams[sortedplayers[i]->userinfo.team].m_iScore += sortedplayers[i]->fragcount; + Teams[sortedplayers[i]->userinfo.GetTeam()].m_iScore += sortedplayers[i]->fragcount; } } @@ -413,12 +413,12 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, TAG_DONE); } - screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.netname, + screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - if (teamplay && Teams[player->userinfo.team].GetLogo ().IsNotEmpty ()) + if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ()) { - FTexture *pic = TexMan[Teams[player->userinfo.team].GetLogo ().GetChars ()]; + FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()]; screen->DrawTexture (pic, col1 - (pic->GetScaledWidth() + 2) * CleanXfac, y, DTA_CleanNoMove, true, TAG_DONE); } @@ -453,8 +453,8 @@ int HU_GetRowColor(player_t *player, bool highlight) { if (teamplay && deathmatch) { - if (TeamLibrary.IsValidTeam (player->userinfo.team)) - return Teams[player->userinfo.team].GetTextColor(); + if (TeamLibrary.IsValidTeam (player->userinfo.GetTeam())) + return Teams[player->userinfo.GetTeam()].GetTextColor(); else return CR_GREY; } diff --git a/src/i_net.cpp b/src/i_net.cpp index 57543b29d..2c01f407d 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -272,12 +272,12 @@ void PacketGet (void) if (StartScreen != NULL) { StartScreen->NetMessage ("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.netname); + players[sendplayer[node]].userinfo.GetName()); } else { Printf("The connection from %s was dropped.\n", - players[sendplayer[node]].userinfo.netname); + players[sendplayer[node]].userinfo.GetName()); } doomcom.data[0] = 0x80; // NCMD_EXIT diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 4ac79f36e..6ee67006e 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -602,7 +602,7 @@ void DIntermissionScreenCast::Drawer () { if (PlayerClasses[i].Type == mClass) { - castsprite = skins[players[consoleplayer].userinfo.skin].sprite; + castsprite = skins[players[consoleplayer].userinfo.GetSkin()].sprite; } } } diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index e717aa3d2..07c467bac 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -522,7 +522,7 @@ void cht_DoCheat (player_t *player, int cheat) if (player == &players[consoleplayer]) Printf ("%s\n", msg); else if (cheat != CHT_CHASECAM) - Printf ("%s cheats: %s\n", player->userinfo.netname, msg); + Printf ("%s cheats: %s\n", player->userinfo.GetName(), msg); } const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickundo) @@ -603,7 +603,7 @@ void cht_Give (player_t *player, const char *name, int amount) const PClass *type; if (player != &players[consoleplayer]) - Printf ("%s is a cheater: give %s\n", player->userinfo.netname, name); + Printf ("%s is a cheater: give %s\n", player->userinfo.GetName(), name); if (player->mo == NULL || player->health <= 0) { diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index b3795b60b..26e6d3b96 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -406,9 +406,9 @@ void FListMenuItemPlayerDisplay::UpdateRandomClass() void FListMenuItemPlayerDisplay::UpdateTranslation() { - int PlayerColor = players[consoleplayer].userinfo.color; - int PlayerSkin = players[consoleplayer].userinfo.skin; - int PlayerColorset = players[consoleplayer].userinfo.colorset; + int PlayerColor = players[consoleplayer].userinfo.GetColor(); + int PlayerSkin = players[consoleplayer].userinfo.GetSkin(); + int PlayerColorset = players[consoleplayer].userinfo.GetColorSet(); if (mPlayerClass != NULL) { diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index a76817055..641b0699f 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -545,11 +545,11 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) li->SetValue(FListMenuItemPlayerDisplay::PDF_ROTATION, 0); li->SetValue(FListMenuItemPlayerDisplay::PDF_MODE, 1); li->SetValue(FListMenuItemPlayerDisplay::PDF_TRANSLATE, 1); - li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.PlayerClass); + li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum()); if (PlayerClass != NULL && !(GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN) && - players[consoleplayer].userinfo.PlayerClass != -1) + players[consoleplayer].userinfo.GetPlayerClassNum() != -1) { - li->SetValue(FListMenuItemPlayerDisplay::PDF_SKIN, players[consoleplayer].userinfo.skin); + li->SetValue(FListMenuItemPlayerDisplay::PDF_SKIN, players[consoleplayer].userinfo.GetSkin()); } } @@ -570,8 +570,8 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) li->SetValue(0, team == TEAM_NONE? 0 : team + 1); } - int mycolorset = players[consoleplayer].userinfo.colorset; - int color = players[consoleplayer].userinfo.color; + int mycolorset = players[consoleplayer].userinfo.GetColorSet(); + int color = players[consoleplayer].userinfo.GetColor(); UpdateColorsets(); @@ -614,7 +614,7 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) const char *cls = GetPrintableDisplayName(PlayerClasses[i].Type); li->SetString(gameinfo.norandomplayerclass ? i : i+1, cls); } - int pclass = players[consoleplayer].userinfo.PlayerClass; + int pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); li->SetValue(0, gameinfo.norandomplayerclass && pclass >= 0 ? pclass : pclass + 1); } } @@ -624,7 +624,7 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) li = GetItem(NAME_Gender); if (li != NULL) { - li->SetValue(0, players[consoleplayer].userinfo.gender); + li->SetValue(0, players[consoleplayer].userinfo.GetGender()); } li = GetItem(NAME_Autoaim); @@ -686,9 +686,9 @@ bool DPlayerMenu::Responder (event_t *ev) void DPlayerMenu::UpdateTranslation() { - int PlayerColor = players[consoleplayer].userinfo.color; - int PlayerSkin = players[consoleplayer].userinfo.skin; - int PlayerColorset = players[consoleplayer].userinfo.colorset; + int PlayerColor = players[consoleplayer].userinfo.GetColor(); + int PlayerSkin = players[consoleplayer].userinfo.GetSkin(); + int PlayerColorset = players[consoleplayer].userinfo.GetColorSet(); if (PlayerClass != NULL) { @@ -722,7 +722,7 @@ void DPlayerMenu::PickPlayerClass() // [GRB] Pick a class from player class list if (PlayerClasses.Size () > 1) { - pclass = players[consoleplayer].userinfo.PlayerClass; + pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); if (pclass < 0) { @@ -745,7 +745,7 @@ void DPlayerMenu::SendNewColor (int red, int green, int blue) { char command[24]; - players[consoleplayer].userinfo.color = MAKERGB(red, green, blue); + players[consoleplayer].userinfo.ColorChanged(MAKERGB(red,green,blue)); mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue); C_DoCommand (command); UpdateTranslation(); @@ -770,7 +770,7 @@ void DPlayerMenu::UpdateColorsets() FPlayerColorSet *colorset = P_GetPlayerColorSet(PlayerClass->Type->TypeName, PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } - int mycolorset = players[consoleplayer].userinfo.colorset; + int mycolorset = players[consoleplayer].userinfo.GetColorSet(); if (mycolorset != -1) { for(unsigned i=0;iType)->flags4 & MF4_NOSKIN || - players[consoleplayer].userinfo.PlayerClass == -1) + players[consoleplayer].userinfo.GetPlayerClassNum() == -1) { li->SetString(0, "Base"); li->SetValue(0, 0); @@ -814,7 +814,7 @@ void DPlayerMenu::UpdateSkins() { int j = PlayerSkins.Push(i); li->SetString(j, skins[i].name); - if (players[consoleplayer].userinfo.skin == i) + if (players[consoleplayer].userinfo.GetSkin() == i) { sel = j; } @@ -886,7 +886,7 @@ void DPlayerMenu::ColorSetChanged (FListMenuItem *li) if (blue != NULL) blue->Enable(mycolorset == -1); char command[24]; - players[consoleplayer].userinfo.colorset = mycolorset; + players[consoleplayer].userinfo.ColorSetChanged(mycolorset); mysnprintf(command, countof(command), "colorset %d", mycolorset); C_DoCommand(command); UpdateTranslation(); @@ -910,7 +910,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) if (li->GetValue(0, &sel)) { - players[consoleplayer].userinfo.PlayerClass = gameinfo.norandomplayerclass ? sel : sel-1; + players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); PickPlayerClass(); cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName)); @@ -922,7 +922,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) li = GetItem(NAME_Playerdisplay); if (li != NULL) { - li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.PlayerClass); + li->SetValue(FListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum()); } } } @@ -936,7 +936,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) void DPlayerMenu::SkinChanged (FListMenuItem *li) { if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN || - players[consoleplayer].userinfo.PlayerClass == -1) + players[consoleplayer].userinfo.GetPlayerClassNum() == -1) { return; } @@ -946,7 +946,7 @@ void DPlayerMenu::SkinChanged (FListMenuItem *li) if (li->GetValue(0, &sel)) { sel = PlayerSkins[sel]; - players[consoleplayer].userinfo.skin = sel; + players[consoleplayer].userinfo.SkinNumChanged(sel); UpdateTranslation(); cvar_set ("skin", skins[sel].name); @@ -1013,7 +1013,7 @@ bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller) case NAME_Red: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (v, GPART(color), BPART(color)); } break; @@ -1021,7 +1021,7 @@ bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller) case NAME_Green: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (RPART(color), v, BPART(color)); } break; @@ -1029,7 +1029,7 @@ bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller) case NAME_Blue: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (RPART(color), GPART(color), v); } break; @@ -1092,7 +1092,7 @@ bool DPlayerMenu::MouseEvent(int type, int x, int y) case NAME_Red: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (v, GPART(color), BPART(color)); } break; @@ -1100,7 +1100,7 @@ bool DPlayerMenu::MouseEvent(int type, int x, int y) case NAME_Green: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (RPART(color), v, BPART(color)); } break; @@ -1108,7 +1108,7 @@ bool DPlayerMenu::MouseEvent(int type, int x, int y) case NAME_Blue: if (li->GetValue(0, &v)) { - int color = players[consoleplayer].userinfo.color; + uint32 color = players[consoleplayer].userinfo.GetColor(); SendNewColor (RPART(color), GPART(color), v); } break; diff --git a/src/namedef.h b/src/namedef.h index 22b21c41c..140b18768 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -558,4 +558,12 @@ xx(Inter_Strife_Bad) xx(Inter_Strife_Lose) xx(Inter_Strife_MAP03) xx(Inter_Strife_MAP10) -xx(Multiplayer) \ No newline at end of file +xx(Multiplayer) + +// more stuff +xx(ColorSet) +xx(NeverSwitchOnPickup) +xx(MoveBob) +xx(StillBob) +xx(PlayerClass) +xx(AutoAim) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 05e9a34a2..2696863e1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5594,7 +5594,7 @@ scriptwait: } if (player) { - work += player->userinfo.netname; + work += player->userinfo.GetName(); } else if (activator) { @@ -7078,14 +7078,14 @@ scriptwait: userinfo_t *userinfo = &pl->userinfo; switch (STACK(1)) { - case PLAYERINFO_TEAM: STACK(2) = userinfo->team; break; + case PLAYERINFO_TEAM: STACK(2) = userinfo->GetTeam(); break; case PLAYERINFO_AIMDIST: STACK(2) = userinfo->GetAimDist(); break; - case PLAYERINFO_COLOR: STACK(2) = userinfo->color; break; - case PLAYERINFO_GENDER: STACK(2) = userinfo->gender; break; - case PLAYERINFO_NEVERSWITCH: STACK(2) = userinfo->neverswitch; break; - case PLAYERINFO_MOVEBOB: STACK(2) = userinfo->MoveBob; break; - case PLAYERINFO_STILLBOB: STACK(2) = userinfo->StillBob; break; - case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->PlayerClass; break; + case PLAYERINFO_COLOR: STACK(2) = userinfo->GetColor(); break; + case PLAYERINFO_GENDER: STACK(2) = userinfo->GetGender(); break; + case PLAYERINFO_NEVERSWITCH: STACK(2) = userinfo->GetNeverSwitch(); break; + case PLAYERINFO_MOVEBOB: STACK(2) = userinfo->GetMoveBob(); break; + case PLAYERINFO_STILLBOB: STACK(2) = userinfo->GetStillBob(); break; + case PLAYERINFO_PLAYERCLASS: STACK(2) = userinfo->GetPlayerClassNum(); break; case PLAYERINFO_DESIREDFOV: STACK(2) = (int)pl->DesiredFOV; break; case PLAYERINFO_FOV: STACK(2) = (int)pl->FOV; break; default: STACK(2) = 0; break; @@ -7583,7 +7583,7 @@ int P_StartScript (AActor *who, line_t *where, int script, const char *map, cons if (!(scriptdata->Flags & SCRIPTF_Net)) { Printf(PRINT_BOLD, "%s tried to puke %s (\n", - who->player->userinfo.netname, ScriptPresentation(script).GetChars()); + who->player->userinfo.GetName(), ScriptPresentation(script).GetChars()); for (int i = 0; i < argcount; ++i) { Printf(PRINT_BOLD, "%d%s", args[i], i == argcount-1 ? "" : ", "); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index a61c1b9dc..cadf5a829 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -192,7 +192,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (self->player == NULL || self->player->mo != self || !show_obituaries) return; - gender = self->player->userinfo.gender; + gender = self->player->userinfo.GetGender(); // Treat voodoo dolls as unknown deaths if (inflictor && inflictor->player && inflictor->player->mo != inflictor) @@ -274,7 +274,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf attacker->player->fragcount -= 2; attacker->player->frags[attacker->player - players]++; self = attacker; - gender = self->player->userinfo.gender; + gender = self->player->userinfo.GetGender(); mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3)); message = GStrings(gendermessage); } @@ -321,7 +321,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf } SexMessage (message, gendermessage, gender, - self->player->userinfo.netname, attacker->player->userinfo.netname); + self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); Printf (PRINT_MEDIUM, "%s\n", gendermessage); } @@ -457,8 +457,8 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (deathmatch && player->spreecount >= 5 && cl_showsprees) { SexMessage (GStrings("SPREEKILLSELF"), buff, - player->userinfo.gender, player->userinfo.netname, - player->userinfo.netname); + player->userinfo.GetGender(), player->userinfo.GetName(), + player->userinfo.GetName()); StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); } @@ -505,8 +505,8 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) { if (!AnnounceSpreeLoss (this)) { - SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.gender, - player->userinfo.netname, source->player->userinfo.netname); + SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); } @@ -515,8 +515,8 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) { if (!AnnounceSpree (source)) { - SexMessage (spreemsg, buff, player->userinfo.gender, - player->userinfo.netname, source->player->userinfo.netname); + SexMessage (spreemsg, buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); } @@ -565,8 +565,8 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (!AnnounceMultikill (source)) { - SexMessage (multimsg, buff, player->userinfo.gender, - player->userinfo.netname, source->player->userinfo.netname); + SexMessage (multimsg, buff, player->userinfo.GetGender(), + player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (new DHUDMessageFadeOut (SmallFont, buff, 1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L')); } diff --git a/src/p_map.cpp b/src/p_map.cpp index 618aa81dc..eec20019e 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3384,7 +3384,7 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p // vrange of 0 degrees, because then toppitch and bottompitch will // be equal, and PTR_AimTraverse will never find anything to shoot at // if it crosses a line. - vrange = clamp (t1->player->userinfo.aimdist, ANGLE_1/2, ANGLE_1*35); + vrange = clamp (t1->player->userinfo.GetAimDist(), ANGLE_1/2, ANGLE_1*35); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ccc454035..b885b1756 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -327,7 +327,7 @@ void AActor::Serialize (FArchive &arc) !(flags4 & MF4_NOSKIN) && state->sprite == GetDefaultByType (player->cls)->SpawnState->sprite) { // Give player back the skin - sprite = skins[player->userinfo.skin].sprite; + sprite = skins[player->userinfo.GetSkin()].sprite; } if (Speed == 0) { @@ -462,7 +462,7 @@ bool AActor::SetState (FState *newstate, bool nofunction) // spawning. if (player != NULL && skins != NULL) { - sprite = skins[player->userinfo.skin].sprite; + sprite = skins[player->userinfo.GetSkin()].sprite; } else if (newsprite != prevsprite) { @@ -910,8 +910,8 @@ bool AActor::IsVisibleToPlayer() const if ( players[consoleplayer].camera == NULL ) return true; - if ( VisibleToTeam != 0 && teamplay && - VisibleToTeam-1 != players[consoleplayer].userinfo.team ) + if (VisibleToTeam != 0 && teamplay && + VisibleToTeam-1 != players[consoleplayer].userinfo.GetTeam()) return false; const player_t* pPlayer = players[consoleplayer].camera->player; @@ -4185,7 +4185,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) } else { - type = p->userinfo.PlayerClass; + type = p->userinfo.GetPlayerClassNum(); if (type < 0) { type = pr_multiclasschoice() % PlayerClasses.Size (); @@ -4267,8 +4267,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) } // [GRB] Reset skin - p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass); - + p->userinfo.SkinNumChanged(R_FindSkin (skins[p->userinfo.GetSkin()].name, p->CurrentPlayerClass)); if (!(mobj->flags2 & MF2_DONTTRANSLATE)) { @@ -4289,7 +4288,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) // [RH] Set player sprite based on skin if (!(mobj->flags4 & MF4_NOSKIN)) { - mobj->sprite = skins[p->userinfo.skin].sprite; + mobj->sprite = skins[p->userinfo.GetSkin()].sprite; } p->DesiredFOV = p->FOV = 90.f; @@ -5736,11 +5735,10 @@ bool AActor::IsTeammate (AActor *other) int myTeam = DesignatedTeam; int otherTeam = other->DesignatedTeam; if (player) - myTeam = player->userinfo.team; + myTeam = player->userinfo.GetTeam(); if (other->player) - otherTeam = other->player->userinfo.team; - if (teamplay && myTeam != TEAM_NONE && - myTeam == otherTeam) + otherTeam = other->player->userinfo.GetTeam(); + if (teamplay && myTeam != TEAM_NONE && myTeam == otherTeam) { return true; } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 5fa41da99..a045c5098 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -91,7 +91,7 @@ void P_SerializePlayers (FArchive &arc, bool skipload) { if (playeringame[i]) { - arc.WriteString (players[i].userinfo.netname); + arc.WriteString (players[i].userinfo.GetName()); players[i].Serialize (arc); } } @@ -185,7 +185,7 @@ static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNo { for (j = 0; j < MAXPLAYERS; ++j) { - if (playerUsed[j] == 0 && stricmp(players[j].userinfo.netname, nametemp[i]) == 0) + if (playerUsed[j] == 0 && stricmp(players[j].userinfo.GetName(), nametemp[i]) == 0) { // Found a match, so copy our temp player to the real player Printf ("Found player %d (%s) at %d\n", i, nametemp[i], j); CopyPlayer (&players[j], &playertemp[i], nametemp[i]); @@ -206,7 +206,7 @@ static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNo { if (playerUsed[j] == 0) { - Printf ("Assigned player %d (%s) to %d (%s)\n", i, nametemp[i], j, players[j].userinfo.netname); + Printf ("Assigned player %d (%s) to %d (%s)\n", i, nametemp[i], j, players[j].userinfo.GetName()); CopyPlayer (&players[j], &playertemp[i], nametemp[i]); playerUsed[j] = 1; tempPlayerUsed[i] = 1; @@ -282,7 +282,7 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name) dst->userinfo = uibackup; } // Validate the skin - dst->userinfo.skin = R_FindSkin(skins[dst->userinfo.skin].name, dst->CurrentPlayerClass); + dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass)); // Make sure the player pawn points to the proper player struct. if (dst->mo != NULL) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 3eb6c422a..3a6357748 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -177,7 +177,7 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info) } if (deathmatch) { - Printf ("%s exited the level.\n", self->player->userinfo.netname); + Printf ("%s exited the level.\n", self->player->userinfo.GetName()); } return true; } diff --git a/src/p_user.cpp b/src/p_user.cpp index 0816d753b..5ac8a1a88 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -819,7 +819,7 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) { - if (!player->userinfo.neverswitch && + if (!player->userinfo.GetNeverSwitch() && player->PendingWeapon == WP_NOCHANGE && (player->ReadyWeapon == NULL || (player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))) @@ -991,10 +991,10 @@ const char *APlayerPawn::GetSoundClass() const { if (player != NULL && (player->mo == NULL || !(player->mo->flags4 &MF4_NOSKIN)) && - (unsigned int)player->userinfo.skin >= PlayerClasses.Size () && - (size_t)player->userinfo.skin < numskins) + (unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size () && + (size_t)player->userinfo.GetSkin() < numskins) { - return skins[player->userinfo.skin].name; + return skins[player->userinfo.GetSkin()].name; } // [GRB] @@ -1500,13 +1500,13 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, fixed_t &scalex, fixed_t player_t *player = actor->player; int crouchspriteno; - if (player->userinfo.skin != 0 && !(actor->flags4 & MF4_NOSKIN)) + if (player->userinfo.GetSkin() != 0 && !(actor->flags4 & MF4_NOSKIN)) { // Convert from default scale to skin scale. fixed_t defscaleY = actor->GetDefault()->scaleY; fixed_t defscaleX = actor->GetDefault()->scaleX; - scaley = Scale(scaley, skins[player->userinfo.skin].ScaleY, defscaleY); - scalex = Scale(scalex, skins[player->userinfo.skin].ScaleX, defscaleX); + scaley = Scale(scaley, skins[player->userinfo.GetSkin()].ScaleY, defscaleY); + scalex = Scale(scalex, skins[player->userinfo.GetSkin()].ScaleX, defscaleX); } // Set the crouch sprite? @@ -1517,10 +1517,10 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, fixed_t &scalex, fixed_t crouchspriteno = player->mo->crouchsprite; } else if (!(actor->flags4 & MF4_NOSKIN) && - (spritenum == skins[player->userinfo.skin].sprite || - spritenum == skins[player->userinfo.skin].crouchsprite)) + (spritenum == skins[player->userinfo.GetSkin()].sprite || + spritenum == skins[player->userinfo.GetSkin()].crouchsprite)) { - crouchspriteno = skins[player->userinfo.skin].crouchsprite; + crouchspriteno = skins[player->userinfo.GetSkin()].crouchsprite; } else { // no sprite -> squash the existing one @@ -1644,7 +1644,7 @@ void P_CalcHeight (player_t *player) } else { - player->bob = FixedMul (player->bob, player->userinfo.MoveBob); + player->bob = FixedMul (player->bob, player->userinfo.GetMoveBob()); if (player->bob > MAXBOB) player->bob = MAXBOB; @@ -1668,7 +1668,7 @@ void P_CalcHeight (player_t *player) if (player->health > 0) { angle = DivScale13 (level.time, 120*TICRATE/35) & FINEMASK; - bob = FixedMul (player->userinfo.StillBob, finesine[angle]); + bob = FixedMul (player->userinfo.GetStillBob(), finesine[angle]); } else { diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index 230689ad9..d11388e6e 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -1101,7 +1101,7 @@ void R_BuildPlayerTranslation (int player) D_GetPlayerColor (player, &h, &s, &v, &colorset); R_CreatePlayerTranslation (h, s, v, colorset, - &skins[players[player].userinfo.skin], + &skins[players[player].userinfo.GetSkin()], translationtables[TRANSLATION_Players][player], translationtables[TRANSLATION_PlayersExtra][player]); } diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 5c49d69ea..c2d567f29 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1797,7 +1797,7 @@ int S_FindSkinnedSound (AActor *actor, FSoundID refid) if (actor != NULL && actor->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { pclass = static_cast(actor)->GetSoundClass (); - if (actor->player != NULL) gender = actor->player->userinfo.gender; + if (actor->player != NULL) gender = actor->player->userinfo.GetGender(); } else { diff --git a/src/tarray.h b/src/tarray.h index 939862fc2..d32a688df 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -468,6 +468,37 @@ public: return *this; } + //======================================================================= + // + // TransferFrom + // + // Moves the contents from one TMap to another, leaving the TMap moved + // from empty. + // + //======================================================================= + + void TransferFrom(TMap &o) + { + // Clear all our nodes. + NumUsed = 0; + ClearNodeVector(); + + // Copy all of o's nodes. + Nodes = o.Nodes; + LastFree = o.LastFree; + Size = o.Size; + NumUsed = o.NumUsed; + + // Tell o it doesn't have any nodes. + o.Nodes = NULL; + o.Size = 0; + o.LastFree = NULL; + o.NumUsed = 0; + + // Leave o functional with one empty node. + o.SetNodeVector(1); + } + //======================================================================= // // Clear diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7ed85a692..5cf413693 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2877,7 +2877,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->player != NULL && - skins[self->player->userinfo.skin].othergame) + skins[self->player->userinfo.GetSkin()].othergame) { ACTION_JUMP(jump); } diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index db462c367..37b418ce9 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1655,7 +1655,7 @@ void WI_drawNetgameStats () FTexture *pic = TexMan[player->mo->ScoreIcon]; screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); } - screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.netname, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); missed_kills -= cnt_kills[i]; if (ng_state >= 4) From e130150af07860c7bce264b67653e06647e80844 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:29:28 +0000 Subject: [PATCH 319/387] - Fixed possible NULL pointer deref in AActor::Grind(). SVN r4254 (trunk) --- src/p_mobj.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b885b1756..c22430af2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1062,11 +1062,12 @@ bool AActor::Grind(bool items) gib->alpha = alpha; gib->height = 0; gib->radius = 0; + + PalEntry bloodcolor = GetBloodColor(); + if (bloodcolor != 0) + gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - - PalEntry bloodcolor = GetBloodColor(); - if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } if (flags & MF_ICECORPSE) { From c63273348a7036dfa5a48a2b428e1b958bebe5cf Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:31:36 +0000 Subject: [PATCH 320/387] - Fixed possible NULL pointer deref in A_CustomPunch SVN r4255 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 5cf413693..95fc1639e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1409,7 +1409,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (LifeSteal) P_GiveBody (self, (Damage * LifeSteal) >> FRACBITS); - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + if (weapon != NULL) + { + S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + } self->angle = R_PointToAngle2 (self->x, self->y, From e935cf9e6294c71c88088127cc15dd23d854d5cd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:34:01 +0000 Subject: [PATCH 321/387] - Fixed possible NULL pointer deref in PrintDLS(). SVN r4256 (trunk) --- src/timidity/instrum_dls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp index 0243461e6..fe5e4fdcd 100644 --- a/src/timidity/instrum_dls.cpp +++ b/src/timidity/instrum_dls.cpp @@ -992,7 +992,7 @@ void PrintDLS(DLS_Data *data) } printf("\n"); } - if ( data->waveList ) { + if ( data->waveList && data->ptbl ) { DWORD i; printf("Waves:\n"); for ( i = 0; i < data->ptbl->cCues; ++i ) { From e8d8e67b56b1214a648a89f0b6d5db26c3c2824f Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:36:03 +0000 Subject: [PATCH 322/387] - Fixed possible NULL pointer deref in P_SpawnPlayerMissile(). SVN r4257 (trunk) --- src/p_mobj.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c22430af2..a6391a71b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5634,7 +5634,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, AActor *defaultobject = GetDefaultByType(type); int vrange = nofreeaim ? ANGLE_1*35 : 0; - if (source && source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM)) + if (source == NULL) + { + return NULL; + } + if (source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM)) { // Keep exactly the same angle and pitch as the player's own aim an = angle; From 363ca592b05a06cca3736a02cd7fd73ba5bdde73 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:37:31 +0000 Subject: [PATCH 323/387] - Fixed possible memory leak in the non-Windows version of CreatePath(). SVN r4258 (trunk) --- src/cmdlib.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index c33cfdf37..557c80cf8 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -537,6 +537,7 @@ void CreatePath(const char *fn) } if (mkdir(copy, 0755) == -1) { // failed + free(copy); return; } exists: if (p != NULL) From cb7bc7e66c430496b23e3b32e78ec578565adfae Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:41:44 +0000 Subject: [PATCH 324/387] - Fixed: TAG_MINEKEY still contained the underscore character. SVN r4259 (trunk) --- wadsrc/static/language.enu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index c719e9ba3..1387bd6ff 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -998,7 +998,7 @@ 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_MINEKEY = "Mine Key"; // "New_Key4" in the Teaser TAG_NEWKEY5 = "New Key5"; TAG_ORACLEPASS = "Oracle Pass"; From 1e32e75eef9dcacfec394bc48a5e6a648defdf19 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 18:43:28 +0000 Subject: [PATCH 325/387] - Removed the music strings from the Brazilian Portuguese translations. (And apparently some whitespace changes too?) SVN r4260 (trunk) --- wadsrc/static/language.ptb | 93 ++++---------------------------------- 1 file changed, 10 insertions(+), 83 deletions(-) diff --git a/wadsrc/static/language.ptb b/wadsrc/static/language.ptb index 3fff46009..3ba7d9d2d 100644 --- a/wadsrc/static/language.ptb +++ b/wadsrc/static/language.ptb @@ -1,6 +1,6 @@ /* Português Brasileiro. Feito por Patryck Padilha de Oliveira */ -/* Não está totalmente completo */ -/* Doom está traduzido 100% */ +/* Não estEtotalmente completo */ +/* Doom estEtraduzido 100% */ /* Chex(R) Quest traduzido 100% */ /* Heretic 75% traduzido (algumas telas ainda faltam) */ /* Hexen ainda não traduzido */ @@ -22,7 +22,7 @@ QUITMSG = "deseja mesmo sair?"; TXT_YES = "Sim"; TXT_NO = "Nao"; -// Mensagens de saída DooM 1 +// Mensagens de saúa DooM 1 QUITMSG1 = "por favor, nao saia, \nprecisamos mata-los..."; QUITMSG2 = "vamo nessa, isso ja esta\nficando insuportavel!"; QUITMSG3 = "eu nao sairia se fosse voce.\nWindows e muito mais chato."; @@ -31,7 +31,7 @@ QUITMSG5 = "nao va, eu acho que vi algo\nse mexendo naquele canto!"; QUITMSG6 = "sabe, na proxima vez,\nvoce ja era."; QUITMSG7 = "va em frente, saia.\nveja se me preocupo."; -// Mensagens de saída DooM II +// Mensagens de saúa DooM II QUITMSG8 = " >sair \n >pedindo permissao para sair\n(tem certeza??)"; QUITMSG9 = "nao va agora, um \num buraco negro lhe espera\n na saida!"; QUITMSG10 = "saia daqui e volte\npara seus programas chatos."; @@ -40,7 +40,7 @@ QUITMSG12 = "OK, pode ir.\nmas pode esquecer sua pontuacao!"; QUITMSG13 = "va. \nquando voltar, estarei lhe esperando\ncom meu BFG."; QUITMSG14 = "tens sorte por nao\nlhe dar um premio por pensar\n em sair."; -// Mensagens de saída Strife +// Mensagens de saúa Strife QUITMSG15 = "aonde pensa que vai?!\n e quanto a nos?"; QUITMSG16 = "interrompendo carnificina....\n tem certeza disso?"; QUITMSG17 = "mas voce e a nossa\n unica esperanca!"; @@ -50,7 +50,7 @@ QUITMSG20 = "OK! tchau para voce tambem!"; QUITMSG21 = "pode ir.\nmas sabemos seu esconderijo..."; QUITMSG22 = "hein? pode repetir?\nvoce deseja sair?"; -// Mensagens de saída Chex +// Mensagens de saúa Chex QUITMSG23 = "Nao saia agora, precisamos\nacabar com eles!"; QUITMSG24 = "Nao desista --- porque\neles nunca desistirao!"; QUITMSG25 = "Nao va.\nPrecisamos de sua ajuda!"; @@ -131,7 +131,7 @@ BETA_BONUS2 = "Voce pegou um skullchest."; BETA_BONUS3 = "Voce pegou um cetro maligno."; BETA_BONUS4 = "Voce pegou uma biblia nao sagrada."; -// Níveis (preferi deixar original por compatibilidade) +// Nú“eis (preferi deixar original por compatibilidade) HUSTR_E1M1 = "E1M1: Hangar"; HUSTR_E1M2 = "E1M2: Nuclear Plant"; HUSTR_E1M3 = "E1M3: Toxin Refinery"; @@ -452,7 +452,7 @@ P1TEXT = P2TEXT = "Nem o labirinto mortal do Arch-Vile pode\n" "para-lo, e agora voce tem o prototipo do\n" - "Acelerador, o qual está com pouca energia\n" + "Acelerador, o qual estEcom pouca energia\n" "e logo se desativara permanentemente.\n" "\n" "Voce e bom nesse tipo de coisa."; @@ -738,7 +738,7 @@ OB_STRIDICUS = "%o foi eslameado por um stridicus."; OB_LARVA = "%o foi eslameado por uma larva."; OB_QUADRUMPUS = "%o foi eslameado por um quadrumpus."; OB_MAXIMUS = "%o foi derrotado por um Maximus."; -// Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde você o baixou +// Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde vocEo baixou _MAXIMUS = "00"; OB_FLEMMINE = "%o foi eslameado por um Flem mine."; OB_SNOTFOLUS = "%o foi derrotado pelo Lord Snotfolus."; @@ -1382,7 +1382,7 @@ TXT_STRIFEMAP = "Voce pegou o mapa."; TXT_BELDINSRING = "Voce pegou o anel."; TXT_OFFERINGCHALICE = "Voce pegou o calice de oferenda."; TXT_EAR = "Voce pegou a orelha."; -TXT_BROKENCOUPLING = "Você pegou o acoplador de energia quebrado."; +TXT_BROKENCOUPLING = "VocEpegou o acoplador de energia quebrado."; TXT_SHADOWARMOR = "Voce pegou a armadura das sombras."; TXT_ENVSUIT = "Voce pegou a roupa anti-radiacao."; TXT_GUARDUNIFORM = "Voce pegou o uniforme - Guarda."; @@ -1755,76 +1755,3 @@ OB_MPP_SPLASH = "%o foi pego pelo propulsor de %k."; OB_MPPHASEZORCH = "%o foi mega zorcheado por %k."; OB_MPLAZ_BOOM = "%o foi vitima do LAZ device de %k."; OB_MPLAZ_SPLASH = "%o foi pego pelo LAZ device de %k."; - -// Music names for Doom. These are needed in the string table only so that they can -// be replaced by Dehacked. -// Note that these names are not prefixed with 'd_' because that's how Dehacked patches -// expect them. - -MUSIC_E1M1 = "e1m1"; -MUSIC_E1M2 = "e1m2"; -MUSIC_E1M3 = "e1m3"; -MUSIC_E1M4 = "e1m4"; -MUSIC_E1M5 = "e1m5"; -MUSIC_E1M6 = "e1m6"; -MUSIC_E1M7 = "e1m7"; -MUSIC_E1M8 = "e1m8"; -MUSIC_E1M9 = "e1m9"; -MUSIC_E2M1 = "e2m1"; -MUSIC_E2M2 = "e2m2"; -MUSIC_E2M3 = "e2m3"; -MUSIC_E2M4 = "e2m4"; -MUSIC_E2M5 = "e2m5"; -MUSIC_E2M6 = "e2m6"; -MUSIC_E2M7 = "e2m7"; -MUSIC_E2M8 = "e2m8"; -MUSIC_E2M9 = "e2m9"; -MUSIC_E3M1 = "e3m1"; -MUSIC_E3M2 = "e3m2"; -MUSIC_E3M3 = "e3m3"; -MUSIC_E3M4 = "e3m4"; -MUSIC_E3M5 = "e3m5"; -MUSIC_E3M6 = "e3m6"; -MUSIC_E3M7 = "e3m7"; -MUSIC_E3M8 = "e3m8"; -MUSIC_E3M9 = "e3m9"; -MUSIC_INTER = "inter"; -MUSIC_INTRO = "intro"; -MUSIC_BUNNY = "bunny"; -MUSIC_VICTOR = "victor"; -MUSIC_INTROA = "introa"; -MUSIC_RUNNIN = "runnin"; -MUSIC_STALKS = "stalks"; -MUSIC_COUNTD = "countd"; -MUSIC_BETWEE = "betwee"; -MUSIC_DOOM = "doom"; -MUSIC_THE_DA = "the_da"; -MUSIC_SHAWN = "shawn"; -MUSIC_DDTBLU = "ddtblu"; -MUSIC_IN_CIT = "in_cit"; -MUSIC_DEAD = "dead"; -MUSIC_STLKS2 = "stlks2"; -MUSIC_THEDA2 = "theda2"; -MUSIC_DOOM2 = "doom2"; -MUSIC_DDTBL2 = "ddtbl2"; -MUSIC_RUNNI2 = "runni2"; -MUSIC_DEAD2 = "dead2"; -MUSIC_STLKS3 = "stlks3"; -MUSIC_ROMERO = "romero"; -MUSIC_SHAWN2 = "shawn2"; -MUSIC_MESSAG = "messag"; -MUSIC_COUNT2 = "count2"; -MUSIC_DDTBL3 = "ddtbl3"; -MUSIC_AMPIE = "ampie"; -MUSIC_THEDA3 = "theda3"; -MUSIC_ADRIAN = "adrian"; -MUSIC_MESSG2 = "messg2"; -MUSIC_ROMER2 = "romer2"; -MUSIC_TENSE = "tense"; -MUSIC_SHAWN3 = "shawn3"; -MUSIC_OPENIN = "openin"; -MUSIC_EVIL = "evil"; -MUSIC_ULTIMA = "ultima"; -MUSIC_READ_M = "read_m"; -MUSIC_DM2TTL = "dm2ttl"; -MUSIC_DM2INT = "dm2int"; From 0ef00cdf6edc0a096576b987f8201340743de076 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 19:02:15 +0000 Subject: [PATCH 326/387] - Fixed: Missiles with STEPMISSILE set should probably be able to bounce off the floor they step up onto. SVN r4261 (trunk) --- src/p_map.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index eec20019e..c2e067686 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1835,6 +1835,11 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y, if (thing->velz < 0) { thing->velz = 0; + // If it's a bouncer, let it bounce off its new floor, too. + if (thing->BounceFlags & BOUNCE_Floors) + { + thing->FloorBounceMissile (tm.floorsector->floorplane); + } } } } From 20d0cc717b4ba16df98425ed0e177272a8913ac0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 12 May 2013 19:05:00 +0000 Subject: [PATCH 327/387] - Fix previous fix: Don't zero the velocity when a missile steps up and bounces. SVN r4262 (trunk) --- src/p_map.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index c2e067686..7a1da4d1e 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1834,12 +1834,15 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y, // If moving down, cancel vertical component of the velocity if (thing->velz < 0) { - thing->velz = 0; // If it's a bouncer, let it bounce off its new floor, too. if (thing->BounceFlags & BOUNCE_Floors) { thing->FloorBounceMissile (tm.floorsector->floorplane); } + else + { + thing->velz = 0; + } } } } From 894c4198b09bb94d432a7c3bd67631bc7983b9ab Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 13 May 2013 02:27:39 +0000 Subject: [PATCH 328/387] - Fixed possible NULL pointer deref in A_FireBullets SVN r4263 (trunk) --- src/thingdef/thingdef_codeptr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 95fc1639e..e7b26cb49 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1247,7 +1247,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + if (weapon != NULL) + { + S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + } if ((NumberOfBullets==1 && !player->refire) || NumberOfBullets==0) { From b418f7de8d011b8e632143df3e7782f1a3b399f3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 13 May 2013 02:30:55 +0000 Subject: [PATCH 329/387] - Fixed possible NULL pointer derefs in P_LineAttack() SVN r4264 (trunk) --- src/p_map.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7a1da4d1e..224719509 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3546,9 +3546,10 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, (t1->player->ReadyWeapon->flags2 & MF2_THRUGHOST)) || (puffDefaults && (puffDefaults->flags2 & MF2_THRUGHOST)); - // if the puff uses a non-standard damage type this will override default, hitscan and melee damage type. + // if the puff uses a non-standard damage type, this will override default, hitscan and melee damage type. // All other explicitly passed damage types (currenty only MDK) will be preserved. - if ((damageType == NAME_None || damageType == NAME_Melee || damageType == NAME_Hitscan) && puffDefaults->DamageType != NAME_None) + if ((damageType == NAME_None || damageType == NAME_Melee || damageType == NAME_Hitscan) && + puffDefaults != NULL && puffDefaults->DamageType != NAME_None) { damageType = puffDefaults->DamageType; } @@ -3568,7 +3569,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, { // Play miss sound S_Sound (t1, CHAN_WEAPON, puffDefaults->ActiveSound, 1, ATTN_NORM); } - if (puffDefaults->flags3 & MF3_ALWAYSPUFF) + if (puffDefaults != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { // Spawn the puff anyway puff = P_SpawnPuff (t1, pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, puffFlags); } From 504496278b5b0d84374ec25c78dc66c9a24808ea Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 13 May 2013 02:55:48 +0000 Subject: [PATCH 330/387] - Fixed: FxBinaryInts that needed to cast the right-side parameter to an int resolved the left side instead. SVN r4265 (trunk) --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 1e4065d28..d217b9555 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1246,7 +1246,7 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) if (right->ValueType != VAL_Int) { right = new FxIntCast(right); - right = left->Resolve(ctx); + right = right->Resolve(ctx); } if (left == NULL || right == NULL) { From 6922049b83202875a3819a4377f7fc10c07e3c6d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 14 May 2013 23:34:24 +0000 Subject: [PATCH 331/387] - Redo r4259, because I guess those weren't actually whitespace changes. (Although they looked like it to me.) SVN r4266 (trunk) --- wadsrc/static/language.ptb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/wadsrc/static/language.ptb b/wadsrc/static/language.ptb index 3ba7d9d2d..2ed605078 100644 --- a/wadsrc/static/language.ptb +++ b/wadsrc/static/language.ptb @@ -1,6 +1,6 @@ /* Português Brasileiro. Feito por Patryck Padilha de Oliveira */ -/* Não estEtotalmente completo */ -/* Doom estEtraduzido 100% */ +/* Não está totalmente completo */ +/* Doom está traduzido 100% */ /* Chex(R) Quest traduzido 100% */ /* Heretic 75% traduzido (algumas telas ainda faltam) */ /* Hexen ainda não traduzido */ @@ -22,7 +22,7 @@ QUITMSG = "deseja mesmo sair?"; TXT_YES = "Sim"; TXT_NO = "Nao"; -// Mensagens de saúa DooM 1 +// Mensagens de saída DooM 1 QUITMSG1 = "por favor, nao saia, \nprecisamos mata-los..."; QUITMSG2 = "vamo nessa, isso ja esta\nficando insuportavel!"; QUITMSG3 = "eu nao sairia se fosse voce.\nWindows e muito mais chato."; @@ -31,7 +31,7 @@ QUITMSG5 = "nao va, eu acho que vi algo\nse mexendo naquele canto!"; QUITMSG6 = "sabe, na proxima vez,\nvoce ja era."; QUITMSG7 = "va em frente, saia.\nveja se me preocupo."; -// Mensagens de saúa DooM II +// Mensagens de saída DooM II QUITMSG8 = " >sair \n >pedindo permissao para sair\n(tem certeza??)"; QUITMSG9 = "nao va agora, um \num buraco negro lhe espera\n na saida!"; QUITMSG10 = "saia daqui e volte\npara seus programas chatos."; @@ -40,7 +40,7 @@ QUITMSG12 = "OK, pode ir.\nmas pode esquecer sua pontuacao!"; QUITMSG13 = "va. \nquando voltar, estarei lhe esperando\ncom meu BFG."; QUITMSG14 = "tens sorte por nao\nlhe dar um premio por pensar\n em sair."; -// Mensagens de saúa Strife +// Mensagens de saída Strife QUITMSG15 = "aonde pensa que vai?!\n e quanto a nos?"; QUITMSG16 = "interrompendo carnificina....\n tem certeza disso?"; QUITMSG17 = "mas voce e a nossa\n unica esperanca!"; @@ -50,7 +50,7 @@ QUITMSG20 = "OK! tchau para voce tambem!"; QUITMSG21 = "pode ir.\nmas sabemos seu esconderijo..."; QUITMSG22 = "hein? pode repetir?\nvoce deseja sair?"; -// Mensagens de saúa Chex +// Mensagens de saída Chex QUITMSG23 = "Nao saia agora, precisamos\nacabar com eles!"; QUITMSG24 = "Nao desista --- porque\neles nunca desistirao!"; QUITMSG25 = "Nao va.\nPrecisamos de sua ajuda!"; @@ -131,7 +131,7 @@ BETA_BONUS2 = "Voce pegou um skullchest."; BETA_BONUS3 = "Voce pegou um cetro maligno."; BETA_BONUS4 = "Voce pegou uma biblia nao sagrada."; -// Nú“eis (preferi deixar original por compatibilidade) +// Níveis (preferi deixar original por compatibilidade) HUSTR_E1M1 = "E1M1: Hangar"; HUSTR_E1M2 = "E1M2: Nuclear Plant"; HUSTR_E1M3 = "E1M3: Toxin Refinery"; @@ -452,7 +452,7 @@ P1TEXT = P2TEXT = "Nem o labirinto mortal do Arch-Vile pode\n" "para-lo, e agora voce tem o prototipo do\n" - "Acelerador, o qual estEcom pouca energia\n" + "Acelerador, o qual está com pouca energia\n" "e logo se desativara permanentemente.\n" "\n" "Voce e bom nesse tipo de coisa."; @@ -738,7 +738,7 @@ OB_STRIDICUS = "%o foi eslameado por um stridicus."; OB_LARVA = "%o foi eslameado por uma larva."; OB_QUADRUMPUS = "%o foi eslameado por um quadrumpus."; OB_MAXIMUS = "%o foi derrotado por um Maximus."; -// Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde vocEo baixou +// Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde você o baixou _MAXIMUS = "00"; OB_FLEMMINE = "%o foi eslameado por um Flem mine."; OB_SNOTFOLUS = "%o foi derrotado pelo Lord Snotfolus."; @@ -1382,7 +1382,7 @@ TXT_STRIFEMAP = "Voce pegou o mapa."; TXT_BELDINSRING = "Voce pegou o anel."; TXT_OFFERINGCHALICE = "Voce pegou o calice de oferenda."; TXT_EAR = "Voce pegou a orelha."; -TXT_BROKENCOUPLING = "VocEpegou o acoplador de energia quebrado."; +TXT_BROKENCOUPLING = "Você pegou o acoplador de energia quebrado."; TXT_SHADOWARMOR = "Voce pegou a armadura das sombras."; TXT_ENVSUIT = "Voce pegou a roupa anti-radiacao."; TXT_GUARDUNIFORM = "Voce pegou o uniforme - Guarda."; From 5b74e1acba3d436e4dbc06aab984ed87c994bc8b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 17 May 2013 00:49:45 +0000 Subject: [PATCH 332/387] - Fixed: A_Face() should use other instead of self->target when calculating pitch. SVN r4267 (trunk) --- src/p_enemy.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 70b80e7fb..81a58ac15 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2790,16 +2790,16 @@ void A_Face (AActor *self, AActor *other, angle_t max_turn, angle_t max_pitch) { // [DH] Don't need to do proper fixed->double conversion, since the // result is only used in a ratio. - double dist_x = self->target->x - self->x; - double dist_y = self->target->y - self->y; + double dist_x = other->x - self->x; + double dist_y = other->y - self->y; // Positioning ala missile spawning, 32 units above foot level fixed_t source_z = self->z + 32*FRACUNIT + self->GetBobOffset(); - fixed_t target_z = self->target->z + 32*FRACUNIT + self->target->GetBobOffset(); + fixed_t target_z = other->z + 32*FRACUNIT + other->GetBobOffset(); // If the target z is above the target's head, reposition to the middle of // its body. - if (target_z >= self->target->z + self->target->height) + if (target_z >= other->z + other->height) { - target_z = self->target->z + self->target->height / 2; + target_z = other->z + other->height / 2; } double dist_z = target_z - source_z; double dist = sqrt(dist_x*dist_x + dist_y*dist_y + dist_z*dist_z); From 4692e3f69c5d0309a4138944b449786e77f8d7e8 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 17 May 2013 01:02:43 +0000 Subject: [PATCH 333/387] - Fixed: Strife line special should have been marked repeatable. SVN r4268 (trunk) --- wadsrc/static/xlat/strife.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/xlat/strife.txt b/wadsrc/static/xlat/strife.txt index 5666fbeb6..229ac10e6 100644 --- a/wadsrc/static/xlat/strife.txt +++ b/wadsrc/static/xlat/strife.txt @@ -121,7 +121,7 @@ RetailOnly = 121 108 = WALK, Door_Raise (tag, D_FAST, VDOORWAIT) 109 = WALK, Door_Open (tag, D_FAST) 100 = WALK, Stairs_BuildUpDoom (tag, ST_TURBO, 16, 0, 0) -197 = WALK, ACS_ExecuteAlways (0, 0, 197, tag) +197 = WALK|REP, ACS_ExecuteAlways (0, 0, 197, tag) 110 = WALK, Door_Close (tag, D_FAST) 119 = WALK, Floor_RaiseToNearest (tag, F_SLOW) 121 = WALK, Plat_DownWaitUpStayLip (tag, P_TURBO, PLATWAIT, 0) From ec7f433da393f9e932eec4daee724df1bfb0f34c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 17 May 2013 01:06:47 +0000 Subject: [PATCH 334/387] - Fixed: Strife line special 200 should also be marked as repeatable. SVN r4269 (trunk) --- wadsrc/static/xlat/strife.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/xlat/strife.txt b/wadsrc/static/xlat/strife.txt index 229ac10e6..710fa1fad 100644 --- a/wadsrc/static/xlat/strife.txt +++ b/wadsrc/static/xlat/strife.txt @@ -135,7 +135,7 @@ RetailOnly = 121 179 = WALK, Ceiling_LowerToFloor (tag, C_SLOW) 187 = WALK|REP, ACS_ExecuteAlways (0, 0, 187, tag) 188 = WALK|REP, ACS_ExecuteAlways (0, 0, 188, tag) -200 = WALK, ACS_ExecuteAlways (0, 0, 200, tag) +200 = WALK|REP, ACS_ExecuteAlways (0, 0, 200, tag) 201 = WALK, SendToCommunicator (tag, 1, 0) 202 = WALK, SendToCommunicator (tag, 0, 0) 210 = WALK, SendToCommunicator (tag, 0, 1) From 71f42122bc87c5570ce116d0c233b2e1d6dbb4d2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 17 May 2013 01:22:19 +0000 Subject: [PATCH 335/387] - Added a definition for OB_MPMAULER1 and removed the needless reference to OB_MPMAULER2. SVN r4270 (trunk) --- wadsrc/static/actors/strife/strifeweapons.txt | 1 - wadsrc/static/language.enu | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/strife/strifeweapons.txt b/wadsrc/static/actors/strife/strifeweapons.txt index 5e3a419d5..deea01a52 100644 --- a/wadsrc/static/actors/strife/strifeweapons.txt +++ b/wadsrc/static/actors/strife/strifeweapons.txt @@ -534,7 +534,6 @@ ACTOR Mauler2 : Mauler Weapon.AmmoGive1 0 Weapon.AmmoType1 "EnergyPod" Weapon.SisterWeapon "Mauler" - Obituary "$OB_MPMAULER2" Tag "$TAG_MAULER2" action native A_FireMauler2Pre (); diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 1387bd6ff..79870abf0 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -806,6 +806,7 @@ 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."; +OP_MPMAULER1 = "%o was zapped by %k."; OB_MPMAULER = "%o was viciously vaporized by %k."; OB_MPSIGIL = "%o bowed down to the sheer power of %k's Sigil."; From 6ada6158ef7d521b38216619f9f97935fada560a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 17 May 2013 02:35:35 +0000 Subject: [PATCH 336/387] - Added a fallback for accented characters to use unaccented ones. - Updated Portuguese strings with the version here: http://forum.zdoom.org/viewtopic.php?p=672839#p672839 SVN r4271 (trunk) --- src/v_font.cpp | 108 +++++++++++--- wadsrc/static/language.ptb | 299 ++++++++++++++++++------------------- 2 files changed, 229 insertions(+), 178 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index eb714fb93..c7a815c7e 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -244,32 +244,69 @@ int NumTextColors; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static const BYTE myislower[256] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0 -}; - static TArray TranslationParms[2]; static TArray TranslationLookup; static TArray TranslationColors; // CODE -------------------------------------------------------------------- +static bool myislower(int code) +{ + if (code >= 'a' && code <= 'z') + return true; + if (code != 0xF7 && code != 0xFF && (code & 0xE0) == 0xE0) + return true; + return false; +} + +// Returns a character without an accent mark. +// FIXME: Only valid for CP-1252; we should go Unicode at some point. + +static int stripaccent(int code) +{ + if (code < 0x8a) + return code; + if (code == 0x8a) // Latin capital letter S with caron + return 'S'; + if (code == 0x8e) // Latin capital letter Z with caron + return 'Z'; + if (code == 0x9a) // Latin small letter S with caron + return 's'; + if (code == 0x9e) // Latin small letter Z with caron + return 'z'; + if (code == 0x9f) // Latin capital letter Y with diaeresis + return 'Y'; + if (code == 0xff) // Latin small letter Y with diaeresis + return 'y'; + // Every other accented character has the high two bits set. + if ((code & 0xC0) == 0) + return code; + // Make lowercase characters uppercase so there are half as many tests. + int acode = code & 0xDF; + if (acode >= 0xC0 && acode <= 0xC5) // A with accents + return 'A' + (code & 0x20); + if (acode == 0xC7) // Cedilla + return 'C' + (acode & 0x20); + if (acode >= 0xC8 && acode <= 0xCB) // E with accents + return 'E' + (code & 0x20); + if (acode >= 0xCC && acode <= 0xCF) // I with accents + return 'I' + (code & 0x20); + if (acode == 0xD0) // Eth + return 'D' + (code & 0x20); + if (acode == 0xD1) // N with tilde + return 'N' + (code & 0x20); + if (acode >= 0xD2 && acode <= 0xD6 || // O with accents + acode == 0xD8) // O with stroke + return 'O' + (code & 0x20); + if (acode >= 0xD9 && acode <= 0xDC) // U with accents + return 'U' + (code & 0x20); + if (acode == 0xDD) // Y with accute + return 'Y' + (code & 0x20); + if (acode == 0xDE) // Thorn + return 'P' + (code & 0x20); // well, it sort of looks like a 'P' + return code; +} + FFont *V_GetFont(const char *name) { FFont *font = FFont::FindFont (name); @@ -760,7 +797,8 @@ int FFont::GetCharCode(int code, bool needpic) const { return code; } - if (myislower[code]) + // Try converting lowercase characters to uppercase. + if (myislower(code)) { code -= 32; if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) @@ -768,6 +806,16 @@ int FFont::GetCharCode(int code, bool needpic) const return code; } } + // Try stripping accents from accented characters. + int newcode = stripaccent(code); + if (newcode != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + { + return code; + } + } return -1; } @@ -2015,8 +2063,8 @@ void FSpecialFont::LoadTranslations() // FFont :: FixXMoves // // If a font has gaps in its characters, set the missing characters' -// XMoves to either SpaceWidth or the uppercase variant's XMove. Missing -// XMoves must be initialized with INT_MIN beforehand. +// XMoves to either SpaceWidth or the unaccented or uppercase variant's +// XMove. Missing XMoves must be initialized with INT_MIN beforehand. // //========================================================================== @@ -2026,7 +2074,8 @@ void FFont::FixXMoves() { if (Chars[i].XMove == INT_MIN) { - if (myislower[i + FirstChar]) + // Try an uppercase character. + if (myislower(i + FirstChar)) { int upper = i - 32; if (upper >= 0) @@ -2035,6 +2084,17 @@ void FFont::FixXMoves() continue; } } + // Try an unnaccented character. + int noaccent = stripaccent(i + FirstChar); + if (noaccent != i + FirstChar) + { + noaccent -= FirstChar; + if (noaccent >= 0) + { + Chars[i].XMove = Chars[noaccent].XMove; + continue; + } + } Chars[i].XMove = SpaceWidth; } } diff --git a/wadsrc/static/language.ptb b/wadsrc/static/language.ptb index 2ed605078..1dc0e36c0 100644 --- a/wadsrc/static/language.ptb +++ b/wadsrc/static/language.ptb @@ -11,34 +11,34 @@ /* Versão 0.97 - 07/12/2012 */ /* No final das traduções, tentarei adicionar os outros jogos suportados pelo ZDoom */ -[ptb] +[ptb pt br] D_DEVSTR = "Modo de desenvolvimento ATIVADO.\n"; D_CDROM = "Rodando do CD/DVD-ROM: zdoom.ini em c:\\zdoomdat\n"; PRESSKEY = "aperte qualquer tecla."; -PRESSYN = "escolha Sim ou Nao"; +PRESSYN = "escolha Sim ou Não"; QUITMSG = "deseja mesmo sair?"; TXT_YES = "Sim"; -TXT_NO = "Nao"; +TXT_NO = "Não"; // Mensagens de saída DooM 1 -QUITMSG1 = "por favor, nao saia, \nprecisamos mata-los..."; -QUITMSG2 = "vamo nessa, isso ja esta\nficando insuportavel!"; -QUITMSG3 = "eu nao sairia se fosse voce.\nWindows e muito mais chato."; -QUITMSG4 = "entao voce gosta mais do windows\ndo que de mim, certo?"; -QUITMSG5 = "nao va, eu acho que vi algo\nse mexendo naquele canto!"; -QUITMSG6 = "sabe, na proxima vez,\nvoce ja era."; -QUITMSG7 = "va em frente, saia.\nveja se me preocupo."; +QUITMSG1 = "por favor, não saia, \nprecisamos matá-los..."; +QUITMSG2 = "vamo nessa, isso já está\nficando insuportável!"; +QUITMSG3 = "eu não sairia se fosse você.\nWindows é muito mais chato."; +QUITMSG4 = "então você gosta mais do windows\ndo que de mim, certo?"; +QUITMSG5 = "nao vá, eu acho que vi algo\nse mexendo naquele canto!"; +QUITMSG6 = "sabe, na próxima vez,\nvocê já era."; +QUITMSG7 = "vá em frente, saia.\nveja se me preocupo."; // Mensagens de saída DooM II -QUITMSG8 = " >sair \n >pedindo permissao para sair\n(tem certeza??)"; -QUITMSG9 = "nao va agora, um \num buraco negro lhe espera\n na saida!"; +QUITMSG8 = " >sair \n >pedindo permissão para sair\n(tem certeza??)"; +QUITMSG9 = "nao vá agora, um \nburaco negro lhe espera\n na saida!"; QUITMSG10 = "saia daqui e volte\npara seus programas chatos."; -QUITMSG11 = "se fosse seu chefe, \nvoce estaria demitido!"; -QUITMSG12 = "OK, pode ir.\nmas pode esquecer sua pontuacao!"; -QUITMSG13 = "va. \nquando voltar, estarei lhe esperando\ncom meu BFG."; -QUITMSG14 = "tens sorte por nao\nlhe dar um premio por pensar\n em sair."; +QUITMSG11 = "se fosse seu chefe, \nvocê estaria demitido!"; +QUITMSG12 = "OK, pode ir.\nmas pode esquecer sua pontuação!"; +QUITMSG13 = "vá. \nquando voltar, estarei lhe esperando\ncom meu BFG."; +QUITMSG14 = "você tem sorte por não\nlhe dar um prêmio por pensar\n em sair."; // Mensagens de saída Strife QUITMSG15 = "aonde pensa que vai?!\n e quanto a nos?"; @@ -59,55 +59,55 @@ QUITMSG27 = "Nao va.\nPrecisamos de sua ajuda!"; QUITMSG28 = "Nao nos abandone!!!"; QUITMSG29 = "O verdadeiro Chex(R) Warrior\n nunca desistiria!"; -LOADNET = "impossivel carregar, porque \n esta em partida online!\naperte uma tecla."; -QLOADNET = "impossivel carregar, porque esta online!\n\naperte uma tecla."; +LOADNET = "impossível carregar, porque \n está em partida online!\naperte uma tecla."; +QLOADNET = "impossível carregar, porque está online!\n\naperte uma tecla."; QSAVESPOT = "escolha um slot antes de fazer isso de novo.\n\naperte uma tecla."; -SAVEDEAD = "precisa estar jogando para faze-lo.\n\naperte uma tecla."; +SAVEDEAD = "precisa estar jogando para fazê-lo.\n\naperte uma tecla."; QSPROMPT = "deseja mesmo salvar aqui?\n\n'%s'\n"; QLPROMPT = "deseja carregar esse jogo?\n\n'%s'\n"; -NEWGAME = "impossivel iniciar um novo jogo\nenquanto se esta online.\n\naperte uma tecla."; +NEWGAME = "impossivel iniciar um novo jogo\nenquanto se está online.\n\naperte uma tecla."; NIGHTMARE = "tem certeza? nem eu mesmo me\nsujeito a jogar nesse modo.\n"; -SWSTRING = "essa e a versao shareware de doom.\nque contem somente o primeiro episodio.\npara continuar, compre a trilogia.\n\naperte uma tecla."; -MSGOFF = "Messagens DESATIVADO"; -MSGON = "Messagens ATIVADO"; -NETEND = "nao pode desligar esse jogo!\n\naperte uma tecla."; +SWSTRING = "essa e a versao shareware de doom.\nque contem somente o primeiro episódio.\npara continuar, compre a trilogia.\n\naperte uma tecla."; +MSGOFF = "Mensagens DESATIVADO"; +MSGON = "Mensagens ATIVADO"; +NETEND = "nâo pode desligar esse jogo!\n\naperte uma tecla."; ENDGAME = "tem certeza que deseja fechar esse jogo?\n"; DOSY = "tem certeza disso?"; EMPTYSTRING = "V A Z I O"; GOTARMOR = "Colete equipado."; GOTMEGA = "Armadura equipada."; -GOTHTHBONUS = "Pegou bonus de vida"; -GOTARMBONUS = "Pegou bonus de protecao (colete)"; +GOTHTHBONUS = "Pegou bônus de vida"; +GOTARMBONUS = "Pegou bônus de proteção (colete)"; GOTSTIM = "Pegou um kit de primeiros socorros\npequeno."; GOTMEDINEED = "Pegou um kit de primeiros socorros\n na HORA CERTA!!"; GOTMEDIKIT = "Pegou um kit de primeiros socorros\ngrande."; GOTSUPER = "Supercarga!"; GOTBLUECARD = "Achou a credencial azul."; GOTYELWCARD = "Achou a credencial amarela."; -GOTREDCARD = "Achou a credencial vermelha equipada."; -GOTBLUESKUL = "Achou o cranio azul."; -GOTYELWSKUL = "Achou o cranio amarelo."; -GOTREDSKUL = "Achou o cranio vermelho."; -GOTINVUL = "Sou invencivel (30 sec)!"; -GOTBERSERK = "Pilulas de força (30 sec)!"; +GOTREDCARD = "Achou a credencial vermelha."; +GOTBLUESKUL = "Achou o crânio azul."; +GOTYELWSKUL = "Achou o crânio amarelo."; +GOTREDSKUL = "Achou o crânio vermelho."; +GOTINVUL = "Invencibilidade (30 sec)!"; +GOTBERSERK = "Pílulas de força (30 sec)!"; GOTINVIS = "Invisibilidade (30 sec)"; -GOTSUIT = "Roupa anti-radiacao (1 min)"; -GOTMAP = "Mapa do nivel"; -GOTVISOR = "Oculos de visao noturna (1 min)"; +GOTSUIT = "Roupa anti-radiação (1 min)"; +GOTMAP = "Mapa do nível"; +GOTVISOR = "Óculos de visão noturna (1 min)"; GOTMSPHERE = "Megaesfera!"; GOTCLIP = "Pegou um clipe."; -GOTCLIPBOX = "Caixa de municao equipada."; +GOTCLIPBOX = "Caixa de munição equipada."; GOTROCKET = "Foguete equipado."; GOTROCKBOX = "Caixa de foguetes equipada."; GOTCELL = "Pack de energia(pequeno) equipada."; GOTCELLBOX = "Pack de energia(grande) equipada."; GOTSHELLS = "Cartuchos de espingarda coletada."; GOTSHELLBOX = "Caixa de cartuchos de espingarda coletada."; -GOTBACKPACK = "Mochila CHEIA de municao coletada!"; +GOTBACKPACK = "Mochila CHEIA de munição coletada!"; GOTBFG9000 = "BFG9000 equipado. Uau!"; GOTCHAINGUN = "Metralhadora equipada!"; GOTCHAINSAW = "A motoserra, enfim!"; -GOTLAUNCHER = "Lanca-foguetes equipada!"; +GOTLAUNCHER = "Lança-foguetes equipada!"; GOTPLASMA = "Metralhadora de plasma equipada!"; GOTSHOTGUN = "Espingarda equipada!"; GOTSHOTGUN2 = "Espingarda de cano duplo equipada!"; @@ -120,11 +120,11 @@ PD_YELLOWK = "Precisa de credencial amarela para ativar esta porta"; PD_BLUECO = "Precisa de credencial azul para ativar este objeto"; PD_REDCO = "Precisa de credencial vermelha para ativar este objeto"; PD_YELLOWCO = "Precisa de credencial amarela para ativar este objeto"; -PD_BLUESO = "Precisa de cranio azul para ativar este objeto"; -PD_REDSO = "Precisa de cranio vermelho para ativar este objeto"; -PD_YELLOWSO = "Precisa de cranio amarelo para ativar este objeto"; +PD_BLUESO = "Precisa de crânio azul para ativar este objeto"; +PD_REDSO = "Precisa de crânio vermelho para ativar este objeto"; +PD_YELLOWSO = "Precisa de crânio amarelo para ativar este objeto"; GGSAVED = "Jogo salvo."; -HUSTR_MSGU = "[Mensagem nao enviada]"; +HUSTR_MSGU = "[Mensagem não enviada]"; PICKUP_PISTOL_DROPPED = "Pistola equipada."; BETA_BONUS1 = "Voce pegou uma adaga demoniaca."; BETA_BONUS2 = "Voce pegou um skullchest."; @@ -268,11 +268,11 @@ THUSTR_30 = "nivel 30: last call"; THUSTR_31 = "nivel 31: pharaoh"; THUSTR_32 = "nivel 32: caribbean"; -HUSTR_TALKTOSELF1 = "Voce pensa..."; -HUSTR_TALKTOSELF2 = "Tem alguem ai?"; -HUSTR_TALKTOSELF3 = "Nao tem ninguem que possa responder"; -HUSTR_TALKTOSELF4 = "Voce esta ficando louco..."; -HUSTR_TALKTOSELF5 = "Eu juro que vi alguem..."; +HUSTR_TALKTOSELF1 = "Você pensa..."; +HUSTR_TALKTOSELF2 = "Tem alguém aí?"; +HUSTR_TALKTOSELF3 = "Não tem ninguém que possa responder"; +HUSTR_TALKTOSELF4 = "Você está ficando louco..."; +HUSTR_TALKTOSELF5 = "Eu juro que vi alguém..."; HUSTR_MESSAGESENT = "[Mensagem enviada]"; AMSTR_FOLLOWON = "Siga-me ATIVADO"; @@ -291,152 +291,152 @@ STSTR_KFAADDED = "O Pacote completo... Trapaceiro!"; STSTR_FAADDED = "Precisa de mais municao?"; STSTR_NCON = "No Clip ATIVADO"; STSTR_NCOFF = "No Clip DESATIVADO"; -STSTR_BEHOLD = "Escolha um poder:\nForca-s; invulnerabilidade-v; invisibilidade-i\nantiradiacao-r; mapa-a; oculos-l"; +STSTR_BEHOLD = "Escolha um poder:\nForça-s; invulnerabilidade-v; invisibilidade-i\nanti-radiação-r; mapa-a; óculos-l"; STSTR_BEHOLDX = "Power-up ATIVADO"; STSTR_CHOPPERS = "... nao enche."; STSTR_CLEV = "Pulando para...\n"; TXT_BUDDHAON = "Modo Buddha ATIVADO"; TXT_BUDDHAOFF = "Modo Buddha DESATIVADO"; -TXT_DEFAULTPICKUPMSG = "Voce pegou um objeto"; +TXT_DEFAULTPICKUPMSG = "Você pegou um objeto"; E1TEXT = - "Apos todo o esforco limpando \n" - "a base da lua, voce deveria ganhar um premio, \n" - "nao deveria? Hein? Cade o maravilhoso \n" + "Apos todo o esforço limpando \n" + "a base da lua, voce deveria ganhar um prêmio, \n" + "não deveria? Hein? Cadê o maravilhoso \n" "presente: voltar para casa? \n" - "Parece que este pesadelo so esta comecando. \n" + "Parece que este pesadelo só está começando. \n" "\n" - "Cheira como carne podre, mas e a base Deimos, \n" + "Cheira como carne podre, mas é a base Deimos, \n" "eu acho. Parece que estou preso no meio do \n" "Inferno... \n" "\n" - "O unico jeito de sair e passando dentro. \n" + "O único jeito de sair é passando dentro. \n" "\n" - "Para continuar, escolha o prox. episodio, \n" - "The Shores of Hell e, na sequencia, \n" + "Para continuar, escolha o prox. episódio, \n" + "The Shores of Hell e, na sequência, \n" "Inferno!\n"; E2TEXT = - "Voce conseguiu! O gigante cyber-\n" + "Você conseguiu! O gigante cyber-\n" "demon que comandava a base lunar\n" "Deimos foi morto, e voce foi o\n" "triunfante nessa batalha... E agora?\n" - "Voce olha pelo parapeito da base e\n" - "entao ve a assustadora verdade.\n" + "Você olha pelo parapeito da base e\n" + "entao vê a assustadora verdade.\n" "\n" - "A base esta flutuando em cima do\n" + "A base está flutuando em cima do\n" "que parece um portal para o inferno!\n" - "Voce nunca ouviu falar de alguem que\n" - "escapou de la, mas aqueles que voce\n" + "Você nunca ouviu falar de alguém que\n" + "escapou de lá, mas aqueles que você\n" "matou se arrependem de ter lhe conhe-\n" - "cido. Voce toma folego e comeca sua jor-\n" - "nada no ultimo episodio de DooM! \n" + "cido. Você toma fôlego e comeca sua jor-\n" + "nada no ultimo episódio de DooM! \n" " Inferno\n" "\n" " "; E3TEXT = - "O inigualavel spiderdemon que esque-\n" - "matizou a invasao na lua causou tanta\n" - "destruicao e morte que foi enfim derro-\n" + "O inigualável spiderdemon que esque-\n" + "matizou a invasão na lua causou tanta\n" + "destruição e morte que foi enfim derro-\n" "tado.\n" "\n" - "Uma passagem secreta abre e voce entra.\n" - "Voce mostrou que inferno nenhum pode\n" - "conte-lo, pelo menos agora acabou.\n" - "Agora esta na hora de voltar para a Terra,\n" + "Uma passagem secreta abre e você entra.\n" + "Você mostrou que inferno nenhum pode\n" + "contê-lo, pelo menos agora acabou.\n" + "Agora está na hora de voltar para a Terra,\n" "para enfim descansar.\n" "Lar doce lar.\n" "\n" - "Voce imagina o que aconteceu nesse\n" + "Você imagina o que aconteceu nesse\n" "meio tempo enquanto voce batalhava\n" "contra o mal. Espero que nenhum daque-\n" - "les monstros nao tenham vindo junto com\n" - "voce naquela passagem ..."; + "les monstros tenham vindo junto com\n" + "você naquela passagem ..."; E4TEXT = "O spider mastermind deve ter sido \n" - "mandado junto com sua legiao de monstros\n" + "mandado junto com sua legião de monstros\n" "para os confins do inferno depois dessa\n" - "batalha. sorte sua que voce se manteve\n" + "batalha. sorte sua que você se manteve\n" "vivo para fazer de tudo para limpar\n" "esse mundo de sofrimento de uma forma que\n" - "so um heroi poderia fazer diante de tanto mal.\n" + "só um herói poderia fazer diante de tanto mal.\n" "\n" - "alias, alguem teria que pagar pelo que\n" - "aconteceu com daisy, seu coelho de estimacao.\n" + "aliás, alguem teria que pagar pelo que\n" + "aconteceu com daisy, seu coelho de estimação.\n" "\n" - "Mas agora, voce ve o que aconteceu no\n" + "Mas agora, voce vê o que aconteceu no\n" "planeta enquanto estava fora: dor e sangue\n" - "trazido pelos demonios que estao a solta nas\n" - "cidades. agora e hora de acabar com isso!\n" - "voce recarrega sua pistola e continua seu arduo\n" + "trazido pelos demônios que estão a solta nas\n" + "cidades. agora é hora de acabar com isso!\n" + "você recarrega sua pistola e continua seu árduo\n" "trabalho: acabar com esses monstros!"; C1TEXT = - "VOCE FOI FUNDO DENTRO DO PORTO\n" - "ESTELAR, MAS ALGO ESTA ERRADO. OS\n" + "VOCÊ FOI FUNDO DENTRO DO PORTO\n" + "ESTELAR, MAS ALGO ESTÁ ERRADO. OS\n" "MONSTROS TROUXERAM SUA REALIDADE\n" "COM ELES, E A TECNOLOGIA AQUI CONTIDA\n" - "ESTA SENDO MODIFICADA COM SUA PRESENCA.\n" + "ESTÁ SENDO MODIFICADA COM SUA PRESENÇA.\n" "\n" - "ADIANTE, VOCE VE UM POSTO DE GUARDA,\n" - "UMA ZONA FORTIFICADA. SE VOCE PASSAR ALI,\n" - "PODERA ENTRAR DENTRO DO CORACAO DA\n" + "ADIANTE, VOCÊ VÊ UM POSTO DE GUARDA,\n" + "UMA ZONA FORTIFICADA. SE VOCÊ PASSAR ALI,\n" + "PODERÁ ENTRAR DENTRO DO CORAÇÃO DA\n" "BASE ESTELAR E DESATIVAR O DISPOSITIVO\n" - "QUE MANTEM O QUE SOBROU DA POPULACAO\n" - "DA TERRA REFEM."; + "QUE MANTÊM O QUE SOBROU DA POPULAÇÃO\n" + "DA TERRA REFÉM."; C2TEXT = - "VOCE CONSEGUIU! APOS ESSA VITORIA VOCE SALVA\n" - "A RACA HUMANA DA DIZIMACAO, FAZENDO COM QUE\n" - "ELES EVACUASSEM A TERRA DE VEZ. AGORA VOCE\n" - "E O UNICO HUMANO NA FACE DA TERRA.\n" - "MUTACOES CANIBAIS, ALIENS CARNIVOROS\n" - "E MAUS ESPIRITOS SAO SEUS VIZINHOS.\n" - "VOCE SENTA E ESPERA PELA MORTE, FELIZ\n" - "POR TER SALVADO A POPULACAO.\n" + "VOCÊ CONSEGUIU! APÓS ESSA VITÓRIA VOCÊ SALVA\n" + "A RAÇA HUMANA DA DIZIMACAO, FAZENDO COM QUE\n" + "ELES EVACUASSEM A TERRA DE VEZ. AGORA VOCÊ\n" + "É O ÚNICO HUMANO NA FACE DA TERRA.\n" + "MUTAÇÕES CANIBAIS, ALIENS CARNÍVOROS\n" + "E MAUS ESPÍRITOS SÃO SEUS VIZINHOS.\n" + "VOCÊ SENTA E ESPERA PELA MORTE, FELIZ\n" + "POR TER SALVADO A POPULAÇÃO.\n" "\n" - "MAS ELES MANDAM UMA MENSAGEM DO ESPACO:\n" - "\"SENSORES LOCALIZARAM O FOCO DA INVASAO\n" - "SE VOCE FOR LA, PODERA BLOQUEAR SUA ENTRADA.\n" - "A BASE ALIEN FICA NO CORACAO DE SUA CIDADE\n" - "NATAL, NAO MUITO LONGE DO PORTO ESTELAR.\" \n" - "LENTAMENTE E SENTINDO MUITA DOR, VOCE SE\n" + "MAS ELES MANDAM UMA MENSAGEM DO ESPAÇO:\n" + "\"SENSORES LOCALIZARAM O FOCO DA INVASÃO\n" + "SE VOCÊ FOR LÁ, PODERÁ BLOQUEAR SUA ENTRADA.\n" + "A BASE ALIEN FICA NO CORAÇÃO DE SUA CIDADE\n" + "NATAL, NÃO MUITO LONGE DO PORTO ESTELAR.\" \n" + "LENTAMENTE E SENTINDO MUITA DOR, VOCÊ SE\n" "LEVANTA E DECIDE CONTINUAR A LIMPEZA.\n"; C3TEXT = - "VOCE CONSEGUE CHEGAR NO CORACAO DA CIDADE,\n" - "CERCADA PELOS CADAVERES DE SEUS INIMIGOS.\n" - "VOCE NAO VE NENHUM JEITO DE DESTRUIR A ENTRADA\n" + "VOCÊ CONSEGUE CHEGAR NO CORAÇÃO DA CIDADE,\n" + "CERCADA PELOS CADÁVERES DE SEUS INIMIGOS.\n" + "VOCÊ NAO VÊ NENHUM JEITO DE DESTRUIR A ENTRADA\n" "POR ESTE LADO, ENTAO VOCE CERRA OS DENTES\n" - "E MERGULHA ATRAVES DELA.\n" + "E MERGULHA ATRAVÉS DA PASSAGEM.\n" "\n" - "DEVE HAVER UM JEITO DE FECHA-LA DO OUTRO LADO.\n" - "PRA QUE SE PREOCUPAR SE TEREI QUE ATRAVESSAR O\n" - "INFERNO PARA FECHA-LA?"; + "DEVE HAVER UM JEITO DE FECHÁ-LA DO OUTRO LADO.\n" + "PRA QUÊ SE PREOCUPAR SE TEREI QUE ATRAVESSAR O\n" + "INFERNO PARA FECHÁ-LA?"; C4TEXT = - "A HORRENDA VISTA DO MAIOR DEMONIO QUE\n" - "VOCE JA VIU DESMORONA NA SUA FRENTE\n" + "A HORRENDA VISTA DO MAIOR DEMÔNIO QUE\n" + "VOCÊ JÁ VIU DESMORONA NA SUA FRENTE\n" "DEPOIS DE VOCE LANCAR ALGUNS FOGUETES\n" - "DENTRO DE SEU CEREBRO EXPOSTO. ELE\n" + "DENTRO DE SEU CÉREBRO EXPOSTO. ELE\n" "MURCHA E MORRE, SEUS MEMBROS ESTAO\n" "DEVASTANDO MILHAS E MILHAS DA\n" - "SUPERFICIE DO INFERNO.\n" + "SUPERFÍCIE DO INFERNO.\n" "\n" - "VOCE CONSEGUIU. A INVASAO ACABOU.\n" - "A TERRA ESTA SALVA. O INFERNO DESTRUIDO.\n" - "VOCE IMAGINA PARA ONDE OS MAUS IRAO\n" - "QUANDO MORREREM AGORA. VOCE SECA O\n" - "SUOR DE SUA TESTA E COMECA A LONGA\n" + "VOCÊ CONSEGUIU. A INVASÃO ACABOU.\n" + "A TERRA ESTÁ SALVA. O INFERNO DESTRUIDO.\n" + "VOCÊ IMAGINA PARA ONDE OS MAUS IRÃO\n" + "QUANDO MORREREM AGORA. VOCÊ SECA O\n" + "SUOR DE SUA TESTA E COMEÇA A LONGA\n" "JORNADA DE VOLTA PRA CASA. E PENSA EM\n" "RECONSTRUIR A TERRA PARA SER MAIS\n" "DIVERTIDA DO QUE ANTES.\n"; C5TEXT = - "MEUS PARABENS, VOCE ACHOU O NIVEL SECRETO!\n" - "PARECE TER SIDO CONSTRUIDO POR HUNANOS,\n" - "EM VEZ DE DEMONIOS. VOCE IMAGINA O QUE\n" + "MEUS PARABÉNS, VOCÊ ACHOU O NÍVEL SECRETO!\n" + "PARECE TER SIDO CONSTRUÍDO POR HUNANOS,\n" + "EM VEZ DE DEMÔNIOS. VOCÊ IMAGINA O QUE\n" "DEVE HABITAR OS CORREDORES DESTE LUGAR.\n"; C6TEXT = - "MEUS PARABENS, DE NOVO! VOCE ACHOU\n" - "OUTRO NIVEL SECRETO. QUERO VER PASSAR\n" + "MEUS PARABÉNS, DE NOVO! VOCÊ ACHOU\n" + "OUTRO NÍVEL SECRETO. QUERO VER PASSAR\n" "ESSE AGORA!\n"; -// Plutonia and TNT intermission screens (ainda não traduzido) +// Plutonia and TNT intermission screens (50% ainda não traduzido) P1TEXT = "Voce vangloria sua vitoria em cima da carcaca\n" "do Guardiao. Apos mata-lo, voce arranca o \n" @@ -571,9 +571,9 @@ CC_HERO = "OUR HERO"; PD_BLUEC = "Precisa de uma credencial azul para abrir a porta"; PD_REDC = "Precisa de uma credencial vermelha para abrir a porta"; PD_YELLOWC = "Precisa de uma credencial amarela para abrir a porta"; -PD_BLUES = "Precisa de um cranio azul para abrir a porta"; -PD_REDS = "Precisa de um cranio vermelho para abrir a porta"; -PD_YELLOWS = "Precisa de um cranio amarelo para abrir a porta"; +PD_BLUES = "Precisa de um crânio azul para abrir a porta"; +PD_REDS = "Precisa de um crânio vermelho para abrir a porta"; +PD_YELLOWS = "Precisa de um crânio amarelo para abrir a porta"; PD_ANY = "Qualquer chave abre a porta"; PD_ANYOBJ = "Qualquer chave ativa este objeto"; PD_ALL3 = "Precisa das 3 chaves para abrir a porta"; @@ -596,23 +596,23 @@ bgflat31 = "RROCK19"; bgcastcall = "BOSSBACK"; // Mensagens de fim de partida online -TXT_FRAGLIMIT = "Pontuacao atingida."; +TXT_FRAGLIMIT = "Pontuação atingida."; TXT_TIMELIMIT = "Tempo atingido."; // Mensagens de pontos cumulativos -SPREEKILLSELF = "%o estava indo bem ate se matar!"; -SPREEOVER = "A matanca de %o foi interrompida por %k"; -SPREE5 = "%k esta indo bem!"; +SPREEKILLSELF = "%o estava indo bem até se matar!"; +SPREEOVER = "A matança de %o foi interrompida por %k"; +SPREE5 = "%k está indo bem!"; SPREE10 = "%k continua indo bem!"; -SPREE15 = "%k esta dominando!"; -SPREE20 = "%k nao se cansa por nada!"; +SPREE15 = "%k está dominando!"; +SPREE20 = "%k não se cansa por nada!"; SPREE25 = "%k parece profissional!"; // Mensagens de COMBO MULTI2 = "COMBO 2X!"; MULTI3 = "COMBO 3X!"; MULTI4 = "COMBO 4X!"; -MULTI5 = "Santa Mae do Ceu!!!"; +MULTI5 = "Santa Mãe do Céu!!!"; // Obituario // Primeiro suicidios, depois as mortes @@ -620,7 +620,7 @@ OB_SUICIDE = "%o suicidou-se."; OB_FALLING = "%o caiu."; OB_CRUSH = "%o foi esmagado."; OB_EXIT = "%o tentou sair."; -OB_WATER = "%o nao sabe nadar."; +OB_WATER = "%o não sabe nadar."; OB_SLIME = "%o se entoxicou."; OB_LAVA = "%o derreteu."; OB_BARREL = "%o explodiu."; @@ -635,7 +635,7 @@ OB_STEALTHVILE = "%o achou que viu um archvile."; OB_STEALTHBARON = "%o achou que viu um Baron of Hell."; OB_STEALTHCACO = "%o achou que viu um cacodemon."; OB_STEALTHCHAINGUY = "%o achou que viu um chaingunner."; -OB_STEALTHDEMON = "%o achou que viu um a demon."; +OB_STEALTHDEMON = "%o achou que viu um demon."; OB_STEALTHKNIGHT = "%o achou que viu um Hell Knight."; OB_STEALTHIMP = "%o achou que viu um imp."; OB_STEALTHFATSO = "%o achou que viu um mancubus."; @@ -739,17 +739,16 @@ OB_LARVA = "%o foi eslameado por uma larva."; OB_QUADRUMPUS = "%o foi eslameado por um quadrumpus."; OB_MAXIMUS = "%o foi derrotado por um Maximus."; // Existe um "You defeated a maximus" que eu não pude traduzir, se alguém souber qual a linha que traduz me diga no fórum onde você o baixou -_MAXIMUS = "00"; OB_FLEMMINE = "%o foi eslameado por um Flem mine."; OB_SNOTFOLUS = "%o foi derrotado pelo Lord Snotfolus."; -OB_MPFIST = "%k fez justica com as proprias maos, na cara de %o."; +OB_MPFIST = "%k fez justiça com as próprias mãos, na cara de %o."; OB_MPCHAINSAW = "%k usou o poder da motoserra para abrir %o."; OB_MPPISTOL = "%o foi morto pela pistola de %k."; OB_MPSHOTGUN = "%o foi morto pela espingarda de %k."; OB_MPSSHOTGUN = "%o foi morto pela espingarda de cano duplo de %k."; OB_MPCHAINGUN = "%o foi massacrado pela metralhadora de %k."; -OB_MPROCKET = "%o nao viu o foguete de %k."; +OB_MPROCKET = "%o não viu o foguete de %k."; OB_MPR_SPLASH = "%o quase escapou do foguete de %k. Quase..."; OB_MPPLASMARIFLE = "%o foi torrado pelo rifle de plasma de %k."; OB_MPBFG_BOOM = "%o foi pego pelo BFG de %k."; @@ -807,27 +806,19 @@ OB_MONTELEFRAG = "%o foi "telefragged" por um monstro."; OB_DEFAULT = "%o morreu."; OB_MPDEFAULT = "%o foi morto por %k."; -OB_FRIENDLY1 = "%k e cego."; +OB_FRIENDLY1 = "%k é cego."; OB_FRIENDLY2 = "%k pensa que sabe o que faz."; OB_FRIENDLY3 = "%k errou o tiro."; OB_FRIENDLY4 = "%k perde outro ponto."; -SAVEGAMENAME = "zdoomsv"; -STARTUP1 = ""; -STARTUP2 = ""; -STARTUP3 = ""; -STARTUP4 = ""; -STARTUP5 = ""; - - // Item tags: Doom weapons -FIST ="Soco Ingles"; +TAG_FIST ="Soco Ingles"; TAG_CHAINSAW = "Motoserra"; TAG_PISTOL = "Pistola"; TAG_SHOTGUN = "Espingarda"; TAG_SUPERSHOTGUN = "Espingarda de cano duplo"; TAG_CHAINGUN = "Metralhadora"; -TAG_ROCKETLAUNCHER = "Lanca-foguetes"; +TAG_ROCKETLAUNCHER = "Lança-foguetes"; TAG_PLASMARIFLE = "Rifle de Plasma"; TAG_BFG9000 = "O BFG 9000"; From 8af465189a06fb9c73629492950d8d1b0c184db7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 18 May 2013 15:38:10 +0000 Subject: [PATCH 337/387] - Fix broken loading of pre-r4253 savegames. SVN r4272 (trunk) --- src/d_netinfo.cpp | 5 ++--- src/namedef.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 7f90822a2..2f4d7c9b9 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -398,7 +398,6 @@ void D_SetupUserInfo () { FBaseCVar **newcvar; FName cvarname(cvar->GetName()); - ECVarType type; switch (cvarname.GetIndex()) { @@ -900,7 +899,7 @@ void D_ReadUserInfoStrings (int pnum, BYTE **stream, bool update) void ReadCompatibleUserInfo(FArchive &arc, userinfo_t &info) { - char netname[MAXPLAYERNAME]; + char netname[MAXPLAYERNAME + 1]; BYTE team; int aimdist, color, colorset, skin, gender; bool neverswitch; @@ -914,7 +913,7 @@ void ReadCompatibleUserInfo(FArchive &arc, userinfo_t &info) *static_cast(info[NAME_Name]) = netname; *static_cast(info[NAME_Team]) = team; - *static_cast(info[NAME_AutoAim]) = (float)aimdist / ANGLE_1; + *static_cast(info[NAME_Autoaim]) = (float)aimdist / ANGLE_1; *static_cast(info[NAME_Skin]) = skin; *static_cast(info[NAME_Gender]) = gender; *static_cast(info[NAME_NeverSwitchOnPickup]) = neverswitch; diff --git a/src/namedef.h b/src/namedef.h index 140b18768..44fe35e79 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -566,4 +566,3 @@ xx(NeverSwitchOnPickup) xx(MoveBob) xx(StillBob) xx(PlayerClass) -xx(AutoAim) From 1d4fbc05a5ac8bdabf1b346d4b7dbe93365f90bc Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 20 May 2013 20:39:34 +0000 Subject: [PATCH 338/387] - Fixed: glbsp nodes in a wad file inside a pk3 would not be loaded. - Fixed: Typo from r4270. SVN r4273 (trunk) --- src/p_glnodes.cpp | 41 ++++++++++++++------------------------ src/p_setup.cpp | 2 ++ wadsrc/static/language.enu | 2 +- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 48db99b67..036d999d5 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -794,17 +794,20 @@ static int FindGLNodesInWAD(int labellump) // 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 +// Function returns the lump number within the file. Returns -1 if the input +// resource file is NULL. // //=========================================================================== -static int FindGLNodesInFile(FileReader * f, const char * label) +static int FindGLNodesInFile(FResourceFile * f, const char * label) { + // No file open? Probably shouldn't happen but assume no GL nodes + if(!f) + return -1; + FString glheader; bool mustcheck=false; - DWORD id, dirofs, numentries; - DWORD offset, size; + DWORD numentries = f->LumpCount(); char lumpname[9]; glheader.Format("GL_%.8s", label); @@ -814,25 +817,17 @@ static int FindGLNodesInFile(FileReader * f, const char * label) mustcheck=true; } - f->Seek(0, SEEK_SET); - (*f) >> id >> numentries >> dirofs; - - if ((id == IWAD_ID || id == PWAD_ID) && numentries > 4) + if (numentries > 4) { - f->Seek(dirofs, SEEK_SET); for(DWORD i=0;i> offset >> size; - f->Read(lumpname, 8); - if (!strnicmp(lumpname, glheader, 8)) + if (!strnicmp(f->GetLump(i)->Name, 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); + FileReader *fr = f->GetLump(i)->GetReader(); + fr->Read(check, 16); if (MatchHeader(label, check)) return i; } else return i; @@ -902,8 +897,7 @@ bool P_LoadGLNodes(MapData * map) int li; int lumpfile = Wads.GetLumpFile(map->lumpnum); bool mapinwad = map->InWad; - FileReader * fr = map->file; - FResourceFile * f_gwa = NULL; + FResourceFile * f_gwa = map->resource; const char * name = Wads.GetWadFullName(lumpfile); @@ -933,15 +927,13 @@ bool P_LoadGLNodes(MapData * map) f_gwa = FResourceFile::OpenResourceFile(path, NULL, true); if (f_gwa==NULL) return false; - fr = f_gwa->GetReader(); - strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(map->lumpnum), 8); } } } bool result = false; - li = FindGLNodesInFile(fr, map->MapLumps[0].Name); + li = FindGLNodesInFile(f_gwa, map->MapLumps[0].Name); if (li!=-1) { static const char check[][9]={"GL_VERT","GL_SEGS","GL_SSECT","GL_NODES"}; @@ -959,11 +951,8 @@ bool P_LoadGLNodes(MapData * map) if (result) result = DoLoadGLNodes(gwalumps); } - if (f_gwa) - { - delete fr; + if (f_gwa != map->resource) delete f_gwa; - } for(unsigned int i = 0;i < 4;++i) delete gwalumps[i]; return result; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index dfabd6420..0f6917f8d 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -305,6 +305,7 @@ MapData *P_OpenMapData(const char * mapname) // This case can only happen if the lump is inside a real WAD file. // As such any special handling for other types of lumps is skipped. map->MapLumps[0].Reader = map->file = Wads.ReopenLumpNum(lump_name); + strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(lump_name), 8); map->Encrypted = Wads.IsEncryptedFile(lump_name); map->InWad = true; @@ -412,6 +413,7 @@ MapData *P_OpenMapData(const char * mapname) int index=0; map->MapLumps[0].Reader = map->resource->GetLump(0)->NewReader(); + strncpy(map->MapLumps[0].Name, map->resource->GetLump(0)->Name, 8); for(DWORD i = 1; i < map->resource->LumpCount(); i++) { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 79870abf0..0c8fff5d3 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -806,7 +806,7 @@ 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."; -OP_MPMAULER1 = "%o was zapped by %k."; +OB_MPMAULER1 = "%o was zapped by %k."; OB_MPMAULER = "%o was viciously vaporized by %k."; OB_MPSIGIL = "%o bowed down to the sheer power of %k's Sigil."; From 5007571732e2c1dba0c37636e13bcfc9c378af25 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 20 May 2013 20:47:55 +0000 Subject: [PATCH 339/387] - Fixed: Possible NULL deref in P_RailAttack. SVN r4274 (trunk) --- src/p_map.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 224719509..b9cbf3f37 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4071,24 +4071,21 @@ void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z, } } - if (trace.HitType == TRACE_HitFloor && - trace.CrossedWater == NULL && - trace.Sector->heightsec == NULL) + if(thepuff != NULL) { - if (thepuff != NULL) + if (trace.HitType == TRACE_HitFloor && + trace.CrossedWater == NULL && + trace.Sector->heightsec == NULL) { thepuff->SetOrigin(trace.X, trace.Y, trace.Z); P_HitWater (thepuff, trace.Sector); } - } - if (trace.Crossed3DWater || trace.CrossedWater) - { - if (thepuff != NULL) + if (trace.Crossed3DWater || trace.CrossedWater) { SpawnDeepSplash (source, trace, thepuff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL); } + thepuff->Destroy (); } - thepuff->Destroy (); // Draw the slug's trail. end.X = FIXED2FLOAT(trace.X); From 7fd0950ab931d9204e16b8ffdae289b65d0cde84 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Mon, 20 May 2013 21:27:50 +0000 Subject: [PATCH 340/387] - Changed the way DrawSelectedInventory is casted so that clang doesn't warn about it. SVN r4275 (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 6d0b77177..febf32b80 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -3374,7 +3374,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) case SBARINFO_DRAWSTRING: return new CommandDrawString(script); case SBARINFO_DRAWNUMBER: return new CommandDrawNumber(script); case SBARINFO_DRAWMUGSHOT: return new CommandDrawMugShot(script); - case SBARINFO_DRAWSELECTEDINVENTORY: return reinterpret_cast (new CommandDrawSelectedInventory(script)); + case SBARINFO_DRAWSELECTEDINVENTORY: return static_cast (new CommandDrawSelectedInventory(script)); case SBARINFO_DRAWSHADER: return new CommandDrawShader(script); case SBARINFO_DRAWINVENTORYBAR: return new CommandDrawInventoryBar(script); case SBARINFO_DRAWKEYBAR: return new CommandDrawKeyBar(script); From 332e39d6c88446cad5e21ea1d6100ec34f4ea55f Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 22 May 2013 21:26:06 +0000 Subject: [PATCH 341/387] - Fixed: Typo in WaterDropOnFloor actor's active sound. SVN r4276 (trunk) --- wadsrc/static/actors/strife/strifestuff.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index a80685c35..9ef147abc 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -510,7 +510,7 @@ ACTOR WaterDropOnFloor 103 Game Strife +NOBLOCKMAP ConversationID 224, -1, -1 - ActiveSound "world/waterdrips" + ActiveSound "world/waterdrip" States { Spawn: From 20b48b7c6525c9fb4440152f1f6aaa8bf532327c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 02:06:34 +0000 Subject: [PATCH 342/387] - Remove now-unused lumpname variable. SVN r4277 (trunk) --- src/p_glnodes.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 036d999d5..694c1684b 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -808,7 +808,6 @@ static int FindGLNodesInFile(FResourceFile * f, const char * label) FString glheader; bool mustcheck=false; DWORD numentries = f->LumpCount(); - char lumpname[9]; glheader.Format("GL_%.8s", label); if (glheader.Len()>8) From e271692dbbca3c517b2e97b114318e103f338291 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 03:23:44 +0000 Subject: [PATCH 343/387] - Changed C_ArchiveCVars()'s type parameter to a filter parameter, because using an arbitrary number to represent a flag combination is stupid unreadable now that there's more than just the two possibilities it had when it was first written. SVN r4278 (trunk) --- src/c_cvars.cpp | 21 +-------------------- src/c_cvars.h | 4 ++-- src/gameconfigfile.cpp | 12 ++++++------ 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index ba41f8259..9681f3ece 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1533,28 +1533,9 @@ void C_SetCVarsToDefaults (void) } } -void C_ArchiveCVars (FConfigFile *f, int type) +void C_ArchiveCVars (FConfigFile *f, uint32 filter) { - // type 0: Game-specific cvars - // type 1: Global cvars - // type 2: Unknown cvars - // type 3: Unknown global cvars - // type 4: User info cvars - // type 5: Server info cvars - static const DWORD filters[6] = - { - CVAR_ARCHIVE, - CVAR_ARCHIVE|CVAR_GLOBALCONFIG, - CVAR_ARCHIVE|CVAR_AUTO, - CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO, - CVAR_ARCHIVE|CVAR_USERINFO, - CVAR_ARCHIVE|CVAR_SERVERINFO - }; - FBaseCVar *cvar = CVars; - DWORD filter; - - filter = filters[type]; while (cvar) { diff --git a/src/c_cvars.h b/src/c_cvars.h index 98539be10..d7b767f33 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -157,7 +157,7 @@ private: friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); friend FBaseCVar *FindCVarSub (const char *var_name, int namelen); friend void UnlatchCVars (void); - friend void C_ArchiveCVars (FConfigFile *f, int type); + friend void C_ArchiveCVars (FConfigFile *f, uint32 filter); friend void C_SetCVarsToDefaults (void); friend void FilterCompactCVars (TArray &cvars, uint32 filter); friend void C_DeinitConsole(); @@ -189,7 +189,7 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags); void UnlatchCVars (void); // archive cvars to FILE f -void C_ArchiveCVars (FConfigFile *f, int type); +void C_ArchiveCVars (FConfigFile *f, uint32 filter); // initialize cvars to default values after they are created void C_SetCVarsToDefaults (void); diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 156973443..56a8a2252 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -483,12 +483,12 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strncpy (subsection, "Player", sublen); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, 4); + C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_USERINFO); strncpy (subsection, "ConsoleVariables", sublen); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, 0); + C_ArchiveCVars (this, CVAR_ARCHIVE); strncpy (subsection, netgame ? "NetServerInfo" : "LocalServerInfo", sublen); if (!netgame || consoleplayer == 0) @@ -496,13 +496,13 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) // this machine was not the initial host. SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, 5); + C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_SERVERINFO); } strncpy (subsection, "UnknownConsoleVariables", sublen); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, 2); + C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_AUTO); strncpy (subsection, "ConsoleAliases", sublen); SetSection (section, true); @@ -532,11 +532,11 @@ void FGameConfigFile::ArchiveGlobalData () SetSection ("GlobalSettings", true); ClearCurrentSection (); - C_ArchiveCVars (this, 1); + C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); SetSection ("GlobalSettings.Unknown", true); ClearCurrentSection (); - C_ArchiveCVars (this, 3); + C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO); } FString FGameConfigFile::GetConfigPath (bool tryProg) From 2767f31a92e0ae3c4b47586f0a152022b3cd776d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 May 2013 16:22:51 +0000 Subject: [PATCH 344/387] - fixed: PillarAlienPower must loop its state. SVN r4279 (trunk) --- wadsrc/static/actors/strife/strifestuff.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index 9ef147abc..d1c952ea8 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -365,7 +365,7 @@ ACTOR PillarAlienPower 227 States { Spawn: - APOW A -1 A_LoopActiveSound + APOW A 4 A_LoopActiveSound Stop } } From 787b84ef91c33d26237639e3cdd292d22a9f5468 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 16:34:23 +0000 Subject: [PATCH 345/387] - Added CVARINFO lump support. This is a lump for defining mod-specific cvars and takes entries of the form: [noarchive] [= ]; Where is one of: * server: This cvar is shared by all players, and in network games, only select players can change it. * user: Each player has their own copy of this cvar, which they can change independently. To prevent the cvar from being written to the config file, add noarchive to its definition. is one of: * int: An integral value. Defaults to 0. * float: A value that can include a fraction. Defaults to 0.0. * color: A color value. Default to black ("00 00 00"). * bool: A boolean value that can hold either true or false. Defaults to false. * string: A string value. It's not too useful for mods but is included for completeness. Defaults to "". is the cvar's name and must begin with a letter and may only include alphanumeric characters and the underscore character. If you wish a non-standard default add an = character after the cvar's name followed by the default value you want to use. Example: server int mymod_coolness = 10; - Fixed: FStringCVar::SetGenericRepDefault() did not make a copy of the input string. SVN r4280 (trunk) --- src/c_cvars.cpp | 27 +++++---- src/c_cvars.h | 2 + src/d_main.cpp | 135 ++++++++++++++++++++++++++++++++++++++++- src/d_netinfo.cpp | 20 +----- src/gameconfigfile.cpp | 64 ++++++++++++++++--- src/gameconfigfile.h | 2 + src/menu/menu.cpp | 1 + src/p_acs.cpp | 3 +- 8 files changed, 214 insertions(+), 40 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 9681f3ece..81ba01135 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -135,7 +135,7 @@ FBaseCVar::~FBaseCVar () void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) { DoSet (value, type); - if (Flags & CVAR_USERINFO) + if ((Flags & CVAR_USERINFO) && !(Flags & CVAR_NOSEND)) D_UserInfoChanged (this); if (m_UseCallback) Callback (); @@ -849,9 +849,7 @@ UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) { - if (DefaultValue) - delete[] DefaultValue; - DefaultValue = ToString (value, type); + ReplaceString(&DefaultValue, ToString(value, type)); if (Flags & CVAR_ISDEFAULT) { SetGenericRep (value, type); @@ -1277,7 +1275,7 @@ void FilterCompactCVars (TArray &cvars, DWORD filter) // Accumulate all cvars that match the filter flags. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if (cvar->Flags & filter) + if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSEND)) cvars.Push(cvar); } // Now sort them, so they're in a deterministic order and not whatever @@ -1316,7 +1314,7 @@ FString C_GetMassCVarString (DWORD filter, bool compact) { for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSAVE)) + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_NOSEND))) { UCVarValue val = cvar->GetGenericRep(CVAR_String); dump << '\\' << cvar->GetName() << '\\' << val.String; @@ -1489,6 +1487,7 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen) FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags) { assert(FindCVar(var_name, NULL) == NULL); + flags |= CVAR_AUTO; switch (var_type) { case CVAR_Bool: return new FBoolCVar(var_name, 0, flags); @@ -1540,7 +1539,7 @@ void C_ArchiveCVars (FConfigFile *f, uint32 filter) while (cvar) { if ((cvar->Flags & - (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) + (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) == filter) { UCVarValue val; @@ -1671,14 +1670,16 @@ void FBaseCVar::ListVars (const char *filter, bool plain) else { ++count; - Printf ("%c%c%c %s : :%s\n", - flags & CVAR_ARCHIVE ? 'A' : ' ', + Printf ("%c%c%c%c %s = %s\n", + flags & CVAR_ARCHIVE ? 'A' : + flags & CVAR_MODARCHIVE ? 'M' : ' ', flags & CVAR_USERINFO ? 'U' : - flags & CVAR_SERVERINFO ? 'S' : - flags & CVAR_AUTO ? 'C' : ' ', + flags & CVAR_SERVERINFO ? 'S' : + flags & CVAR_AUTO ? 'C' : ' ', flags & CVAR_NOSET ? '-' : - flags & CVAR_LATCH ? 'L' : - flags & CVAR_UNSETTABLE ? '*' : ' ', + flags & CVAR_LATCH ? 'L' : + flags & CVAR_UNSETTABLE ? '*' : ' ', + flags & CVAR_NOSEND ? 'X' : ' ', var->GetName(), var->GetGenericRep (CVAR_String).String); } diff --git a/src/c_cvars.h b/src/c_cvars.h index d7b767f33..744643d82 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -61,6 +61,8 @@ enum CVAR_GLOBALCONFIG = 1024, // cvar is saved to global config section CVAR_VIDEOCONFIG = 2048, // cvar is saved to video config section (not implemented) CVAR_NOSAVE = 4096, // when used with CVAR_SERVERINFO, do not save var to savegame + CVAR_MODARCHIVE = 8192, // cvar will be saved to a mod-specific section of the ini + CVAR_NOSEND = 16384,// do not send cvar across the network (dummy mod cvar) }; union UCVarValue diff --git a/src/d_main.cpp b/src/d_main.cpp index aa4abd366..0f66f68a6 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1358,6 +1358,136 @@ CCMD (endgame) } } +//========================================================================== +// +// ParseCVarInfo +// +//========================================================================== + +void ParseCVarInfo() +{ + int lump, lastlump = 0; + bool addedcvars = false; + + while ((lump = Wads.FindLump("CVARINFO", &lastlump)) != -1) + { + FScanner sc(lump); + sc.SetCMode(true); + + while (sc.GetToken()) + { + FString cvarname; + char *cvardefault = NULL; + ECVarType cvartype = CVAR_Dummy; + int cvarflags = CVAR_MODARCHIVE; + FBaseCVar *cvar; + + // Check for flag tokens. + while (sc.TokenType == TK_Identifier) + { + if (stricmp(sc.String, "server") == 0) + { + cvarflags |= CVAR_SERVERINFO; + } + else if (stricmp(sc.String, "user") == 0) + { + cvarflags |= CVAR_USERINFO; + } + else if (stricmp(sc.String, "noarchive") == 0) + { + cvarflags &= ~CVAR_MODARCHIVE; + } + else + { + sc.ScriptError("Unknown cvar attribute '%s'", sc.String); + } + sc.MustGetAnyToken(); + } + // Do some sanity checks. + if ((cvarflags & (CVAR_SERVERINFO|CVAR_USERINFO)) == 0 || + (cvarflags & (CVAR_SERVERINFO|CVAR_USERINFO)) == (CVAR_SERVERINFO|CVAR_USERINFO)) + { + sc.ScriptError("One of 'server' or 'user' must be specified"); + } + // The next token must be the cvar type. + if (sc.TokenType == TK_Bool) + { + cvartype = CVAR_Bool; + } + else if (sc.TokenType == TK_Int) + { + cvartype = CVAR_Int; + } + else if (sc.TokenType == TK_Float) + { + cvartype = CVAR_Float; + } + else if (sc.TokenType == TK_Color) + { + cvartype = CVAR_Color; + } + else if (sc.TokenType == TK_String) + { + cvartype = CVAR_String; + } + else + { + sc.ScriptError("Bad cvar type '%s'", sc.String); + } + // The next token must be the cvar name. + sc.MustGetToken(TK_Identifier); + if (FindCVar(sc.String, NULL) != NULL) + { + sc.ScriptError("cvar '%s' already exists", sc.String); + } + cvarname = sc.String; + // A default value is optional and signalled by a '=' token. + if (sc.CheckToken('=')) + { + switch (cvartype) + { + case CVAR_Bool: + if (!sc.CheckToken(TK_True) && !sc.CheckToken(TK_False)) + { + sc.ScriptError("Expected true or false"); + } + cvardefault = sc.String; + break; + case CVAR_Int: + sc.MustGetNumber(); + cvardefault = sc.String; + break; + case CVAR_Float: + sc.MustGetFloat(); + cvardefault = sc.String; + break; + default: + sc.MustGetString(); + cvardefault = sc.String; + break; + } + } + // Now create the cvar. + cvar = C_CreateCVar(cvarname, cvartype, cvarflags); + if (cvardefault != NULL) + { + UCVarValue val; + val.String = cvardefault; + cvar->SetGenericRepDefault(val, CVAR_String); + } + // To be like C and ACS, require a semicolon after everything. + sc.MustGetToken(';'); + addedcvars = true; + } + } + // Only load mod cvars from the config if we defined some, so we don't + // clutter up the cvar space when not playing mods with custom cvars. + if (addedcvars) + { + GameConfig->DoModSetup (gameinfo.ConfigName); + } +} + //========================================================================== // // D_AddFile @@ -2164,7 +2294,10 @@ void D_DoomMain (void) allwads.Clear(); allwads.ShrinkToFit(); SetMapxxFlag(); - + + // Now that wads are loaded, define mod-specific cvars. + ParseCVarInfo(); + // [RH] Initialize localizable strings. GStrings.LoadStrings (false); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 2f4d7c9b9..2f75d8372 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -92,22 +92,6 @@ enum const char *GenderNames[3] = { "male", "female", "other" }; -static const char *UserInfoStrings[] = -{ - "name", - "autoaim", - "color", - "skin", - "team", - "gender", - "neverswitchonpickup", - "movebob", - "stillbob", - "playerclass", - "colorset", - NULL -}; - // Replace \ with %/ and % with %% FString D_EscapeUserInfo (const char *str) { @@ -394,7 +378,7 @@ void D_SetupUserInfo () for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if (cvar->GetFlags() & CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) { FBaseCVar **newcvar; FName cvarname(cvar->GetName()); @@ -432,7 +416,7 @@ void userinfo_t::Reset() // Create userinfo vars for this player, initialized to their defaults. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if (cvar->GetFlags() & CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) { ECVarType type; FName cvarname(cvar->GetName()); diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 56a8a2252..ddb331cfa 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -86,6 +86,7 @@ FGameConfigFile::FGameConfigFile () OkayToWrite = false; // Do not allow saving of the config before DoGameSetup() bMigrating = false; + bModSetup = false; pathname = GetConfigPath (true); ChangePathName (pathname); LoadConfigFile (MigrateStub, NULL); @@ -376,8 +377,8 @@ void FGameConfigFile::DoGameSetup (const char *gamename) SetRavenDefaults (gameinfo.gametype == GAME_Hexen); } - // The NetServerInfo section will be read when it's determined that - // a netgame is being played. + // The NetServerInfo section will be read and override anything loaded + // here when it's determined that a netgame is being played. strncpy (subsection, "LocalServerInfo", sublen); if (SetSection (section)) { @@ -445,6 +446,24 @@ void FGameConfigFile::DoGameSetup (const char *gamename) OkayToWrite = true; } +// Like DoGameSetup(), but for mod-specific cvars. +// Called after CVARINFO has been parsed. +void FGameConfigFile::DoModSetup(const char *gamename) +{ + mysnprintf(section, countof(section), "%s.Player.Mod", gamename); + if (SetSection(section)) + { + ReadCVars(CVAR_MODARCHIVE|CVAR_USERINFO|CVAR_NOSEND); + } + mysnprintf(section, countof(section), "%s.LocalServerInfo.Mod", gamename); + if (SetSection (section)) + { + ReadCVars (CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + } + // Signal that these sections should be rewritten when saving the config. + bModSetup = true; +} + void FGameConfigFile::ReadNetVars () { strncpy (subsection, "NetServerInfo", sublen); @@ -452,21 +471,35 @@ void FGameConfigFile::ReadNetVars () { ReadCVars (0); } + if (bModSetup) + { + mysnprintf(subsection, sublen, "NetServerInfo.Mod"); + if (SetSection(section)) + { + ReadCVars(CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + } + } } +// Read cvars from a cvar section of the ini. Flags are the flags to give +// to newly-created cvars that were not already defined. void FGameConfigFile::ReadCVars (DWORD flags) { const char *key, *value; FBaseCVar *cvar; UCVarValue val; + if (!(flags & CVAR_MODARCHIVE)) + { + flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE; + } + flags |= CVAR_AUTO; while (NextInSection (key, value)) { cvar = FindCVar (key, NULL); if (cvar == NULL) { - cvar = new FStringCVar (key, NULL, - CVAR_AUTO|CVAR_UNSETTABLE|CVAR_ARCHIVE|flags); + cvar = new FStringCVar (key, NULL, flags); } val.String = const_cast(value); cvar->SetGenericRep (val, CVAR_String); @@ -485,18 +518,35 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) ClearCurrentSection (); C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_USERINFO); + if (bModSetup) + { + strncpy (subsection + 6, ".Mod", sublen - 6); + SetSection (section, true); + ClearCurrentSection (); + C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO); + } + strncpy (subsection, "ConsoleVariables", sublen); SetSection (section, true); ClearCurrentSection (); C_ArchiveCVars (this, CVAR_ARCHIVE); - strncpy (subsection, netgame ? "NetServerInfo" : "LocalServerInfo", sublen); + // Do not overwrite the serverinfo section if playing a netgame, and + // this machine was not the initial host. if (!netgame || consoleplayer == 0) - { // Do not overwrite this section if playing a netgame, and - // this machine was not the initial host. + { + strncpy (subsection, netgame ? "NetServerInfo" : "LocalServerInfo", sublen); SetSection (section, true); ClearCurrentSection (); C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_SERVERINFO); + + if (bModSetup) + { + strncpy (subsection, netgame ? "NetServerInfo.Mod" : "LocalServerInfo.Mod", sublen); + SetSection (section, true); + ClearCurrentSection (); + C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_SERVERINFO); + } } strncpy (subsection, "UnknownConsoleVariables", sublen); diff --git a/src/gameconfigfile.h b/src/gameconfigfile.h index 440d900da..74376b583 100644 --- a/src/gameconfigfile.h +++ b/src/gameconfigfile.h @@ -47,6 +47,7 @@ public: void DoGlobalSetup (); void DoGameSetup (const char *gamename); + void DoModSetup (const char *gamename); void ArchiveGlobalData (); void ArchiveGameData (const char *gamename); void AddAutoexec (DArgs *list, const char *gamename); @@ -65,6 +66,7 @@ private: void ReadCVars (DWORD flags); bool bMigrating; + bool bModSetup; char section[64]; char *subsection; diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 4b4b0c5e8..dc1b8ccd8 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -957,5 +957,6 @@ CCMD(reset2saved) { GameConfig->DoGlobalSetup (); GameConfig->DoGameSetup (gameinfo.ConfigName); + GameConfig->DoModSetup (gameinfo.ConfigName); R_SetViewSize (screenblocks); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2696863e1..a8469f46a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6885,7 +6885,8 @@ scriptwait: case PCD_GETCVAR: { FBaseCVar *cvar = FindCVar (FBehavior::StaticLookupString (STACK(1)), NULL); - if (cvar == NULL) + // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. + if (cvar == NULL || (cvar->GetFlags() & CVAR_NOSEND)) { STACK(1) = 0; } From 4fa198244c557804331869cfe7ca0fe428f60564 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 17:08:59 +0000 Subject: [PATCH 346/387] - Renamed CVAR_NOSEND to CVAR_IGNORE to better reflect its intent. - Separated CVAR_MODARCHIVE into CVAR_MOD|CVAR_ARCHIVE so that mod-defined cvars can still be identified when they aren't meant to be archived. SVN r4281 (trunk) --- src/c_cvars.cpp | 16 ++++++++-------- src/c_cvars.h | 4 ++-- src/d_main.cpp | 4 ++-- src/d_netinfo.cpp | 4 ++-- src/gameconfigfile.cpp | 16 ++++++---------- src/p_acs.cpp | 2 +- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 81ba01135..72335f1f6 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -135,7 +135,7 @@ FBaseCVar::~FBaseCVar () void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) { DoSet (value, type); - if ((Flags & CVAR_USERINFO) && !(Flags & CVAR_NOSEND)) + if ((Flags & CVAR_USERINFO) && !(Flags & CVAR_IGNORE)) D_UserInfoChanged (this); if (m_UseCallback) Callback (); @@ -1275,7 +1275,7 @@ void FilterCompactCVars (TArray &cvars, DWORD filter) // Accumulate all cvars that match the filter flags. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSEND)) + if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE)) cvars.Push(cvar); } // Now sort them, so they're in a deterministic order and not whatever @@ -1314,7 +1314,7 @@ FString C_GetMassCVarString (DWORD filter, bool compact) { for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_NOSEND))) + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE))) { UCVarValue val = cvar->GetGenericRep(CVAR_String); dump << '\\' << cvar->GetName() << '\\' << val.String; @@ -1539,7 +1539,7 @@ void C_ArchiveCVars (FConfigFile *f, uint32 filter) while (cvar) { if ((cvar->Flags & - (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) + (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) == filter) { UCVarValue val; @@ -1670,16 +1670,16 @@ void FBaseCVar::ListVars (const char *filter, bool plain) else { ++count; - Printf ("%c%c%c%c %s = %s\n", - flags & CVAR_ARCHIVE ? 'A' : - flags & CVAR_MODARCHIVE ? 'M' : ' ', + Printf ("%c%c%c%c%c %s = %s\n", + flags & CVAR_ARCHIVE ? 'A' : ' ', flags & CVAR_USERINFO ? 'U' : flags & CVAR_SERVERINFO ? 'S' : flags & CVAR_AUTO ? 'C' : ' ', flags & CVAR_NOSET ? '-' : flags & CVAR_LATCH ? 'L' : flags & CVAR_UNSETTABLE ? '*' : ' ', - flags & CVAR_NOSEND ? 'X' : ' ', + flags & CVAR_MOD ? 'M' : ' ', + flags & CVAR_IGNORE ? 'X' : ' ', var->GetName(), var->GetGenericRep (CVAR_String).String); } diff --git a/src/c_cvars.h b/src/c_cvars.h index 744643d82..e6b7388c2 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -61,8 +61,8 @@ enum CVAR_GLOBALCONFIG = 1024, // cvar is saved to global config section CVAR_VIDEOCONFIG = 2048, // cvar is saved to video config section (not implemented) CVAR_NOSAVE = 4096, // when used with CVAR_SERVERINFO, do not save var to savegame - CVAR_MODARCHIVE = 8192, // cvar will be saved to a mod-specific section of the ini - CVAR_NOSEND = 16384,// do not send cvar across the network (dummy mod cvar) + CVAR_MOD = 8192, // cvar was defined by a mod + CVAR_IGNORE = 16384,// do not send cvar across the network/inaccesible from ACS (dummy mod cvar) }; union UCVarValue diff --git a/src/d_main.cpp b/src/d_main.cpp index 0f66f68a6..6c92babe4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1379,7 +1379,7 @@ void ParseCVarInfo() FString cvarname; char *cvardefault = NULL; ECVarType cvartype = CVAR_Dummy; - int cvarflags = CVAR_MODARCHIVE; + int cvarflags = CVAR_MOD|CVAR_ARCHIVE; FBaseCVar *cvar; // Check for flag tokens. @@ -1395,7 +1395,7 @@ void ParseCVarInfo() } else if (stricmp(sc.String, "noarchive") == 0) { - cvarflags &= ~CVAR_MODARCHIVE; + cvarflags &= ~CVAR_ARCHIVE; } else { diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 2f75d8372..6b89efc22 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -378,7 +378,7 @@ void D_SetupUserInfo () for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { FBaseCVar **newcvar; FName cvarname(cvar->GetName()); @@ -416,7 +416,7 @@ void userinfo_t::Reset() // Create userinfo vars for this player, initialized to their defaults. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { ECVarType type; FName cvarname(cvar->GetName()); diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index ddb331cfa..2b97bf4bd 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -453,12 +453,12 @@ void FGameConfigFile::DoModSetup(const char *gamename) mysnprintf(section, countof(section), "%s.Player.Mod", gamename); if (SetSection(section)) { - ReadCVars(CVAR_MODARCHIVE|CVAR_USERINFO|CVAR_NOSEND); + ReadCVars(CVAR_MOD|CVAR_USERINFO|CVAR_IGNORE); } mysnprintf(section, countof(section), "%s.LocalServerInfo.Mod", gamename); if (SetSection (section)) { - ReadCVars (CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + ReadCVars (CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE); } // Signal that these sections should be rewritten when saving the config. bModSetup = true; @@ -476,7 +476,7 @@ void FGameConfigFile::ReadNetVars () mysnprintf(subsection, sublen, "NetServerInfo.Mod"); if (SetSection(section)) { - ReadCVars(CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + ReadCVars(CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE); } } } @@ -489,11 +489,7 @@ void FGameConfigFile::ReadCVars (DWORD flags) FBaseCVar *cvar; UCVarValue val; - if (!(flags & CVAR_MODARCHIVE)) - { - flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE; - } - flags |= CVAR_AUTO; + flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE|CVAR_AUTO; while (NextInSection (key, value)) { cvar = FindCVar (key, NULL); @@ -523,7 +519,7 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strncpy (subsection + 6, ".Mod", sublen - 6); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO); + C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO); } strncpy (subsection, "ConsoleVariables", sublen); @@ -545,7 +541,7 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strncpy (subsection, netgame ? "NetServerInfo.Mod" : "LocalServerInfo.Mod", sublen); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_SERVERINFO); + C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_SERVERINFO); } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a8469f46a..42e2cfec8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -6886,7 +6886,7 @@ scriptwait: { FBaseCVar *cvar = FindCVar (FBehavior::StaticLookupString (STACK(1)), NULL); // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. - if (cvar == NULL || (cvar->GetFlags() & CVAR_NOSEND)) + if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE)) { STACK(1) = 0; } From 567fbace2255abeda2037aae217afe82c8aabd83 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 May 2013 18:30:23 +0000 Subject: [PATCH 347/387] - re-fixed r4279. SVN r4282 (trunk) --- wadsrc/static/actors/strife/strifestuff.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index d1c952ea8..b0f4024f4 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -366,7 +366,7 @@ ACTOR PillarAlienPower 227 { Spawn: APOW A 4 A_LoopActiveSound - Stop + Loop } } From 167ee9e7fbbf76cac05bb3afcea2c492333436a5 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 19:08:05 +0000 Subject: [PATCH 348/387] - Added three new ACS functions: * int GetUserCVar(int playernum, "cvarname") * bool SetCVar("cvarname", newvalue) * bool SetUserCVar(int playernum, "cvarname", newvalue) GetUserCVar is analogous to GetCVar, except it returns the value of a user cvar for a specific player. (All user cvars can be examined using the playerinfo console command.) SetCVar sets a cvar to a new value. If the cvar is floating point, then newvalue is treated as a fixed point number, otherwise it's treated as an integer. SetUserCVar is the same, but for a specific player's user cvar. SetCVar and SetUserCVar can only change cvars created via CVARINFO. They cannot alter built-in cvars. If you use GetCVar or SetCVar with a user cvar, they will act on the copy of the user cvar for the player who activated the script. e.g. GetCVar("gender") is the same as GetUserCVar(PlayerNumber(), "gender") If you get the value of a floating point cvar, it will be returned as a fixed point number. Otherwise, it will be returned as an integer. SVN r4283 (trunk) --- src/c_cvars.cpp | 4 +- src/c_cvars.h | 2 +- src/d_netinfo.cpp | 2 +- src/p_acs.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 168 insertions(+), 17 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 72335f1f6..308d53613 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -132,10 +132,10 @@ FBaseCVar::~FBaseCVar () } } -void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) +void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend) { DoSet (value, type); - if ((Flags & CVAR_USERINFO) && !(Flags & CVAR_IGNORE)) + if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE)) D_UserInfoChanged (this); if (m_UseCallback) Callback (); diff --git a/src/c_cvars.h b/src/c_cvars.h index e6b7388c2..f1bf254b9 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -101,7 +101,7 @@ public: inline FBaseCVar *GetNext() const { return m_Next; } void CmdSet (const char *newval); - void ForceSet (UCVarValue value, ECVarType type); + void ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend=false); void SetGenericRep (UCVarValue value, ECVarType type); void ResetToDefault (); void SetArchiveBit () { Flags |= CVAR_ARCHIVE; } diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6b89efc22..7f94ef686 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -430,7 +430,7 @@ void userinfo_t::Reset() case NAME_PlayerClass: type = CVAR_Int; break; default: type = cvar->GetRealType(); break; } - newcvar = C_CreateCVar(NULL, type, 0); + newcvar = C_CreateCVar(NULL, type, cvar->GetFlags() & CVAR_MOD); newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String); Insert(cvarname, newcvar); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 42e2cfec8..f251ab2e7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3474,6 +3474,9 @@ enum EACSFunctions ACSF_VectorLength, ACSF_SetHUDClipRect, ACSF_SetHUDWrapWidth, + ACSF_SetCVar, + ACSF_GetUserCVar, + ACSF_SetUserCVar, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -3573,6 +3576,145 @@ static int GetUserVariable(AActor *self, FName varname, int index) return 0; } +// Converts fixed- to floating-point as required. +static void DoSetCVar(FBaseCVar *cvar, int value, bool force=false) +{ + UCVarValue val; + ECVarType type; + + // For serverinfo variables, only the arbitrator should set it. + // The actual change to this cvar will not show up until it's + // been replicated to all peers. + if ((cvar->GetFlags() & CVAR_SERVERINFO) && consoleplayer != Net_Arbitrator) + { + return; + } + if (cvar->GetRealType() == CVAR_Float) + { + val.Float = FIXED2FLOAT(value); + type = CVAR_Float; + } + else + { + val.Int = value; + type = CVAR_Int; + } + if (force) + { + cvar->ForceSet(val, type, true); + } + else + { + cvar->SetGenericRep(val, type); + } +} + +// Converts floating- to fixed-point as required. +static int DoGetCVar(FBaseCVar *cvar) +{ + UCVarValue val; + + if (cvar->GetRealType() == CVAR_Float) + { + val = cvar->GetGenericRep(CVAR_Float); + return FLOAT2FIXED(val.Float); + } + else + { + val = cvar->GetGenericRep(CVAR_Int); + return val.Int; + } +} + +static int GetUserCVar(int playernum, const char *cvarname) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return 0; + } + FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar *cvar; + if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE)) + { + return 0; + } + return DoGetCVar(cvar); +} + +static int GetCVar(AActor *activator, const char *cvarname) +{ + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. + if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE)) + { + return 0; + } + else + { + // For userinfo cvars, redirect to GetUserCVar + if (cvar->GetFlags() & CVAR_USERINFO) + { + if (activator == NULL || activator->player == NULL) + { + return 0; + } + return GetUserCVar(int(activator->player - players), cvarname); + } + return DoGetCVar(cvar); + } +} + +static int SetUserCVar(int playernum, const char *cvarname, int value) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return 0; + } + FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar *cvar; + // Only mod-created cvars may be set. + if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE) || !(cvar->GetFlags() & CVAR_MOD)) + { + return 0; + } + DoSetCVar(cvar, value); + + // If we are this player, then also reflect this change in the local version of this cvar. + if (playernum == consoleplayer) + { + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // If we can find it in the userinfo, then we should also be able to find it in the normal cvar list, + // but check just to be safe. + if (cvar != NULL) + { + DoSetCVar(cvar, value, true); + } + } + + return 1; +} + +static int SetCVar(AActor *activator, const char *cvarname, int value) +{ + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // Only mod-created cvars may be set. + if (cvar == NULL || (cvar->GetFlags() & (CVAR_IGNORE|CVAR_NOSET)) || !(cvar->GetFlags() & CVAR_MOD)) + { + return 0; + } + // For userinfo cvars, redirect to SetUserCVar + if (cvar->GetFlags() & CVAR_USERINFO) + { + if (activator == NULL || activator->player == NULL) + { + return 0; + } + return SetUserCVar(int(activator->player - players), cvarname, value); + } + DoSetCVar(cvar, value); + return 1; +} + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) { AActor *actor; @@ -4017,6 +4159,27 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) WrapWidth = argCount > 0 ? args[0] : 0; break; + case ACSF_GetUserCVar: + if (argCount == 2) + { + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])); + } + break; + + case ACSF_SetUserCVar: + if (argCount == 3) + { + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2]); + } + break; + + case ACSF_SetCVar: + if (argCount == 2) + { + return SetCVar(activator, FBehavior::StaticLookupString(args[0]), args[1]); + } + break; + default: break; } @@ -6883,19 +7046,7 @@ scriptwait: break; case PCD_GETCVAR: - { - FBaseCVar *cvar = FindCVar (FBehavior::StaticLookupString (STACK(1)), NULL); - // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. - if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE)) - { - STACK(1) = 0; - } - else - { - UCVarValue val = cvar->GetGenericRep (CVAR_Int); - STACK(1) = val.Int; - } - } + STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1))); break; case PCD_SETHUDSIZE: From 78437d917c37e4a18a294294f53422aa116a4b83 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 25 May 2013 22:01:26 +0000 Subject: [PATCH 349/387] - Added edward850's patch to cope with stalled network games. SVN r4285 (trunk) --- src/d_net.cpp | 40 ++++++++++++++++++++++++++++++++++++ src/d_player.h | 1 + src/g_shared/sbar.h | 1 + src/g_shared/shared_sbar.cpp | 34 ++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/src/d_net.cpp b/src/d_net.cpp index 902d912bb..0ea8e58c5 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -108,6 +108,8 @@ int resendcount[MAXNETNODES]; unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings unsigned int currrecvtime[MAXPLAYERS]; +unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved. +bool hadlate; int nodeforplayer[MAXPLAYERS]; int playerfornode[MAXNETNODES]; @@ -311,6 +313,8 @@ void Net_ClearBuffers () oldentertics = entertic; gametic = 0; maketic = 0; + + lastglobalrecvtime = 0; } // @@ -700,6 +704,8 @@ void GetPackets (void) } continue; // extra setup packet } + + lastglobalrecvtime = I_GetTime (false); //Update the last time a packet was recieved netnode = doomcom.remotenode; netconsole = playerfornode[netnode] & ~PL_DRONE; @@ -1820,6 +1826,33 @@ void TryRunTics (void) if (lowtic < gametic) I_Error ("TryRunTics: lowtic < gametic"); + // [Ed850] Check to see the last time a packet was recieved. + // If it's longer then 3 seconds, a node has likely stalled. Check which one and re-request its last packet. + if(I_GetTime(false) - lastglobalrecvtime >= TICRATE*3) + { + int latenode = 0; // Node 0 is the local player, and should always be the highest + lastglobalrecvtime = I_GetTime(false); //Bump the count + + if(NetMode == NET_PeerToPeer || consoleplayer == Net_Arbitrator) + { + for (i = 0; i < doomcom.numnodes; i++) + if (nodeingame[i] && nettics[i] < nettics[latenode]) + latenode = i; + } + else if (nodeingame[nodeforplayer[Net_Arbitrator]] && + nettics[nodeforplayer[Net_Arbitrator]] < nettics[0]) + { // Likely a packet server game. Only check the packet host. + latenode = Net_Arbitrator; + } + + if (debugfile) + fprintf (debugfile, "lost tics from %i (%i to %i)\n", + latenode, nettics[latenode], gametic); + + if(latenode != 0) // Send resend request to late node (if not yourself... somehow). Also mark the node as waiting to display it in the hud. + remoteresend[latenode] = players[playerfornode[latenode]].waiting = hadlate = true; + } + // don't stay in here forever -- give the menu a chance to work if (I_GetTime (false) - entertic >= TICRATE/3) { @@ -1829,6 +1862,13 @@ void TryRunTics (void) } } + if (hadlate) + { + hadlate = false; + for (i = 0; i < MAXPLAYERS; i++) + players[i].waiting = false; + } + // run the count tics if (counts > 0) { diff --git a/src/d_player.h b/src/d_player.h index e8c183141..6169dcebf 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -404,6 +404,7 @@ public: int timefreezer; // Player has an active time freezer short refire; // refired shots are less accurate short inconsistant; + bool waiting; int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing int hazardcount; // for delayed Strife damage diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 230e457d8..3d8c62001 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -424,6 +424,7 @@ private: bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const; void DrawMessages (int layer, int bottom); void DrawConsistancy () const; + void DrawWaiting () const; TObjPtr Messages[NUM_HUDMSGLAYERS]; bool ShowLog; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index fd543f194..0ceea11a0 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1511,6 +1511,7 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) } DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT); DrawConsistancy (); + DrawWaiting (); if (ShowLog && MustDrawLog(state)) DrawLog (); if (noisedebug) @@ -1612,6 +1613,39 @@ void DBaseStatusBar::DrawConsistancy () const } } +void DBaseStatusBar::DrawWaiting () const +{ + int i; + char conbuff[64], *buff_p; + + if (!netgame) + return; + + buff_p = NULL; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].waiting) + { + if (buff_p == NULL) + { + strcpy (conbuff, "Waiting for:"); + buff_p = conbuff + 12; + } + *buff_p++ = ' '; + *buff_p++ = '1' + i; + *buff_p = 0; + } + } + + if (buff_p != NULL) + { + screen->DrawText (SmallFont, CR_ORANGE, + (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2, + SmallFont->GetHeight()*CleanYfac, conbuff, DTA_CleanNoMove, true, TAG_DONE); + BorderTopRefresh = screen->GetPageCount (); + } +} + void DBaseStatusBar::FlashItem (const PClass *itemtype) { } From ce28c9c99179d033b945d520474b5a6c341a55bb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 26 May 2013 00:53:48 +0000 Subject: [PATCH 350/387] - Added parentheses for clarity. SVN r4286 (trunk) --- src/v_font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index c7a815c7e..0d88a47df 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -295,7 +295,7 @@ static int stripaccent(int code) return 'D' + (code & 0x20); if (acode == 0xD1) // N with tilde return 'N' + (code & 0x20); - if (acode >= 0xD2 && acode <= 0xD6 || // O with accents + if ((acode >= 0xD2 && acode <= 0xD6) || // O with accents acode == 0xD8) // O with stroke return 'O' + (code & 0x20); if (acode >= 0xD9 && acode <= 0xDC) // U with accents From 17c7c32a5828871dfcc01cd3b3c9be6a72c669d4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 26 May 2013 02:56:25 +0000 Subject: [PATCH 351/387] - Fixed potential uninitialized access in FMapInfoParser::ParseEndGame(). SVN r4287 (trunk) --- src/intermission/intermission_parse.cpp | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index d621d4c6c..6166e608f 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -660,7 +660,7 @@ FName FMapInfoParser::ParseEndGame() } } FIntermissionDescriptor *desc = new FIntermissionDescriptor; - FIntermissionAction *action; + FIntermissionAction *action = NULL; switch (newSeq.EndType) { @@ -699,15 +699,23 @@ FName FMapInfoParser::ParseEndGame() break; } - action->mBackground = newSeq.PicName; - action->mMusic = newSeq.Music; - action->mMusicLooping = newSeq.MusicLooping; - desc->mActions.Push(action); + if (action == NULL) + { + sc.ScriptError("Endgame type was not defined"); + return NAME_None; // We won't really get here. + } + else + { + action->mBackground = newSeq.PicName; + action->mMusic = newSeq.Music; + action->mMusicLooping = newSeq.MusicLooping; + desc->mActions.Push(action); - FString seq; - seq.Format("@EndSequence_%d_", generated++); - ReplaceIntermission(seq, desc); - return FName(seq); + FString seq; + seq.Format("@EndSequence_%d_", generated++); + ReplaceIntermission(seq, desc); + return FName(seq); + } } //========================================================================== From dabd48ab813318ccbdb190a4cf7e770aa7da3528 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 26 May 2013 04:03:47 +0000 Subject: [PATCH 352/387] - Fixed: 4, 2, and 1 bit grayscale images weren't properly supported. - Fixed: Valgrind uninitialized memory error and a signed/unsigned warning. SVN r4288 (trunk) --- src/p_mobj.cpp | 2 +- src/textures/pngtexture.cpp | 24 ++++++++++++++++++++---- src/textures/texture.cpp | 16 ++++++++++++++++ src/textures/textures.h | 3 +++ src/v_font.cpp | 1 + 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a6391a71b..e70f3cc0a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -911,7 +911,7 @@ bool AActor::IsVisibleToPlayer() const return true; if (VisibleToTeam != 0 && teamplay && - VisibleToTeam-1 != players[consoleplayer].userinfo.GetTeam()) + (signed)(VisibleToTeam-1) != players[consoleplayer].userinfo.GetTeam()) return false; const player_t* pPlayer = players[consoleplayer].camera->player; diff --git a/src/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index 7927c0a93..8120df968 100644 --- a/src/textures/pngtexture.cpp +++ b/src/textures/pngtexture.cpp @@ -297,17 +297,33 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename case 0: // Grayscale if (!bAlphaTexture) { + BYTE *GrayMapSrc; + switch(BitDepth) + { + default: + GrayMapSrc = GrayMap; + break; + case 4: + GrayMapSrc = GrayMap4bit; + break; + case 2: + GrayMapSrc = GrayMap2bit; + break; + case 1: + GrayMapSrc = GrayMap1bit; + break; + } if (colortype == 0 && havetRNS && trans[0] != 0) { bMasked = true; - PaletteSize = 256; - PaletteMap = new BYTE[256]; - memcpy (PaletteMap, GrayMap, 256); + PaletteSize = 1< Date: Sun, 26 May 2013 04:56:52 +0000 Subject: [PATCH 353/387] - Just remembered that the true color stuff generates textures differently. Changed the previous commit to expand 1, 2, and 4 bit grayscale images while reading the PNG instead of changing the palette. SVN r4289 (trunk) --- src/m_png.cpp | 30 ++++++++++++++++++++++++++---- src/textures/pngtexture.cpp | 24 ++++-------------------- src/textures/texture.cpp | 16 ---------------- src/textures/textures.h | 3 --- 4 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/m_png.cpp b/src/m_png.cpp index dd2e46970..1e1a331af 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -103,7 +103,7 @@ static inline void MakeChunk (void *where, DWORD type, size_t len); static inline void StuffPalette (const PalEntry *from, BYTE *to); static bool WriteIDAT (FILE *file, const BYTE *data, int len); static void UnfilterRow (int width, BYTE *dest, BYTE *stream, BYTE *prev, int bpp); -static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout); +static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout, bool grayscale); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- @@ -604,7 +604,7 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc in = prev; if (bitdepth < 8) { - UnpackPixels (passwidth, bytesPerRowIn, bitdepth, in, adam7buff[2]); + UnpackPixels (passwidth, bytesPerRowIn, bitdepth, in, adam7buff[2], colortype == 0); in = adam7buff[2]; } // Distribute pixels into the output buffer @@ -688,7 +688,7 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc passpitch = pitch << interlace; for (curr = buffer + pitch * interlace; curr <= prev; curr += passpitch) { - UnpackPixels (width, bytesPerRowIn, bitdepth, curr, curr); + UnpackPixels (width, bytesPerRowIn, bitdepth, curr, curr, colortype == 0); } } return true; @@ -1155,7 +1155,7 @@ void UnfilterRow (int width, BYTE *dest, BYTE *row, BYTE *prev, int bpp) // //========================================================================== -static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout) +static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout, bool grayscale) { const BYTE *in; BYTE *out; @@ -1242,4 +1242,26 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE * } break; } + + // Expand gray scale to 8bpp + if(grayscale) + { + out = rowout + width; + while(--out >= rowout) + { + switch(bitdepth) + { + case 1: + *out *= 0xFF; + break; + case 2: + *out |= (*out<<2)|(*out<<4)|(*out<<6); + break; + case 4: + *out |= (*out<<4); + break; + default: break; + } + } + } } diff --git a/src/textures/pngtexture.cpp b/src/textures/pngtexture.cpp index 8120df968..7927c0a93 100644 --- a/src/textures/pngtexture.cpp +++ b/src/textures/pngtexture.cpp @@ -297,33 +297,17 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename case 0: // Grayscale if (!bAlphaTexture) { - BYTE *GrayMapSrc; - switch(BitDepth) - { - default: - GrayMapSrc = GrayMap; - break; - case 4: - GrayMapSrc = GrayMap4bit; - break; - case 2: - GrayMapSrc = GrayMap2bit; - break; - case 1: - GrayMapSrc = GrayMap1bit; - break; - } if (colortype == 0 && havetRNS && trans[0] != 0) { bMasked = true; - PaletteSize = 1< Date: Sun, 26 May 2013 20:56:20 +0000 Subject: [PATCH 354/387] - Fixed more possible NULL derefs from r4264 SVN r4290 (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 b9cbf3f37..1b85961c2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3646,7 +3646,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, hitz = shootz + FixedMul (vz, dist); // Spawn bullet puffs or blood spots, depending on target type. - if ((puffDefaults->flags3 & MF3_PUFFONACTORS) || + if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) || (trace.Actor->flags & MF_NOBLOOD) || (trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) { @@ -3658,7 +3658,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->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) + if (puffDefaults != NULL && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { P_PoisonMobj(trace.Actor, puff ? puff : t1, t1, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); } @@ -3666,7 +3666,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, // [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. int newdam = damage; - if (damage || (puffDefaults->flags6 & MF6_FORCEPAIN)) + if (damage || (puffDefaults != NULL && puffDefaults->flags6 & MF6_FORCEPAIN)) { int dmgflags = DMG_INFLICTOR_IS_PUFF | pflag; // Allow MF5_PIERCEARMOR on a weapon as well. @@ -3685,7 +3685,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } newdam = P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); } - if (!(puffDefaults->flags3&MF3_BLOODLESSIMPACT)) + if (!(puffDefaults != NULL && puffDefaults->flags3&MF3_BLOODLESSIMPACT)) { if (!bloodsplatter && !axeBlood && !(trace.Actor->flags & MF_NOBLOOD) && From 4a8037d66ee16a992604fb5c6830cdda169fcb0c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 27 May 2013 02:04:54 +0000 Subject: [PATCH 355/387] - Move bitdepth check outside the loop for grayscale unpacking. Also, don't use a multiply for 1-bit pixels. Use a lookup table for 2-bit pixels, because it's probably faster than a bunch of shifts and register juggling. SVN r4291 (trunk) --- src/m_png.cpp | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/m_png.cpp b/src/m_png.cpp index 1e1a331af..2bec48103 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -1162,6 +1162,8 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE * BYTE pack; int lastbyte; + assert(bitdepth == 1 || bitdepth == 2 || bitdepth == 4); + out = rowout + width; in = rowin + bytesPerRow; @@ -1243,25 +1245,42 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE * break; } - // Expand gray scale to 8bpp - if(grayscale) + // Expand grayscale to 8bpp + if (grayscale) { - out = rowout + width; - while(--out >= rowout) + // Put the 2-bit lookup table on the stack, since it's probably already + // in a cache line. + union { - switch(bitdepth) + uint32 bits2l; + BYTE bits2[4]; + }; + + out = rowout + width; + switch (bitdepth) + { + case 1: + while (--out >= rowout) { - case 1: - *out *= 0xFF; - break; - case 2: - *out |= (*out<<2)|(*out<<4)|(*out<<6); - break; - case 4: - *out |= (*out<<4); - break; - default: break; + // 1 becomes -1 (0xFF), and 0 remains untouched. + *out = 0 - *out; } + break; + + case 2: + bits2l = MAKE_ID(0x00,0x55,0xAA,0xFF); + while (--out >= rowout) + { + *out = bits2[*out]; + } + break; + + case 4: + while (--out >= rowout) + { + *out |= (*out << 4); + } + break; } } } From 587f1e83ba6436b204d320dadb636d847610f8e2 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 27 May 2013 02:20:32 +0000 Subject: [PATCH 356/387] - Added ACS functions SetCVarString and SetUserCVarString. These work just like their non-string counterparts except that their value argument is an ACS string. (Note that they work with any type of cvar, not just string cvars.) - Make UCVarValue::String point to a constant string. SVN r4292 (trunk) --- src/c_cvars.cpp | 2 +- src/c_cvars.h | 4 ++-- src/p_acs.cpp | 41 +++++++++++++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 308d53613..19187353f 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -266,7 +266,7 @@ static GUID cGUID; static char truestr[] = "true"; static char falsestr[] = "false"; -char *FBaseCVar::ToString (UCVarValue value, ECVarType type) +const char *FBaseCVar::ToString (UCVarValue value, ECVarType type) { switch (type) { diff --git a/src/c_cvars.h b/src/c_cvars.h index f1bf254b9..17d3f7b1d 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -70,7 +70,7 @@ union UCVarValue bool Bool; int Int; float Float; - char *String; + const char *String; const GUID *pGUID; }; @@ -132,7 +132,7 @@ protected: static bool ToBool (UCVarValue value, ECVarType type); static int ToInt (UCVarValue value, ECVarType type); static float ToFloat (UCVarValue value, ECVarType type); - static char *ToString (UCVarValue value, ECVarType type); + static const char *ToString (UCVarValue value, ECVarType type); static const GUID *ToGUID (UCVarValue value, ECVarType type); static UCVarValue FromBool (bool value, ECVarType type); static UCVarValue FromInt (int value, ECVarType type); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f251ab2e7..050e1cf28 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3477,6 +3477,8 @@ enum EACSFunctions ACSF_SetCVar, ACSF_GetUserCVar, ACSF_SetUserCVar, + ACSF_SetCVarString, + ACSF_SetUserCVarString, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -3577,7 +3579,7 @@ static int GetUserVariable(AActor *self, FName varname, int index) } // Converts fixed- to floating-point as required. -static void DoSetCVar(FBaseCVar *cvar, int value, bool force=false) +static void DoSetCVar(FBaseCVar *cvar, int value, bool is_string, bool force=false) { UCVarValue val; ECVarType type; @@ -3589,7 +3591,12 @@ static void DoSetCVar(FBaseCVar *cvar, int value, bool force=false) { return; } - if (cvar->GetRealType() == CVAR_Float) + if (is_string) + { + val.String = FBehavior::StaticLookupString(value); + type = CVAR_String; + } + else if (cvar->GetRealType() == CVAR_Float) { val.Float = FIXED2FLOAT(value); type = CVAR_Float; @@ -3664,7 +3671,7 @@ static int GetCVar(AActor *activator, const char *cvarname) } } -static int SetUserCVar(int playernum, const char *cvarname, int value) +static int SetUserCVar(int playernum, const char *cvarname, int value, bool is_string) { if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) { @@ -3677,7 +3684,7 @@ static int SetUserCVar(int playernum, const char *cvarname, int value) { return 0; } - DoSetCVar(cvar, value); + DoSetCVar(cvar, value, is_string); // If we are this player, then also reflect this change in the local version of this cvar. if (playernum == consoleplayer) @@ -3687,14 +3694,14 @@ static int SetUserCVar(int playernum, const char *cvarname, int value) // but check just to be safe. if (cvar != NULL) { - DoSetCVar(cvar, value, true); + DoSetCVar(cvar, value, is_string, true); } } return 1; } -static int SetCVar(AActor *activator, const char *cvarname, int value) +static int SetCVar(AActor *activator, const char *cvarname, int value, bool is_string) { FBaseCVar *cvar = FindCVar(cvarname, NULL); // Only mod-created cvars may be set. @@ -3709,9 +3716,9 @@ static int SetCVar(AActor *activator, const char *cvarname, int value) { return 0; } - return SetUserCVar(int(activator->player - players), cvarname, value); + return SetUserCVar(int(activator->player - players), cvarname, value, is_string); } - DoSetCVar(cvar, value); + DoSetCVar(cvar, value, is_string); return 1; } @@ -4169,14 +4176,28 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_SetUserCVar: if (argCount == 3) { - return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2]); + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], false); + } + break; + + case ACSF_SetUserCVarString: + if (argCount == 3) + { + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], true); } break; case ACSF_SetCVar: if (argCount == 2) { - return SetCVar(activator, FBehavior::StaticLookupString(args[0]), args[1]); + return SetCVar(activator, FBehavior::StaticLookupString(args[0]), args[1], false); + } + break; + + case ACSF_SetCVarString: + if (argCount == 2) + { + return SetCVar(activator, FBehavior::StaticLookupString(args[0]), args[1], true); } break; From 493edd2df00d15b060bae3d3071eb30e5f53f4bb Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 27 May 2013 02:41:50 +0000 Subject: [PATCH 357/387] - Added ACS functions GetCVarString and GetUserCVarString. These act like their non-string counterparts, except that they return strings. Like strparam, the strings they return are only guaranteed to be valid for the tick they are called during. (Note that these work with any cvar, not just string ones.) SVN r4293 (trunk) --- src/p_acs.cpp | 100 +++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 37 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 050e1cf28..903ea9cf9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -168,9 +168,22 @@ FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; #define LIB_ACSSTRINGS_ONTHEFLY 0x7fff #define ACSSTRING_OR_ONTHEFLY (LIB_ACSSTRINGS_ONTHEFLY<<16) -TArray - ACS_StringsOnTheFly, - ACS_StringBuilderStack; +class OnTheFlyArray : public TArray +{ +public: + // Returns a valid string identifier for this tick, or + // -1 if we ran out of room. + int Push(FString &str) + { + if (Size() >= 0x10000) + { + return -1; + } + return (int)TArray::Push(str) | ACSSTRING_OR_ONTHEFLY; + } +} +ACS_StringsOnTheFly; +TArray ACS_StringBuilderStack; #define STRINGBUILDER_START(Builder) if (Builder.IsNotEmpty() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; } #define STRINGBUILDER_FINISH(Builder) if (!ACS_StringBuilderStack.Pop(Builder)) { Builder = ""; } @@ -3477,7 +3490,9 @@ enum EACSFunctions ACSF_SetCVar, ACSF_GetUserCVar, ACSF_SetUserCVar, + ACSF_GetCVarString, ACSF_SetCVarString, + ACSF_GetUserCVarString, ACSF_SetUserCVarString, // ZDaemon @@ -3617,11 +3632,16 @@ static void DoSetCVar(FBaseCVar *cvar, int value, bool is_string, bool force=fal } // Converts floating- to fixed-point as required. -static int DoGetCVar(FBaseCVar *cvar) +static int DoGetCVar(FBaseCVar *cvar, bool is_string) { UCVarValue val; - if (cvar->GetRealType() == CVAR_Float) + if (is_string) + { + val = cvar->GetGenericRep(CVAR_String); + return ACS_StringsOnTheFly.Push(FString(val.String)); + } + else if (cvar->GetRealType() == CVAR_Float) { val = cvar->GetGenericRep(CVAR_Float); return FLOAT2FIXED(val.Float); @@ -3633,7 +3653,7 @@ static int DoGetCVar(FBaseCVar *cvar) } } -static int GetUserCVar(int playernum, const char *cvarname) +static int GetUserCVar(int playernum, const char *cvarname, bool is_string) { if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) { @@ -3645,10 +3665,10 @@ static int GetUserCVar(int playernum, const char *cvarname) { return 0; } - return DoGetCVar(cvar); + return DoGetCVar(cvar, is_string); } -static int GetCVar(AActor *activator, const char *cvarname) +static int GetCVar(AActor *activator, const char *cvarname, bool is_string) { FBaseCVar *cvar = FindCVar(cvarname, NULL); // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. @@ -3665,9 +3685,9 @@ static int GetCVar(AActor *activator, const char *cvarname) { return 0; } - return GetUserCVar(int(activator->player - players), cvarname); + return GetUserCVar(int(activator->player - players), cvarname, is_string); } - return DoGetCVar(cvar); + return DoGetCVar(cvar, is_string); } } @@ -4166,24 +4186,10 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) WrapWidth = argCount > 0 ? args[0] : 0; break; - case ACSF_GetUserCVar: - if (argCount == 2) + case ACSF_GetCVarString: + if (argCount == 1) { - return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])); - } - break; - - case ACSF_SetUserCVar: - if (argCount == 3) - { - return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], false); - } - break; - - case ACSF_SetUserCVarString: - if (argCount == 3) - { - return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], true); + return GetCVar(activator, FBehavior::StaticLookupString(args[0]), true); } break; @@ -4201,6 +4207,34 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } break; + case ACSF_GetUserCVar: + if (argCount == 2) + { + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), false); + } + break; + + case ACSF_GetUserCVarString: + if (argCount == 2) + { + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), true); + } + break; + + case ACSF_SetUserCVar: + if (argCount == 3) + { + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], false); + } + break; + + case ACSF_SetUserCVarString: + if (argCount == 3) + { + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2], true); + } + break; + default: break; } @@ -7067,7 +7101,7 @@ scriptwait: break; case PCD_GETCVAR: - STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1))); + STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1)), false); break; case PCD_SETHUDSIZE: @@ -7451,15 +7485,7 @@ scriptwait: case PCD_SAVESTRING: // Saves the string { - unsigned int str_otf = ACS_StringsOnTheFly.Push(work); - if (str_otf > 0xffff) - { - PushToStack(-1); - } - else - { - PushToStack((SDWORD)str_otf|ACSSTRING_OR_ONTHEFLY); - } + PushToStack(ACS_StringsOnTheFly.Push(work)); STRINGBUILDER_FINISH(work); } break; From 0eb72156ede540aefa7de515aecb2f738bcd0e97 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 30 May 2013 02:22:47 +0000 Subject: [PATCH 358/387] I hope I don't regret doing this so close before I want to do a release, since it's a pretty major change to ACS's workings. However, I had an epiphany yesterday and just had to do this, since it seems like too big a deal to hold off until a later release: - Dynamically generated strings returned via strparam and get(user)cvar now last as long as they need to. They do not disappear at the end of each tic. You can now safely store them in variables and hold on to them indefinitely. In addition, strings from libraries no longer require you to load the exact same libraries in the exact same order. You can even store a library's string in a world variable and retrieve it on another map that doesn't load the library at all, and it will still be the correct string. - ACS library IDs now only get 12 bits instead of 16 so that each string table can hold up to about a million strings instead of just 65536. This shouldn't be a problem, although it means that save games that had strings with the larger IDs stored in variables are no longer compatible. Since many saves don't involve libraries at all, and even many that do are not actually affected, I'm not bumping the min save version. The worst that can happen is that you get no text at all where some was expected. SVN r4295 (trunk) --- src/g_level.cpp | 8 + src/g_mapinfo.cpp | 3 + src/p_acs.cpp | 743 ++++++++++++++++++++++++++++++++++++++++++---- src/p_acs.h | 76 ++++- 4 files changed, 767 insertions(+), 63 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 526ec2a22..755a4fba6 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -737,6 +737,9 @@ void G_DoCompleted (void) if (!(level.flags2 & LEVEL2_FORGETSTATE)) { G_SnapshotLevel (); + // Do not free any global strings this level might reference + // while it's not loaded. + FBehavior::StaticLockLevelVarStrings(); } else { // Make sure we don't have a snapshot lying around from before. @@ -1575,6 +1578,11 @@ void G_UnSnapshotLevel (bool hubLoad) } // No reason to keep the snapshot around once the level's been entered. level.info->ClearSnapshot(); + if (hubLoad) + { + // Unlock ACS global strings that were locked when the snapshot was made. + FBehavior::StaticUnlockLevelVarStrings(); + } } //========================================================================== diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index cb7b03932..7a8075174 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -198,6 +198,9 @@ void G_ClearSnapshots (void) { wadlevelinfos[i].ClearSnapshot(); } + // Since strings are only locked when snapshotting a level, unlock them + // all now, since we got rid of all the snapshots that cared about them. + GlobalACSStrings.UnlockAll(); } //========================================================================== diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 903ea9cf9..71c0f53f3 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -80,7 +80,6 @@ extern FILE *Logfile; FRandom pr_acs ("ACS"); - // I imagine this much stack space is probably overkill, but it could // potentially get used with recursive functions. #define STACK_SIZE 4096 @@ -142,47 +141,6 @@ struct FBehavior::ArrayInfo }; TArray FBehavior::StaticModules; - - -//============================================================================ -// -// Global and world variables -// -//============================================================================ - -// ACS variables with world scope -SDWORD ACS_WorldVars[NUM_WORLDVARS]; -FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; - -// ACS variables with global scope -SDWORD ACS_GlobalVars[NUM_GLOBALVARS]; -FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; - - -//============================================================================ -// -// On the fly strings -// -//============================================================================ - -#define LIB_ACSSTRINGS_ONTHEFLY 0x7fff -#define ACSSTRING_OR_ONTHEFLY (LIB_ACSSTRINGS_ONTHEFLY<<16) - -class OnTheFlyArray : public TArray -{ -public: - // Returns a valid string identifier for this tick, or - // -1 if we ran out of room. - int Push(FString &str) - { - if (Size() >= 0x10000) - { - return -1; - } - return (int)TArray::Push(str) | ACSSTRING_OR_ONTHEFLY; - } -} -ACS_StringsOnTheFly; TArray ACS_StringBuilderStack; #define STRINGBUILDER_START(Builder) if (Builder.IsNotEmpty() || ACS_StringBuilderStack.Size()) { ACS_StringBuilderStack.Push(Builder); Builder = ""; } @@ -209,6 +167,571 @@ inline int uallong(const int &foo) } #endif +//============================================================================ +// +// Global and world variables +// +//============================================================================ + +// ACS variables with world scope +SDWORD ACS_WorldVars[NUM_WORLDVARS]; +FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; + +// ACS variables with global scope +SDWORD ACS_GlobalVars[NUM_GLOBALVARS]; +FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; + + +//---------------------------------------------------------------------------- +// +// Global ACS strings (Formerly known as On the fly strings) +// +// This special string table is part of the global state. Programmatically +// generated strings (e.g. those returned by strparam) are stored here. +// PCD_TAGSTRING also now stores strings in this table instead of simply +// tagging strings with their library ID. +// +// Identical strings map to identical string identifiers. +// +// When the string table needs to grow to hold more strings, a garbage +// collection is first attempted to see if more room can be made to store +// strings without growing. A string is concidered in use if any value +// in any of these variable blocks contains a valid ID in the global string +// table: +// * All running scripts' local variables +// * All map variables +// * All world variables +// * All global variables +// It's not important whether or not they are really used as strings, only +// that they might be. A string is also concidered in use if its lock count +// is non-zero, even if none of the above variable blocks referenced it. +// +// To keep track of local and map variables for nonresident maps in a hub, +// when a map's state is archived, all strings found in its local and map +// variables are locked. When a map is revisited in a hub, all strings found +// in its local and map variables are unlocked. Locking and unlocking are +// cumulative operations. +// +// What this all means is that: +// * Strings returned by strparam last indefinitely. No longer do they +// disappear at the end of the tic they were generated. +// * You can pass library strings around freely without having to worry +// about always having the same libraries loaded in the same order on +// every map that needs to use those strings. +// +//---------------------------------------------------------------------------- + +ACSStringPool GlobalACSStrings; + +ACSStringPool::ACSStringPool() +{ + memset(PoolBuckets, 0xFF, sizeof(PoolBuckets)); + FirstFreeEntry = 0; +} + +//============================================================================ +// +// ACSStringPool :: Clear +// +// Remove all strings from the pool. +// +//============================================================================ + +void ACSStringPool::Clear() +{ + Pool.Clear(); + memset(PoolBuckets, 0xFF, sizeof(PoolBuckets)); + FirstFreeEntry = 0; +} + +//============================================================================ +// +// ACSStringPool :: AddString +// +// Returns a valid string identifier (including library ID) or -1 if we ran +// out of room. Identical strings will return identical values. +// +//============================================================================ + +int ACSStringPool::AddString(const char *str) +{ + size_t len = strlen(str); + unsigned int h = SuperFastHash(str, len); + unsigned int bucketnum = h % NUM_BUCKETS; + int i = FindString(str, len, h, bucketnum); + if (i >= 0) + { + return i | STRPOOL_LIBRARYID_OR; + } + FString fstr(str); + return InsertString(fstr, h, bucketnum); +} + +int ACSStringPool::AddString(FString &str) +{ + unsigned int h = SuperFastHash(str.GetChars(), str.Len()); + unsigned int bucketnum = h % NUM_BUCKETS; + int i = FindString(str, str.Len(), h, bucketnum); + if (i >= 0) + { + return i | STRPOOL_LIBRARYID_OR; + } + return InsertString(str, h, bucketnum); +} + +//============================================================================ +// +// ACSStringPool :: GetString +// +//============================================================================ + +const char *ACSStringPool::GetString(int strnum) +{ + assert((strnum & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR); + strnum &= ~LIBRARYID_MASK; + if ((unsigned)strnum < Pool.Size() && Pool[strnum].Next != FREE_ENTRY) + { + return Pool[strnum].Str; + } + return NULL; +} + +//============================================================================ +// +// ACSStringPool :: LockString +// +// Prevents this string from being purged. +// +//============================================================================ + +void ACSStringPool::LockString(int strnum) +{ + assert((strnum & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR); + strnum &= ~LIBRARYID_MASK; + assert((unsigned)strnum < Pool.Size()); + Pool[strnum].LockCount++; +} + +//============================================================================ +// +// ACSStringPool :: UnlockString +// +// When equally mated with LockString, allows this string to be purged. +// +//============================================================================ + +void ACSStringPool::UnlockString(int strnum) +{ + assert((strnum & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR); + strnum &= ~LIBRARYID_MASK; + assert((unsigned)strnum < Pool.Size()); + assert(Pool[strnum].LockCount > 0); + Pool[strnum].LockCount--; +} + +//============================================================================ +// +// ACSStringPool :: MarkString +// +// Prevent this string from being purged during the next call to PurgeStrings. +// This does not carry over to subsequent calls of PurgeStrings. +// +//============================================================================ + +void ACSStringPool::MarkString(int strnum) +{ + assert((strnum & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR); + strnum &= ~LIBRARYID_MASK; + assert((unsigned)strnum < Pool.Size()); + Pool[strnum].LockCount |= 0x80000000; +} + +//============================================================================ +// +// ACSStringPool :: LockStringArray +// +// Prevents several strings from being purged. Entries not in this pool will +// be silently ignored. The idea here is to pass this function a block of +// ACS variables. Everything that looks like it might be a string in the pool +// is locked, even if it's not actually used as such. It's better to keep +// more strings than we need than to throw away ones we do need. +// +//============================================================================ + +void ACSStringPool::LockStringArray(const int *strnum, unsigned int count) +{ + for (unsigned int i = 0; i < count; ++i) + { + int num = strnum[i]; + if ((num & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR) + { + num &= ~LIBRARYID_MASK; + if ((unsigned)num < Pool.Size()) + { + Pool[num].LockCount++; + } + } + } +} + +//============================================================================ +// +// ACSStringPool :: UnlockStringArray +// +// Reverse of LockStringArray. +// +//============================================================================ + +void ACSStringPool::UnlockStringArray(const int *strnum, unsigned int count) +{ + for (unsigned int i = 0; i < count; ++i) + { + int num = strnum[i]; + if ((num & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR) + { + num &= ~LIBRARYID_MASK; + if ((unsigned)num < Pool.Size()) + { + assert(Pool[num].LockCount > 0); + Pool[num].LockCount--; + } + } + } +} + +//============================================================================ +// +// ACSStringPool :: MarkStringArray +// +// Array version of MarkString. +// +//============================================================================ + +void ACSStringPool::MarkStringArray(const int *strnum, unsigned int count) +{ + for (unsigned int i = 0; i < count; ++i) + { + int num = strnum[i]; + if ((num & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR) + { + num &= ~LIBRARYID_MASK; + if ((unsigned)num < Pool.Size()) + { + Pool[num].LockCount |= 0x80000000; + } + } + } +} + +//============================================================================ +// +// ACSStringPool :: MarkStringMap +// +// World/global variables version of MarkString. +// +//============================================================================ + +void ACSStringPool::MarkStringMap(const FWorldGlobalArray &aray) +{ + FWorldGlobalArray::ConstIterator it(aray); + FWorldGlobalArray::ConstPair *pair; + + while (it.NextPair(pair)) + { + int num = pair->Value; + if ((num & LIBRARYID_MASK) == STRPOOL_LIBRARYID_OR) + { + num &= ~LIBRARYID_MASK; + if ((unsigned)num < Pool.Size()) + { + Pool[num].LockCount |= 0x80000000; + } + } + } +} + +//============================================================================ +// +// ACSStringPool :: UnlockAll +// +// Resets every entry's lock count to 0. Used when doing a partial reset of +// ACS state such as travelling to a new hub. +// +//============================================================================ + +void ACSStringPool::UnlockAll() +{ + for (unsigned int i = 0; i < Pool.Size(); ++i) + { + Pool[i].LockCount = 0; + } +} + +//============================================================================ +// +// ACSStringPool :: PurgeStrings +// +// Remove all unlocked strings from the pool. +// +//============================================================================ + +void ACSStringPool::PurgeStrings() +{ + // Clear the hash buckets. We'll rebuild them as we decide what strings + // to keep and which to toss. + memset(PoolBuckets, 0xFF, sizeof(PoolBuckets)); + for (unsigned int i = 0; i < Pool.Size(); ++i) + { + PoolEntry *entry = &Pool[i]; + if (entry->Next != FREE_ENTRY) + { + if (entry->LockCount == 0) + { // Mark this entry as free. + entry->Next = FREE_ENTRY; + if (i < FirstFreeEntry) + { + FirstFreeEntry = i; + } + } + else + { + // Rehash this entry. + unsigned int h = entry->Hash % NUM_BUCKETS; + entry->Next = PoolBuckets[h]; + PoolBuckets[h] = i; + // Remove MarkString's mark. + entry->LockCount &= 0x7FFFFFFF; + } + } + } +} + +//============================================================================ +// +// ACSStringPool :: FindString +// +// Finds a string in the pool. Does not include the library ID in the returned +// value. Returns -1 if the string does not exist in the pool. +// +//============================================================================ + +int ACSStringPool::FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum) +{ + unsigned int i = PoolBuckets[bucketnum]; + while (i != NO_ENTRY) + { + PoolEntry *entry = &Pool[i]; + assert(entry->Next != FREE_ENTRY); + if (entry->Hash == h && entry->Str.Len() == len && + memcmp(entry->Str.GetChars(), str, len) == 0) + { + return i; + } + i = entry->Next; + } + return -1; +} + +//============================================================================ +// +// ACSStringPool :: InsertString +// +// Inserts a new string into the pool. +// +//============================================================================ + +int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucketnum) +{ + if (Pool.Size() >= STRPOOL_LIBRARYID) + { + return -1; + } + unsigned int index = FirstFreeEntry; + if (index >= MIN_GC_SIZE && index == Pool.Max()) + { // We will need to grow the array. Try a garbage collection first. + P_CollectACSGlobalStrings(); + } + if (index == Pool.Size()) + { // There were no free entries; make a new one. + Pool.Reserve(1); + FirstFreeEntry++; + } + else + { // Scan for the next free entry + unsigned int i; + for (i = FirstFreeEntry + 1; i < Pool.Size() && Pool[i].Next != FREE_ENTRY; ++i) + { + } + FirstFreeEntry = i; + } + PoolEntry *entry = &Pool[index]; + entry->Str = str; + entry->Hash = h; + entry->Next = PoolBuckets[bucketnum]; + entry->LockCount = 0; + PoolBuckets[bucketnum] = index; + return index | STRPOOL_LIBRARYID_OR; +} + +//============================================================================ +// +// ACSStringPool :: ReadStrings +// +// Reads strings from a PNG chunk. +// +//============================================================================ + +void ACSStringPool::ReadStrings(PNGHandle *png, DWORD id) +{ + Clear(); + + size_t len = M_FindPNGChunk(png, id); + if (len != 0) + { + FPNGChunkArchive arc(png->File->GetFile(), id, len); + int32 i, j, poolsize; + unsigned int h, bucketnum; + char *str = NULL; + + arc << poolsize; + + Pool.Resize(poolsize); + i = 0; + j = arc.ReadCount(); + while (j >= 0) + { + // Mark skipped entries as free + for (; i < j; ++i) + { + Pool[i].Next = FREE_ENTRY; + Pool[i].LockCount = 0; + } + arc << str; + h = SuperFastHash(str, strlen(str)); + bucketnum = h % NUM_BUCKETS; + Pool[i].Str = str; + Pool[i].Hash = h; + Pool[i].LockCount = arc.ReadCount(); + Pool[i].Next = PoolBuckets[bucketnum]; + PoolBuckets[bucketnum] = i; + i++; + j = arc.ReadCount(); + } + if (str != NULL) + { + delete[] str; + } + } +} + +//============================================================================ +// +// ACSStringPool :: WriteStrings +// +// Writes strings to a PNG chunk. +// +//============================================================================ + +void ACSStringPool::WriteStrings(FILE *file, DWORD id) const +{ + int32 i, poolsize = (int32)Pool.Size(); + + if (poolsize == 0) + { // No need to write if we don't have anything. + return; + } + FPNGChunkArchive arc(file, id); + + arc << poolsize; + for (i = 0; i < poolsize; ++i) + { + PoolEntry *entry = &Pool[i]; + if (entry->Next != FREE_ENTRY) + { + arc.WriteCount(i); + arc.WriteString(entry->Str); + arc.WriteCount(entry->LockCount); + } + } + arc.WriteCount(-1); +} + +//============================================================================ +// +// ACSStringPool :: Dump +// +// Lists all strings in the pool. +// +//============================================================================ + +void ACSStringPool::Dump() const +{ + for (unsigned int i = 0; i < Pool.Size(); ++i) + { + if (Pool[i].Next != FREE_ENTRY) + { + Printf("%4u. (%2d) \"%s\"\n", i, Pool[i].LockCount, Pool[i].Str.GetChars()); + } + } +} + +//============================================================================ +// +// P_MarkWorldVarStrings +// +//============================================================================ + +void P_MarkWorldVarStrings() +{ + GlobalACSStrings.MarkStringArray(ACS_WorldVars, countof(ACS_WorldVars)); + for (size_t i = 0; i < countof(ACS_WorldArrays); ++i) + { + GlobalACSStrings.MarkStringMap(ACS_WorldArrays[i]); + } +} + +//============================================================================ +// +// P_MarkGlobalVarStrings +// +//============================================================================ + +void P_MarkGlobalVarStrings() +{ + GlobalACSStrings.MarkStringArray(ACS_GlobalVars, countof(ACS_GlobalVars)); + for (size_t i = 0; i < countof(ACS_GlobalArrays); ++i) + { + GlobalACSStrings.MarkStringMap(ACS_GlobalArrays[i]); + } +} + +//============================================================================ +// +// P_CollectACSGlobalStrings +// +// Garbage collect ACS global strings. +// +//============================================================================ + +void P_CollectACSGlobalStrings() +{ + FBehavior::StaticMarkLevelVarStrings(); + P_MarkWorldVarStrings(); + P_MarkGlobalVarStrings(); + GlobalACSStrings.PurgeStrings(); +} + +#ifdef _DEBUG +CCMD(acsgc) +{ + P_CollectACSGlobalStrings(); +} +CCMD(globstr) +{ + GlobalACSStrings.Dump(); +} +#endif + //============================================================================ // // ScriptPresentation @@ -236,7 +759,7 @@ static FString ScriptPresentation(int script) //============================================================================ // -// +// P_ClearACSVars // //============================================================================ @@ -256,12 +779,22 @@ void P_ClearACSVars(bool alsoglobal) { ACS_GlobalArrays[i].Clear (); } + // Since we cleared all ACS variables, we know nothing refers to them + // anymore. + GlobalACSStrings.Clear(); + } + else + { + // Purge any strings that aren't referenced by global variables, since + // they're the only possible references left. + P_MarkGlobalVarStrings(); + GlobalACSStrings.PurgeStrings(); } } //============================================================================ // -// +// WriteVars // //============================================================================ @@ -419,6 +952,7 @@ void P_ReadACSVars(PNGHandle *png) ReadVars (png, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r')); ReadArrayVars (png, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r')); ReadArrayVars (png, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r')); + GlobalACSStrings.ReadStrings(png, MAKE_ID('a','s','T','r')); } //============================================================================ @@ -433,6 +967,7 @@ void P_WriteACSVars(FILE *stdfile) WriteVars (stdfile, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r')); WriteArrayVars (stdfile, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r')); WriteArrayVars (stdfile, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r')); + GlobalACSStrings.WriteStrings(stdfile, MAKE_ID('a','s','T','r')); } //---- Inventory functions --------------------------------------// @@ -904,6 +1439,84 @@ FBehavior *FBehavior::StaticGetModule (int lib) return StaticModules[lib]; } +void FBehavior::StaticMarkLevelVarStrings() +{ + // Mark map variables. + for (DWORD modnum = 0; modnum < StaticModules.Size(); ++modnum) + { + StaticModules[modnum]->MarkMapVarStrings(); + } + // Mark running scripts' local variables. + if (DACSThinker::ActiveThinker != NULL) + { + for (DLevelScript *script = DACSThinker::ActiveThinker->Scripts; script != NULL; script = script->GetNext()) + { + script->MarkLocalVarStrings(); + } + } +} + +void FBehavior::StaticLockLevelVarStrings() +{ + // Lock map variables. + for (DWORD modnum = 0; modnum < StaticModules.Size(); ++modnum) + { + StaticModules[modnum]->LockMapVarStrings(); + } + // Lock running scripts' local variables. + if (DACSThinker::ActiveThinker != NULL) + { + for (DLevelScript *script = DACSThinker::ActiveThinker->Scripts; script != NULL; script = script->GetNext()) + { + script->LockLocalVarStrings(); + } + } +} + +void FBehavior::StaticUnlockLevelVarStrings() +{ + // Unlock map variables. + for (DWORD modnum = 0; modnum < StaticModules.Size(); ++modnum) + { + StaticModules[modnum]->UnlockMapVarStrings(); + } + // Unlock running scripts' local variables. + if (DACSThinker::ActiveThinker != NULL) + { + for (DLevelScript *script = DACSThinker::ActiveThinker->Scripts; script != NULL; script = script->GetNext()) + { + script->UnlockLocalVarStrings(); + } + } +} + +void FBehavior::MarkMapVarStrings() const +{ + GlobalACSStrings.MarkStringArray(MapVarStore, NUM_MAPVARS); + for (int i = 0; i < NumArrays; ++i) + { + GlobalACSStrings.MarkStringArray(ArrayStore[i].Elements, ArrayStore[i].ArraySize); + } +} + +void FBehavior::LockMapVarStrings() const +{ + GlobalACSStrings.LockStringArray(MapVarStore, NUM_MAPVARS); + for (int i = 0; i < NumArrays; ++i) + { + GlobalACSStrings.LockStringArray(ArrayStore[i].Elements, ArrayStore[i].ArraySize); + } +} + +void FBehavior::UnlockMapVarStrings() const +{ + GlobalACSStrings.UnlockStringArray(MapVarStore, NUM_MAPVARS); + for (int i = 0; i < NumArrays; ++i) + { + GlobalACSStrings.UnlockStringArray(ArrayStore[i].Elements, ArrayStore[i].ArraySize); + } +} + void FBehavior::StaticSerializeModuleStates (FArchive &arc) { DWORD modnum; @@ -1055,7 +1668,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) // 1. If not, corrupt modules cause memory leaks // 2. Corrupt modules won't be reported when a level is being loaded if this function quits before // adding it to the list. - LibraryID = StaticModules.Push (this) << 16; + LibraryID = StaticModules.Push (this) << LIBRARYID_SHIFT; if (fr == NULL) len = Wads.LumpLength (lumpnum); @@ -1167,7 +1780,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) { MapVars[i] = &MapVarStore[i]; } - //LibraryID = StaticModules.Push (this) << 16; + //LibraryID = StaticModules.Push (this) << LIBRARYID_SHIFT; } else { @@ -1267,7 +1880,8 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) { for (DWORD i = 0; i < chunk[1]/4; ++i) { - MapVarStore[chunk[i+2]] |= LibraryID; +// MapVarStore[chunk[i+2]] |= LibraryID; + MapVarStore[chunk[i+2]] = GlobalACSStrings.AddString(LookupString(MapVarStore[chunk[i+2]])); } } @@ -1282,7 +1896,8 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) SDWORD *elems = ArrayStore[arraynum].Elements; for (int j = ArrayStore[arraynum].ArraySize; j > 0; --j, ++elems) { - *elems |= LibraryID; +// *elems |= LibraryID; + *elems = GlobalACSStrings.AddString(LookupString(*elems)); } } } @@ -1306,8 +1921,14 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) { // For ATAG, a value of 0 = Integer, 1 = String, 2 = FunctionPtr // Our implementation uses the same tags for both String and FunctionPtr - if(*chunkData) + if (*chunkData == 2) + { *elems |= LibraryID; + } + else if (*chunkData == 1) + { + *elems = GlobalACSStrings.AddString(LookupString(*elems)); + } } i += 4+ArrayStore[arraynum].ArraySize; } @@ -1942,15 +2563,12 @@ BYTE *FBehavior::NextChunk (BYTE *chunk) const const char *FBehavior::StaticLookupString (DWORD index) { - DWORD lib = index >> 16; - - switch (lib) - { - case LIB_ACSSTRINGS_ONTHEFLY: - index &= 0xffff; - return (ACS_StringsOnTheFly.Size() > index) ? ACS_StringsOnTheFly[index].GetChars() : NULL; - } + DWORD lib = index >> LIBRARYID_SHIFT; + if (lib == STRPOOL_LIBRARYID) + { + return GlobalACSStrings.GetString(index); + } if (lib >= (DWORD)StaticModules.Size()) { return NULL; @@ -2167,7 +2785,7 @@ void DACSThinker::Tick () script = next; } - ACS_StringsOnTheFly.Clear(); +// GlobalACSStrings.Clear(); if (ACS_StringBuilderStack.Size()) { @@ -2233,7 +2851,7 @@ void DLevelScript::Serialize (FArchive &arc) if (arc.IsStoring ()) { - WORD lib = activeBehavior->GetLibraryID() >> 16; + WORD lib = activeBehavior->GetLibraryID() >> LIBRARYID_SHIFT; arc << lib; i = activeBehavior->PC2Ofs (pc); arc << i; @@ -3639,7 +4257,7 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string) if (is_string) { val = cvar->GetGenericRep(CVAR_String); - return ACS_StringsOnTheFly.Push(FString(val.String)); + return GlobalACSStrings.AddString(val.String); } else if (cvar->GetRealType() == CVAR_Float) { @@ -4385,7 +5003,8 @@ int DLevelScript::RunScript () break; case PCD_TAGSTRING: - Stack[sp-1] |= activeBehavior->GetLibraryID(); + //Stack[sp-1] |= activeBehavior->GetLibraryID(); + Stack[sp-1] = GlobalACSStrings.AddString(activeBehavior->LookupString(Stack[sp-1])); break; case PCD_PUSHNUMBER: @@ -7485,7 +8104,7 @@ scriptwait: case PCD_SAVESTRING: // Saves the string { - PushToStack(ACS_StringsOnTheFly.Push(work)); + PushToStack(GlobalACSStrings.AddString(work)); STRINGBUILDER_FINISH(work); } break; diff --git a/src/p_acs.h b/src/p_acs.h index e4eadf3b0..c9c999556 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -69,6 +69,56 @@ extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS]; extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; +#define LIBRARYID_MASK 0xFFF00000 +#define LIBRARYID_SHIFT 20 + +// Global ACS string table +#define STRPOOL_LIBRARYID (INT_MAX >> LIBRARYID_SHIFT) +#define STRPOOL_LIBRARYID_OR (STRPOOL_LIBRARYID << LIBRARYID_SHIFT) + +class ACSStringPool +{ +public: + ACSStringPool(); + int AddString(const char *str); + int AddString(FString &str); + const char *GetString(int strnum); + void LockString(int strnum); + void UnlockString(int strnum); + void UnlockAll(); + void MarkString(int strnum); + void LockStringArray(const int *strnum, unsigned int count); + void UnlockStringArray(const int *strnum, unsigned int count); + void MarkStringArray(const int *strnum, unsigned int count); + void MarkStringMap(const FWorldGlobalArray &array); + void PurgeStrings(); + void Clear(); + void Dump() const; + void ReadStrings(PNGHandle *png, DWORD id); + void WriteStrings(FILE *file, DWORD id) const; + +private: + int FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum); + int InsertString(FString &str, unsigned int h, unsigned int bucketnum); + + enum { NUM_BUCKETS = 251 }; + enum { FREE_ENTRY = 0xFFFFFFFE }; // Stored in PoolEntry's Next field + enum { NO_ENTRY = 0xFFFFFFFF }; + enum { MIN_GC_SIZE = 100 }; // Don't auto-collect until there are this many strings + struct PoolEntry + { + FString Str; + unsigned int Hash; + unsigned int Next; + unsigned int LockCount; + }; + TArray Pool; + unsigned int PoolBuckets[NUM_BUCKETS]; + unsigned int FirstFreeEntry; +}; +extern ACSStringPool GlobalACSStrings; + +void P_CollectACSGlobalStrings(); void P_ReadACSVars(PNGHandle *); void P_WriteACSVars(FILE*); void P_ClearACSVars(bool); @@ -204,6 +254,8 @@ public: const char *GetModuleName() const { return ModuleName; } ACSProfileInfo *GetFunctionProfileData(int index) { return index >= 0 && index < NumFunctions ? &FunctionProfileData[index] : NULL; } ACSProfileInfo *GetFunctionProfileData(ScriptFunction *func) { return GetFunctionProfileData((int)(func - (ScriptFunction *)Functions)); } + const char *LookupString (DWORD index) const; + SDWORD *MapVars[NUM_MAPVARS]; static FBehavior *StaticLoadModule (int lumpnum, FileReader * fr=NULL, int len=0); @@ -212,6 +264,9 @@ public: static bool StaticCheckAllGood (); static FBehavior *StaticGetModule (int lib); static void StaticSerializeModuleStates (FArchive &arc); + static void StaticMarkLevelVarStrings(); + static void StaticLockLevelVarStrings(); + static void StaticUnlockLevelVarStrings(); static const ScriptPtr *StaticFindScript (int script, FBehavior *&module); static const char *StaticLookupString (DWORD index); @@ -251,11 +306,14 @@ private: void UnencryptStrings (); void UnescapeStringTable(BYTE *chunkstart, BYTE *datastart, bool haspadding); int FindStringInChunk (DWORD *chunk, const char *varname) const; - const char *LookupString (DWORD index) const; void SerializeVars (FArchive &arc); void SerializeVarSet (FArchive &arc, SDWORD *vars, int max); + void MarkMapVarStrings() const; + void LockMapVarStrings() const; + void UnlockMapVarStrings() const; + friend void ArrangeScriptProfiles(TArray &profiles); friend void ArrangeFunctionProfiles(TArray &profiles); }; @@ -727,6 +785,21 @@ public: inline void SetState (EScriptState newstate) { state = newstate; } inline EScriptState GetState () { return state; } + DLevelScript *GetNext() const { return next; } + + void MarkLocalVarStrings() const + { + GlobalACSStrings.MarkStringArray(localvars, numlocalvars); + } + void LockLocalVarStrings() const + { + GlobalACSStrings.LockStringArray(localvars, numlocalvars); + } + void UnlockLocalVarStrings() const + { + GlobalACSStrings.UnlockStringArray(localvars, numlocalvars); + } + protected: DLevelScript *next, *prev; int script; @@ -804,6 +877,7 @@ private: DLevelScript *Scripts; // List of all running scripts friend class DLevelScript; + friend class FBehavior; }; // The structure used to control scripts between maps From a7c2346b32374270e8fe08e4c54dd1d7292aadc7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 30 May 2013 08:52:29 +0000 Subject: [PATCH 359/387] - added a FloatBobPhase property for DECORATE. Now, if FloatBobPhase is anything but -1 it will be used directly as the initial phase, allowing to define actors that bob in sync. The allowed range of phases is 0 - 63. The main reason for this is that each actor spawn called the pr_spawnmobj RNG just to randomize this value which causes problems with non-interactive actors, in particular GZDoom's dynamic lights. SVN r4296 (trunk) --- src/p_mobj.cpp | 2 +- src/thingdef/thingdef_properties.cpp | 10 ++++++++++ wadsrc/static/actors/actor.txt | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e70f3cc0a..955672c67 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3879,7 +3879,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t actor->SpawnPoint[2] = (actor->z - actor->floorz); } - actor->FloatBobPhase = rng(); // Don't make everything bob in sync + if (actor->FloatBobPhase < 0) actor->FloatBobPhase = rng(); // Don't make everything bob in sync (unless deliberately told to do) if (actor->flags2 & MF2_FLOORCLIP) { actor->AdjustFloorClip (); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index e3461792b..662c868ee 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -624,6 +624,16 @@ DEFINE_PROPERTY(scale, F, Actor) defaults->scaleX = defaults->scaleY = id; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(floatbobphase, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + if (id < -1 || id >= 64) I_Error ("FloatBobPhase must be in range [-1,63]"); + defaults->FloatBobPhase = id; +} + //========================================================================== // //========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 8e76ca374..950521361 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -16,6 +16,7 @@ ACTOR Actor native //: Thinker WallBounceFactor 0.75 BounceCount -1 FloatSpeed 4 + FloatBobPhase -1 // randomly initialize by default Gravity 1 DamageFactor 1.0 PushFactor 0.25 From 0bca41c2022a949d2c6667332364fd16e3c825ec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 30 May 2013 10:18:46 +0000 Subject: [PATCH 360/387] - replaced unused RNGs with pr_damagemobj for consistency checksum. SVN r4297 (trunk) --- src/g_doom/a_lostsoul.cpp | 1 - src/m_random.cpp | 6 ++---- src/p_interaction.cpp | 2 +- src/p_mobj.cpp | 1 - 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp index b6c2ee067..fdc0257cb 100644 --- a/src/g_doom/a_lostsoul.cpp +++ b/src/g_doom/a_lostsoul.cpp @@ -12,7 +12,6 @@ #include "thingdef/thingdef.h" */ - FRandom pr_lost ("LostMissileRange"); FRandom pr_oldsoul ("BetaLostSoul"); // diff --git a/src/m_random.cpp b/src/m_random.cpp index 436b803bc..763410111 100644 --- a/src/m_random.cpp +++ b/src/m_random.cpp @@ -86,9 +86,8 @@ extern FRandom pr_spawnmobj; extern FRandom pr_acs; extern FRandom pr_chase; -extern FRandom pr_lost; -extern FRandom pr_slam; extern FRandom pr_exrandom; +extern FRandom pr_damagemobj; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -245,8 +244,7 @@ DWORD FRandom::StaticSumSeeds () pr_spawnmobj.sfmt.u[0] + pr_spawnmobj.idx + pr_acs.sfmt.u[0] + pr_acs.idx + pr_chase.sfmt.u[0] + pr_chase.idx + - pr_lost.sfmt.u[0] + pr_lost.idx + - pr_slam.sfmt.u[0] + pr_slam.idx; + pr_damagemobj.sfmt.u[0] + pr_damagemobj.idx; } //========================================================================== diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index cadf5a829..96b52e0b7 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -62,7 +62,7 @@ static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); static FRandom pr_killmobj ("ActorDie"); -static FRandom pr_damagemobj ("ActorTakeDamage"); +FRandom pr_damagemobj ("ActorTakeDamage"); static FRandom pr_lightning ("LightningDamage"); static FRandom pr_poison ("PoisonDamage"); static FRandom pr_switcher ("SwitchTarget"); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 955672c67..083ba23fb 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -105,7 +105,6 @@ static FRandom pr_chunk ("Chunk"); static FRandom pr_checkmissilespawn ("CheckMissileSpawn"); static FRandom pr_spawnmissile ("SpawnMissile"); static FRandom pr_missiledamage ("MissileDamage"); - FRandom pr_slam ("SkullSlam"); static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_rockettrail("RocketTrail"); static FRandom pr_uniquetid("UniqueTID"); From dbf68e3f2c39c1a42d5dd31f3a49e149d2ee34d6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 30 May 2013 21:07:29 +0000 Subject: [PATCH 361/387] - fixed the Peasants DECORATE definition. SVN r4298 (trunk) --- wadsrc/static/actors/strife/peasants.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/actors/strife/peasants.txt b/wadsrc/static/actors/strife/peasants.txt index c0e988558..e7bbdadcf 100644 --- a/wadsrc/static/actors/strife/peasants.txt +++ b/wadsrc/static/actors/strife/peasants.txt @@ -12,6 +12,8 @@ ACTOR Peasant : StrifeHumanoid +FRIENDLY -COUNTKILL +NOSPLASHALERT + +FLOORCLIP + +JUSTHIT MinMissileChance 150 MaxStepHeight 16 MaxDropoffHeight 32 @@ -27,7 +29,7 @@ ACTOR Peasant : StrifeHumanoid Loop See: PEAS AABBCCDD 5 A_Wander - Loop + Goto Spawn Melee: PEAS E 10 A_FaceTarget PEAS F 8 A_CustomMeleeAttack(2*random[PeasantAttack](1,5)+2) From ad12be4877e31e6218f62be0e571b3be3da026ab Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 30 May 2013 21:10:54 +0000 Subject: [PATCH 362/387] - fixed inappropriate type for FloatBobPhase property. SVN r4299 (trunk) --- src/thingdef/thingdef_properties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 662c868ee..e745c8f03 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -629,7 +629,7 @@ DEFINE_PROPERTY(scale, F, Actor) //========================================================================== DEFINE_PROPERTY(floatbobphase, F, Actor) { - PROP_FIXED_PARM(id, 0); + PROP_INT_PARM(id, 0); if (id < -1 || id >= 64) I_Error ("FloatBobPhase must be in range [-1,63]"); defaults->FloatBobPhase = id; } From 9e3c6a3cc7f84bbb13060420344d7ba495f9b377 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 31 May 2013 18:10:41 +0000 Subject: [PATCH 363/387] - fixed parameter type for Floatbobphase property. SVN r4300 (trunk) --- src/thingdef/thingdef_properties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index e745c8f03..cf4ef95bb 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -627,7 +627,7 @@ DEFINE_PROPERTY(scale, F, Actor) //========================================================================== // //========================================================================== -DEFINE_PROPERTY(floatbobphase, F, Actor) +DEFINE_PROPERTY(floatbobphase, I, Actor) { PROP_INT_PARM(id, 0); if (id < -1 || id >= 64) I_Error ("FloatBobPhase must be in range [-1,63]"); From 890dc71e0de97ab23fa8a4665043e013bb65c26f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 31 May 2013 22:10:12 +0000 Subject: [PATCH 364/387] . added AFADoomer's patch to set a text highlight color for the list menu. SVN r4301 (trunk) --- src/menu/listmenu.cpp | 5 +++-- src/menu/menu.h | 3 ++- src/menu/menudef.cpp | 14 +++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 5e9fc13d1..53b4fee22 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -495,12 +495,13 @@ bool FListMenuItemSelectable::MouseEvent(int type, int x, int y) // //============================================================================= -FListMenuItemText::FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param) +FListMenuItemText::FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, EColorRange color2, FName child, int param) : FListMenuItemSelectable(x, y, height, child, param) { mText = ncopystring(text); mFont = font; mColor = color; + mColorSelected = color2; mHotkey = hotkey; } @@ -518,7 +519,7 @@ void FListMenuItemText::Drawer(bool selected) if (text != NULL) { if (*text == '$') text = GStrings(text+1); - screen->DrawText(mFont, mColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE); + screen->DrawText(mFont, selected ? mColorSelected : mColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE); } } diff --git a/src/menu/menu.h b/src/menu/menu.h index 4ab3d2e10..1388a33bb 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -393,8 +393,9 @@ class FListMenuItemText : public FListMenuItemSelectable const char *mText; FFont *mFont; EColorRange mColor; + EColorRange mColorSelected; public: - FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, FName child, int param = 0); + FListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, EColorRange color2, FName child, int param = 0); ~FListMenuItemText(); void Drawer(bool selected); int GetWidth(); diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 8167f6592..00af179a5 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -324,7 +324,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) param = sc.Number; } - FListMenuItem *it = new FListMenuItemText(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, text, desc->mFont, desc->mFontColor, action, param); + FListMenuItem *it = new FListMenuItemText(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, param); desc->mItems.Push(it); desc->mYpos += desc->mLinespacing; if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1; @@ -976,7 +976,7 @@ static void BuildEpisodeMenu() else { it = new FListMenuItemText(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut, - AllEpisodes[i].mEpisodeName, ld->mFont, ld->mFontColor, NAME_Skillmenu, i); + AllEpisodes[i].mEpisodeName, ld->mFont, ld->mFontColor, ld->mFontColor2, NAME_Skillmenu, i); } ld->mItems.Push(it); posy += ld->mLinespacing; @@ -1065,7 +1065,7 @@ static void BuildPlayerclassMenu() { // create a dummy item that auto-chooses the default class. FListMenuItemText *it = new FListMenuItemText(0, 0, 0, 'p', "player", - ld->mFont,ld->mFontColor, NAME_Episodemenu, -1000); + ld->mFont,ld->mFontColor, ld->mFontColor2, NAME_Episodemenu, -1000); ld->mAutoselect = ld->mItems.Push(it); success = true; } @@ -1091,7 +1091,7 @@ static void BuildPlayerclassMenu() if (pname != NULL) { FListMenuItemText *it = new FListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, - pname, ld->mFont,ld->mFontColor, NAME_Episodemenu, i); + pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, i); ld->mItems.Push(it); ld->mYpos += ld->mLinespacing; n++; @@ -1101,7 +1101,7 @@ static void BuildPlayerclassMenu() if (n > 1 && !gameinfo.norandomplayerclass) { FListMenuItemText *it = new FListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r', - "$MNU_RANDOM", ld->mFont,ld->mFontColor, NAME_Episodemenu, -1); + "$MNU_RANDOM", ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, -1); ld->mItems.Push(it); } if (n == 0) @@ -1110,7 +1110,7 @@ static void BuildPlayerclassMenu() if (pname != NULL) { FListMenuItemText *it = new FListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname, - pname, ld->mFont,ld->mFontColor, NAME_Episodemenu, 0); + pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, 0); ld->mItems.Push(it); } } @@ -1369,7 +1369,7 @@ void M_StartupSkillMenu(FGameStartup *gs) EColorRange color = (EColorRange)skill.GetTextColor(); if (color == CR_UNTRANSLATED) color = ld->mFontColor; li = new FListMenuItemText(x, y, ld->mLinespacing, skill.Shortcut, - pItemText? *pItemText : skill.MenuName, ld->mFont, color, action, i); + pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, i); } ld->mItems.Push(li); y += ld->mLinespacing; From 8565484e29c42a76f45bcf94688601d168e2efa4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:04:44 +0000 Subject: [PATCH 365/387] - Heretic and Hexen can now have their big fonts overridden by a font named "HBIGFONT". In addition, a font named "BIGFONT" will override the big font for every game. SVN r4302 (trunk) --- src/v_font.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index fad3243e0..d34b08be5 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -2649,7 +2649,12 @@ void V_InitFonts() } if (!(BigFont = FFont::FindFont("BigFont"))) { - if (gameinfo.gametype & GAME_DoomChex) + int lump = Wads.CheckNumForName("BIGFONT"); + if (lump >= 0) + { + BigFont = new FSingleLumpFont("BigFont", lump); + } + else if (gameinfo.gametype & GAME_DoomChex) { BigFont = new FSingleLumpFont ("BigFont", Wads.GetNumForName ("DBIGFONT")); } @@ -2659,7 +2664,15 @@ void V_InitFonts() } else { - BigFont = new FFont ("BigFont", "FONTB%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1); + lump = Wads.CheckNumForName("HBIGFONT"); + if (lump >= 0) + { + BigFont = new FSingleLumpFont("BigFont", lump); + } + else + { + BigFont = new FFont ("BigFont", "FONTB%02u", HU_FONTSTART, HU_FONTSIZE, 1, -1); + } } } if (!(ConFont = FFont::FindFont("ConsoleFont"))) From 53b284fb5d1bdf612cbd049ec6eab944d12569a6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:09:09 +0000 Subject: [PATCH 366/387] - Added Gez's OverridePalette VOXELDEF flag. SVN r4303 (trunk) --- src/r_data/voxels.cpp | 25 ++++++++++++++++++++++++- src/r_data/voxels.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/r_data/voxels.cpp b/src/r_data/voxels.cpp index 693986704..d5ad1fa89 100644 --- a/src/r_data/voxels.cpp +++ b/src/r_data/voxels.cpp @@ -71,13 +71,14 @@ TDeletingArray VoxelDefs; struct VoxelOptions { VoxelOptions() - : DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(ANGLE_90) + : DroppedSpin(0), PlacedSpin(0), Scale(FRACUNIT), AngleOffset(ANGLE_90), OverridePalette(false) {} int DroppedSpin; int PlacedSpin; fixed_t Scale; angle_t AngleOffset; + bool OverridePalette; }; //========================================================================== @@ -408,6 +409,20 @@ void FVoxel::Remap() { RemapVoxelSlabs((kvxslab_t *)Mips[i].SlabData, Mips[i].OffsetX[Mips[i].SizeX], remap); } + RemovePalette(); + } +} + +//========================================================================== +// +// Delete the voxel's built-in palette +// +//========================================================================== + +void FVoxel::RemovePalette() +{ + if (Palette != NULL) + { delete [] Palette; Palette = NULL; } @@ -518,6 +533,10 @@ static void VOX_ReadOptions(FScanner &sc, VoxelOptions &opts) } opts.AngleOffset = ANGLE_90 + angle_t(sc.Float * ANGLE_180 / 180.0); } + else if (sc.Compare("overridepalette")) + { + opts.OverridePalette = true; + } else { sc.ScriptMessage("Unknown voxel option '%s'\n", sc.String); @@ -603,6 +622,10 @@ void R_InitVoxels() sc.SetCMode(false); if (voxeldata != NULL && vsprites.Size() != 0) { + if (opts.OverridePalette) + { + voxeldata->RemovePalette(); + } FVoxelDef *def = new FVoxelDef; def->Voxel = voxeldata; diff --git a/src/r_data/voxels.h b/src/r_data/voxels.h index 90b57e0af..9dce7820b 100644 --- a/src/r_data/voxels.h +++ b/src/r_data/voxels.h @@ -42,6 +42,7 @@ struct FVoxel FVoxel(); ~FVoxel(); void Remap(); + void RemovePalette(); }; struct FVoxelDef From 2191b4bfa6c9ac10e540f0b308565a527f11de4e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:19:18 +0000 Subject: [PATCH 367/387] - Added ACS function LineAttack via Ryan Cordell. SVN r4304 (trunk) --- src/p_acs.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 71c0f53f3..57bcc07c2 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4112,6 +4112,7 @@ enum EACSFunctions ACSF_SetCVarString, ACSF_GetUserCVarString, ACSF_SetUserCVarString, + ACSF_LineAttack, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4853,6 +4854,33 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } break; + //[RC] A bullet firing function for ACS. Thanks to DavidPH. + case ACSF_LineAttack: + { + fixed_t angle = args[1] << FRACBITS; + fixed_t pitch = args[2] << FRACBITS; + int damage = args[3]; + FName pufftype = argCount > 4 && args[4]? FName(FBehavior::StaticLookupString(args[4])) : NAME_BulletPuff; + FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None; + fixed_t range = argCount > 6 && args[6]? args[6] : 0x7FFFFFFF; + + if (args[0] == 0) + { + P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype); + } + else + { + AActor *source; + FActorIterator it(args[0]); + + while ((source = it.Next()) != NULL) + { + P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype); + } + } + } + break; + default: break; } From 2d13a45773621ae42cb29b6eabe6e5ed45ba47d4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:23:27 +0000 Subject: [PATCH 368/387] - Added read access to an actor's melee range from DECORATE and ACS, via Blue Shadow. SVN r4305 (trunk) --- src/p_acs.cpp | 3 +++ src/thingdef/thingdef_expression.cpp | 1 + wadsrc/static/actors/actor.txt | 1 + 3 files changed, 5 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 57bcc07c2..2ac34ebc9 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3479,6 +3479,7 @@ enum APROP_Height = 35, APROP_Radius = 36, APROP_ReactionTime = 37, + APROP_MeleeRange = 38, }; // These are needed for ACS's APROP_RenderStyle @@ -3765,6 +3766,7 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Height: return actor->height; case APROP_Radius: return actor->radius; case APROP_ReactionTime:return actor->reactiontime; + case APROP_MeleeRange: return actor->meleerange; default: return 0; } @@ -3808,6 +3810,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Height: case APROP_Radius: case APROP_ReactionTime: + case APROP_MeleeRange: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d217b9555..c578ddb2b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -87,6 +87,7 @@ DEFINE_MEMBER_VARIABLE(stamina, AActor) DEFINE_MEMBER_VARIABLE(height, AActor) DEFINE_MEMBER_VARIABLE(radius, AActor) DEFINE_MEMBER_VARIABLE(reactiontime, AActor) +DEFINE_MEMBER_VARIABLE(meleerange, AActor) //========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 950521361..12c625596 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -60,6 +60,7 @@ ACTOR Actor native //: Thinker native fixed_t height; native fixed_t radius; native int reactiontime; + native fixed_t meleerange; // Meh, MBF redundant functions. Only for DeHackEd support. action native A_Turn(float angle = 0); From 1a67e6fa5d63787fd7f393a673a0a140227e988c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:43:36 +0000 Subject: [PATCH 369/387] - Added PlaySound and StopSound functions for ACS. They are mostly analogous to their DECORATE counterparts except that (1) PlaySound requires you to specify a sound instead of defaulting to "weapons/pistol", and (2) StopSound defaults to CHAN_BODY instead of CHAN_VOICE. SVN r4306 (trunk) --- src/p_acs.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2ac34ebc9..a594d0179 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4116,6 +4116,8 @@ enum EACSFunctions ACSF_GetUserCVarString, ACSF_SetUserCVarString, ACSF_LineAttack, + ACSF_PlaySound, + ACSF_StopSound, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4884,6 +4886,62 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } break; + case ACSF_PlaySound: + // PlaySound(tid, "SoundName", channel, volume, looping, attenuation) + { + const char *lookup = FBehavior::StaticLookupString(args[1]); + if (lookup != NULL) + { + FActorIterator it(args[0]); + AActor *spot; + + FSoundID sid(lookup); + int chan = argCount > 2 ? args[2] : CHAN_BODY; + float vol = argCount > 3 ? FIXED2FLOAT(args[3]) : 1.f; + INTBOOL looping = argCount > 4 ? args[4] : false; + float atten = argCount > 5 ? FIXED2FLOAT(args[5]) : ATTN_NORM; + + if (args[0] == 0) + { + spot = activator; + goto doplaysound; + } + while ((spot = it.Next()) != NULL) + { +doplaysound: if (!looping) + { + S_Sound(spot, chan, sid, vol, atten); + } + else if (!S_IsActorPlayingSomething(spot, chan, sid)) + { + S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + } + } + } + } + break; + + case ACSF_StopSound: + { + int chan = argCount > 1 ? args[1] : CHAN_BODY; + + if (args[0] == 0) + { + S_StopSound(activator, chan); + } + else + { + FActorIterator it(args[0]); + AActor *spot; + + while ((spot = it.Next()) != NULL) + { + S_StopSound(spot, chan); + } + } + } + break; + default: break; } From 26d2d7402422eafe22579d84a7c9963b0f2b8c74 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 02:51:14 +0000 Subject: [PATCH 370/387] - GetActorProperty now works with the string properties that were formerly restricted to CheckActorProperty. SVN r4307 (trunk) --- src/p_acs.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a594d0179..6ccf7339d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3768,6 +3768,14 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_ReactionTime:return actor->reactiontime; case APROP_MeleeRange: return actor->meleerange; + case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound); + case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound); + case APROP_PainSound: return GlobalACSStrings.AddString(actor->PainSound); + case APROP_DeathSound: return GlobalACSStrings.AddString(actor->DeathSound); + case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound); + case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies()); + case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag()); + default: return 0; } } @@ -3825,7 +3833,8 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Dormant: return (GetActorProperty(tid, property) == (!!value)); - // Strings are not covered by GetActorProperty, so make the check here + // Strings are covered by GetActorProperty, but they're fairly + // heavy-duty, so make the check here. case APROP_SeeSound: string = actor->SeeSound; break; case APROP_AttackSound: string = actor->AttackSound; break; case APROP_PainSound: string = actor->PainSound; break; From d40d7f2e77971277bf3d4637a5606a5f2912417b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 Jun 2013 12:03:15 +0000 Subject: [PATCH 371/387] - fixed signed-ness issue with FloatBobPhase. SVN r4310 (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 083ba23fb..aff990907 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3878,7 +3878,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t actor->SpawnPoint[2] = (actor->z - actor->floorz); } - if (actor->FloatBobPhase < 0) actor->FloatBobPhase = rng(); // Don't make everything bob in sync (unless deliberately told to do) + if (actor->FloatBobPhase == (BYTE)-1) actor->FloatBobPhase = rng(); // Don't make everything bob in sync (unless deliberately told to do) if (actor->flags2 & MF2_FLOORCLIP) { actor->AdjustFloorClip (); From 037477a20b8422bcf3e809c85389489e3685f210 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 17:07:24 +0000 Subject: [PATCH 372/387] - Added more string functions to ACS: * The standard C functions strcmp and stricmp (aka strcasecmp), which double up as strncmp and strnicmp if you pass a third argument. * The BASIC-like functions strleft, strright, and strmid, which extract parts of a string to create a new string. SVN r4313 (trunk) --- src/p_acs.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6ccf7339d..18ab347eb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4127,6 +4127,11 @@ enum EACSFunctions ACSF_LineAttack, ACSF_PlaySound, ACSF_StopSound, + ACSF_strcmp, + ACSF_stricmp, + ACSF_StrLeft, + ACSF_StrRight, + ACSF_StrMid, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4951,6 +4956,75 @@ doplaysound: if (!looping) } break; + case ACSF_strcmp: + case ACSF_stricmp: + if (argCount >= 2) + { + const char *a, *b; + a = FBehavior::StaticLookupString(args[0]); + b = FBehavior::StaticLookupString(args[1]); + + // Don't crash on invalid strings. + if (a == NULL) a = ""; + if (b == NULL) b = ""; + + if (argCount > 2) + { + int n = args[2]; + return (funcIndex == ACSF_strcmp) ? strncmp(a, b, n) : strnicmp(a, b, n); + } + else + { + return (funcIndex == ACSF_strcmp) ? strcmp(a, b) : stricmp(a, b); + } + } + break; + + case ACSF_StrLeft: + case ACSF_StrRight: + if (argCount >= 2) + { + const char *oldstr = FBehavior::StaticLookupString(args[0]); + if (oldstr == NULL || *oldstr == '\0') + { + return GlobalACSStrings.AddString(""); + } + size_t oldlen = strlen(oldstr); + size_t newlen = args[1]; + + if (oldlen < newlen) + { + newlen = oldlen; + } + FString newstr(funcIndex == ACSF_StrLeft ? oldstr : oldstr + oldlen - newlen, newlen); + return GlobalACSStrings.AddString(newstr); + } + break; + + case ACSF_StrMid: + if (argCount >= 3) + { + const char *oldstr = FBehavior::StaticLookupString(args[0]); + if (oldstr == NULL || *oldstr == '\0') + { + return GlobalACSStrings.AddString(""); + } + size_t oldlen = strlen(oldstr); + size_t pos = args[1]; + size_t newlen = args[2]; + + if (pos >= oldlen) + { + return GlobalACSStrings.AddString(""); + } + if (pos + newlen > oldlen || pos + newlen < pos) + { + newlen = oldlen - pos; + } + return GlobalACSStrings.AddString(FString(oldstr + pos, newlen)); + } + break; + default: break; } From e9702fc43dc6678c9b57a9e946b411dcd679bec9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 17:13:15 +0000 Subject: [PATCH 373/387] - Clean up excess code around a few calls to SingleActorFromTID(), since that function is already designed specifically to handle the case where tid is 0. SVN r4315 (trunk) --- src/p_acs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 18ab347eb..cb7da1a53 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4598,7 +4598,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) FName varname(FBehavior::StaticLookupString(args[1]), true); if (varname != NAME_None) { - AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); + AActor *a = SingleActorFromTID(args[0], activator); return a != NULL ? GetUserVariable(a, varname, 0) : 0; } return 0; @@ -4637,7 +4637,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) FName varname(FBehavior::StaticLookupString(args[1]), true); if (varname != NAME_None) { - AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); + AActor *a = SingleActorFromTID(args[0], activator); return a != NULL ? GetUserVariable(a, varname, args[2]) : 0; } return 0; @@ -4649,7 +4649,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_CheckActorClass: { - AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); + AActor *a = SingleActorFromTID(args[0], activator); return a == NULL ? false : a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1])); } From 19eb09f9f7adf9c36aab2ec2a01ec99b51fa5517 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 17:17:15 +0000 Subject: [PATCH 374/387] - Added GetActorClass and GetWeapon functions to ACS. SVN r4316 (trunk) --- src/p_acs.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index cb7da1a53..bd1f18484 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4132,6 +4132,8 @@ enum EACSFunctions ACSF_StrLeft, ACSF_StrRight, ACSF_StrMid, + ACSF_GetActorClass, + ACSF_GetWeapon, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4653,6 +4655,12 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) return a == NULL ? false : a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1])); } + case ACSF_GetActorClass: + { + AActor *a = SingleActorFromTID(args[0], activator); + return GlobalACSStrings.AddString(a == NULL ? "None" : a->GetClass()->TypeName.GetChars()); + } + case ACSF_SoundSequenceOnActor: { const char *seqname = FBehavior::StaticLookupString(args[1]); @@ -5025,6 +5033,17 @@ doplaysound: if (!looping) } break; + case ACSF_GetWeapon: + if (activator == NULL || activator->player == NULL || // Non-players do not have weapons + activator->player->ReadyWeapon == NULL) + { + return GlobalACSStrings.AddString("None"); + } + else + { + return GlobalACSStrings.AddString(activator->player->ReadyWeapon->GetClass()->TypeName.GetChars()); + } + default: break; } From 1b9c71b2520a2f5ffc3cb024bd7ccf8aeab52350 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 1 Jun 2013 17:46:50 +0000 Subject: [PATCH 375/387] - Added S_ChangeSoundVolume() to change the volume of an already playing sound, accessible through the new ACS function SoundVolume. SVN r4318 (trunk) --- src/p_acs.cpp | 24 ++++++++++++++++++++++++ src/s_sound.cpp | 24 +++++++++++++++++++++++- src/s_sound.h | 3 +++ src/sound/fmodsound.cpp | 14 ++++++++++++++ src/sound/fmodsound.h | 3 +++ src/sound/i_sound.cpp | 3 +++ src/sound/i_sound.h | 3 +++ 7 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index bd1f18484..99ddf7780 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4134,6 +4134,7 @@ enum EACSFunctions ACSF_StrMid, ACSF_GetActorClass, ACSF_GetWeapon, + ACSF_SoundVolume, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4964,6 +4965,29 @@ doplaysound: if (!looping) } break; + case ACSF_SoundVolume: + // SoundVolume(int tid, int channel, fixed volume) + { + int chan = args[1]; + float volume = FIXED2FLOAT(args[2]); + + if (args[0] == 0) + { + S_ChangeSoundVolume(activator, chan, volume); + } + else + { + FActorIterator it(args[0]); + AActor *spot; + + while ((spot = it.Next()) != NULL) + { + S_ChangeSoundVolume(spot, chan, volume); + } + } + } + break; + case ACSF_strcmp: case ACSF_stricmp: if (argCount >= 2) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 3da346bf3..2626c2b82 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1592,6 +1592,29 @@ void S_RelinkSound (AActor *from, AActor *to) } } + +//========================================================================== +// +// S_ChangeSoundVolume +// +//========================================================================== + +bool S_ChangeSoundVolume(AActor *actor, int channel, float volume) +{ + for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) + { + if (chan->SourceType == SOURCE_Actor && + chan->Actor == actor && + (chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE))) + { + GSnd->ChannelVolume(chan, volume); + chan->Volume = volume; + return true; + } + } + return false; +} + //========================================================================== // // S_GetSoundPlayingInfo @@ -2136,7 +2159,6 @@ void S_StopChannel(FSoundChan *chan) } } - //========================================================================== // // (FArchive &) << (FSoundID &) diff --git a/src/s_sound.h b/src/s_sound.h index 2f4f68647..346e51ce1 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -303,6 +303,9 @@ bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id); bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id); +// Change a playing sound's volume +bool S_ChangeSoundVolume(AActor *actor, int channel, float volume); + // Moves all sounds from one mobj to another void S_RelinkSound (AActor *from, AActor *to); diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 5abb67e76..133fc2406 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -2053,6 +2053,20 @@ void FMODSoundRenderer::StopChannel(FISoundChannel *chan) } } +//========================================================================== +// +// FMODSoundRenderer :: ChannelVolume +// +//========================================================================== + +void FMODSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) +{ + if (chan != NULL && chan->SysChannel != NULL) + { + ((FMOD::Channel *)chan->SysChannel)->setVolume(volume); + } +} + //========================================================================== // // FMODSoundRenderer :: GetPosition diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 99d627e5f..93b70ce87 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -33,6 +33,9 @@ public: // Stops a sound channel. void StopChannel (FISoundChannel *chan); + // Changes a channel's volume. + void ChannelVolume (FISoundChannel *chan, float volume); + // Marks a channel's start time without actually playing it. void MarkStartTime (FISoundChannel *chan); diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 0fe68a25c..c95b0221f 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -150,6 +150,9 @@ public: void StopChannel(FISoundChannel *chan) { } + void ChannelVolume(FISoundChannel *, float) + { + } // Streaming sounds. SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index c905678ad..adce8796b 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -110,6 +110,9 @@ public: // Stops a sound channel. virtual void StopChannel (FISoundChannel *chan) = 0; + // Changes a channel's volume. + virtual void ChannelVolume (FISoundChannel *chan, float volume) = 0; + // Marks a channel's start time without actually playing it. virtual void MarkStartTime (FISoundChannel *chan) = 0; From 45c1787203a78d557b86dcc5fd1a82476a82dc75 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 2 Jun 2013 23:17:46 +0000 Subject: [PATCH 376/387] - Fixed: Don't transform map variable string initializers into global string table entries if they don't really exist in the source string table. SVN r4321 (trunk) --- src/p_acs.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 99ddf7780..8f00bad73 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1881,7 +1881,11 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) for (DWORD i = 0; i < chunk[1]/4; ++i) { // MapVarStore[chunk[i+2]] |= LibraryID; - MapVarStore[chunk[i+2]] = GlobalACSStrings.AddString(LookupString(MapVarStore[chunk[i+2]])); + const char *str = LookupString(MapVarStore[chunk[i+2]]); + if (str != NULL) + { + MapVarStore[chunk[i+2]] = GlobalACSStrings.AddString(str); + } } } @@ -1897,7 +1901,11 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) for (int j = ArrayStore[arraynum].ArraySize; j > 0; --j, ++elems) { // *elems |= LibraryID; - *elems = GlobalACSStrings.AddString(LookupString(*elems)); + const char *str = LookupString(*elems); + if (str != NULL) + { + *elems = GlobalACSStrings.AddString(str); + } } } } @@ -1927,7 +1935,11 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) } else if (*chunkData == 1) { - *elems = GlobalACSStrings.AddString(LookupString(*elems)); + const char *str = LookupString(*elems); + if (str != NULL) + { + *elems = GlobalACSStrings.AddString(str); + } } } i += 4+ArrayStore[arraynum].ArraySize; From aa40801015b7eceb16134bc6e28162a25d756ae0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 2 Jun 2013 23:58:29 +0000 Subject: [PATCH 377/387] - Fixed: When garbage collecting ACS strings, the active values on the ACS stack also need to be included in the mark phase. SVN r4322 (trunk) --- src/p_acs.cpp | 95 +++++++++++++++++++++++++++------------------------ src/p_acs.h | 12 +++---- 2 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8f00bad73..668a2bb5f 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -198,6 +198,7 @@ FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; // strings without growing. A string is concidered in use if any value // in any of these variable blocks contains a valid ID in the global string // table: +// * The active area of the ACS stack // * All running scripts' local variables // * All map variables // * All world variables @@ -253,7 +254,7 @@ void ACSStringPool::Clear() // //============================================================================ -int ACSStringPool::AddString(const char *str) +int ACSStringPool::AddString(const char *str, const SDWORD *stack, int stackdepth) { size_t len = strlen(str); unsigned int h = SuperFastHash(str, len); @@ -264,10 +265,10 @@ int ACSStringPool::AddString(const char *str) return i | STRPOOL_LIBRARYID_OR; } FString fstr(str); - return InsertString(fstr, h, bucketnum); + return InsertString(fstr, h, bucketnum, stack, stackdepth); } -int ACSStringPool::AddString(FString &str) +int ACSStringPool::AddString(FString &str, const SDWORD *stack, int stackdepth) { unsigned int h = SuperFastHash(str.GetChars(), str.Len()); unsigned int bucketnum = h % NUM_BUCKETS; @@ -276,7 +277,7 @@ int ACSStringPool::AddString(FString &str) { return i | STRPOOL_LIBRARYID_OR; } - return InsertString(str, h, bucketnum); + return InsertString(str, h, bucketnum, stack, stackdepth); } //============================================================================ @@ -540,7 +541,7 @@ int ACSStringPool::FindString(const char *str, size_t len, unsigned int h, unsig // //============================================================================ -int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucketnum) +int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucketnum, const SDWORD *stack, int stackdepth) { if (Pool.Size() >= STRPOOL_LIBRARYID) { @@ -549,7 +550,7 @@ int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucke unsigned int index = FirstFreeEntry; if (index >= MIN_GC_SIZE && index == Pool.Max()) { // We will need to grow the array. Try a garbage collection first. - P_CollectACSGlobalStrings(); + P_CollectACSGlobalStrings(stack, stackdepth); } if (index == Pool.Size()) { // There were no free entries; make a new one. @@ -713,8 +714,12 @@ void P_MarkGlobalVarStrings() // //============================================================================ -void P_CollectACSGlobalStrings() +void P_CollectACSGlobalStrings(const SDWORD *stack, int stackdepth) { + if (stack != NULL && stackdepth != 0) + { + GlobalACSStrings.MarkStringArray(stack, stackdepth); + } FBehavior::StaticMarkLevelVarStrings(); P_MarkWorldVarStrings(); P_MarkGlobalVarStrings(); @@ -724,7 +729,7 @@ void P_CollectACSGlobalStrings() #ifdef _DEBUG CCMD(acsgc) { - P_CollectACSGlobalStrings(); + P_CollectACSGlobalStrings(NULL, 0); } CCMD(globstr) { @@ -1884,7 +1889,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) const char *str = LookupString(MapVarStore[chunk[i+2]]); if (str != NULL) { - MapVarStore[chunk[i+2]] = GlobalACSStrings.AddString(str); + MapVarStore[chunk[i+2]] = GlobalACSStrings.AddString(str, NULL, 0); } } } @@ -1904,7 +1909,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) const char *str = LookupString(*elems); if (str != NULL) { - *elems = GlobalACSStrings.AddString(str); + *elems = GlobalACSStrings.AddString(str, NULL, 0); } } } @@ -1938,7 +1943,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len) const char *str = LookupString(*elems); if (str != NULL) { - *elems = GlobalACSStrings.AddString(str); + *elems = GlobalACSStrings.AddString(str, NULL, 0); } } } @@ -3713,7 +3718,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) } } -int DLevelScript::GetActorProperty (int tid, int property) +int DLevelScript::GetActorProperty (int tid, int property, const SDWORD *stack, int stackdepth) { AActor *actor = SingleActorFromTID (tid, activator); @@ -3780,13 +3785,13 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_ReactionTime:return actor->reactiontime; case APROP_MeleeRange: return actor->meleerange; - case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound); - case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound); - case APROP_PainSound: return GlobalACSStrings.AddString(actor->PainSound); - case APROP_DeathSound: return GlobalACSStrings.AddString(actor->DeathSound); - case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound); - case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies()); - case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag()); + case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound, stack, stackdepth); + case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound, stack, stackdepth); + case APROP_PainSound: return GlobalACSStrings.AddString(actor->PainSound, stack, stackdepth); + case APROP_DeathSound: return GlobalACSStrings.AddString(actor->DeathSound, stack, stackdepth); + case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound, stack, stackdepth); + case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies(), stack, stackdepth); + case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag(), stack, stackdepth); default: return 0; } @@ -3831,7 +3836,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Radius: case APROP_ReactionTime: case APROP_MeleeRange: - return (GetActorProperty(tid, property) == value); + return (GetActorProperty(tid, property, NULL, 0) == value); // Boolean values need to compare to a binary version of value case APROP_Ambush: @@ -3843,7 +3848,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Notarget: case APROP_Notrigger: case APROP_Dormant: - return (GetActorProperty(tid, property) == (!!value)); + return (GetActorProperty(tid, property, NULL, 0) == (!!value)); // Strings are covered by GetActorProperty, but they're fairly // heavy-duty, so make the check here. @@ -4285,14 +4290,14 @@ static void DoSetCVar(FBaseCVar *cvar, int value, bool is_string, bool force=fal } // Converts floating- to fixed-point as required. -static int DoGetCVar(FBaseCVar *cvar, bool is_string) +static int DoGetCVar(FBaseCVar *cvar, bool is_string, const SDWORD *stack, int stackdepth) { UCVarValue val; if (is_string) { val = cvar->GetGenericRep(CVAR_String); - return GlobalACSStrings.AddString(val.String); + return GlobalACSStrings.AddString(val.String, stack, stackdepth); } else if (cvar->GetRealType() == CVAR_Float) { @@ -4306,7 +4311,7 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string) } } -static int GetUserCVar(int playernum, const char *cvarname, bool is_string) +static int GetUserCVar(int playernum, const char *cvarname, bool is_string, const SDWORD *stack, int stackdepth) { if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) { @@ -4318,10 +4323,10 @@ static int GetUserCVar(int playernum, const char *cvarname, bool is_string) { return 0; } - return DoGetCVar(cvar, is_string); + return DoGetCVar(cvar, is_string, stack, stackdepth); } -static int GetCVar(AActor *activator, const char *cvarname, bool is_string) +static int GetCVar(AActor *activator, const char *cvarname, bool is_string, const SDWORD *stack, int stackdepth) { FBaseCVar *cvar = FindCVar(cvarname, NULL); // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. @@ -4338,9 +4343,9 @@ static int GetCVar(AActor *activator, const char *cvarname, bool is_string) { return 0; } - return GetUserCVar(int(activator->player - players), cvarname, is_string); + return GetUserCVar(int(activator->player - players), cvarname, is_string, stack, stackdepth); } - return DoGetCVar(cvar, is_string); + return DoGetCVar(cvar, is_string, stack, stackdepth); } } @@ -4395,7 +4400,7 @@ static int SetCVar(AActor *activator, const char *cvarname, int value, bool is_s return 1; } -int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) +int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth) { AActor *actor; switch(funcIndex) @@ -4671,7 +4676,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_GetActorClass: { AActor *a = SingleActorFromTID(args[0], activator); - return GlobalACSStrings.AddString(a == NULL ? "None" : a->GetClass()->TypeName.GetChars()); + return GlobalACSStrings.AddString(a == NULL ? "None" : a->GetClass()->TypeName.GetChars(), stack, stackdepth); } case ACSF_SoundSequenceOnActor: @@ -4848,7 +4853,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_GetCVarString: if (argCount == 1) { - return GetCVar(activator, FBehavior::StaticLookupString(args[0]), true); + return GetCVar(activator, FBehavior::StaticLookupString(args[0]), true, stack, stackdepth); } break; @@ -4869,14 +4874,14 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_GetUserCVar: if (argCount == 2) { - return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), false); + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), false, stack, stackdepth); } break; case ACSF_GetUserCVarString: if (argCount == 2) { - return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), true); + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), true, stack, stackdepth); } break; @@ -5031,7 +5036,7 @@ doplaysound: if (!looping) const char *oldstr = FBehavior::StaticLookupString(args[0]); if (oldstr == NULL || *oldstr == '\0') { - return GlobalACSStrings.AddString(""); + return GlobalACSStrings.AddString("", stack, stackdepth); } size_t oldlen = strlen(oldstr); size_t newlen = args[1]; @@ -5041,7 +5046,7 @@ doplaysound: if (!looping) newlen = oldlen; } FString newstr(funcIndex == ACSF_StrLeft ? oldstr : oldstr + oldlen - newlen, newlen); - return GlobalACSStrings.AddString(newstr); + return GlobalACSStrings.AddString(newstr, stack, stackdepth); } break; @@ -5051,7 +5056,7 @@ doplaysound: if (!looping) const char *oldstr = FBehavior::StaticLookupString(args[0]); if (oldstr == NULL || *oldstr == '\0') { - return GlobalACSStrings.AddString(""); + return GlobalACSStrings.AddString("", stack, stackdepth); } size_t oldlen = strlen(oldstr); size_t pos = args[1]; @@ -5059,13 +5064,13 @@ doplaysound: if (!looping) if (pos >= oldlen) { - return GlobalACSStrings.AddString(""); + return GlobalACSStrings.AddString("", stack, stackdepth); } if (pos + newlen > oldlen || pos + newlen < pos) { newlen = oldlen - pos; } - return GlobalACSStrings.AddString(FString(oldstr + pos, newlen)); + return GlobalACSStrings.AddString(FString(oldstr + pos, newlen), stack, stackdepth); } break; @@ -5073,11 +5078,11 @@ doplaysound: if (!looping) if (activator == NULL || activator->player == NULL || // Non-players do not have weapons activator->player->ReadyWeapon == NULL) { - return GlobalACSStrings.AddString("None"); + return GlobalACSStrings.AddString("None", stack, stackdepth); } else { - return GlobalACSStrings.AddString(activator->player->ReadyWeapon->GetClass()->TypeName.GetChars()); + return GlobalACSStrings.AddString(activator->player->ReadyWeapon->GetClass()->TypeName.GetChars(), stack, stackdepth); } default: @@ -5231,7 +5236,7 @@ int DLevelScript::RunScript () case PCD_TAGSTRING: //Stack[sp-1] |= activeBehavior->GetLibraryID(); - Stack[sp-1] = GlobalACSStrings.AddString(activeBehavior->LookupString(Stack[sp-1])); + Stack[sp-1] = GlobalACSStrings.AddString(activeBehavior->LookupString(Stack[sp-1]), Stack, sp); break; case PCD_PUSHNUMBER: @@ -5429,7 +5434,7 @@ int DLevelScript::RunScript () int argCount = NEXTBYTE; int funcIndex = NEXTSHORT; - int retval = CallFunction(argCount, funcIndex, &STACK(argCount)); + int retval = CallFunction(argCount, funcIndex, &STACK(argCount), Stack, sp); sp -= argCount-1; STACK(1) = retval; } @@ -7865,7 +7870,7 @@ scriptwait: break; case PCD_GETACTORPROPERTY: - STACK(2) = GetActorProperty (STACK(2), STACK(1)); + STACK(2) = GetActorProperty (STACK(2), STACK(1), Stack, sp); sp -= 1; break; @@ -7947,7 +7952,7 @@ scriptwait: break; case PCD_GETCVAR: - STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1)), false); + STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1)), false, Stack, sp); break; case PCD_SETHUDSIZE: @@ -8331,7 +8336,7 @@ scriptwait: case PCD_SAVESTRING: // Saves the string { - PushToStack(GlobalACSStrings.AddString(work)); + PushToStack(GlobalACSStrings.AddString(work, Stack, sp)); STRINGBUILDER_FINISH(work); } break; diff --git a/src/p_acs.h b/src/p_acs.h index c9c999556..1a0fb3f60 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -80,8 +80,8 @@ class ACSStringPool { public: ACSStringPool(); - int AddString(const char *str); - int AddString(FString &str); + int AddString(const char *str, const SDWORD *stack, int stackdepth); + int AddString(FString &str, const SDWORD *stack, int stackdepth); const char *GetString(int strnum); void LockString(int strnum); void UnlockString(int strnum); @@ -99,7 +99,7 @@ public: private: int FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum); - int InsertString(FString &str, unsigned int h, unsigned int bucketnum); + int InsertString(FString &str, unsigned int h, unsigned int bucketnum, const SDWORD *stack, int stackdepth); enum { NUM_BUCKETS = 251 }; enum { FREE_ENTRY = 0xFFFFFFFE }; // Stored in PoolEntry's Next field @@ -118,7 +118,7 @@ private: }; extern ACSStringPool GlobalACSStrings; -void P_CollectACSGlobalStrings(); +void P_CollectACSGlobalStrings(const SDWORD *stack, int stackdepth); void P_ReadACSVars(PNGHandle *); void P_WriteACSVars(FILE*); void P_ClearACSVars(bool); @@ -833,7 +833,7 @@ protected: int DoSpawnSpot (int type, int spot, int tid, int angle, bool forced); int DoSpawnSpotFacing (int type, int spot, int tid, bool forced); int DoClassifyActor (int tid); - int CallFunction(int argCount, int funcIndex, SDWORD *args); + int CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth); void DoFadeTo (int r, int g, int b, int a, fixed_t time); void DoFadeRange (int r1, int g1, int b1, int a1, @@ -841,7 +841,7 @@ protected: void DoSetFont (int fontnum); void SetActorProperty (int tid, int property, int value); void DoSetActorProperty (AActor *actor, int property, int value); - int GetActorProperty (int tid, int property); + int GetActorProperty (int tid, int property, const SDWORD *stack, int stackdepth); int CheckActorProperty (int tid, int property, int value); int GetPlayerInput (int playernum, int inputnum); From 44a9c75b6b4df2882ba2b4c3ce46ede152599a74 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 3 Jun 2013 00:09:46 +0000 Subject: [PATCH 378/387] - Added ACS function PlayActorSound. It's functionally equivalent to PlaySound, except instead of taking an actual sound name as its second parameter, it selects the sound to play based on the actor playing the sound and the selector passed as the second parameter. SVN r4323 (trunk) --- src/p_acs.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 668a2bb5f..e982d6993 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4080,6 +4080,38 @@ int DLevelScript::DoClassifyActor(int tid) return classify; } +enum +{ + SOUND_See, + SOUND_Attack, + SOUND_Pain, + SOUND_Death, + SOUND_Active, + SOUND_Use, + SOUND_Bounce, + SOUND_WallBounce, + SOUND_CrushPain, + SOUND_Howl, +}; + +static FSoundID GetActorSound(const AActor *actor, int soundtype) +{ + switch (soundtype) + { + case SOUND_See: return actor->SeeSound; + case SOUND_Attack: return actor->AttackSound; + case SOUND_Pain: return actor->PainSound; + case SOUND_Death: return actor->DeathSound; + case SOUND_Active: return actor->ActiveSound; + case SOUND_Use: return actor->UseSound; + case SOUND_Bounce: return actor->BounceSound; + case SOUND_WallBounce: return actor->WallBounceSound; + case SOUND_CrushPain: return actor->CrushPainSound; + case SOUND_Howl: return actor->GetClass()->Meta.GetMetaInt(AMETA_HowlSound); + default: return 0; + } +} + enum EACSFunctions { ACSF_GetLineUDMFInt=1, @@ -4152,6 +4184,7 @@ enum EACSFunctions ACSF_GetActorClass, ACSF_GetWeapon, ACSF_SoundVolume, + ACSF_PlayActorSound, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4927,15 +4960,24 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const break; case ACSF_PlaySound: + case ACSF_PlayActorSound: // PlaySound(tid, "SoundName", channel, volume, looping, attenuation) { - const char *lookup = FBehavior::StaticLookupString(args[1]); - if (lookup != NULL) + FSoundID sid; + + if (funcIndex == ACSF_PlaySound) + { + const char *lookup = FBehavior::StaticLookupString(args[1]); + if (lookup != NULL) + { + sid = lookup; + } + } + if (sid != 0 || funcIndex == ACSF_PlayActorSound) { FActorIterator it(args[0]); AActor *spot; - FSoundID sid(lookup); int chan = argCount > 2 ? args[2] : CHAN_BODY; float vol = argCount > 3 ? FIXED2FLOAT(args[3]) : 1.f; INTBOOL looping = argCount > 4 ? args[4] : false; @@ -4948,13 +4990,20 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const } while ((spot = it.Next()) != NULL) { -doplaysound: if (!looping) +doplaysound: if (funcIndex == ACSF_PlayActorSound) { - S_Sound(spot, chan, sid, vol, atten); + sid = GetActorSound(spot, args[1]); } - else if (!S_IsActorPlayingSomething(spot, chan, sid)) + if (sid != 0) { - S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + if (!looping) + { + S_Sound(spot, chan, sid, vol, atten); + } + else if (!S_IsActorPlayingSomething(spot, chan, sid)) + { + S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + } } } } From c4b73353120053a2b32e8fff1fd587f04c22e9d6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 3 Jun 2013 07:14:42 +0000 Subject: [PATCH 379/387] - fixed: UDMF's Doom namespace needs to retain Boom's sector special flags. - fixed: UDMF's ZDoomTranslated namespace needs to set the DUMMYSWITCHES flag so that it remains compatible with Doom-format ZDoom maps. SVN r4325 (trunk) --- src/p_udmf.cpp | 1 + wadsrc/static/xlat/doom_base.txt | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 6a38708ea..c1d18fd4c 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1542,6 +1542,7 @@ public: isTranslated = false; break; case NAME_ZDoomTranslated: + level.flags2 |= LEVEL2_DUMMYSWITCHES; namespace_bits = Zdt; break; case NAME_Vavoom: diff --git a/wadsrc/static/xlat/doom_base.txt b/wadsrc/static/xlat/doom_base.txt index e75cd4109..351784da7 100644 --- a/wadsrc/static/xlat/doom_base.txt +++ b/wadsrc/static/xlat/doom_base.txt @@ -3,8 +3,6 @@ include "xlat/doom.txt" maxlinespecial = 272; -sector bitmask 0xffe0 clear; - sector 15 = 0; sector 17 = 0; sector 18 = 0; From 5e7ee8f33e088c9e2db7005abc5eb39a4afd9cd9 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Jun 2013 02:06:40 +0000 Subject: [PATCH 380/387] - Addded support for multi-line values in INI files, so you can't maliciously inject stray newline characters into the config file using ACS's SetCVarString. SVN r4326 (trunk) --- src/configfile.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++- src/configfile.h | 2 + 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/configfile.cpp b/src/configfile.cpp index fcbed42c3..b8e37d91c 100644 --- a/src/configfile.cpp +++ b/src/configfile.cpp @@ -38,9 +38,12 @@ #include "doomtype.h" #include "configfile.h" +#include "m_random.h" #define READBUFFERSIZE 256 +static FRandom pr_endtag; + //==================================================================== // // FConfigFile Constructor @@ -679,13 +682,68 @@ bool FConfigFile::ReadConfig (void *file) whiteprobe++; } *(whiteprobe - 1) = 0; - NewConfigEntry (section, start, whiteprobe); + // Check for multi-line value + if (whiteprobe[0] == '<' && whiteprobe[1] == '<' && whiteprobe[2] == '<' && whiteprobe[3] != '\0') + { + ReadMultiLineValue (file, section, start, whiteprobe + 3); + } + else + { + NewConfigEntry (section, start, whiteprobe); + } } } } return true; } +//==================================================================== +// +// FConfigFile :: ReadMultiLineValue +// +// Reads a multi-line value, with format as follows: +// +// key=<<>>ENDTAG +// +// The final ENDTAG must be on a line all by itself. +// +//==================================================================== + +FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSection *section, const char *key, const char *endtag) +{ + char readbuf[READBUFFERSIZE]; + FString value; + size_t endlen = strlen(endtag); + + // Keep on reading lines until we reach a line that matches >>>endtag + while (ReadLine(readbuf, READBUFFERSIZE, file) != NULL) + { + // Does the start of this line match the endtag? + if (readbuf[0] == '>' && readbuf[1] == '>' && readbuf[2] == '>' && + strncmp(readbuf + 3, endtag, endlen) == 0) + { // Is there nothing but line break characters after the match? + size_t i; + for (i = endlen + 3; readbuf[i] != '\0'; ++i) + { + if (readbuf[i] != '\n' && readbuf[i] != '\r') + { // Not a line break character + break; + } + } + if (readbuf[i] == '\0') + { // We're done; strip the previous line's line breaks, since it's not part of the value. + value.StripRight("\n\r"); + } + break; + } + // Append this line to the value. + value << readbuf; + } + return NewConfigEntry(section, key, value); +} + //==================================================================== // // FConfigFile :: ReadLine @@ -732,7 +790,16 @@ bool FConfigFile::WriteConfigFile () const fprintf (file, "[%s]\n", section->Name); while (entry != NULL) { - fprintf (file, "%s=%s\n", entry->Key, entry->Value); + if (strpbrk(entry->Value, "\r\n") == NULL) + { // Single-line value + fprintf (file, "%s=%s\n", entry->Key, entry->Value); + } + else + { // Multi-line value + const char *endtag = GenerateEndTag(entry->Value); + fprintf (file, "%s=<<<%s\n%s\n>>>%s\n", entry->Key, + endtag, entry->Value, endtag); + } entry = entry->Next; } section = section->Next; @@ -742,6 +809,44 @@ bool FConfigFile::WriteConfigFile () const return true; } +//==================================================================== +// +// FConfigFile :: GenerateEndTag +// +// Generates a terminator sequence for multi-line values that does +// not appear anywhere in the value. +// +//==================================================================== + +const char *FConfigFile::GenerateEndTag(const char *value) +{ + static const char Base64Table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; + static char EndTag[25] = "EOV-"; + + // Try different 20-character sequences until we find one that + // isn't in the value. We create the sequences by generating two + // 64-bit random numbers and Base64 encoding the first 15 bytes + // from them. + union { QWORD rand_num[2]; BYTE rand_bytes[16]; }; + do + { + rand_num[0] = pr_endtag.GenRand64(); + rand_num[1] = pr_endtag.GenRand64(); + + for (int i = 0; i < 5; ++i) + { + DWORD three_bytes = (rand_bytes[i*3] << 16) | (rand_bytes[i*3+1] << 8) | (rand_bytes[i*3+2]); + EndTag[4+i*4 ] = Base64Table[rand_bytes[i*3] >> 2]; + EndTag[4+i*4+1] = Base64Table[((rand_bytes[i*3] & 3) << 4) | (rand_bytes[i*3+1] >> 4)]; + EndTag[4+i*4+2] = Base64Table[((rand_bytes[i*3+1] & 15) << 2) | (rand_bytes[i*3+2] >> 6)]; + EndTag[4+i*4+3] = Base64Table[rand_bytes[i*3+2] & 63]; + } + } + while (strstr(value, EndTag) != NULL); + return EndTag; +} + //==================================================================== // // FConfigFile :: WriteCommentHeader diff --git a/src/configfile.h b/src/configfile.h index b704dd359..25c366f01 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -78,6 +78,7 @@ protected: virtual char *ReadLine (char *string, int n, void *file) const; bool ReadConfig (void *file); + static const char *GenerateEndTag(const char *value); bool OkayToWrite; bool FileExisted; @@ -110,6 +111,7 @@ private: FConfigEntry *FindEntry (FConfigSection *section, const char *key) const; FConfigSection *NewConfigSection (const char *name); FConfigEntry *NewConfigEntry (FConfigSection *section, const char *key, const char *value); + FConfigEntry *ReadMultiLineValue (void *file, FConfigSection *section, const char *key, const char *terminator); void SetSectionNote (FConfigSection *section, const char *note); public: From e2be8b9e7e2bee1df92da3dc00e04962ebda1700 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Jun 2013 02:49:07 +0000 Subject: [PATCH 381/387] - When purging ACS strings, free the strings themselves as well as marking them as free. - Fixed: ACSStringPool::InsertString()'s overflow check was far too low. - Fixed: When ACSStringPool::InsertString() triggered a garbage collection, it ignored the newly freed space and expanded the array anyway. SVN r4328 (trunk) --- src/p_acs.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e982d6993..6237fedbe 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -481,21 +481,27 @@ void ACSStringPool::PurgeStrings() // Clear the hash buckets. We'll rebuild them as we decide what strings // to keep and which to toss. memset(PoolBuckets, 0xFF, sizeof(PoolBuckets)); + size_t usedcount = 0, freedcount = 0; for (unsigned int i = 0; i < Pool.Size(); ++i) { PoolEntry *entry = &Pool[i]; if (entry->Next != FREE_ENTRY) { if (entry->LockCount == 0) - { // Mark this entry as free. + { + freedcount++; + // Mark this entry as free. entry->Next = FREE_ENTRY; if (i < FirstFreeEntry) { FirstFreeEntry = i; } + // And free the string. + entry->Str = ""; } else { + usedcount++; // Rehash this entry. unsigned int h = entry->Hash % NUM_BUCKETS; entry->Next = PoolBuckets[h]; @@ -543,14 +549,15 @@ int ACSStringPool::FindString(const char *str, size_t len, unsigned int h, unsig int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucketnum, const SDWORD *stack, int stackdepth) { - if (Pool.Size() >= STRPOOL_LIBRARYID) - { - return -1; - } unsigned int index = FirstFreeEntry; if (index >= MIN_GC_SIZE && index == Pool.Max()) { // We will need to grow the array. Try a garbage collection first. P_CollectACSGlobalStrings(stack, stackdepth); + index = FirstFreeEntry; + } + if (FirstFreeEntry >= STRPOOL_LIBRARYID_OR) + { // If we go any higher, we'll collide with the library ID marker. + return -1; } if (index == Pool.Size()) { // There were no free entries; make a new one. From 5a00f4b59a71894e572e56dde9085b3a1e154842 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 4 Jun 2013 02:54:57 +0000 Subject: [PATCH 382/387] - Reduce ACS LineAttack's default range to the standard MISSILERANGE, because making it INT_MAX seems pretty iffy. SVN r4329 (trunk) --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6237fedbe..5d3961ac7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4947,7 +4947,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const int damage = args[3]; FName pufftype = argCount > 4 && args[4]? FName(FBehavior::StaticLookupString(args[4])) : NAME_BulletPuff; FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None; - fixed_t range = argCount > 6 && args[6]? args[6] : 0x7FFFFFFF; + fixed_t range = argCount > 6 && args[6]? args[6] : MISSILERANGE; if (args[0] == 0) { From e32e44209e0d25b33c849c3449a2b122fbb2c6bd Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 5 Jun 2013 02:15:21 +0000 Subject: [PATCH 383/387] - Added SpawnDecal ACS function: int SpawnDecal(int tid, str decalname, int flags, fixed angle, int zoffset, int distance) Traces a line from tid's actor until hitting a wall, then creates a decal there. Returns the number of decals spawned. * tid = Which actor(s) to start the trace at. * decalname = Which decal to spawn. * flags = * SDF_ABSANGLE = Angle parameter is an absolute angle. Otherwise, it's relative to the origin actor's angle. * SDF_PERMANENT = Decal ignores cl_maxdecals. Otherwise, it will eventually disappear. * angle = Direction in which to search for a wall. Defaults to 0.0. * zoffset = Offset from the middle of the origin actor for the Z height of the decal. Defaults to 0. * distance = Maximum distance to search for a wall. Defaults to 64. SVN r4330 (trunk) --- src/g_shared/a_decals.cpp | 65 +++++++++++++++++++++++------------ src/g_shared/a_sharedglobal.h | 3 +- src/p_acs.cpp | 52 ++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 22f53eefa..576ff6a5c 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -755,6 +755,48 @@ CCMD (spray) Net_WriteString (argv[1]); } +DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixed_t tracedist, bool permanent) +{ + if (tpl == NULL || (tpl = tpl->GetDecal()) == NULL) + { + return NULL; + } + + FTraceResults trace; + DBaseDecal *decal; + side_t *wall; + + angle >>= ANGLETOFINESHIFT; + + Trace(x, y, z, sec, + finecosine[angle], finesine[angle], 0, + tracedist, 0, 0, NULL, trace, TRACE_NoSky); + + if (trace.HitType == TRACE_HitWall) + { + if (permanent) + { + decal = new DBaseDecal(trace.Z); + wall = trace.Line->sidedef[trace.Side]; + decal->StickToWall(wall, trace.X, trace.Y, trace.ffloor); + tpl->ApplyToDecal(decal, wall); + // Spread decal to nearby walls if it does not all fit on this one + if (cl_spreaddecals) + { + decal->Spread(tpl, wall, trace.X, trace.Y, trace.Z, trace.ffloor); + } + return decal; + } + else + { + return DImpactDecal::StaticCreate(tpl, + trace.X, trace.Y, trace.Z, + trace.Line->sidedef[trace.Side], NULL); + } + } + return NULL; +} + class ADecal : public AActor { DECLARE_CLASS (ADecal, AActor); @@ -767,9 +809,6 @@ IMPLEMENT_CLASS (ADecal) void ADecal::BeginPlay () { const FDecalTemplate *tpl; - FTraceResults trace; - DBaseDecal *decal; - side_t *wall; Super::BeginPlay (); @@ -781,31 +820,13 @@ void ADecal::BeginPlay () if (!tpl->PicNum.Exists()) { Printf("Decal actor at (%d,%d) does not have a valid texture\n", x>>FRACBITS, y>>FRACBITS); - } else { // Look for a wall within 64 units behind the actor. If none can be // found, then no decal is created, and this actor is destroyed // without effectively doing anything. - Trace (x, y, z, Sector, - finecosine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], - finesine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], 0, - 64*FRACUNIT, 0, 0, NULL, trace, TRACE_NoSky); - - if (trace.HitType == TRACE_HitWall) - { - decal = new DBaseDecal (this); - wall = trace.Line->sidedef[trace.Side]; - decal->StickToWall (wall, trace.X, trace.Y, trace.ffloor); - tpl->ApplyToDecal (decal, wall); - // Spread decal to nearby walls if it does not all fit on this one - if (cl_spreaddecals) - { - decal->Spread (tpl, wall, trace.X, trace.Y, z, trace.ffloor); - } - } - else + if (NULL == ShootDecal(tpl, this, Sector, x, y, z, angle + ANGLE_180, 64*FRACUNIT, true)) { DPrintf ("Could not find a wall to stick decal to at (%d,%d)\n", x>>FRACBITS, y>>FRACBITS); } diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index 87e103975..a898433f0 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -9,7 +9,8 @@ struct vertex_t; struct side_t; struct F3DFloor; -extern void P_SpawnDirt (AActor *actor, fixed_t radius); +void P_SpawnDirt (AActor *actor, fixed_t radius); +class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, fixed_t x, fixed_t y, fixed_t z, angle_t angle, fixed_t tracedist, bool permanent); class DBaseDecal : public DThinker { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5d3961ac7..ab704e9df 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -73,6 +73,7 @@ #include "po_man.h" #include "actorptrselect.h" #include "farchive.h" +#include "decallib.h" #include "g_shared/a_pickups.h" @@ -111,6 +112,10 @@ FRandom pr_acs ("ACS"); #define NOT_FLOOR 8 #define NOT_CEILING 16 +// SpawnDecal flags +#define SDF_ABSANGLE 1 +#define SDF_PERMANENT 2 + struct CallReturn { CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, bool discard, unsigned int runaway) @@ -4192,6 +4197,7 @@ enum EACSFunctions ACSF_GetWeapon, ACSF_SoundVolume, ACSF_PlayActorSound, + ACSF_SpawnDecal, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4440,6 +4446,17 @@ static int SetCVar(AActor *activator, const char *cvarname, int value, bool is_s return 1; } +static bool DoSpawnDecal(AActor *actor, const FDecalTemplate *tpl, int flags, angle_t angle, fixed_t zofs, fixed_t distance) +{ + if (!(flags & SDF_ABSANGLE)) + { + angle += actor->angle; + } + return NULL != ShootDecal(tpl, actor, actor->Sector, actor->x, actor->y, + actor->z + (actor->height>>1) - actor->floorclip + actor->GetBobOffset() + zofs, + angle, distance, !!(flags & SDF_PERMANENT)); +} + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth) { AActor *actor; @@ -5141,6 +5158,41 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return GlobalACSStrings.AddString(activator->player->ReadyWeapon->GetClass()->TypeName.GetChars(), stack, stackdepth); } + case ACSF_SpawnDecal: + // int SpawnDecal(int tid, str decalname, int flags, fixed angle, int zoffset, int distance) + // Returns number of decals spawned (not including spreading) + { + int count = 0; + const FDecalTemplate *tpl = DecalLibrary.GetDecalByName(FBehavior::StaticLookupString(args[1])); + if (tpl != NULL) + { + int flags = (argCount > 2) ? args[2] : 0; + angle_t angle = (argCount > 3) ? (args[3] << FRACBITS) : 0; + fixed_t zoffset = (argCount > 4) ? (args[4] << FRACBITS) : 0; + fixed_t distance = (argCount > 5) ? (args[5] << FRACBITS) : 64*FRACUNIT; + + if (args[0] == 0) + { + if (activator != NULL) + { + count += DoSpawnDecal(activator, tpl, flags, angle, zoffset, distance); + } + } + else + { + FActorIterator it(args[0]); + AActor *actor; + + while ((actor = it.Next()) != NULL) + { + count += DoSpawnDecal(actor, tpl, flags, angle, zoffset, distance); + } + } + } + return count; + } + break; + default: break; } From c6dd658aa861c9fc2bfe794a94e835af8d5c8d98 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 6 Jun 2013 20:08:56 +0000 Subject: [PATCH 384/387] - Fixed: Polyobjs that rotated faster than their distance would overshoot on their first tic and continue spinning until the next time around because the check for moving too fast was only done after the polyobject had been rotated once. - Reduced the potential for overflow when setting up the speed of a rotating polyobj. SVN r4332 (trunk) --- src/po_man.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/po_man.cpp b/src/po_man.cpp index 1464f3ee5..289e06016 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -382,24 +382,24 @@ void DRotatePoly::Tick () FPolyObj *poly = PO_GetPolyobj (m_PolyObj); if (poly == NULL) return; + // Don't let non-perpetual polyobjs overshoot their targets. + if (m_Dist != -1 && (unsigned int)m_Dist < (unsigned int)abs(m_Speed)) + { + m_Speed = m_Speed < 0 ? -m_Dist : m_Dist; + } + if (poly->RotatePolyobj (m_Speed)) { - unsigned int absSpeed = abs (m_Speed); - if (m_Dist == -1) { // perpetual polyobj return; } - m_Dist -= absSpeed; + m_Dist -= abs(m_Speed); if (m_Dist == 0) { SN_StopSequence (poly); Destroy (); } - else if ((unsigned int)m_Dist < absSpeed) - { - m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); - } } } @@ -446,7 +446,7 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, { pe->m_Dist = ANGLE_MAX-1; } - pe->m_Speed = (speed*direction*(ANGLE_90/64))>>3; + pe->m_Speed = speed*direction*(ANGLE_90/(64<<3)); SN_StartSequence (poly, poly->seqType, SEQ_DOOR, 0); direction = -direction; // Reverse the direction } From b9e771576f2c46d58a1b578b4cb096f4d1ccf359 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 6 Jun 2013 20:15:04 +0000 Subject: [PATCH 385/387] - Fixed: The time freezer power should do nothing while predicting. SVN r4333 (trunk) --- src/g_shared/a_artifacts.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index adad4e2c4..0de822f62 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1441,7 +1441,8 @@ void APowerTimeFreezer::DoEffect() Super::DoEffect(); // [RH] Do not change LEVEL_FROZEN on odd tics, or the Revenant's tracer // will get thrown off. - if (level.time & 1) + // [ED850] Don't change it if the player is predicted either. + if (level.time & 1 || (Owner != NULL && Owner->player != NULL && Owner->player->cheats & CF_PREDICTING)) { return; } From bac66d5b0ef3cb5347af23755a8629de683ecc30 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 6 Jun 2013 20:34:39 +0000 Subject: [PATCH 386/387] - Moved the status bar Tick call after the players have been ticked by P_Ticker(), because P_PlayerThink() is where the check for unspawned players happens. If the player attached to the status bar is one of them, it will crash while ticking. SVN r4334 (trunk) --- src/p_tick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 26c4c2ae1..07e153ffa 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -117,13 +117,13 @@ void P_Ticker (void) { P_ThinkParticles (); // [RH] make the particles think } - StatusBar->Tick (); // [RH] moved this here for (i = 0; iTick (); // [RH] moved this here level.Tick (); // [RH] let the level tick DThinker::RunThinkers (); From 902f6647b6cf4bfb474c5b78fed5091e572dcbb6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 6 Jun 2013 20:48:57 +0000 Subject: [PATCH 387/387] - Added ACS function CheckFont. SVN r4335 (trunk) --- src/p_acs.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ab704e9df..cd55caefb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4198,6 +4198,7 @@ enum EACSFunctions ACSF_SoundVolume, ACSF_PlayActorSound, ACSF_SpawnDecal, + ACSF_CheckFont, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -5193,6 +5194,10 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } break; + case ACSF_CheckFont: + // bool CheckFont(str fontname) + return V_GetFont(FBehavior::StaticLookupString(args[0])) != NULL; + default: break; }