mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-06-01 09:41:58 +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 += -DNEED_STRUPR
|
||||
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 += -lGL -lGLU
|
||||
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 += -Isnes_spc/snes_spc/ -I/usr/include/fmodex/
|
||||
CFLAGS += $(INCLUDES)
|
||||
|
||||
RELEASEOBJ ?= releaseobj
|
||||
DEBUGOBJ ?= debugobj
|
||||
|
||||
CPPSRCS = $(wildcard $(addsuffix *.cpp,$(SRCDIRS)))
|
||||
CSRCS = $(wildcard $(addsuffix *.c,$(SRCDIRS)))
|
||||
CSRCS = $(filter-out src/xlat/xlat_parser.c, $(wildcard $(addsuffix *.c,$(SRCDIRS))))
|
||||
ifndef NOASM
|
||||
ASRCS = $(wildcard src/*.nas)
|
||||
CFLAGS += -DUSEASM=1
|
||||
|
@ -78,11 +79,11 @@ endef
|
|||
|
||||
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
|
||||
$(CCDV) $(CXX) $(LDFLAGS) $(OBJDIR)/autostart.o \
|
||||
$(filter-out %/autostart.o %/autozend.o,$(OBJS)) \
|
||||
$(OBJDIR)/autozend.o -o $(ZDOOMBIN)
|
||||
snes_spc/libsnes_spc.a $(OBJDIR)/autozend.o -o $(ZDOOMBIN)
|
||||
endif
|
||||
|
||||
# include any of the dep files that already exist
|
||||
|
@ -119,23 +120,36 @@ ifdef RESTART
|
|||
@make -f $(firstword $(MAKEFILE_LIST)) RESTART=
|
||||
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):
|
||||
mkdir $(OBJDIR)
|
||||
|
||||
toolsandpk3: tools/makewad/makewad tools/dehsupp/dehsupp tools/xlatcc/xlatcc
|
||||
toolsandpk3: tools/makewad/makewad src/svnrevision_gz.h
|
||||
make -C wadsrc/
|
||||
|
||||
zdoom.pk3: toolsandpk3
|
||||
ln -sf wadsrc/gzdoom.pk3 ./
|
||||
|
||||
snes_spc/libsnes_spc.a:
|
||||
$(MAKE) -C snes_spc/
|
||||
|
||||
tools/makewad/makewad: ccdv
|
||||
make -C tools/makewad/
|
||||
|
||||
tools/dehsupp/dehsupp: ccdv
|
||||
make -C tools/dehsupp/
|
||||
tools/lemon/lemon:
|
||||
$(MAKE) -C tools/lemon/
|
||||
|
||||
tools/xlatcc/xlatcc: ccdv
|
||||
make -C tools/xlatcc/
|
||||
tools/updaterevision/updaterevision: ccdv
|
||||
make -C tools/updaterevision/
|
||||
|
||||
src/svnrevision_gz.h: tools/updaterevision/updaterevision
|
||||
tools/updaterevision/updaterevision src src/svnrevision_gz.h
|
||||
|
||||
ccdv: ccdv-posix.c
|
||||
@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]));
|
||||
memset(gArgsStr, 0, sizeof(gArgsStr));
|
||||
|
||||
if(strcmp(gAction+8, "ar") == 0)
|
||||
{
|
||||
snprintf(gTarget, sizeof(gTarget), "%s", Basename(argv[i + 1]));
|
||||
}
|
||||
else if(strcmp(gAction+8, "cc") == 0 ||
|
||||
if(strcmp(gAction+8, "cc") == 0 ||
|
||||
strcmp(gAction+8, "ld") == 0 ||
|
||||
strcmp(gAction+8, "gcc") == 0 ||
|
||||
strcmp(gAction+8, "g++") == 0 ||
|
||||
|
|
|
@ -769,7 +769,7 @@ public:
|
|||
|
||||
enum { S_NULL = 2, S_GENERICFREEZEDEATH = 3 };
|
||||
|
||||
TArray<TObjPtr<AActor>> dynamiclights;
|
||||
TArray<TObjPtr<AActor> > dynamiclights;
|
||||
void * lightassociations;
|
||||
bool hasmodel;
|
||||
subsector_s * subsector;
|
||||
|
|
|
@ -88,7 +88,6 @@ enum
|
|||
|
||||
static bool waitingforspawn[MAXPLAYERS];
|
||||
|
||||
|
||||
DCajunMaster::~DCajunMaster()
|
||||
{
|
||||
ForgetBots();
|
||||
|
|
|
@ -865,7 +865,7 @@ int VPrintf (int printlevel, const char *format, va_list parms)
|
|||
|
||||
FString outline;
|
||||
outline.VFormat (format, parms);
|
||||
return PrintString (printlevel, outline);
|
||||
return PrintString (printlevel, outline.GetChars());
|
||||
}
|
||||
|
||||
int STACK_ARGS Printf (int printlevel, const char *format, ...)
|
||||
|
|
|
@ -242,7 +242,20 @@ static const char *IWADNames[] =
|
|||
"hexen.wad",
|
||||
"hexdd.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
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "a_sharedglobal.h"
|
||||
#include "st_start.h"
|
||||
#include "teaminfo.h"
|
||||
#include "p_conversation.h"
|
||||
|
||||
int P_StartScript (AActor *who, line_t *where, int script, char *map, bool backSide,
|
||||
int arg0, int arg1, int arg2, int always, bool wantResultCode, bool net);
|
||||
|
@ -2361,6 +2362,10 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
}
|
||||
break;
|
||||
|
||||
case DEM_CONVERSATION:
|
||||
P_ConversationCommand (player, stream);
|
||||
break;
|
||||
|
||||
default:
|
||||
I_Error ("Unknown net command: %d", type);
|
||||
break;
|
||||
|
@ -2451,6 +2456,31 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
skip = 3 + *(*stream + 2) * 4;
|
||||
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:
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -320,6 +320,11 @@ public:
|
|||
fixed_t crouchoffset;
|
||||
fixed_t crouchviewdelta;
|
||||
|
||||
// [CW] I moved these here for multiplayer conversation support.
|
||||
AActor *ConversationNPC, *ConversationPC;
|
||||
angle_t ConversationNPCAngle;
|
||||
bool ConversationFaceTalker;
|
||||
|
||||
fixed_t GetDeltaViewHeight() const
|
||||
{
|
||||
return (mo->ViewHeight + crouchviewdelta - viewheight) >> 3;
|
||||
|
|
|
@ -150,6 +150,7 @@ enum EDemoCommand
|
|||
DEM_ADDCONTROLLER, // 48 Player to add to the controller list.
|
||||
DEM_DELCONTROLLER, // 49 Player to remove from the controller list.
|
||||
DEM_KILLCLASSCHEAT, // 50 String: Class to kill.
|
||||
DEM_CONVERSATION, // 51 Make conversations work.
|
||||
};
|
||||
|
||||
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
||||
|
|
|
@ -418,16 +418,19 @@ void DObject::Destroy ()
|
|||
size_t DObject::PropagateMark()
|
||||
{
|
||||
const PClass *info = GetClass();
|
||||
const size_t *offsets = info->FlatPointers;
|
||||
if (offsets == NULL)
|
||||
if (!PClass::bShutdown)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildFlatPointers();
|
||||
offsets = info->FlatPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||
offsets++;
|
||||
const size_t *offsets = info->FlatPointers;
|
||||
if (offsets == NULL)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildFlatPointers();
|
||||
offsets = info->FlatPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
GC::Mark((DObject **)((BYTE *)this + *offsets));
|
||||
offsets++;
|
||||
}
|
||||
}
|
||||
return info->Size;
|
||||
}
|
||||
|
|
|
@ -298,10 +298,14 @@ static void MarkRoot()
|
|||
if (playeringame[i])
|
||||
players[i].PropagateMark();
|
||||
}
|
||||
if (SectorMarker == NULL)
|
||||
if (SectorMarker == NULL && sectors != NULL)
|
||||
{
|
||||
SectorMarker = new DSectorMarker;
|
||||
}
|
||||
else if (sectors == NULL)
|
||||
{
|
||||
SectorMarker = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
SectorMarker->SecNum = 0;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
TArray<PClass *> PClass::m_RuntimeActors;
|
||||
TArray<PClass *> PClass::m_Types;
|
||||
PClass *PClass::TypeHash[PClass::HASH_SIZE];
|
||||
bool PClass::bShutdown;
|
||||
|
||||
// A harmless non_NULL FlatPointer for classes without pointers.
|
||||
static const size_t TheEnd = ~0u;
|
||||
|
@ -110,6 +111,7 @@ void PClass::StaticShutdown ()
|
|||
{
|
||||
delete[] uniqueFPs[i];
|
||||
}
|
||||
bShutdown = true;
|
||||
}
|
||||
|
||||
void PClass::StaticFreeData (PClass *type)
|
||||
|
|
|
@ -138,6 +138,8 @@ struct PClass
|
|||
|
||||
enum { HASH_SIZE = 256 };
|
||||
static PClass *TypeHash[HASH_SIZE];
|
||||
|
||||
static bool bShutdown;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -476,7 +476,7 @@ DFsSection *FParser::looping_section()
|
|||
SDWORD rover_index = Script->MakeIndex(Rover);
|
||||
|
||||
for(n=0; n<SECTIONSLOTS; n++)
|
||||
{
|
||||
{
|
||||
DFsSection *current = Script->sections[n];
|
||||
|
||||
// check all the sections in this hashchain
|
||||
|
@ -494,7 +494,7 @@ DFsSection *FParser::looping_section()
|
|||
}
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best; // return the best one found
|
||||
}
|
||||
|
@ -510,10 +510,10 @@ void FParser::SF_Continue(void)
|
|||
DFsSection *section;
|
||||
|
||||
if(!(section = looping_section()) ) // no loop found
|
||||
{
|
||||
{
|
||||
script_error("continue() not in loop\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Rover = Script->SectionEnd(section); // jump to the closing brace
|
||||
}
|
||||
|
@ -529,10 +529,10 @@ void FParser::SF_Break(void)
|
|||
DFsSection *section;
|
||||
|
||||
if(!(section = looping_section()) )
|
||||
{
|
||||
{
|
||||
script_error("break() not in loop\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Rover = Script->SectionEnd(section) + 1; // jump out of the loop
|
||||
}
|
||||
|
@ -761,12 +761,12 @@ void FParser::SF_PlayerName(void)
|
|||
int plnum;
|
||||
|
||||
if(!t_argc)
|
||||
{
|
||||
{
|
||||
player_t *pl=NULL;
|
||||
if (Script->trigger) pl = Script->trigger->player;
|
||||
if(pl) plnum = pl - players;
|
||||
else plnum=-1;
|
||||
}
|
||||
}
|
||||
else
|
||||
plnum = T_GetPlayerNum(t_argv[0]);
|
||||
|
||||
|
@ -820,8 +820,17 @@ void FParser::SF_PlayerObj(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;
|
||||
|
||||
if(mo && mo->player) // haleyjd: added mo->player
|
||||
|
@ -924,11 +933,17 @@ void FParser::SF_RemoveObj(void)
|
|||
|
||||
void FParser::SF_KillObj(void)
|
||||
{
|
||||
// use trigger object if not specified
|
||||
AActor *mo;
|
||||
|
||||
if(t_argc) mo = actorvalue(t_argv[0]);
|
||||
else mo = Script->trigger; // default to trigger object
|
||||
|
||||
if(t_argc)
|
||||
{
|
||||
mo = actorvalue(t_argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mo = Script->trigger; // default to trigger object
|
||||
}
|
||||
|
||||
if(mo)
|
||||
{
|
||||
// ensure the thing can be killed
|
||||
|
@ -949,8 +964,17 @@ void FParser::SF_KillObj(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.value.f = mo ? mo->x : 0; // null ptr check
|
||||
}
|
||||
|
@ -963,8 +987,17 @@ void FParser::SF_ObjX(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.value.f = mo ? mo->y : 0; // null ptr check
|
||||
}
|
||||
|
@ -977,8 +1010,17 @@ void FParser::SF_ObjY(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.value.f = mo ? mo->z : 0; // null ptr check
|
||||
}
|
||||
|
@ -992,8 +1034,17 @@ void FParser::SF_ObjZ(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.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)
|
||||
{
|
||||
// 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.value.i = mo ? mo->Sector->tag : 0; // nullptr check
|
||||
}
|
||||
|
@ -1113,8 +1172,16 @@ void FParser::SF_ObjSector(void)
|
|||
void FParser::SF_ObjHealth(void)
|
||||
{
|
||||
// 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.value.i = mo ? mo->health : 0;
|
||||
}
|
||||
|
@ -1155,7 +1222,7 @@ void FParser::SF_ObjFlag(void)
|
|||
|
||||
// make the new flag
|
||||
mo->flags |= (!!intvalue(t_argv[2])) << flagnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
t_return.type = svt_int;
|
||||
if (mo && flagnum<26)
|
||||
|
@ -1352,7 +1419,7 @@ void FParser::SF_PointToDist(void)
|
|||
// Doing this in floating point is actually faster with modern computers!
|
||||
float x = floatvalue(t_argv[2]) - floatvalue(t_argv[0]);
|
||||
float y = floatvalue(t_argv[3]) - floatvalue(t_argv[1]);
|
||||
|
||||
|
||||
t_return.type = svt_fixed;
|
||||
t_return.value.f = (fixed_t)(sqrtf(x*x+y*y)*65536.f);
|
||||
}
|
||||
|
@ -1875,7 +1942,7 @@ void DLightLevel::Tick()
|
|||
}
|
||||
else
|
||||
{
|
||||
// decrease lightlevel
|
||||
// decrease lightlevel
|
||||
if(m_Sector->lightlevel - speed <= destlevel)
|
||||
{
|
||||
// stop changing light level
|
||||
|
@ -1987,7 +2054,7 @@ void FParser::SF_SectorColormap(void)
|
|||
int i = -1;
|
||||
|
||||
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]);
|
||||
|
||||
|
@ -1995,7 +2062,7 @@ void FParser::SF_SectorColormap(void)
|
|||
secnum = T_FindSectorFromTag(tagnum, -1);
|
||||
|
||||
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];
|
||||
|
||||
|
@ -2463,15 +2530,17 @@ void FParser::SF_Gamemode(void)
|
|||
|
||||
void FParser::SF_IsPlayerObj(void)
|
||||
{
|
||||
// use trigger object if not specified
|
||||
AActor *mo;
|
||||
|
||||
if(!t_argc)
|
||||
if(t_argc)
|
||||
{
|
||||
mo = actorvalue(t_argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mo = Script->trigger;
|
||||
}
|
||||
else
|
||||
mo = actorvalue(t_argv[0]);
|
||||
|
||||
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = (mo && mo->player) ? 1 : 0;
|
||||
}
|
||||
|
@ -2770,9 +2839,9 @@ void FParser::SF_PlayerWeapon()
|
|||
"PlasmaRifle", "BFG9000", "Chainsaw", "SuperShotgun" };
|
||||
|
||||
|
||||
int playernum;
|
||||
int weaponnum;
|
||||
int newweapon;
|
||||
int playernum;
|
||||
int weaponnum;
|
||||
int newweapon;
|
||||
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
|
@ -3014,7 +3083,7 @@ void FParser::SF_MoveCamera(void)
|
|||
// I have to use floats for the math where angles are divided
|
||||
// by fixed values.
|
||||
double fangledist, fanglestep, fmovestep;
|
||||
int angledir;
|
||||
int angledir;
|
||||
AActor* target;
|
||||
int moved;
|
||||
int quad1, quad2;
|
||||
|
@ -3177,17 +3246,21 @@ void FParser::SF_MoveCamera(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)
|
||||
mo = Script->trigger;
|
||||
else
|
||||
mo = actorvalue(t_argv[0]);
|
||||
|
||||
if(mo)
|
||||
{
|
||||
mo->Activate(Script->trigger);
|
||||
}
|
||||
if(mo)
|
||||
{
|
||||
mo->Activate(Script->trigger);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3316,9 +3389,9 @@ void FParser::SF_SpawnExplosion()
|
|||
|
||||
void FParser::SF_RadiusAttack()
|
||||
{
|
||||
AActor *spot;
|
||||
AActor *source;
|
||||
int damage;
|
||||
AActor *spot;
|
||||
AActor *source;
|
||||
int damage;
|
||||
|
||||
if (CheckArgs(3))
|
||||
{
|
||||
|
@ -3367,13 +3440,22 @@ void FParser::SF_SetObjPosition()
|
|||
|
||||
void FParser::SF_TestLocation()
|
||||
{
|
||||
AActor *mo = t_argc ? actorvalue(t_argv[0]) : Script->trigger;
|
||||
|
||||
if (mo)
|
||||
// use trigger object if not specified
|
||||
AActor *mo;
|
||||
if(t_argc)
|
||||
{
|
||||
t_return.type = svt_int;
|
||||
t_return.value.f = !!P_TestMobjLocation(mo);
|
||||
}
|
||||
mo = actorvalue(t_argv[0]);
|
||||
}
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -3411,8 +3502,17 @@ void FParser::SF_HealObj() //no pain sound
|
|||
|
||||
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;
|
||||
if(mo && (mo->health <= 0 || mo->flags&MF_CORPSE))
|
||||
t_return.value.i = 1;
|
||||
|
@ -3428,8 +3528,8 @@ void FParser::SF_ObjDead()
|
|||
|
||||
void FParser::SF_SpawnMissile()
|
||||
{
|
||||
AActor *mobj;
|
||||
AActor *target;
|
||||
AActor *mobj;
|
||||
AActor *target;
|
||||
const PClass * PClass;
|
||||
|
||||
if (CheckArgs(3))
|
||||
|
@ -3450,9 +3550,9 @@ void FParser::SF_SpawnMissile()
|
|||
|
||||
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))
|
||||
{
|
||||
|
@ -3479,10 +3579,10 @@ void FParser::SF_MapThingNumExist()
|
|||
|
||||
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.value.i = SpawnedThings.Size();
|
||||
t_return.value.i = SpawnedThings.Size();
|
||||
}
|
||||
|
||||
|
||||
|
@ -3495,7 +3595,7 @@ void FParser::SF_MapThings()
|
|||
void FParser::SF_ObjState()
|
||||
{
|
||||
int state;
|
||||
AActor *mo;
|
||||
AActor *mo = NULL;
|
||||
|
||||
if (CheckArgs(1))
|
||||
{
|
||||
|
@ -3691,7 +3791,15 @@ void FParser::SF_LineAttack()
|
|||
void FParser::SF_ObjType()
|
||||
{
|
||||
// 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])
|
||||
{
|
||||
|
@ -3851,38 +3959,38 @@ void FParser::SF_DeleteHUPic()
|
|||
{
|
||||
if (CheckArgs(1))
|
||||
{
|
||||
if (HU_DeleteFSPic(intvalue(t_argv[0])) == -1)
|
||||
script_error("deletehupic: Invalid sfpic handle: %i\n", intvalue(t_argv[0]));
|
||||
if (HU_DeleteFSPic(intvalue(t_argv[0])) == -1)
|
||||
script_error("deletehupic: Invalid sfpic handle: %i\n", intvalue(t_argv[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void FParser::SF_ModifyHUPic()
|
||||
{
|
||||
if (t_argc != 4)
|
||||
{
|
||||
script_error("modifyhupic: invalid number of arguments\n");
|
||||
return;
|
||||
}
|
||||
if (t_argc != 4)
|
||||
{
|
||||
script_error("modifyhupic: invalid number of arguments\n");
|
||||
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),
|
||||
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()
|
||||
{
|
||||
if (t_argc != 2)
|
||||
{
|
||||
script_error("sethupicdisplay: invalud number of arguments\n");
|
||||
return;
|
||||
}
|
||||
if (t_argc != 2)
|
||||
{
|
||||
script_error("sethupicdisplay: invalud number of arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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]));
|
||||
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]));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3900,47 +4008,47 @@ void FParser::SF_SetCorona(void)
|
|||
return;
|
||||
}
|
||||
|
||||
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 ival = t_argv[2].value.i; // the value of what we modify
|
||||
double fval = ((double) t_argv[2].value.f / FRACUNIT);
|
||||
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 ival = t_argv[2].value.i; // the value of what we modify
|
||||
double fval = ((double) t_argv[2].value.f / FRACUNIT);
|
||||
|
||||
/*
|
||||
switch (what)
|
||||
{
|
||||
case 0:
|
||||
lspr[num].type = ival;
|
||||
break;
|
||||
case 1:
|
||||
lspr[num].light_xoffset = fval;
|
||||
break;
|
||||
case 2:
|
||||
lspr[num].light_yoffset = fval;
|
||||
break;
|
||||
case 3:
|
||||
if (t_argv[2].type == svt_string)
|
||||
lspr[num].corona_color = String2Hex(t_argv[2].value.s);
|
||||
else
|
||||
memcpy(&lspr[num].corona_color, &ival, sizeof(int));
|
||||
break;
|
||||
case 4:
|
||||
lspr[num].corona_radius = fval;
|
||||
break;
|
||||
case 5:
|
||||
if (t_argv[2].type == svt_string)
|
||||
lspr[num].dynamic_color = String2Hex(t_argv[2].value.s);
|
||||
else
|
||||
memcpy(&lspr[num].dynamic_color, &ival, sizeof(int));
|
||||
break;
|
||||
case 6:
|
||||
lspr[num].dynamic_radius = fval;
|
||||
lspr[num].dynamic_sqrradius = sqrt(lspr[num].dynamic_radius);
|
||||
break;
|
||||
default:
|
||||
CONS_Printf("Error in setcorona\n");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
switch (what)
|
||||
{
|
||||
case 0:
|
||||
lspr[num].type = ival;
|
||||
break;
|
||||
case 1:
|
||||
lspr[num].light_xoffset = fval;
|
||||
break;
|
||||
case 2:
|
||||
lspr[num].light_yoffset = fval;
|
||||
break;
|
||||
case 3:
|
||||
if (t_argv[2].type == svt_string)
|
||||
lspr[num].corona_color = String2Hex(t_argv[2].value.s);
|
||||
else
|
||||
memcpy(&lspr[num].corona_color, &ival, sizeof(int));
|
||||
break;
|
||||
case 4:
|
||||
lspr[num].corona_radius = fval;
|
||||
break;
|
||||
case 5:
|
||||
if (t_argv[2].type == svt_string)
|
||||
lspr[num].dynamic_color = String2Hex(t_argv[2].value.s);
|
||||
else
|
||||
memcpy(&lspr[num].dynamic_color, &ival, sizeof(int));
|
||||
break;
|
||||
case 6:
|
||||
lspr[num].dynamic_radius = fval;
|
||||
lspr[num].dynamic_sqrradius = sqrt(lspr[num].dynamic_radius);
|
||||
break;
|
||||
default:
|
||||
CONS_Printf("Error in setcorona\n");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
// no use for this!
|
||||
t_return.type = svt_int;
|
||||
|
@ -4074,7 +4182,7 @@ again:
|
|||
}
|
||||
else
|
||||
{
|
||||
while (mo=it.Next())
|
||||
while ((mo=it.Next()))
|
||||
{
|
||||
if (mo->IsA(pClass) && mo->health>0) count++;
|
||||
}
|
||||
|
@ -4361,10 +4469,10 @@ void FParser::SF_Wait()
|
|||
DRunningScript *runscr;
|
||||
|
||||
if(t_argc != 1)
|
||||
{
|
||||
{
|
||||
script_error("incorrect arguments to function\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
runscr = SaveCurrentScript();
|
||||
|
||||
|
@ -4385,10 +4493,10 @@ void FParser::SF_TagWait()
|
|||
DRunningScript *runscr;
|
||||
|
||||
if(t_argc != 1)
|
||||
{
|
||||
{
|
||||
script_error("incorrect arguments to function\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
runscr = SaveCurrentScript();
|
||||
|
||||
|
@ -4408,10 +4516,10 @@ void FParser::SF_ScriptWait()
|
|||
DRunningScript *runscr;
|
||||
|
||||
if(t_argc != 1)
|
||||
{
|
||||
{
|
||||
script_error("insufficient arguments to function\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
runscr = SaveCurrentScript();
|
||||
|
||||
|
@ -4451,10 +4559,10 @@ void FParser::SF_ScriptWaitPre()
|
|||
void FParser::SF_StartScript()
|
||||
{
|
||||
if(t_argc != 1)
|
||||
{
|
||||
{
|
||||
script_error("incorrect arguments to function\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int snum = intvalue(t_argv[0]);
|
||||
|
||||
|
@ -4493,15 +4601,15 @@ void FParser::SF_ScriptRunning()
|
|||
int snum = 0;
|
||||
|
||||
if(t_argc < 1)
|
||||
{
|
||||
{
|
||||
script_error("not enough arguments to function\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snum = intvalue(t_argv[0]);
|
||||
|
||||
for(current = DFraggleThinker::ActiveThinker->RunningScripts->next; current; current=current->next)
|
||||
{
|
||||
{
|
||||
if(current->script->scriptnum == snum)
|
||||
{
|
||||
// script found so return
|
||||
|
@ -4509,7 +4617,7 @@ void FParser::SF_ScriptRunning()
|
|||
t_return.value.i = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// script not found
|
||||
t_return.type = svt_int;
|
||||
|
@ -4578,27 +4686,27 @@ void init_functions(void)
|
|||
new_function("playertip", &FParser::SF_PlayerTip);
|
||||
new_function("playeringame", &FParser::SF_PlayerInGame);
|
||||
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("isplayerobj", &FParser::SF_IsPlayerObj);
|
||||
new_function("isobjplayer", &FParser::SF_IsPlayerObj);
|
||||
new_function("skincolor", &FParser::SF_SkinColor);
|
||||
new_function("playerkeys", &FParser::SF_PlayerKeys);
|
||||
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("playerselwep", &FParser::SF_PlayerSelectedWeapon);
|
||||
|
||||
// mobj stuff
|
||||
new_function("spawn", &FParser::SF_Spawn);
|
||||
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("removeobj", &FParser::SF_RemoveObj);
|
||||
new_function("objx", &FParser::SF_ObjX);
|
||||
new_function("objy", &FParser::SF_ObjY);
|
||||
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("silentteleport", &FParser::SF_SilentTeleport);
|
||||
new_function("damageobj", &FParser::SF_DamageObj);
|
||||
|
@ -4618,10 +4726,10 @@ void init_functions(void)
|
|||
new_function("objmomy", &FParser::SF_MobjMomy);
|
||||
new_function("objmomz", &FParser::SF_MobjMomz);
|
||||
|
||||
new_function("spawnmissile", &FParser::SF_SpawnMissile);
|
||||
new_function("mapthings", &FParser::SF_MapThings);
|
||||
new_function("objtype", &FParser::SF_ObjType);
|
||||
new_function("mapthingnumexist", &FParser::SF_MapThingNumExist);
|
||||
new_function("spawnmissile", &FParser::SF_SpawnMissile);
|
||||
new_function("mapthings", &FParser::SF_MapThings);
|
||||
new_function("objtype", &FParser::SF_ObjType);
|
||||
new_function("mapthingnumexist", &FParser::SF_MapThingNumExist);
|
||||
new_function("objstate", &FParser::SF_ObjState);
|
||||
new_function("resurrect", &FParser::SF_Resurrect);
|
||||
new_function("lineattack", &FParser::SF_LineAttack);
|
||||
|
@ -4665,19 +4773,19 @@ void init_functions(void)
|
|||
new_function("opendoor", &FParser::SF_OpenDoor);
|
||||
new_function("closedoor", &FParser::SF_CloseDoor);
|
||||
|
||||
// HU Graphics
|
||||
new_function("newhupic", &FParser::SF_NewHUPic);
|
||||
new_function("createpic", &FParser::SF_NewHUPic);
|
||||
new_function("deletehupic", &FParser::SF_DeleteHUPic);
|
||||
new_function("modifyhupic", &FParser::SF_ModifyHUPic);
|
||||
new_function("modifypic", &FParser::SF_ModifyHUPic);
|
||||
new_function("sethupicdisplay", &FParser::SF_SetHUPicDisplay);
|
||||
new_function("setpicvisible", &FParser::SF_SetHUPicDisplay);
|
||||
// HU Graphics
|
||||
new_function("newhupic", &FParser::SF_NewHUPic);
|
||||
new_function("createpic", &FParser::SF_NewHUPic);
|
||||
new_function("deletehupic", &FParser::SF_DeleteHUPic);
|
||||
new_function("modifyhupic", &FParser::SF_ModifyHUPic);
|
||||
new_function("modifypic", &FParser::SF_ModifyHUPic);
|
||||
new_function("sethupicdisplay", &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("checkcvar", &FParser::SF_CheckCVar);
|
||||
new_function("checkcvar", &FParser::SF_CheckCVar);
|
||||
new_function("setlinetexture", &FParser::SF_SetLineTexture);
|
||||
new_function("linetrigger", &FParser::SF_LineTrigger);
|
||||
new_function("lineflag", &FParser::SF_LineFlag);
|
||||
|
|
|
@ -328,7 +328,7 @@ void T_RegisterSpawnThing(AActor * ac)
|
|||
{
|
||||
if (DFraggleThinker::ActiveThinker)
|
||||
{
|
||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
SpawnedThings[SpawnedThings.Size()-1] = ac;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -655,7 +655,7 @@ public:
|
|||
|
||||
TObjPtr<DFsScript> LevelScript;
|
||||
TObjPtr<DRunningScript> RunningScripts;
|
||||
TArray<TObjPtr<AActor>> SpawnedThings;
|
||||
TArray<TObjPtr<AActor> > SpawnedThings;
|
||||
|
||||
DFraggleThinker();
|
||||
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;
|
||||
|
||||
|
@ -151,7 +151,7 @@ AActor *actorvalue(const svalue_t &svalue)
|
|||
}
|
||||
else
|
||||
{
|
||||
TArray<TObjPtr<AActor>> &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
// this requires some creativity. We use the intvalue
|
||||
// as the thing number of a thing in the level.
|
||||
intval = intvalue(svalue);
|
||||
|
|
|
@ -125,6 +125,11 @@ public:
|
|||
OldFaceIndex = -1;
|
||||
}
|
||||
|
||||
void AddFaceToImageCollection (void *skn, FImageCollection *images)
|
||||
{
|
||||
AddFaceToImageCollectionActual (skn, images, true);
|
||||
}
|
||||
|
||||
void MultiplayerChanged ()
|
||||
{
|
||||
DBaseStatusBar::MultiplayerChanged ();
|
||||
|
@ -989,24 +994,6 @@ private:
|
|||
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 Faces;
|
||||
|
||||
|
|
|
@ -165,6 +165,25 @@ public:
|
|||
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);
|
||||
void Destroy ();
|
||||
|
||||
|
@ -190,7 +209,8 @@ public:
|
|||
virtual void AttachToPlayer (player_s *player);
|
||||
virtual void FlashCrosshair ();
|
||||
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 ScreenSizeChanged ();
|
||||
virtual void MultiplayerChanged ();
|
||||
|
@ -222,6 +242,8 @@ protected:
|
|||
|
||||
void GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const;
|
||||
|
||||
void AddFaceToImageCollectionActual (void *skn, FImageCollection *images, bool isDoom);
|
||||
|
||||
public:
|
||||
AInventory *ValidateInvFirst (int numVisible) const;
|
||||
void DrawCrosshair ();
|
||||
|
|
|
@ -86,6 +86,7 @@ struct SBarInfo
|
|||
bool interpolateHealth;
|
||||
bool interpolateArmor;
|
||||
bool completeBorder;
|
||||
bool lowerHealthCap;
|
||||
char spacingCharacter;
|
||||
int interpolationSpeed;
|
||||
int armorInterpolationSpeed;
|
||||
|
@ -119,7 +120,7 @@ struct 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 reset();
|
||||
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;
|
||||
|
@ -197,6 +198,7 @@ enum //drawnumber flags
|
|||
DRAWNUMBER_SECRETS = 4096,
|
||||
DRAWNUMBER_TOTALSECRETS = 8192,
|
||||
DRAWNUMBER_ARMORCLASS = 16384,
|
||||
DRAWNUMBER_GLOBALVAR = 32768,
|
||||
};
|
||||
|
||||
enum //drawbar flags (will go into special2)
|
||||
|
@ -253,6 +255,14 @@ enum //event flags
|
|||
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
|
||||
{
|
||||
SBARINFO_BASE,
|
||||
|
@ -261,6 +271,7 @@ enum //Key words
|
|||
SBARINFO_INTERPOLATEARMOR,
|
||||
SBARINFO_COMPLETEBORDER,
|
||||
SBARINFO_MONOSPACEFONTS,
|
||||
SBARINFO_LOWERHEALTHCAP,
|
||||
SBARINFO_STATUSBAR,
|
||||
SBARINFO_MUGSHOT,
|
||||
};
|
||||
|
@ -293,7 +304,9 @@ enum //Bar key words
|
|||
SBARINFO_DRAWKEYBAR,
|
||||
SBARINFO_GAMEMODE,
|
||||
SBARINFO_PLAYERCLASS,
|
||||
SBARINFO_ASPECTRATIO,
|
||||
SBARINFO_WEAPONAMMO,
|
||||
SBARINFO_ININVENTORY,
|
||||
};
|
||||
|
||||
//All this so I can change the mugshot state in ACS...
|
||||
|
@ -321,13 +334,14 @@ public:
|
|||
void Tick();
|
||||
void ReceivedWeapon (AWeapon *weapon);
|
||||
void FlashItem(const PClass *itemtype);
|
||||
void ShowPop(int popnum);
|
||||
void SetMugShotState(const char* stateName, bool waitTillDone=false);
|
||||
private:
|
||||
void doCommands(SBarInfoBlock &block);
|
||||
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 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);
|
||||
void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow,
|
||||
int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter);
|
||||
|
@ -349,6 +363,7 @@ private:
|
|||
int mugshotHealth;
|
||||
int chainWiggle;
|
||||
int artiflash;
|
||||
int currentPopup;
|
||||
unsigned int invBarOffset;
|
||||
FBarShader shader_horz_normal;
|
||||
FBarShader shader_horz_reverse;
|
||||
|
|
|
@ -83,13 +83,13 @@ MugShotFrame::~MugShotFrame()
|
|||
}
|
||||
|
||||
//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;
|
||||
if(index > (signed int) (graphic.Size()-1))
|
||||
index = graphic.Size()-1;
|
||||
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]));
|
||||
sprite[3+strlen(graphic[index])] = '\0';
|
||||
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];
|
||||
}
|
||||
for (i = 0;i < numskins;i++)
|
||||
{
|
||||
AddFaceToImageCollection (&skins[i], &Images);
|
||||
}
|
||||
invBarOffset = SBarInfoScript->Images.Size();
|
||||
Images.Init(&patchnames[0], patchnames.Size());
|
||||
drawingFont = V_GetFont("ConFont");
|
||||
|
@ -313,6 +317,15 @@ void DSBarInfo::Draw (EHudState state)
|
|||
else if(state == HUD_Fullscreen)
|
||||
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 ()
|
||||
|
@ -409,6 +422,15 @@ void DSBarInfo::FlashItem(const PClass *itemtype)
|
|||
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
|
||||
//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.
|
||||
|
@ -543,25 +565,27 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
}
|
||||
break;
|
||||
case SBARINFO_DRAWNUMBER:
|
||||
{
|
||||
int value = cmd.value;
|
||||
if(drawingFont != cmd.font)
|
||||
{
|
||||
drawingFont = cmd.font;
|
||||
}
|
||||
if(cmd.flags == DRAWNUMBER_HEALTH)
|
||||
{
|
||||
cmd.value = health;
|
||||
if(cmd.value < 0) //health shouldn't display negatives
|
||||
value = health;
|
||||
if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives
|
||||
{
|
||||
cmd.value = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
else if(cmd.flags == DRAWNUMBER_ARMOR)
|
||||
{
|
||||
cmd.value = armorAmount;
|
||||
value = armorAmount;
|
||||
}
|
||||
else if(cmd.flags == DRAWNUMBER_AMMO1)
|
||||
{
|
||||
cmd.value = ammocount1;
|
||||
value = ammocount1;
|
||||
if(ammo1 == NULL) //no ammo, do not draw
|
||||
{
|
||||
continue;
|
||||
|
@ -569,7 +593,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
}
|
||||
else if(cmd.flags == DRAWNUMBER_AMMO2)
|
||||
{
|
||||
cmd.value = ammocount2;
|
||||
value = ammocount2;
|
||||
if(ammo2 == NULL) //no ammo, do not draw
|
||||
{
|
||||
continue;
|
||||
|
@ -581,11 +605,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
||||
if(item != NULL)
|
||||
{
|
||||
cmd.value = item->Amount;
|
||||
value = item->Amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.value = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY)
|
||||
|
@ -594,61 +618,64 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
AInventory* item = CPlayer->mo->FindInventory(ammo);
|
||||
if(item != NULL)
|
||||
{
|
||||
cmd.value = item->MaxAmount;
|
||||
value = item->MaxAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
|
||||
value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
|
||||
}
|
||||
}
|
||||
else if(cmd.flags == DRAWNUMBER_FRAGS)
|
||||
cmd.value = CPlayer->fragcount;
|
||||
value = CPlayer->fragcount;
|
||||
else if(cmd.flags == DRAWNUMBER_KILLS)
|
||||
cmd.value = level.killed_monsters;
|
||||
value = level.killed_monsters;
|
||||
else if(cmd.flags == DRAWNUMBER_MONSTERS)
|
||||
cmd.value = level.total_monsters;
|
||||
value = level.total_monsters;
|
||||
else if(cmd.flags == DRAWNUMBER_ITEMS)
|
||||
cmd.value = level.found_items;
|
||||
value = level.found_items;
|
||||
else if(cmd.flags == DRAWNUMBER_TOTALITEMS)
|
||||
cmd.value = level.total_items;
|
||||
value = level.total_items;
|
||||
else if(cmd.flags == DRAWNUMBER_SECRETS)
|
||||
cmd.value = level.found_secrets;
|
||||
value = level.found_secrets;
|
||||
else if(cmd.flags == DRAWNUMBER_TOTALSECRETS)
|
||||
cmd.value = level.total_secrets;
|
||||
value = level.total_secrets;
|
||||
else if(cmd.flags == DRAWNUMBER_ARMORCLASS)
|
||||
{
|
||||
AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
|
||||
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];
|
||||
}
|
||||
//Hexen counts basic armor also so we should too.
|
||||
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)
|
||||
{
|
||||
AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
|
||||
if(item != NULL)
|
||||
{
|
||||
cmd.value = item->Amount;
|
||||
value = item->Amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.value = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
case SBARINFO_DRAWMUGSHOT:
|
||||
{
|
||||
bool xdth = false;
|
||||
|
@ -657,7 +684,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
xdth = true;
|
||||
if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE)
|
||||
animatedgodmode = true;
|
||||
DrawFace(cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
|
||||
DrawFace(cmd.string[0], cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
|
||||
break;
|
||||
}
|
||||
case SBARINFO_DRAWSELECTEDINVENTORY:
|
||||
|
@ -1000,7 +1027,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
{
|
||||
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;
|
||||
case SBARINFO_DRAWKEYBAR:
|
||||
{
|
||||
|
@ -1046,6 +1073,12 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SBARINFO_ASPECTRATIO:
|
||||
if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value)
|
||||
{
|
||||
doCommands(cmd.subBlock);
|
||||
}
|
||||
break;
|
||||
case SBARINFO_WEAPONAMMO:
|
||||
if(CPlayer->ReadyWeapon != NULL)
|
||||
{
|
||||
|
@ -1090,6 +1123,30 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
|
|||
}
|
||||
}
|
||||
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;
|
||||
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))
|
||||
DrawImage(texture, x, y, getTranslation());
|
||||
{
|
||||
screen->DrawTexture(texture, x, y,
|
||||
DTA_DestWidth, w,
|
||||
DTA_DestHeight, h,
|
||||
DTA_Translation, getTranslation(),
|
||||
TAG_DONE);
|
||||
}
|
||||
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,
|
||||
DTA_DestWidth, w,
|
||||
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
|
||||
x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size
|
||||
DrawImage(character, x, y, drawingFont->GetColorTranslation(translation));
|
||||
x += width + spacing;
|
||||
int rx = x + ST_X;
|
||||
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')
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
@ -1165,14 +1238,23 @@ void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translati
|
|||
}
|
||||
|
||||
//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 level = 0;
|
||||
for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++);
|
||||
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",
|
||||
"completeborder",
|
||||
"monospacefonts",
|
||||
"lowerhealthcap",
|
||||
"statusbar",
|
||||
"mugshot",
|
||||
NULL
|
||||
|
@ -91,7 +92,9 @@ static const char *SBarInfoRoutineLevel[] =
|
|||
"drawkeybar",
|
||||
"gamemode",
|
||||
"playerclass",
|
||||
"aspectratio",
|
||||
"weaponammo", //event
|
||||
"ininventory",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -230,6 +233,18 @@ void SBarInfo::ParseSBarInfo(int lump)
|
|||
}
|
||||
sc.MustGetToken(';');
|
||||
break;
|
||||
case SBARINFO_LOWERHEALTHCAP:
|
||||
if(sc.CheckToken(TK_False))
|
||||
{
|
||||
lowerHealthCap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.MustGetToken(TK_True);
|
||||
lowerHealthCap = true;
|
||||
}
|
||||
sc.MustGetToken(';');
|
||||
break;
|
||||
case SBARINFO_STATUSBAR:
|
||||
{
|
||||
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;
|
||||
else if(sc.Compare("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
|
||||
{
|
||||
cmd.flags = DRAWNUMBER_INVENTORY;
|
||||
|
@ -738,7 +761,7 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
|||
cmd.flags = DRAWNUMBER_INVENTORY;
|
||||
cmd.setString(sc, sc.String, 0);
|
||||
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);
|
||||
}
|
||||
|
@ -843,6 +866,11 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
|||
cmd.setString(sc, sc.String, 0, -1, false);
|
||||
sc.MustGetToken(',');
|
||||
this->getCoordinates(sc, cmd);
|
||||
if(sc.CheckToken(',')) //spacing
|
||||
{
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
cmd.special = sc.Number;
|
||||
}
|
||||
sc.MustGetToken(';');
|
||||
break;
|
||||
case SBARINFO_DRAWKEYBAR:
|
||||
|
@ -908,6 +936,21 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
|||
FinishPlayerClass:
|
||||
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||
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:
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
if(sc.Compare("not"))
|
||||
|
@ -939,6 +982,39 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
|
|||
sc.MustGetToken('{');
|
||||
this->ParseSBarInfoBlock(sc, cmd.subBlock);
|
||||
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);
|
||||
}
|
||||
|
@ -1044,6 +1120,7 @@ void SBarInfo::Init()
|
|||
interpolateHealth = false;
|
||||
interpolateArmor = false;
|
||||
completeBorder = false;
|
||||
lowerHealthCap = true;
|
||||
interpolationSpeed = 8;
|
||||
armorInterpolationSpeed = 8;
|
||||
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 ()
|
||||
{
|
||||
|
@ -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
|
||||
|
|
|
@ -81,6 +81,13 @@ public:
|
|||
bool TryPickup (AActor *toucher);
|
||||
};
|
||||
|
||||
class ASlideshowStarter : public ADummyStrifeItem
|
||||
{
|
||||
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
||||
public:
|
||||
bool TryPickup (AActor *toucher);
|
||||
};
|
||||
|
||||
class AStrifeWeapon : public AWeapon
|
||||
{
|
||||
DECLARE_STATELESS_ACTOR (AStrifeWeapon, AWeapon)
|
||||
|
|
|
@ -514,13 +514,6 @@ bool AUpgradeAccuracy::TryPickup (AActor *toucher)
|
|||
|
||||
// Start a slideshow --------------------------------------------------------
|
||||
|
||||
class ASlideshowStarter : public ADummyStrifeItem
|
||||
{
|
||||
DECLARE_STATELESS_ACTOR (ASlideshowStarter, ADummyStrifeItem)
|
||||
public:
|
||||
bool TryPickup (AActor *toucher);
|
||||
};
|
||||
|
||||
IMPLEMENT_STATELESS_ACTOR (ASlideshowStarter, Strife, -1, 0)
|
||||
PROP_StrifeType (343)
|
||||
END_DEFAULTS
|
||||
|
|
|
@ -692,7 +692,7 @@ CCMD(listlights)
|
|||
ADynamicLight * dl;
|
||||
TThinkerIterator<ADynamicLight> it;
|
||||
|
||||
while (dl=it.Next())
|
||||
while ((dl=it.Next()))
|
||||
{
|
||||
walls=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
|
||||
void M_InitVideoModesMenu (void);
|
||||
|
||||
struct menu_s;
|
||||
void M_SwitchMenu (struct menu_s *menu);
|
||||
void M_SwitchMenu (struct menu_t *menu);
|
||||
|
||||
void M_PopMenuStack (void);
|
||||
|
||||
|
@ -100,6 +99,7 @@ typedef enum {
|
|||
discrete,
|
||||
discretes,
|
||||
cdiscrete,
|
||||
ediscrete,
|
||||
discrete_guid,
|
||||
control,
|
||||
screenres,
|
||||
|
@ -145,8 +145,9 @@ typedef struct menuitem_s {
|
|||
char *res3;
|
||||
} d;
|
||||
union {
|
||||
struct value_s *values;
|
||||
struct value_t *values;
|
||||
struct valuestring_t *valuestrings;
|
||||
struct valueenum_t *enumvalues;
|
||||
GUIDName *guidvalues;
|
||||
char *command;
|
||||
void (*cfunc)(FBaseCVar *cvar, float newval);
|
||||
|
@ -157,7 +158,7 @@ typedef struct menuitem_s {
|
|||
} e;
|
||||
} menuitem_t;
|
||||
|
||||
typedef struct menu_s {
|
||||
struct menu_t {
|
||||
const char *texttitle;
|
||||
int lastOn;
|
||||
int numitems;
|
||||
|
@ -169,18 +170,23 @@ typedef struct menu_s {
|
|||
void (*PreDraw)(void);
|
||||
bool DontDim;
|
||||
void (*EscapeHandler)(void);
|
||||
} menu_t;
|
||||
};
|
||||
|
||||
typedef struct value_s {
|
||||
struct value_t {
|
||||
float value;
|
||||
const char *name;
|
||||
} value_t;
|
||||
};
|
||||
|
||||
struct valuestring_t {
|
||||
float value;
|
||||
FString name;
|
||||
};
|
||||
|
||||
struct valueenum_t {
|
||||
const char *value; // Value of cvar
|
||||
const char *name; // Name on menu
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// -1 = no cursor here, 1 = ok, 2 = arrows ok
|
||||
|
|
|
@ -1144,62 +1144,131 @@ EXTERN_CVAR (Float, snd_movievolume)
|
|||
#endif
|
||||
EXTERN_CVAR (Bool, snd_flipstereo)
|
||||
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 AdvSoundOptions ();
|
||||
static void ChooseMIDI ();
|
||||
|
||||
static value_t SampleRates[] =
|
||||
{
|
||||
{ 4000.f, "4000 Hz" },
|
||||
{ 8000.f, "8000 Hz" },
|
||||
{ 11025.f, "11025 Hz" },
|
||||
{ 22050.f, "22050 Hz" },
|
||||
{ 32000.f, "32000 Hz" },
|
||||
{ 44100.f, "44100 Hz" },
|
||||
{ 48000.f, "48000 Hz" },
|
||||
{ 96000.f, "96000 Hz" }
|
||||
{ 0.f, "Default" },
|
||||
{ 4000.f, "4000 Hz" },
|
||||
{ 8000.f, "8000 Hz" },
|
||||
{ 11025.f, "11025 Hz" },
|
||||
{ 22050.f, "22050 Hz" },
|
||||
{ 32000.f, "32000 Hz" },
|
||||
{ 44100.f, "44100 Hz" },
|
||||
{ 48000.f, "48000 Hz" }
|
||||
};
|
||||
|
||||
static value_t BufferSizes[] =
|
||||
{
|
||||
{ 0.f, "Default" },
|
||||
{ 20.f, "20 ms" },
|
||||
{ 40.f, "40 ms" },
|
||||
{ 60.f, "60 ms" },
|
||||
{ 80.f, "80 ms" },
|
||||
{ 100.f, "100 ms" },
|
||||
{ 120.f, "120 ms" },
|
||||
{ 140.f, "140 ms" },
|
||||
{ 160.f, "160 ms" },
|
||||
{ 180.f, "180 ms" },
|
||||
{ 200.f, "200 ms" },
|
||||
{ 0.f, "Default" },
|
||||
{ 64.f, "64 samples" },
|
||||
{ 128.f, "128 samples" },
|
||||
{ 256.f, "256 samples" },
|
||||
{ 512.f, "512 samples" },
|
||||
{ 1024.f, "1024 samples" },
|
||||
{ 2048.f, "2048 samples" },
|
||||
{ 4096.f, "4096 samples" }
|
||||
};
|
||||
|
||||
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[] =
|
||||
{
|
||||
{ slider, "Sound effects volume", {&snd_sfxvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
||||
#ifdef _WIN32
|
||||
{ slider, "Sounds volume", {&snd_sfxvolume}, {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} },
|
||||
#else
|
||||
{ slider, "Music volume", {&snd_musicvolume}, {0.0}, {1.0}, {0.05}, {NULL} },
|
||||
#endif
|
||||
{ discrete, "MIDI device", {&snd_mididevice}, {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, "Flip Stereo Channels", {&snd_flipstereo}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ discrete, "Random Pitch Variations", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ discrete, "Underwater reverb", {&snd_waterreverb}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ discrete, "Randomize pitches", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ 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} },
|
||||
{ discrete, "Sample Rate", {&snd_samplerate}, {8.0}, {0.0}, {0.0}, {SampleRates} },
|
||||
{ discrete, "Buffer Size", {&snd_buffersize}, {11.0}, {0.0}, {0.0}, {BufferSizes} },
|
||||
{ ediscrete,"Output system", {&snd_output}, {countof(Outputs)}, {0.0}, {0.0}, {(value_t *)Outputs} },
|
||||
{ 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} },
|
||||
{ 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
|
||||
{ more, "Advanced options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)AdvSoundOptions} },
|
||||
};
|
||||
|
||||
static menu_t SoundMenu =
|
||||
|
@ -1211,29 +1280,7 @@ static menu_t SoundMenu =
|
|||
SoundItems,
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
/*=======================================
|
||||
*
|
||||
* 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
|
||||
#define MIDI_DEVICE_ITEM 2
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
|
@ -1521,6 +1568,42 @@ int M_FindCurGUID (const GUID &guid, GUIDName *values, int numvals)
|
|||
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 ()
|
||||
{
|
||||
EColorRange color;
|
||||
|
@ -1707,6 +1790,16 @@ void M_OptDrawer ()
|
|||
}
|
||||
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:
|
||||
{
|
||||
int v, vals;
|
||||
|
@ -2186,6 +2279,13 @@ void M_OptResponder (event_t *ev)
|
|||
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||
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:
|
||||
{
|
||||
int cur;
|
||||
|
@ -2328,6 +2428,13 @@ void M_OptResponder (event_t *ev)
|
|||
S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE);
|
||||
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:
|
||||
{
|
||||
int cur;
|
||||
|
@ -2893,9 +3000,19 @@ CCMD (menu_joystick)
|
|||
JoystickOptions ();
|
||||
}
|
||||
|
||||
static void FreeMIDIMenuList()
|
||||
{
|
||||
if (SoundItems[MIDI_DEVICE_ITEM].e.values != NULL)
|
||||
{
|
||||
delete[] SoundItems[MIDI_DEVICE_ITEM].e.values;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -2917,22 +3034,6 @@ CCMD (menu_advsound)
|
|||
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 char snd_reset[] = "snd_reset";
|
||||
|
|
|
@ -93,7 +93,7 @@ static size_t ReadVarLen (const BYTE *buf, int *time_out)
|
|||
return ofs;
|
||||
}
|
||||
|
||||
static size_t WriteVarLen (FILE *file, int time)
|
||||
static size_t WriteVarLen (TArray<BYTE> &file, int time)
|
||||
{
|
||||
long buffer;
|
||||
size_t ofs;
|
||||
|
@ -105,7 +105,7 @@ static size_t WriteVarLen (FILE *file, int time)
|
|||
}
|
||||
for (ofs = 0;;)
|
||||
{
|
||||
fputc (buffer & 0xff, file);
|
||||
file.Push(BYTE(buffer & 0xff));
|
||||
if (buffer & 0x80)
|
||||
buffer >>= 8;
|
||||
else
|
||||
|
@ -114,7 +114,7 @@ static size_t WriteVarLen (FILE *file, int time)
|
|||
return ofs;
|
||||
}
|
||||
|
||||
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
||||
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile)
|
||||
{
|
||||
BYTE midStatus, midArgs, mid1, mid2;
|
||||
size_t mus_p, maxmus_p;
|
||||
|
@ -125,7 +125,6 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
|||
BYTE lastVel[16];
|
||||
SBYTE chanMap[16];
|
||||
int chanCount;
|
||||
int dupCount = 0;
|
||||
long trackLen;
|
||||
|
||||
// Do some validation of the MUS file
|
||||
|
@ -136,7 +135,9 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
|||
return false;
|
||||
|
||||
// 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);
|
||||
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,
|
||||
// so sets its volume to 127.
|
||||
fputc (0, outFile);
|
||||
fputc (0xB0 | chanCount, outFile);
|
||||
fputc (7, outFile);
|
||||
fputc (127, outFile);
|
||||
outFile.Push(0);
|
||||
outFile.Push(0xB0 | chanCount);
|
||||
outFile.Push(7);
|
||||
outFile.Push(127);
|
||||
chanMap[channel] = chanCount++;
|
||||
if (chanCount == 9)
|
||||
++chanCount;
|
||||
|
@ -237,20 +238,15 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
|||
|
||||
WriteVarLen (outFile, deltaTime);
|
||||
|
||||
if (midStatus == status)
|
||||
{
|
||||
++dupCount;
|
||||
fputc (mid1, outFile);
|
||||
if (!midArgs)
|
||||
fputc (mid2, outFile);
|
||||
}
|
||||
else
|
||||
if (midStatus != status)
|
||||
{
|
||||
status = midStatus;
|
||||
fputc (status, outFile);
|
||||
fputc (mid1, outFile);
|
||||
if (!midArgs)
|
||||
fputc (mid2, outFile);
|
||||
outFile.Push(status);
|
||||
}
|
||||
outFile.Push(mid1);
|
||||
if (midArgs == 0)
|
||||
{
|
||||
outFile.Push(mid2);
|
||||
}
|
||||
if (event & 128)
|
||||
{
|
||||
|
@ -263,12 +259,20 @@ bool ProduceMIDI (const BYTE *musBuf, FILE *outFile)
|
|||
}
|
||||
|
||||
// fill in track length
|
||||
trackLen = ftell (outFile) - 22;
|
||||
fseek (outFile, 18, SEEK_SET);
|
||||
fputc ((trackLen >> 24) & 255, outFile);
|
||||
fputc ((trackLen >> 16) & 255, outFile);
|
||||
fputc ((trackLen >> 8) & 255, outFile);
|
||||
fputc (trackLen & 255, outFile);
|
||||
|
||||
trackLen = outFile.Size() - 22;
|
||||
outFile[18] = BYTE((trackLen >> 24) & 255);
|
||||
outFile[19] = BYTE((trackLen >> 16) & 255);
|
||||
outFile[20] = BYTE((trackLen >> 8) & 255);
|
||||
outFile[21] = BYTE(trackLen & 255);
|
||||
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;
|
||||
} MUSHeader;
|
||||
|
||||
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);
|
||||
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile);
|
||||
|
||||
#endif //__MUS2MIDI_H__
|
||||
|
|
|
@ -117,9 +117,8 @@ static void ConversationMenuEscaped ();
|
|||
|
||||
static FStrifeDialogueNode *CurNode, *PrevNode;
|
||||
static FBrokenLines *DialogueLines;
|
||||
static AActor *ConversationNPC, *ConversationPC;
|
||||
static angle_t ConversationNPCAngle;
|
||||
static bool ConversationFaceTalker;
|
||||
|
||||
static bool Conversation_TakeStuff;
|
||||
|
||||
#define NUM_RANDOM_LINES 10
|
||||
#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;
|
||||
|
||||
if (itemtype == NULL || amount == 0)
|
||||
return true;
|
||||
|
||||
item = ConversationPC->FindInventory (itemtype);
|
||||
item = player->ConversationPC->FindInventory (itemtype);
|
||||
if (item == NULL)
|
||||
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)
|
||||
return;
|
||||
|
@ -611,15 +610,10 @@ static void TakeStrifeItem (const PClass *itemtype, int amount)
|
|||
if (itemtype == RUNTIME_CLASS(ASigil))
|
||||
return;
|
||||
|
||||
AInventory *item = ConversationPC->FindInventory (itemtype);
|
||||
if (item != NULL)
|
||||
{
|
||||
item->Amount -= amount;
|
||||
if (item->Amount <= 0)
|
||||
{
|
||||
item->Destroy ();
|
||||
}
|
||||
}
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
Net_WriteByte (CONV_TAKEINVENTORY);
|
||||
Net_WriteString (itemtype->TypeName.GetChars ());
|
||||
Net_WriteWord (amount);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
||||
|
@ -633,7 +627,6 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
|
|||
// P_StartConversation
|
||||
//
|
||||
// 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;
|
||||
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->player->momx = pc->player->momy = 0;
|
||||
|
||||
if (pc->player - players != consoleplayer)
|
||||
return;
|
||||
|
||||
ConversationPC = pc;
|
||||
ConversationNPC = npc;
|
||||
pc->player->ConversationPC = pc;
|
||||
pc->player->ConversationNPC = npc;
|
||||
|
||||
CurNode = npc->Conversation;
|
||||
|
||||
|
@ -662,10 +663,10 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
}
|
||||
|
||||
npc->reactiontime = 2;
|
||||
ConversationFaceTalker = facetalker;
|
||||
pc->player->ConversationFaceTalker = facetalker;
|
||||
if (saveangle)
|
||||
{
|
||||
ConversationNPCAngle = npc->angle;
|
||||
pc->player->ConversationNPCAngle = npc->angle;
|
||||
}
|
||||
oldtarget = npc->target;
|
||||
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
|
||||
while (CurNode->ItemCheck[0] != NULL)
|
||||
{
|
||||
if (CheckStrifeItem (CurNode->ItemCheck[0]) &&
|
||||
CheckStrifeItem (CurNode->ItemCheck[1]) &&
|
||||
CheckStrifeItem (CurNode->ItemCheck[2]))
|
||||
if (CheckStrifeItem (pc->player, CurNode->ItemCheck[0]) &&
|
||||
CheckStrifeItem (pc->player, CurNode->ItemCheck[1]) &&
|
||||
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];
|
||||
}
|
||||
else
|
||||
|
@ -697,10 +698,13 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
|
||||
if (CurNode->SpeakerVoice != 0)
|
||||
{
|
||||
I_SetMusicVolume(dlg_musicvolume);
|
||||
I_SetMusicVolume (dlg_musicvolume);
|
||||
S_SoundID (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
||||
}
|
||||
|
||||
if (pc->player != &players[consoleplayer])
|
||||
return;
|
||||
|
||||
// Set up the menu
|
||||
ConversationMenu.PreDraw = DrawConversationMenu;
|
||||
ConversationMenu.EscapeHandler = ConversationMenuEscaped;
|
||||
|
@ -786,9 +790,17 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
|
||||
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;
|
||||
int i, x, y, linesize;
|
||||
|
||||
player_t *cp = &players[consoleplayer];
|
||||
|
||||
assert (DialogueLines != NULL);
|
||||
assert (CurNode != NULL);
|
||||
|
||||
|
@ -812,7 +826,8 @@ static void DrawConversationMenu ()
|
|||
return;
|
||||
}
|
||||
|
||||
if (ConversationPauseTic < gametic)
|
||||
// [CW] Pausing the game in a multiplayer game is a bad idea.
|
||||
if (ConversationPauseTic < gametic && !multiplayer)
|
||||
{
|
||||
menuactive = MENU_On;
|
||||
}
|
||||
|
@ -832,7 +847,7 @@ static void DrawConversationMenu ()
|
|||
}
|
||||
else
|
||||
{
|
||||
speakerName = ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
||||
speakerName = cp->ConversationNPC->GetClass()->Meta.GetMetaString (AMETA_StrifeName);
|
||||
if (speakerName == NULL)
|
||||
{
|
||||
speakerName = "Person";
|
||||
|
@ -873,7 +888,7 @@ static void DrawConversationMenu ()
|
|||
|
||||
if (ShowGold)
|
||||
{
|
||||
AInventory *coin = ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
||||
AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin));
|
||||
char goldstr[32];
|
||||
|
||||
sprintf (goldstr, "%d", coin != NULL ? coin->Amount : 0);
|
||||
|
@ -892,94 +907,89 @@ static void DrawConversationMenu ()
|
|||
//
|
||||
// PickConversationReply
|
||||
//
|
||||
// FIXME: Make this work in multiplayer
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
static void PickConversationReply ()
|
||||
{
|
||||
const char *replyText = NULL;
|
||||
FStrifeDialogueReply *reply = (FStrifeDialogueReply *)ConversationItems[ConversationMenu.lastOn].c.extra;
|
||||
bool takestuff;
|
||||
int i;
|
||||
player_t *cp = &players[consoleplayer];
|
||||
|
||||
Conversation_TakeStuff = false;
|
||||
|
||||
M_ClearMenus ();
|
||||
CleanupConversationMenu ();
|
||||
if (reply == NULL)
|
||||
{
|
||||
ConversationNPC->angle = ConversationNPCAngle;
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
Net_WriteByte (CONV_NPCANGLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if you have the requisite items for this choice
|
||||
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.
|
||||
if (reply->QuickNo)
|
||||
{
|
||||
Printf ("%s\n", reply->QuickNo);
|
||||
}
|
||||
ConversationNPC->ConversationAnimation (2);
|
||||
ConversationNPC->angle = ConversationNPCAngle;
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
Net_WriteByte (CONV_ANIMATE);
|
||||
Net_WriteByte (2);
|
||||
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
Net_WriteByte (CONV_NPCANGLE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
takestuff = true;
|
||||
Conversation_TakeStuff = true;
|
||||
if (reply->GiveType != NULL)
|
||||
{
|
||||
if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
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));
|
||||
// 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[consoleplayer].mo))
|
||||
{
|
||||
item->Destroy ();
|
||||
takestuff = false;
|
||||
}
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
Net_WriteByte (CONV_GIVEINVENTORY);
|
||||
Net_WriteString (reply->GiveType->TypeName.GetChars ());
|
||||
}
|
||||
|
||||
if (reply->GiveType->IsDescendantOf (RUNTIME_CLASS (ASlideshowStarter)))
|
||||
gameaction = ga_slideshow;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
// Take away required items if the give was successful or none was needed.
|
||||
if (takestuff)
|
||||
if (Conversation_TakeStuff)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -989,9 +999,9 @@ static void PickConversationReply ()
|
|||
}
|
||||
|
||||
// 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)
|
||||
|
@ -1000,32 +1010,43 @@ static void PickConversationReply ()
|
|||
}
|
||||
|
||||
// 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.
|
||||
if (reply->NextNode != 0)
|
||||
{
|
||||
int rootnode = FindNode (ConversationNPC->GetDefault()->Conversation);
|
||||
int rootnode = FindNode (cp->ConversationNPC->GetDefault()->Conversation);
|
||||
if (reply->NextNode < 0)
|
||||
{
|
||||
ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
||||
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
|
||||
if (gameaction != ga_slideshow)
|
||||
{
|
||||
P_StartConversation (ConversationNPC, players[consoleplayer].mo, ConversationFaceTalker, false);
|
||||
P_StartConversation (cp->ConversationNPC, cp->mo, cp->ConversationFaceTalker, false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
S_StopSound (ConversationNPC, CHAN_VOICE);
|
||||
S_StopSound (cp->ConversationNPC, CHAN_VOICE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
||||
cp->ConversationNPC->Conversation = StrifeDialogues[rootnode + reply->NextNode - 1];
|
||||
}
|
||||
}
|
||||
|
||||
ConversationNPC->angle = ConversationNPCAngle;
|
||||
I_SetMusicVolume(1.f);
|
||||
Net_WriteByte (DEM_CONVERSATION);
|
||||
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;
|
||||
}
|
||||
ConversationItems.Clear ();
|
||||
I_SetMusicVolume(1.f);
|
||||
I_SetMusicVolume (1.f);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// 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 ()
|
||||
{
|
||||
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
|
||||
// the ability to call ACS functions to implement AppearsWhen properties
|
||||
// and ACS scripts to implement ActionTaken properties.
|
||||
// TODO: Make this work in multiplayer and in demos. Multiplayer probably
|
||||
// isn't possible for Strife conversations, but demo playback should be.
|
||||
// TODO: Make this work in demos.
|
||||
|
||||
struct FStrifeDialogueReply;
|
||||
class FTexture;
|
||||
|
@ -48,6 +47,16 @@ struct FStrifeDialogueReply
|
|||
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;
|
||||
|
||||
// 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_ResumeConversation ();
|
||||
|
||||
void P_ConversationCommand (int player, BYTE **stream);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -370,7 +370,8 @@ FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad)
|
|||
thisframe.Time = ((max - min + 1) << 16) | min;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
thisframe.Time = 0; // Shush, GCC.
|
||||
sc.ScriptError ("Must specify a duration for switch frame");
|
||||
}
|
||||
frames.Push(thisframe);
|
||||
|
|
|
@ -287,7 +287,11 @@ player_s::player_s()
|
|||
crouchdir(0),
|
||||
crouchfactor(0),
|
||||
crouchoffset(0),
|
||||
crouchviewdelta(0)
|
||||
crouchviewdelta(0),
|
||||
ConversationNPC(0),
|
||||
ConversationPC(0),
|
||||
ConversationNPCAngle(0),
|
||||
ConversationFaceTalker(0)
|
||||
{
|
||||
memset (&cmd, 0, sizeof(cmd));
|
||||
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 (ReadyWeapon == old) ReadyWeapon = 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;
|
||||
}
|
||||
|
||||
|
@ -337,6 +343,8 @@ size_t player_s::PropagateMark()
|
|||
GC::Mark(mate);
|
||||
GC::Mark(last_mate);
|
||||
GC::Mark(ReadyWeapon);
|
||||
GC::Mark(ConversationNPC);
|
||||
GC::Mark(ConversationPC);
|
||||
if (PendingWeapon != WP_NOCHANGE)
|
||||
{
|
||||
GC::Mark(PendingWeapon);
|
||||
|
@ -2426,7 +2434,11 @@ void player_s::Serialize (FArchive &arc)
|
|||
<< BlendB
|
||||
<< BlendA
|
||||
<< accuracy << stamina
|
||||
<< LogText;
|
||||
<< LogText
|
||||
<< ConversationNPC
|
||||
<< ConversationPC
|
||||
<< ConversationNPCAngle
|
||||
<< ConversationFaceTalker;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; 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;
|
||||
else special = SectorTranslations[special].newtype;
|
||||
|
|
|
@ -193,8 +193,8 @@ void R_InitPicAnims (void)
|
|||
if (debuganimated)
|
||||
{
|
||||
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()),
|
||||
tex2->Name, tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump()));
|
||||
tex1->Name, pic1, tex1->GetSourceLump(), Wads.GetLumpFile(tex1->GetSourceLump()),
|
||||
tex2->Name, pic2, tex2->GetSourceLump(), Wads.GetLumpFile(tex2->GetSourceLump()));
|
||||
}
|
||||
|
||||
/* FIXME: doesn't work with hires texture replacements.
|
||||
|
|
|
@ -61,4 +61,5 @@ void restoreinterpolations();
|
|||
void clearinterpolations();
|
||||
void SerializeInterpolations(FArchive &arc);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1261,10 +1261,11 @@ static void S_AddSNDINFO (int lump)
|
|||
sc.MustGetString();
|
||||
FName nm = sc.String;
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("timidity")) MidiDevices[nm] = 1;
|
||||
else if (sc.Compare("standard")) MidiDevices[nm] = 0;
|
||||
else if (sc.Compare("opl")) MidiDevices[nm] = 2;
|
||||
else if (sc.Compare("default")) MidiDevices[nm] = -1;
|
||||
if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY;
|
||||
else if (sc.Compare("fmod")) MidiDevices[nm] = MDEV_FMOD;
|
||||
else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI;
|
||||
else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL;
|
||||
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT;
|
||||
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -502,7 +502,7 @@ void S_ParseSndSeq (int levellump)
|
|||
FScanner sc(lump, "SNDSEQ");
|
||||
while (sc.GetString ())
|
||||
{
|
||||
bool bDoorSound;
|
||||
bool bDoorSound = false;
|
||||
|
||||
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 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 (!FileExists (musicname))
|
||||
|
|
|
@ -311,6 +311,15 @@ ReverbContainer *S_FindEnvironment (const char *name);
|
|||
ReverbContainer *S_FindEnvironment (int id);
|
||||
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;
|
||||
|
||||
extern MidiDeviceMap MidiDevices;
|
||||
|
|
|
@ -152,7 +152,7 @@ void I_InitGraphics ()
|
|||
}
|
||||
gl_disabled = gl_nogl;
|
||||
#endif
|
||||
val.Bool = !!Args.CheckParm ("-devparm");
|
||||
val.Bool = !!Args->CheckParm ("-devparm");
|
||||
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
||||
|
||||
#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 ()
|
||||
{
|
||||
I_FatalError ("Failed to allocate memory from system heap");
|
||||
|
@ -209,6 +223,7 @@ int main (int argc, char **argv)
|
|||
try
|
||||
{
|
||||
Args = new DArgs(argc, argv);
|
||||
atterm(FinalGC);
|
||||
|
||||
/*
|
||||
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 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 ----------------------------------------------
|
||||
|
||||
EXTERN_CVAR (String, snd_output)
|
||||
|
@ -106,15 +111,19 @@ EXTERN_CVAR (Int, snd_channels)
|
|||
ReverbContainer *ForcedEnvironment;
|
||||
|
||||
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 (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, snd_dspnet, false, 0)
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static const ReverbContainer *PrevEnvironment;
|
||||
static bool ShowedBanner;
|
||||
|
||||
// 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
|
||||
|
@ -164,8 +173,6 @@ static const FEnumList SpeakerModeNames[] =
|
|||
{ "1", FMOD_SPEAKERMODE_MONO },
|
||||
{ "2", FMOD_SPEAKERMODE_STEREO },
|
||||
{ "4", FMOD_SPEAKERMODE_QUAD },
|
||||
{ "Headphones", 9001 },
|
||||
{ "HRTF", 9001 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
@ -195,6 +202,16 @@ static const FEnumList SoundFormatNames[] =
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static const char *OpenStateNames[] =
|
||||
{
|
||||
"Ready",
|
||||
"Loading",
|
||||
"Error",
|
||||
"Connecting",
|
||||
"Buffering",
|
||||
"Seeking"
|
||||
};
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
|
@ -374,6 +391,26 @@ public:
|
|||
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)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
@ -445,6 +482,8 @@ bool FMODSoundRenderer::Init()
|
|||
FMOD_SOUND_FORMAT format;
|
||||
FMOD_DSP_RESAMPLER resampler;
|
||||
FMOD_INITFLAGS initflags;
|
||||
int samplerate;
|
||||
int driver;
|
||||
|
||||
int eval;
|
||||
|
||||
|
@ -454,7 +493,12 @@ bool FMODSoundRenderer::Init()
|
|||
PausableSfx = NULL;
|
||||
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.
|
||||
result = FMOD::System_Create(&Sys);
|
||||
|
@ -472,30 +516,6 @@ bool FMODSoundRenderer::Init()
|
|||
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
|
||||
if (OSPlatform == os_WinNT4)
|
||||
{
|
||||
|
@ -541,18 +561,74 @@ bool FMODSoundRenderer::Init()
|
|||
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)
|
||||
{ // The user has the 'Acceleration' slider set to off!
|
||||
// This is really bad for latency!
|
||||
Printf ("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"Warning: The sound acceleration slider has been set to off.\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.
|
||||
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
|
||||
initflags = FMOD_INIT_NORMAL;
|
||||
if (speakermode > 9000)
|
||||
if (snd_hrtf)
|
||||
{
|
||||
initflags |= FMOD_INIT_SOFTWARE_HRTF;
|
||||
}
|
||||
|
@ -560,17 +636,38 @@ bool FMODSoundRenderer::Init()
|
|||
{
|
||||
initflags |= FMOD_INIT_ENABLE_DSPNET;
|
||||
}
|
||||
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
||||
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);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
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)
|
||||
{ // Initializing FMOD failed. Cry cry.
|
||||
Printf (" System::init returned error code %d\n", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -656,6 +753,8 @@ void FMODSoundRenderer::PrintStatus()
|
|||
int samplerate;
|
||||
int numoutputchannels;
|
||||
int num2d, num3d, total;
|
||||
unsigned int bufferlength;
|
||||
int numbuffers;
|
||||
|
||||
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 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);
|
||||
|
||||
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;
|
||||
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_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
|
||||
FMOD::Sound *stream;
|
||||
FMOD_RESULT result;
|
||||
|
||||
mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM;
|
||||
if (flags & SoundStream::Loop)
|
||||
|
@ -905,8 +1009,25 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
|
|||
}
|
||||
exinfo.length = length;
|
||||
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);
|
||||
}
|
||||
|
@ -1080,6 +1201,10 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
|
|||
if (chan->get3DPanLevel(&old_level) == FMOD_OK && old_level != level)
|
||||
{ // Only set it if it's different.
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -69,12 +69,12 @@ extern void ChildSigHandler (int signum);
|
|||
#include "i_cd.h"
|
||||
#include "tempfiles.h"
|
||||
#include "templates.h"
|
||||
#include "stats.h"
|
||||
|
||||
#include <fmod.h>
|
||||
|
||||
EXTERN_CVAR (Int, snd_samplerate)
|
||||
EXTERN_CVAR (Int, snd_mididevice)
|
||||
CVAR(Bool, snd_modplug, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
static bool MusicDown = true;
|
||||
|
||||
|
@ -83,6 +83,11 @@ int nomusic = 0;
|
|||
float relative_volume = 1.f;
|
||||
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
|
||||
|
@ -131,6 +136,11 @@ void MusInfo::TimidityVolumeChanged()
|
|||
{
|
||||
}
|
||||
|
||||
FString MusInfo::GetStats()
|
||||
{
|
||||
return "No stats available for this song";
|
||||
}
|
||||
|
||||
void I_InitMusic (void)
|
||||
{
|
||||
static bool setatterm = false;
|
||||
|
@ -187,6 +197,9 @@ void I_PlaySong (void *handle, int _looping, float rel_vol)
|
|||
currSong = info;
|
||||
else
|
||||
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;
|
||||
MusInfo *info = NULL;
|
||||
|
@ -238,7 +251,7 @@ void *I_RegisterSong (const char *filename, char * musiccache, int offset, int l
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (offset!=-1)
|
||||
if (offset != -1)
|
||||
{
|
||||
file = fopen (filename, "rb");
|
||||
if (file == NULL)
|
||||
|
@ -270,105 +283,177 @@ void *I_RegisterSong (const char *filename, char * musiccache, int offset, int l
|
|||
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
|
||||
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)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (device == 1 && GSnd != NULL)
|
||||
info = new MUSSong2 (file, musiccache, len);
|
||||
}
|
||||
#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);
|
||||
if (!info->IsValid())
|
||||
{
|
||||
delete info;
|
||||
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
|
||||
if (device == 1 && GSnd != NULL)
|
||||
{
|
||||
info = new TimiditySong (file, musiccache, len);
|
||||
if (!info->IsValid())
|
||||
if (info == NULL && device != MDEV_FMOD && (snd_mididevice >= 0 || device == MDEV_MMAPI))
|
||||
{
|
||||
delete info;
|
||||
info = NULL;
|
||||
info = new MIDISong2 (file, musiccache, len);
|
||||
}
|
||||
}
|
||||
if (info == NULL && (snd_mididevice != -2 || device == 0))
|
||||
{
|
||||
info = new MIDISong2 (file, musiccache, len);
|
||||
}
|
||||
else if (info == NULL && GSnd != NULL)
|
||||
#endif // _WIN32
|
||||
{
|
||||
info = new TimiditySong (file, musiccache, len);
|
||||
}
|
||||
}
|
||||
// Check for RDosPlay raw OPL format
|
||||
else if (id == MAKE_ID('R','A','W','A') && len >= 12)
|
||||
{
|
||||
DWORD fullsig[2];
|
||||
|
||||
if (file != NULL)
|
||||
// Check for RDosPlay raw OPL format
|
||||
else if (id == MAKE_ID('R','A','W','A') && len >= 12)
|
||||
{
|
||||
if (fread (fullsig, 4, 2, file) != 2)
|
||||
DWORD fullsig[2];
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
fclose (file);
|
||||
return 0;
|
||||
if (fread (fullsig, 4, 2, file) != 2)
|
||||
{
|
||||
fclose (file);
|
||||
return 0;
|
||||
}
|
||||
fseek (file, -8, SEEK_CUR);
|
||||
}
|
||||
fseek (file, -8, SEEK_CUR);
|
||||
}
|
||||
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)
|
||||
else
|
||||
{
|
||||
fclose (file);
|
||||
return 0;
|
||||
memcpy(fullsig, musiccache, 8);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (fullhead[4] == 'B' && fullhead[5] == 1)
|
||||
{
|
||||
info = new OPLMUSSong (file, musiccache, len);
|
||||
char fullhead[6];
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
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
|
||||
// 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.
|
||||
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)
|
||||
{
|
||||
info = ModPlugSong::Create(file, musiccache, len);
|
||||
info = ModPlugSong_Create(file, musiccache, len);
|
||||
}
|
||||
if (info == NULL)
|
||||
{
|
||||
|
@ -488,3 +574,18 @@ CCMD(testmusicvol)
|
|||
else
|
||||
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_ShutdownMusic ();
|
||||
void I_BuildMIDIMenuList (struct value_s **values, float *numValues);
|
||||
void I_BuildMIDIMenuList (struct value_t **values, float *numValues);
|
||||
void I_UpdateMusic ();
|
||||
|
||||
// Volume.
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "c_cvars.h"
|
||||
#include "mus2midi.h"
|
||||
#include "i_sound.h"
|
||||
#include "modplug/modplug.h"
|
||||
|
||||
void I_InitMusicWin32 ();
|
||||
void I_ShutdownMusicWin32 ();
|
||||
|
@ -45,6 +44,7 @@ public:
|
|||
virtual bool IsValid () const = 0;
|
||||
virtual bool SetPosition (int order);
|
||||
virtual void Update();
|
||||
virtual FString GetStats();
|
||||
|
||||
enum EState
|
||||
{
|
||||
|
@ -243,6 +243,7 @@ public:
|
|||
bool IsMIDI () const { return false; }
|
||||
bool IsValid () const { return m_Stream != NULL; }
|
||||
bool SetPosition (int order);
|
||||
FString GetStats();
|
||||
|
||||
protected:
|
||||
StreamSong () : m_Stream(NULL), m_LastPos(0) {}
|
||||
|
@ -289,25 +290,6 @@ protected:
|
|||
#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 -------
|
||||
|
||||
class OPLMUSSong : public StreamSong
|
||||
|
|
|
@ -68,12 +68,13 @@ extern HINSTANCE g_hInst;
|
|||
#include "w_wad.h"
|
||||
#include "i_video.h"
|
||||
#include "s_sound.h"
|
||||
#include "v_text.h"
|
||||
#include "gi.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
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 (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
|
@ -124,7 +125,7 @@ void I_InitSound ()
|
|||
{
|
||||
delete GSnd;
|
||||
GSnd = NULL;
|
||||
Printf ("Sound init failed. Using nosound.\n");
|
||||
Printf (TEXTCOLOR_RED"Sound init failed. Using nosound.\n");
|
||||
}
|
||||
I_InitMusic ();
|
||||
snd_sfxvolume.Callback ();
|
||||
|
@ -215,3 +216,8 @@ bool SoundStream::SetPosition(int pos)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString SoundStream::GetStats()
|
||||
{
|
||||
return "No stream stats available.";
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
virtual bool SetPaused (bool paused) = 0;
|
||||
virtual unsigned int GetPosition () = 0;
|
||||
virtual bool SetPosition (int pos);
|
||||
virtual FString GetStats();
|
||||
};
|
||||
|
||||
typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, void *userdata);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef _WIN32
|
||||
#include "i_musicinterns.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "i_music.h"
|
||||
#include "i_system.h"
|
||||
|
||||
#include "templates.h"
|
||||
#include "v_text.h"
|
||||
|
@ -9,6 +9,7 @@
|
|||
|
||||
static DWORD nummididevices;
|
||||
static bool nummididevicesset;
|
||||
#ifdef _WIN32
|
||||
UINT mididevice;
|
||||
|
||||
CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
|
@ -56,19 +57,22 @@ void I_InitMusicWin32 ()
|
|||
|
||||
void I_ShutdownMusicWin32 ()
|
||||
{
|
||||
// I don't know if this is an NT 4.0 bug or an FMOD bug, but if waveout
|
||||
// is used for sound, and a MIDI is also played, then when I quit, the OS
|
||||
// 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
|
||||
// tells me a free block was modified after being freed. This is
|
||||
// apparently a synchronization issue between two threads, because if I
|
||||
// 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
|
||||
// a driver problem, because it happens with both a Vortex 2 and an Audigy.
|
||||
// Though if their drivers are both based off some common Microsoft sample
|
||||
// code, I suppose it could be a driver issue.
|
||||
Sleep (50);
|
||||
// the entire sound system, the error does not happen. Observed with a
|
||||
// Vortex 2 (may Aureal rest in peace) and an Audigy (damn you, Creative!).
|
||||
// I no longer have a system with NT4 drivers, so I don't know if this
|
||||
// workaround is still needed or not.
|
||||
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)
|
||||
{
|
||||
|
@ -79,13 +83,13 @@ void I_BuildMIDIMenuList (struct value_s **outValues, float *numValues)
|
|||
|
||||
values[0].name = "TiMidity++";
|
||||
values[0].value = -2.0;
|
||||
values[1].name = "FMOD";
|
||||
values[1].value = -1.0;
|
||||
if (nummididevices > 0)
|
||||
{
|
||||
UINT id;
|
||||
int p;
|
||||
|
||||
values[1].name = "MIDI Mapper";
|
||||
values[1].value = -1.0;
|
||||
for (id = 0, p = 2; id < nummididevices; ++id)
|
||||
{
|
||||
MIDIOUTCAPS caps;
|
||||
|
@ -107,7 +111,7 @@ void I_BuildMIDIMenuList (struct value_s **outValues, float *numValues)
|
|||
}
|
||||
else
|
||||
{
|
||||
*numValues = 1.f;
|
||||
*numValues = 2.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,9 +161,9 @@ CCMD (snd_listmididevices)
|
|||
MMRESULT res;
|
||||
|
||||
PrintMidiDevice (-2, "TiMidity++", 0, 0);
|
||||
PrintMidiDevice (-1, "FMOD", 0, 0);
|
||||
if (nummididevices != 0)
|
||||
{
|
||||
PrintMidiDevice (-1, "MIDI Mapper", MOD_MAPPER, 0);
|
||||
for (id = 0; id < nummididevices; ++id)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -244,6 +244,7 @@ TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
|
|||
void TimiditySong::PrepTimidity ()
|
||||
{
|
||||
int pipeSize;
|
||||
|
||||
#ifdef _WIN32
|
||||
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, TRUE };
|
||||
|
||||
|
@ -267,6 +268,11 @@ void TimiditySong::PrepTimidity ()
|
|||
|
||||
pipeSize = (timidity_pipe * timidity_frequency / 1000)
|
||||
<< (timidity_stereo + !timidity_8bit);
|
||||
|
||||
if (GSnd == NULL)
|
||||
{ // Can't pipe if using no sound.
|
||||
pipeSize = 0;
|
||||
}
|
||||
|
||||
if (pipeSize != 0)
|
||||
{
|
||||
|
@ -520,11 +526,11 @@ bool TimiditySong::LaunchTimidity ()
|
|||
close (WavePipe[0]);
|
||||
dup2 (WavePipe[1], STDOUT_FILENO);
|
||||
freopen ("/dev/null", "r", stdin);
|
||||
freopen ("/dev/null", "w", stderr);
|
||||
// freopen ("/dev/null", "w", stderr);
|
||||
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
|
||||
}
|
||||
else if (forkres < 0)
|
||||
|
@ -536,7 +542,12 @@ bool TimiditySong::LaunchTimidity ()
|
|||
// printf ("child is %d\n", forkres);
|
||||
ChildProcess = forkres;
|
||||
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);
|
||||
|
@ -575,21 +586,36 @@ bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *u
|
|||
}
|
||||
}
|
||||
#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);
|
||||
if (got < len)
|
||||
{
|
||||
memset ((BYTE *)buff+got, 0, len-got);
|
||||
}
|
||||
|
||||
if (ChildQuit == song->ChildProcess)
|
||||
{
|
||||
ChildQuit = 0;
|
||||
// printf ("child gone\n");
|
||||
song->ChildProcess = -1;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,24 @@
|
|||
// 192 approximately replicates the volume of a WinAmp Wave export of the song.
|
||||
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;
|
||||
|
||||
|
|
|
@ -50,8 +50,15 @@ StreamSong::~StreamSong ()
|
|||
}
|
||||
|
||||
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 ()
|
||||
|
@ -92,3 +99,12 @@ bool StreamSong::SetPosition(int order)
|
|||
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
|
||||
// updaterevision tool. Do not edit by hand.
|
||||
|
||||
#define ZD_SVN_REVISION_STRING "853"
|
||||
#define ZD_SVN_REVISION_NUMBER 853
|
||||
#define ZD_SVN_REVISION_STRING "858"
|
||||
#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 ()
|
||||
{
|
||||
if (ImageMap != NULL)
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
~FImageCollection ();
|
||||
|
||||
void Init (const char **patchnames, int numPatches, int namespc=0);
|
||||
void Add (const char **patchnames, int numPatches, int namespc=0);
|
||||
void Uninit ();
|
||||
|
||||
FTexture *operator[] (int index) const;
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
// Protocol version used in demos.
|
||||
// Bump it if you change existing DEM_ commands or add new ones.
|
||||
// Otherwise, it should be safe to leave it alone.
|
||||
#define DEMOGAMEVERSION 0x20B
|
||||
#define DEMOGAMEVERSION 0x20C
|
||||
|
||||
// Minimum demo version we can play.
|
||||
// Bump it whenever you change or remove existing DEM_ commands.
|
||||
|
@ -77,7 +77,7 @@
|
|||
// SAVESIG should match SAVEVER.
|
||||
|
||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||
#define MINSAVEVER 849
|
||||
#define MINSAVEVER 854
|
||||
|
||||
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
|
||||
// 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
|
||||
|
@ -777,6 +791,7 @@ void DoMain (HINSTANCE hInstance)
|
|||
#endif
|
||||
|
||||
Args = new DArgs(__argc, __argv);
|
||||
atterm(FinalGC);
|
||||
|
||||
// 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue