This commit is contained in:
Christoph Oelckers 2016-01-01 00:46:00 +01:00
commit 3bad7f9b55
31 changed files with 282 additions and 244 deletions

View file

@ -221,7 +221,11 @@ enum
WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon.
WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function.
WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire
}; WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4
WF_USER2OK = 1 << 9,
WF_USER3OK = 1 << 10,
WF_USER4OK = 1 << 11,
};
#define WPIECE1 1 #define WPIECE1 1
#define WPIECE2 2 #define WPIECE2 2
@ -405,7 +409,7 @@ public:
int lastkilltime; // [RH] For multikills int lastkilltime; // [RH] For multikills
BYTE multicount; BYTE multicount;
BYTE spreecount; // [RH] Keep track of killing sprees BYTE spreecount; // [RH] Keep track of killing sprees
BYTE WeaponState; WORD WeaponState;
AWeapon *ReadyWeapon; AWeapon *ReadyWeapon;
AWeapon *PendingWeapon; // WP_NOCHANGE if not changing AWeapon *PendingWeapon; // WP_NOCHANGE if not changing

View file

@ -305,8 +305,7 @@ public:
virtual FState *GetReadyState (); virtual FState *GetReadyState ();
virtual FState *GetAtkState (bool hold); virtual FState *GetAtkState (bool hold);
virtual FState *GetAltAtkState (bool hold); virtual FState *GetAltAtkState (bool hold);
virtual FState *GetRelState (); virtual FState *GetStateForButtonName (FName button);
virtual FState *GetZoomState ();
virtual void PostMorphWeapon (); virtual void PostMorphWeapon ();
virtual void EndPowerup (); virtual void EndPowerup ();

View file

@ -683,25 +683,15 @@ FState *AWeapon::GetAltAtkState (bool hold)
//=========================================================================== //===========================================================================
// //
// AWeapon :: GetRelState // AWeapon :: GetStateForButtonName
// //
//=========================================================================== //===========================================================================
FState *AWeapon::GetRelState () FState *AWeapon::GetStateForButtonName (FName button)
{ {
return FindState(NAME_Reload); return FindState(button);
} }
//===========================================================================
//
// AWeapon :: GetZoomState
//
//===========================================================================
FState *AWeapon::GetZoomState ()
{
return FindState(NAME_Zoom);
}
/* Weapon giver ***********************************************************/ /* Weapon giver ***********************************************************/

View file

@ -221,6 +221,10 @@ xx(Flash)
xx(AltFlash) xx(AltFlash)
xx(Reload) xx(Reload)
xx(Zoom) xx(Zoom)
xx(User1)
xx(User2)
xx(User3)
xx(User4)
// State names used by ASwitchableDecoration // State names used by ASwitchableDecoration
xx(Active) xx(Active)

View file

@ -48,6 +48,7 @@
#define HALF_PI (PI*0.5) #define HALF_PI (PI*0.5)
EXTERN_CVAR(Int, opl_core) EXTERN_CVAR(Int, opl_core)
extern int current_opl_core;
OPLio::~OPLio() OPLio::~OPLio()
{ {
@ -323,7 +324,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
{ {
assert(numchips >= 1 && numchips <= countof(chips)); assert(numchips >= 1 && numchips <= countof(chips));
uint i; uint i;
IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3); IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3);
memset(chips, 0, sizeof(chips)); memset(chips, 0, sizeof(chips));
if (IsOPL3) if (IsOPL3)
@ -332,7 +333,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
} }
for (i = 0; i < numchips; ++i) for (i = 0; i < numchips; ++i)
{ {
OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
if (chip == NULL) if (chip == NULL)
{ {
break; break;

View file

@ -53,6 +53,7 @@
#endif #endif
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void OPL_SetCore(const char *args);
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -76,8 +77,9 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
// //
//========================================================================== //==========================================================================
OPLMIDIDevice::OPLMIDIDevice() OPLMIDIDevice::OPLMIDIDevice(const char *args)
{ {
OPL_SetCore(args);
FullPan = opl_fullpan; FullPan = opl_fullpan;
FWadLump data = Wads.OpenLumpName("GENMIDI"); FWadLump data = Wads.OpenLumpName("GENMIDI");
OPLloadBank(data); OPLloadBank(data);

View file

@ -262,6 +262,7 @@ protected:
//========================================================================== //==========================================================================
OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename) OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename)
: OPLMIDIDevice(NULL)
{ {
// Replace the standard OPL device with a disk writer. // Replace the standard OPL device with a disk writer.
delete io; delete io;

View file

@ -38,6 +38,30 @@
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
struct FGenericButtons
{
int ReadyFlag; // Flag passed to A_WeaponReady
int StateFlag; // Flag set in WeaponState
int ButtonFlag; // Button to press
ENamedName StateName; // Name of the button/state
};
enum EWRF_Options
{
WRF_NoBob = 1,
WRF_NoSwitch = 1 << 1,
WRF_NoPrimary = 1 << 2,
WRF_NoSecondary = 1 << 3,
WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary,
WRF_AllowReload = 1 << 4,
WRF_AllowZoom = 1 << 5,
WRF_DisableSwitch = 1 << 6,
WRF_AllowUser1 = 1 << 7,
WRF_AllowUser2 = 1 << 8,
WRF_AllowUser3 = 1 << 9,
WRF_AllowUser4 = 1 << 10,
};
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -57,6 +81,16 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO);
static FRandom pr_wpnreadysnd ("WpnReadySnd"); static FRandom pr_wpnreadysnd ("WpnReadySnd");
static FRandom pr_gunshot ("GunShot"); static FRandom pr_gunshot ("GunShot");
static const FGenericButtons ButtonChecks[] =
{
{ WRF_AllowReload, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom },
{ WRF_AllowZoom, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload },
{ WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 },
{ WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 },
{ WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 },
{ WRF_AllowUser4, WF_USER4OK, BT_USER4, NAME_User4 },
};
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -95,7 +129,8 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio
if (position == ps_weapon && !nofunction) if (position == ps_weapon && !nofunction)
{ // A_WeaponReady will re-set these as needed { // A_WeaponReady will re-set these as needed
player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK); player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK |
WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK);
} }
psp = &player->psprites[position]; psp = &player->psprites[position];
@ -289,66 +324,6 @@ void P_FireWeaponAlt (player_t *player, FState *state)
} }
} }
//---------------------------------------------------------------------------
//
// PROC P_ReloadWeapon
//
//---------------------------------------------------------------------------
void P_ReloadWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (player->Bot == NULL && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetRelState();
}
// [XA] don't change state if still null, so if the modder sets
// WRF_RELOAD to true but forgets to define the Reload state, the weapon
// won't disappear. ;)
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//---------------------------------------------------------------------------
//
// PROC P_ZoomWeapon
//
//---------------------------------------------------------------------------
void P_ZoomWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (player->Bot == NULL && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetZoomState();
}
// [XA] don't change state if still null. Same reasons as above.
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// PROC P_DropWeapon // PROC P_DropWeapon
@ -562,22 +537,21 @@ void DoReadyWeaponToBob (AActor *self)
} }
} }
void DoReadyWeaponToReload (AActor *self) void DoReadyWeaponToGeneric(AActor *self, int paramflags)
{ {
// Prepare for reload action. int flags = 0;
player_t *player;
if (self && (player = self->player))
player->WeaponState |= WF_WEAPONRELOADOK;
return;
}
void DoReadyWeaponToZoom (AActor *self) for (size_t i = 0; i < countof(ButtonChecks); ++i)
{ {
// Prepare for reload action. if (paramflags & ButtonChecks[i].ReadyFlag)
player_t *player; {
if (self && (player = self->player)) flags |= ButtonChecks[i].StateFlag;
player->WeaponState |= WF_WEAPONZOOMOK; }
return; }
if (self != NULL && self->player != NULL)
{
self->player->WeaponState |= flags;
}
} }
// This function replaces calls to A_WeaponReady in other codepointers. // This function replaces calls to A_WeaponReady in other codepointers.
@ -586,22 +560,9 @@ void DoReadyWeapon(AActor *self)
DoReadyWeaponToBob(self); DoReadyWeaponToBob(self);
DoReadyWeaponToFire(self); DoReadyWeaponToFire(self);
DoReadyWeaponToSwitch(self); DoReadyWeaponToSwitch(self);
DoReadyWeaponToReload(self); DoReadyWeaponToGeneric(self, ~0);
DoReadyWeaponToZoom(self);
} }
enum EWRF_Options
{
WRF_NoBob = 1,
WRF_NoSwitch = 2,
WRF_NoPrimary = 4,
WRF_NoSecondary = 8,
WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary,
WRF_AllowReload = 16,
WRF_AllowZoom = 32,
WRF_DisableSwitch = 64,
};
DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady)
{ {
ACTION_PARAM_START(1); ACTION_PARAM_START(1);
@ -610,10 +571,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady)
DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch));
if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary));
if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self);
if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); DoReadyWeaponToGeneric(self, paramflags);
if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch);
DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -690,45 +649,40 @@ void P_CheckWeaponSwitch (player_t *player)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// PROC P_CheckWeaponReload // PROC P_CheckWeaponButtons
// //
// The player can reload the weapon. // Check extra button presses for weapons.
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void P_CheckWeaponReload (player_t *player) static void P_CheckWeaponButtons (player_t *player)
{ {
AWeapon *weapon = player->ReadyWeapon; if (player->Bot == NULL && bot_observer)
if (weapon == NULL)
return;
// Check for reload.
if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD))
{ {
P_ReloadWeapon (player, NULL); return;
} }
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponZoom
//
// The player can use the weapon's zoom function.
//
//---------------------------------------------------------------------------
void P_CheckWeaponZoom (player_t *player)
{
AWeapon *weapon = player->ReadyWeapon; AWeapon *weapon = player->ReadyWeapon;
if (weapon == NULL) if (weapon == NULL)
return;
// Check for zoom.
if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM))
{ {
P_ZoomWeapon (player, NULL); return;
}
// The button checks are ordered by precedence. The first one to match a
// button press and affect a state change wins.
for (size_t i = 0; i < countof(ButtonChecks); ++i)
{
if ((player->WeaponState & ButtonChecks[i].StateFlag) &&
(player->cmd.ucmd.buttons & ButtonChecks[i].ButtonFlag))
{
FState *state = weapon->GetStateForButtonName(ButtonChecks[i].StateName);
// [XA] don't change state if still null, so if the modder
// sets WRF_xxx to true but forgets to define the corresponding
// state, the weapon won't disappear. ;)
if (state != NULL)
{
P_SetPsprite(player, ps_weapon, state);
return;
}
}
} }
} }
@ -1095,14 +1049,9 @@ void P_MovePsprites (player_t *player)
{ {
P_CheckWeaponFire (player); P_CheckWeaponFire (player);
} }
if (player->WeaponState & WF_WEAPONRELOADOK)
{ // Check custom buttons
P_CheckWeaponReload (player); P_CheckWeaponButtons(player);
}
if (player->WeaponState & WF_WEAPONZOOMOK)
{
P_CheckWeaponZoom (player);
}
} }
} }

View file

@ -3043,6 +3043,12 @@ void player_t::Serialize (FArchive &arc)
WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1));
cheats &= ~((1 << 14) | (0x37 << 24)); cheats &= ~((1 << 14) | (0x37 << 24));
} }
if (SaveVersion < 4527)
{
BYTE oldWeaponState;
arc << oldWeaponState;
WeaponState = oldWeaponState;
}
else else
{ {
arc << WeaponState; arc << WeaponState;

View file

@ -1364,16 +1364,36 @@ static void S_AddSNDINFO (int lump)
case SI_MidiDevice: { case SI_MidiDevice: {
sc.MustGetString(); sc.MustGetString();
FName nm = sc.String; FName nm = sc.String;
FScanner::SavedPos save = sc.SavePos();
sc.SetCMode(true);
sc.MustGetString(); sc.MustGetString();
if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY; MidiDeviceSetting devset;
else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS; if (sc.Compare("timidity")) devset.device = MDEV_TIMIDITY;
else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; else if (sc.Compare("fmod") || sc.Compare("sndsys")) devset.device = MDEV_SNDSYS;
else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; else if (sc.Compare("standard")) devset.device = MDEV_MMAPI;
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; else if (sc.Compare("opl")) devset.device = MDEV_OPL;
else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; else if (sc.Compare("default")) devset.device = MDEV_DEFAULT;
else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS; else if (sc.Compare("fluidsynth")) devset.device = MDEV_FLUIDSYNTH;
else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI; else if (sc.Compare("gus")) devset.device = MDEV_GUS;
else if (sc.Compare("wildmidi")) devset.device = MDEV_WILDMIDI;
else sc.ScriptError("Unknown MIDI device %s\n", sc.String); else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
if (sc.CheckString(","))
{
sc.SetCMode(false);
sc.MustGetString();
devset.args = sc.String;
}
else
{
// This does not really do what one might expect, because the next token has already been parsed and can be a '$'.
// So in order to continue parsing without C-Mode, we need to reset and parse the last token again.
sc.SetCMode(false);
sc.RestorePos(save);
sc.MustGetString();
}
MidiDevices[nm] = devset;
} }
break; break;

View file

@ -2421,11 +2421,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
{ {
int lumpnum = -1; int lumpnum = -1;
int length = 0; int length = 0;
int device = MDEV_DEFAULT;
MusInfo *handle = NULL; MusInfo *handle = NULL;
MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname);
int *devp = MidiDevices.CheckKey(musicname);
if (devp != NULL) device = *devp;
// Strip off any leading file:// component. // Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0) if (strncmp(musicname, "file://", 7) == 0)
@ -2495,7 +2492,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
} }
else else
{ {
mus_playing.handle = I_RegisterSong (reader, device); mus_playing.handle = I_RegisterSong (reader, devp);
} }
} }

View file

@ -397,8 +397,19 @@ enum EMidiDevice
MDEV_WILDMIDI = 6, MDEV_WILDMIDI = 6,
}; };
struct MidiDeviceSetting
{
int device;
FString args;
MidiDeviceSetting()
{
device = MDEV_DEFAULT;
}
};
typedef TMap<FName, FName> MusicAliasMap; typedef TMap<FName, FName> MusicAliasMap;
typedef TMap<FName, int> MidiDeviceMap; typedef TMap<FName, MidiDeviceSetting> MidiDeviceMap;
extern MusicAliasMap MusicAliases; extern MusicAliasMap MusicAliases;
extern MidiDeviceMap MidiDevices; extern MidiDeviceMap MidiDevices;

View file

@ -311,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
// //
//========================================================================== //==========================================================================
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype) static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args)
{ {
switch (miditype) switch (miditype)
{ {
case MIDI_MUS: case MIDI_MUS:
return new MUSSong2(reader, devtype); return new MUSSong2(reader, devtype, args);
case MIDI_MIDI: case MIDI_MIDI:
return new MIDISong2(reader, devtype); return new MIDISong2(reader, devtype, args);
case MIDI_HMI: case MIDI_HMI:
return new HMISong(reader, devtype); return new HMISong(reader, devtype, args);
case MIDI_XMI: case MIDI_XMI:
return new XMISong(reader, devtype); return new XMISong(reader, devtype, args);
default: default:
return NULL; return NULL;
@ -387,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size)
// //
//========================================================================== //==========================================================================
MusInfo *I_RegisterSong (FileReader *reader, int device) MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device)
{ {
MusInfo *info = NULL; MusInfo *info = NULL;
const char *fmt; const char *fmt;
@ -405,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
return 0; return 0;
} }
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (device == MDEV_MMAPI)
device = MDEV_SNDSYS;
#endif
// Check for gzip compression. Some formats are expected to have players // Check for gzip compression. Some formats are expected to have players
// that can handle it, so it simplifies things if we make all songs // that can handle it, so it simplifies things if we make all songs
// gzippable. // gzippable.
@ -447,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
if (miditype != MIDI_NOTMIDI) if (miditype != MIDI_NOTMIDI)
{ {
EMidiDevice devtype = (EMidiDevice)device; EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device;
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (devtype == MDEV_MMAPI)
devtype = MDEV_SNDSYS;
#endif
retry_as_sndsys: retry_as_sndsys:
info = CreateMIDIStreamer(*reader, devtype, miditype); info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : "");
if (info != NULL && !info->IsValid()) if (info != NULL && !info->IsValid())
{ {
delete info; delete info;
@ -464,7 +463,7 @@ retry_as_sndsys:
#ifdef _WIN32 #ifdef _WIN32
if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0)
{ {
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype); info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, "");
} }
#endif #endif
} }
@ -475,7 +474,7 @@ retry_as_sndsys:
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
{ {
info = new OPLMUSSong (*reader); info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : "");
} }
// Check for game music // Check for game music
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')

View file

@ -53,7 +53,8 @@ void I_SetMusicVolume (float volume);
// Registers a song handle to song data. // Registers a song handle to song data.
class MusInfo; class MusInfo;
MusInfo *I_RegisterSong (FileReader *reader, int device); struct MidiDeviceSetting;
MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device);
MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterCDSong (int track, int cdid = 0);
MusInfo *I_RegisterURLSong (const char *url); MusInfo *I_RegisterURLSong (const char *url);

View file

@ -185,7 +185,7 @@ public:
class TimidityPPMIDIDevice : public PseudoMIDIDevice class TimidityPPMIDIDevice : public PseudoMIDIDevice
{ {
public: public:
TimidityPPMIDIDevice(); TimidityPPMIDIDevice(const char *args);
~TimidityPPMIDIDevice(); ~TimidityPPMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -270,7 +270,7 @@ protected:
class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
{ {
public: public:
OPLMIDIDevice(); OPLMIDIDevice(const char *args);
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void Close(); void Close();
int GetTechnology() const; int GetTechnology() const;
@ -303,7 +303,7 @@ namespace Timidity { struct Renderer; }
class TimidityMIDIDevice : public SoftSynthMIDIDevice class TimidityMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
TimidityMIDIDevice(); TimidityMIDIDevice(const char *args);
~TimidityMIDIDevice(); ~TimidityMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -337,7 +337,7 @@ protected:
class WildMIDIDevice : public SoftSynthMIDIDevice class WildMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
WildMIDIDevice(); WildMIDIDevice(const char *args);
~WildMIDIDevice(); ~WildMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -366,7 +366,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{ {
public: public:
FluidSynthMIDIDevice(); FluidSynthMIDIDevice(const char *args);
~FluidSynthMIDIDevice(); ~FluidSynthMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -431,7 +431,7 @@ protected:
class MIDIStreamer : public MusInfo class MIDIStreamer : public MusInfo
{ {
public: public:
MIDIStreamer(EMidiDevice type); MIDIStreamer(EMidiDevice type, const char *args);
~MIDIStreamer(); ~MIDIStreamer();
void MusicVolumeChanged(); void MusicVolumeChanged();
@ -517,6 +517,7 @@ protected:
bool CallbackIsThreaded; bool CallbackIsThreaded;
int LoopLimit; int LoopLimit;
FString DumpFilename; FString DumpFilename;
FString Args;
}; };
// MUS file played with a MIDI stream --------------------------------------- // MUS file played with a MIDI stream ---------------------------------------
@ -524,7 +525,7 @@ protected:
class MUSSong2 : public MIDIStreamer class MUSSong2 : public MIDIStreamer
{ {
public: public:
MUSSong2(FileReader &reader, EMidiDevice type); MUSSong2(FileReader &reader, EMidiDevice type, const char *args);
~MUSSong2(); ~MUSSong2();
MusInfo *GetOPLDumper(const char *filename); MusInfo *GetOPLDumper(const char *filename);
@ -550,7 +551,7 @@ protected:
class MIDISong2 : public MIDIStreamer class MIDISong2 : public MIDIStreamer
{ {
public: public:
MIDISong2(FileReader &reader, EMidiDevice type); MIDISong2(FileReader &reader, EMidiDevice type, const char *args);
~MIDISong2(); ~MIDISong2();
MusInfo *GetOPLDumper(const char *filename); MusInfo *GetOPLDumper(const char *filename);
@ -607,7 +608,7 @@ protected:
class HMISong : public MIDIStreamer class HMISong : public MIDIStreamer
{ {
public: public:
HMISong(FileReader &reader, EMidiDevice type); HMISong(FileReader &reader, EMidiDevice type, const char *args);
~HMISong(); ~HMISong();
MusInfo *GetOPLDumper(const char *filename); MusInfo *GetOPLDumper(const char *filename);
@ -650,7 +651,7 @@ protected:
class XMISong : public MIDIStreamer class XMISong : public MIDIStreamer
{ {
public: public:
XMISong(FileReader &reader, EMidiDevice type); XMISong(FileReader &reader, EMidiDevice type, const char *args);
~XMISong(); ~XMISong();
MusInfo *GetOPLDumper(const char *filename); MusInfo *GetOPLDumper(const char *filename);
@ -713,7 +714,7 @@ protected:
class OPLMUSSong : public StreamSong class OPLMUSSong : public StreamSong
{ {
public: public:
OPLMUSSong (FileReader &reader); OPLMUSSong (FileReader &reader, const char *args);
~OPLMUSSong (); ~OPLMUSSong ();
void Play (bool looping, int subsong); void Play (bool looping, int subsong);
bool IsPlaying (); bool IsPlaying ();

View file

@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
// //
//========================================================================== //==========================================================================
FluidSynthMIDIDevice::FluidSynthMIDIDevice() FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
{ {
FluidSynth = NULL; FluidSynth = NULL;
FluidSettings = NULL; FluidSettings = NULL;
@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice()
fluid_reverb_width, fluid_reverb_level); fluid_reverb_width, fluid_reverb_level);
fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level, fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level,
fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type); fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type);
if (0 == LoadPatchSets(fluid_patchset))
// try loading a patch set that got specified with $mididevice.
int res = 0;
if (args != NULL && *args != 0)
{
res = LoadPatchSets(args);
}
if (res == 0 && 0 == LoadPatchSets(fluid_patchset))
{ {
#ifdef __unix__ #ifdef __unix__
// This is the standard location on Ubuntu. // This is the standard location on Ubuntu.

View file

@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15];
// //
//========================================================================== //==========================================================================
HMISong::HMISong (FileReader &reader, EMidiDevice type) HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type), MusHeader(0), Tracks(0) : MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{ {
#ifdef _WIN32 #ifdef _WIN32
if (ExitEvent == NULL) if (ExitEvent == NULL)

View file

@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// //
//========================================================================== //==========================================================================
TimidityPPMIDIDevice::TimidityPPMIDIDevice() TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
: DiskName("zmid"), : DiskName("zmid"),
#ifdef _WIN32 #ifdef _WIN32
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
@ -85,7 +85,13 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice()
#ifndef _WIN32 #ifndef _WIN32
WavePipe[0] = WavePipe[1] = -1; WavePipe[0] = WavePipe[1] = -1;
#endif #endif
if (args == NULL || *args == 0) args = timidity_exe;
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
args, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
if (DiskName == NULL) if (DiskName == NULL)
{ {
Printf(PRINT_BOLD, "Could not create temp music file\n"); Printf(PRINT_BOLD, "Could not create temp music file\n");
@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO
Validated = true; Validated = true;
#endif // WIN32 #endif // WIN32
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
*timidity_exe, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
pipeSize = (timidity_pipe * timidity_frequency / 1000) pipeSize = (timidity_pipe * timidity_frequency / 1000)
<< (timidity_stereo + !timidity_8bit); << (timidity_stereo + !timidity_8bit);

View file

@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] =
// //
//========================================================================== //==========================================================================
MIDIStreamer::MIDIStreamer(EMidiDevice type) MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
: :
#ifdef _WIN32 #ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0), PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif #endif
MIDI(0), Division(0), InitialTempo(500000), DeviceType(type) MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args)
{ {
#ifdef _WIN32 #ifdef _WIN32
BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -269,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
#ifdef HAVE_FLUIDSYNTH #ifdef HAVE_FLUIDSYNTH
case MDEV_FLUIDSYNTH: case MDEV_FLUIDSYNTH:
return new FluidSynthMIDIDevice; return new FluidSynthMIDIDevice(Args);
#endif #endif
case MDEV_SNDSYS: case MDEV_SNDSYS:
return new SndSysMIDIDevice; return new SndSysMIDIDevice;
case MDEV_GUS: case MDEV_GUS:
return new TimidityMIDIDevice; return new TimidityMIDIDevice(Args);
case MDEV_OPL: case MDEV_OPL:
try try
{ {
return new OPLMIDIDevice; return new OPLMIDIDevice(Args);
} }
catch (CRecoverableError &err) catch (CRecoverableError &err)
{ {
@ -291,10 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
} }
case MDEV_TIMIDITY: case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice; return new TimidityPPMIDIDevice(Args);
case MDEV_WILDMIDI: case MDEV_WILDMIDI:
return new WildMIDIDevice; return new WildMIDIDevice(Args);
default: default:
return NULL; return NULL;

View file

@ -43,6 +43,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "m_swap.h" #include "m_swap.h"
#include "files.h" #include "files.h"
#include "s_sound.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -92,8 +93,8 @@ static const BYTE CtrlTranslate[15] =
// //
//========================================================================== //==========================================================================
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type) MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type), MusHeader(0), MusBuffer(0) : MIDIStreamer(type, args), MusHeader(0), MusBuffer(0)
{ {
#ifdef _WIN32 #ifdef _WIN32
if (ExitEvent == NULL) if (ExitEvent == NULL)
@ -210,23 +211,44 @@ bool MUSSong2::CheckDone()
void MUSSong2::Precache() void MUSSong2::Precache()
{ {
WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD)); TArray<WORD> work(MusHeader->NumInstruments);
const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD); const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE);
int i, j; int i, k;
for (i = j = 0; i < MusHeader->NumInstruments; ++i) for (i = k = 0; i < MusHeader->NumInstruments; ++i)
{ {
WORD instr = LittleShort(used[i]); BYTE instr = used[k++];
WORD val;
if (instr < 128) if (instr < 128)
{ {
work[j++] = instr; val = instr;
} }
else if (used[i] >= 135 && used[i] <= 181) else if (instr >= 135 && instr <= 188)
{ // Percussions are 100-based, not 128-based, eh? { // Percussions are 100-based, not 128-based, eh?
work[j++] = instr - 100 + (1 << 14); val = instr - 100 + (1 << 14);
}
else
{
// skip it.
val = used[k++];
k += val;
continue;
}
int numbanks = used[k++];
if (numbanks > 0)
{
for (int b = 0; b < numbanks; b++)
{
work.Push(val | (used[k++] << 7));
}
}
else
{
work.Push(val);
} }
} }
MIDI->PrecacheInstruments(&work[0], j); MIDI->PrecacheInstruments(&work[0], work.Size());
} }
//========================================================================== //==========================================================================

View file

@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
} }
} }
CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
int current_opl_core;
OPLMUSSong::OPLMUSSong (FileReader &reader) // Get OPL core override from $mididevice
void OPL_SetCore(const char *args)
{
current_opl_core = opl_core;
if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0';
}
OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args)
{ {
int samples = int(OPL_SAMPLE_RATE / 14); int samples = int(OPL_SAMPLE_RATE / 14);
OPL_SetCore(args);
Music = new OPLmusicFile (&reader); Music = new OPLmusicFile (&reader);
m_Stream = GSnd->CreateStream (FillStream, samples*4, m_Stream = GSnd->CreateStream (FillStream, samples*4,
(opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); (current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
if (m_Stream == NULL) if (m_Stream == NULL)
{ {
Printf (PRINT_BOLD, "Could not create music stream.\n"); Printf (PRINT_BOLD, "Could not create music stream.\n");

View file

@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// //
//========================================================================== //==========================================================================
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type) MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type), MusHeader(0), Tracks(0) : MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{ {
int p; int p;
int i; int i;

View file

@ -86,10 +86,10 @@ struct FmtChunk
// //
//========================================================================== //==========================================================================
TimidityMIDIDevice::TimidityMIDIDevice() TimidityMIDIDevice::TimidityMIDIDevice(const char *args)
{ {
Renderer = NULL; Renderer = NULL;
Renderer = new Timidity::Renderer((float)SampleRate); Renderer = new Timidity::Renderer((float)SampleRate, args);
} }
//========================================================================== //==========================================================================
@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats()
//========================================================================== //==========================================================================
TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate) TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate)
:TimidityMIDIDevice(NULL)
{ {
File = fopen(filename, "wb"); File = fopen(filename, "wb");
if (File != NULL) if (File != NULL)

View file

@ -81,7 +81,7 @@ CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBAL
// //
//========================================================================== //==========================================================================
WildMIDIDevice::WildMIDIDevice() WildMIDIDevice::WildMIDIDevice(const char *args)
{ {
Renderer = NULL; Renderer = NULL;
@ -94,16 +94,18 @@ WildMIDIDevice::WildMIDIDevice()
SampleRate = clamp(SampleRate, 11025, 65535); SampleRate = clamp(SampleRate, 11025, 65535);
} }
if (CurrentConfig.CompareNoCase(wildmidi_config) != 0 || SampleRate != WildMidi_GetSampleRate()) if (args == NULL || *args == 0) args = wildmidi_config;
if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate())
{ {
if (CurrentConfig.IsNotEmpty()) if (CurrentConfig.IsNotEmpty())
{ {
WildMidi_Shutdown(); WildMidi_Shutdown();
CurrentConfig = ""; CurrentConfig = "";
} }
if (!WildMidi_Init(wildmidi_config, SampleRate, 0)) if (!WildMidi_Init(args, SampleRate, 0))
{ {
CurrentConfig = wildmidi_config; CurrentConfig = args;
} }
} }
if (CurrentConfig.IsNotEmpty()) if (CurrentConfig.IsNotEmpty())

View file

@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15];
// //
//========================================================================== //==========================================================================
XMISong::XMISong (FileReader &reader, EMidiDevice type) XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type), MusHeader(0), Songs(0) : MIDIStreamer(type, args), MusHeader(0), Songs(0)
{ {
#ifdef _WIN32 #ifdef _WIN32
if (ExitEvent == NULL) if (ExitEvent == NULL)

View file

@ -678,8 +678,9 @@ int LoadDMXGUS()
return 0; return 0;
} }
Renderer::Renderer(float sample_rate) Renderer::Renderer(float sample_rate, const char *args)
{ {
// 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first
rate = sample_rate; rate = sample_rate;
patches = NULL; patches = NULL;
resample_buffer_size = 0; resample_buffer_size = 0;

View file

@ -630,7 +630,7 @@ struct Renderer
int voices; int voices;
int lost_notes, cut_notes; int lost_notes, cut_notes;
Renderer(float sample_rate); Renderer(float sample_rate, const char *args);
~Renderer(); ~Renderer();
void HandleEvent(int status, int parm1, int parm2); void HandleEvent(int status, int parm1, int parm2);

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the // Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got. // SVN revision ever got.
#define SAVEVER 4526 #define SAVEVER 4527
#define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

View file

@ -2719,14 +2719,14 @@ midi *WildMidi_NewMidi() {
} }
} }
if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width,
reverb_room_length, reverb_listen_posx, reverb_listen_posy)) reverb_room_length, reverb_listen_posx, reverb_listen_posy))
== NULL) { == NULL) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0);
WildMidi_Close(ret); WildMidi_Close(ret);
ret = NULL; ret = NULL;
} }
return ret; return ret;
} }

View file

@ -129,6 +129,10 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY;
const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWRELOAD = 16;
const int WRF_ALLOWZOOM = 32; const int WRF_ALLOWZOOM = 32;
const int WRF_DISABLESWITCH = 64; const int WRF_DISABLESWITCH = 64;
const int WRF_ALLOWUSER1 = 128;
const int WRF_ALLOWUSER2 = 256;
const int WRF_ALLOWUSER3 = 512;
const int WRF_ALLOWUSER4 = 1024;
// Morph constants // Morph constants
const int MRF_ADDSTAMINA = 1; const int MRF_ADDSTAMINA = 1;

View file

@ -435,8 +435,12 @@ OptionMenu "CustomizeControls"
StaticText "Controls", 1 StaticText "Controls", 1
Control "Fire", "+attack" Control "Fire", "+attack"
Control "Secondary Fire", "+altattack" Control "Secondary Fire", "+altattack"
Control "Weapon Reload", "+reload" Control "Weapon Reload", "+reload"
Control "Weapon Zoom", "+zoom" Control "Weapon Zoom", "+zoom"
Control "Weapon State 1", "+user1"
Control "Weapon State 2", "+user2"
Control "Weapon State 3", "+user3"
Control "Weapon State 4", "+user4"
Control "Use / Open", "+use" Control "Use / Open", "+use"
Control "Move forward", "+forward" Control "Move forward", "+forward"
Control "Move backward", "+back" Control "Move backward", "+back"