mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-06-03 02:30:53 +00:00
- Update to ZDoom r858:
- Added FMOD_OPENONLY to the callback version of CreateStream() to prevent it from doing prebuffering of the song. This was causing the Linux version to hang while waiting for input from the pipe, since Timidity hadn't been started yet. I tried using a select call in the FillStream() method, but it always seems to return the pipe as having nothing available. Unfortunately, the game still falls all over itself if Timidity isn't available. Instead of execvp failing nicely, X errors kill the game. I don't know why it's doing that. My advice for Linux music: Skip Timidity++ and get a DLS patch set (/WINDOWS/system32/drivers/gm.dls is probably the most common by far) and set the snd_midipatchset cvar to point to it. It's faster and also sounds a whole lot better than the crappy freepats Ubuntu wants to install with Timidity++ (thank goodness I have the official patches from a real GUS so I don't need to use them). - GCC fixes. - Fixed: After starting new music the music volume has to be reset so that the song's relative volume takes effect. - Removed the arbitrary 1024 bytes limit when the file being played is a MIDI file. I had a D_DM2TTL that's only 990 bytes. - Restructured I_RegisterSong so that $mididevice works again and also supports selecting FMOD. - Added Jim' Linux fix. - Added MartinHowe's fix for mugshot display in status bars. - The garbage collector is now run one last time just before exiting the game. - Removed movie volume from the sound menu and renamed some of the other options to give the MIDI device name more room to display itself. - Moved the midi device selection into the main sound menu. - Added FMOD as MIDI device -1, to replace the MIDI mapper. This is still the default device. By default, it uses exactly the same DLS instruments as the Microsoft GS Wavetable Synth. If you have another set DLS level 1 patch set you want to use, set the snd_midipatchset cvar to specify where it should load the instruments from. - Changed the ProduceMIDI function to store its output into a TArray<BYTE>. An overloaded version wraps around it to continue to supply file-writing support for external Timidity++ usage. - Added an FMOD credits banner to comply with their non-commercial license. - Reimplemented the snd_buffersize cvar for the FMOD Ex sound system. Rather than a time in ms, this is now the length in samples of the DSP buffer. Also added the snd_buffercount cvar to offer complete control over the call to FMOD::System::setDSPBufferSize(). Note that with any snd_samplerate below about 44kHz, you will need to set snd_buffersize to avoid long latencies. - Reimplemented the snd_output cvar for the FMOD Ex sound system. - Changed snd_samplerate default to 0. This now means to use the default sample rate. - Made snd_output, snd_output_format, snd_speakermode, snd_resampler, and snd_hrtf available through the menu. - Split the HRTF effect selection into its own cvar: snd_hrtf. - Removed 96000 Hz option from the menu. It's still available through the cvar, if desired. - Fixed: If Windows sound init failed, retry with DirectSound. (Apparently, WASAPI doesn't work with more than two speakers and PCM-Float output at the same time.) - Fixed: Area sounds only played from the front speakers once you got within the 2D panning area. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@79 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
parent
f0ef4540b6
commit
a2b23a7e43
58 changed files with 1685 additions and 641 deletions
|
@ -12,19 +12,20 @@ CFLAGS += `pkg-config gtk+-2.0 --cflags`
|
||||||
CFLAGS += -DHAVE_FILELENGTH -D__forceinline=inline `sdl-config --cflags`
|
CFLAGS += -DHAVE_FILELENGTH -D__forceinline=inline `sdl-config --cflags`
|
||||||
CFLAGS += -DNEED_STRUPR
|
CFLAGS += -DNEED_STRUPR
|
||||||
CFLAGS += -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp
|
CFLAGS += -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp
|
||||||
LDFLAGS += -lFLAC++ -lFLAC -lz -lmodplug -lfmod `sdl-config --libs`
|
LDFLAGS += -lFLAC++ -lFLAC -lz -lmodplug -lfmodex `sdl-config --libs`
|
||||||
LDFLAGS += -ljpeg `pkg-config gtk+-2.0 --libs`
|
LDFLAGS += -ljpeg `pkg-config gtk+-2.0 --libs`
|
||||||
LDFLAGS += -lGL -lGLU
|
LDFLAGS += -lGL -lGLU
|
||||||
NASMFLAGS += -f elf -DM_TARGET_LINUX
|
NASMFLAGS += -f elf -DM_TARGET_LINUX
|
||||||
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ fragglescript/ thingdef/ Linux/ sdl/ gl/ gl/r_render/ textures/)
|
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ fragglescript/ thingdef/ Linux/ sdl/ gl/ gl/r_render/ textures/ xlat/)
|
||||||
INCLUDES = $(addprefix -I,$(SRCDIRS))
|
INCLUDES = $(addprefix -I,$(SRCDIRS))
|
||||||
|
INCLUDES += -Isnes_spc/snes_spc/ -I/usr/include/fmodex/
|
||||||
CFLAGS += $(INCLUDES)
|
CFLAGS += $(INCLUDES)
|
||||||
|
|
||||||
RELEASEOBJ ?= releaseobj
|
RELEASEOBJ ?= releaseobj
|
||||||
DEBUGOBJ ?= debugobj
|
DEBUGOBJ ?= debugobj
|
||||||
|
|
||||||
CPPSRCS = $(wildcard $(addsuffix *.cpp,$(SRCDIRS)))
|
CPPSRCS = $(wildcard $(addsuffix *.cpp,$(SRCDIRS)))
|
||||||
CSRCS = $(wildcard $(addsuffix *.c,$(SRCDIRS)))
|
CSRCS = $(filter-out src/xlat/xlat_parser.c, $(wildcard $(addsuffix *.c,$(SRCDIRS))))
|
||||||
ifndef NOASM
|
ifndef NOASM
|
||||||
ASRCS = $(wildcard src/*.nas)
|
ASRCS = $(wildcard src/*.nas)
|
||||||
CFLAGS += -DUSEASM=1
|
CFLAGS += -DUSEASM=1
|
||||||
|
@ -78,11 +79,11 @@ endef
|
||||||
|
|
||||||
all: $(ZDOOMBIN) toolsandpk3 zdoom.pk3
|
all: $(ZDOOMBIN) toolsandpk3 zdoom.pk3
|
||||||
|
|
||||||
$(ZDOOMBIN): ccdv $(OBJDIR) $(if $(RESTART),deps) $(OBJS)
|
$(ZDOOMBIN): ccdv $(OBJDIR) $(if $(RESTART),deps) $(OBJS) snes_spc/libsnes_spc.a
|
||||||
ifndef RESTART
|
ifndef RESTART
|
||||||
$(CCDV) $(CXX) $(LDFLAGS) $(OBJDIR)/autostart.o \
|
$(CCDV) $(CXX) $(LDFLAGS) $(OBJDIR)/autostart.o \
|
||||||
$(filter-out %/autostart.o %/autozend.o,$(OBJS)) \
|
$(filter-out %/autostart.o %/autozend.o,$(OBJS)) \
|
||||||
$(OBJDIR)/autozend.o -o $(ZDOOMBIN)
|
snes_spc/libsnes_spc.a $(OBJDIR)/autozend.o -o $(ZDOOMBIN)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# include any of the dep files that already exist
|
# include any of the dep files that already exist
|
||||||
|
@ -119,23 +120,36 @@ ifdef RESTART
|
||||||
@make -f $(firstword $(MAKEFILE_LIST)) RESTART=
|
@make -f $(firstword $(MAKEFILE_LIST)) RESTART=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# This file needs special handling because GCC misoptimizes it otherwise.
|
||||||
|
$(OBJDIR)/fmopl.o: src/oplsynth/fmopl.cpp
|
||||||
|
$(CCDV) $(CXX) $(CXXFLAGS) -fno-tree-dominator-opts -fno-tree-fre -c -o $@ $<
|
||||||
|
|
||||||
|
src/xlat/xlat_parser.h src/xlat/xlat_parser.c: tools/lemon/lemon src/xlat/xlat_parser.y
|
||||||
|
$(CCDV) tools/lemon/lemon -s src/xlat/xlat_parser.y
|
||||||
|
|
||||||
$(OBJDIR):
|
$(OBJDIR):
|
||||||
mkdir $(OBJDIR)
|
mkdir $(OBJDIR)
|
||||||
|
|
||||||
toolsandpk3: tools/makewad/makewad tools/dehsupp/dehsupp tools/xlatcc/xlatcc
|
toolsandpk3: tools/makewad/makewad src/svnrevision_gz.h
|
||||||
make -C wadsrc/
|
make -C wadsrc/
|
||||||
|
|
||||||
zdoom.pk3: toolsandpk3
|
zdoom.pk3: toolsandpk3
|
||||||
ln -sf wadsrc/gzdoom.pk3 ./
|
ln -sf wadsrc/gzdoom.pk3 ./
|
||||||
|
|
||||||
|
snes_spc/libsnes_spc.a:
|
||||||
|
$(MAKE) -C snes_spc/
|
||||||
|
|
||||||
tools/makewad/makewad: ccdv
|
tools/makewad/makewad: ccdv
|
||||||
make -C tools/makewad/
|
make -C tools/makewad/
|
||||||
|
|
||||||
tools/dehsupp/dehsupp: ccdv
|
tools/lemon/lemon:
|
||||||
make -C tools/dehsupp/
|
$(MAKE) -C tools/lemon/
|
||||||
|
|
||||||
tools/xlatcc/xlatcc: ccdv
|
tools/updaterevision/updaterevision: ccdv
|
||||||
make -C tools/xlatcc/
|
make -C tools/updaterevision/
|
||||||
|
|
||||||
|
src/svnrevision_gz.h: tools/updaterevision/updaterevision
|
||||||
|
tools/updaterevision/updaterevision src src/svnrevision_gz.h
|
||||||
|
|
||||||
ccdv: ccdv-posix.c
|
ccdv: ccdv-posix.c
|
||||||
@gcc -Os -s ccdv-posix.c -o ccdv
|
@gcc -Os -s ccdv-posix.c -o ccdv
|
||||||
|
|
|
@ -304,11 +304,7 @@ int main(int argc, char **argv)
|
||||||
snprintf(gAction, sizeof(gAction), "Running %s", Basename(argv[1]));
|
snprintf(gAction, sizeof(gAction), "Running %s", Basename(argv[1]));
|
||||||
memset(gArgsStr, 0, sizeof(gArgsStr));
|
memset(gArgsStr, 0, sizeof(gArgsStr));
|
||||||
|
|
||||||
if(strcmp(gAction+8, "ar") == 0)
|
if(strcmp(gAction+8, "cc") == 0 ||
|
||||||
{
|
|
||||||
snprintf(gTarget, sizeof(gTarget), "%s", Basename(argv[i + 1]));
|
|
||||||
}
|
|
||||||
else if(strcmp(gAction+8, "cc") == 0 ||
|
|
||||||
strcmp(gAction+8, "ld") == 0 ||
|
strcmp(gAction+8, "ld") == 0 ||
|
||||||
strcmp(gAction+8, "gcc") == 0 ||
|
strcmp(gAction+8, "gcc") == 0 ||
|
||||||
strcmp(gAction+8, "g++") == 0 ||
|
strcmp(gAction+8, "g++") == 0 ||
|
||||||
|
|
|
@ -769,7 +769,7 @@ public:
|
||||||
|
|
||||||
enum { S_NULL = 2, S_GENERICFREEZEDEATH = 3 };
|
enum { S_NULL = 2, S_GENERICFREEZEDEATH = 3 };
|
||||||
|
|
||||||
TArray<TObjPtr<AActor>> dynamiclights;
|
TArray<TObjPtr<AActor> > dynamiclights;
|
||||||
void * lightassociations;
|
void * lightassociations;
|
||||||
bool hasmodel;
|
bool hasmodel;
|
||||||
subsector_s * subsector;
|
subsector_s * subsector;
|
||||||
|
|
|
@ -88,7 +88,6 @@ enum
|
||||||
|
|
||||||
static bool waitingforspawn[MAXPLAYERS];
|
static bool waitingforspawn[MAXPLAYERS];
|
||||||
|
|
||||||
|
|
||||||
DCajunMaster::~DCajunMaster()
|
DCajunMaster::~DCajunMaster()
|
||||||
{
|
{
|
||||||
ForgetBots();
|
ForgetBots();
|
||||||
|
|
|
@ -865,7 +865,7 @@ int VPrintf (int printlevel, const char *format, va_list parms)
|
||||||
|
|
||||||
FString outline;
|
FString outline;
|
||||||
outline.VFormat (format, parms);
|
outline.VFormat (format, parms);
|
||||||
return PrintString (printlevel, outline);
|
return PrintString (printlevel, outline.GetChars());
|
||||||
}
|
}
|
||||||
|
|
||||||
int STACK_ARGS Printf (int printlevel, const char *format, ...)
|
int STACK_ARGS Printf (int printlevel, const char *format, ...)
|
||||||
|
|
|
@ -242,7 +242,20 @@ static const char *IWADNames[] =
|
||||||
"hexen.wad",
|
"hexen.wad",
|
||||||
"hexdd.wad",
|
"hexdd.wad",
|
||||||
"strife1.wad",
|
"strife1.wad",
|
||||||
"strife0.wad",
|
"strife0.wad",
|
||||||
|
#ifdef unix
|
||||||
|
"DOOM2.WAD", // Also look for all-uppercase names
|
||||||
|
"PLUTONIA.WAD",
|
||||||
|
"TNT.WAD",
|
||||||
|
"DOOM.WAD",
|
||||||
|
"DOOM1.WAD",
|
||||||
|
"HERETIC.WAD",
|
||||||
|
"HERETIC1.WAD",
|
||||||
|
"HEXEN.WAD",
|
||||||
|
"HEXDD.WAD",
|
||||||
|
"STRIFE1.WAD",
|
||||||
|
"STRIFE0.WAD",
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
#include "st_start.h"
|
#include "st_start.h"
|
||||||
#include "teaminfo.h"
|
#include "teaminfo.h"
|
||||||
|
#include "p_conversation.h"
|
||||||
|
|
||||||
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
||||||
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
||||||
|
@ -2361,6 +2362,10 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DEM_CONVERSATION:
|
||||||
|
P_ConversationCommand (player, stream);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
I_Error ("Unknown net command: %d", type);
|
I_Error ("Unknown net command: %d", type);
|
||||||
break;
|
break;
|
||||||
|
@ -2451,6 +2456,31 @@ void Net_SkipCommand (int type, BYTE **stream)
|
||||||
skip = 3 + *(*stream + 2) * 4;
|
skip = 3 + *(*stream + 2) * 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DEM_CONVERSATION:
|
||||||
|
{
|
||||||
|
t = **stream;
|
||||||
|
skip = 1;
|
||||||
|
|
||||||
|
switch (t)
|
||||||
|
{
|
||||||
|
case CONV_ANIMATE:
|
||||||
|
skip += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_GIVEINVENTORY:
|
||||||
|
skip += strlen ((char *)(*stream + skip)) + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_TAKEINVENTORY:
|
||||||
|
skip += strlen ((char *)(*stream + skip)) + 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,11 @@ public:
|
||||||
fixed_t crouchoffset;
|
fixed_t crouchoffset;
|
||||||
fixed_t crouchviewdelta;
|
fixed_t crouchviewdelta;
|
||||||
|
|
||||||
|
// [CW] I moved these here for multiplayer conversation support.
|
||||||
|
AActor *ConversationNPC, *ConversationPC;
|
||||||
|
angle_t ConversationNPCAngle;
|
||||||
|
bool ConversationFaceTalker;
|
||||||
|
|
||||||
fixed_t GetDeltaViewHeight() const
|
fixed_t GetDeltaViewHeight() const
|
||||||
{
|
{
|
||||||
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
||||||
|
|
|
@ -150,6 +150,7 @@ enum EDemoCommand
|
||||||
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
|
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
|
||||||
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
|
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
|
||||||
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
|
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
|
||||||
|
DEM_CONVERSATION, // 51 Make conversations work.
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
||||||
|
|
|
@ -418,16 +418,19 @@ void DObject::Destroy ()
|
||||||
size_t DObject::PropagateMark()
|
size_t DObject::PropagateMark()
|
||||||
{
|
{
|
||||||
const PClass *info = GetClass();
|
const PClass *info = GetClass();
|
||||||
const size_t *offsets = info->FlatPointers;
|
if (!PClass::bShutdown)
|
||||||
if (offsets == NULL)
|
|
||||||
{
|
{
|
||||||
const_cast<PClass *>(info)->BuildFlatPointers();
|
const size_t *offsets = info->FlatPointers;
|
||||||
offsets = info->FlatPointers;
|
if (offsets == NULL)
|
||||||
}
|
{
|
||||||
while (*offsets != ~(size_t)0)
|
const_cast<PClass *>(info)->BuildFlatPointers();
|
||||||
{
|
offsets = info->FlatPointers;
|
||||||
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
}
|
||||||
offsets++;
|
while (*offsets != ~(size_t)0)
|
||||||
|
{
|
||||||
|
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||||
|
offsets++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return info->Size;
|
return info->Size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,10 +298,14 @@ static void MarkRoot()
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
players[i].PropagateMark();
|
players[i].PropagateMark();
|
||||||
}
|
}
|
||||||
if (SectorMarker == NULL)
|
if (SectorMarker == NULL && sectors != NULL)
|
||||||
{
|
{
|
||||||
SectorMarker = new DSectorMarker;
|
SectorMarker = new DSectorMarker;
|
||||||
}
|
}
|
||||||
|
else if (sectors == NULL)
|
||||||
|
{
|
||||||
|
SectorMarker = NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SectorMarker->SecNum = 0;
|
SectorMarker->SecNum = 0;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
TArray<PClass *> PClass::m_RuntimeActors;
|
TArray<PClass *> PClass::m_RuntimeActors;
|
||||||
TArray<PClass *> PClass::m_Types;
|
TArray<PClass *> PClass::m_Types;
|
||||||
PClass *PClass::TypeHash[PClass::HASH_SIZE];
|
PClass *PClass::TypeHash[PClass::HASH_SIZE];
|
||||||
|
bool PClass::bShutdown;
|
||||||
|
|
||||||
// A harmless non_NULL FlatPointer for classes without pointers.
|
// A harmless non_NULL FlatPointer for classes without pointers.
|
||||||
static const size_t TheEnd = ~0u;
|
static const size_t TheEnd = ~0u;
|
||||||
|
@ -110,6 +111,7 @@ void PClass::StaticShutdown ()
|
||||||
{
|
{
|
||||||
delete[] uniqueFPs[i];
|
delete[] uniqueFPs[i];
|
||||||
}
|
}
|
||||||
|
bShutdown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PClass::StaticFreeData (PClass *type)
|
void PClass::StaticFreeData (PClass *type)
|
||||||
|
|
|
@ -138,6 +138,8 @@ struct PClass
|
||||||
|
|
||||||
enum { HASH_SIZE = 256 };
|
enum { HASH_SIZE = 256 };
|
||||||
static PClass *TypeHash[HASH_SIZE];
|
static PClass *TypeHash[HASH_SIZE];
|
||||||
|
|
||||||
|
static bool bShutdown;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -476,7 +476,7 @@ DFsSection *FParser::looping_section()
|
||||||
SDWORD rover_index = Script->MakeIndex(Rover);
|
SDWORD rover_index = Script->MakeIndex(Rover);
|
||||||
|
|
||||||
for(n=0; n<SECTIONSLOTS; n++)
|
for(n=0; n<SECTIONSLOTS; n++)
|
||||||
{
|
{
|
||||||
DFsSection *current = Script->sections[n];
|
DFsSection *current = Script->sections[n];
|
||||||
|
|
||||||
// check all the sections in this hashchain
|
// check all the sections in this hashchain
|
||||||
|
@ -494,7 +494,7 @@ DFsSection *FParser::looping_section()
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return best; // return the best one found
|
return best; // return the best one found
|
||||||
}
|
}
|
||||||
|
@ -510,10 +510,10 @@ void FParser::SF_Continue(void)
|
||||||
DFsSection *section;
|
DFsSection *section;
|
||||||
|
|
||||||
if(!(section = looping_section()) ) // no loop found
|
if(!(section = looping_section()) ) // no loop found
|
||||||
{
|
{
|
||||||
script_error("continue() not in loop\n");
|
script_error("continue() not in loop\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rover = Script->SectionEnd(section); // jump to the closing brace
|
Rover = Script->SectionEnd(section); // jump to the closing brace
|
||||||
}
|
}
|
||||||
|
@ -529,10 +529,10 @@ void FParser::SF_Break(void)
|
||||||
DFsSection *section;
|
DFsSection *section;
|
||||||
|
|
||||||
if(!(section = looping_section()) )
|
if(!(section = looping_section()) )
|
||||||
{
|
{
|
||||||
script_error("break() not in loop\n");
|
script_error("break() not in loop\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rover = Script->SectionEnd(section) + 1; // jump out of the loop
|
Rover = Script->SectionEnd(section) + 1; // jump out of the loop
|
||||||
}
|
}
|
||||||
|
@ -761,12 +761,12 @@ void FParser::SF_PlayerName(void)
|
||||||
int plnum;
|
int plnum;
|
||||||
|
|
||||||
if(!t_argc)
|
if(!t_argc)
|
||||||
{
|
{
|
||||||
player_t *pl=NULL;
|
player_t *pl=NULL;
|
||||||
if (Script->trigger) pl = Script->trigger->player;
|
if (Script->trigger) pl = Script->trigger->player;
|
||||||
if(pl) plnum = pl - players;
|
if(pl) plnum = pl - players;
|
||||||
else plnum=-1;
|
else plnum=-1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
plnum = T_GetPlayerNum(t_argv[0]);
|
plnum = T_GetPlayerNum(t_argv[0]);
|
||||||
|
|
||||||
|
@ -820,8 +820,17 @@ void FParser::SF_PlayerObj(void)
|
||||||
|
|
||||||
void FParser::SF_Player(void)
|
void FParser::SF_Player(void)
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
|
|
||||||
if(mo && mo->player) // haleyjd: added mo->player
|
if(mo && mo->player) // haleyjd: added mo->player
|
||||||
|
@ -924,11 +933,17 @@ void FParser::SF_RemoveObj(void)
|
||||||
|
|
||||||
void FParser::SF_KillObj(void)
|
void FParser::SF_KillObj(void)
|
||||||
{
|
{
|
||||||
|
// use trigger object if not specified
|
||||||
AActor *mo;
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
if(t_argc) mo = actorvalue(t_argv[0]);
|
{
|
||||||
else mo = Script->trigger; // default to trigger object
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger; // default to trigger object
|
||||||
|
}
|
||||||
|
|
||||||
if(mo)
|
if(mo)
|
||||||
{
|
{
|
||||||
// ensure the thing can be killed
|
// ensure the thing can be killed
|
||||||
|
@ -949,8 +964,17 @@ void FParser::SF_KillObj(void)
|
||||||
|
|
||||||
void FParser::SF_ObjX(void)
|
void FParser::SF_ObjX(void)
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_fixed; // haleyjd: SoM's fixed-point fix
|
t_return.type = svt_fixed; // haleyjd: SoM's fixed-point fix
|
||||||
t_return.value.f = mo ? mo->x : 0; // null ptr check
|
t_return.value.f = mo ? mo->x : 0; // null ptr check
|
||||||
}
|
}
|
||||||
|
@ -963,8 +987,17 @@ void FParser::SF_ObjX(void)
|
||||||
|
|
||||||
void FParser::SF_ObjY(void)
|
void FParser::SF_ObjY(void)
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_fixed; // haleyjd
|
t_return.type = svt_fixed; // haleyjd
|
||||||
t_return.value.f = mo ? mo->y : 0; // null ptr check
|
t_return.value.f = mo ? mo->y : 0; // null ptr check
|
||||||
}
|
}
|
||||||
|
@ -977,8 +1010,17 @@ void FParser::SF_ObjY(void)
|
||||||
|
|
||||||
void FParser::SF_ObjZ(void)
|
void FParser::SF_ObjZ(void)
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_fixed; // haleyjd
|
t_return.type = svt_fixed; // haleyjd
|
||||||
t_return.value.f = mo ? mo->z : 0; // null ptr check
|
t_return.value.f = mo ? mo->z : 0; // null ptr check
|
||||||
}
|
}
|
||||||
|
@ -992,8 +1034,17 @@ void FParser::SF_ObjZ(void)
|
||||||
|
|
||||||
void FParser::SF_ObjAngle(void)
|
void FParser::SF_ObjAngle(void)
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_fixed; // haleyjd: fixed-point -- SoM again :)
|
t_return.type = svt_fixed; // haleyjd: fixed-point -- SoM again :)
|
||||||
t_return.value.f = mo ? (fixed_t)AngleToFixed(mo->angle) : 0; // null ptr check
|
t_return.value.f = mo ? (fixed_t)AngleToFixed(mo->angle) : 0; // null ptr check
|
||||||
}
|
}
|
||||||
|
@ -1097,8 +1148,16 @@ void FParser::SF_DamageObj(void)
|
||||||
void FParser::SF_ObjSector(void)
|
void FParser::SF_ObjSector(void)
|
||||||
{
|
{
|
||||||
// use trigger object if not specified
|
// use trigger object if not specified
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
t_return.value.i = mo ? mo->Sector->tag : 0; // nullptr check
|
t_return.value.i = mo ? mo->Sector->tag : 0; // nullptr check
|
||||||
}
|
}
|
||||||
|
@ -1113,8 +1172,16 @@ void FParser::SF_ObjSector(void)
|
||||||
void FParser::SF_ObjHealth(void)
|
void FParser::SF_ObjHealth(void)
|
||||||
{
|
{
|
||||||
// use trigger object if not specified
|
// use trigger object if not specified
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
t_return.value.i = mo ? mo->health : 0;
|
t_return.value.i = mo ? mo->health : 0;
|
||||||
}
|
}
|
||||||
|
@ -1155,7 +1222,7 @@ void FParser::SF_ObjFlag(void)
|
||||||
|
|
||||||
// make the new flag
|
// make the new flag
|
||||||
mo->flags |= (!!intvalue(t_argv[2])) << flagnum;
|
mo->flags |= (!!intvalue(t_argv[2])) << flagnum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
if (mo && flagnum<26)
|
if (mo && flagnum<26)
|
||||||
|
@ -1352,7 +1419,7 @@ void FParser::SF_PointToDist(void)
|
||||||
// Doing this in floating point is actually faster with modern computers!
|
// Doing this in floating point is actually faster with modern computers!
|
||||||
float x = floatvalue(t_argv[2]) - floatvalue(t_argv[0]);
|
float x = floatvalue(t_argv[2]) - floatvalue(t_argv[0]);
|
||||||
float y = floatvalue(t_argv[3]) - floatvalue(t_argv[1]);
|
float y = floatvalue(t_argv[3]) - floatvalue(t_argv[1]);
|
||||||
|
|
||||||
t_return.type = svt_fixed;
|
t_return.type = svt_fixed;
|
||||||
t_return.value.f = (fixed_t)(sqrtf(x*x+y*y)*65536.f);
|
t_return.value.f = (fixed_t)(sqrtf(x*x+y*y)*65536.f);
|
||||||
}
|
}
|
||||||
|
@ -1875,7 +1942,7 @@ void DLightLevel::Tick()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// decrease lightlevel
|
// decrease lightlevel
|
||||||
if(m_Sector->lightlevel - speed <= destlevel)
|
if(m_Sector->lightlevel - speed <= destlevel)
|
||||||
{
|
{
|
||||||
// stop changing light level
|
// stop changing light level
|
||||||
|
@ -1987,7 +2054,7 @@ void FParser::SF_SectorColormap(void)
|
||||||
int i = -1;
|
int i = -1;
|
||||||
|
|
||||||
if(t_argc<2)
|
if(t_argc<2)
|
||||||
{ script_error("insufficient arguments to function\n"); return; }
|
{ script_error("insufficient arguments to function\n"); return; }
|
||||||
|
|
||||||
tagnum = intvalue(t_argv[0]);
|
tagnum = intvalue(t_argv[0]);
|
||||||
|
|
||||||
|
@ -1995,7 +2062,7 @@ void FParser::SF_SectorColormap(void)
|
||||||
secnum = T_FindSectorFromTag(tagnum, -1);
|
secnum = T_FindSectorFromTag(tagnum, -1);
|
||||||
|
|
||||||
if(secnum < 0)
|
if(secnum < 0)
|
||||||
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
||||||
|
|
||||||
sector = §ors[secnum];
|
sector = §ors[secnum];
|
||||||
|
|
||||||
|
@ -2463,15 +2530,17 @@ void FParser::SF_Gamemode(void)
|
||||||
|
|
||||||
void FParser::SF_IsPlayerObj(void)
|
void FParser::SF_IsPlayerObj(void)
|
||||||
{
|
{
|
||||||
|
// use trigger object if not specified
|
||||||
AActor *mo;
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
if(!t_argc)
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
mo = Script->trigger;
|
mo = Script->trigger;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
mo = actorvalue(t_argv[0]);
|
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
t_return.value.i = (mo && mo->player) ? 1 : 0;
|
t_return.value.i = (mo && mo->player) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
@ -2770,9 +2839,9 @@ void FParser::SF_PlayerWeapon()
|
||||||
"PlasmaRifle", "BFG9000", "Chainsaw", "SuperShotgun" };
|
"PlasmaRifle", "BFG9000", "Chainsaw", "SuperShotgun" };
|
||||||
|
|
||||||
|
|
||||||
int playernum;
|
int playernum;
|
||||||
int weaponnum;
|
int weaponnum;
|
||||||
int newweapon;
|
int newweapon;
|
||||||
|
|
||||||
if (CheckArgs(2))
|
if (CheckArgs(2))
|
||||||
{
|
{
|
||||||
|
@ -3014,7 +3083,7 @@ void FParser::SF_MoveCamera(void)
|
||||||
// I have to use floats for the math where angles are divided
|
// I have to use floats for the math where angles are divided
|
||||||
// by fixed values.
|
// by fixed values.
|
||||||
double fangledist, fanglestep, fmovestep;
|
double fangledist, fanglestep, fmovestep;
|
||||||
int angledir;
|
int angledir;
|
||||||
AActor* target;
|
AActor* target;
|
||||||
int moved;
|
int moved;
|
||||||
int quad1, quad2;
|
int quad1, quad2;
|
||||||
|
@ -3177,17 +3246,21 @@ void FParser::SF_MoveCamera(void)
|
||||||
|
|
||||||
void FParser::SF_ObjAwaken(void)
|
void FParser::SF_ObjAwaken(void)
|
||||||
{
|
{
|
||||||
AActor *mo;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
if(!t_argc)
|
if(mo)
|
||||||
mo = Script->trigger;
|
{
|
||||||
else
|
mo->Activate(Script->trigger);
|
||||||
mo = actorvalue(t_argv[0]);
|
}
|
||||||
|
|
||||||
if(mo)
|
|
||||||
{
|
|
||||||
mo->Activate(Script->trigger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -3316,9 +3389,9 @@ void FParser::SF_SpawnExplosion()
|
||||||
|
|
||||||
void FParser::SF_RadiusAttack()
|
void FParser::SF_RadiusAttack()
|
||||||
{
|
{
|
||||||
AActor *spot;
|
AActor *spot;
|
||||||
AActor *source;
|
AActor *source;
|
||||||
int damage;
|
int damage;
|
||||||
|
|
||||||
if (CheckArgs(3))
|
if (CheckArgs(3))
|
||||||
{
|
{
|
||||||
|
@ -3367,13 +3440,22 @@ void FParser::SF_SetObjPosition()
|
||||||
|
|
||||||
void FParser::SF_TestLocation()
|
void FParser::SF_TestLocation()
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
if (mo)
|
if(t_argc)
|
||||||
{
|
{
|
||||||
t_return.type = svt_int;
|
mo = actorvalue(t_argv[0]);
|
||||||
t_return.value.f = !!P_TestMobjLocation(mo);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mo)
|
||||||
|
{
|
||||||
|
t_return.type = svt_int;
|
||||||
|
t_return.value.f = !!P_TestMobjLocation(mo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -3384,7 +3466,16 @@ void FParser::SF_TestLocation()
|
||||||
|
|
||||||
void FParser::SF_HealObj() //no pain sound
|
void FParser::SF_HealObj() //no pain sound
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
if(t_argc < 2)
|
if(t_argc < 2)
|
||||||
{
|
{
|
||||||
|
@ -3411,8 +3502,17 @@ void FParser::SF_HealObj() //no pain sound
|
||||||
|
|
||||||
void FParser::SF_ObjDead()
|
void FParser::SF_ObjDead()
|
||||||
{
|
{
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
// use trigger object if not specified
|
||||||
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
if(mo && (mo->health <= 0 || mo->flags&MF_CORPSE))
|
if(mo && (mo->health <= 0 || mo->flags&MF_CORPSE))
|
||||||
t_return.value.i = 1;
|
t_return.value.i = 1;
|
||||||
|
@ -3428,8 +3528,8 @@ void FParser::SF_ObjDead()
|
||||||
|
|
||||||
void FParser::SF_SpawnMissile()
|
void FParser::SF_SpawnMissile()
|
||||||
{
|
{
|
||||||
AActor *mobj;
|
AActor *mobj;
|
||||||
AActor *target;
|
AActor *target;
|
||||||
const PClass * PClass;
|
const PClass * PClass;
|
||||||
|
|
||||||
if (CheckArgs(3))
|
if (CheckArgs(3))
|
||||||
|
@ -3450,9 +3550,9 @@ void FParser::SF_SpawnMissile()
|
||||||
|
|
||||||
void FParser::SF_MapThingNumExist()
|
void FParser::SF_MapThingNumExist()
|
||||||
{
|
{
|
||||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||||
|
|
||||||
int intval;
|
int intval;
|
||||||
|
|
||||||
if (CheckArgs(1))
|
if (CheckArgs(1))
|
||||||
{
|
{
|
||||||
|
@ -3479,10 +3579,10 @@ void FParser::SF_MapThingNumExist()
|
||||||
|
|
||||||
void FParser::SF_MapThings()
|
void FParser::SF_MapThings()
|
||||||
{
|
{
|
||||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||||
|
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
t_return.value.i = SpawnedThings.Size();
|
t_return.value.i = SpawnedThings.Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3495,7 +3595,7 @@ void FParser::SF_MapThings()
|
||||||
void FParser::SF_ObjState()
|
void FParser::SF_ObjState()
|
||||||
{
|
{
|
||||||
int state;
|
int state;
|
||||||
AActor *mo;
|
AActor *mo = NULL;
|
||||||
|
|
||||||
if (CheckArgs(1))
|
if (CheckArgs(1))
|
||||||
{
|
{
|
||||||
|
@ -3691,7 +3791,15 @@ void FParser::SF_LineAttack()
|
||||||
void FParser::SF_ObjType()
|
void FParser::SF_ObjType()
|
||||||
{
|
{
|
||||||
// use trigger object if not specified
|
// use trigger object if not specified
|
||||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
AActor *mo;
|
||||||
|
if(t_argc)
|
||||||
|
{
|
||||||
|
mo = actorvalue(t_argv[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mo = Script->trigger;
|
||||||
|
}
|
||||||
|
|
||||||
for(unsigned int i=0;i<countof(ActorTypes);i++) if (mo->GetClass() == ActorTypes[i])
|
for(unsigned int i=0;i<countof(ActorTypes);i++) if (mo->GetClass() == ActorTypes[i])
|
||||||
{
|
{
|
||||||
|
@ -3851,38 +3959,38 @@ void FParser::SF_DeleteHUPic()
|
||||||
{
|
{
|
||||||
if (CheckArgs(1))
|
if (CheckArgs(1))
|
||||||
{
|
{
|
||||||
if (HU_DeleteFSPic(intvalue(t_argv[0])) == -1)
|
if (HU_DeleteFSPic(intvalue(t_argv[0])) == -1)
|
||||||
script_error("deletehupic: Invalid sfpic handle: %i\n", intvalue(t_argv[0]));
|
script_error("deletehupic: Invalid sfpic handle: %i\n", intvalue(t_argv[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FParser::SF_ModifyHUPic()
|
void FParser::SF_ModifyHUPic()
|
||||||
{
|
{
|
||||||
if (t_argc != 4)
|
if (t_argc != 4)
|
||||||
{
|
{
|
||||||
script_error("modifyhupic: invalid number of arguments\n");
|
script_error("modifyhupic: invalid number of arguments\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HU_ModifyFSPic(intvalue(t_argv[0]),
|
if (HU_ModifyFSPic(intvalue(t_argv[0]),
|
||||||
TexMan.GetTexture(stringvalue(t_argv[0]), FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny),
|
TexMan.GetTexture(stringvalue(t_argv[0]), FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny),
|
||||||
intvalue(t_argv[2]), intvalue(t_argv[3])) == -1)
|
intvalue(t_argv[2]), intvalue(t_argv[3])) == -1)
|
||||||
{
|
{
|
||||||
script_error("modifyhypic: invalid sfpic handle %i\n", intvalue(t_argv[0]));
|
script_error("modifyhypic: invalid sfpic handle %i\n", intvalue(t_argv[0]));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FParser::SF_SetHUPicDisplay()
|
void FParser::SF_SetHUPicDisplay()
|
||||||
{
|
{
|
||||||
if (t_argc != 2)
|
if (t_argc != 2)
|
||||||
{
|
{
|
||||||
script_error("sethupicdisplay: invalud number of arguments\n");
|
script_error("sethupicdisplay: invalud number of arguments\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HU_FSDisplay(intvalue(t_argv[0]), intvalue(t_argv[1]) > 0 ? 1 : 0) == -1)
|
if (HU_FSDisplay(intvalue(t_argv[0]), intvalue(t_argv[1]) > 0 ? 1 : 0) == -1)
|
||||||
script_error("sethupicdisplay: invalid pic handle %i\n", intvalue(t_argv[0]));
|
script_error("sethupicdisplay: invalid pic handle %i\n", intvalue(t_argv[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3900,47 +4008,47 @@ void FParser::SF_SetCorona(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num = t_argv[0].value.i; // which corona we want to modify
|
int num = t_argv[0].value.i; // which corona we want to modify
|
||||||
int what = t_argv[1].value.i; // what we want to modify (type, color, offset,...)
|
int what = t_argv[1].value.i; // what we want to modify (type, color, offset,...)
|
||||||
int ival = t_argv[2].value.i; // the value of what we modify
|
int ival = t_argv[2].value.i; // the value of what we modify
|
||||||
double fval = ((double) t_argv[2].value.f / FRACUNIT);
|
double fval = ((double) t_argv[2].value.f / FRACUNIT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
switch (what)
|
switch (what)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
lspr[num].type = ival;
|
lspr[num].type = ival;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
lspr[num].light_xoffset = fval;
|
lspr[num].light_xoffset = fval;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
lspr[num].light_yoffset = fval;
|
lspr[num].light_yoffset = fval;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (t_argv[2].type == svt_string)
|
if (t_argv[2].type == svt_string)
|
||||||
lspr[num].corona_color = String2Hex(t_argv[2].value.s);
|
lspr[num].corona_color = String2Hex(t_argv[2].value.s);
|
||||||
else
|
else
|
||||||
memcpy(&lspr[num].corona_color, &ival, sizeof(int));
|
memcpy(&lspr[num].corona_color, &ival, sizeof(int));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
lspr[num].corona_radius = fval;
|
lspr[num].corona_radius = fval;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (t_argv[2].type == svt_string)
|
if (t_argv[2].type == svt_string)
|
||||||
lspr[num].dynamic_color = String2Hex(t_argv[2].value.s);
|
lspr[num].dynamic_color = String2Hex(t_argv[2].value.s);
|
||||||
else
|
else
|
||||||
memcpy(&lspr[num].dynamic_color, &ival, sizeof(int));
|
memcpy(&lspr[num].dynamic_color, &ival, sizeof(int));
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
lspr[num].dynamic_radius = fval;
|
lspr[num].dynamic_radius = fval;
|
||||||
lspr[num].dynamic_sqrradius = sqrt(lspr[num].dynamic_radius);
|
lspr[num].dynamic_sqrradius = sqrt(lspr[num].dynamic_radius);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CONS_Printf("Error in setcorona\n");
|
CONS_Printf("Error in setcorona\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// no use for this!
|
// no use for this!
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
|
@ -4074,7 +4182,7 @@ again:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (mo=it.Next())
|
while ((mo=it.Next()))
|
||||||
{
|
{
|
||||||
if (mo->IsA(pClass) && mo->health>0) count++;
|
if (mo->IsA(pClass) && mo->health>0) count++;
|
||||||
}
|
}
|
||||||
|
@ -4361,10 +4469,10 @@ void FParser::SF_Wait()
|
||||||
DRunningScript *runscr;
|
DRunningScript *runscr;
|
||||||
|
|
||||||
if(t_argc != 1)
|
if(t_argc != 1)
|
||||||
{
|
{
|
||||||
script_error("incorrect arguments to function\n");
|
script_error("incorrect arguments to function\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runscr = SaveCurrentScript();
|
runscr = SaveCurrentScript();
|
||||||
|
|
||||||
|
@ -4385,10 +4493,10 @@ void FParser::SF_TagWait()
|
||||||
DRunningScript *runscr;
|
DRunningScript *runscr;
|
||||||
|
|
||||||
if(t_argc != 1)
|
if(t_argc != 1)
|
||||||
{
|
{
|
||||||
script_error("incorrect arguments to function\n");
|
script_error("incorrect arguments to function\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runscr = SaveCurrentScript();
|
runscr = SaveCurrentScript();
|
||||||
|
|
||||||
|
@ -4408,10 +4516,10 @@ void FParser::SF_ScriptWait()
|
||||||
DRunningScript *runscr;
|
DRunningScript *runscr;
|
||||||
|
|
||||||
if(t_argc != 1)
|
if(t_argc != 1)
|
||||||
{
|
{
|
||||||
script_error("insufficient arguments to function\n");
|
script_error("insufficient arguments to function\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runscr = SaveCurrentScript();
|
runscr = SaveCurrentScript();
|
||||||
|
|
||||||
|
@ -4451,10 +4559,10 @@ void FParser::SF_ScriptWaitPre()
|
||||||
void FParser::SF_StartScript()
|
void FParser::SF_StartScript()
|
||||||
{
|
{
|
||||||
if(t_argc != 1)
|
if(t_argc != 1)
|
||||||
{
|
{
|
||||||
script_error("incorrect arguments to function\n");
|
script_error("incorrect arguments to function\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snum = intvalue(t_argv[0]);
|
int snum = intvalue(t_argv[0]);
|
||||||
|
|
||||||
|
@ -4493,15 +4601,15 @@ void FParser::SF_ScriptRunning()
|
||||||
int snum = 0;
|
int snum = 0;
|
||||||
|
|
||||||
if(t_argc < 1)
|
if(t_argc < 1)
|
||||||
{
|
{
|
||||||
script_error("not enough arguments to function\n");
|
script_error("not enough arguments to function\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
snum = intvalue(t_argv[0]);
|
snum = intvalue(t_argv[0]);
|
||||||
|
|
||||||
for(current = DFraggleThinker::ActiveThinker->RunningScripts->next; current; current=current->next)
|
for(current = DFraggleThinker::ActiveThinker->RunningScripts->next; current; current=current->next)
|
||||||
{
|
{
|
||||||
if(current->script->scriptnum == snum)
|
if(current->script->scriptnum == snum)
|
||||||
{
|
{
|
||||||
// script found so return
|
// script found so return
|
||||||
|
@ -4509,7 +4617,7 @@ void FParser::SF_ScriptRunning()
|
||||||
t_return.value.i = 1;
|
t_return.value.i = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// script not found
|
// script not found
|
||||||
t_return.type = svt_int;
|
t_return.type = svt_int;
|
||||||
|
@ -4578,27 +4686,27 @@ void init_functions(void)
|
||||||
new_function("playertip", &FParser::SF_PlayerTip);
|
new_function("playertip", &FParser::SF_PlayerTip);
|
||||||
new_function("playeringame", &FParser::SF_PlayerInGame);
|
new_function("playeringame", &FParser::SF_PlayerInGame);
|
||||||
new_function("playername", &FParser::SF_PlayerName);
|
new_function("playername", &FParser::SF_PlayerName);
|
||||||
new_function("playeraddfrag", &FParser::SF_PlayerAddFrag);
|
new_function("playeraddfrag", &FParser::SF_PlayerAddFrag);
|
||||||
new_function("playerobj", &FParser::SF_PlayerObj);
|
new_function("playerobj", &FParser::SF_PlayerObj);
|
||||||
new_function("isplayerobj", &FParser::SF_IsPlayerObj);
|
new_function("isplayerobj", &FParser::SF_IsPlayerObj);
|
||||||
new_function("isobjplayer", &FParser::SF_IsPlayerObj);
|
new_function("isobjplayer", &FParser::SF_IsPlayerObj);
|
||||||
new_function("skincolor", &FParser::SF_SkinColor);
|
new_function("skincolor", &FParser::SF_SkinColor);
|
||||||
new_function("playerkeys", &FParser::SF_PlayerKeys);
|
new_function("playerkeys", &FParser::SF_PlayerKeys);
|
||||||
new_function("playerammo", &FParser::SF_PlayerAmmo);
|
new_function("playerammo", &FParser::SF_PlayerAmmo);
|
||||||
new_function("maxplayerammo", &FParser::SF_MaxPlayerAmmo);
|
new_function("maxplayerammo", &FParser::SF_MaxPlayerAmmo);
|
||||||
new_function("playerweapon", &FParser::SF_PlayerWeapon);
|
new_function("playerweapon", &FParser::SF_PlayerWeapon);
|
||||||
new_function("playerselwep", &FParser::SF_PlayerSelectedWeapon);
|
new_function("playerselwep", &FParser::SF_PlayerSelectedWeapon);
|
||||||
|
|
||||||
// mobj stuff
|
// mobj stuff
|
||||||
new_function("spawn", &FParser::SF_Spawn);
|
new_function("spawn", &FParser::SF_Spawn);
|
||||||
new_function("spawnexplosion", &FParser::SF_SpawnExplosion);
|
new_function("spawnexplosion", &FParser::SF_SpawnExplosion);
|
||||||
new_function("radiusattack", &FParser::SF_RadiusAttack);
|
new_function("radiusattack", &FParser::SF_RadiusAttack);
|
||||||
new_function("kill", &FParser::SF_KillObj);
|
new_function("kill", &FParser::SF_KillObj);
|
||||||
new_function("removeobj", &FParser::SF_RemoveObj);
|
new_function("removeobj", &FParser::SF_RemoveObj);
|
||||||
new_function("objx", &FParser::SF_ObjX);
|
new_function("objx", &FParser::SF_ObjX);
|
||||||
new_function("objy", &FParser::SF_ObjY);
|
new_function("objy", &FParser::SF_ObjY);
|
||||||
new_function("objz", &FParser::SF_ObjZ);
|
new_function("objz", &FParser::SF_ObjZ);
|
||||||
new_function("testlocation", &FParser::SF_TestLocation);
|
new_function("testlocation", &FParser::SF_TestLocation);
|
||||||
new_function("teleport", &FParser::SF_Teleport);
|
new_function("teleport", &FParser::SF_Teleport);
|
||||||
new_function("silentteleport", &FParser::SF_SilentTeleport);
|
new_function("silentteleport", &FParser::SF_SilentTeleport);
|
||||||
new_function("damageobj", &FParser::SF_DamageObj);
|
new_function("damageobj", &FParser::SF_DamageObj);
|
||||||
|
@ -4618,10 +4726,10 @@ void init_functions(void)
|
||||||
new_function("objmomy", &FParser::SF_MobjMomy);
|
new_function("objmomy", &FParser::SF_MobjMomy);
|
||||||
new_function("objmomz", &FParser::SF_MobjMomz);
|
new_function("objmomz", &FParser::SF_MobjMomz);
|
||||||
|
|
||||||
new_function("spawnmissile", &FParser::SF_SpawnMissile);
|
new_function("spawnmissile", &FParser::SF_SpawnMissile);
|
||||||
new_function("mapthings", &FParser::SF_MapThings);
|
new_function("mapthings", &FParser::SF_MapThings);
|
||||||
new_function("objtype", &FParser::SF_ObjType);
|
new_function("objtype", &FParser::SF_ObjType);
|
||||||
new_function("mapthingnumexist", &FParser::SF_MapThingNumExist);
|
new_function("mapthingnumexist", &FParser::SF_MapThingNumExist);
|
||||||
new_function("objstate", &FParser::SF_ObjState);
|
new_function("objstate", &FParser::SF_ObjState);
|
||||||
new_function("resurrect", &FParser::SF_Resurrect);
|
new_function("resurrect", &FParser::SF_Resurrect);
|
||||||
new_function("lineattack", &FParser::SF_LineAttack);
|
new_function("lineattack", &FParser::SF_LineAttack);
|
||||||
|
@ -4665,19 +4773,19 @@ void init_functions(void)
|
||||||
new_function("opendoor", &FParser::SF_OpenDoor);
|
new_function("opendoor", &FParser::SF_OpenDoor);
|
||||||
new_function("closedoor", &FParser::SF_CloseDoor);
|
new_function("closedoor", &FParser::SF_CloseDoor);
|
||||||
|
|
||||||
// HU Graphics
|
// HU Graphics
|
||||||
new_function("newhupic", &FParser::SF_NewHUPic);
|
new_function("newhupic", &FParser::SF_NewHUPic);
|
||||||
new_function("createpic", &FParser::SF_NewHUPic);
|
new_function("createpic", &FParser::SF_NewHUPic);
|
||||||
new_function("deletehupic", &FParser::SF_DeleteHUPic);
|
new_function("deletehupic", &FParser::SF_DeleteHUPic);
|
||||||
new_function("modifyhupic", &FParser::SF_ModifyHUPic);
|
new_function("modifyhupic", &FParser::SF_ModifyHUPic);
|
||||||
new_function("modifypic", &FParser::SF_ModifyHUPic);
|
new_function("modifypic", &FParser::SF_ModifyHUPic);
|
||||||
new_function("sethupicdisplay", &FParser::SF_SetHUPicDisplay);
|
new_function("sethupicdisplay", &FParser::SF_SetHUPicDisplay);
|
||||||
new_function("setpicvisible", &FParser::SF_SetHUPicDisplay);
|
new_function("setpicvisible", &FParser::SF_SetHUPicDisplay);
|
||||||
|
|
||||||
//
|
//
|
||||||
new_function("playdemo", &FParser::SF_PlayDemo);
|
new_function("playdemo", &FParser::SF_PlayDemo);
|
||||||
new_function("runcommand", &FParser::SF_RunCommand);
|
new_function("runcommand", &FParser::SF_RunCommand);
|
||||||
new_function("checkcvar", &FParser::SF_CheckCVar);
|
new_function("checkcvar", &FParser::SF_CheckCVar);
|
||||||
new_function("setlinetexture", &FParser::SF_SetLineTexture);
|
new_function("setlinetexture", &FParser::SF_SetLineTexture);
|
||||||
new_function("linetrigger", &FParser::SF_LineTrigger);
|
new_function("linetrigger", &FParser::SF_LineTrigger);
|
||||||
new_function("lineflag", &FParser::SF_LineFlag);
|
new_function("lineflag", &FParser::SF_LineFlag);
|
||||||
|
|
|
@ -328,7 +328,7 @@ void T_RegisterSpawnThing(AActor * ac)
|
||||||
{
|
{
|
||||||
if (DFraggleThinker::ActiveThinker)
|
if (DFraggleThinker::ActiveThinker)
|
||||||
{
|
{
|
||||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||||
SpawnedThings[SpawnedThings.Size()-1] = ac;
|
SpawnedThings[SpawnedThings.Size()-1] = ac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,7 +655,7 @@ public:
|
||||||
|
|
||||||
TObjPtr<DFsScript> LevelScript;
|
TObjPtr<DFsScript> LevelScript;
|
||||||
TObjPtr<DRunningScript> RunningScripts;
|
TObjPtr<DRunningScript> RunningScripts;
|
||||||
TArray<TObjPtr<AActor>> SpawnedThings;
|
TArray<TObjPtr<AActor> > SpawnedThings;
|
||||||
|
|
||||||
DFraggleThinker();
|
DFraggleThinker();
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
|
@ -133,7 +133,7 @@ const char *stringvalue(const svalue_t & v)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
AActor *actorvalue(const svalue_t &svalue)
|
AActor* actorvalue(const svalue_t &svalue)
|
||||||
{
|
{
|
||||||
int intval;
|
int intval;
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ AActor *actorvalue(const svalue_t &svalue)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||||
// this requires some creativity. We use the intvalue
|
// this requires some creativity. We use the intvalue
|
||||||
// as the thing number of a thing in the level.
|
// as the thing number of a thing in the level.
|
||||||
intval = intvalue(svalue);
|
intval = intvalue(svalue);
|
||||||
|
|
|
@ -125,6 +125,11 @@ public:
|
||||||
OldFaceIndex = -1;
|
OldFaceIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddFaceToImageCollection (void *skn, FImageCollection *images)
|
||||||
|
{
|
||||||
|
AddFaceToImageCollectionActual (skn, images, true);
|
||||||
|
}
|
||||||
|
|
||||||
void MultiplayerChanged ()
|
void MultiplayerChanged ()
|
||||||
{
|
{
|
||||||
DBaseStatusBar::MultiplayerChanged ();
|
DBaseStatusBar::MultiplayerChanged ();
|
||||||
|
@ -989,24 +994,6 @@ private:
|
||||||
NUM_DOOMSB_IMAGES
|
NUM_DOOMSB_IMAGES
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ST_NUMPAINFACES = 5,
|
|
||||||
ST_NUMSTRAIGHTFACES = 3,
|
|
||||||
ST_NUMTURNFACES = 2,
|
|
||||||
ST_NUMSPECIALFACES = 3,
|
|
||||||
ST_NUMEXTRAFACES = 2,
|
|
||||||
ST_FACESTRIDE = ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES,
|
|
||||||
ST_NUMFACES = ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES,
|
|
||||||
|
|
||||||
ST_TURNOFFSET = ST_NUMSTRAIGHTFACES,
|
|
||||||
ST_OUCHOFFSET = ST_TURNOFFSET + ST_NUMTURNFACES,
|
|
||||||
ST_EVILGRINOFFSET = ST_OUCHOFFSET + 1,
|
|
||||||
ST_RAMPAGEOFFSET = ST_EVILGRINOFFSET + 1,
|
|
||||||
ST_GODFACE = ST_NUMPAINFACES*ST_FACESTRIDE,
|
|
||||||
ST_DEADFACE = ST_GODFACE + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
FImageCollection Images;
|
FImageCollection Images;
|
||||||
FImageCollection Faces;
|
FImageCollection Faces;
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,25 @@ public:
|
||||||
POP_Status
|
POP_Status
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Status face stuff
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ST_NUMPAINFACES = 5,
|
||||||
|
ST_NUMSTRAIGHTFACES = 3,
|
||||||
|
ST_NUMTURNFACES = 2,
|
||||||
|
ST_NUMSPECIALFACES = 3,
|
||||||
|
ST_NUMEXTRAFACES = 2,
|
||||||
|
ST_FACESTRIDE = ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES,
|
||||||
|
ST_NUMFACES = ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES,
|
||||||
|
|
||||||
|
ST_TURNOFFSET = ST_NUMSTRAIGHTFACES,
|
||||||
|
ST_OUCHOFFSET = ST_TURNOFFSET + ST_NUMTURNFACES,
|
||||||
|
ST_EVILGRINOFFSET = ST_OUCHOFFSET + 1,
|
||||||
|
ST_RAMPAGEOFFSET = ST_EVILGRINOFFSET + 1,
|
||||||
|
ST_GODFACE = ST_NUMPAINFACES*ST_FACESTRIDE,
|
||||||
|
ST_DEADFACE = ST_GODFACE + 1
|
||||||
|
};
|
||||||
|
|
||||||
DBaseStatusBar (int reltop);
|
DBaseStatusBar (int reltop);
|
||||||
void Destroy ();
|
void Destroy ();
|
||||||
|
|
||||||
|
@ -190,7 +209,8 @@ public:
|
||||||
virtual void AttachToPlayer (player_s *player);
|
virtual void AttachToPlayer (player_s *player);
|
||||||
virtual void FlashCrosshair ();
|
virtual void FlashCrosshair ();
|
||||||
virtual void BlendView (float blend[4]);
|
virtual void BlendView (float blend[4]);
|
||||||
virtual void SetFace (void *); // Takes a FPlayerSkin as input
|
virtual void SetFace (void *skn); // Takes a FPlayerSkin as input
|
||||||
|
virtual void AddFaceToImageCollection (void *skn, FImageCollection *images); // Takes a FPlayerSkin as input
|
||||||
virtual void NewGame ();
|
virtual void NewGame ();
|
||||||
virtual void ScreenSizeChanged ();
|
virtual void ScreenSizeChanged ();
|
||||||
virtual void MultiplayerChanged ();
|
virtual void MultiplayerChanged ();
|
||||||
|
@ -222,6 +242,8 @@ protected:
|
||||||
|
|
||||||
void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const;
|
void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const;
|
||||||
|
|
||||||
|
void AddFaceToImageCollectionActual (void *skn, FImageCollection *images, bool isDoom);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AInventory *ValidateInvFirst (int numVisible) const;
|
AInventory *ValidateInvFirst (int numVisible) const;
|
||||||
void DrawCrosshair ();
|
void DrawCrosshair ();
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct SBarInfo
|
||||||
bool interpolateHealth;
|
bool interpolateHealth;
|
||||||
bool interpolateArmor;
|
bool interpolateArmor;
|
||||||
bool completeBorder;
|
bool completeBorder;
|
||||||
|
bool lowerHealthCap;
|
||||||
char spacingCharacter;
|
char spacingCharacter;
|
||||||
int interpolationSpeed;
|
int interpolationSpeed;
|
||||||
int armorInterpolationSpeed;
|
int armorInterpolationSpeed;
|
||||||
|
@ -119,7 +120,7 @@ struct MugShotFrame
|
||||||
|
|
||||||
MugShotFrame();
|
MugShotFrame();
|
||||||
~MugShotFrame();
|
~MugShotFrame();
|
||||||
FTexture *getTexture(FPlayerSkin *skn, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false);
|
FTexture *getTexture(FString &defaultFace, FPlayerSkin *skn, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ struct MugShotState
|
||||||
void tick();
|
void tick();
|
||||||
void reset();
|
void reset();
|
||||||
MugShotFrame getCurrentFrame() { return frames[position]; }
|
MugShotFrame getCurrentFrame() { return frames[position]; }
|
||||||
FTexture *getCurrentFrameTexture(FPlayerSkin *skn, int level=0, int direction=0) { return getCurrentFrame().getTexture(skn, random, level, direction, usesLevels, health2, healthspecial, directional); }
|
FTexture *getCurrentFrameTexture(FString &defaultFace, FPlayerSkin *skn, int level=0, int direction=0) { return getCurrentFrame().getTexture(defaultFace, skn, random, level, direction, usesLevels, health2, healthspecial, directional); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TArray<MugShotState> MugShotStates;
|
extern TArray<MugShotState> MugShotStates;
|
||||||
|
@ -197,6 +198,7 @@ enum //drawnumber flags
|
||||||
DRAWNUMBER_SECRETS = 4096,
|
DRAWNUMBER_SECRETS = 4096,
|
||||||
DRAWNUMBER_TOTALSECRETS = 8192,
|
DRAWNUMBER_TOTALSECRETS = 8192,
|
||||||
DRAWNUMBER_ARMORCLASS = 16384,
|
DRAWNUMBER_ARMORCLASS = 16384,
|
||||||
|
DRAWNUMBER_GLOBALVAR = 32768,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum //drawbar flags (will go into special2)
|
enum //drawbar flags (will go into special2)
|
||||||
|
@ -253,6 +255,14 @@ enum //event flags
|
||||||
SBARINFOEVENT_AND = 4,
|
SBARINFOEVENT_AND = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum //aspect ratios
|
||||||
|
{
|
||||||
|
ASPECTRATIO_4_3 = 0,
|
||||||
|
ASPECTRATIO_16_9 = 1,
|
||||||
|
ASPECTRATIO_16_10 = 2,
|
||||||
|
ASPECTRATIO_5_4 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
enum //Key words
|
enum //Key words
|
||||||
{
|
{
|
||||||
SBARINFO_BASE,
|
SBARINFO_BASE,
|
||||||
|
@ -261,6 +271,7 @@ enum //Key words
|
||||||
SBARINFO_INTERPOLATEARMOR,
|
SBARINFO_INTERPOLATEARMOR,
|
||||||
SBARINFO_COMPLETEBORDER,
|
SBARINFO_COMPLETEBORDER,
|
||||||
SBARINFO_MONOSPACEFONTS,
|
SBARINFO_MONOSPACEFONTS,
|
||||||
|
SBARINFO_LOWERHEALTHCAP,
|
||||||
SBARINFO_STATUSBAR,
|
SBARINFO_STATUSBAR,
|
||||||
SBARINFO_MUGSHOT,
|
SBARINFO_MUGSHOT,
|
||||||
};
|
};
|
||||||
|
@ -293,7 +304,9 @@ enum //Bar key words
|
||||||
SBARINFO_DRAWKEYBAR,
|
SBARINFO_DRAWKEYBAR,
|
||||||
SBARINFO_GAMEMODE,
|
SBARINFO_GAMEMODE,
|
||||||
SBARINFO_PLAYERCLASS,
|
SBARINFO_PLAYERCLASS,
|
||||||
|
SBARINFO_ASPECTRATIO,
|
||||||
SBARINFO_WEAPONAMMO,
|
SBARINFO_WEAPONAMMO,
|
||||||
|
SBARINFO_ININVENTORY,
|
||||||
};
|
};
|
||||||
|
|
||||||
//All this so I can change the mugshot state in ACS...
|
//All this so I can change the mugshot state in ACS...
|
||||||
|
@ -321,13 +334,14 @@ public:
|
||||||
void Tick();
|
void Tick();
|
||||||
void ReceivedWeapon (AWeapon *weapon);
|
void ReceivedWeapon (AWeapon *weapon);
|
||||||
void FlashItem(const PClass *itemtype);
|
void FlashItem(const PClass *itemtype);
|
||||||
|
void ShowPop(int popnum);
|
||||||
void SetMugShotState(const char* stateName, bool waitTillDone=false);
|
void SetMugShotState(const char* stateName, bool waitTillDone=false);
|
||||||
private:
|
private:
|
||||||
void doCommands(SBarInfoBlock &block);
|
void doCommands(SBarInfoBlock &block);
|
||||||
void DrawGraphic(FTexture* texture, int x, int y, int flags);
|
void DrawGraphic(FTexture* texture, int x, int y, int flags);
|
||||||
void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0);
|
void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0);
|
||||||
void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0);
|
void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0);
|
||||||
void DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y);
|
void DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y);
|
||||||
int updateState(bool xdth, bool animatedgodmode);
|
int updateState(bool xdth, bool animatedgodmode);
|
||||||
void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow,
|
void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow,
|
||||||
int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter);
|
int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter);
|
||||||
|
@ -349,6 +363,7 @@ private:
|
||||||
int mugshotHealth;
|
int mugshotHealth;
|
||||||
int chainWiggle;
|
int chainWiggle;
|
||||||
int artiflash;
|
int artiflash;
|
||||||
|
int currentPopup;
|
||||||
unsigned int invBarOffset;
|
unsigned int invBarOffset;
|
||||||
FBarShader shader_horz_normal;
|
FBarShader shader_horz_normal;
|
||||||
FBarShader shader_horz_reverse;
|
FBarShader shader_horz_reverse;
|
||||||
|
|
|
@ -83,13 +83,13 @@ MugShotFrame::~MugShotFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Assemble a graphic name with the specified prefix and return the FTexture.
|
//Assemble a graphic name with the specified prefix and return the FTexture.
|
||||||
FTexture *MugShotFrame::getTexture(FPlayerSkin *skin, int random, int level, int direction, bool usesLevels, bool health2, bool healthspecial, bool directional)
|
FTexture *MugShotFrame::getTexture(FString &defaultFace, FPlayerSkin *skin, int random, int level, int direction, bool usesLevels, bool health2, bool healthspecial, bool directional)
|
||||||
{
|
{
|
||||||
int index = !directional ? random % graphic.Size() : direction;
|
int index = !directional ? random % graphic.Size() : direction;
|
||||||
if(index > (signed int) (graphic.Size()-1))
|
if(index > (signed int) (graphic.Size()-1))
|
||||||
index = graphic.Size()-1;
|
index = graphic.Size()-1;
|
||||||
char* sprite = new char[9];
|
char* sprite = new char[9];
|
||||||
memcpy(sprite, skin->face[0] != 0 ? skin->face : "STF", 3);
|
memcpy(sprite, skin->face[0] != 0 ? skin->face : defaultFace, 3);
|
||||||
memcpy(sprite+3, graphic[index], strlen(graphic[index]));
|
memcpy(sprite+3, graphic[index], strlen(graphic[index]));
|
||||||
sprite[3+strlen(graphic[index])] = '\0';
|
sprite[3+strlen(graphic[index])] = '\0';
|
||||||
if(usesLevels) //change the last character to the level
|
if(usesLevels) //change the last character to the level
|
||||||
|
@ -249,6 +249,10 @@ DSBarInfo::DSBarInfo () : DBaseStatusBar (SBarInfoScript->height),
|
||||||
{
|
{
|
||||||
patchnames[i+SBarInfoScript->Images.Size()] = InventoryBarLumps[i];
|
patchnames[i+SBarInfoScript->Images.Size()] = InventoryBarLumps[i];
|
||||||
}
|
}
|
||||||
|
for (i = 0;i < numskins;i++)
|
||||||
|
{
|
||||||
|
AddFaceToImageCollection (&skins[i], &Images);
|
||||||
|
}
|
||||||
invBarOffset = SBarInfoScript->Images.Size();
|
invBarOffset = SBarInfoScript->Images.Size();
|
||||||
Images.Init(&patchnames[0], patchnames.Size());
|
Images.Init(&patchnames[0], patchnames.Size());
|
||||||
drawingFont = V_GetFont("ConFont");
|
drawingFont = V_GetFont("ConFont");
|
||||||
|
@ -313,6 +317,15 @@ void DSBarInfo::Draw (EHudState state)
|
||||||
else if(state == HUD_Fullscreen)
|
else if(state == HUD_Fullscreen)
|
||||||
doCommands(SBarInfoScript->huds[STBAR_INVENTORYFULLSCREEN]);
|
doCommands(SBarInfoScript->huds[STBAR_INVENTORYFULLSCREEN]);
|
||||||
}
|
}
|
||||||
|
if(currentPopup != POP_None)
|
||||||
|
{
|
||||||
|
if(currentPopup == POP_Log)
|
||||||
|
doCommands(SBarInfoScript->huds[STBAR_POPUPLOG]);
|
||||||
|
else if(currentPopup == POP_Keys)
|
||||||
|
doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS]);
|
||||||
|
else if(currentPopup == POP_Status)
|
||||||
|
doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSBarInfo::NewGame ()
|
void DSBarInfo::NewGame ()
|
||||||
|
@ -409,6 +422,15 @@ void DSBarInfo::FlashItem(const PClass *itemtype)
|
||||||
artiflash = 4;
|
artiflash = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSBarInfo::ShowPop(int popnum)
|
||||||
|
{
|
||||||
|
DBaseStatusBar::ShowPop(popnum);
|
||||||
|
if(popnum != currentPopup)
|
||||||
|
currentPopup = popnum;
|
||||||
|
else
|
||||||
|
currentPopup = POP_None;
|
||||||
|
}
|
||||||
|
|
||||||
//Public so it can be called by ACS
|
//Public so it can be called by ACS
|
||||||
//Sets the mug shot state and resets it if it is not the state we are already on.
|
//Sets the mug shot state and resets it if it is not the state we are already on.
|
||||||
//waitTillDone is basically a priority variable when just to true the state won't change unless the previous state is finished.
|
//waitTillDone is basically a priority variable when just to true the state won't change unless the previous state is finished.
|
||||||
|
@ -543,25 +565,27 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBARINFO_DRAWNUMBER:
|
case SBARINFO_DRAWNUMBER:
|
||||||
|
{
|
||||||
|
int value = cmd.value;
|
||||||
if(drawingFont != cmd.font)
|
if(drawingFont != cmd.font)
|
||||||
{
|
{
|
||||||
drawingFont = cmd.font;
|
drawingFont = cmd.font;
|
||||||
}
|
}
|
||||||
if(cmd.flags == DRAWNUMBER_HEALTH)
|
if(cmd.flags == DRAWNUMBER_HEALTH)
|
||||||
{
|
{
|
||||||
cmd.value = health;
|
value = health;
|
||||||
if(cmd.value < 0) //health shouldn't display negatives
|
if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives
|
||||||
{
|
{
|
||||||
cmd.value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(cmd.flags == DRAWNUMBER_ARMOR)
|
else if(cmd.flags == DRAWNUMBER_ARMOR)
|
||||||
{
|
{
|
||||||
cmd.value = armorAmount;
|
value = armorAmount;
|
||||||
}
|
}
|
||||||
else if(cmd.flags == DRAWNUMBER_AMMO1)
|
else if(cmd.flags == DRAWNUMBER_AMMO1)
|
||||||
{
|
{
|
||||||
cmd.value = ammocount1;
|
value = ammocount1;
|
||||||
if(ammo1 == NULL) //no ammo, do not draw
|
if(ammo1 == NULL) //no ammo, do not draw
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -569,7 +593,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
}
|
}
|
||||||
else if(cmd.flags == DRAWNUMBER_AMMO2)
|
else if(cmd.flags == DRAWNUMBER_AMMO2)
|
||||||
{
|
{
|
||||||
cmd.value = ammocount2;
|
value = ammocount2;
|
||||||
if(ammo2 == NULL) //no ammo, do not draw
|
if(ammo2 == NULL) //no ammo, do not draw
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -581,11 +605,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
||||||
if(item != NULL)
|
if(item != NULL)
|
||||||
{
|
{
|
||||||
cmd.value = item->Amount;
|
value = item->Amount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmd.value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY)
|
else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY)
|
||||||
|
@ -594,61 +618,64 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
||||||
if(item != NULL)
|
if(item != NULL)
|
||||||
{
|
{
|
||||||
cmd.value = item->MaxAmount;
|
value = item->MaxAmount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmd.value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
|
value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(cmd.flags == DRAWNUMBER_FRAGS)
|
else if(cmd.flags == DRAWNUMBER_FRAGS)
|
||||||
cmd.value = CPlayer->fragcount;
|
value = CPlayer->fragcount;
|
||||||
else if(cmd.flags == DRAWNUMBER_KILLS)
|
else if(cmd.flags == DRAWNUMBER_KILLS)
|
||||||
cmd.value = level.killed_monsters;
|
value = level.killed_monsters;
|
||||||
else if(cmd.flags == DRAWNUMBER_MONSTERS)
|
else if(cmd.flags == DRAWNUMBER_MONSTERS)
|
||||||
cmd.value = level.total_monsters;
|
value = level.total_monsters;
|
||||||
else if(cmd.flags == DRAWNUMBER_ITEMS)
|
else if(cmd.flags == DRAWNUMBER_ITEMS)
|
||||||
cmd.value = level.found_items;
|
value = level.found_items;
|
||||||
else if(cmd.flags == DRAWNUMBER_TOTALITEMS)
|
else if(cmd.flags == DRAWNUMBER_TOTALITEMS)
|
||||||
cmd.value = level.total_items;
|
value = level.total_items;
|
||||||
else if(cmd.flags == DRAWNUMBER_SECRETS)
|
else if(cmd.flags == DRAWNUMBER_SECRETS)
|
||||||
cmd.value = level.found_secrets;
|
value = level.found_secrets;
|
||||||
else if(cmd.flags == DRAWNUMBER_TOTALSECRETS)
|
else if(cmd.flags == DRAWNUMBER_TOTALSECRETS)
|
||||||
cmd.value = level.total_secrets;
|
value = level.total_secrets;
|
||||||
else if(cmd.flags == DRAWNUMBER_ARMORCLASS)
|
else if(cmd.flags == DRAWNUMBER_ARMORCLASS)
|
||||||
{
|
{
|
||||||
AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
|
AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
|
||||||
if(harmor != NULL)
|
if(harmor != NULL)
|
||||||
{
|
{
|
||||||
cmd.value = harmor->Slots[0] + harmor->Slots[1] +
|
value = harmor->Slots[0] + harmor->Slots[1] +
|
||||||
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4];
|
||||||
}
|
}
|
||||||
//Hexen counts basic armor also so we should too.
|
//Hexen counts basic armor also so we should too.
|
||||||
if(armor != NULL)
|
if(armor != NULL)
|
||||||
{
|
{
|
||||||
cmd.value += armor->SavePercent;
|
value += armor->SavePercent;
|
||||||
}
|
}
|
||||||
cmd.value /= (5*FRACUNIT);
|
value /= (5*FRACUNIT);
|
||||||
}
|
}
|
||||||
|
else if(cmd.flags == DRAWNUMBER_GLOBALVAR)
|
||||||
|
value = ACS_GlobalVars[cmd.value];
|
||||||
else if(cmd.flags == DRAWNUMBER_INVENTORY)
|
else if(cmd.flags == DRAWNUMBER_INVENTORY)
|
||||||
{
|
{
|
||||||
AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
|
AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
|
||||||
if(item != NULL)
|
if(item != NULL)
|
||||||
{
|
{
|
||||||
cmd.value = item->Amount;
|
value = item->Amount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmd.value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low
|
if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low
|
||||||
DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2);
|
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2);
|
||||||
else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high
|
else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high
|
||||||
DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2);
|
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2);
|
||||||
else
|
else
|
||||||
DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2);
|
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SBARINFO_DRAWMUGSHOT:
|
case SBARINFO_DRAWMUGSHOT:
|
||||||
{
|
{
|
||||||
bool xdth = false;
|
bool xdth = false;
|
||||||
|
@ -657,7 +684,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
xdth = true;
|
xdth = true;
|
||||||
if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE)
|
if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE)
|
||||||
animatedgodmode = true;
|
animatedgodmode = true;
|
||||||
DrawFace(cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
|
DrawFace(cmd.string[0], cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SBARINFO_DRAWSELECTEDINVENTORY:
|
case SBARINFO_DRAWSELECTEDINVENTORY:
|
||||||
|
@ -1000,7 +1027,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
{
|
{
|
||||||
drawingFont = cmd.font;
|
drawingFont = cmd.font;
|
||||||
}
|
}
|
||||||
DrawString(cmd.string[0], cmd.x - drawingFont->StringWidth(cmd.string[0]), cmd.y, cmd.translation);
|
DrawString(cmd.string[0], cmd.x - drawingFont->StringWidth(cmd.string[0]), cmd.y, cmd.translation, cmd.special);
|
||||||
break;
|
break;
|
||||||
case SBARINFO_DRAWKEYBAR:
|
case SBARINFO_DRAWKEYBAR:
|
||||||
{
|
{
|
||||||
|
@ -1046,6 +1073,12 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SBARINFO_ASPECTRATIO:
|
||||||
|
if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value)
|
||||||
|
{
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SBARINFO_WEAPONAMMO:
|
case SBARINFO_WEAPONAMMO:
|
||||||
if(CPlayer->ReadyWeapon != NULL)
|
if(CPlayer->ReadyWeapon != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1090,6 +1123,30 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SBARINFO_ININVENTORY:
|
||||||
|
{
|
||||||
|
AInventory *item1 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
|
||||||
|
AInventory *item2 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[1]));
|
||||||
|
if(cmd.flags & SBARINFOEVENT_AND)
|
||||||
|
{
|
||||||
|
if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
}
|
||||||
|
else if(cmd.flags & SBARINFOEVENT_OR)
|
||||||
|
{
|
||||||
|
if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
}
|
||||||
|
else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
|
||||||
|
doCommands(cmd.subBlock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1102,15 +1159,21 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
|
||||||
x -= (texture->GetWidth()/2)-texture->LeftOffset;
|
x -= (texture->GetWidth()/2)-texture->LeftOffset;
|
||||||
y -= (texture->GetHeight()/2)-texture->TopOffset;
|
y -= (texture->GetHeight()/2)-texture->TopOffset;
|
||||||
}
|
}
|
||||||
|
x += ST_X;
|
||||||
|
y += ST_Y;
|
||||||
|
int w = texture->GetScaledWidth();
|
||||||
|
int h = texture->GetScaledHeight();
|
||||||
|
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
|
||||||
if((flags & DRAWIMAGE_TRANSLATABLE))
|
if((flags & DRAWIMAGE_TRANSLATABLE))
|
||||||
DrawImage(texture, x, y, getTranslation());
|
{
|
||||||
|
screen->DrawTexture(texture, x, y,
|
||||||
|
DTA_DestWidth, w,
|
||||||
|
DTA_DestHeight, h,
|
||||||
|
DTA_Translation, getTranslation(),
|
||||||
|
TAG_DONE);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x += ST_X;
|
|
||||||
y += ST_Y;
|
|
||||||
int w = texture->GetScaledWidth();
|
|
||||||
int h = texture->GetScaledHeight();
|
|
||||||
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
|
|
||||||
screen->DrawTexture(texture, x, y,
|
screen->DrawTexture(texture, x, y,
|
||||||
DTA_DestWidth, w,
|
DTA_DestWidth, w,
|
||||||
DTA_DestHeight, h,
|
DTA_DestHeight, h,
|
||||||
|
@ -1142,10 +1205,20 @@ void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translatio
|
||||||
}
|
}
|
||||||
if(SBarInfoScript->spacingCharacter == '\0') //If we are monospaced lets use the offset
|
if(SBarInfoScript->spacingCharacter == '\0') //If we are monospaced lets use the offset
|
||||||
x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size
|
x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size
|
||||||
DrawImage(character, x, y, drawingFont->GetColorTranslation(translation));
|
int rx = x + ST_X;
|
||||||
x += width + spacing;
|
int ry = y + ST_Y;
|
||||||
|
int rw = character->GetScaledWidth();
|
||||||
|
int rh = character->GetScaledHeight();
|
||||||
|
screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true);
|
||||||
|
screen->DrawTexture(character, rx, ry,
|
||||||
|
DTA_DestWidth, rw,
|
||||||
|
DTA_DestHeight, rh,
|
||||||
|
DTA_Translation, drawingFont->GetColorTranslation(translation),
|
||||||
|
TAG_DONE);
|
||||||
if(SBarInfoScript->spacingCharacter == '\0')
|
if(SBarInfoScript->spacingCharacter == '\0')
|
||||||
x -= (character->LeftOffset+1);
|
x += width + spacing - (character->LeftOffset+1);
|
||||||
|
else //width gets changed at the call to GetChar()
|
||||||
|
x += drawingFont->GetCharWidth((int) SBarInfoScript->spacingCharacter) + spacing;
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1165,14 +1238,23 @@ void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translati
|
||||||
}
|
}
|
||||||
|
|
||||||
//draws the mug shot
|
//draws the mug shot
|
||||||
void DSBarInfo::DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y)
|
void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y)
|
||||||
{
|
{
|
||||||
int angle = updateState(xdth, animatedgodmode);
|
int angle = updateState(xdth, animatedgodmode);
|
||||||
int level = 0;
|
int level = 0;
|
||||||
for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++);
|
for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++);
|
||||||
if(currentState != NULL)
|
if(currentState != NULL)
|
||||||
{
|
{
|
||||||
DrawImage(currentState->getCurrentFrameTexture(&skins[CPlayer->userinfo.skin], level, angle), x, y);
|
FTexture *face = currentState->getCurrentFrameTexture(defaultFace, &skins[CPlayer->userinfo.skin], level, angle);
|
||||||
|
x += ST_X;
|
||||||
|
y += ST_Y;
|
||||||
|
int w = face->GetScaledWidth();
|
||||||
|
int h = face->GetScaledHeight();
|
||||||
|
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
|
||||||
|
screen->DrawTexture(face, x, y,
|
||||||
|
DTA_DestWidth, w,
|
||||||
|
DTA_DestHeight, h,
|
||||||
|
TAG_DONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ static const char *SBarInfoTopLevel[] =
|
||||||
"interpolatearmor",
|
"interpolatearmor",
|
||||||
"completeborder",
|
"completeborder",
|
||||||
"monospacefonts",
|
"monospacefonts",
|
||||||
|
"lowerhealthcap",
|
||||||
"statusbar",
|
"statusbar",
|
||||||
"mugshot",
|
"mugshot",
|
||||||
NULL
|
NULL
|
||||||
|
@ -91,7 +92,9 @@ static const char *SBarInfoRoutineLevel[] =
|
||||||
"drawkeybar",
|
"drawkeybar",
|
||||||
"gamemode",
|
"gamemode",
|
||||||
"playerclass",
|
"playerclass",
|
||||||
|
"aspectratio",
|
||||||
"weaponammo", //event
|
"weaponammo", //event
|
||||||
|
"ininventory",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -230,6 +233,18 @@ void SBarInfo::ParseSBarInfo(int lump)
|
||||||
}
|
}
|
||||||
sc.MustGetToken(';');
|
sc.MustGetToken(';');
|
||||||
break;
|
break;
|
||||||
|
case SBARINFO_LOWERHEALTHCAP:
|
||||||
|
if(sc.CheckToken(TK_False))
|
||||||
|
{
|
||||||
|
lowerHealthCap = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sc.MustGetToken(TK_True);
|
||||||
|
lowerHealthCap = true;
|
||||||
|
}
|
||||||
|
sc.MustGetToken(';');
|
||||||
|
break;
|
||||||
case SBARINFO_STATUSBAR:
|
case SBARINFO_STATUSBAR:
|
||||||
{
|
{
|
||||||
if(!baseSet) //If the user didn't explicitly define a base, do so now.
|
if(!baseSet) //If the user didn't explicitly define a base, do so now.
|
||||||
|
@ -470,6 +485,14 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
||||||
cmd.flags += DRAWNUMBER_TOTALSECRETS;
|
cmd.flags += DRAWNUMBER_TOTALSECRETS;
|
||||||
else if(sc.Compare("armorclass"))
|
else if(sc.Compare("armorclass"))
|
||||||
cmd.flags += DRAWNUMBER_ARMORCLASS;
|
cmd.flags += DRAWNUMBER_ARMORCLASS;
|
||||||
|
else if(sc.Compare("globalvar"))
|
||||||
|
{
|
||||||
|
cmd.flags += DRAWNUMBER_GLOBALVAR;
|
||||||
|
sc.MustGetToken(TK_IntConst);
|
||||||
|
if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS)
|
||||||
|
sc.ScriptError("Global variable number out of range: %d", sc.Number);
|
||||||
|
cmd.value = sc.Number;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmd.flags = DRAWNUMBER_INVENTORY;
|
cmd.flags = DRAWNUMBER_INVENTORY;
|
||||||
|
@ -738,7 +761,7 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
||||||
cmd.flags = DRAWNUMBER_INVENTORY;
|
cmd.flags = DRAWNUMBER_INVENTORY;
|
||||||
cmd.setString(sc, sc.String, 0);
|
cmd.setString(sc, sc.String, 0);
|
||||||
const PClass* item = PClass::FindClass(sc.String);
|
const PClass* item = PClass::FindClass(sc.String);
|
||||||
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) //must be a kind of ammo
|
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item))
|
||||||
{
|
{
|
||||||
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -843,6 +866,11 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
||||||
cmd.setString(sc, sc.String, 0, -1, false);
|
cmd.setString(sc, sc.String, 0, -1, false);
|
||||||
sc.MustGetToken(',');
|
sc.MustGetToken(',');
|
||||||
this->getCoordinates(sc, cmd);
|
this->getCoordinates(sc, cmd);
|
||||||
|
if(sc.CheckToken(',')) //spacing
|
||||||
|
{
|
||||||
|
sc.MustGetToken(TK_IntConst);
|
||||||
|
cmd.special = sc.Number;
|
||||||
|
}
|
||||||
sc.MustGetToken(';');
|
sc.MustGetToken(';');
|
||||||
break;
|
break;
|
||||||
case SBARINFO_DRAWKEYBAR:
|
case SBARINFO_DRAWKEYBAR:
|
||||||
|
@ -908,6 +936,21 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
||||||
FinishPlayerClass:
|
FinishPlayerClass:
|
||||||
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||||
break;
|
break;
|
||||||
|
case SBARINFO_ASPECTRATIO:
|
||||||
|
sc.MustGetToken(TK_StringConst);
|
||||||
|
if(sc.Compare("4:3"))
|
||||||
|
cmd.value = ASPECTRATIO_4_3;
|
||||||
|
else if(sc.Compare("16:9"))
|
||||||
|
cmd.value = ASPECTRATIO_16_9;
|
||||||
|
else if(sc.Compare("16:10"))
|
||||||
|
cmd.value = ASPECTRATIO_16_10;
|
||||||
|
else if(sc.Compare("5:4"))
|
||||||
|
cmd.value = ASPECTRATIO_5_4;
|
||||||
|
else
|
||||||
|
sc.ScriptError("Unkown aspect ratio: %s", sc.String);
|
||||||
|
sc.MustGetToken('{');
|
||||||
|
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||||
|
break;
|
||||||
case SBARINFO_WEAPONAMMO:
|
case SBARINFO_WEAPONAMMO:
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
if(sc.Compare("not"))
|
if(sc.Compare("not"))
|
||||||
|
@ -939,6 +982,39 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
||||||
sc.MustGetToken('{');
|
sc.MustGetToken('{');
|
||||||
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||||
break;
|
break;
|
||||||
|
case SBARINFO_ININVENTORY:
|
||||||
|
{
|
||||||
|
sc.MustGetToken(TK_Identifier);
|
||||||
|
if(sc.Compare("not"))
|
||||||
|
{
|
||||||
|
cmd.flags += SBARINFOEVENT_NOT;
|
||||||
|
sc.MustGetToken(TK_Identifier);
|
||||||
|
}
|
||||||
|
for(int i = 0;i < 2;i++)
|
||||||
|
{
|
||||||
|
cmd.setString(sc, sc.String, i);
|
||||||
|
const PClass* item = PClass::FindClass(sc.String);
|
||||||
|
if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item))
|
||||||
|
{
|
||||||
|
sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
|
||||||
|
}
|
||||||
|
if(sc.CheckToken(TK_OrOr))
|
||||||
|
{
|
||||||
|
cmd.flags += SBARINFOEVENT_OR;
|
||||||
|
sc.MustGetToken(TK_Identifier);
|
||||||
|
}
|
||||||
|
else if(sc.CheckToken(TK_AndAnd))
|
||||||
|
{
|
||||||
|
cmd.flags += SBARINFOEVENT_AND;
|
||||||
|
sc.MustGetToken(TK_Identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sc.MustGetToken('{');
|
||||||
|
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
block.commands.Push(cmd);
|
block.commands.Push(cmd);
|
||||||
}
|
}
|
||||||
|
@ -1044,6 +1120,7 @@ void SBarInfo::Init()
|
||||||
interpolateHealth = false;
|
interpolateHealth = false;
|
||||||
interpolateArmor = false;
|
interpolateArmor = false;
|
||||||
completeBorder = false;
|
completeBorder = false;
|
||||||
|
lowerHealthCap = true;
|
||||||
interpolationSpeed = 8;
|
interpolationSpeed = 8;
|
||||||
armorInterpolationSpeed = 8;
|
armorInterpolationSpeed = 8;
|
||||||
height = 0;
|
height = 0;
|
||||||
|
|
|
@ -1536,9 +1536,14 @@ void DBaseStatusBar::FlashItem (const PClass *itemtype)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBaseStatusBar::SetFace (void *)
|
void DBaseStatusBar::SetFace (void *skn)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DBaseStatusBar::AddFaceToImageCollection (void *skn, FImageCollection *images)
|
||||||
|
{
|
||||||
|
AddFaceToImageCollectionActual (skn, images, false);
|
||||||
|
}
|
||||||
|
|
||||||
void DBaseStatusBar::NewGame ()
|
void DBaseStatusBar::NewGame ()
|
||||||
{
|
{
|
||||||
|
@ -1575,6 +1580,72 @@ void DBaseStatusBar::ScreenSizeChanged ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AddFaceToImageCollectionActual
|
||||||
|
//
|
||||||
|
// Adds face graphics for specified skin to the specified image collection.
|
||||||
|
// If not in DOOM statusbar and no face in current skin, do NOT default STF*
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void DBaseStatusBar::AddFaceToImageCollectionActual (void *skn, FImageCollection *images, bool isDoom)
|
||||||
|
{
|
||||||
|
const char *nameptrs[ST_NUMFACES];
|
||||||
|
char names[ST_NUMFACES][9];
|
||||||
|
char prefix[4];
|
||||||
|
int i, j;
|
||||||
|
int namespc;
|
||||||
|
int facenum;
|
||||||
|
FPlayerSkin *skin = (FPlayerSkin *)skn;
|
||||||
|
|
||||||
|
if ((skin->face[0] == 0) && !isDoom)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ST_NUMFACES; i++)
|
||||||
|
{
|
||||||
|
nameptrs[i] = names[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skin->face[0] != 0)
|
||||||
|
{
|
||||||
|
prefix[0] = skin->face[0];
|
||||||
|
prefix[1] = skin->face[1];
|
||||||
|
prefix[2] = skin->face[2];
|
||||||
|
prefix[3] = 0;
|
||||||
|
namespc = skin->namespc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prefix[0] = 'S';
|
||||||
|
prefix[1] = 'T';
|
||||||
|
prefix[2] = 'F';
|
||||||
|
prefix[3] = 0;
|
||||||
|
namespc = ns_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
facenum = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ST_NUMPAINFACES; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < ST_NUMSTRAIGHTFACES; j++)
|
||||||
|
{
|
||||||
|
sprintf (names[facenum++], "%sST%d%d", prefix, i, j);
|
||||||
|
}
|
||||||
|
sprintf (names[facenum++], "%sTR%d0", prefix, i); // turn right
|
||||||
|
sprintf (names[facenum++], "%sTL%d0", prefix, i); // turn left
|
||||||
|
sprintf (names[facenum++], "%sOUCH%d", prefix, i); // ouch!
|
||||||
|
sprintf (names[facenum++], "%sEVL%d", prefix, i); // evil grin ;)
|
||||||
|
sprintf (names[facenum++], "%sKILL%d", prefix, i); // pissed off
|
||||||
|
}
|
||||||
|
sprintf (names[facenum++], "%sGOD0", prefix);
|
||||||
|
sprintf (names[facenum++], "%sDEAD0", prefix);
|
||||||
|
|
||||||
|
images->Add (nameptrs, ST_NUMFACES, namespc);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// ValidateInvFirst
|
// ValidateInvFirst
|
||||||
|
|
|
@ -81,6 +81,13 @@ public:
|
||||||
bool TryPickup (AActor *toucher);
|
bool TryPickup (AActor *toucher);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ASlideshowStarter : public ADummyStrifeItem
|
||||||
|
{
|
||||||
|
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
||||||
|
public:
|
||||||
|
bool TryPickup (AActor *toucher);
|
||||||
|
};
|
||||||
|
|
||||||
class AStrifeWeapon : public AWeapon
|
class AStrifeWeapon : public AWeapon
|
||||||
{
|
{
|
||||||
DECLARE_STATELESS_ACTOR (AStrifeWeapon, AWeapon)
|
DECLARE_STATELESS_ACTOR (AStrifeWeapon, AWeapon)
|
||||||
|
|
|
@ -514,13 +514,6 @@ bool AUpgradeAccuracy::TryPickup (AActor *toucher)
|
||||||
|
|
||||||
// Start a slideshow --------------------------------------------------------
|
// Start a slideshow --------------------------------------------------------
|
||||||
|
|
||||||
class ASlideshowStarter : public ADummyStrifeItem
|
|
||||||
{
|
|
||||||
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
|
||||||
public:
|
|
||||||
bool TryPickup (AActor *toucher);
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_STATELESS_ACTOR (ASlideshowStarter, Strife, -1, 0)
|
IMPLEMENT_STATELESS_ACTOR (ASlideshowStarter, Strife, -1, 0)
|
||||||
PROP_StrifeType (343)
|
PROP_StrifeType (343)
|
||||||
END_DEFAULTS
|
END_DEFAULTS
|
||||||
|
|
|
@ -692,7 +692,7 @@ CCMD(listlights)
|
||||||
ADynamicLight * dl;
|
ADynamicLight * dl;
|
||||||
TThinkerIterator<ADynamicLight> it;
|
TThinkerIterator<ADynamicLight> it;
|
||||||
|
|
||||||
while (dl=it.Next())
|
while ((dl=it.Next()))
|
||||||
{
|
{
|
||||||
walls=0;
|
walls=0;
|
||||||
sectors=0;
|
sectors=0;
|
||||||
|
|
20
src/m_menu.h
20
src/m_menu.h
|
@ -71,8 +71,7 @@ void M_OptInit (void);
|
||||||
// [RH] Initialize the video modes menu
|
// [RH] Initialize the video modes menu
|
||||||
void M_InitVideoModesMenu (void);
|
void M_InitVideoModesMenu (void);
|
||||||
|
|
||||||
struct menu_s;
|
void M_SwitchMenu (struct menu_t *menu);
|
||||||
void M_SwitchMenu (struct menu_s *menu);
|
|
||||||
|
|
||||||
void M_PopMenuStack (void);
|
void M_PopMenuStack (void);
|
||||||
|
|
||||||
|
@ -100,6 +99,7 @@ typedef enum {
|
||||||
discrete,
|
discrete,
|
||||||
discretes,
|
discretes,
|
||||||
cdiscrete,
|
cdiscrete,
|
||||||
|
ediscrete,
|
||||||
discrete_guid,
|
discrete_guid,
|
||||||
control,
|
control,
|
||||||
screenres,
|
screenres,
|
||||||
|
@ -145,8 +145,9 @@ typedef struct menuitem_s {
|
||||||
char *res3;
|
char *res3;
|
||||||
} d;
|
} d;
|
||||||
union {
|
union {
|
||||||
struct value_s *values;
|
struct value_t *values;
|
||||||
struct valuestring_t *valuestrings;
|
struct valuestring_t *valuestrings;
|
||||||
|
struct valueenum_t *enumvalues;
|
||||||
GUIDName *guidvalues;
|
GUIDName *guidvalues;
|
||||||
char *command;
|
char *command;
|
||||||
void (*cfunc)(FBaseCVar *cvar, float newval);
|
void (*cfunc)(FBaseCVar *cvar, float newval);
|
||||||
|
@ -157,7 +158,7 @@ typedef struct menuitem_s {
|
||||||
} e;
|
} e;
|
||||||
} menuitem_t;
|
} menuitem_t;
|
||||||
|
|
||||||
typedef struct menu_s {
|
struct menu_t {
|
||||||
const char *texttitle;
|
const char *texttitle;
|
||||||
int lastOn;
|
int lastOn;
|
||||||
int numitems;
|
int numitems;
|
||||||
|
@ -169,18 +170,23 @@ typedef struct menu_s {
|
||||||
void (*PreDraw)(void);
|
void (*PreDraw)(void);
|
||||||
bool DontDim;
|
bool DontDim;
|
||||||
void (*EscapeHandler)(void);
|
void (*EscapeHandler)(void);
|
||||||
} menu_t;
|
};
|
||||||
|
|
||||||
typedef struct value_s {
|
struct value_t {
|
||||||
float value;
|
float value;
|
||||||
const char *name;
|
const char *name;
|
||||||
} value_t;
|
};
|
||||||
|
|
||||||
struct valuestring_t {
|
struct valuestring_t {
|
||||||
float value;
|
float value;
|
||||||
FString name;
|
FString name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct valueenum_t {
|
||||||
|
const char *value; // Value of cvar
|
||||||
|
const char *name; // Name on menu
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// -1 = no cursor here, 1 = ok, 2 = arrows ok
|
// -1 = no cursor here, 1 = ok, 2 = arrows ok
|
||||||
|
|
|
@ -1144,62 +1144,131 @@ EXTERN_CVAR (Float, snd_movievolume)
|
||||||
#endif
|
#endif
|
||||||
EXTERN_CVAR (Bool, snd_flipstereo)
|
EXTERN_CVAR (Bool, snd_flipstereo)
|
||||||
EXTERN_CVAR (Bool, snd_pitched)
|
EXTERN_CVAR (Bool, snd_pitched)
|
||||||
|
EXTERN_CVAR (String, snd_output_format)
|
||||||
|
EXTERN_CVAR (String, snd_speakermode)
|
||||||
|
EXTERN_CVAR (String, snd_resampler)
|
||||||
|
EXTERN_CVAR (String, snd_output)
|
||||||
|
EXTERN_CVAR (Int, snd_buffersize)
|
||||||
|
EXTERN_CVAR (Int, snd_buffercount)
|
||||||
|
EXTERN_CVAR (Int, snd_samplerate)
|
||||||
|
EXTERN_CVAR (Bool, snd_hrtf)
|
||||||
|
EXTERN_CVAR (Bool, snd_waterreverb)
|
||||||
|
EXTERN_CVAR (Int, snd_mididevice)
|
||||||
|
|
||||||
static void MakeSoundChanges ();
|
static void MakeSoundChanges ();
|
||||||
static void AdvSoundOptions ();
|
static void AdvSoundOptions ();
|
||||||
static void ChooseMIDI ();
|
|
||||||
|
|
||||||
static value_t SampleRates[] =
|
static value_t SampleRates[] =
|
||||||
{
|
{
|
||||||
{ 4000.f, "4000 Hz" },
|
{ 0.f, "Default" },
|
||||||
{ 8000.f, "8000 Hz" },
|
{ 4000.f, "4000 Hz" },
|
||||||
{ 11025.f, "11025 Hz" },
|
{ 8000.f, "8000 Hz" },
|
||||||
{ 22050.f, "22050 Hz" },
|
{ 11025.f, "11025 Hz" },
|
||||||
{ 32000.f, "32000 Hz" },
|
{ 22050.f, "22050 Hz" },
|
||||||
{ 44100.f, "44100 Hz" },
|
{ 32000.f, "32000 Hz" },
|
||||||
{ 48000.f, "48000 Hz" },
|
{ 44100.f, "44100 Hz" },
|
||||||
{ 96000.f, "96000 Hz" }
|
{ 48000.f, "48000 Hz" }
|
||||||
};
|
};
|
||||||
|
|
||||||
static value_t BufferSizes[] =
|
static value_t BufferSizes[] =
|
||||||
{
|
{
|
||||||
{ 0.f, "Default" },
|
{ 0.f, "Default" },
|
||||||
{ 20.f, "20 ms" },
|
{ 64.f, "64 samples" },
|
||||||
{ 40.f, "40 ms" },
|
{ 128.f, "128 samples" },
|
||||||
{ 60.f, "60 ms" },
|
{ 256.f, "256 samples" },
|
||||||
{ 80.f, "80 ms" },
|
{ 512.f, "512 samples" },
|
||||||
{ 100.f, "100 ms" },
|
{ 1024.f, "1024 samples" },
|
||||||
{ 120.f, "120 ms" },
|
{ 2048.f, "2048 samples" },
|
||||||
{ 140.f, "140 ms" },
|
{ 4096.f, "4096 samples" }
|
||||||
{ 160.f, "160 ms" },
|
};
|
||||||
{ 180.f, "180 ms" },
|
|
||||||
{ 200.f, "200 ms" },
|
static value_t BufferCounts[] =
|
||||||
|
{
|
||||||
|
{ 0.f, "Default" },
|
||||||
|
{ 2.f, "2" },
|
||||||
|
{ 3.f, "3" },
|
||||||
|
{ 4.f, "4" },
|
||||||
|
{ 5.f, "5" },
|
||||||
|
{ 6.f, "6" },
|
||||||
|
{ 7.f, "7" },
|
||||||
|
{ 8.f, "8" },
|
||||||
|
{ 9.f, "9" },
|
||||||
|
{ 10.f, "10" },
|
||||||
|
{ 11.f, "11" },
|
||||||
|
{ 12.f, "12" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static valueenum_t Outputs[] =
|
||||||
|
{
|
||||||
|
{ "Default", "Default" },
|
||||||
|
#if defined(_WIN32)
|
||||||
|
{ "DirectSound", "DirectSound" },
|
||||||
|
{ "WASAPI", "Vista WASAPI" },
|
||||||
|
{ "ASIO", "ASIO" },
|
||||||
|
{ "WaveOut", "WaveOut" },
|
||||||
|
{ "OpenAL", "OpenAL (very beta)" },
|
||||||
|
#elif defined(unix)
|
||||||
|
{ "OSS", "OSS" },
|
||||||
|
{ "ALSA", "ALSA" },
|
||||||
|
{ "ESD", "ESD" },
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
{ "Sound Manager", "Sound Manager" },
|
||||||
|
{ "Core Audio", "Core Audio" },
|
||||||
|
#endif
|
||||||
|
{ "No sound", "No sound" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static valueenum_t OutputFormats[] =
|
||||||
|
{
|
||||||
|
{ "PCM-8", "8-bit" },
|
||||||
|
{ "PCM-16", "16-bit" },
|
||||||
|
{ "PCM-24", "24-bit" },
|
||||||
|
{ "PCM-32", "32-bit" },
|
||||||
|
{ "PCM-Float", "32-bit float" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static valueenum_t SpeakerModes[] =
|
||||||
|
{
|
||||||
|
{ "Auto", "Auto" },
|
||||||
|
{ "Mono", "Mono" },
|
||||||
|
{ "Stereo", "Stereo" },
|
||||||
|
{ "Prologic", "Dolby Prologic Decoder" },
|
||||||
|
{ "Quad", "Quad" },
|
||||||
|
{ "Surround", "5 speakers" },
|
||||||
|
{ "5.1", "5.1 speakers" },
|
||||||
|
{ "7.1", "7.1 speakers" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static valueenum_t Resamplers[] =
|
||||||
|
{
|
||||||
|
{ "NoInterp", "No interpolation" },
|
||||||
|
{ "Linear", "Linear" },
|
||||||
|
{ "Cubic", "Cubic" },
|
||||||
|
{ "Spline", "Spline" }
|
||||||
};
|
};
|
||||||
|
|
||||||
static menuitem_t SoundItems[] =
|
static menuitem_t SoundItems[] =
|
||||||
{
|
{
|
||||||
{ slider, "Sound effects volume", {&snd_sfxvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
{ slider, "Sounds volume", {&snd_sfxvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
||||||
#ifdef _WIN32
|
|
||||||
{ slider, "Music volume", {&snd_musicvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
{ slider, "Music volume", {&snd_musicvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
||||||
{ slider, "Movie volume", {&snd_movievolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
{ discrete, "MIDI device", {&snd_mididevice}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
#else
|
|
||||||
{ slider, "Music volume", {&snd_musicvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
|
||||||
#endif
|
|
||||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
{ discrete, "Underwater Reverb", {&snd_waterreverb}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
{ discrete, "Underwater reverb", {&snd_waterreverb}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||||
{ discrete, "Flip Stereo Channels", {&snd_flipstereo}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
{ discrete, "Randomize pitches", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||||
{ discrete, "Random Pitch Variations", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
|
||||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
{ more, "Activate below settings", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)MakeSoundChanges} },
|
{ more, "Restart sound", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)MakeSoundChanges} },
|
||||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
{ discrete, "Sample Rate", {&snd_samplerate}, {8.0}, {0.0}, {0.0}, {SampleRates} },
|
{ ediscrete,"Output system", {&snd_output}, {countof(Outputs)}, {0.0}, {0.0}, {(value_t *)Outputs} },
|
||||||
{ discrete, "Buffer Size", {&snd_buffersize}, {11.0}, {0.0}, {0.0}, {BufferSizes} },
|
{ ediscrete,"Output format", {&snd_output_format}, {5.0}, {0.0}, {0.0}, {(value_t *)OutputFormats} },
|
||||||
|
{ ediscrete,"Speaker mode", {&snd_speakermode}, {8.0}, {0.0}, {0.0}, {(value_t *)SpeakerModes} },
|
||||||
|
{ ediscrete,"Resampler", {&snd_resampler}, {4.0}, {0.0}, {0.0}, {(value_t *)Resamplers} },
|
||||||
|
{ discrete, "HRTF filter", {&snd_hrtf}, {2.0}, {0.0}, {0.0}, {(value_t *)OnOff} },
|
||||||
|
{ discrete, "Sample rate", {&snd_samplerate}, {8.0}, {0.0}, {0.0}, {SampleRates} },
|
||||||
|
{ discrete, "Buffer size", {&snd_buffersize}, {8.0}, {0.0}, {0.0}, {BufferSizes} },
|
||||||
|
{ discrete, "Buffer count", {&snd_buffercount}, {12.0}, {0.0}, {0.0}, {BufferCounts} },
|
||||||
|
|
||||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
{ more, "Advanced Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)AdvSoundOptions} },
|
{ more, "Advanced options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)AdvSoundOptions} },
|
||||||
#ifdef _WIN32
|
|
||||||
{ more, "Select MIDI Device", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)ChooseMIDI} },
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static menu_t SoundMenu =
|
static menu_t SoundMenu =
|
||||||
|
@ -1211,29 +1280,7 @@ static menu_t SoundMenu =
|
||||||
SoundItems,
|
SoundItems,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#define MIDI_DEVICE_ITEM 2
|
||||||
/*=======================================
|
|
||||||
*
|
|
||||||
* MIDI Device Menu
|
|
||||||
*
|
|
||||||
*=======================================*/
|
|
||||||
|
|
||||||
EXTERN_CVAR (Int, snd_mididevice)
|
|
||||||
|
|
||||||
static menuitem_t MidiDeviceItems[] =
|
|
||||||
{
|
|
||||||
{ discrete, "Device", {&snd_mididevice}, {0.0}, {0.0}, {0.0}, {NULL} },
|
|
||||||
};
|
|
||||||
|
|
||||||
static menu_t MidiDeviceMenu =
|
|
||||||
{
|
|
||||||
"SELECT MIDI DEVICE",
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
MidiDeviceItems,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*=======================================
|
/*=======================================
|
||||||
*
|
*
|
||||||
|
@ -1521,6 +1568,42 @@ int M_FindCurGUID (const GUID &guid, GUIDName *values, int numvals)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *M_FindCurVal(const char *cur, valueenum_t *values, int numvals)
|
||||||
|
{
|
||||||
|
for (int v = 0; v < numvals; ++v)
|
||||||
|
{
|
||||||
|
if (stricmp(values[v].value, cur) == 0)
|
||||||
|
{
|
||||||
|
return values[v].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *M_FindPrevVal(const char *cur, valueenum_t *values, int numvals)
|
||||||
|
{
|
||||||
|
for (int v = 0; v < numvals; ++v)
|
||||||
|
{
|
||||||
|
if (stricmp(values[v].value, cur) == 0)
|
||||||
|
{
|
||||||
|
return values[v == 0 ? numvals - 1 : v - 1].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *M_FindNextVal(const char *cur, valueenum_t *values, int numvals)
|
||||||
|
{
|
||||||
|
for (int v = 0; v < numvals; ++v)
|
||||||
|
{
|
||||||
|
if (stricmp(values[v].value, cur) == 0)
|
||||||
|
{
|
||||||
|
return values[v == numvals - 1 ? 0 : v + 1].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
void M_OptDrawer ()
|
void M_OptDrawer ()
|
||||||
{
|
{
|
||||||
EColorRange color;
|
EColorRange color;
|
||||||
|
@ -1707,6 +1790,16 @@ void M_OptDrawer ()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ediscrete:
|
||||||
|
{
|
||||||
|
const char *v;
|
||||||
|
|
||||||
|
value = item->a.cvar->GetGenericRep (CVAR_String);
|
||||||
|
v = M_FindCurVal(value.String, item->e.enumvalues, (int)item->b.numvalues);
|
||||||
|
screen->DrawText(ValueColor, CurrentMenu->indent + 14, y, v, DTA_Clean, true, TAG_DONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case discrete_guid:
|
case discrete_guid:
|
||||||
{
|
{
|
||||||
int v, vals;
|
int v, vals;
|
||||||
|
@ -2186,6 +2279,13 @@ void M_OptResponder (event_t *ev)
|
||||||
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ediscrete:
|
||||||
|
value = item->a.cvar->GetGenericRep(CVAR_String);
|
||||||
|
value.String = const_cast<char *>(M_FindPrevVal(value.String, item->e.enumvalues, (int)item->b.numvalues));
|
||||||
|
item->a.cvar->SetGenericRep(value, CVAR_String);
|
||||||
|
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||||
|
break;
|
||||||
|
|
||||||
case bitmask:
|
case bitmask:
|
||||||
{
|
{
|
||||||
int cur;
|
int cur;
|
||||||
|
@ -2328,6 +2428,13 @@ void M_OptResponder (event_t *ev)
|
||||||
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ediscrete:
|
||||||
|
value = item->a.cvar->GetGenericRep(CVAR_String);
|
||||||
|
value.String = const_cast<char *>(M_FindNextVal(value.String, item->e.enumvalues, (int)item->b.numvalues));
|
||||||
|
item->a.cvar->SetGenericRep(value, CVAR_String);
|
||||||
|
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||||
|
break;
|
||||||
|
|
||||||
case bitmask:
|
case bitmask:
|
||||||
{
|
{
|
||||||
int cur;
|
int cur;
|
||||||
|
@ -2893,9 +3000,19 @@ CCMD (menu_joystick)
|
||||||
JoystickOptions ();
|
JoystickOptions ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FreeMIDIMenuList()
|
||||||
|
{
|
||||||
|
if (SoundItems[MIDI_DEVICE_ITEM].e.values != NULL)
|
||||||
|
{
|
||||||
|
delete[] SoundItems[MIDI_DEVICE_ITEM].e.values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void SoundOptions ()
|
static void SoundOptions ()
|
||||||
{
|
{
|
||||||
M_SwitchMenu (&SoundMenu);
|
I_BuildMIDIMenuList(&SoundItems[MIDI_DEVICE_ITEM].e.values, &SoundItems[MIDI_DEVICE_ITEM].b.min);
|
||||||
|
atterm(FreeMIDIMenuList);
|
||||||
|
M_SwitchMenu(&SoundMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCMD (menu_sound)
|
CCMD (menu_sound)
|
||||||
|
@ -2917,22 +3034,6 @@ CCMD (menu_advsound)
|
||||||
AdvSoundOptions ();
|
AdvSoundOptions ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static void ChooseMIDI ()
|
|
||||||
{
|
|
||||||
I_BuildMIDIMenuList (&MidiDeviceItems[0].e.values,
|
|
||||||
&MidiDeviceItems[0].b.min);
|
|
||||||
M_SwitchMenu (&MidiDeviceMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
CCMD (menu_mididevice)
|
|
||||||
{
|
|
||||||
M_StartControlPanel (true);
|
|
||||||
OptionsActive = true;
|
|
||||||
ChooseMIDI ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void MakeSoundChanges (void)
|
static void MakeSoundChanges (void)
|
||||||
{
|
{
|
||||||
static char snd_reset[] = "snd_reset";
|
static char snd_reset[] = "snd_reset";
|
||||||
|
|
|
@ -93,7 +93,7 @@ static size_t ReadVarLen (const BYTE *buf, int *time_out)
|
||||||
return ofs;
|
return ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t WriteVarLen (FILE *file, int time)
|
static size_t WriteVarLen (TArray<BYTE> &file, int time)
|
||||||
{
|
{
|
||||||
long buffer;
|
long buffer;
|
||||||
size_t ofs;
|
size_t ofs;
|
||||||
|
@ -105,7 +105,7 @@ static size_t WriteVarLen (FILE *file, int time)
|
||||||
}
|
}
|
||||||
for (ofs = 0;;)
|
for (ofs = 0;;)
|
||||||
{
|
{
|
||||||
fputc (buffer & 0xff, file);
|
file.Push(BYTE(buffer & 0xff));
|
||||||
if (buffer & 0x80)
|
if (buffer & 0x80)
|
||||||
buffer >>= 8;
|
buffer >>= 8;
|
||||||
else
|
else
|
||||||
|
@ -114,7 +114,7 @@ static size_t WriteVarLen (FILE *file, int time)
|
||||||
return ofs;
|
return ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile)
|
||||||
{
|
{
|
||||||
BYTE midStatus, midArgs, mid1, mid2;
|
BYTE midStatus, midArgs, mid1, mid2;
|
||||||
size_t mus_p, maxmus_p;
|
size_t mus_p, maxmus_p;
|
||||||
|
@ -125,7 +125,6 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||||
BYTE lastVel[16];
|
BYTE lastVel[16];
|
||||||
SBYTE chanMap[16];
|
SBYTE chanMap[16];
|
||||||
int chanCount;
|
int chanCount;
|
||||||
int dupCount = 0;
|
|
||||||
long trackLen;
|
long trackLen;
|
||||||
|
|
||||||
// Do some validation of the MUS file
|
// Do some validation of the MUS file
|
||||||
|
@ -136,7 +135,9 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Prep for conversion
|
// Prep for conversion
|
||||||
fwrite (StaticMIDIhead, 1, sizeof(StaticMIDIhead), outFile);
|
outFile.Clear();
|
||||||
|
outFile.Reserve(sizeof(StaticMIDIhead));
|
||||||
|
memcpy(&outFile[0], StaticMIDIhead, sizeof(StaticMIDIhead));
|
||||||
|
|
||||||
musBuf += LittleShort(musHead->SongStart);
|
musBuf += LittleShort(musHead->SongStart);
|
||||||
maxmus_p = LittleShort(musHead->SongLen);
|
maxmus_p = LittleShort(musHead->SongLen);
|
||||||
|
@ -167,10 +168,10 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||||
{
|
{
|
||||||
// This is the first time this channel has been used,
|
// This is the first time this channel has been used,
|
||||||
// so sets its volume to 127.
|
// so sets its volume to 127.
|
||||||
fputc (0, outFile);
|
outFile.Push(0);
|
||||||
fputc (0xB0 | chanCount, outFile);
|
outFile.Push(0xB0 | chanCount);
|
||||||
fputc (7, outFile);
|
outFile.Push(7);
|
||||||
fputc (127, outFile);
|
outFile.Push(127);
|
||||||
chanMap[channel] = chanCount++;
|
chanMap[channel] = chanCount++;
|
||||||
if (chanCount == 9)
|
if (chanCount == 9)
|
||||||
++chanCount;
|
++chanCount;
|
||||||
|
@ -237,20 +238,15 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||||
|
|
||||||
WriteVarLen (outFile, deltaTime);
|
WriteVarLen (outFile, deltaTime);
|
||||||
|
|
||||||
if (midStatus == status)
|
if (midStatus != status)
|
||||||
{
|
|
||||||
++dupCount;
|
|
||||||
fputc (mid1, outFile);
|
|
||||||
if (!midArgs)
|
|
||||||
fputc (mid2, outFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
status = midStatus;
|
status = midStatus;
|
||||||
fputc (status, outFile);
|
outFile.Push(status);
|
||||||
fputc (mid1, outFile);
|
}
|
||||||
if (!midArgs)
|
outFile.Push(mid1);
|
||||||
fputc (mid2, outFile);
|
if (midArgs == 0)
|
||||||
|
{
|
||||||
|
outFile.Push(mid2);
|
||||||
}
|
}
|
||||||
if (event & 128)
|
if (event & 128)
|
||||||
{
|
{
|
||||||
|
@ -263,12 +259,20 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill in track length
|
// fill in track length
|
||||||
trackLen = ftell (outFile) - 22;
|
trackLen = outFile.Size() - 22;
|
||||||
fseek (outFile, 18, SEEK_SET);
|
outFile[18] = BYTE((trackLen >> 24) & 255);
|
||||||
fputc ((trackLen >> 24) & 255, outFile);
|
outFile[19] = BYTE((trackLen >> 16) & 255);
|
||||||
fputc ((trackLen >> 16) & 255, outFile);
|
outFile[20] = BYTE((trackLen >> 8) & 255);
|
||||||
fputc ((trackLen >> 8) & 255, outFile);
|
outFile[21] = BYTE(trackLen & 255);
|
||||||
fputc (trackLen & 255, outFile);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProduceMIDI(const BYTE *musBuf, FILE *outFile)
|
||||||
|
{
|
||||||
|
TArray<BYTE> work;
|
||||||
|
if (ProduceMIDI(musBuf, work))
|
||||||
|
{
|
||||||
|
return fwrite(&work[0], 1, work.Size(), outFile) == work.Size();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ typedef struct
|
||||||
WORD Pad;
|
WORD Pad;
|
||||||
} MUSHeader;
|
} MUSHeader;
|
||||||
|
|
||||||
|
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);
|
||||||
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile);
|
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile);
|
||||||
|
|
||||||
#endif //__MUS2MIDI_H__
|
#endif //__MUS2MIDI_H__
|
||||||
|
|
|
@ -117,9 +117,8 @@ static void ConversationMenuEscaped ();
|
||||||
|
|
||||||
static FStrifeDialogueNode *CurNode, *PrevNode;
|
static FStrifeDialogueNode *CurNode, *PrevNode;
|
||||||
static FBrokenLines *DialogueLines;
|
static FBrokenLines *DialogueLines;
|
||||||
static AActor *ConversationNPC, *ConversationPC;
|
|
||||||
static angle_t ConversationNPCAngle;
|
static bool Conversation_TakeStuff;
|
||||||
static bool ConversationFaceTalker;
|
|
||||||
|
|
||||||
#define NUM_RANDOM_LINES 10
|
#define NUM_RANDOM_LINES 10
|
||||||
#define NUM_RANDOM_GOODBYES 3
|
#define NUM_RANDOM_GOODBYES 3
|
||||||
|
@ -571,14 +570,14 @@ static int FindNode (const FStrifeDialogueNode *node)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static bool CheckStrifeItem (const PClass *itemtype, int amount=-1)
|
static bool CheckStrifeItem (player_t *player, const PClass *itemtype, int amount=-1)
|
||||||
{
|
{
|
||||||
AInventory *item;
|
AInventory *item;
|
||||||
|
|
||||||
if (itemtype == NULL || amount == 0)
|
if (itemtype == NULL || amount == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
item = ConversationPC->FindInventory (itemtype);
|
item = player->ConversationPC->FindInventory (itemtype);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -594,7 +593,7 @@ static bool CheckStrifeItem (const PClass *itemtype, int amount=-1)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void TakeStrifeItem (const PClass *itemtype, int amount)
|
static void TakeStrifeItem (player_t *player, const PClass *itemtype, int amount)
|
||||||
{
|
{
|
||||||
if (itemtype == NULL || amount == 0)
|
if (itemtype == NULL || amount == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -611,15 +610,10 @@ static void TakeStrifeItem (const PClass *itemtype, int amount)
|
||||||
if (itemtype == RUNTIME_CLASS(ASigil))
|
if (itemtype == RUNTIME_CLASS(ASigil))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AInventory *item = ConversationPC->FindInventory (itemtype);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
if (item != NULL)
|
Net_WriteByte (CONV_TAKEINVENTORY);
|
||||||
{
|
Net_WriteString (itemtype->TypeName.GetChars ());
|
||||||
item->Amount -= amount;
|
Net_WriteWord (amount);
|
||||||
if (item->Amount <= 0)
|
|
||||||
{
|
|
||||||
item->Destroy ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
||||||
|
@ -633,7 +627,6 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
||||||
// P_StartConversation
|
// P_StartConversation
|
||||||
//
|
//
|
||||||
// Begins a conversation between a PC and NPC.
|
// Begins a conversation between a PC and NPC.
|
||||||
// FIXME: Make this work in multiplayer.
|
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
@ -645,14 +638,22 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
const char *toSay;
|
const char *toSay;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
// [CW] If an NPC is talking to a PC already, then don't let
|
||||||
|
// anyone else talk to NPC.
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || pc->player == &players[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (npc == players[i].ConversationNPC)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pc->momx = pc->momy = 0; // Stop moving
|
pc->momx = pc->momy = 0; // Stop moving
|
||||||
pc->player->momx = pc->player->momy = 0;
|
pc->player->momx = pc->player->momy = 0;
|
||||||
|
|
||||||
if (pc->player - players != consoleplayer)
|
pc->player->ConversationPC = pc;
|
||||||
return;
|
pc->player->ConversationNPC = npc;
|
||||||
|
|
||||||
ConversationPC = pc;
|
|
||||||
ConversationNPC = npc;
|
|
||||||
|
|
||||||
CurNode = npc->Conversation;
|
CurNode = npc->Conversation;
|
||||||
|
|
||||||
|
@ -662,10 +663,10 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->reactiontime = 2;
|
npc->reactiontime = 2;
|
||||||
ConversationFaceTalker = facetalker;
|
pc->player->ConversationFaceTalker = facetalker;
|
||||||
if (saveangle)
|
if (saveangle)
|
||||||
{
|
{
|
||||||
ConversationNPCAngle = npc->angle;
|
pc->player->ConversationNPCAngle = npc->angle;
|
||||||
}
|
}
|
||||||
oldtarget = npc->target;
|
oldtarget = npc->target;
|
||||||
npc->target = pc;
|
npc->target = pc;
|
||||||
|
@ -682,11 +683,11 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
// Check if we should jump to another node
|
// Check if we should jump to another node
|
||||||
while (CurNode->ItemCheck[0] != NULL)
|
while (CurNode->ItemCheck[0] != NULL)
|
||||||
{
|
{
|
||||||
if (CheckStrifeItem (CurNode->ItemCheck[0]) &&
|
if (CheckStrifeItem (pc->player, CurNode->ItemCheck[0]) &&
|
||||||
CheckStrifeItem (CurNode->ItemCheck[1]) &&
|
CheckStrifeItem (pc->player, CurNode->ItemCheck[1]) &&
|
||||||
CheckStrifeItem (CurNode->ItemCheck[2]))
|
CheckStrifeItem (pc->player, CurNode->ItemCheck[2]))
|
||||||
{
|
{
|
||||||
int root = FindNode (ConversationNPC->GetDefault()->Conversation);
|
int root = FindNode (pc->player->ConversationNPC->GetDefault()->Conversation);
|
||||||
CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1];
|
CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -697,10 +698,13 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
|
|
||||||
if (CurNode->SpeakerVoice != 0)
|
if (CurNode->SpeakerVoice != 0)
|
||||||
{
|
{
|
||||||
I_SetMusicVolume(dlg_musicvolume);
|
I_SetMusicVolume (dlg_musicvolume);
|
||||||
S_SoundID (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
S_SoundID (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pc->player != &players[consoleplayer])
|
||||||
|
return;
|
||||||
|
|
||||||
// Set up the menu
|
// Set up the menu
|
||||||
ConversationMenu.PreDraw = DrawConversationMenu;
|
ConversationMenu.PreDraw = DrawConversationMenu;
|
||||||
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
|
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
|
||||||
|
@ -786,9 +790,17 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
||||||
|
|
||||||
void P_ResumeConversation ()
|
void P_ResumeConversation ()
|
||||||
{
|
{
|
||||||
if (ConversationPC != NULL && ConversationNPC != NULL)
|
for (int i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
P_StartConversation (ConversationNPC, ConversationPC, ConversationFaceTalker, false);
|
if (!playeringame[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
player_t *p = &players[i];
|
||||||
|
|
||||||
|
if (p->ConversationPC != NULL && p->ConversationNPC != NULL)
|
||||||
|
{
|
||||||
|
P_StartConversation (p->ConversationNPC, p->ConversationPC, p->ConversationFaceTalker, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,6 +815,8 @@ static void DrawConversationMenu ()
|
||||||
const char *speakerName;
|
const char *speakerName;
|
||||||
int i, x, y, linesize;
|
int i, x, y, linesize;
|
||||||
|
|
||||||
|
player_t *cp = &players[consoleplayer];
|
||||||
|
|
||||||
assert (DialogueLines != NULL);
|
assert (DialogueLines != NULL);
|
||||||
assert (CurNode != NULL);
|
assert (CurNode != NULL);
|
||||||
|
|
||||||
|
@ -812,7 +826,8 @@ static void DrawConversationMenu ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConversationPauseTic < gametic)
|
// [CW] Pausing the game in a multiplayer game is a bad idea.
|
||||||
|
if (ConversationPauseTic < gametic && !multiplayer)
|
||||||
{
|
{
|
||||||
menuactive = MENU_On;
|
menuactive = MENU_On;
|
||||||
}
|
}
|
||||||
|
@ -832,7 +847,7 @@ static void DrawConversationMenu ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
speakerName = ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
speakerName = cp->ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
||||||
if (speakerName == NULL)
|
if (speakerName == NULL)
|
||||||
{
|
{
|
||||||
speakerName = "Person";
|
speakerName = "Person";
|
||||||
|
@ -873,7 +888,7 @@ static void DrawConversationMenu ()
|
||||||
|
|
||||||
if (ShowGold)
|
if (ShowGold)
|
||||||
{
|
{
|
||||||
AInventory *coin = ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
||||||
char goldstr[32];
|
char goldstr[32];
|
||||||
|
|
||||||
sprintf (goldstr, "%d", coin != NULL ? coin->Amount : 0);
|
sprintf (goldstr, "%d", coin != NULL ? coin->Amount : 0);
|
||||||
|
@ -892,94 +907,89 @@ static void DrawConversationMenu ()
|
||||||
//
|
//
|
||||||
// PickConversationReply
|
// PickConversationReply
|
||||||
//
|
//
|
||||||
// FIXME: Make this work in multiplayer
|
|
||||||
//
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void PickConversationReply ()
|
static void PickConversationReply ()
|
||||||
{
|
{
|
||||||
const char *replyText = NULL;
|
const char *replyText = NULL;
|
||||||
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
|
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
|
||||||
bool takestuff;
|
|
||||||
int i;
|
int i;
|
||||||
|
player_t *cp = &players[consoleplayer];
|
||||||
|
|
||||||
|
Conversation_TakeStuff = false;
|
||||||
|
|
||||||
M_ClearMenus ();
|
M_ClearMenus ();
|
||||||
CleanupConversationMenu ();
|
CleanupConversationMenu ();
|
||||||
if (reply == NULL)
|
if (reply == NULL)
|
||||||
{
|
{
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if you have the requisite items for this choice
|
// Check if you have the requisite items for this choice
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
if (!CheckStrifeItem (reply->ItemCheck[i], reply->ItemCheckAmount[i]))
|
if (!CheckStrifeItem (cp, reply->ItemCheck[i], reply->ItemCheckAmount[i]))
|
||||||
{
|
{
|
||||||
// No, you don't. Say so and let the NPC animate negatively.
|
// No, you don't. Say so and let the NPC animate negatively.
|
||||||
if (reply->QuickNo)
|
if (reply->QuickNo)
|
||||||
{
|
{
|
||||||
Printf ("%s\n", reply->QuickNo);
|
Printf ("%s\n", reply->QuickNo);
|
||||||
}
|
}
|
||||||
ConversationNPC->ConversationAnimation (2);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (CONV_ANIMATE);
|
||||||
|
Net_WriteByte (2);
|
||||||
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yay, you do! Let the NPC animate affirmatively.
|
// Yay, you do! Let the NPC animate affirmatively.
|
||||||
ConversationNPC->ConversationAnimation (1);
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_ANIMATE);
|
||||||
|
Net_WriteByte (1);
|
||||||
|
|
||||||
// If this reply gives you something, then try to receive it.
|
// If this reply gives you something, then try to receive it.
|
||||||
takestuff = true;
|
Conversation_TakeStuff = true;
|
||||||
if (reply->GiveType != NULL)
|
if (reply->GiveType != NULL)
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||||
{
|
{
|
||||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||||
{
|
{
|
||||||
if (players[consoleplayer].mo->FindInventory(reply->GiveType) != NULL)
|
if (cp->mo->FindInventory(reply->GiveType) != NULL)
|
||||||
{
|
{
|
||||||
takestuff = false;
|
Conversation_TakeStuff = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (takestuff)
|
if (Conversation_TakeStuff)
|
||||||
{
|
{
|
||||||
AInventory *item = static_cast<AInventory *> (Spawn (reply->GiveType, 0, 0, 0, NO_REPLACE));
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
// Items given here should not count as items!
|
Net_WriteByte (CONV_GIVEINVENTORY);
|
||||||
if (item->flags & MF_COUNTITEM)
|
Net_WriteString (reply->GiveType->TypeName.GetChars ());
|
||||||
{
|
|
||||||
level.total_items--;
|
|
||||||
item->flags &= ~MF_COUNTITEM;
|
|
||||||
}
|
|
||||||
if (item->IsA(RUNTIME_CLASS(AFlameThrower)))
|
|
||||||
{
|
|
||||||
// The flame thrower gives less ammo when given in a dialog
|
|
||||||
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
|
|
||||||
}
|
|
||||||
item->flags |= MF_DROPPED;
|
|
||||||
if (!item->TryPickup (players[consoleplayer].mo))
|
|
||||||
{
|
|
||||||
item->Destroy ();
|
|
||||||
takestuff = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reply->GiveType->IsDescendantOf (RUNTIME_CLASS (ASlideshowStarter)))
|
||||||
|
gameaction = ga_slideshow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Trying to give a non-inventory item.
|
// Trying to give a non-inventory item.
|
||||||
takestuff = false;
|
Conversation_TakeStuff = false;
|
||||||
Printf("Attempting to give non-inventory item %s\n", reply->GiveType->TypeName.GetChars());
|
Printf("Attempting to give non-inventory item %s\n", reply->GiveType->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take away required items if the give was successful or none was needed.
|
// Take away required items if the give was successful or none was needed.
|
||||||
if (takestuff)
|
if (Conversation_TakeStuff)
|
||||||
{
|
{
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
TakeStrifeItem (reply->ItemCheck[i], reply->ItemCheckAmount[i]);
|
TakeStrifeItem (&players[consoleplayer], reply->ItemCheck[i], reply->ItemCheckAmount[i]);
|
||||||
}
|
}
|
||||||
replyText = reply->QuickYes;
|
replyText = reply->QuickYes;
|
||||||
}
|
}
|
||||||
|
@ -989,9 +999,9 @@ static void PickConversationReply ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the quest log, if needed.
|
// Update the quest log, if needed.
|
||||||
if (reply->LogNumber != 0)
|
if (reply->LogNumber != 0)
|
||||||
{
|
{
|
||||||
players[consoleplayer].SetLogNumber (reply->LogNumber);
|
cp->SetLogNumber (reply->LogNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replyText != NULL)
|
if (replyText != NULL)
|
||||||
|
@ -1000,32 +1010,43 @@ static void PickConversationReply ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this reply alter the speaker's conversation node? If NextNode is positive,
|
// Does this reply alter the speaker's conversation node? If NextNode is positive,
|
||||||
// the next time they talk, the will show the new node. If it is negative, then they
|
// the next time they talk, they will show the new node. If it is negative, then they
|
||||||
// will show the new node right away without terminating the dialogue.
|
// will show the new node right away without terminating the dialogue.
|
||||||
if (reply->NextNode != 0)
|
if (reply->NextNode != 0)
|
||||||
{
|
{
|
||||||
int rootnode = FindNode (ConversationNPC->GetDefault()->Conversation);
|
int rootnode = FindNode (cp->ConversationNPC->GetDefault()->Conversation);
|
||||||
if (reply->NextNode < 0)
|
if (reply->NextNode < 0)
|
||||||
{
|
{
|
||||||
ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
||||||
if (gameaction != ga_slideshow)
|
if (gameaction != ga_slideshow)
|
||||||
{
|
{
|
||||||
P_StartConversation (ConversationNPC, players[consoleplayer].mo, ConversationFaceTalker, false);
|
P_StartConversation (cp->ConversationNPC, cp->mo, cp->ConversationFaceTalker, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
S_StopSound (ConversationNPC, CHAN_VOICE);
|
S_StopSound (cp->ConversationNPC, CHAN_VOICE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
I_SetMusicVolume(1.f);
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
|
|
||||||
|
// [CW] Set these to NULL because we're not talking to them
|
||||||
|
// anymore. However, this can interfere with slideshows so
|
||||||
|
// we don't set them to NULL in that case.
|
||||||
|
if (gameaction != ga_slideshow)
|
||||||
|
{
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_SETNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
I_SetMusicVolume (1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
@ -1058,19 +1079,96 @@ void CleanupConversationMenu ()
|
||||||
DialogueLines = NULL;
|
DialogueLines = NULL;
|
||||||
}
|
}
|
||||||
ConversationItems.Clear ();
|
ConversationItems.Clear ();
|
||||||
I_SetMusicVolume(1.f);
|
I_SetMusicVolume (1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// ConversationMenuEscaped
|
// ConversationMenuEscaped
|
||||||
//
|
//
|
||||||
// Called when the user presses escape to leave tho conversation menu.
|
// Called when the user presses escape to leave the conversation menu.
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
void ConversationMenuEscaped ()
|
void ConversationMenuEscaped ()
|
||||||
{
|
{
|
||||||
CleanupConversationMenu ();
|
CleanupConversationMenu ();
|
||||||
ConversationNPC->angle = ConversationNPCAngle;
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_NPCANGLE);
|
||||||
|
|
||||||
|
Net_WriteByte (DEM_CONVERSATION);
|
||||||
|
Net_WriteByte (CONV_SETNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// P_ConversationCommand
|
||||||
|
//
|
||||||
|
// Complete a conversation command.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void P_ConversationCommand (int player, BYTE **stream)
|
||||||
|
{
|
||||||
|
int type = ReadByte (stream);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CONV_NPCANGLE:
|
||||||
|
players[player].ConversationNPC->angle = players[player].ConversationNPCAngle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_ANIMATE:
|
||||||
|
players[player].ConversationNPC->ConversationAnimation (ReadByte (stream));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_GIVEINVENTORY:
|
||||||
|
{
|
||||||
|
AInventory *item = static_cast<AInventory *> (Spawn (ReadString (stream), 0, 0, 0, NO_REPLACE));
|
||||||
|
// Items given here should not count as items!
|
||||||
|
if (item->flags & MF_COUNTITEM)
|
||||||
|
{
|
||||||
|
level.total_items--;
|
||||||
|
item->flags &= ~MF_COUNTITEM;
|
||||||
|
}
|
||||||
|
if (item->IsA(RUNTIME_CLASS(AFlameThrower)))
|
||||||
|
{
|
||||||
|
// The flame thrower gives less ammo when given in a dialog
|
||||||
|
static_cast<AWeapon*>(item)->AmmoGive1 = 40;
|
||||||
|
}
|
||||||
|
item->flags |= MF_DROPPED;
|
||||||
|
if (!item->TryPickup (players[player].mo))
|
||||||
|
{
|
||||||
|
item->Destroy ();
|
||||||
|
Conversation_TakeStuff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_TAKEINVENTORY:
|
||||||
|
{
|
||||||
|
AInventory *item = players[player].ConversationPC->FindInventory (PClass::FindClass (ReadString (stream)));
|
||||||
|
|
||||||
|
if (item != NULL)
|
||||||
|
{
|
||||||
|
item->Amount -= ReadWord (stream);
|
||||||
|
if (item->Amount <= 0)
|
||||||
|
{
|
||||||
|
item->Destroy ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONV_SETNULL:
|
||||||
|
players[player].ConversationFaceTalker = NULL;
|
||||||
|
players[player].ConversationNPC = NULL;
|
||||||
|
players[player].ConversationPC = NULL;
|
||||||
|
players[player].ConversationNPCAngle = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
// users can edit as simple text files. Particularly useful would be
|
// users can edit as simple text files. Particularly useful would be
|
||||||
// the ability to call ACS functions to implement AppearsWhen properties
|
// the ability to call ACS functions to implement AppearsWhen properties
|
||||||
// and ACS scripts to implement ActionTaken properties.
|
// and ACS scripts to implement ActionTaken properties.
|
||||||
// TODO: Make this work in multiplayer and in demos. Multiplayer probably
|
// TODO: Make this work in demos.
|
||||||
// isn't possible for Strife conversations, but demo playback should be.
|
|
||||||
|
|
||||||
struct FStrifeDialogueReply;
|
struct FStrifeDialogueReply;
|
||||||
class FTexture;
|
class FTexture;
|
||||||
|
@ -48,6 +47,16 @@ struct FStrifeDialogueReply
|
||||||
FBrokenLines *ReplyLines;
|
FBrokenLines *ReplyLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// [CW] These are used to make conversations work.
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CONV_NPCANGLE,
|
||||||
|
CONV_ANIMATE,
|
||||||
|
CONV_GIVEINVENTORY,
|
||||||
|
CONV_TAKEINVENTORY,
|
||||||
|
CONV_SETNULL,
|
||||||
|
};
|
||||||
|
|
||||||
extern TArray<FStrifeDialogueNode *> StrifeDialogues;
|
extern TArray<FStrifeDialogueNode *> StrifeDialogues;
|
||||||
|
|
||||||
// There were 344 types in Strife, and Strife conversations refer
|
// There were 344 types in Strife, and Strife conversations refer
|
||||||
|
@ -62,4 +71,6 @@ void P_FreeStrifeConversations ();
|
||||||
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle);
|
void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveangle);
|
||||||
void P_ResumeConversation ();
|
void P_ResumeConversation ();
|
||||||
|
|
||||||
|
void P_ConversationCommand (int player, BYTE **stream);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -370,7 +370,8 @@ FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad)
|
||||||
thisframe.Time = ((max - min + 1) << 16) | min;
|
thisframe.Time = ((max - min + 1) << 16) | min;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
thisframe.Time = 0; // Shush, GCC.
|
||||||
sc.ScriptError ("Must specify a duration for switch frame");
|
sc.ScriptError ("Must specify a duration for switch frame");
|
||||||
}
|
}
|
||||||
frames.Push(thisframe);
|
frames.Push(thisframe);
|
||||||
|
|
|
@ -287,7 +287,11 @@ player_s::player_s()
|
||||||
crouchdir(0),
|
crouchdir(0),
|
||||||
crouchfactor(0),
|
crouchfactor(0),
|
||||||
crouchoffset(0),
|
crouchoffset(0),
|
||||||
crouchviewdelta(0)
|
crouchviewdelta(0),
|
||||||
|
ConversationNPC(0),
|
||||||
|
ConversationPC(0),
|
||||||
|
ConversationNPCAngle(0),
|
||||||
|
ConversationFaceTalker(0)
|
||||||
{
|
{
|
||||||
memset (&cmd, 0, sizeof(cmd));
|
memset (&cmd, 0, sizeof(cmd));
|
||||||
memset (&userinfo, 0, sizeof(userinfo));
|
memset (&userinfo, 0, sizeof(userinfo));
|
||||||
|
@ -321,6 +325,8 @@ size_t player_s::FixPointers (const DObject *old, DObject *rep)
|
||||||
if (last_mate == old) last_mate = replacement, changed++;
|
if (last_mate == old) last_mate = replacement, changed++;
|
||||||
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
|
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
|
||||||
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
|
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
|
||||||
|
if (ConversationNPC == old) ConversationNPC = replacement, changed++;
|
||||||
|
if (ConversationPC == old) ConversationPC = replacement, changed++;
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +343,8 @@ size_t player_s::PropagateMark()
|
||||||
GC::Mark(mate);
|
GC::Mark(mate);
|
||||||
GC::Mark(last_mate);
|
GC::Mark(last_mate);
|
||||||
GC::Mark(ReadyWeapon);
|
GC::Mark(ReadyWeapon);
|
||||||
|
GC::Mark(ConversationNPC);
|
||||||
|
GC::Mark(ConversationPC);
|
||||||
if (PendingWeapon != WP_NOCHANGE)
|
if (PendingWeapon != WP_NOCHANGE)
|
||||||
{
|
{
|
||||||
GC::Mark(PendingWeapon);
|
GC::Mark(PendingWeapon);
|
||||||
|
@ -2426,7 +2434,11 @@ void player_s::Serialize (FArchive &arc)
|
||||||
<< BlendB
|
<< BlendB
|
||||||
<< BlendA
|
<< BlendA
|
||||||
<< accuracy << stamina
|
<< accuracy << stamina
|
||||||
<< LogText;
|
<< LogText
|
||||||
|
<< ConversationNPC
|
||||||
|
<< ConversationPC
|
||||||
|
<< ConversationNPCAngle
|
||||||
|
<< ConversationFaceTalker;
|
||||||
|
|
||||||
for (i = 0; i < MAXPLAYERS; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
arc << frags[i];
|
arc << frags[i];
|
||||||
|
|
|
@ -343,7 +343,7 @@ int P_TranslateSectorSpecial (int special)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (special>=0 && special<SectorTranslations.Size())
|
if ((unsigned)special < SectorTranslations.Size())
|
||||||
{
|
{
|
||||||
if (SectorTranslations[special].bitmask_allowed && mask) special = 0;
|
if (SectorTranslations[special].bitmask_allowed && mask) special = 0;
|
||||||
else special = SectorTranslations[special].newtype;
|
else special = SectorTranslations[special].newtype;
|
||||||
|
|
|
@ -193,8 +193,8 @@ void R_InitPicAnims (void)
|
||||||
if (debuganimated)
|
if (debuganimated)
|
||||||
{
|
{
|
||||||
Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n",
|
Printf("Defining animation '%s' (texture %d, lump %d, file %d) to '%s' (texture %d, lump %d, file %d)\n",
|
||||||
tex1->Name, tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()),
|
tex1->Name, pic1, tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()),
|
||||||
tex2->Name, tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump()));
|
tex2->Name, pic2, tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: doesn't work with hires texture replacements.
|
/* FIXME: doesn't work with hires texture replacements.
|
||||||
|
|
|
@ -61,4 +61,5 @@ void restoreinterpolations();
|
||||||
void clearinterpolations();
|
void clearinterpolations();
|
||||||
void SerializeInterpolations(FArchive &arc);
|
void SerializeInterpolations(FArchive &arc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1261,10 +1261,11 @@ static void S_AddSNDINFO (int lump)
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
FName nm = sc.String;
|
FName nm = sc.String;
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
if (sc.Compare("timidity")) MidiDevices[nm] = 1;
|
if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY;
|
||||||
else if (sc.Compare("standard")) MidiDevices[nm] = 0;
|
else if (sc.Compare("fmod")) MidiDevices[nm] = MDEV_FMOD;
|
||||||
else if (sc.Compare("opl")) MidiDevices[nm] = 2;
|
else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI;
|
||||||
else if (sc.Compare("default")) MidiDevices[nm] = -1;
|
else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL;
|
||||||
|
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT;
|
||||||
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
|
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -502,7 +502,7 @@ void S_ParseSndSeq (int levellump)
|
||||||
FScanner sc(lump, "SNDSEQ");
|
FScanner sc(lump, "SNDSEQ");
|
||||||
while (sc.GetString ())
|
while (sc.GetString ())
|
||||||
{
|
{
|
||||||
bool bDoorSound;
|
bool bDoorSound = false;
|
||||||
|
|
||||||
if (*sc.String == ':' || *sc.String == '[')
|
if (*sc.String == ':' || *sc.String == '[')
|
||||||
{
|
{
|
||||||
|
|
|
@ -1307,10 +1307,10 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
{
|
{
|
||||||
int lumpnum = -1;
|
int lumpnum = -1;
|
||||||
int offset, length;
|
int offset, length;
|
||||||
int device = -1;
|
int device = MDEV_DEFAULT;
|
||||||
|
|
||||||
|
|
||||||
int * devp = MidiDevices.CheckKey(FName(musicname));
|
int *devp = MidiDevices.CheckKey(FName(musicname));
|
||||||
if (devp != NULL) device = *devp;
|
if (devp != NULL) device = *devp;
|
||||||
|
|
||||||
if (!FileExists (musicname))
|
if (!FileExists (musicname))
|
||||||
|
|
|
@ -311,6 +311,15 @@ ReverbContainer *S_FindEnvironment (const char *name);
|
||||||
ReverbContainer *S_FindEnvironment (int id);
|
ReverbContainer *S_FindEnvironment (int id);
|
||||||
void S_AddEnvironment (ReverbContainer *settings);
|
void S_AddEnvironment (ReverbContainer *settings);
|
||||||
|
|
||||||
|
enum EMidiDevice
|
||||||
|
{
|
||||||
|
MDEV_DEFAULT = -1,
|
||||||
|
MDEV_MMAPI = 0,
|
||||||
|
MDEV_TIMIDITY = 1,
|
||||||
|
MDEV_OPL = 2,
|
||||||
|
MDEV_FMOD = 3,
|
||||||
|
};
|
||||||
|
|
||||||
typedef TMap<FName, int> MidiDeviceMap;
|
typedef TMap<FName, int> MidiDeviceMap;
|
||||||
|
|
||||||
extern MidiDeviceMap MidiDevices;
|
extern MidiDeviceMap MidiDevices;
|
||||||
|
|
|
@ -152,7 +152,7 @@ void I_InitGraphics ()
|
||||||
}
|
}
|
||||||
gl_disabled = gl_nogl;
|
gl_disabled = gl_nogl;
|
||||||
#endif
|
#endif
|
||||||
val.Bool = !!Args.CheckParm ("-devparm");
|
val.Bool = !!Args->CheckParm ("-devparm");
|
||||||
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
||||||
|
|
||||||
#ifndef NO_GL
|
#ifndef NO_GL
|
||||||
|
|
|
@ -121,6 +121,20 @@ void STACK_ARGS call_terms ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FinalGC
|
||||||
|
//
|
||||||
|
// Collect garbage one last time before exiting.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void FinalGC()
|
||||||
|
{
|
||||||
|
Args = NULL;
|
||||||
|
GC::FullGC();
|
||||||
|
}
|
||||||
|
|
||||||
static void STACK_ARGS NewFailure ()
|
static void STACK_ARGS NewFailure ()
|
||||||
{
|
{
|
||||||
I_FatalError ("Failed to allocate memory from system heap");
|
I_FatalError ("Failed to allocate memory from system heap");
|
||||||
|
@ -209,6 +223,7 @@ int main (int argc, char **argv)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Args = new DArgs(argc, argv);
|
Args = new DArgs(argc, argv);
|
||||||
|
atterm(FinalGC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
killough 1/98:
|
killough 1/98:
|
||||||
|
|
|
@ -92,6 +92,11 @@ FMOD_RESULT SPC_CreateCodec(FMOD::System *sys);
|
||||||
static int Enum_NumForName(const FEnumList *list, const char *name);
|
static int Enum_NumForName(const FEnumList *list, const char *name);
|
||||||
static const char *Enum_NameForNum(const FEnumList *list, int num);
|
static const char *Enum_NameForNum(const FEnumList *list, int num);
|
||||||
|
|
||||||
|
static FMOD_RESULT F_CALLBACK Memory_Open(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata);
|
||||||
|
static FMOD_RESULT F_CALLBACK Memory_Close(void *handle, void *userdata);
|
||||||
|
static FMOD_RESULT F_CALLBACK Memory_Read(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata);
|
||||||
|
static FMOD_RESULT F_CALLBACK Memory_Seek(void *handle, unsigned int pos, void *userdata);
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
EXTERN_CVAR (String, snd_output)
|
EXTERN_CVAR (String, snd_output)
|
||||||
|
@ -106,15 +111,19 @@ EXTERN_CVAR (Int, snd_channels)
|
||||||
ReverbContainer *ForcedEnvironment;
|
ReverbContainer *ForcedEnvironment;
|
||||||
|
|
||||||
CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
CVAR (Int, snd_buffercount, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
CVAR (Bool, snd_hrtf, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (Bool, snd_dspnet, false, 0)
|
CVAR (Bool, snd_dspnet, false, 0)
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
static const ReverbContainer *PrevEnvironment;
|
static const ReverbContainer *PrevEnvironment;
|
||||||
|
static bool ShowedBanner;
|
||||||
|
|
||||||
// The rolloff callback is called during FMOD::Sound::play, so we need this
|
// The rolloff callback is called during FMOD::Sound::play, so we need this
|
||||||
// global variable to contain the sound info during that time for the
|
// global variable to contain the sound info during that time for the
|
||||||
|
@ -164,8 +173,6 @@ static const FEnumList SpeakerModeNames[] =
|
||||||
{ "1", FMOD_SPEAKERMODE_MONO },
|
{ "1", FMOD_SPEAKERMODE_MONO },
|
||||||
{ "2", FMOD_SPEAKERMODE_STEREO },
|
{ "2", FMOD_SPEAKERMODE_STEREO },
|
||||||
{ "4", FMOD_SPEAKERMODE_QUAD },
|
{ "4", FMOD_SPEAKERMODE_QUAD },
|
||||||
{ "Headphones", 9001 },
|
|
||||||
{ "HRTF", 9001 },
|
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,6 +202,16 @@ static const FEnumList SoundFormatNames[] =
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *OpenStateNames[] =
|
||||||
|
{
|
||||||
|
"Ready",
|
||||||
|
"Loading",
|
||||||
|
"Error",
|
||||||
|
"Connecting",
|
||||||
|
"Buffering",
|
||||||
|
"Seeking"
|
||||||
|
};
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -374,6 +391,26 @@ public:
|
||||||
return FMOD_OK == Channel->setPosition(pos, FMOD_TIMEUNIT_MS);
|
return FMOD_OK == Channel->setPosition(pos, FMOD_TIMEUNIT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString GetStats()
|
||||||
|
{
|
||||||
|
FString stats;
|
||||||
|
FMOD_OPENSTATE openstate;
|
||||||
|
unsigned int percentbuffered;
|
||||||
|
unsigned int position;
|
||||||
|
bool starving;
|
||||||
|
|
||||||
|
if (FMOD_OK == Stream->getOpenState(&openstate, &percentbuffered, &starving))
|
||||||
|
{
|
||||||
|
stats = (openstate <= FMOD_OPENSTATE_SEEKING ? OpenStateNames[openstate] : "Unknown state");
|
||||||
|
stats.AppendFormat(",%3d%% buffered, %s", percentbuffered, starving ? "Starving" : "Well-fed");
|
||||||
|
}
|
||||||
|
if (Channel != NULL && FMOD_OK == Channel->getPosition(&position, FMOD_TIMEUNIT_MS))
|
||||||
|
{
|
||||||
|
stats.AppendFormat(", %d ms", position);
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
static FMOD_RESULT F_CALLBACK PCMReadCallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
|
static FMOD_RESULT F_CALLBACK PCMReadCallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
|
||||||
{
|
{
|
||||||
FMOD_RESULT result;
|
FMOD_RESULT result;
|
||||||
|
@ -445,6 +482,8 @@ bool FMODSoundRenderer::Init()
|
||||||
FMOD_SOUND_FORMAT format;
|
FMOD_SOUND_FORMAT format;
|
||||||
FMOD_DSP_RESAMPLER resampler;
|
FMOD_DSP_RESAMPLER resampler;
|
||||||
FMOD_INITFLAGS initflags;
|
FMOD_INITFLAGS initflags;
|
||||||
|
int samplerate;
|
||||||
|
int driver;
|
||||||
|
|
||||||
int eval;
|
int eval;
|
||||||
|
|
||||||
|
@ -454,7 +493,12 @@ bool FMODSoundRenderer::Init()
|
||||||
PausableSfx = NULL;
|
PausableSfx = NULL;
|
||||||
PrevEnvironment = DefaultEnvironments[0];
|
PrevEnvironment = DefaultEnvironments[0];
|
||||||
|
|
||||||
Printf ("I_InitSound: Initializing FMOD\n");
|
Printf("I_InitSound: Initializing FMOD\n");
|
||||||
|
if (!ShowedBanner)
|
||||||
|
{
|
||||||
|
Printf("FMOD Sound System, copyright © Firelight Technologies Pty, Ltd., 1994-2007.\n");
|
||||||
|
ShowedBanner = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a System object and initialize.
|
// Create a System object and initialize.
|
||||||
result = FMOD::System_Create(&Sys);
|
result = FMOD::System_Create(&Sys);
|
||||||
|
@ -472,30 +516,6 @@ bool FMODSoundRenderer::Init()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Sys->getDriverCaps(0, &Driver_Caps, &Driver_MinFrequency, &Driver_MaxFrequency, &speakermode);
|
|
||||||
ERRCHECK(result);
|
|
||||||
|
|
||||||
// Set the user selected speaker mode.
|
|
||||||
eval = Enum_NumForName(SpeakerModeNames, snd_speakermode);
|
|
||||||
if (eval >= 0)
|
|
||||||
{
|
|
||||||
speakermode = FMOD_SPEAKERMODE(eval);
|
|
||||||
}
|
|
||||||
result = Sys->setSpeakerMode(speakermode < 9000 ? speakermode : FMOD_SPEAKERMODE_STEREO);
|
|
||||||
ERRCHECK(result);
|
|
||||||
|
|
||||||
// Set software format
|
|
||||||
eval = Enum_NumForName(SoundFormatNames, snd_output_format);
|
|
||||||
format = eval >= 0 ? FMOD_SOUND_FORMAT(eval) : FMOD_SOUND_FORMAT_PCM16;
|
|
||||||
eval = Enum_NumForName(ResamplerNames, snd_resampler);
|
|
||||||
resampler = eval >= 0 ? FMOD_DSP_RESAMPLER(eval) : FMOD_DSP_RESAMPLER_LINEAR;
|
|
||||||
result = Sys->setSoftwareFormat(snd_samplerate, format, 0, 0, resampler);
|
|
||||||
ERRCHECK(result);
|
|
||||||
|
|
||||||
// Set software channels according to snd_channels
|
|
||||||
result = Sys->setSoftwareChannels(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS);
|
|
||||||
ERRCHECK(result);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (OSPlatform == os_WinNT4)
|
if (OSPlatform == os_WinNT4)
|
||||||
{
|
{
|
||||||
|
@ -541,18 +561,74 @@ bool FMODSoundRenderer::Init()
|
||||||
ERRCHECK(result);
|
ERRCHECK(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = Sys->getNumDrivers(&driver);
|
||||||
|
if (result == FMOD_OK)
|
||||||
|
{
|
||||||
|
if (snd_driver >= driver)
|
||||||
|
{
|
||||||
|
Printf (TEXTCOLOR_BLUE"Driver %d does not exist. Using 0.\n", *snd_driver);
|
||||||
|
driver = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
driver = snd_driver;
|
||||||
|
}
|
||||||
|
result = Sys->setDriver(driver);
|
||||||
|
}
|
||||||
|
result = Sys->getDriver(&driver);
|
||||||
|
result = Sys->getDriverCaps(driver, &Driver_Caps, &Driver_MinFrequency, &Driver_MaxFrequency, &speakermode);
|
||||||
|
ERRCHECK(result);
|
||||||
|
|
||||||
|
// Set the user selected speaker mode.
|
||||||
|
eval = Enum_NumForName(SpeakerModeNames, snd_speakermode);
|
||||||
|
if (eval >= 0)
|
||||||
|
{
|
||||||
|
speakermode = FMOD_SPEAKERMODE(eval);
|
||||||
|
}
|
||||||
|
result = Sys->setSpeakerMode(speakermode < 9000 ? speakermode : FMOD_SPEAKERMODE_STEREO);
|
||||||
|
ERRCHECK(result);
|
||||||
|
|
||||||
|
// Set software format
|
||||||
|
eval = Enum_NumForName(SoundFormatNames, snd_output_format);
|
||||||
|
format = eval >= 0 ? FMOD_SOUND_FORMAT(eval) : FMOD_SOUND_FORMAT_PCM16;
|
||||||
|
eval = Enum_NumForName(ResamplerNames, snd_resampler);
|
||||||
|
resampler = eval >= 0 ? FMOD_DSP_RESAMPLER(eval) : FMOD_DSP_RESAMPLER_LINEAR;
|
||||||
|
samplerate = clamp<int>(snd_samplerate, Driver_MinFrequency, Driver_MaxFrequency);
|
||||||
|
if (samplerate == 0 || snd_samplerate == 0)
|
||||||
|
{ // Creative's ASIO drivers report the only supported frequency as 0!
|
||||||
|
if (FMOD_OK != Sys->getSoftwareFormat(&samplerate, NULL, NULL, NULL, NULL, NULL))
|
||||||
|
{
|
||||||
|
samplerate = 48000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (samplerate != snd_samplerate && snd_samplerate != 0)
|
||||||
|
{
|
||||||
|
Printf(TEXTCOLOR_BLUE"Sample rate %d is unsupported. Trying %d\n", *snd_samplerate, samplerate);
|
||||||
|
}
|
||||||
|
result = Sys->setSoftwareFormat(samplerate, format, 0, 0, resampler);
|
||||||
|
|
||||||
|
// Set software channels according to snd_channels
|
||||||
|
result = Sys->setSoftwareChannels(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS);
|
||||||
|
ERRCHECK(result);
|
||||||
|
|
||||||
if (Driver_Caps & FMOD_CAPS_HARDWARE_EMULATED)
|
if (Driver_Caps & FMOD_CAPS_HARDWARE_EMULATED)
|
||||||
{ // The user has the 'Acceleration' slider set to off!
|
{ // The user has the 'Acceleration' slider set to off!
|
||||||
// This is really bad for latency!
|
// This is really bad for latency!
|
||||||
Printf ("Warning: The sound acceleration slider has been set to off.\n");
|
Printf (TEXTCOLOR_BLUE"Warning: The sound acceleration slider has been set to off.\n");
|
||||||
Printf ("Please turn it back on if you want decent sound.\n");
|
Printf (TEXTCOLOR_BLUE"Please turn it back on if you want decent sound.\n");
|
||||||
result = Sys->setDSPBufferSize(1024, 10); // At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms.
|
result = Sys->setDSPBufferSize(1024, 10); // At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms.
|
||||||
ERRCHECK(result);
|
ERRCHECK(result);
|
||||||
}
|
}
|
||||||
|
else if (snd_buffersize != 0 || snd_buffercount != 0)
|
||||||
|
{
|
||||||
|
int buffersize = snd_buffersize ? snd_buffersize : 1024;
|
||||||
|
int buffercount = snd_buffercount ? snd_buffercount : 4;
|
||||||
|
result = Sys->setDSPBufferSize(buffersize, buffercount);
|
||||||
|
}
|
||||||
|
|
||||||
// Try to init
|
// Try to init
|
||||||
initflags = FMOD_INIT_NORMAL;
|
initflags = FMOD_INIT_NORMAL;
|
||||||
if (speakermode > 9000)
|
if (snd_hrtf)
|
||||||
{
|
{
|
||||||
initflags |= FMOD_INIT_SOFTWARE_HRTF;
|
initflags |= FMOD_INIT_SOFTWARE_HRTF;
|
||||||
}
|
}
|
||||||
|
@ -560,17 +636,38 @@ bool FMODSoundRenderer::Init()
|
||||||
{
|
{
|
||||||
initflags |= FMOD_INIT_ENABLE_DSPNET;
|
initflags |= FMOD_INIT_ENABLE_DSPNET;
|
||||||
}
|
}
|
||||||
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
for (;;)
|
||||||
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
{
|
||||||
{ // The speaker mode selected isn't supported by this soundcard. Switch it back to stereo.
|
|
||||||
result = Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
|
||||||
ERRCHECK(result);
|
|
||||||
|
|
||||||
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
||||||
ERRCHECK(result);
|
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||||
|
{ // The speaker mode selected isn't supported by this soundcard. Switch it back to stereo.
|
||||||
|
result = Sys->getSpeakerMode(&speakermode);
|
||||||
|
if (result == FMOD_OK && FMOD_OK == Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
else if (result == FMOD_ERR_OUTPUT_INIT)
|
||||||
|
{
|
||||||
|
FMOD_OUTPUTTYPE output;
|
||||||
|
result = Sys->getOutput(&output);
|
||||||
|
if (result == FMOD_OK && output != FMOD_OUTPUTTYPE_DSOUND)
|
||||||
|
{
|
||||||
|
Printf(TEXTCOLOR_BLUE" Init failed for output type %s. Retrying with DirectSound.\n",
|
||||||
|
Enum_NameForNum(OutputNames, output));
|
||||||
|
if (FMOD_OK == Sys->setOutput(FMOD_OUTPUTTYPE_DSOUND))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (result != FMOD_OK)
|
if (result != FMOD_OK)
|
||||||
{ // Initializing FMOD failed. Cry cry.
|
{ // Initializing FMOD failed. Cry cry.
|
||||||
|
Printf (" System::init returned error code %d\n", result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,6 +753,8 @@ void FMODSoundRenderer::PrintStatus()
|
||||||
int samplerate;
|
int samplerate;
|
||||||
int numoutputchannels;
|
int numoutputchannels;
|
||||||
int num2d, num3d, total;
|
int num2d, num3d, total;
|
||||||
|
unsigned int bufferlength;
|
||||||
|
int numbuffers;
|
||||||
|
|
||||||
if (FMOD_OK == Sys->getOutput(&output))
|
if (FMOD_OK == Sys->getOutput(&output))
|
||||||
{
|
{
|
||||||
|
@ -688,6 +787,10 @@ void FMODSoundRenderer::PrintStatus()
|
||||||
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: "TEXTCOLOR_GREEN"%d\n", numoutputchannels);
|
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: "TEXTCOLOR_GREEN"%d\n", numoutputchannels);
|
||||||
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(ResamplerNames, resampler));
|
Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(ResamplerNames, resampler));
|
||||||
}
|
}
|
||||||
|
if (FMOD_OK == Sys->getDSPBufferSize(&bufferlength, &numbuffers))
|
||||||
|
{
|
||||||
|
Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: "TEXTCOLOR_GREEN"%u samples x %d\n", bufferlength, numbuffers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -839,7 +942,7 @@ SoundStream *FMODSoundRenderer::CreateStream (SoundStreamCallback callback, int
|
||||||
|
|
||||||
capsule = new FMODStreamCapsule (userdata, callback, this);
|
capsule = new FMODStreamCapsule (userdata, callback, this);
|
||||||
|
|
||||||
mode = FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_SOFTWARE | FMOD_CREATESTREAM;
|
mode = FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_SOFTWARE | FMOD_CREATESTREAM | FMOD_OPENONLY;
|
||||||
sample_shift = (flags & SoundStream::Bits8) ? 0 : 1;
|
sample_shift = (flags & SoundStream::Bits8) ? 0 : 1;
|
||||||
channel_shift = (flags & SoundStream::Mono) ? 0 : 1;
|
channel_shift = (flags & SoundStream::Mono) ? 0 : 1;
|
||||||
|
|
||||||
|
@ -892,6 +995,7 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
|
||||||
FMOD_MODE mode;
|
FMOD_MODE mode;
|
||||||
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
|
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
|
||||||
FMOD::Sound *stream;
|
FMOD::Sound *stream;
|
||||||
|
FMOD_RESULT result;
|
||||||
|
|
||||||
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||||
if (flags & SoundStream::Loop)
|
if (flags & SoundStream::Loop)
|
||||||
|
@ -905,8 +1009,25 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
|
||||||
}
|
}
|
||||||
exinfo.length = length;
|
exinfo.length = length;
|
||||||
exinfo.fileoffset = offset;
|
exinfo.fileoffset = offset;
|
||||||
|
if ((*snd_midipatchset)[0] != '\0')
|
||||||
|
{
|
||||||
|
exinfo.dlsname = snd_midipatchset;
|
||||||
|
}
|
||||||
|
|
||||||
if (FMOD_OK == Sys->createSound(filename_or_data, mode, &exinfo, &stream))
|
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
|
||||||
|
if (result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL)
|
||||||
|
{
|
||||||
|
// FMOD_ERR_FORMAT could refer to either the main sound file or
|
||||||
|
// to the DLS instrument set. Try again without special DLS
|
||||||
|
// instruments to see if that lets it succeed.
|
||||||
|
exinfo.dlsname = NULL;
|
||||||
|
result = Sys->createSound(filename_or_data, mode, &exinfo, &stream);
|
||||||
|
if (result == FMOD_OK)
|
||||||
|
{
|
||||||
|
Printf("%s is an unsupported format.\n", *snd_midipatchset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == FMOD_OK)
|
||||||
{
|
{
|
||||||
return new FMODStreamCapsule(stream, this);
|
return new FMODStreamCapsule(stream, this);
|
||||||
}
|
}
|
||||||
|
@ -1080,6 +1201,10 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
|
||||||
if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level)
|
if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level)
|
||||||
{ // Only set it if it's different.
|
{ // Only set it if it's different.
|
||||||
chan->set3DPanLevel(level);
|
chan->set3DPanLevel(level);
|
||||||
|
if (level < 1)
|
||||||
|
{ // Let the noise come from all speakers, not just the front ones.
|
||||||
|
chan->setSpeakerMix(1,1,1,1,1,1,1,1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return oldmode;
|
return oldmode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,12 +69,12 @@ extern void ChildSigHandler (int signum);
|
||||||
#include "i_cd.h"
|
#include "i_cd.h"
|
||||||
#include "tempfiles.h"
|
#include "tempfiles.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
|
#include "stats.h"
|
||||||
|
|
||||||
#include <fmod.h>
|
#include <fmod.h>
|
||||||
|
|
||||||
EXTERN_CVAR (Int, snd_samplerate)
|
EXTERN_CVAR (Int, snd_samplerate)
|
||||||
EXTERN_CVAR (Int, snd_mididevice)
|
EXTERN_CVAR (Int, snd_mididevice)
|
||||||
CVAR(Bool, snd_modplug, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
||||||
|
|
||||||
static bool MusicDown = true;
|
static bool MusicDown = true;
|
||||||
|
|
||||||
|
@ -83,6 +83,11 @@ int nomusic = 0;
|
||||||
float relative_volume = 1.f;
|
float relative_volume = 1.f;
|
||||||
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
|
float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function
|
||||||
|
|
||||||
|
|
||||||
|
CVAR(Bool, snd_modplug, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
StreamSong *ModPlugSong_Create(FILE *file, char *musiccache, int length);
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// CVAR snd_musicvolume
|
// CVAR snd_musicvolume
|
||||||
|
@ -131,6 +136,11 @@ void MusInfo::TimidityVolumeChanged()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString MusInfo::GetStats()
|
||||||
|
{
|
||||||
|
return "No stats available for this song";
|
||||||
|
}
|
||||||
|
|
||||||
void I_InitMusic (void)
|
void I_InitMusic (void)
|
||||||
{
|
{
|
||||||
static bool setatterm = false;
|
static bool setatterm = false;
|
||||||
|
@ -187,6 +197,9 @@ void I_PlaySong (void *handle, int _looping, float rel_vol)
|
||||||
currSong = info;
|
currSong = info;
|
||||||
else
|
else
|
||||||
currSong = NULL;
|
currSong = NULL;
|
||||||
|
|
||||||
|
// Notify the sound system of the changed relative volume
|
||||||
|
snd_musicvolume.Callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +240,7 @@ void I_UnRegisterSong (void *handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *I_RegisterSong (const char *filename, char * musiccache, int offset, int len, int device)
|
void *I_RegisterSong (const char *filename, char *musiccache, int offset, int len, int device)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
MusInfo *info = NULL;
|
MusInfo *info = NULL;
|
||||||
|
@ -238,7 +251,7 @@ void *I_RegisterSong (const char *filename, char * musiccache, int offset, int l
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset!=-1)
|
if (offset != -1)
|
||||||
{
|
{
|
||||||
file = fopen (filename, "rb");
|
file = fopen (filename, "rb");
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
|
@ -270,105 +283,177 @@ void *I_RegisterSong (const char *filename, char * musiccache, int offset, int l
|
||||||
memcpy(&id, &musiccache[0], 4);
|
memcpy(&id, &musiccache[0], 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
// non-windows platforms don't support MDEV_MIDI so map to MDEV_FMOD
|
||||||
|
if (device == MDEV_MMAPI) device = MDEV_FMOD;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Check for MUS format
|
// Check for MUS format
|
||||||
if (id == MAKE_ID('M','U','S',0x1a))
|
if (id == MAKE_ID('M','U','S',0x1a))
|
||||||
{
|
{
|
||||||
if (GSnd != NULL && device != 0 && device != 1 && (opl_enable || device == 2) )
|
if (GSnd != NULL)
|
||||||
{
|
{
|
||||||
info = new OPLMUSSong (file, musiccache, len);
|
/* MUS are played as:
|
||||||
|
- OPL:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when opl_enable is true and no midi device is set for the song
|
||||||
|
|
||||||
|
Timidity:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when snd_mididevice is -2 and no midi device is set for the song
|
||||||
|
|
||||||
|
FMod:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when snd_mididevice is -1 and no midi device is set for the song
|
||||||
|
- as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0
|
||||||
|
|
||||||
|
MMAPI (Win32 only):
|
||||||
|
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
|
||||||
|
- when snd_mididevice is >= 0 and no midi device is set for the song
|
||||||
|
- as fallback when both OPL and Timidity failed and snd_mididevice is >= 0
|
||||||
|
*/
|
||||||
|
if ((opl_enable && device == MDEV_DEFAULT) || device == MDEV_OPL)
|
||||||
|
{
|
||||||
|
info = new OPLMUSSong (file, musiccache, len);
|
||||||
|
}
|
||||||
|
else if (device == MDEV_TIMIDITY || (device == MDEV_DEFAULT && snd_mididevice == -2))
|
||||||
|
{
|
||||||
|
info = new TimiditySong (file, musiccache, len);
|
||||||
|
}
|
||||||
|
if (info != NULL && !info->IsValid())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
info = NULL;
|
||||||
|
device = MDEV_DEFAULT;
|
||||||
|
}
|
||||||
|
if (info == NULL && (snd_mididevice == -1 || device == MDEV_FMOD) && device != MDEV_MMAPI)
|
||||||
|
{
|
||||||
|
TArray<BYTE> midi;
|
||||||
|
bool midi_made = false;
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
midi_made = ProduceMIDI((BYTE *)musiccache, midi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BYTE *mus = new BYTE[len];
|
||||||
|
size_t did_read = fread(mus, 1, len, file);
|
||||||
|
if (did_read == (size_t)len)
|
||||||
|
{
|
||||||
|
midi_made = ProduceMIDI(mus, midi);
|
||||||
|
}
|
||||||
|
fseek(file, -(long)did_read, SEEK_CUR);
|
||||||
|
delete[] mus;
|
||||||
|
}
|
||||||
|
if (midi_made)
|
||||||
|
{
|
||||||
|
info = new StreamSong((char *)&midi[0], -1, midi.Size());
|
||||||
|
if (!info->IsValid())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
info = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
info = new MUSSong2 (file, musiccache, len);
|
||||||
if (device == 1 && GSnd != NULL)
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
// Check for MIDI format
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (id == MAKE_ID('M','T','h','d'))
|
||||||
|
{
|
||||||
|
// This is a midi file
|
||||||
|
// MIDI can't be played with OPL so use default.
|
||||||
|
if (device == MDEV_OPL) device = MDEV_DEFAULT;
|
||||||
|
|
||||||
|
/* MIDI are played as:
|
||||||
|
Timidity:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when snd_mididevice is -2 and no midi device is set for the song
|
||||||
|
|
||||||
|
FMod:
|
||||||
|
- if explicitly selected by $mididevice
|
||||||
|
- when snd_mididevice is -1 and no midi device is set for the song
|
||||||
|
- as fallback when Timidity failed unless snd_mididevice is >= 0
|
||||||
|
|
||||||
|
MMAPI (Win32 only):
|
||||||
|
- if explicitly selected by $mididevice (non-Win32 redirects this to FMOD)
|
||||||
|
- when snd_mididevice is >= 0 and no midi device is set for the song
|
||||||
|
- as fallback when Timidity failed and snd_mididevice is >= 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((device == MDEV_TIMIDITY || (snd_mididevice == -2 && device == MDEV_DEFAULT)) && GSnd != NULL)
|
||||||
{
|
{
|
||||||
info = new TimiditySong (file, musiccache, len);
|
info = new TimiditySong (file, musiccache, len);
|
||||||
if (!info->IsValid())
|
if (!info->IsValid())
|
||||||
{
|
{
|
||||||
delete info;
|
delete info;
|
||||||
info = NULL;
|
info = NULL;
|
||||||
|
device = MDEV_DEFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info == NULL && (snd_mididevice != -2 || device == 0))
|
|
||||||
{
|
|
||||||
info = new MUSSong2 (file, musiccache, len);
|
|
||||||
}
|
|
||||||
else if (info == NULL && GSnd != NULL)
|
|
||||||
#endif // _WIN32
|
|
||||||
{
|
|
||||||
info = new TimiditySong (file, musiccache, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for MIDI format
|
|
||||||
else if (id == MAKE_ID('M','T','h','d'))
|
|
||||||
{
|
|
||||||
// This is a midi file
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (device == 1 && GSnd != NULL)
|
if (info == NULL && device != MDEV_FMOD && (snd_mididevice >= 0 || device == MDEV_MMAPI))
|
||||||
{
|
|
||||||
info = new TimiditySong (file, musiccache, len);
|
|
||||||
if (!info->IsValid())
|
|
||||||
{
|
{
|
||||||
delete info;
|
info = new MIDISong2 (file, musiccache, len);
|
||||||
info = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (info == NULL && (snd_mididevice != -2 || device == 0))
|
|
||||||
{
|
|
||||||
info = new MIDISong2 (file, musiccache, len);
|
|
||||||
}
|
|
||||||
else if (info == NULL && GSnd != NULL)
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
{
|
|
||||||
info = new TimiditySong (file, musiccache, len);
|
|
||||||
}
|
}
|
||||||
}
|
// Check for RDosPlay raw OPL format
|
||||||
// Check for RDosPlay raw OPL format
|
else if (id == MAKE_ID('R','A','W','A') && len >= 12)
|
||||||
else if (id == MAKE_ID('R','A','W','A') && len >= 12)
|
|
||||||
{
|
|
||||||
DWORD fullsig[2];
|
|
||||||
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
{
|
||||||
if (fread (fullsig, 4, 2, file) != 2)
|
DWORD fullsig[2];
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
fclose (file);
|
if (fread (fullsig, 4, 2, file) != 2)
|
||||||
return 0;
|
{
|
||||||
|
fclose (file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fseek (file, -8, SEEK_CUR);
|
||||||
}
|
}
|
||||||
fseek (file, -8, SEEK_CUR);
|
else
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(fullsig, musiccache, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullsig[1] == MAKE_ID('D','A','T','A'))
|
|
||||||
{
|
|
||||||
info = new OPLMUSSong (file, musiccache, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for Martin Fernandez's modified IMF format
|
|
||||||
else if (id == MAKE_ID('A','D','L','I'))
|
|
||||||
{
|
|
||||||
char fullhead[6];
|
|
||||||
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
|
||||||
if (fread (fullhead, 1, 6, file) != 6)
|
|
||||||
{
|
{
|
||||||
fclose (file);
|
memcpy(fullsig, musiccache, 8);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
if (fullsig[1] == MAKE_ID('D','A','T','A'))
|
||||||
|
{
|
||||||
|
info = new OPLMUSSong (file, musiccache, len);
|
||||||
}
|
}
|
||||||
fseek (file, -6, SEEK_CUR);
|
|
||||||
}
|
}
|
||||||
else
|
// Check for Martin Fernandez's modified IMF format
|
||||||
|
else if (id == MAKE_ID('A','D','L','I'))
|
||||||
{
|
{
|
||||||
memcpy(fullhead, musiccache, 6);
|
char fullhead[6];
|
||||||
}
|
|
||||||
if (fullhead[4] == 'B' && fullhead[5] == 1)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
info = new OPLMUSSong (file, musiccache, len);
|
if (fread (fullhead, 1, 6, file) != 6)
|
||||||
|
{
|
||||||
|
fclose (file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fseek (file, -6, SEEK_CUR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(fullhead, musiccache, 6);
|
||||||
|
}
|
||||||
|
if (fullhead[4] == 'B' && fullhead[5] == 1)
|
||||||
|
{
|
||||||
|
info = new OPLMUSSong (file, musiccache, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,11 +486,12 @@ void *I_RegisterSong (const char *filename, char * musiccache, int offset, int l
|
||||||
// 1024 bytes is an arbitrary restriction. It's assumed that anything
|
// 1024 bytes is an arbitrary restriction. It's assumed that anything
|
||||||
// smaller than this can't possibly be a valid music file if it hasn't
|
// smaller than this can't possibly be a valid music file if it hasn't
|
||||||
// been identified already, so don't even bother trying to load it.
|
// been identified already, so don't even bother trying to load it.
|
||||||
if (info == NULL && GSnd != NULL && len >= 1024)
|
// Of course MIDIs shorter than 1024 bytes should pass.
|
||||||
|
if (info == NULL && GSnd != NULL && (len >= 1024 || id == MAKE_ID('M','T','h','d')))
|
||||||
{
|
{
|
||||||
if (snd_modplug)
|
if (snd_modplug)
|
||||||
{
|
{
|
||||||
info = ModPlugSong::Create(file, musiccache, len);
|
info = ModPlugSong_Create(file, musiccache, len);
|
||||||
}
|
}
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
{
|
{
|
||||||
|
@ -488,3 +574,18 @@ CCMD(testmusicvol)
|
||||||
else
|
else
|
||||||
Printf("Current relative volume is %1.2f\n", relative_volume);
|
Printf("Current relative volume is %1.2f\n", relative_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// STAT music
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
ADD_STAT(music)
|
||||||
|
{
|
||||||
|
if (currSong != NULL)
|
||||||
|
{
|
||||||
|
return currSong->GetStats();
|
||||||
|
}
|
||||||
|
return "No song playing";
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
//
|
//
|
||||||
void I_InitMusic ();
|
void I_InitMusic ();
|
||||||
void I_ShutdownMusic ();
|
void I_ShutdownMusic ();
|
||||||
void I_BuildMIDIMenuList (struct value_s **values, float *numValues);
|
void I_BuildMIDIMenuList (struct value_t **values, float *numValues);
|
||||||
void I_UpdateMusic ();
|
void I_UpdateMusic ();
|
||||||
|
|
||||||
// Volume.
|
// Volume.
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
#include "mus2midi.h"
|
#include "mus2midi.h"
|
||||||
#include "i_sound.h"
|
#include "i_sound.h"
|
||||||
#include "modplug/modplug.h"
|
|
||||||
|
|
||||||
void I_InitMusicWin32 ();
|
void I_InitMusicWin32 ();
|
||||||
void I_ShutdownMusicWin32 ();
|
void I_ShutdownMusicWin32 ();
|
||||||
|
@ -45,6 +44,7 @@ public:
|
||||||
virtual bool IsValid () const = 0;
|
virtual bool IsValid () const = 0;
|
||||||
virtual bool SetPosition (int order);
|
virtual bool SetPosition (int order);
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
|
virtual FString GetStats();
|
||||||
|
|
||||||
enum EState
|
enum EState
|
||||||
{
|
{
|
||||||
|
@ -243,6 +243,7 @@ public:
|
||||||
bool IsMIDI () const { return false; }
|
bool IsMIDI () const { return false; }
|
||||||
bool IsValid () const { return m_Stream != NULL; }
|
bool IsValid () const { return m_Stream != NULL; }
|
||||||
bool SetPosition (int order);
|
bool SetPosition (int order);
|
||||||
|
FString GetStats();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StreamSong () : m_Stream(NULL), m_LastPos(0) {}
|
StreamSong () : m_Stream(NULL), m_LastPos(0) {}
|
||||||
|
@ -289,25 +290,6 @@ protected:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModPlugSong : public StreamSong
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ModPlugSong *Create(FILE *file, char *musiccache, int length);
|
|
||||||
~ModPlugSong ();
|
|
||||||
bool IsPlaying ();
|
|
||||||
bool SetPosition (int order);
|
|
||||||
void Play(bool);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
|
|
||||||
ModPlugSong (ModPlugFile *dat);
|
|
||||||
|
|
||||||
ModPlugFile * Data;
|
|
||||||
int order;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// MUS file played by a software OPL2 synth and streamed through FMOD -------
|
// MUS file played by a software OPL2 synth and streamed through FMOD -------
|
||||||
|
|
||||||
class OPLMUSSong : public StreamSong
|
class OPLMUSSong : public StreamSong
|
||||||
|
|
|
@ -68,12 +68,13 @@ extern HINSTANCE g_hInst;
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "i_video.h"
|
#include "i_video.h"
|
||||||
#include "s_sound.h"
|
#include "s_sound.h"
|
||||||
|
#include "v_text.h"
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
|
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
|
|
||||||
EXTERN_CVAR (Float, snd_sfxvolume)
|
EXTERN_CVAR (Float, snd_sfxvolume)
|
||||||
CVAR (Int, snd_samplerate, 48000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
|
@ -124,7 +125,7 @@ void I_InitSound ()
|
||||||
{
|
{
|
||||||
delete GSnd;
|
delete GSnd;
|
||||||
GSnd = NULL;
|
GSnd = NULL;
|
||||||
Printf ("Sound init failed. Using nosound.\n");
|
Printf (TEXTCOLOR_RED"Sound init failed. Using nosound.\n");
|
||||||
}
|
}
|
||||||
I_InitMusic ();
|
I_InitMusic ();
|
||||||
snd_sfxvolume.Callback ();
|
snd_sfxvolume.Callback ();
|
||||||
|
@ -215,3 +216,8 @@ bool SoundStream::SetPosition(int pos)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString SoundStream::GetStats()
|
||||||
|
{
|
||||||
|
return "No stream stats available.";
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
virtual bool SetPaused (bool paused) = 0;
|
virtual bool SetPaused (bool paused) = 0;
|
||||||
virtual unsigned int GetPosition () = 0;
|
virtual unsigned int GetPosition () = 0;
|
||||||
virtual bool SetPosition (int pos);
|
virtual bool SetPosition (int pos);
|
||||||
|
virtual FString GetStats();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, void *userdata);
|
typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, void *userdata);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifdef _WIN32
|
|
||||||
#include "i_musicinterns.h"
|
#include "i_musicinterns.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
#include "i_music.h"
|
#include "i_music.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
static DWORD nummididevices;
|
static DWORD nummididevices;
|
||||||
static bool nummididevicesset;
|
static bool nummididevicesset;
|
||||||
|
#ifdef _WIN32
|
||||||
UINT mididevice;
|
UINT mididevice;
|
||||||
|
|
||||||
CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||||
|
@ -56,19 +57,22 @@ void I_InitMusicWin32 ()
|
||||||
|
|
||||||
void I_ShutdownMusicWin32 ()
|
void I_ShutdownMusicWin32 ()
|
||||||
{
|
{
|
||||||
// I don't know if this is an NT 4.0 bug or an FMOD bug, but if waveout
|
// Ancient bug a saw on NT 4.0 and an old version of FMOD 3: If waveout
|
||||||
// is used for sound, and a MIDI is also played, then when I quit, the OS
|
// is used for sound and a MIDI is also played, then when I quit, the OS
|
||||||
// tells me a free block was modified after being freed. This is
|
// tells me a free block was modified after being freed. This is
|
||||||
// apparently a synchronization issue between two threads, because if I
|
// apparently a synchronization issue between two threads, because if I
|
||||||
// put this Sleep here after stopping the music but before shutting down
|
// put this Sleep here after stopping the music but before shutting down
|
||||||
// the entire sound system, the error does not happen. I don't think it's
|
// the entire sound system, the error does not happen. Observed with a
|
||||||
// a driver problem, because it happens with both a Vortex 2 and an Audigy.
|
// Vortex 2 (may Aureal rest in peace) and an Audigy (damn you, Creative!).
|
||||||
// Though if their drivers are both based off some common Microsoft sample
|
// I no longer have a system with NT4 drivers, so I don't know if this
|
||||||
// code, I suppose it could be a driver issue.
|
// workaround is still needed or not.
|
||||||
Sleep (50);
|
if (OSPlatform == os_WinNT4)
|
||||||
|
{
|
||||||
|
Sleep(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I_BuildMIDIMenuList (struct value_s **outValues, float *numValues)
|
void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
|
||||||
{
|
{
|
||||||
if (*outValues == NULL)
|
if (*outValues == NULL)
|
||||||
{
|
{
|
||||||
|
@ -79,13 +83,13 @@ void I_BuildMIDIMenuList (struct value_s **outValues, float *numValues)
|
||||||
|
|
||||||
values[0].name = "TiMidity++";
|
values[0].name = "TiMidity++";
|
||||||
values[0].value = -2.0;
|
values[0].value = -2.0;
|
||||||
|
values[1].name = "FMOD";
|
||||||
|
values[1].value = -1.0;
|
||||||
if (nummididevices > 0)
|
if (nummididevices > 0)
|
||||||
{
|
{
|
||||||
UINT id;
|
UINT id;
|
||||||
int p;
|
int p;
|
||||||
|
|
||||||
values[1].name = "MIDI Mapper";
|
|
||||||
values[1].value = -1.0;
|
|
||||||
for (id = 0, p = 2; id < nummididevices; ++id)
|
for (id = 0, p = 2; id < nummididevices; ++id)
|
||||||
{
|
{
|
||||||
MIDIOUTCAPS caps;
|
MIDIOUTCAPS caps;
|
||||||
|
@ -107,7 +111,7 @@ void I_BuildMIDIMenuList (struct value_s **outValues, float *numValues)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*numValues = 1.f;
|
*numValues = 2.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,9 +161,9 @@ CCMD (snd_listmididevices)
|
||||||
MMRESULT res;
|
MMRESULT res;
|
||||||
|
|
||||||
PrintMidiDevice (-2, "TiMidity++", 0, 0);
|
PrintMidiDevice (-2, "TiMidity++", 0, 0);
|
||||||
|
PrintMidiDevice (-1, "FMOD", 0, 0);
|
||||||
if (nummididevices != 0)
|
if (nummididevices != 0)
|
||||||
{
|
{
|
||||||
PrintMidiDevice (-1, "MIDI Mapper", MOD_MAPPER, 0);
|
|
||||||
for (id = 0; id < nummididevices; ++id)
|
for (id = 0; id < nummididevices; ++id)
|
||||||
{
|
{
|
||||||
res = midiOutGetDevCaps (id, &caps, sizeof(caps));
|
res = midiOutGetDevCaps (id, &caps, sizeof(caps));
|
||||||
|
@ -174,4 +178,39 @@ CCMD (snd_listmididevices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Everything but Windows uses this code.
|
||||||
|
|
||||||
|
CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
{
|
||||||
|
if (self < -2)
|
||||||
|
self = -2;
|
||||||
|
else if (self > -1)
|
||||||
|
self = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
|
||||||
|
{
|
||||||
|
if (*outValues == NULL)
|
||||||
|
{
|
||||||
|
int count = 1 + nummididevices + (nummididevices > 0);
|
||||||
|
value_t *values;
|
||||||
|
|
||||||
|
*outValues = values = new value_t[count];
|
||||||
|
|
||||||
|
values[0].name = "TiMidity++";
|
||||||
|
values[0].value = -2.0;
|
||||||
|
values[1].name = "FMOD";
|
||||||
|
values[1].value = -1.0;
|
||||||
|
*numValues = 2.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CCMD (snd_listmididevices)
|
||||||
|
{
|
||||||
|
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
|
Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -244,6 +244,7 @@ TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
|
||||||
void TimiditySong::PrepTimidity ()
|
void TimiditySong::PrepTimidity ()
|
||||||
{
|
{
|
||||||
int pipeSize;
|
int pipeSize;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, TRUE };
|
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, TRUE };
|
||||||
|
|
||||||
|
@ -267,6 +268,11 @@ void TimiditySong::PrepTimidity ()
|
||||||
|
|
||||||
pipeSize = (timidity_pipe * timidity_frequency / 1000)
|
pipeSize = (timidity_pipe * timidity_frequency / 1000)
|
||||||
<< (timidity_stereo + !timidity_8bit);
|
<< (timidity_stereo + !timidity_8bit);
|
||||||
|
|
||||||
|
if (GSnd == NULL)
|
||||||
|
{ // Can't pipe if using no sound.
|
||||||
|
pipeSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (pipeSize != 0)
|
if (pipeSize != 0)
|
||||||
{
|
{
|
||||||
|
@ -520,11 +526,11 @@ bool TimiditySong::LaunchTimidity ()
|
||||||
close (WavePipe[0]);
|
close (WavePipe[0]);
|
||||||
dup2 (WavePipe[1], STDOUT_FILENO);
|
dup2 (WavePipe[1], STDOUT_FILENO);
|
||||||
freopen ("/dev/null", "r", stdin);
|
freopen ("/dev/null", "r", stdin);
|
||||||
freopen ("/dev/null", "w", stderr);
|
// freopen ("/dev/null", "w", stderr);
|
||||||
close (WavePipe[1]);
|
close (WavePipe[1]);
|
||||||
|
|
||||||
printf ("exec %s\n", words.we_wordv[0]);
|
execvp (words.we_wordv[0], words.we_wordv);
|
||||||
execvp (words.we_wordv[0], words.we_wordv);
|
fprintf(stderr,"execvp failed\n");
|
||||||
exit (0); // if execvp succeeds, we never get here
|
exit (0); // if execvp succeeds, we never get here
|
||||||
}
|
}
|
||||||
else if (forkres < 0)
|
else if (forkres < 0)
|
||||||
|
@ -536,7 +542,12 @@ bool TimiditySong::LaunchTimidity ()
|
||||||
// printf ("child is %d\n", forkres);
|
// printf ("child is %d\n", forkres);
|
||||||
ChildProcess = forkres;
|
ChildProcess = forkres;
|
||||||
close (WavePipe[1]);
|
close (WavePipe[1]);
|
||||||
WavePipe[1] = -1;
|
WavePipe[1] = -1;
|
||||||
|
/* usleep(1000000);
|
||||||
|
if (waitpid(ChildProcess, NULL, WNOHANG) == ChildProcess)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Launching timidity failed\n");
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
wordfree (&words);
|
wordfree (&words);
|
||||||
|
@ -575,21 +586,36 @@ bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
if (ChildQuit == song->ChildProcess)
|
||||||
|
{
|
||||||
|
ChildQuit = 0;
|
||||||
|
fprintf (stderr, "child gone\n");
|
||||||
|
song->ChildProcess = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(song->WavePipe[0], &rfds);
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 50;
|
||||||
|
// fprintf(stderr,"select\n");
|
||||||
|
if (select(1, &rfds, NULL, NULL, &tv) <= 0 && 0)
|
||||||
|
{ // Nothing available, so play silence.
|
||||||
|
// fprintf(stderr,"nothing\n");
|
||||||
|
// memset(buff, 0, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// fprintf(stderr,"something\n");
|
||||||
|
|
||||||
got = read (song->WavePipe[0], (BYTE *)buff, len);
|
got = read (song->WavePipe[0], (BYTE *)buff, len);
|
||||||
if (got < len)
|
if (got < len)
|
||||||
{
|
{
|
||||||
memset ((BYTE *)buff+got, 0, len-got);
|
memset ((BYTE *)buff+got, 0, len-got);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ChildQuit == song->ChildProcess)
|
|
||||||
{
|
|
||||||
ChildQuit = 0;
|
|
||||||
// printf ("child gone\n");
|
|
||||||
song->ChildProcess = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,24 @@
|
||||||
// 192 approximately replicates the volume of a WinAmp Wave export of the song.
|
// 192 approximately replicates the volume of a WinAmp Wave export of the song.
|
||||||
CVAR(Int, snd_mod_mastervolume, 192, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR(Int, snd_mod_mastervolume, 192, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
ModPlugSong *ModPlugSong::Create (FILE *iofile, char * musiccache, int len)
|
class ModPlugSong : public StreamSong
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
~ModPlugSong ();
|
||||||
|
bool IsPlaying ();
|
||||||
|
bool SetPosition (int order);
|
||||||
|
void Play(bool);
|
||||||
|
|
||||||
|
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
|
||||||
|
ModPlugSong (ModPlugFile *dat);
|
||||||
|
|
||||||
|
ModPlugFile * Data;
|
||||||
|
int order;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
StreamSong *ModPlugSong_Create (FILE *iofile, char * musiccache, int len)
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,15 @@ StreamSong::~StreamSong ()
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSong::StreamSong (const char *filename_or_data, int offset, int len)
|
StreamSong::StreamSong (const char *filename_or_data, int offset, int len)
|
||||||
{
|
{
|
||||||
m_Stream = GSnd->OpenStream (filename_or_data, SoundStream::Loop, offset, len);
|
if (GSnd != NULL)
|
||||||
|
{
|
||||||
|
m_Stream = GSnd->OpenStream (filename_or_data, SoundStream::Loop, offset, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_Stream = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StreamSong::IsPlaying ()
|
bool StreamSong::IsPlaying ()
|
||||||
|
@ -92,3 +99,12 @@ bool StreamSong::SetPosition(int order)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString StreamSong::GetStats()
|
||||||
|
{
|
||||||
|
if (m_Stream != NULL)
|
||||||
|
{
|
||||||
|
return m_Stream->GetStats();
|
||||||
|
}
|
||||||
|
return "No song loaded\n";
|
||||||
|
}
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
// This file was automatically generated by the
|
// This file was automatically generated by the
|
||||||
// updaterevision tool. Do not edit by hand.
|
// updaterevision tool. Do not edit by hand.
|
||||||
|
|
||||||
#define ZD_SVN_REVISION_STRING "853"
|
#define ZD_SVN_REVISION_STRING "858"
|
||||||
#define ZD_SVN_REVISION_NUMBER 853
|
#define ZD_SVN_REVISION_NUMBER 858
|
||||||
|
|
|
@ -70,6 +70,30 @@ void FImageCollection::Init (const char **patchNames, int numPatches, int namesp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MH] Mainly for mugshots with skins and SBARINFO
|
||||||
|
void FImageCollection::Add (const char **patchNames, int numPatches, int namespc)
|
||||||
|
{
|
||||||
|
int NewNumImages = NumImages + numPatches;
|
||||||
|
int *NewImageMap = new int[NewNumImages];
|
||||||
|
|
||||||
|
memcpy(NewImageMap, ImageMap, (NumImages * sizeof(int)));
|
||||||
|
|
||||||
|
for (int i = 0; i < numPatches; ++i)
|
||||||
|
{
|
||||||
|
int picnum = TexMan.AddPatch (patchNames[i], namespc, true);
|
||||||
|
|
||||||
|
if (picnum == -1 && namespc != ns_sprites)
|
||||||
|
{
|
||||||
|
picnum = TexMan.AddPatch (patchNames[i], ns_sprites);
|
||||||
|
}
|
||||||
|
NewImageMap[NumImages + i] = picnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] ImageMap;
|
||||||
|
ImageMap = NewImageMap;
|
||||||
|
NumImages = NewNumImages;
|
||||||
|
}
|
||||||
|
|
||||||
void FImageCollection::Uninit ()
|
void FImageCollection::Uninit ()
|
||||||
{
|
{
|
||||||
if (ImageMap != NULL)
|
if (ImageMap != NULL)
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
~FImageCollection ();
|
~FImageCollection ();
|
||||||
|
|
||||||
void Init (const char **patchnames, int numPatches, int namespc=0);
|
void Init (const char **patchnames, int numPatches, int namespc=0);
|
||||||
|
void Add (const char **patchnames, int numPatches, int namespc=0);
|
||||||
void Uninit ();
|
void Uninit ();
|
||||||
|
|
||||||
FTexture *operator[] (int index) const;
|
FTexture *operator[] (int index) const;
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
// Protocol version used in demos.
|
// Protocol version used in demos.
|
||||||
// Bump it if you change existing DEM_ commands or add new ones.
|
// Bump it if you change existing DEM_ commands or add new ones.
|
||||||
// Otherwise, it should be safe to leave it alone.
|
// Otherwise, it should be safe to leave it alone.
|
||||||
#define DEMOGAMEVERSION 0x20B
|
#define DEMOGAMEVERSION 0x20C
|
||||||
|
|
||||||
// Minimum demo version we can play.
|
// Minimum demo version we can play.
|
||||||
// Bump it whenever you change or remove existing DEM_ commands.
|
// Bump it whenever you change or remove existing DEM_ commands.
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
// SAVESIG should match SAVEVER.
|
// SAVESIG should match SAVEVER.
|
||||||
|
|
||||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||||
#define MINSAVEVER 849
|
#define MINSAVEVER 854
|
||||||
|
|
||||||
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
|
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
|
||||||
// Never write a savegame with a version lower than what we need
|
// Never write a savegame with a version lower than what we need
|
||||||
|
|
|
@ -238,6 +238,20 @@ static void UnWTS (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FinalGC
|
||||||
|
//
|
||||||
|
// If this doesn't free everything, the debug CRT will let us know.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void FinalGC()
|
||||||
|
{
|
||||||
|
Args = NULL;
|
||||||
|
GC::FullGC();
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// LayoutErrorPane
|
// LayoutErrorPane
|
||||||
|
@ -777,6 +791,7 @@ void DoMain (HINSTANCE hInstance)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Args = new DArgs(__argc, __argv);
|
Args = new DArgs(__argc, __argv);
|
||||||
|
atterm(FinalGC);
|
||||||
|
|
||||||
// Under XP, get our session ID so we can know when the user changes/locks sessions.
|
// Under XP, get our session ID so we can know when the user changes/locks sessions.
|
||||||
// Since we need to remain binary compatible with older versions of Windows, we
|
// Since we need to remain binary compatible with older versions of Windows, we
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue