- Fixed: The players were not added to FS's list of spawned things.

- Update to ZDoom r882
- Added the option to use $ as a prefix to a string table name everywhere in
  MAPINFO where 'lookup' could be specified so that there is one consistent
  way to do it.
- Externalized all default episode definitions. Added an 'optional' keyword
  to handle M4 and 5 in Doom and Heretic.
- Added P_CheckMapData function and replaced all calls to P_OpenMapData that
  only checked for a map's presence with it.
- Added Martin Howe's player statusbar face submission.
- Added an 'adddefaultmap' option for MAPINFO. This is the same as 'defaultmap'
  but keeps all existing information in the default and just adds to it. This
  is needed because Hexen and Strife set some information in their base
  MAPINFO and using 'defaultmap' in a PWAD would override that.
- Fixed: Using MAPINFO's f1 option could cause memory leaks.
- Added option to load lumps by full name to several places:
  * Finale texts loaded from a text lump
  * Demos
  * Local SNDINFOs
  * Local SNDSEQs
  * Image names in FONTDEFS
  * intermission script names
- Changed the STCFN121 handling. The character is not an 'I' but a '|' so
  instead of discarding it it should be inserted at position 124.
- Renamed indexfont.fon to indexfont so that I could remove a special case
  from V_GetFont that was just added for this one font.
- Added a 'dumpspawnedthings' CVAR that enables a listing of all things in 
  the map and the actor type they spawned.

SBarInfo Update #16
- Added: fillzeros flag for drawnumber.  When set the string will always have
  a length of the specified size and zeros will fill in for the missing places.
  If the number is negative the negative sign will take the place of the last
  digit.
- Added: globalarray type to drawnumber which will display the value in a
  global array with the index set to the player's number.  Untested.
- Added: isselected command to SBarInfo.
- Fixed: Bi and Tri colored numbers didn't work.
- Fixed: Crash when using nullimage as the last image in drawswitchableimage.
- Applied Graf suggestion to include the y coord when calulating heights to fix
  most of the gaps caused by round off errors.  At least for now anyways and it
  is only applied for drawimage.
- SBarInfo inventory bars have been converted to use screen->DrawTexture()
- Increased limit for demon/melee to 4.
- Fixed: P_CheckSwitchRange accessed invalid memory when testing a one-sided
  line.
- Fixed: P_SpawnPuff assumed that all melee attacks have the same range
  (MELEERANGE) and didn't set the puff to its melee state if the range
  was different. Even worse, it checked a global variable for this so
  the behavior was undefined when P_SpawnPuff was called from anywhere
  else but P_LineAttack. To reduce the amount of parameters I combined
  this information with the hitthing and temporary parameters into one
  flags parameter. Also changed P_LineAttack so that it gets passed
  an additional parameter that specifies whether the attack is a melee
  attack or not and set this to true in all calls that are to be considered
  melee attacks. I couldn't use the damage type because A_CustomPunch
  and A_CustomMeleeAttack allow passing any damage type they want.
- Added a sprite option as an alternative of particles for FX_ROCKET 
  and FX_GRENADE.
- Fixed: The minimum parameter count for ACS_Execute and ACS_ExecuteAlways for
  DECORATE was wrong (2 instead of 1.)
- Changed: Hexen set every cluster to be a hub if it hadn't been defined before
  a level using this cluster. Now it will only do that if HexenHack is true, 
  i.e. when original Hexen format MAPINFOs are parsed. For ZDoom format 
  MAPINFOs it will now be the same as for the other games which means that 
  'hub' has to be declared explicitly.
- Added an Idle state that is entered in place of the spawn state if a monster
  has to return to its inactive state if it can't find any more targets.
- Added MF5_NOINTERACTION flag which completely disables all physics related
  code for any actor with this flag. Mostly useful for particle effects where
  the actors just move a certain distance and then disappear.
- Removed the last remains of the antialias precalculation code from
  am_map.cpp because it was no longer used.
- Fixed: Two-sided lines bordering a secret sector were not drawn in the
  proper color
- Fixed: The automap didn't check ACS_LockedExecuteDoor for its lock color.
- Switched sounds local to the listener from head-relative 3D sounds to 2D
  sounds so stereo sounds have full separation. I tried using set3DSpread,
  but that still caused some blending of the channels.
- Changed FScanner so that opening a lump gives the complete wad+lump name
  rather than a generic one, so identifying errors among files that all have
  the same lump name no longer involves any degree of guesswork in
  determining exactly which file the error occurred in.
- Added a check to S_ParseSndSeq() for SNDSEQ lumps with unterminated final
  sequences.
- Fixed: Parts of s_sndseq.cpp that scan the Sequences array need NULL
  pointer checks, in case an improper sequence was encountered during
  parsing but not early enough to avoid creating a slot for it in the array.
- Added support for dumping from RAW/DRO/IMF files, so now anything that
  can be played as OPL can also be dumped.
- Removed the opl_enable cvar, since OPL playback is now selectable as just
  another MIDI device.
- Added support for DRO playback and dual-chip RAW playback.
- Removed MUS support from OPLMUSSong, since using the OPLMIDIDevice with
  MUSSong2 works just as well. There are still lots of leftover bits in
  the class that should probably be removed at some point, too.
- Added dual-chip dumping support for the RAW format.
- Added DosBox Raw OPL (.DRO) dumping support. For whatever reason,
  in_adlib calculates the song length for this format wrong, even though
  the exact length is stored right in the header. (But in_adlib seems buggy
  in general; too bad it's the only Windows version of Adplug that seems to
  exist.)
- Rewrote the OPL dumper to work with MIDI as well as MUS. 

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@86 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
Christoph Oelckers 2008-04-05 13:28:48 +00:00
parent 0c2898d332
commit cabaf17cac
121 changed files with 19530 additions and 18639 deletions

File diff suppressed because it is too large Load diff

View file

@ -2860,6 +2860,10 @@
RelativePath=".\src\oplsynth\music_opl_mididevice.cpp" RelativePath=".\src\oplsynth\music_opl_mididevice.cpp"
> >
</File> </File>
<File
RelativePath=".\src\oplsynth\music_opldumper_mididevice.cpp"
>
</File>
<File <File
RelativePath="src\sound\music_spc.cpp" RelativePath="src\sound\music_spc.cpp"
> >
@ -2903,10 +2907,6 @@
RelativePath=".\src\oplsynth\fmopl.h" RelativePath=".\src\oplsynth\fmopl.h"
> >
</File> </File>
<File
RelativePath=".\src\oplsynth\mlkernel.cpp"
>
</File>
<File <File
RelativePath=".\src\oplsynth\mlopl.cpp" RelativePath=".\src\oplsynth\mlopl.cpp"
> >

View file

@ -33,7 +33,7 @@ $(STATICLIB): $(OBJS)
.PHONY: clean .PHONY: clean
clean: clean:
ifeq (msys,$(OSTYPE)) ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
rm -f $(STATICLIB) rm -f $(STATICLIB)
rm -f *.o rm -f *.o
else else

View file

@ -1,10 +1,11 @@
# Makefile for snes_spc, derived from zlib/Makefile.mgw. # Makefile for snes_spc, derived from zlib/Makefile.mgw.
CMD=0
ifeq (Windows_NT,$(OS)) ifeq (Windows_NT,$(OS))
CMD=1 CMD=1
endif ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys) CMD=0
CMD=0 endif
endif endif
STATICLIB = libsnes_spc.a STATICLIB = libsnes_spc.a

View file

@ -72,7 +72,7 @@ DEFINE_SPECIAL(TeleportOther, 76, 3, 3)
DEFINE_SPECIAL(TeleportGroup, 77, 5, 5) DEFINE_SPECIAL(TeleportGroup, 77, 5, 5)
DEFINE_SPECIAL(TeleportInSector, 78, 4, 5) DEFINE_SPECIAL(TeleportInSector, 78, 4, 5)
DEFINE_SPECIAL(ACS_Execute, 80, 2, 5) DEFINE_SPECIAL(ACS_Execute, 80, 1, 5)
DEFINE_SPECIAL(ACS_Suspend, 81, 2, 2) DEFINE_SPECIAL(ACS_Suspend, 81, 2, 2)
DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2) DEFINE_SPECIAL(ACS_Terminate, 82, 2, 2)
DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5) DEFINE_SPECIAL(ACS_LockedExecute, 83, 5, 5)
@ -197,7 +197,7 @@ DEFINE_SPECIAL(Scroll_Texture_Model, 222, -1, -1)
DEFINE_SPECIAL(Scroll_Floor, 223, 4, 4) DEFINE_SPECIAL(Scroll_Floor, 223, 4, 4)
DEFINE_SPECIAL(Scroll_Ceiling, 224, 4, 4) DEFINE_SPECIAL(Scroll_Ceiling, 224, 4, 4)
DEFINE_SPECIAL(Scroll_Texture_Offsets, 225, -1, -1) DEFINE_SPECIAL(Scroll_Texture_Offsets, 225, -1, -1)
DEFINE_SPECIAL(ACS_ExecuteAlways, 226, 2, 5) DEFINE_SPECIAL(ACS_ExecuteAlways, 226, 1, 5)
DEFINE_SPECIAL(PointPush_SetForce, 227, -1, -1) DEFINE_SPECIAL(PointPush_SetForce, 227, -1, -1)
DEFINE_SPECIAL(Plat_RaiseAndStayTx0, 228, 2, 2) DEFINE_SPECIAL(Plat_RaiseAndStayTx0, 228, 2, 2)
DEFINE_SPECIAL(Thing_SetGoal, 229, 3, 4) DEFINE_SPECIAL(Thing_SetGoal, 229, 3, 4)

View file

@ -299,6 +299,7 @@ enum
MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting
MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hittin this actor MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hittin this actor
MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt MF5_NOINFIGHTING = 0x00100000, // This actor doesn't switch target when it's hurt
MF5_NOINTERACTION = 0x00200000, // Thing is completely excluded from any gameplay related checks
// --- mobj.renderflags --- // --- mobj.renderflags ---
@ -702,6 +703,7 @@ public:
//Added by MC: //Added by MC:
SDWORD id; // Player ID (for items, # in list.) SDWORD id; // Player ID (for items, # in list.)
BYTE smokecounter;
BYTE FloatBobPhase; BYTE FloatBobPhase;
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
DWORD Translation; DWORD Translation;
@ -760,6 +762,7 @@ public:
bool SetStateNF (FState *newstate); bool SetStateNF (FState *newstate);
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
bool isFast(); bool isFast();
void SetIdle();
FState *FindState (FName label) const; FState *FindState (FName label) const;
FState *FindState (FName label, FName sublabel, bool exact = false) const; FState *FindState (FName label, FName sublabel, bool exact = false) const;

View file

@ -115,8 +115,6 @@ inline fixed_t MTOF(fixed_t x)
return MulScale24 (x, scale_mtof); return MulScale24 (x, scale_mtof);
} }
//static int WeightingScale;
CVAR (Int, am_rotate, 0, CVAR_ARCHIVE); CVAR (Int, am_rotate, 0, CVAR_ARCHIVE);
CVAR (Int, am_overlay, 0, CVAR_ARCHIVE); CVAR (Int, am_overlay, 0, CVAR_ARCHIVE);
CVAR (Bool, am_showsecrets, true, CVAR_ARCHIVE); CVAR (Bool, am_showsecrets, true, CVAR_ARCHIVE);
@ -125,7 +123,6 @@ CVAR (Bool, am_showitems, false, CVAR_ARCHIVE);
CVAR (Bool, am_showtime, true, CVAR_ARCHIVE); CVAR (Bool, am_showtime, true, CVAR_ARCHIVE);
CVAR (Bool, am_showtotaltime, false, CVAR_ARCHIVE); CVAR (Bool, am_showtotaltime, false, CVAR_ARCHIVE);
CVAR (Bool, am_usecustomcolors, true, CVAR_ARCHIVE); CVAR (Bool, am_usecustomcolors, true, CVAR_ARCHIVE);
CVAR (Float, am_ovtrans, 1.f, CVAR_ARCHIVE);
CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE); CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE);
CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE); CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE);
CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE); CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE);
@ -347,16 +344,6 @@ static fixed_t mapxstart=0; //x-value for the bitmap.
static bool stopped = true; static bool stopped = true;
/*
#define NUMALIASES 3
#define WALLCOLORS -1
#define FDWALLCOLORS -2
#define CDWALLCOLORS -3
static BYTE antialias[NUMALIASES][NUMWEIGHTS];
*/
void AM_rotatePoint (fixed_t *x, fixed_t *y); void AM_rotatePoint (fixed_t *x, fixed_t *y);
void AM_rotate (fixed_t *x, fixed_t *y, angle_t an); void AM_rotate (fixed_t *x, fixed_t *y, angle_t an);
void AM_doFollowPlayer (); void AM_doFollowPlayer ();
@ -733,57 +720,6 @@ static void AM_initColors (bool overlayed)
NotSeenColor = DoomColors[10]; NotSeenColor = DoomColors[10];
} }
#if 0
// Due to a bug (marked below) precalculated antialiasing was never working properly.
// Also, tests show it provides no measurable performance improvement.
// And since it only complicates matters it's disabled for now.
// initialize the anti-aliased lines
static struct
{
int *color;
int prevcolor;
int falseColor;
} aliasedLines[3] = {
{ &WallColor, -1, WALLCOLORS },
{ &FDWallColor, -1, FDWALLCOLORS },
{ &CDWallColor, -1, CDWALLCOLORS }
};
float backRed, backGreen, backBlue;
GetComponents (Background, palette, backRed, backGreen, backBlue);
for (int alias = 0; alias < NUMALIASES; alias++)
{
if (aliasedLines[alias].prevcolor != *(aliasedLines[alias].color) ||
lastpal != palette || lastback != Background)
{
float foreRed, foreGreen, foreBlue;
aliasedLines[alias].prevcolor = *(aliasedLines[alias].color);
GetComponents (*(aliasedLines[alias].color), palette, foreRed, foreGreen, foreBlue);
for (int i = 0; i < NUMWEIGHTS; i++)
{
float step = (float)i;
float fore = (NUMWEIGHTS-1 - step) / (NUMWEIGHTS-1);
float back = step / (NUMWEIGHTS-1);
int red = (int)(backRed * back + foreRed * fore);
int green = (int)(backGreen * back + foreGreen * fore);
int blue = (int)(backGreen * back + foreBlue * fore);
// [RH] What was I thinking here?
// if (palette)
antialias[alias][i] = ColorMatcher.Pick (red, green, blue);
// else
// antialias[alias][i] = MAKERGB(red, green, blue);
}
}
// This line was inside the 'if' block rendering the whole
// precalculation inoperable.
*(aliasedLines[alias].color) = aliasedLines[alias].falseColor;
}
lastback = Background;
#endif
lastpal = palette; lastpal = palette;
} }
@ -1357,6 +1293,22 @@ void AM_drawGrid (const AMColor &color)
} }
} }
static bool AM_CheckSecret(line_t *line)
{
if (line->frontsector != NULL)
{
if (line->frontsector->oldspecial &&
(am_map_secrets==2 || (am_map_secrets==1 && !(line->frontsector->special&SECRET_MASK))))
return true;
}
if (line->backsector != NULL)
{
if (line->backsector->oldspecial &&
(am_map_secrets==2 || (am_map_secrets==1 && !(line->backsector->special&SECRET_MASK))))
return true;
}
return false;
}
// //
// Determines visible lines, draws them. // Determines visible lines, draws them.
// This is LineDef based, not LineSeg based. // This is LineDef based, not LineSeg based.
@ -1384,18 +1336,14 @@ void AM_drawWalls (bool allmap)
if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0) if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0)
continue; continue;
if (!lines[i].backsector) if (AM_CheckSecret(&lines[i]))
{ {
if (lines[i].frontsector->oldspecial && // map secret sectors like Boom
(am_map_secrets==2 || (am_map_secrets==1 && !(lines[i].frontsector->special&SECRET_MASK)))) AM_drawMline(&l, SecretSectorColor);
{ }
// map secret sectors like Boom else if (!lines[i].backsector)
AM_drawMline(&l, SecretSectorColor); {
} AM_drawMline(&l, WallColor);
else
{
AM_drawMline(&l, WallColor);
}
} }
else else
{ {
@ -1424,6 +1372,7 @@ void AM_drawWalls (bool allmap)
} }
else if (lines[i].special == Door_LockedRaise || else if (lines[i].special == Door_LockedRaise ||
lines[i].special == ACS_LockedExecute || lines[i].special == ACS_LockedExecute ||
lines[i].special == ACS_LockedExecuteDoor ||
(lines[i].special == Generic_Door && lines[i].args[4]!=0)) (lines[i].special == Generic_Door && lines[i].args[4]!=0))
{ {
if (am_usecustomcolors) if (am_usecustomcolors)
@ -1805,7 +1754,6 @@ void AM_Drawer ()
f_w = screen->GetWidth (); f_w = screen->GetWidth ();
f_h = ST_Y; f_h = ST_Y;
f_p = screen->GetPitch (); f_p = screen->GetPitch ();
//WeightingScale = 0;
AM_clearFB(Background); AM_clearFB(Background);
} }
@ -1816,13 +1764,6 @@ void AM_Drawer ()
f_w = realviewwidth; f_w = realviewwidth;
f_h = realviewheight; f_h = realviewheight;
f_p = screen->GetPitch (); f_p = screen->GetPitch ();
/*
WeightingScale = (int)(am_ovtrans * 256.f);
if (WeightingScale < 0 || WeightingScale >= 256)
{
WeightingScale = 0;
}
*/
} }
AM_activateNewScale(); AM_activateNewScale();

View file

@ -266,12 +266,10 @@ CCMD (idclev)
// Catch invalid maps. // Catch invalid maps.
mapname = CalcMapName (epsd, map); mapname = CalcMapName (epsd, map);
MapData * mapd = P_OpenMapData(mapname); if (!P_CheckMapData(mapname))
if (mapd == NULL)
return; return;
// So be it. // So be it.
delete mapd;
Printf ("%s\n", GStrings("STSTR_CLEV")); Printf ("%s\n", GStrings("STSTR_CLEV"));
G_DeferedInitNew (mapname); G_DeferedInitNew (mapname);
players[0].health = 0; // Force reset players[0].health = 0; // Force reset
@ -293,11 +291,9 @@ CCMD (hxvisit)
{ {
// Just because it's in MAPINFO doesn't mean it's in the wad. // Just because it's in MAPINFO doesn't mean it's in the wad.
MapData * map = P_OpenMapData(mapname); if (P_CheckMapData(mapname))
if (map != NULL)
{ {
// So be it. // So be it.
delete map;
Printf ("%s\n", GStrings("STSTR_CLEV")); Printf ("%s\n", GStrings("STSTR_CLEV"));
G_DeferedInitNew (mapname); G_DeferedInitNew (mapname);
return; return;
@ -323,14 +319,12 @@ CCMD (changemap)
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
MapData * map = P_OpenMapData(argv[1]); if (!P_CheckMapData(argv[1]))
if (map == NULL)
{ {
Printf ("No map %s\n", argv[1]); Printf ("No map %s\n", argv[1]);
} }
else else
{ {
delete map;
if (argv.argc() > 2) if (argv.argc() > 2)
{ {
Net_WriteByte (DEM_CHANGEMAP2); Net_WriteByte (DEM_CHANGEMAP2);

View file

@ -2184,8 +2184,15 @@ void DoDehPatch (const char *patchfile, bool autoloading)
if (!PatchFile) if (!PatchFile)
{ {
// Couldn't find it on disk, try reading it from a lump // Couldn't find it on disk, try reading it from a lump
FString filebase(ExtractFileBase (patchfile)); lump = Wads.CheckNumForFullName(patchfile, true);
lump = Wads.CheckNumForName (filebase); if (lump == -1)
{
// Compatibility fallback. It's just here because
// some WAD may need it. Should be deleted it it can
// be confirmed that nothing uses this case.
FString filebase(ExtractFileBase (patchfile));
lump = Wads.CheckNumForName (filebase);
}
if (lump >= 0) if (lump >= 0)
{ {
filelen = Wads.LumpLength (lump); filelen = Wads.LumpLength (lump);

View file

@ -1013,10 +1013,8 @@ void D_DoAdvanceDemo (void)
// [RH] If you want something more dynamic for your title, create a map // [RH] If you want something more dynamic for your title, create a map
// and name it TITLEMAP. That map will be loaded and used as the title. // and name it TITLEMAP. That map will be loaded and used as the title.
MapData * map = P_OpenMapData("TITLEMAP"); if (P_CheckMapData("TITLEMAP"))
if (map != NULL)
{ {
delete map;
G_InitNew ("TITLEMAP", true); G_InitNew ("TITLEMAP", true);
return; return;
} }
@ -2281,14 +2279,12 @@ void D_DoomMain (void)
p = Args->CheckParm ("+map"); p = Args->CheckParm ("+map");
if (p && p < Args->NumArgs()-1) if (p && p < Args->NumArgs()-1)
{ {
MapData * map = P_OpenMapData(Args->GetArg (p+1)); if (!P_CheckMapData(Args->GetArg (p+1)))
if (map == NULL)
{ {
Printf ("Can't find map %s\n", Args->GetArg (p+1)); Printf ("Can't find map %s\n", Args->GetArg (p+1));
} }
else else
{ {
delete map;
strncpy (startmap, Args->GetArg (p+1), 8); strncpy (startmap, Args->GetArg (p+1), 8);
Args->GetArg (p)[0] = '-'; Args->GetArg (p)[0] = '-';
autostart = true; autostart = true;
@ -2355,10 +2351,6 @@ void D_DoomMain (void)
StartScreen->AppendStatusLine(temp); StartScreen->AppendStatusLine(temp);
} }
// [RH] Now that all text strings are set up,
// insert them into the level and cluster data.
G_MakeEpisodes ();
// [RH] Parse through all loaded mapinfo lumps // [RH] Parse through all loaded mapinfo lumps
Printf ("G_ParseMapInfo: Load map definitions.\n"); Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo (); G_ParseMapInfo ();

View file

@ -51,6 +51,7 @@ enum
APMETA_DisplayName, // display name (used in menus etc.) APMETA_DisplayName, // display name (used in menus etc.)
APMETA_SoundClass, // sound class APMETA_SoundClass, // sound class
APMETA_Face, // doom status bar face (when used)
APMETA_ColorRange, // skin color range APMETA_ColorRange, // skin color range
APMETA_InvulMode, APMETA_InvulMode,
APMETA_HealingRadius, APMETA_HealingRadius,
@ -252,6 +253,7 @@ public:
int fixedcolormap; // can be set to REDCOLORMAP, etc. int fixedcolormap; // can be set to REDCOLORMAP, etc.
pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc) pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc)
int morphTics; // player is a chicken/pig if > 0 int morphTics; // player is a chicken/pig if > 0
BYTE MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
AWeapon *PremorphWeapon; // ready weapon before morphing AWeapon *PremorphWeapon; // ready weapon before morphing
int chickenPeck; // chicken peck countdown int chickenPeck; // chicken peck countdown
int jumpTics; // delay the next jump for a moment int jumpTics; // delay the next jump for a moment

View file

@ -346,7 +346,7 @@ void FDecalLib::ReadAllDecals ()
while ((lump = Wads.FindLump ("DECALDEF", &lastlump)) != -1) while ((lump = Wads.FindLump ("DECALDEF", &lastlump)) != -1)
{ {
FScanner sc(lump, "DECALDEF"); FScanner sc(lump);
ReadDecals (sc); ReadDecals (sc);
} }
// Supporting code to allow specifying decals directly in the DECORATE lump // Supporting code to allow specifying decals directly in the DECORATE lump

View file

@ -149,9 +149,6 @@ extern int viewangleoffset;
extern int consoleplayer; extern int consoleplayer;
extern level_locals_t level;
// -------------------------------------- // --------------------------------------
// DEMO playback/recording related stuff. // DEMO playback/recording related stuff.
// No demo, there is a human player in charge? // No demo, there is a human player in charge?

View file

@ -1314,7 +1314,7 @@ static void GetFinaleText (const char *msgLumpName)
{ {
int msgLump; int msgLump;
msgLump = Wads.CheckNumForName(msgLumpName); msgLump = Wads.CheckNumForFullName(msgLumpName, true);
if (msgLump != -1) if (msgLump != -1)
{ {
char *textbuf; char *textbuf;

View file

@ -9,7 +9,6 @@ class AActor;
void T_PreprocessScripts(); void T_PreprocessScripts();
void T_LoadScripts(MapData * map); void T_LoadScripts(MapData * map);
void T_PrepareSpawnThing(); void T_AddSpawnedThing(AActor * );
void T_RegisterSpawnThing(AActor * );
#endif #endif

View file

@ -304,31 +304,15 @@ void T_LoadScripts(MapData *map)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// Registers an entry in the SpawnedThings table // Adds an actor to the list of spawned things
// If no actor is spawned it will remain NULL, otherwise T_RegisterSpawnThing
// will be called to set it
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void T_PrepareSpawnThing() void T_AddSpawnedThing(AActor * ac)
{
if (DFraggleThinker::ActiveThinker)
{
DFraggleThinker::ActiveThinker->SpawnedThings.Push(NULL);
}
}
//-----------------------------------------------------------------------------
//
// Sets the last entry in the table to the passed actor
//
//-----------------------------------------------------------------------------
void T_RegisterSpawnThing(AActor * ac)
{ {
if (DFraggleThinker::ActiveThinker) if (DFraggleThinker::ActiveThinker)
{ {
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings; TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
SpawnedThings[SpawnedThings.Size()-1] = ac; SpawnedThings.Push(GC::ReadBarrier(ac));
} }
} }

View file

@ -617,7 +617,7 @@ void T_PreprocessScripts()
// //
//========================================================================== //==========================================================================
static bool T_RunScript(int snum, AActor * t_trigger) static bool RunScript(int snum, AActor * t_trigger)
{ {
DFraggleThinker *th = DFraggleThinker::ActiveThinker; DFraggleThinker *th = DFraggleThinker::ActiveThinker;
if (th) if (th)
@ -651,7 +651,7 @@ static int LS_FS_Execute (line_t *ln, AActor *it, bool backSide,
{ {
if (arg1 && ln && backSide) return false; if (arg1 && ln && backSide) return false;
if (arg2!=0 && !P_CheckKeys(it, arg2, !!arg3)) return false; if (arg2!=0 && !P_CheckKeys(it, arg2, !!arg3)) return false;
return T_RunScript(arg0,it); return RunScript(arg0,it);
} }
//========================================================================== //==========================================================================
@ -713,6 +713,6 @@ CCMD(fpuke)
} }
else else
{ {
T_RunScript(atoi(argv[1]), players[consoleplayer].mo); RunScript(atoi(argv[1]), players[consoleplayer].mo);
} }
} }

View file

@ -48,7 +48,7 @@ void A_Punch (AActor *actor)
angle += pr_punch.Random2() << 18; angle += pr_punch.Random2() << 18;
pitch = P_AimLineAttack (actor, angle, MELEERANGE); pitch = P_AimLineAttack (actor, angle, MELEERANGE);
P_LineAttack (actor, angle, MELEERANGE, pitch, damage, NAME_None, NAME_BulletPuff); P_LineAttack (actor, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
// turn to face target // turn to face target
if (linetarget) if (linetarget)

View file

@ -456,7 +456,7 @@ void A_M_Punch (AActor *self)
A_FaceTarget (self); A_FaceTarget (self);
angle = self->angle + (pr_m_punch.Random2() << 18); angle = self->angle + (pr_m_punch.Random2() << 18);
pitch = P_AimLineAttack (self, angle, MELEERANGE); pitch = P_AimLineAttack (self, angle, MELEERANGE);
P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff); P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
// turn to face target // turn to face target
if (linetarget) if (linetarget)
@ -486,7 +486,7 @@ void A_M_BerserkPunch (AActor *self)
A_FaceTarget (self); A_FaceTarget (self);
angle = self->angle + (pr_m_punch.Random2() << 18); angle = self->angle + (pr_m_punch.Random2() << 18);
pitch = P_AimLineAttack (self, angle, MELEERANGE); pitch = P_AimLineAttack (self, angle, MELEERANGE);
P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff); P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
// turn to face target // turn to face target
if (linetarget) if (linetarget)

View file

@ -2291,11 +2291,11 @@ void G_BeginRecording (const char *startmap)
// G_PlayDemo // G_PlayDemo
// //
char defdemoname[128]; FString defdemoname;
void G_DeferedPlayDemo (char *name) void G_DeferedPlayDemo (char *name)
{ {
strncpy (defdemoname, name, 127); defdemoname = name;
gameaction = ga_playdemo; gameaction = ga_playdemo;
} }
@ -2457,7 +2457,7 @@ void G_DoPlayDemo (void)
gameaction = ga_nothing; gameaction = ga_nothing;
// [RH] Allow for demos not loaded as lumps // [RH] Allow for demos not loaded as lumps
demolump = Wads.CheckNumForName (defdemoname); demolump = Wads.CheckNumForFullName (defdemoname, true);
if (demolump >= 0) if (demolump >= 0)
{ {
int demolen = Wads.LumpLength (demolump); int demolen = Wads.LumpLength (demolump);
@ -2472,7 +2472,7 @@ void G_DoPlayDemo (void)
} }
demo_p = demobuffer; demo_p = demobuffer;
Printf ("Playing demo %s\n", defdemoname); Printf ("Playing demo %s\n", defdemoname.GetChars());
C_BackupCVars (); // [RH] Save cvars that might be affected by demo C_BackupCVars (); // [RH] Save cvars that might be affected by demo
@ -2520,7 +2520,7 @@ void G_TimeDemo (char* name)
timingdemo = true; timingdemo = true;
singletics = true; singletics = true;
strncpy (defdemoname, name, 128); defdemoname = name;
gameaction = ga_playdemo; gameaction = ga_playdemo;
} }

View file

@ -412,7 +412,7 @@ void A_BeakAttackPL1 (AActor *actor)
damage = 1 + (pr_beakatkpl1()&3); damage = 1 + (pr_beakatkpl1()&3);
angle = player->mo->angle; angle = player->mo->angle;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE); slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff)); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff), true);
if (linetarget) if (linetarget)
{ {
player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->angle = R_PointToAngle2 (player->mo->x,
@ -444,7 +444,7 @@ void A_BeakAttackPL2 (AActor *actor)
damage = pr_beakatkpl2.HitDice (4); damage = pr_beakatkpl2.HitDice (4);
angle = player->mo->angle; angle = player->mo->angle;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE); slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff)); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff), true);
if (linetarget) if (linetarget)
{ {
player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->angle = R_PointToAngle2 (player->mo->x,

View file

@ -217,7 +217,7 @@ void A_StaffAttackPL1 (AActor *actor)
angle = player->mo->angle; angle = player->mo->angle;
angle += pr_sap.Random2() << 18; angle += pr_sap.Random2() << 18;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE); slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff)); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff), true);
if (linetarget) if (linetarget)
{ {
//S_StartSound(player->mo, sfx_stfhit); //S_StartSound(player->mo, sfx_stfhit);
@ -256,7 +256,7 @@ void A_StaffAttackPL2 (AActor *actor)
angle = player->mo->angle; angle = player->mo->angle;
angle += pr_sap2.Random2() << 18; angle += pr_sap2.Random2() << 18;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE); slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff2)); P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff2), true);
if (linetarget) if (linetarget)
{ {
//S_StartSound(player->mo, sfx_stfpow); //S_StartSound(player->mo, sfx_stfpow);

View file

@ -94,7 +94,7 @@ void A_CMaceAttack (AActor *actor)
slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE); slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE);
if (linetarget) if (linetarget)
{ {
P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)); P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
AdjustPlayerAngle (player->mo); AdjustPlayerAngle (player->mo);
// player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->angle = R_PointToAngle2(player->mo->x,
// player->mo->y, linetarget->x, linetarget->y); // player->mo->y, linetarget->x, linetarget->y);
@ -104,7 +104,7 @@ void A_CMaceAttack (AActor *actor)
slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE); slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE);
if (linetarget) if (linetarget)
{ {
P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)); P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
AdjustPlayerAngle (player->mo); AdjustPlayerAngle (player->mo);
// player->mo->angle = R_PointToAngle2(player->mo->x, // player->mo->angle = R_PointToAngle2(player->mo->x,
// player->mo->y, linetarget->x, linetarget->y); // player->mo->y, linetarget->x, linetarget->y);

View file

@ -352,7 +352,7 @@ void A_FAxeAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, AXERANGE); slope = P_AimLineAttack (pmo, angle, AXERANGE);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{ {
P_ThrustMobj (linetarget, angle, power); P_ThrustMobj (linetarget, angle, power);
@ -365,7 +365,7 @@ void A_FAxeAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, AXERANGE); slope = P_AimLineAttack (pmo, angle, AXERANGE);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true);
if (linetarget->flags3&MF3_ISMONSTER) if (linetarget->flags3&MF3_ISMONSTER)
{ {
P_ThrustMobj (linetarget, angle, power); P_ThrustMobj (linetarget, angle, power);
@ -380,7 +380,7 @@ void A_FAxeAttack (AActor *actor)
angle = pmo->angle; angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, MELEERANGE); slope = P_AimLineAttack (pmo, angle, MELEERANGE);
P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
axedone: axedone:
if (useMana == 2) if (useMana == 2)

View file

@ -194,7 +194,7 @@ void A_FHammerAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
if (linetarget) if (linetarget)
{ {
P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)); P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
AdjustPlayerAngle(pmo); AdjustPlayerAngle(pmo);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{ {
@ -207,7 +207,7 @@ void A_FHammerAttack (AActor *actor)
slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE); slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
if(linetarget) if(linetarget)
{ {
P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)); P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
AdjustPlayerAngle(pmo); AdjustPlayerAngle(pmo);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{ {
@ -220,7 +220,7 @@ void A_FHammerAttack (AActor *actor)
// didn't find any targets in meleerange, so set to throw out a hammer // didn't find any targets in meleerange, so set to throw out a hammer
angle = pmo->angle; angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE); slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)) != NULL) if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true) != NULL)
{ {
pmo->special1 = false; pmo->special1 = false;
} }

View file

@ -258,7 +258,7 @@ void A_FPunchAttack (AActor *actor)
power = 6*FRACUNIT; power = 6*FRACUNIT;
pufftype = RUNTIME_CLASS(AHammerPuff); pufftype = RUNTIME_CLASS(AHammerPuff);
} }
P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{ {
P_ThrustMobj (linetarget, angle, power); P_ThrustMobj (linetarget, angle, power);
@ -277,7 +277,7 @@ void A_FPunchAttack (AActor *actor)
power = 6*FRACUNIT; power = 6*FRACUNIT;
pufftype = RUNTIME_CLASS(AHammerPuff); pufftype = RUNTIME_CLASS(AHammerPuff);
} }
P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player) if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{ {
P_ThrustMobj (linetarget, angle, power); P_ThrustMobj (linetarget, angle, power);
@ -291,7 +291,7 @@ void A_FPunchAttack (AActor *actor)
angle = pmo->angle; angle = pmo->angle;
slope = P_AimLineAttack (pmo, angle, MELEERANGE); slope = P_AimLineAttack (pmo, angle, MELEERANGE);
P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype); P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
punchdone: punchdone:
if (pmo->special1 == 3) if (pmo->special1 == 3)

View file

@ -269,7 +269,7 @@ void A_SnoutAttack (AActor *actor)
damage = 3+(pr_snoutattack()&3); damage = 3+(pr_snoutattack()&3);
angle = player->mo->angle; angle = player->mo->angle;
slope = P_AimLineAttack(player->mo, angle, MELEERANGE); slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ASnoutPuff)); puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ASnoutPuff), true);
S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
if(linetarget) if(linetarget)
{ {

View file

@ -41,6 +41,7 @@
#include "gi.h" #include "gi.h"
#include "files.h" #include "files.h"
#include "m_png.h" #include "m_png.h"
#include "gstrings.h"
//========================================================================== //==========================================================================
@ -102,7 +103,14 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
} }
if (cluster->clustername) if (cluster->clustername)
{ {
strncpy(level.level_name, cluster->clustername, 64); if (cluster->flags & CLUSTER_LOOKUPNAME)
{
strncpy(level.level_name, GStrings(cluster->clustername), 64);
}
else
{
strncpy(level.level_name, cluster->clustername, 64);
}
level.level_name[63]=0; level.level_name[63]=0;
} }
} }

View file

@ -137,7 +137,7 @@ extern const AInventory *SendItemUse, *SendItemDrop;
void *statcopy; // for statistics driver void *statcopy; // for statistics driver
level_locals_t level; // info about current level FLevelLocals level; // info about current level
static TArray<cluster_info_t> wadclusterinfos; static TArray<cluster_info_t> wadclusterinfos;
TArray<level_info_t> wadlevelinfos; TArray<level_info_t> wadlevelinfos;
@ -180,6 +180,7 @@ static const char *MapInfoTopLevel[] =
"clearepisodes", "clearepisodes",
"skill", "skill",
"clearskills", "clearskills",
"adddefaultmap",
NULL NULL
}; };
@ -192,6 +193,7 @@ enum
MITL_CLEAREPISODES, MITL_CLEAREPISODES,
MITL_SKILL, MITL_SKILL,
MITL_CLEARSKILLS, MITL_CLEARSKILLS,
MITL_ADDDEFAULTMAP,
}; };
static const char *MapInfoMapLevel[] = static const char *MapInfoMapLevel[] =
@ -337,7 +339,6 @@ enum EMIType
MITYPE_REDIRECT, MITYPE_REDIRECT,
MITYPE_SPECIALACTION, MITYPE_SPECIALACTION,
MITYPE_COMPATFLAG, MITYPE_COMPATFLAG,
MITYPE_F1, // [RC] F1 help
}; };
struct MapInfoHandler struct MapInfoHandler
@ -414,18 +415,18 @@ MapHandlers[] =
{ MITYPE_CLRFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO }, { MITYPE_CLRFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_SETFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO }, { MITYPE_SETFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL}, { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 }, { MITYPE_STRING, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 }, { MITYPE_STRING, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(enterpic), 0 }, { MITYPE_STRING, lioffset(enterpic), 0 },
{ MITYPE_MUSIC, lioffset(intermusic), lioffset(intermusicorder) }, { MITYPE_MUSIC, lioffset(intermusic), lioffset(intermusicorder) },
{ MITYPE_INT, lioffset(airsupply), 0 }, { MITYPE_INT, lioffset(airsupply), 0 },
{ MITYPE_SPECIALACTION, lioffset(specialactions), 0 }, { MITYPE_SPECIALACTION, lioffset(specialactions), 0 },
{ MITYPE_SETFLAG, LEVEL_KEEPFULLINVENTORY, 0 }, { MITYPE_SETFLAG, LEVEL_KEEPFULLINVENTORY, 0 },
{ MITYPE_SETFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 }, { MITYPE_SETFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
{ MITYPE_CLRFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 }, { MITYPE_CLRFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
{ MITYPE_LUMPNAME, lioffset(sndseq), 0 }, { MITYPE_STRING, lioffset(sndseq), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 0 }, { MITYPE_STRING, lioffset(soundinfo), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 0 }, { MITYPE_STRING, lioffset(soundinfo), 0 },
{ MITYPE_SETFLAG, LEVEL_CLIPMIDTEX, 0 }, { MITYPE_SETFLAG, LEVEL_CLIPMIDTEX, 0 },
{ MITYPE_SETFLAG, LEVEL_WRAPMIDTEX, 0 }, { MITYPE_SETFLAG, LEVEL_WRAPMIDTEX, 0 },
{ MITYPE_CLRFLAG, LEVEL_CROUCH_NO, 0 }, { MITYPE_CLRFLAG, LEVEL_CROUCH_NO, 0 },
@ -446,7 +447,7 @@ MapHandlers[] =
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL}, { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_COMPATFLAG, COMPATF_INVISIBILITY}, { MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
{ MITYPE_LUMPNAME, lioffset(bordertexture), 0 }, { MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
{ MITYPE_F1, lioffset(f1), 0, }, { MITYPE_LUMPNAME, lioffset(f1), 0, },
{ MITYPE_SCFLAGS, LEVEL_NOINFIGHTING, ~LEVEL_TOTALINFIGHTING }, { MITYPE_SCFLAGS, LEVEL_NOINFIGHTING, ~LEVEL_TOTALINFIGHTING },
{ MITYPE_SCFLAGS, 0, ~(LEVEL_NOINFIGHTING|LEVEL_TOTALINFIGHTING)}, { MITYPE_SCFLAGS, 0, ~(LEVEL_NOINFIGHTING|LEVEL_TOTALINFIGHTING)},
{ MITYPE_SCFLAGS, LEVEL_TOTALINFIGHTING, ~LEVEL_NOINFIGHTING }, { MITYPE_SCFLAGS, LEVEL_TOTALINFIGHTING, ~LEVEL_NOINFIGHTING },
@ -493,7 +494,7 @@ MapInfoHandler ClusterHandlers[] =
{ MITYPE_HEX, cioffset(cdid), 0 }, { MITYPE_HEX, cioffset(cdid), 0 },
{ MITYPE_SETFLAG, CLUSTER_ENTERTEXTINLUMP, 0 }, { MITYPE_SETFLAG, CLUSTER_ENTERTEXTINLUMP, 0 },
{ MITYPE_SETFLAG, CLUSTER_EXITTEXTINLUMP, 0 }, { MITYPE_SETFLAG, CLUSTER_EXITTEXTINLUMP, 0 },
{ MITYPE_STRING, cioffset(clustername), 0 }, { MITYPE_STRING, cioffset(clustername), CLUSTER_LOOKUPNAME },
}; };
static void ParseMapInfoLower (FScanner &sc, static void ParseMapInfoLower (FScanner &sc,
@ -537,10 +538,6 @@ static void SetLevelDefaults (level_info_t *levelinfo)
// For maps without a BEHAVIOR, this will be cleared. // For maps without a BEHAVIOR, this will be cleared.
levelinfo->flags |= LEVEL_LAXMONSTERACTIVATION; levelinfo->flags |= LEVEL_LAXMONSTERACTIVATION;
} }
else
{
levelinfo->flags |= LEVEL_MONSTERFALLINGDAMAGE;
}
levelinfo->airsupply = 10; levelinfo->airsupply = 10;
// new // new
@ -627,6 +624,48 @@ static FSpecialAction *CopySpecialActions(FSpecialAction *spec)
return spec; return spec;
} }
static void CopyString (char *& string)
{
if (string != NULL)
string = copystring(string);
}
static void SafeDelete(char *&string)
{
if (string != NULL)
{
delete[] string;
string = NULL;
}
}
static void ClearLevelInfoStrings(level_info_t *linfo)
{
SafeDelete(linfo->music);
SafeDelete(linfo->intermusic);
SafeDelete(linfo->level_name);
SafeDelete(linfo->translator);
SafeDelete(linfo->enterpic);
SafeDelete(linfo->exitpic);
SafeDelete(linfo->soundinfo);
SafeDelete(linfo->sndseq);
for (FSpecialAction *spac = linfo->specialactions; spac != NULL; )
{
FSpecialAction *next = spac->Next;
delete spac;
spac = next;
}
}
static void ClearClusterInfoStrings(cluster_info_t *cinfo)
{
SafeDelete(cinfo->exittext);
SafeDelete(cinfo->entertext);
SafeDelete(cinfo->messagemusic);
SafeDelete(cinfo->clustername);
}
static void G_DoParseMapInfo (int lump) static void G_DoParseMapInfo (int lump)
{ {
level_info_t defaultinfo; level_info_t defaultinfo;
@ -636,7 +675,7 @@ static void G_DoParseMapInfo (int lump)
int clusterindex; int clusterindex;
QWORD levelflags; QWORD levelflags;
FScanner sc(lump, Wads.GetLumpFullName(lump)); FScanner sc(lump);
SetLevelDefaults (&defaultinfo); SetLevelDefaults (&defaultinfo);
HexenHack = false; HexenHack = false;
@ -651,6 +690,11 @@ static void G_DoParseMapInfo (int lump)
ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags); ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags);
break; break;
case MITL_ADDDEFAULTMAP:
// Same as above but adds to the existing definitions instead of replacing them completely
ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags);
break;
case MITL_MAP: // map <MAPNAME> <Nice Name> case MITL_MAP: // map <MAPNAME> <Nice Name>
levelflags = defaultinfo.flags; levelflags = defaultinfo.flags;
sc.MustGetString (); sc.MustGetString ();
@ -668,7 +712,8 @@ static void G_DoParseMapInfo (int lump)
| LEVEL_FALLDMG_HX | LEVEL_FALLDMG_HX
| LEVEL_ACTOWNSPECIAL | LEVEL_ACTOWNSPECIAL
| LEVEL_MISSILESACTIVATEIMPACT | LEVEL_MISSILESACTIVATEIMPACT
| LEVEL_INFINITE_FLIGHT; | LEVEL_INFINITE_FLIGHT
| LEVEL_MONSTERFALLINGDAMAGE;
} }
levelindex = FindWadLevelInfo (sc.String); levelindex = FindWadLevelInfo (sc.String);
if (levelindex == -1) if (levelindex == -1)
@ -681,18 +726,13 @@ static void G_DoParseMapInfo (int lump)
} }
levelinfo = &wadlevelinfos[levelindex]; levelinfo = &wadlevelinfos[levelindex];
memcpy (levelinfo, &defaultinfo, sizeof(*levelinfo)); memcpy (levelinfo, &defaultinfo, sizeof(*levelinfo));
if (levelinfo->music != NULL) CopyString(levelinfo->music);
{ CopyString(levelinfo->intermusic);
levelinfo->music = copystring (levelinfo->music); CopyString(levelinfo->translator);
} CopyString(levelinfo->enterpic);
if (levelinfo->intermusic != NULL) CopyString(levelinfo->exitpic);
{ CopyString(levelinfo->soundinfo);
levelinfo->intermusic = copystring (levelinfo->intermusic); CopyString(levelinfo->sndseq);
}
if (levelinfo->translator != NULL)
{
levelinfo->translator = copystring (levelinfo->translator);
}
levelinfo->specialactions = CopySpecialActions(levelinfo->specialactions); levelinfo->specialactions = CopySpecialActions(levelinfo->specialactions);
if (HexenHack) if (HexenHack)
{ {
@ -700,14 +740,19 @@ static void G_DoParseMapInfo (int lump)
} }
uppercopy (levelinfo->mapname, sc.String); uppercopy (levelinfo->mapname, sc.String);
sc.MustGetString (); sc.MustGetString ();
if (sc.Compare ("lookup")) if (sc.String[0] == '$')
{ {
sc.MustGetString (); // For consistency with other definitions allow $Stringtablename here, too.
ReplaceString (&levelinfo->level_name, sc.String);
levelflags |= LEVEL_LOOKUPLEVELNAME; levelflags |= LEVEL_LOOKUPLEVELNAME;
ReplaceString (&levelinfo->level_name, sc.String+1);
} }
else else
{ {
if (sc.Compare ("lookup"))
{
sc.MustGetString ();
levelflags |= LEVEL_LOOKUPLEVELNAME;
}
ReplaceString (&levelinfo->level_name, sc.String); ReplaceString (&levelinfo->level_name, sc.String);
} }
// Set up levelnum now so that you can use Teleport_NewMap specials // Set up levelnum now so that you can use Teleport_NewMap specials
@ -734,10 +779,6 @@ static void G_DoParseMapInfo (int lump)
{ {
strcpy (levelinfo->skypic2, levelinfo->skypic1); strcpy (levelinfo->skypic2, levelinfo->skypic1);
} }
if (levelinfo->f1 != NULL)
{
levelinfo->f1 = copystring (levelinfo->f1);
}
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps. SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
if (levelinfo->pname[0] != 0) if (levelinfo->pname[0] != 0)
{ {
@ -759,22 +800,7 @@ static void G_DoParseMapInfo (int lump)
else else
{ {
clusterinfo = &wadclusterinfos[clusterindex]; clusterinfo = &wadclusterinfos[clusterindex];
if (clusterinfo->entertext != NULL) ClearClusterInfoStrings(clusterinfo);
{
delete[] clusterinfo->entertext;
}
if (clusterinfo->exittext != NULL)
{
delete[] clusterinfo->exittext;
}
if (clusterinfo->messagemusic != NULL)
{
delete[] clusterinfo->messagemusic;
}
if (clusterinfo->clustername != NULL)
{
delete[] clusterinfo->clustername;
}
} }
memset (clusterinfo, 0, sizeof(cluster_info_t)); memset (clusterinfo, 0, sizeof(cluster_info_t));
clusterinfo->cluster = sc.Number; clusterinfo->cluster = sc.Number;
@ -802,60 +828,6 @@ static void G_DoParseMapInfo (int lump)
ClearLevelInfoStrings(&defaultinfo); ClearLevelInfoStrings(&defaultinfo);
} }
static void ClearLevelInfoStrings(level_info_t *linfo)
{
if (linfo->music != NULL)
{
delete[] linfo->music;
linfo->music = NULL;
}
if (linfo->intermusic != NULL)
{
delete[] linfo->intermusic;
linfo->intermusic = NULL;
}
if (linfo->level_name != NULL)
{
delete[] linfo->level_name;
linfo->level_name = NULL;
}
if (linfo->translator != NULL)
{
delete[] linfo->translator;
linfo->translator = NULL;
}
for (FSpecialAction *spac = linfo->specialactions; spac != NULL; )
{
FSpecialAction *next = spac->Next;
delete spac;
spac = next;
}
}
static void ClearClusterInfoStrings(cluster_info_t *cinfo)
{
if (cinfo->exittext != NULL)
{
delete[] cinfo->exittext;
cinfo->exittext = NULL;
}
if (cinfo->entertext != NULL)
{
delete[] cinfo->entertext;
cinfo->entertext = NULL;
}
if (cinfo->messagemusic != NULL)
{
delete[] cinfo->messagemusic;
cinfo->messagemusic = NULL;
}
if (cinfo->clustername != NULL)
{
delete[] cinfo->clustername;
cinfo->clustername = NULL;
}
}
static void ClearEpisodes() static void ClearEpisodes()
{ {
for (int i = 0; i < EpiDef.numitems; ++i) for (int i = 0; i < EpiDef.numitems; ++i)
@ -920,13 +892,6 @@ static void ParseMapInfoLower (FScanner &sc,
case MITYPE_REDIRECT: case MITYPE_REDIRECT:
sc.MustGetString (); sc.MustGetString ();
levelinfo->RedirectType = sc.String; levelinfo->RedirectType = sc.String;
/*
if (levelinfo->RedirectType == NULL ||
!(levelinfo->RedirectType->IsDescendantOf (RUNTIME_CLASS(AInventory))))
{
SC_ScriptError ("%s is not an inventory item", sc.String);
}
*/
// Intentional fall-through // Intentional fall-through
case MITYPE_MAPNAME: { case MITYPE_MAPNAME: {
@ -1064,7 +1029,7 @@ static void ParseMapInfoLower (FScanner &sc,
clusterinfo = &wadclusterinfos[clusterindex]; clusterinfo = &wadclusterinfos[clusterindex];
memset (clusterinfo, 0, sizeof(cluster_info_t)); memset (clusterinfo, 0, sizeof(cluster_info_t));
clusterinfo->cluster = sc.Number; clusterinfo->cluster = sc.Number;
if (gameinfo.gametype == GAME_Hexen) if (HexenHack)
{ {
clusterinfo->flags |= CLUSTER_HUB; clusterinfo->flags |= CLUSTER_HUB;
} }
@ -1073,21 +1038,18 @@ static void ParseMapInfoLower (FScanner &sc,
case MITYPE_STRING: case MITYPE_STRING:
sc.MustGetString (); sc.MustGetString ();
if (sc.Compare ("lookup")) if (sc.String[0] == '$')
{ {
// For consistency with other definitions allow $Stringtablename here, too.
flags |= handler->data2; flags |= handler->data2;
sc.MustGetString (); ReplaceString ((char **)(info + handler->data1), sc.String+1);
} }
ReplaceString ((char **)(info + handler->data1), sc.String); else
break;
case MITYPE_F1:
sc.MustGetString ();
{ {
char *colon = strchr (sc.String, ':'); if (sc.Compare ("lookup"))
if (colon)
{ {
*colon = 0; flags |= handler->data2;
sc.MustGetString ();
} }
ReplaceString ((char **)(info + handler->data1), sc.String); ReplaceString ((char **)(info + handler->data1), sc.String);
} }
@ -1194,6 +1156,7 @@ static void ParseEpisodeInfo (FScanner &sc)
bool remove = false; bool remove = false;
char key = 0; char key = 0;
bool noskill = false; bool noskill = false;
bool optional = false;
// Get map name // Get map name
sc.MustGetString (); sc.MustGetString ();
@ -1212,7 +1175,12 @@ static void ParseEpisodeInfo (FScanner &sc)
} }
do do
{ {
if (sc.Compare ("name")) if (sc.Compare ("optional"))
{
// For M4 in Doom and M4 and M5 in Heretic
optional = true;
}
else if (sc.Compare ("name"))
{ {
sc.MustGetString (); sc.MustGetString ();
ReplaceString (&pic, sc.String); ReplaceString (&pic, sc.String);
@ -1245,6 +1213,17 @@ static void ParseEpisodeInfo (FScanner &sc)
} }
while (sc.GetString ()); while (sc.GetString ());
if (optional && !remove)
{
if (!P_CheckMapData(map))
{
// If the episode is optional and the map does not exist
// just ignore this episode definition.
return;
}
}
for (i = 0; i < EpiDef.numitems; ++i) for (i = 0; i < EpiDef.numitems; ++i)
{ {
if (strncmp (EpisodeMaps[i], map, 8) == 0) if (strncmp (EpisodeMaps[i], map, 8) == 0)
@ -1412,8 +1391,8 @@ void P_RemoveDefereds (void)
bool CheckWarpTransMap (char mapname[9], bool substitute) bool CheckWarpTransMap (char mapname[9], bool substitute)
{ {
if (mapname[0] == '&' && mapname[1] == 'w' && if (mapname[0] == '&' && (mapname[1]&223) == 'W' &&
mapname[2] == 't' && mapname[3] == '@') (mapname[2]&223) == 'T' && mapname[3] == '@')
{ {
level_info_t *lev = FindLevelByWarpTrans (atoi (mapname + 4)); level_info_t *lev = FindLevelByWarpTrans (atoi (mapname + 4));
if (lev != NULL) if (lev != NULL)
@ -1461,12 +1440,12 @@ CCMD (map)
} }
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
MapData * map = P_OpenMapData(argv[1]); if (!P_CheckMapData(argv[1]))
if (map == NULL) {
Printf ("No map %s\n", argv[1]); Printf ("No map %s\n", argv[1]);
}
else else
{ {
delete map;
G_DeferedInitNew (argv[1]); G_DeferedInitNew (argv[1]);
} }
} }
@ -1486,12 +1465,12 @@ CCMD (open)
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
sprintf(d_mapname, "file:%s", argv[1]); sprintf(d_mapname, "file:%s", argv[1]);
MapData * map = P_OpenMapData(d_mapname); if (!P_CheckMapData(d_mapname))
if (map == NULL) {
Printf ("No map %s\n", d_mapname); Printf ("No map %s\n", d_mapname);
}
else else
{ {
delete map;
gameaction = ga_newgame2; gameaction = ga_newgame2;
d_skill = -1; d_skill = -1;
} }
@ -1642,12 +1621,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
} }
// [RH] If this map doesn't exist, bomb out // [RH] If this map doesn't exist, bomb out
MapData * map = P_OpenMapData(mapname); if (!P_CheckMapData(mapname))
if (!map)
{ {
I_Error ("Could not find map %s\n", mapname); I_Error ("Could not find map %s\n", mapname);
} }
delete map;
oldSpeed = GameSpeed; oldSpeed = GameSpeed;
wantFast = !!G_SkillProperty(SKILLP_FastMonsters); wantFast = !!G_SkillProperty(SKILLP_FastMonsters);
@ -1819,10 +1796,8 @@ const char *G_GetSecretExitMap()
if (level.secretmap[0] != 0) if (level.secretmap[0] != 0)
{ {
MapData *map = P_OpenMapData(level.secretmap); if (P_CheckMapData(level.secretmap))
if (map != NULL)
{ {
delete map;
nextmap = level.secretmap; nextmap = level.secretmap;
} }
} }
@ -2067,7 +2042,7 @@ void G_DoLoadLevel (int position, bool autosave)
// DOOM determines the sky texture to be used // DOOM determines the sky texture to be used
// depending on the current episode and the game version. // depending on the current episode and the game version.
// [RH] Fetch sky parameters from level_locals_t. // [RH] Fetch sky parameters from FLevelLocals.
sky1texture = TexMan.GetTexture (level.skypic1, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); sky1texture = TexMan.GetTexture (level.skypic1, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
sky2texture = TexMan.GetTexture (level.skypic2, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable); sky2texture = TexMan.GetTexture (level.skypic2, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
@ -2310,9 +2285,7 @@ void G_FinishTravel ()
// The player being spawned here is a short lived dummy and // The player being spawned here is a short lived dummy and
// must not start any ENTER script or big problems will happen. // must not start any ENTER script or big problems will happen.
P_SpawnPlayer (&playerstarts[pawn->player - players], true); pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], true);
pawndup = pawn->player->mo;
if (!startkeepfacing) if (!startkeepfacing)
{ {
pawn->angle = pawndup->angle; pawn->angle = pawndup->angle;
@ -2431,7 +2404,6 @@ void G_InitLevelLocals ()
level.levelnum = info->levelnum; level.levelnum = info->levelnum;
level.music = info->music; level.music = info->music;
level.musicorder = info->musicorder; level.musicorder = info->musicorder;
level.f1 = info->f1; // [RC] And import the f1 name
strncpy (level.level_name, info->level_name, 63); strncpy (level.level_name, info->level_name, 63);
G_MaybeLookupLevelName (NULL); G_MaybeLookupLevelName (NULL);
@ -2467,7 +2439,7 @@ void G_InitLevelLocals ()
gl_SetFogParams(info->fogdensity, info->outsidefog, info->outsidefogdensity, info->skyfog); gl_SetFogParams(info->fogdensity, info->outsidefog, info->outsidefogdensity, info->skyfog);
} }
bool level_locals_s::IsJumpingAllowed() const bool FLevelLocals::IsJumpingAllowed() const
{ {
if (dmflags & DF_NO_JUMP) if (dmflags & DF_NO_JUMP)
return false; return false;
@ -2476,7 +2448,7 @@ bool level_locals_s::IsJumpingAllowed() const
return !(level.flags & LEVEL_JUMP_NO); return !(level.flags & LEVEL_JUMP_NO);
} }
bool level_locals_s::IsCrouchingAllowed() const bool FLevelLocals::IsCrouchingAllowed() const
{ {
if (dmflags & DF_NO_CROUCH) if (dmflags & DF_NO_CROUCH)
return false; return false;
@ -2485,7 +2457,7 @@ bool level_locals_s::IsCrouchingAllowed() const
return !(level.flags & LEVEL_CROUCH_NO); return !(level.flags & LEVEL_CROUCH_NO);
} }
bool level_locals_s::IsFreelookAllowed() const bool FLevelLocals::IsFreelookAllowed() const
{ {
if (level.flags & LEVEL_FREELOOK_NO) if (level.flags & LEVEL_FREELOOK_NO)
return false; return false;
@ -2544,10 +2516,8 @@ level_info_t *CheckLevelRedirect (level_info_t *info)
if (playeringame[i] && players[i].mo->FindInventory (type)) if (playeringame[i] && players[i].mo->FindInventory (type))
{ {
// check for actual presence of the map. // check for actual presence of the map.
MapData * map = P_OpenMapData(info->RedirectMap); if (P_CheckMapData(info->RedirectMap))
if (map != NULL)
{ {
delete map;
return FindLevelInfo(info->RedirectMap); return FindLevelInfo(info->RedirectMap);
} }
break; break;
@ -2634,90 +2604,6 @@ const char *G_MaybeLookupLevelName (level_info_t *ininfo)
return info != NULL ? info->level_name : NULL; return info != NULL ? info->level_name : NULL;
} }
void G_MakeEpisodes ()
{
int i;
// Set the default episodes
if (EpiDef.numitems == 0)
{
static const char eps[5][8] =
{
"E1M1", "E2M1", "E3M1", "E4M1", "E5M1"
};
static const char depinames[4][7] =
{
"M_EPI1", "M_EPI2", "M_EPI3", "M_EPI4"
};
static const char depikeys[4] = { 'k', 't', 'i', 't' };
static const char *hepinames[5] =
{
"$MNU_COTD",
"$MNU_HELLSMAW",
"$MNU_DOME",
"$MNU_OSSUARY",
"$MNU_DEMESNE",
};
static const char hepikeys[5] = { 'c', 'h', 'd', 'o', 's' };
if (gameinfo.flags & GI_MAPxx)
{
if (gameinfo.gametype == GAME_Hexen)
{
// "&wt@01" is a magic name that will become whatever map has
// warptrans 1.
strcpy (EpisodeMaps[0], "&wt@01");
EpisodeMenu[0].name = copystring ("Hexen");
}
else
{
strcpy (EpisodeMaps[0], "MAP01");
EpisodeMenu[0].name = copystring ("Hell on Earth");
}
EpisodeMenu[0].alphaKey = 'h';
EpisodeMenu[0].fulltext = true;
EpiDef.numitems = 1;
}
else if (gameinfo.gametype == GAME_Doom)
{
memcpy (EpisodeMaps, eps, 4*8);
for (i = 0; i < 4; ++i)
{
EpisodeMenu[i].name = copystring (depinames[i]);
EpisodeMenu[i].fulltext = false;
EpisodeMenu[i].alphaKey = depikeys[i];
}
if (gameinfo.flags & GI_MENUHACK_RETAIL)
{
EpiDef.numitems = 4;
}
else
{
EpiDef.numitems = 3;
}
}
else
{
memcpy (EpisodeMaps, eps, 5*8);
for (i = 0; i < 5; ++i)
{
EpisodeMenu[i].name = copystring (hepinames[i]);
EpisodeMenu[i].fulltext = true;
EpisodeMenu[i].alphaKey = hepikeys[i];
}
if (gameinfo.flags & GI_MENUHACK_EXTENDED)
{
EpiDef.numitems = 5;
}
else
{
EpiDef.numitems = 3;
}
}
}
}
void G_AirControlChanged () void G_AirControlChanged ()
{ {
if (level.aircontrol <= 256) if (level.aircontrol <= 256)
@ -3166,7 +3052,7 @@ void P_ReadACSDefereds (PNGHandle *png)
} }
void level_locals_s::Tick () void FLevelLocals::Tick ()
{ {
// Reset carry sectors // Reset carry sectors
if (Scrolls != NULL) if (Scrolls != NULL)
@ -3175,7 +3061,7 @@ void level_locals_s::Tick ()
} }
} }
void level_locals_s::AddScroller (DScroller *scroller, int secnum) void FLevelLocals::AddScroller (DScroller *scroller, int secnum)
{ {
if (secnum < 0) if (secnum < 0)
{ {

View file

@ -130,7 +130,7 @@ struct FSpecialAction
FSpecialAction *Next; FSpecialAction *Next;
}; };
struct level_info_s struct level_info_t
{ {
char mapname[9]; char mapname[9];
int levelnum; int levelnum;
@ -146,7 +146,7 @@ struct level_info_s
char *level_name; char *level_name;
char fadetable[9]; char fadetable[9];
SBYTE WallVertLight, WallHorizLight; SBYTE WallVertLight, WallHorizLight;
const char *f1; char f1[9];
// TheDefaultLevelInfo initializes everything above this line. // TheDefaultLevelInfo initializes everything above this line.
int musicorder; int musicorder;
FCompressedMemFile *snapshot; FCompressedMemFile *snapshot;
@ -172,13 +172,13 @@ struct level_info_s
FName RedirectType; FName RedirectType;
char RedirectMap[9]; char RedirectMap[9];
char enterpic[9]; char *enterpic;
char exitpic[9]; char *exitpic;
char *intermusic; char *intermusic;
int intermusicorder; int intermusicorder;
char soundinfo[9]; char *soundinfo;
char sndseq[9]; char *sndseq;
char bordertexture[9]; char bordertexture[9];
int fogdensity; int fogdensity;
@ -187,8 +187,8 @@ struct level_info_s
FSpecialAction * specialactions; FSpecialAction * specialactions;
float teamdamage; float teamdamage;
}; };
typedef struct level_info_s level_info_t;
// [RH] These get zeroed every tic and are updated by thinkers. // [RH] These get zeroed every tic and are updated by thinkers.
struct FSectorScrollValues struct FSectorScrollValues
@ -196,7 +196,7 @@ struct FSectorScrollValues
fixed_t ScrollX, ScrollY; fixed_t ScrollX, ScrollY;
}; };
struct level_locals_s struct FLevelLocals
{ {
void Tick (); void Tick ();
void AddScroller (DScroller *, int secnum); void AddScroller (DScroller *, int secnum);
@ -254,15 +254,12 @@ struct level_locals_s
bool FromSnapshot; // The current map was restored from a snapshot bool FromSnapshot; // The current map was restored from a snapshot
const char *f1;
float teamdamage; float teamdamage;
bool IsJumpingAllowed() const; bool IsJumpingAllowed() const;
bool IsCrouchingAllowed() const; bool IsCrouchingAllowed() const;
bool IsFreelookAllowed() const; bool IsFreelookAllowed() const;
}; };
typedef struct level_locals_s level_locals_t;
enum EndTypes enum EndTypes
{ {
@ -309,8 +306,9 @@ typedef struct cluster_info_s cluster_info_t;
#define CLUSTER_FINALEPIC 0x00000008 // Finale "flat" is actually a full-sized image #define CLUSTER_FINALEPIC 0x00000008 // Finale "flat" is actually a full-sized image
#define CLUSTER_LOOKUPEXITTEXT 0x00000010 // Exit text is the name of a language string #define CLUSTER_LOOKUPEXITTEXT 0x00000010 // Exit text is the name of a language string
#define CLUSTER_LOOKUPENTERTEXT 0x00000020 // Enter text is the name of a language string #define CLUSTER_LOOKUPENTERTEXT 0x00000020 // Enter text is the name of a language string
#define CLUSTER_LOOKUPNAME 0x00000040 // Name is the name of a language string
extern level_locals_t level; extern FLevelLocals level;
extern TArray<level_info_t> wadlevelinfos; extern TArray<level_info_t> wadlevelinfos;
@ -360,7 +358,6 @@ void G_InitLevelLocals (void);
void G_AirControlChanged (); void G_AirControlChanged ();
void G_MakeEpisodes (void);
const char *G_MaybeLookupLevelName (level_info_t *level); const char *G_MaybeLookupLevelName (level_info_t *level);
cluster_info_t *FindClusterInfo (int cluster); cluster_info_t *FindClusterInfo (int cluster);

View file

@ -344,7 +344,7 @@ void P_InitKeyMessages()
ClearLocks(); ClearLocks();
while ((lump = Wads.FindLump ("LOCKDEFS", &lastlump)) != -1) while ((lump = Wads.FindLump ("LOCKDEFS", &lastlump)) != -1)
{ {
FScanner sc(lump, "LOCKDEFS"); FScanner sc(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {
if (sc.Compare("LOCK")) if (sc.Compare("LOCK"))

View file

@ -8,6 +8,7 @@
#include "s_sound.h" #include "s_sound.h"
#include "m_random.h" #include "m_random.h"
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "sbar.h"
#define MORPHTICS (40*TICRATE) #define MORPHTICS (40*TICRATE)
@ -56,6 +57,10 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
{ {
return false; return false;
} }
if (spawntype == p->mo->GetClass())
{
return false;
}
morphed = static_cast<APlayerPawn *>(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE)); morphed = static_cast<APlayerPawn *>(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE));
DObject::StaticPointerSubstitution (actor, morphed); DObject::StaticPointerSubstitution (actor, morphed);
@ -78,6 +83,18 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
actor->flags |= MF_UNMORPHED; actor->flags |= MF_UNMORPHED;
actor->renderflags |= RF_INVISIBLE; actor->renderflags |= RF_INVISIBLE;
p->morphTics = MORPHTICS; p->morphTics = MORPHTICS;
// [MH] Used by SBARINFO to speed up face drawing
p->MorphedPlayerClass = 0;
for (unsigned int i = 1; i < PlayerClasses.Size (); i++)
{
if (PlayerClasses[i].Type == spawntype)
{
p->MorphedPlayerClass = i;
break;
}
}
p->health = morphed->health; p->health = morphed->health;
p->mo = morphed; p->mo = morphed;
p->momx = p->momy = 0; p->momx = p->momy = 0;
@ -116,6 +133,18 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
p->camera = morphed; p->camera = morphed;
} }
morphed->ScoreIcon = actor->ScoreIcon; // [GRB] morphed->ScoreIcon = actor->ScoreIcon; // [GRB]
// [MH]
// If the player that was morphed is the one
// taking events, set up the face, if any;
// this is only needed for old-skool skins
// and for the original DOOM status bar.
if ((p == &players[consoleplayer]) &&
(strcmp(spawntype->Meta.GetMetaString (APMETA_Face), "None") != 0))
{
StatusBar->SetFace(&skins[p->MorphedPlayerClass]);
}
return true; return true;
} }
@ -182,6 +211,39 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
{ {
player->camera = mo; player->camera = mo;
} }
// [MH]
// If the player that was morphed is the one
// taking events, reset up the face, if any;
// this is only needed for old-skool skins
// and for the original DOOM status bar.
if ((player == &players[consoleplayer]) &&
(strcmp(pmo->GetClass()->Meta.GetMetaString (APMETA_Face), "None") != 0))
{
// Assume root-level base skin to begin with
size_t skinindex = 0;
// If a custom skin was in use, then reload it
// or else the base skin for the player class.
if ((unsigned int)player->userinfo.skin >= PlayerClasses.Size () &&
(size_t)player->userinfo.skin < numskins)
{
skinindex = player->userinfo.skin;
}
else if (PlayerClasses.Size () > 1)
{
const PClass *whatami = player->mo->GetClass();
for (unsigned int i = 0; i < PlayerClasses.Size (); ++i)
{
if (PlayerClasses[i].Type == whatami)
{
skinindex = i;
break;
}
}
}
StatusBar->SetFace(&skins[skinindex]);
}
angle = mo->angle >> ANGLETOFINESHIFT; angle = mo->angle >> ANGLETOFINESHIFT;
Spawn<ATeleportFog> (pmo->x + 20*finecosine[angle], Spawn<ATeleportFog> (pmo->x + 20*finecosine[angle],
pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE);

View file

@ -183,22 +183,24 @@ enum //drawimage flags
enum //drawnumber flags enum //drawnumber flags
{ {
DRAWNUMBER_HEALTH = 1, DRAWNUMBER_HEALTH = 0x1,
DRAWNUMBER_ARMOR = 2, DRAWNUMBER_ARMOR = 0x2,
DRAWNUMBER_AMMO1 = 4, DRAWNUMBER_AMMO1 = 0x4,
DRAWNUMBER_AMMO2 = 8, DRAWNUMBER_AMMO2 = 0x8,
DRAWNUMBER_AMMO = 16, DRAWNUMBER_AMMO = 0x10,
DRAWNUMBER_AMMOCAPACITY = 32, DRAWNUMBER_AMMOCAPACITY = 0x20,
DRAWNUMBER_FRAGS = 64, DRAWNUMBER_FRAGS = 0x40,
DRAWNUMBER_INVENTORY = 128, DRAWNUMBER_INVENTORY = 0x80,
DRAWNUMBER_KILLS = 256, DRAWNUMBER_KILLS = 0x100,
DRAWNUMBER_MONSTERS = 512, DRAWNUMBER_MONSTERS = 0x200,
DRAWNUMBER_ITEMS = 1024, DRAWNUMBER_ITEMS = 0x400,
DRAWNUMBER_TOTALITEMS = 2048, DRAWNUMBER_TOTALITEMS = 0x800,
DRAWNUMBER_SECRETS = 4096, DRAWNUMBER_SECRETS = 0x1000,
DRAWNUMBER_TOTALSECRETS = 8192, DRAWNUMBER_TOTALSECRETS = 0x2000,
DRAWNUMBER_ARMORCLASS = 16384, DRAWNUMBER_ARMORCLASS = 0x4000,
DRAWNUMBER_GLOBALVAR = 32768, DRAWNUMBER_GLOBALVAR = 0x8000,
DRAWNUMBER_GLOBALARRAY = 0x10000,
DRAWNUMBER_FILLZEROS = 0x20000,
}; };
enum //drawbar flags (will go into special2) enum //drawbar flags (will go into special2)
@ -305,6 +307,7 @@ enum //Bar key words
SBARINFO_GAMEMODE, SBARINFO_GAMEMODE,
SBARINFO_PLAYERCLASS, SBARINFO_PLAYERCLASS,
SBARINFO_ASPECTRATIO, SBARINFO_ASPECTRATIO,
SBARINFO_ISSELECTED,
SBARINFO_WEAPONAMMO, SBARINFO_WEAPONAMMO,
SBARINFO_ININVENTORY, SBARINFO_ININVENTORY,
}; };
@ -338,9 +341,9 @@ public:
void SetMugShotState(const char* stateName, bool waitTillDone=false); void SetMugShotState(const char* stateName, bool waitTillDone=false);
private: private:
void doCommands(SBarInfoBlock &block); void doCommands(SBarInfoBlock &block);
void DrawGraphic(FTexture* texture, int x, int y, int flags); void DrawGraphic(FTexture* texture, int x, int y, int flags=0);
void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0); void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0);
void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0); void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0, bool fillzeros=false);
void DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y); void DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y);
int updateState(bool xdth, bool animatedgodmode); int updateState(bool xdth, bool animatedgodmode);
void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow, void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow,

View file

@ -559,7 +559,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
{ {
DrawGraphic(TexMan[cmd.sprite], cmd.x, cmd.y, cmd.flags); DrawGraphic(TexMan[cmd.sprite], cmd.x, cmd.y, cmd.flags);
} }
else else if(cmd.sprite != -1)
{ {
DrawGraphic(Images[cmd.sprite], cmd.x, cmd.y, cmd.flags); DrawGraphic(Images[cmd.sprite], cmd.x, cmd.y, cmd.flags);
} }
@ -571,7 +571,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
{ {
drawingFont = cmd.font; drawingFont = cmd.font;
} }
if(cmd.flags == DRAWNUMBER_HEALTH) if(cmd.flags & DRAWNUMBER_HEALTH)
{ {
value = health; value = health;
if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives
@ -579,11 +579,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0; value = 0;
} }
} }
else if(cmd.flags == DRAWNUMBER_ARMOR) else if(cmd.flags & DRAWNUMBER_ARMOR)
{ {
value = armorAmount; value = armorAmount;
} }
else if(cmd.flags == DRAWNUMBER_AMMO1) else if(cmd.flags & DRAWNUMBER_AMMO1)
{ {
value = ammocount1; value = ammocount1;
if(ammo1 == NULL) //no ammo, do not draw if(ammo1 == NULL) //no ammo, do not draw
@ -591,7 +591,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
continue; continue;
} }
} }
else if(cmd.flags == DRAWNUMBER_AMMO2) else if(cmd.flags & DRAWNUMBER_AMMO2)
{ {
value = ammocount2; value = ammocount2;
if(ammo2 == NULL) //no ammo, do not draw if(ammo2 == NULL) //no ammo, do not draw
@ -599,7 +599,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
continue; continue;
} }
} }
else if(cmd.flags == DRAWNUMBER_AMMO) else if(cmd.flags & DRAWNUMBER_AMMO)
{ {
const PClass* ammo = PClass::FindClass(cmd.string[0]); const PClass* ammo = PClass::FindClass(cmd.string[0]);
AInventory* item = CPlayer->mo->FindInventory(ammo); AInventory* item = CPlayer->mo->FindInventory(ammo);
@ -612,7 +612,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0; value = 0;
} }
} }
else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY) else if(cmd.flags & DRAWNUMBER_AMMOCAPACITY)
{ {
const PClass* ammo = PClass::FindClass(cmd.string[0]); const PClass* ammo = PClass::FindClass(cmd.string[0]);
AInventory* item = CPlayer->mo->FindInventory(ammo); AInventory* item = CPlayer->mo->FindInventory(ammo);
@ -625,21 +625,21 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount; value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
} }
} }
else if(cmd.flags == DRAWNUMBER_FRAGS) else if(cmd.flags & DRAWNUMBER_FRAGS)
value = CPlayer->fragcount; value = CPlayer->fragcount;
else if(cmd.flags == DRAWNUMBER_KILLS) else if(cmd.flags & DRAWNUMBER_KILLS)
value = level.killed_monsters; value = level.killed_monsters;
else if(cmd.flags == DRAWNUMBER_MONSTERS) else if(cmd.flags & DRAWNUMBER_MONSTERS)
value = level.total_monsters; value = level.total_monsters;
else if(cmd.flags == DRAWNUMBER_ITEMS) else if(cmd.flags & DRAWNUMBER_ITEMS)
value = level.found_items; value = level.found_items;
else if(cmd.flags == DRAWNUMBER_TOTALITEMS) else if(cmd.flags & DRAWNUMBER_TOTALITEMS)
value = level.total_items; value = level.total_items;
else if(cmd.flags == DRAWNUMBER_SECRETS) else if(cmd.flags & DRAWNUMBER_SECRETS)
value = level.found_secrets; value = level.found_secrets;
else if(cmd.flags == DRAWNUMBER_TOTALSECRETS) else if(cmd.flags & DRAWNUMBER_TOTALSECRETS)
value = level.total_secrets; value = level.total_secrets;
else if(cmd.flags == DRAWNUMBER_ARMORCLASS) else if(cmd.flags & DRAWNUMBER_ARMORCLASS)
{ {
AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>(); AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
if(harmor != NULL) if(harmor != NULL)
@ -654,9 +654,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
} }
value /= (5*FRACUNIT); value /= (5*FRACUNIT);
} }
else if(cmd.flags == DRAWNUMBER_GLOBALVAR) else if(cmd.flags & DRAWNUMBER_GLOBALVAR)
value = ACS_GlobalVars[cmd.value]; value = ACS_GlobalVars[cmd.value];
else if(cmd.flags == DRAWNUMBER_INVENTORY) else if(cmd.flags & DRAWNUMBER_GLOBALARRAY)
value = ACS_GlobalArrays[cmd.value][consoleplayer];
else if(cmd.flags & DRAWNUMBER_INVENTORY)
{ {
AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
if(item != NULL) if(item != NULL)
@ -668,12 +670,13 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0; value = 0;
} }
} }
if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low bool fillzeros = !!(cmd.flags & DRAWNUMBER_FILLZEROS);
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2); if(cmd.special3 != -1 && value <= cmd.special3) //low
else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2, fillzeros);
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2); else if(cmd.special4 != -1 && value >= cmd.special4) //high
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2, fillzeros);
else else
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2); DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2, fillzeros);
break; break;
} }
case SBARINFO_DRAWMUGSHOT: case SBARINFO_DRAWMUGSHOT:
@ -1079,6 +1082,27 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
doCommands(cmd.subBlock); doCommands(cmd.subBlock);
} }
break; break;
case SBARINFO_ISSELECTED:
if(CPlayer->ReadyWeapon != NULL)
{
const PClass *weapon1 = PClass::FindClass(cmd.string[0]);
const PClass *weapon2 = PClass::FindClass(cmd.string[1]);
if(weapon2 != NULL)
{
if((cmd.flags & SBARINFOEVENT_NOT) && (weapon1 != CPlayer->ReadyWeapon->GetSpecies() && weapon2 != CPlayer->ReadyWeapon->GetSpecies()))
doCommands(cmd.subBlock);
else if(!(cmd.flags & SBARINFOEVENT_NOT) && (weapon1 == CPlayer->ReadyWeapon->GetSpecies() || weapon2 == CPlayer->ReadyWeapon->GetSpecies()))
doCommands(cmd.subBlock);
}
else
{
if(!(cmd.flags & SBARINFOEVENT_NOT) && weapon1 == CPlayer->ReadyWeapon->GetSpecies())
doCommands(cmd.subBlock);
else if((cmd.flags & SBARINFOEVENT_NOT) && weapon1 != CPlayer->ReadyWeapon->GetSpecies())
doCommands(cmd.subBlock);
}
}
break;
case SBARINFO_WEAPONAMMO: case SBARINFO_WEAPONAMMO:
if(CPlayer->ReadyWeapon != NULL) if(CPlayer->ReadyWeapon != NULL)
{ {
@ -1154,6 +1178,10 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
//draws an image with the specified flags //draws an image with the specified flags
void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags) void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
{ {
if (texture == NULL)
{
return;
}
if((flags & DRAWIMAGE_OFFSET_CENTER)) if((flags & DRAWIMAGE_OFFSET_CENTER))
{ {
x -= (texture->GetWidth()/2)-texture->LeftOffset; x -= (texture->GetWidth()/2)-texture->LeftOffset;
@ -1162,8 +1190,9 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
x += ST_X; x += ST_X;
y += ST_Y; y += ST_Y;
int w = texture->GetScaledWidth(); int w = texture->GetScaledWidth();
int h = texture->GetScaledHeight(); int h = texture->GetScaledHeight() + y;
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
h -= y;
if((flags & DRAWIMAGE_TRANSLATABLE)) if((flags & DRAWIMAGE_TRANSLATABLE))
{ {
screen->DrawTexture(texture, x, y, screen->DrawTexture(texture, x, y,
@ -1224,12 +1253,27 @@ void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translatio
} }
//draws the specified number up to len digits //draws the specified number up to len digits
void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing) void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing, bool fillzeros)
{ {
FString value; FString value;
int maxval = (int) ceil(pow(10., len))-1; int maxval = (int) ceil(pow(10., len))-1;
num = clamp(num, -maxval, maxval); if(!fillzeros || len == 1)
num = clamp(num, -maxval, maxval);
else //The community wanted negatives to take the last digit, but we can only do this if there is room
num = clamp(num, (int) -(ceil(pow(10., len-1))-1), maxval);
value.Format("%d", num); value.Format("%d", num);
if(fillzeros)
{
if(num < 0) //We don't want the negative just yet
value.Format("%d", -num);
while(fillzeros && value.Len() < (unsigned int) len)
{
if(num < 0 && value.Len() == (unsigned int) (len-1))
value.Insert(0, "-");
else
value.Insert(0, "0");
}
}
if(SBarInfoScript->spacingCharacter == '\0') if(SBarInfoScript->spacingCharacter == '\0')
x -= int(drawingFont->StringWidth(value)+(spacing * value.Len())); x -= int(drawingFont->StringWidth(value)+(spacing * value.Len()));
else //monospaced so just multiplay the character size else //monospaced so just multiplay the character size
@ -1245,16 +1289,20 @@ void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool ani
for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++); for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++);
if(currentState != NULL) if(currentState != NULL)
{ {
FTexture *face = currentState->getCurrentFrameTexture(defaultFace, &skins[CPlayer->userinfo.skin], level, angle); FPlayerSkin *skin = &skins[CPlayer->morphTics ? CPlayer->MorphedPlayerClass : CPlayer->userinfo.skin];
x += ST_X; FTexture *face = currentState->getCurrentFrameTexture(defaultFace, skin, level, angle);
y += ST_Y; if (face != NULL)
int w = face->GetScaledWidth(); {
int h = face->GetScaledHeight(); x += ST_X;
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); y += ST_Y;
screen->DrawTexture(face, x, y, int w = face->GetScaledWidth();
DTA_DestWidth, w, int h = face->GetScaledHeight();
DTA_DestHeight, h, screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
TAG_DONE); screen->DrawTexture(face, x, y,
DTA_DestWidth, w,
DTA_DestHeight, h,
TAG_DONE);
}
} }
} }
@ -1391,7 +1439,7 @@ void DSBarInfo::DrawInventoryBar(int type, int num, int x, int y, bool alwayssho
{ {
if(drawArtiboxes) if(drawArtiboxes)
{ {
DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); DrawGraphic(Images[invBarOffset + imgARTIBOX], x+i*31, y);
} }
DrawDimImage (TexMan(item->Icon), x+i*31, y, item->Amount <= 0); DrawDimImage (TexMan(item->Icon), x+i*31, y, item->Amount <= 0);
if(alwaysshowcounter || item->Amount != 1) if(alwaysshowcounter || item->Amount != 1)
@ -1402,28 +1450,28 @@ void DSBarInfo::DrawInventoryBar(int type, int num, int x, int y, bool alwayssho
{ {
if(type == GAME_Heretic) if(type == GAME_Heretic)
{ {
DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29); DrawGraphic(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29);
} }
else else
{ {
DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y); DrawGraphic(Images[invBarOffset + imgSELECTBOX], x+i*31, y);
} }
} }
} }
for (; i < num && drawArtiboxes; ++i) for (; i < num && drawArtiboxes; ++i)
{ {
DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); DrawGraphic(Images[invBarOffset + imgARTIBOX], x+i*31, y);
} }
// Is there something to the left? // Is there something to the left?
if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst)
{ {
DrawImage (Images[!(gametic & 4) ? DrawGraphic(Images[!(gametic & 4) ?
invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x-12, y); invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x-12, y);
} }
// Is there something to the right? // Is there something to the right?
if (!noArrows && item != NULL) if (!noArrows && item != NULL)
{ {
DrawImage (Images[!(gametic & 4) ? DrawGraphic(Images[!(gametic & 4) ?
invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x+num*31+2, y); invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x+num*31+2, y);
} }
} }

View file

@ -93,6 +93,7 @@ static const char *SBarInfoRoutineLevel[] =
"gamemode", "gamemode",
"playerclass", "playerclass",
"aspectratio", "aspectratio",
"isselected",
"weaponammo", //event "weaponammo", //event
"ininventory", "ininventory",
NULL NULL
@ -130,17 +131,14 @@ void SBarInfo::ParseSBarInfo(int lump)
{ {
gameType = gameinfo.gametype; gameType = gameinfo.gametype;
bool baseSet = false; bool baseSet = false;
FScanner sc(lump, Wads.GetLumpFullName(lump)); FScanner sc(lump);
sc.SetCMode(true); sc.SetCMode(true);
while(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_Include)) while(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_Include))
{ {
if(sc.TokenType == TK_Include) if(sc.TokenType == TK_Include)
{ {
sc.MustGetToken(TK_StringConst); sc.MustGetToken(TK_StringConst);
int lump = Wads.CheckNumForFullName(sc.String); //zip/pk3 int lump = Wads.CheckNumForFullName(sc.String, true);
//Do a normal wad lookup.
if (lump == -1 && sc.StringLen <= 8 && !strchr(sc.String, '/'))
lump = Wads.CheckNumForName(sc.String);
if (lump == -1) if (lump == -1)
sc.ScriptError("Lump '%s' not found", sc.String); sc.ScriptError("Lump '%s' not found", sc.String);
ParseSBarInfo(lump); ParseSBarInfo(lump);
@ -493,6 +491,14 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.ScriptError("Global variable number out of range: %d", sc.Number); sc.ScriptError("Global variable number out of range: %d", sc.Number);
cmd.value = sc.Number; cmd.value = sc.Number;
} }
else if(sc.Compare("globalarray")) //acts like variable[playernumber()]
{
cmd.flags += DRAWNUMBER_GLOBALARRAY;
sc.MustGetToken(TK_IntConst);
if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS)
sc.ScriptError("Global variable number out of range: %d", sc.Number);
cmd.value = sc.Number;
}
else else
{ {
cmd.flags = DRAWNUMBER_INVENTORY; cmd.flags = DRAWNUMBER_INVENTORY;
@ -506,6 +512,18 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
} }
sc.MustGetToken(','); sc.MustGetToken(',');
} }
while(sc.CheckToken(TK_Identifier))
{
if(sc.Compare("fillzeros"))
{
cmd.flags += DRAWNUMBER_FILLZEROS;
Printf("%d", cmd.flags);
}
else
sc.ScriptError("Unknown flag '%s'.", sc.String);
if(!sc.CheckToken('|'))
sc.MustGetToken(',');
}
this->getCoordinates(sc, cmd); this->getCoordinates(sc, cmd);
if(sc.CheckToken(',')) if(sc.CheckToken(','))
{ {
@ -951,6 +969,33 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.MustGetToken('{'); sc.MustGetToken('{');
this->ParseSBarInfoBlock(sc, cmd.subBlock); this->ParseSBarInfoBlock(sc, cmd.subBlock);
break; break;
case SBARINFO_ISSELECTED:
if(sc.CheckToken(TK_Identifier))
{
if(sc.Compare("not"))
{
cmd.flags += SBARINFOEVENT_NOT;
}
else
sc.ScriptError("Expected 'not' got '%s' instead.", sc.String);
}
sc.MustGetToken(TK_StringConst);
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(AWeapon)->IsAncestorOf(item))
{
sc.ScriptError("'%s' is not a type of weapon.", sc.String);
}
if(sc.CheckToken(','))
sc.MustGetToken(TK_StringConst);
else
break;
}
sc.MustGetToken('{');
this->ParseSBarInfoBlock(sc, cmd.subBlock);
break;
case SBARINFO_WEAPONAMMO: case SBARINFO_WEAPONAMMO:
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
if(sc.Compare("not")) if(sc.Compare("not"))
@ -983,7 +1028,6 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
this->ParseSBarInfoBlock(sc, cmd.subBlock); this->ParseSBarInfoBlock(sc, cmd.subBlock);
break; break;
case SBARINFO_ININVENTORY: case SBARINFO_ININVENTORY:
{
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
if(sc.Compare("not")) if(sc.Compare("not"))
{ {
@ -1014,7 +1058,6 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.MustGetToken('{'); sc.MustGetToken('{');
this->ParseSBarInfoBlock(sc, cmd.subBlock); this->ParseSBarInfoBlock(sc, cmd.subBlock);
break; break;
}
} }
block.commands.Push(cmd); block.commands.Push(cmd);
} }

View file

@ -928,7 +928,7 @@ void HUD_InitHud()
while ((lump = Wads.FindLump ("ALTHUDCF", &lastlump)) != -1) while ((lump = Wads.FindLump ("ALTHUDCF", &lastlump)) != -1)
{ {
FScanner sc(lump, "ALTHUDCF"); FScanner sc(lump);
while (sc.GetString()) while (sc.GetString())
{ {
if (sc.Compare("Health")) if (sc.Compare("Health"))

View file

@ -543,7 +543,7 @@ void A_KlaxonBlare (AActor *self)
A_TurretLook (self); A_TurretLook (self);
if (self->target == NULL) if (self->target == NULL)
{ {
self->SetState (self->SpawnState); self->SetIdle();
} }
else else
{ {

View file

@ -210,7 +210,7 @@ void A_JabDagger (AActor *actor)
angle = actor->angle + (pr_jabdagger.Random2() << 18); angle = actor->angle + (pr_jabdagger.Random2() << 18);
pitch = P_AimLineAttack (actor, angle, 80*FRACUNIT); pitch = P_AimLineAttack (actor, angle, 80*FRACUNIT);
P_LineAttack (actor, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, RUNTIME_CLASS(AStrifeSpark)); P_LineAttack (actor, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, RUNTIME_CLASS(AStrifeSpark), true);
// turn to face target // turn to face target
if (linetarget) if (linetarget)
@ -934,7 +934,7 @@ void A_RocketInFlight (AActor *self)
AActor *trail; AActor *trail;
S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM);
P_SpawnPuff (RUNTIME_CLASS(AMiniMissilePuff), self->x, self->y, self->z, self->angle - ANGLE_180, 2, true); P_SpawnPuff (RUNTIME_CLASS(AMiniMissilePuff), self->x, self->y, self->z, self->angle - ANGLE_180, 2, PF_HITTHING);
trail = Spawn<ARocketTrail> (self->x - self->momx, self->y - self->momy, self->z, ALLOW_REPLACE); trail = Spawn<ARocketTrail> (self->x - self->momx, self->y - self->momy, self->z, ALLOW_REPLACE);
if (trail != NULL) if (trail != NULL)
{ {

View file

@ -1126,7 +1126,7 @@ void gl_DoParseDefs(FScanner &sc, int workingLump)
if (lump==-1) if (lump==-1)
sc.ScriptError("Lump '%s' not found", sc.String); sc.ScriptError("Lump '%s' not found", sc.String);
FScanner newscanner(lump, sc.String); FScanner newscanner(lump);
gl_DoParseDefs(newscanner, lump); gl_DoParseDefs(newscanner, lump);
break; break;
} }
@ -1186,7 +1186,7 @@ void gl_LoadDynLightDefs(char * defsLump)
lastLump = 0; lastLump = 0;
while ((workingLump = Wads.FindLump(defsLump, &lastLump)) != -1) while ((workingLump = Wads.FindLump(defsLump, &lastLump)) != -1)
{ {
FScanner sc(workingLump, defsLump); FScanner sc(workingLump);
gl_DoParseDefs(sc, workingLump); gl_DoParseDefs(sc, workingLump);
} }
} }

View file

@ -247,7 +247,7 @@ void gl_InitModels()
memset(&smf, 0, sizeof(smf)); memset(&smf, 0, sizeof(smf));
while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1) while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1)
{ {
FScanner sc(Lump, "MODELDEF"); FScanner sc(Lump);
while (sc.GetString()) while (sc.GetString())
{ {
if (sc.Compare("model")) if (sc.Compare("model"))

View file

@ -112,9 +112,9 @@ static void DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy,
else else
{ {
fU2=pti->GetUL(); fU2=pti->GetUL();
fV2=pti->GetVT(); fV1=pti->GetVT();
fU1=pti->GetUR(); fU1=pti->GetUR();
fV1=pti->GetVB(); fV2=pti->GetVB();
} }
gl.Begin(GL_TRIANGLE_STRIP); gl.Begin(GL_TRIANGLE_STRIP);

View file

@ -247,6 +247,7 @@ enum
ADEF_PlayerPawn_CrouchSprite, ADEF_PlayerPawn_CrouchSprite,
ADEF_PlayerPawn_DisplayName, ADEF_PlayerPawn_DisplayName,
ADEF_PlayerPawn_SoundClass, ADEF_PlayerPawn_SoundClass,
ADEF_PlayerPawn_Face,
ADEF_PlayerPawn_ScoreIcon, ADEF_PlayerPawn_ScoreIcon,
ADEF_PlayerPawn_MorphWeapon, ADEF_PlayerPawn_MorphWeapon,
ADEF_LastString = ADEF_PlayerPawn_MorphWeapon, ADEF_LastString = ADEF_PlayerPawn_MorphWeapon,

View file

@ -328,6 +328,9 @@ static void ApplyActorDefault (int defnum, const char *datastr, int dataint)
case ADEF_PlayerPawn_SoundClass: case ADEF_PlayerPawn_SoundClass:
sgClass->Meta.SetMetaString (APMETA_SoundClass, datastr); sgClass->Meta.SetMetaString (APMETA_SoundClass, datastr);
break; break;
case ADEF_PlayerPawn_Face:
sgClass->Meta.SetMetaString (APMETA_Face, datastr);
break;
case ADEF_PlayerPawn_ScoreIcon: case ADEF_PlayerPawn_ScoreIcon:
player->ScoreIcon = TexMan.AddPatch (datastr); player->ScoreIcon = TexMan.AddPatch (datastr);
if (player->ScoreIcon <= 0) if (player->ScoreIcon <= 0)

View file

@ -218,8 +218,9 @@ public:
#define PROP_PlayerPawn_CrouchSprite(x) ADD_STRING_PROP(ADEF_PlayerPawn_CrouchSprite,"\24",x) #define PROP_PlayerPawn_CrouchSprite(x) ADD_STRING_PROP(ADEF_PlayerPawn_CrouchSprite,"\24",x)
#define PROP_PlayerPawn_DisplayName(x) ADD_STRING_PROP(ADEF_PlayerPawn_DisplayName,"\25",x) #define PROP_PlayerPawn_DisplayName(x) ADD_STRING_PROP(ADEF_PlayerPawn_DisplayName,"\25",x)
#define PROP_PlayerPawn_SoundClass(x) ADD_STRING_PROP(ADEF_PlayerPawn_SoundClass,"\26",x) #define PROP_PlayerPawn_SoundClass(x) ADD_STRING_PROP(ADEF_PlayerPawn_SoundClass,"\26",x)
#define PROP_PlayerPawn_ScoreIcon(x) ADD_STRING_PROP(ADEF_PlayerPawn_ScoreIcon,"\27",x) #define PROP_PlayerPawn_Face(x) ADD_STRING_PROP(ADEF_PlayerPawn_Face,"\27",x) // Octal - 'tis quaint!
#define PROP_PlayerPawn_MorphWeapon(x) ADD_STRING_PROP(ADEF_PlayerPawn_MorphWeapon,"\30",x) #define PROP_PlayerPawn_ScoreIcon(x) ADD_STRING_PROP(ADEF_PlayerPawn_ScoreIcon,"\30",x)
#define PROP_PlayerPawn_MorphWeapon(x) ADD_STRING_PROP(ADEF_PlayerPawn_MorphWeapon,"\31",x)
#define PROP_XScale(x) ADD_LONG_PROP(ADEF_XScale,x) #define PROP_XScale(x) ADD_LONG_PROP(ADEF_XScale,x)
#define PROP_YScale(x) ADD_LONG_PROP(ADEF_YScale,x) #define PROP_YScale(x) ADD_LONG_PROP(ADEF_YScale,x)

View file

@ -1446,7 +1446,7 @@ void M_QuickLoad ()
// //
void M_DrawReadThis () void M_DrawReadThis ()
{ {
FTexture *tex, *prevpic = NULL; FTexture *tex = NULL, *prevpic = NULL;
fixed_t alpha; fixed_t alpha;
if (gameinfo.flags & GI_INFOINDEXED) if (gameinfo.flags & GI_INFOINDEXED)
@ -1463,11 +1463,15 @@ void M_DrawReadThis ()
} }
else else
{ {
tex = TexMan[gameinfo.info.infoPage[InfoType-1]];
// Did the mapper choose a custom help page via MAPINFO? // Did the mapper choose a custom help page via MAPINFO?
if((level.f1 != NULL) && (strlen(level.f1) > 0)) if (level.info->f1[0] != 0)
{ {
tex = TexMan.FindTexture(level.f1); tex = TexMan.FindTexture(level.info->f1);
}
if (tex == NULL)
{
tex = TexMan[gameinfo.info.infoPage[InfoType-1]];
} }
if (InfoType > 1) if (InfoType > 1)

View file

@ -492,6 +492,13 @@ static value_t ColumnMethods[] = {
{ 1.0, "Optimized" } { 1.0, "Optimized" }
}; };
static value_t RocketTrailTypes[] = {
{ 0.0, "Off" },
{ 1.0, "Particles" },
{ 2.0, "Sprites" },
{ 3.0, "Sprites & Particles" }
};
static value_t BloodTypes[] = { static value_t BloodTypes[] = {
{ 0.0, "Sprites" }, { 0.0, "Sprites" },
{ 1.0, "Sprites & Particles" }, { 1.0, "Sprites & Particles" },
@ -540,7 +547,7 @@ static menuitem_t VideoItems[] = {
#endif #endif
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ discrete, "Use fuzz effect", {&r_drawfuzz}, {2.0}, {0.0}, {0.0}, {YesNo} }, { discrete, "Use fuzz effect", {&r_drawfuzz}, {2.0}, {0.0}, {0.0}, {YesNo} },
{ discrete, "Rocket Trails", {&cl_rockettrails}, {2.0}, {0.0}, {0.0}, {OnOff} }, { discrete, "Rocket Trails", {&cl_rockettrails}, {4.0}, {0.0}, {0.0}, {RocketTrailTypes} },
{ discrete, "Blood Type", {&cl_bloodtype}, {3.0}, {0.0}, {0.0}, {BloodTypes} }, { discrete, "Blood Type", {&cl_bloodtype}, {3.0}, {0.0}, {0.0}, {BloodTypes} },
{ discrete, "Bullet Puff Type", {&cl_pufftype}, {2.0}, {0.0}, {0.0}, {PuffTypes} }, { discrete, "Bullet Puff Type", {&cl_pufftype}, {2.0}, {0.0}, {0.0}, {PuffTypes} },
}; };
@ -1285,7 +1292,6 @@ static menu_t SoundMenu =
* *
*=======================================*/ *=======================================*/
EXTERN_CVAR (Bool, opl_enable)
EXTERN_CVAR (Bool, opl_onechip) EXTERN_CVAR (Bool, opl_onechip)
static menuitem_t AdvSoundItems[] = static menuitem_t AdvSoundItems[] =
@ -3465,7 +3471,7 @@ void InitCrosshairsList()
while ((lump = Wads.FindLump("XHAIRS", &lastlump)) != -1) while ((lump = Wads.FindLump("XHAIRS", &lastlump)) != -1)
{ {
FScanner sc(lump, "XHAIRS"); FScanner sc(lump);
while (sc.GetNumber()) while (sc.GetNumber())
{ {
value.value = float(sc.Number); value.value = float(sc.Number);

View file

@ -140,6 +140,7 @@ xx(Crush)
xx(Yes) xx(Yes)
xx(No) xx(No)
xx(Greetings) xx(Greetings)
xx(Idle)
// Compatible death names for the decorate parser. // Compatible death names for the decorate parser.
xx(XDeath) xx(XDeath)

View file

@ -75,17 +75,6 @@ Revision History:
#endif #endif
/* output final shift */
#if (OPL_SAMPLE_BITS==16)
#define FINAL_SH (0)
#define MAXOUT (+32767)
#define MINOUT (-32768)
#else
#define FINAL_SH (8)
#define MAXOUT (+127)
#define MINOUT (-128)
#endif
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define EG_SH 16 /* 16.16 fixed point (EG timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ #define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */

View file

@ -3,8 +3,8 @@
#include "zstring.h" #include "zstring.h"
/* select output bits size of output : 8 or 16 */ // Multiplying OPL_SAMPLE_RATE by ADLIB_CLOCK_MUL gives the number
#define OPL_SAMPLE_BITS 16 // Adlib clocks per second, as used by the RAWADATA file format.
/* compiler dependence */ /* compiler dependence */
#ifndef OSD_CPU_H #ifndef OSD_CPU_H
@ -17,13 +17,6 @@ typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */ typedef signed int INT32; /* signed 32bit */
#endif #endif
#if (OPL_SAMPLE_BITS==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef INT8 OPLSAMPLE;
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq); typedef void (*OPL_IRQHANDLER)(int param,int irq);

View file

@ -1,124 +0,0 @@
/*
* Name: MUS Playing kernel
* Project: MUS File Player Library
* Version: 1.70
* Author: Vladimir Arnost (QA-Software)
* Last revision: Oct-28-1995
* Compiler: Borland C++ 3.1, Watcom C/C++ 10.0
*
*/
/*
* Revision History:
*
* Aug-8-1994 V1.00 V.Arnost
* Written from scratch
* Aug-9-1994 V1.10 V.Arnost
* Some minor changes to improve sound quality. Tried to add
* stereo sound capabilities, but failed to -- my SB Pro refuses
* to switch to stereo mode.
* Aug-13-1994 V1.20 V.Arnost
* Stereo sound fixed. Now works also with Sound Blaster Pro II
* (chip OPL3 -- gives 18 "stereo" (ahem) channels).
* Changed code to handle properly notes without volume.
* (Uses previous volume on given channel.)
* Added cyclic channel usage to avoid annoying clicking noise.
* Aug-17-1994 V1.30 V.Arnost
* Completely rewritten time synchronization. Now the player runs
* on IRQ 8 (RTC Clock - 1024 Hz).
* Aug-28-1994 V1.40 V.Arnost
* Added Adlib and SB Pro II detection.
* Fixed bug that caused high part of 32-bit registers (EAX,EBX...)
* to be corrupted.
* Oct-30-1994 V1.50 V.Arnost
* Tidied up the source code
* Added C key - invoke COMMAND.COM
* Added RTC timer interrupt flag check (0000:04A0)
* Added BLASTER environment variable parsing
* FIRST PUBLIC RELEASE
* Apr-16-1995 V1.60 V.Arnost
* Moved into separate source file MUSLIB.C
* May-01-1995 V1.61 V.Arnost
* Added system timer (IRQ 0) support
* Jul-12-1995 V1.62 V.Arnost
* OPL2/OPL3-specific code moved to module MLOPL.C
* Module MUSLIB.C renamed to MLKERNEL.C
* Aug-04-1995 V1.63 V.Arnost
* Fixed stack-related bug occuring in big-code models in Watcom C
* Aug-16-1995 V1.64 V.Arnost
* Stack size changed from 256 to 512 words because of stack
* underflows caused by AWE32 driver
* Aug-28-1995 V1.65 V.Arnost
* Fixed a serious bug that caused the player to generate an
* exception in AWE32 driver under DOS/4GW: Register ES contained
* garbage instead of DGROUP. The compiler-generated prolog of
* interrupt handlers doesn't set ES register at all, thus any
* STOS/MOVS/SCAS/CMPS instruction used within the int. handler
* crashes the program.
* Oct-28-1995 V1.70 V.Arnost
* System-specific timer code moved separate modules
*/
#include "muslib.h"
char MLversion[] = "MUS Lib V"MLVERSIONSTR;
char MLcopyright[] = "Copyright (c) 1994-1996 QA-Software";
/* Program */
int musicBlock::playTick()
{
int delay = 0;
while (delay == 0)
{
uchar data = *score++;
uchar command = (data >> 4) & 7;
uchar channel = data & 0x0F;
uchar last = data & 0x80;
switch (command)
{
case 0: // release note
playingcount--;
OPLreleaseNote(channel, *score++);
break;
case 1: { // play note
uchar note = *score++;
playingcount++;
if (note & 0x80) // note with volume
OPLplayNote(channel, note & 0x7F, *score++);
else
OPLplayNote(channel, note, -1);
} break;
case 2: // pitch wheel
// MUS pitch wheel is 8 bits, but MIDI is 14
OPLpitchWheel(channel, *score++ << (14 - 8));
break;
case 3: // system event (valueless controller)
OPLchangeControl(channel, *score++, 0);
break;
case 4: { // change control
uchar ctrl = *score++;
uchar value = *score++;
OPLchangeControl(channel, ctrl, value);
} break;
case 6: // end
return 0;
case 5: // ???
case 7: // ???
break;
}
if (last)
{
uchar t;
do
{
t = *score++;
delay = (delay << 7) | (t & 127);
} while (t & 128);
}
}
return delay;
}

View file

@ -44,6 +44,18 @@
#include "muslib.h" #include "muslib.h"
#include "fmopl.h" #include "fmopl.h"
OPLio::~OPLio()
{
}
void OPLio::SetClockRate(double samples_per_tick)
{
}
void OPLio::WriteDelay(int ticks)
{
}
void OPLio::OPLwriteReg(int which, uint reg, uchar data) void OPLio::OPLwriteReg(int which, uint reg, uchar data)
{ {
YM3812Write (which, 0, reg); YM3812Write (which, 0, reg);
@ -106,64 +118,73 @@ static WORD frequencies[] =
0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3,
0x1e4, 0x1e5, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, 0x1e4, 0x1e5, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed,
0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f6, 0x1f7, 0x1f8,
0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200,
0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f,
0x210, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x201, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f,
0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x210, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e,
0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232,
0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e,
0x23f, 0x240, 0x241, 0x242, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, 0x22f, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e,
0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x256, 0x257, 0x258,
0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, 0x23f, 0x240, 0x241, 0x242, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, 0x24f,
0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272, 0x250, 0x251, 0x252, 0x253, 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260,
0x273, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280,
0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28b, 0x28c, 0x28d, 0x28e, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272,
0x28f, 0x290, 0x292, 0x293, 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x273, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x284, 0x285,
0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a9, 0x2aa, 0x2ab,
0x2ac, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, 0x286, 0x287, 0x288, 0x289, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, 0x294, 0x295, 0x296, 0x298,
0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x299, 0x29a, 0x29b, 0x29c, 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a9, 0x2aa, 0x2ab,
0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9,
0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ac, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, 0x2bb, 0x2bd, 0x2be, 0x2bf,
0x2ea, 0x2ec, 0x2ed, 0x2ee, 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, 0x2c0, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2d0, 0x2d1, 0x2d2, 0x2d4,
0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, 0x306, 0x307, 0x309, 0x30a,
0x30b, 0x30d, 0x30e, 0x310, 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, 0x2d5, 0x2d6, 0x2d8, 0x2d9, 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, 0x2e5, 0x2e6, 0x2e8, 0x2e9,
0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, 0x328, 0x329, 0x32b, 0x32c, 0x2ea, 0x2ec, 0x2ed, 0x2ee, 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, 0x2fb, 0x2fc, 0x2fd, 0x2ff,
0x32e, 0x32f, 0x331, 0x332, 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e,
0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, 0x34c, 0x34d, 0x34f, 0x350, 0x300, 0x302, 0x303, 0x304, 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, 0x311, 0x312, 0x314, 0x315,
0x352, 0x353, 0x355, 0x357, 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, 0x317, 0x318, 0x31a, 0x31b, 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, 0x328, 0x329, 0x32b, 0x32c,
0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, 0x371, 0x373, 0x374, 0x376,
0x378, 0x379, 0x37b, 0x37c, 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, 0x32e, 0x32f, 0x331, 0x332, 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, 0x340, 0x341, 0x343, 0x344,
0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, 0x398, 0x39a, 0x39c, 0x39d, 0x346, 0x347, 0x349, 0x34a, 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, 0x358, 0x35a, 0x35b, 0x35d,
0x39f, 0x3a1, 0x3a2, 0x3a4, 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1,
0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x35e, 0x360, 0x361, 0x363, 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, 0x371, 0x373, 0x374, 0x376,
0x3c8, 0x3ca, 0x3cb, 0x3cd, 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, 0x378, 0x379, 0x37b, 0x37c, 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, 0x38b, 0x38d, 0x38e, 0x390,
0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ed, 0x3ef, 0x3f1,
0x3f3, 0x3f5, 0x3f6, 0x3f8, 0x3fa, 0x3fc, 0x3fe, 0x36c, 0x388 0x392, 0x393, 0x395, 0x397, 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, 0x3a6, 0x3a7, 0x3a9, 0x3ab,
0x3ac, 0x3ae, 0x3b0, 0x3b1, 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, 0x3c1, 0x3c3, 0x3c4, 0x3c6,
0x3c8, 0x3ca, 0x3cb, 0x3cd, 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, 0x3dd, 0x3df, 0x3e1, 0x3e3,
0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, 0x3fa, 0x3fc, 0x3fe, 0x36c
}; };
/* /*
* Write frequency/octave/keyon data to a channel * Write frequency/octave/keyon data to a channel
* [RH] This is totally different from the original MUS library code
* but matches exactly what DMX does. I haven't a clue why there are 284
* special bytes at the beginning of the table for the first few notes.
* That last byte in the table doesn't look right, either, but that's what
* it really is.
*/ */
void OPLio::OPLwriteFreq(uint channel, uint freq, uint octave, uint keyon) void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon)
{ {
int i; int octave = 0;
int j = (freq<<5) + octave; int j = (note << 5) + pitch;
i = 0;
if (j < 0) if (j < 0)
{ {
j = 0; j = 0;
} }
else if (j >= 0x11C) else if (j >= 284)
{ {
j -= 0x11C; j -= 284;
i = j / 0x180; octave = j / (32*12);
if (i > 7) if (octave > 7)
{ {
i = 7; octave = 7;
} }
j = (j % 0x180) + 0x11C; j = (j % (32*12)) + 284;
} }
i = frequencies[j] | (i << 10); int i = frequencies[j] | (octave << 10);
OPLwriteValue (0xA0, channel, (BYTE)i); OPLwriteValue (0xA0, channel, (BYTE)i);
OPLwriteValue (0xB0, channel, (BYTE)(i>>8)|(keyon<<5)); OPLwriteValue (0xB0, channel, (BYTE)(i>>8)|(keyon<<5));
@ -277,20 +298,12 @@ void OPLio::OPLshutup(void)
/* /*
* Initialize hardware upon startup * Initialize hardware upon startup
*/ */
int OPLio::OPLinit(uint numchips, uint rate) int OPLio::OPLinit(uint numchips)
{ {
if (!YM3812Init (numchips, 3579545, rate)) if (!YM3812Init (numchips, 3579545, int(OPL_SAMPLE_RATE)))
{ {
uint i; OPLchannels = OPL2CHANNELS * numchips;
OPLwriteInitState();
OPLchannels = OPL2CHANNELS*numchips;
for (i = 0; i < numchips; ++i)
{
OPLwriteReg (i, 0x01, 0x20); // enable Waveform Select
OPLwriteReg (i, 0x0B, 0x40); // turn off CSW mode
OPLwriteReg (i, 0xBD, 0x00); // set vibrato/tremolo depth to low, set melodic mode
}
OPLshutup();
return 0; return 0;
} }
else else
@ -299,6 +312,17 @@ int OPLio::OPLinit(uint numchips, uint rate)
} }
} }
void OPLio::OPLwriteInitState()
{
for (uint i = 0; i < OPLchannels / OPL2CHANNELS; ++i)
{
OPLwriteReg (i, 0x01, 0x20); // enable Waveform Select
OPLwriteReg (i, 0x0B, 0x40); // turn off CSW mode
OPLwriteReg (i, 0xBD, 0x00); // set vibrato/tremolo depth to low, set melodic mode
}
OPLshutup();
}
/* /*
* Deinitialize hardware before shutdown * Deinitialize hardware before shutdown
*/ */

View file

@ -40,6 +40,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "m_swap.h" #include "m_swap.h"
#include "w_wad.h" #include "w_wad.h"
#include "fmopl.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -105,7 +106,7 @@ OPLMIDIDevice::~OPLMIDIDevice()
int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{ {
if (io == NULL || io->OPLinit(TwoChips + 1, uint(OPL_SAMPLE_RATE))) if (io == NULL || io->OPLinit(TwoChips + 1))
{ {
return 1; return 1;
} }
@ -209,6 +210,7 @@ int OPLMIDIDevice::SetTimeDiv(int timediv)
void OPLMIDIDevice::CalcTickRate() void OPLMIDIDevice::CalcTickRate()
{ {
SamplesPerTick = OPL_SAMPLE_RATE / (1000000.0 / Tempo) / Division; SamplesPerTick = OPL_SAMPLE_RATE / (1000000.0 / Tempo) / Division;
io->SetClockRate(SamplesPerTick);
} }
//========================================================================== //==========================================================================

View file

@ -0,0 +1,372 @@
/*
** music_opl_mididevice.cpp
** Writes raw OPL commands from the emulated OPL MIDI output to disk.
**
**---------------------------------------------------------------------------
** Copyright 2008 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "i_musicinterns.h"
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "w_wad.h"
#include "fmopl.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// CODE --------------------------------------------------------------------
//==========================================================================
//
// OPLDumperMIDIDevice Constructor
//
//==========================================================================
OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename)
{
// Replace the standard OPL device with a disk writer.
delete io;
io = new DiskWriterIO(filename);
}
//==========================================================================
//
// OPLDumperMIDIDevice Destructor
//
//==========================================================================
OPLDumperMIDIDevice::~OPLDumperMIDIDevice()
{
}
//==========================================================================
//
// OPLDumperMIDIDevice :: Resume
//
//==========================================================================
int OPLDumperMIDIDevice::Resume()
{
int time;
time = PlayTick();
while (time != 0)
{
io->WriteDelay(time);
time = PlayTick();
}
return 0;
}
//==========================================================================
//
// OPLDumperMIDIDevice :: Stop
//
//==========================================================================
void OPLDumperMIDIDevice::Stop()
{
}
//==========================================================================
//
// DiskWriterIO Constructor
//
//==========================================================================
DiskWriterIO::DiskWriterIO(const char *filename)
: Filename(filename)
{
}
//==========================================================================
//
// DiskWriterIO Destructor
//
//==========================================================================
DiskWriterIO::~DiskWriterIO()
{
OPLdeinit();
}
//==========================================================================
//
// DiskWriterIO :: OPLinit
//
//==========================================================================
int DiskWriterIO::OPLinit(uint numchips)
{
// If the file extension is unknown or not present, the default format
// is RAW. Otherwise, you can use DRO.
if (Filename.Len() < 5 || stricmp(&Filename[Filename.Len() - 4], ".dro") != 0)
{
Format = FMT_RDOS;
}
else
{
Format = FMT_DOSBOX;
}
File = fopen(Filename, "wb");
if (File == NULL)
{
Printf("Could not open %s for writing.\n", Filename.GetChars());
return -1;
}
if (Format == FMT_RDOS)
{
fwrite("RAWADATA\0", 1, 10, File);
NeedClockRate = true;
}
else
{
fwrite("DBRAWOPL"
"\0\0" // Minor version number
"\1\0" // Major version number
"\0\0\0\0" // Total milliseconds
"\0\0\0", // Total data
1, 20, File);
if (numchips == 1)
{
fwrite("\0\0\0", 1, 4, File); // Single OPL-2
}
else
{
fwrite("\2\0\0", 1, 4, File); // Dual OPL-2
}
NeedClockRate = false;
}
TimePerTick = 0;
TickMul = 1;
CurTime = 0;
CurIntTime = 0;
CurChip = 0;
OPLchannels = OPL2CHANNELS * numchips;
OPLwriteInitState();
return 0;
}
//==========================================================================
//
// DiskWriterIO :: OPLdeinit
//
//==========================================================================
void DiskWriterIO::OPLdeinit()
{
if (File != NULL)
{
if (Format == FMT_RDOS)
{
WORD endmark = 65535;
fwrite(&endmark, 2, 1, File);
}
else
{
long where_am_i = ftell(File);
DWORD len[2];
fseek(File, 12, SEEK_SET);
len[0] = LittleLong(CurIntTime);
len[1] = LittleLong(where_am_i - 24);
fwrite(len, 4, 2, File);
}
fclose(File);
File = NULL;
}
}
//==========================================================================
//
// DiskWriterIO :: OPLwriteReg
//
//==========================================================================
void DiskWriterIO::OPLwriteReg(int which, uint reg, uchar data)
{
SetChip(which);
if (Format == FMT_RDOS)
{
if (reg != 0 && reg != 2 && (reg != 255 || data != 255))
{
BYTE cmd[2] = { data, reg };
fwrite(cmd, 1, 2, File);
}
}
else
{
BYTE cmd[3] = { 4, reg, data };
fwrite (cmd + (reg > 4), 1, 3 - (reg > 4), File);
}
}
//==========================================================================
//
// DiskWriterIO :: SetChip
//
//==========================================================================
void DiskWriterIO :: SetChip(int chipnum)
{
assert(chipnum == 0 || chipnum == 1);
if (chipnum != CurChip)
{
CurChip = chipnum;
if (Format == FMT_RDOS)
{
BYTE switcher[2] = { chipnum + 1, 2 };
fwrite(switcher, 1, 2, File);
}
else
{
BYTE switcher = chipnum + 2;
fwrite(&switcher, 1, 1, File);
}
}
}
//==========================================================================
//
// DiskWriterIO :: SetClockRate
//
//==========================================================================
void DiskWriterIO::SetClockRate(double samples_per_tick)
{
TimePerTick = samples_per_tick / OPL_SAMPLE_RATE * 1000.0;
if (Format == FMT_RDOS)
{
double clock_rate;
int clock_mul;
WORD clock_word;
clock_rate = samples_per_tick * ADLIB_CLOCK_MUL;
clock_mul = 1;
// The RDos raw format's clock rate is stored in a word. Therefore,
// the longest tick that can be stored is only ~55 ms.
while (clock_rate / clock_mul + 0.5 > 65535.0)
{
clock_mul++;
}
clock_word = WORD(clock_rate / clock_mul + 0.5);
if (NeedClockRate)
{ // Set the initial clock rate.
clock_word = LittleShort(clock_word);
fseek(File, 8, SEEK_SET);
fwrite(&clock_word, 2, 1, File);
fseek(File, 0, SEEK_END);
NeedClockRate = false;
}
else
{ // Change the clock rate in the middle of the song.
BYTE clock_change[4] = { 0, 2, clock_word & 255, clock_word >> 8 };
fwrite(clock_change, 1, 4, File);
}
}
}
//==========================================================================
//
// DiskWriterIO :: WriteDelay
//
//==========================================================================
void DiskWriterIO :: WriteDelay(int ticks)
{
if (ticks <= 0)
{
return;
}
if (Format == FMT_RDOS)
{ // RDos raw has very precise delays but isn't very efficient at
// storing long delays.
BYTE delay[2];
ticks *= TickMul;
delay[1] = 0;
while (ticks > 255)
{
ticks -= 255;
delay[0] = 255;
fwrite(delay, 1, 2, File);
}
delay[0] = BYTE(ticks);
fwrite(delay, 1, 2, File);
}
else
{ // DosBox only has millisecond-precise delays.
int delay;
CurTime += TimePerTick * ticks;
delay = int(CurTime + 0.5) - CurIntTime;
CurIntTime += delay;
while (delay > 65536)
{
BYTE cmd[3] = { 1, 255, 255 };
fwrite(cmd, 1, 2, File);
delay -= 65536;
}
delay--;
if (delay <= 255)
{
BYTE cmd[2] = { 0, BYTE(delay) };
fwrite(cmd, 1, 2, File);
}
else
{
assert(delay <= 65535);
BYTE cmd[3] = { 1, BYTE(delay & 255), BYTE(delay >> 8) };
fwrite(cmd, 1, 3, File);
}
}
}

View file

@ -130,7 +130,7 @@ struct OP2instrEntry {
}; };
#define FL_FIXED_PITCH 0x0001 // note has fixed pitch (see below) #define FL_FIXED_PITCH 0x0001 // note has fixed pitch (see below)
#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) #define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only)
#define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one #define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one
@ -160,7 +160,7 @@ struct OPLdata {
}; };
struct OPLio { struct OPLio {
virtual ~OPLio() {} virtual ~OPLio();
void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2); void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2);
void OPLwriteValue(uint regbase, uint channel, uchar value); void OPLwriteValue(uint regbase, uint channel, uchar value);
@ -171,14 +171,43 @@ struct OPLio {
void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan); void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan);
void OPLwriteInstrument(uint channel, struct OPL2instrument *instr); void OPLwriteInstrument(uint channel, struct OPL2instrument *instr);
void OPLshutup(void); void OPLshutup(void);
void OPLwriteInitState();
virtual int OPLinit(uint numchips, uint rate); virtual int OPLinit(uint numchips);
virtual void OPLdeinit(void); virtual void OPLdeinit(void);
virtual void OPLwriteReg(int which, uint reg, uchar data); virtual void OPLwriteReg(int which, uint reg, uchar data);
virtual void SetClockRate(double samples_per_tick);
virtual void WriteDelay(int ticks);
uint OPLchannels; uint OPLchannels;
}; };
struct DiskWriterIO : public OPLio
{
DiskWriterIO(const char *filename);
~DiskWriterIO();
int OPLinit(uint numchips);
void OPLdeinit();
void OPLwriteReg(int which, uint reg, uchar data);
void SetClockRate(double samples_per_tick);
void WriteDelay(int ticks);
void SetChip(int chipnum);
FILE *File;
FString Filename;
int Format;
bool NeedClockRate;
double TimePerTick; // In milliseconds
double CurTime;
int CurIntTime;
int TickMul;
int CurChip;
enum { FMT_RDOS, FMT_DOSBOX };
};
struct musicBlock { struct musicBlock {
musicBlock(); musicBlock();
~musicBlock(); ~musicBlock();
@ -193,8 +222,6 @@ struct musicBlock {
ulong MLtime; ulong MLtime;
int playTick();
void OPLplayNote(uint channel, uchar note, int volume); void OPLplayNote(uint channel, uchar note, int volume);
void OPLreleaseNote(uint channel, uchar note); void OPLreleaseNote(uint channel, uchar note);
void OPLpitchWheel(uint channel, int pitch); void OPLpitchWheel(uint channel, int pitch);
@ -254,4 +281,7 @@ enum MUSctrl {
ctrlResetCtrls ctrlResetCtrls
}; };
#define OPL_SAMPLE_RATE 49716.0
#define ADLIB_CLOCK_MUL 24.0
#endif // __MUSLIB_H_ #endif // __MUSLIB_H_

View file

@ -79,7 +79,7 @@ void OPLmusicBlock::ResetChips ()
TwoChips = !opl_onechip; TwoChips = !opl_onechip;
Serialize(); Serialize();
io->OPLdeinit (); io->OPLdeinit ();
io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE)); io->OPLinit (TwoChips + 1);
Unserialize(); Unserialize();
} }
@ -91,7 +91,7 @@ void OPLmusicBlock::Restart()
playingcount = 0; playingcount = 0;
} }
OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSamples) OPLmusicFile::OPLmusicFile (FILE *file, char *musiccache, int len)
: ScoreLen (len) : ScoreLen (len)
{ {
if (io == NULL) if (io == NULL)
@ -115,29 +115,15 @@ OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSampl
memcpy(scoredata, &musiccache[0], len); memcpy(scoredata, &musiccache[0], len);
} }
if (io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE))) if (io->OPLinit (TwoChips + 1))
{ {
delete[] scoredata; delete[] scoredata;
scoredata = NULL; scoredata = NULL;
return; return;
} }
// Check for MUS format
if (*(DWORD *)scoredata == MAKE_ID('M','U','S',0x1a))
{
FWadLump data = Wads.OpenLumpName ("GENMIDI");
if (0 != OPLloadBank (data))
{
delete[] scoredata;
scoredata = NULL;
return;
}
BlockForStats = this;
SamplesPerTick = OPL_SAMPLE_RATE / 140.0;
RawPlayer = NotRaw;
}
// Check for RDosPlay raw OPL format // Check for RDosPlay raw OPL format
else if (((DWORD *)scoredata)[0] == MAKE_ID('R','A','W','A') && if (((DWORD *)scoredata)[0] == MAKE_ID('R','A','W','A') &&
((DWORD *)scoredata)[1] == MAKE_ID('D','A','T','A')) ((DWORD *)scoredata)[1] == MAKE_ID('D','A','T','A'))
{ {
RawPlayer = RDosPlay; RawPlayer = RDosPlay;
@ -145,7 +131,16 @@ OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSampl
{ // A clock speed of 0 is bad { // A clock speed of 0 is bad
*(WORD *)(scoredata + 8) = 0xFFFF; *(WORD *)(scoredata + 8) = 0xFFFF;
} }
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(scoredata + 8)) / 1193180.0; SamplesPerTick = LittleShort(*(WORD *)(scoredata + 8)) / ADLIB_CLOCK_MUL;
}
// Check for DosBox OPL dump
else if (((DWORD *)scoredata)[0] == MAKE_ID('D','B','R','A') &&
((DWORD *)scoredata)[1] == MAKE_ID('W','O','P','L') &&
((DWORD *)scoredata)[2] == MAKE_ID(0,0,1,0))
{
RawPlayer = DosBox;
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
ScoreLen = MIN<int>(len - 24, LittleLong(((DWORD *)scoredata)[4]));
} }
// Check for modified IMF format (includes a header) // Check for modified IMF format (includes a header)
else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') && else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') &&
@ -202,14 +197,16 @@ void OPLmusicFile::SetLooping (bool loop)
void OPLmusicFile::Restart () void OPLmusicFile::Restart ()
{ {
OPLmusicBlock::Restart(); OPLmusicBlock::Restart();
if (RawPlayer == NotRaw) WhichChip = 0;
{ if (RawPlayer == RDosPlay)
score = scoredata + ((MUSheader *)scoredata)->scoreStart;
}
else if (RawPlayer == RDosPlay)
{ {
score = scoredata + 10; score = scoredata + 10;
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(scoredata + 8)) / 1193180.0; SamplesPerTick = LittleShort(*(WORD *)(scoredata + 8)) / ADLIB_CLOCK_MUL;
}
else if (RawPlayer == DosBox)
{
score = scoredata + 24;
SamplesPerTick = OPL_SAMPLE_RATE / 1000;
} }
else if (RawPlayer == IMF) else if (RawPlayer == IMF)
{ {
@ -226,6 +223,7 @@ void OPLmusicFile::Restart ()
score += 4; // Skip song length score += 4; // Skip song length
} }
} }
io->SetClockRate(SamplesPerTick);
} }
bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
@ -289,6 +287,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
else else
{ {
prevEnded = false; prevEnded = false;
io->WriteDelay(next);
NextTickIn += SamplesPerTick * next; NextTickIn += SamplesPerTick * next;
assert (NextTickIn >= 0); assert (NextTickIn >= 0);
MLtime += next; MLtime += next;
@ -303,11 +302,7 @@ int OPLmusicFile::PlayTick ()
{ {
BYTE reg, data; BYTE reg, data;
if (RawPlayer == NotRaw) if (RawPlayer == RDosPlay)
{
return playTick ();
}
else if (RawPlayer == RDosPlay)
{ {
while (score < scoredata + ScoreLen) while (score < scoredata + ScoreLen)
{ {
@ -325,9 +320,18 @@ int OPLmusicFile::PlayTick ()
case 2: // Speed change or OPL3 switch case 2: // Speed change or OPL3 switch
if (data == 0) if (data == 0)
{ {
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(score)) / 1193180.0; SamplesPerTick = LittleShort(*(WORD *)(score)) / ADLIB_CLOCK_MUL;
io->SetClockRate(SamplesPerTick);
score += 2; score += 2;
} }
else if (data == 1)
{
WhichChip = 0;
}
else if (data == 2)
{
WhichChip = 1;
}
break; break;
case 0xFF: // End of song case 0xFF: // End of song
@ -338,11 +342,55 @@ int OPLmusicFile::PlayTick ()
break; break;
default: // It's something to stuff into the OPL chip default: // It's something to stuff into the OPL chip
io->OPLwriteReg (0, reg, data); if (WhichChip == 0 || TwoChips)
{
io->OPLwriteReg(WhichChip, reg, data);
}
break; break;
} }
} }
} }
else if (RawPlayer == DosBox)
{
while (score < scoredata + ScoreLen)
{
reg = *score++;
if (reg == 4)
{
reg = *score++;
data = *score++;
}
else if (reg == 0)
{ // One-byte delay
return *score++ + 1;
}
else if (reg == 1)
{ // Two-byte delay
int delay = score[0] + (score[1] << 8) + 1;
score += 2;
return delay;
}
else if (reg == 2)
{ // Select OPL chip 0
WhichChip = 0;
continue;
}
else if (reg == 3)
{ // Select OPL chip 1
WhichChip = 1;
continue;
}
else
{
data = *score++;
}
if (WhichChip == 0 || TwoChips)
{
io->OPLwriteReg(WhichChip, reg, data);
}
}
}
else if (RawPlayer == IMF) else if (RawPlayer == IMF)
{ {
WORD delay = 0; WORD delay = 0;
@ -398,161 +446,33 @@ ADD_STAT (opl)
} }
} }
struct DiskWriterIO : public OPLio OPLmusicFile::OPLmusicFile(const OPLmusicFile *source, const char *filename)
{ {
DiskWriterIO () : File(NULL) {} ScoreLen = source->ScoreLen;
virtual ~DiskWriterIO () { if (File != NULL) fclose (File); } scoredata = new BYTE[ScoreLen];
int OPLinit(const char *filename); memcpy(scoredata, source->scoredata, ScoreLen);
virtual void OPLwriteReg(int which, uint reg, uchar data); SamplesPerTick = source->SamplesPerTick;
RawPlayer = source->RawPlayer;
FILE *File; score = source->score;
bool RawFormat; TwoChips = source->TwoChips;
}; WhichChip = 0;
if (io != NULL)
class OPLmusicWriter : public musicBlock
{
public:
OPLmusicWriter (const char *songname, const char *filename);
~OPLmusicWriter ();
void Go ();
bool SharingData;
FILE *File;
};
OPLmusicWriter::OPLmusicWriter (const char *songname, const char *filename)
{
io = NULL;
SharingData = true;
if (songname == NULL)
{ {
if (BlockForStats == NULL) delete io;
{
Printf ("Not currently playing an OPL song.\n");
return;
}
scoredata = BlockForStats->scoredata;
OPLinstruments = BlockForStats->OPLinstruments;
}
else
{
SharingData = false;
int lumpnum = Wads.CheckNumForName (songname, ns_music);
if (lumpnum == -1)
{
Printf ("Song %s is unknown.\n", songname);
return;
}
FWadLump song = Wads.OpenLumpNum (lumpnum);
scoredata = new BYTE [song.GetLength ()];
song.Read (scoredata, song.GetLength());
FWadLump genmidi = Wads.OpenLumpName ("GENMIDI");
OPLloadBank (genmidi);
}
io = new DiskWriterIO ();
if (((DiskWriterIO *)io)->OPLinit (filename) == 0)
{
OPLplayMusic (127);
score = scoredata + ((MUSheader *)scoredata)->scoreStart;
Go ();
} }
io = new DiskWriterIO(filename);
io->OPLinit(TwoChips);
Restart();
} }
OPLmusicWriter::~OPLmusicWriter () void OPLmusicFile::Dump()
{ {
if (io != NULL) delete io; int time;
if (!SharingData)
time = PlayTick();
while (time != 0)
{ {
delete scoredata; io->WriteDelay(time);
} time = PlayTick();
else
{
OPLinstruments = NULL;
} }
} }
void OPLmusicWriter::Go ()
{
int next;
while ((next = playTick()) != 0)
{
MLtime += next;
while (next > 255)
{
io->OPLwriteReg (10, 0, 255);
next -= 255;
}
io->OPLwriteReg (10, 0, next);
}
io->OPLwriteReg (10, 0xFF, 0xFF);
}
int DiskWriterIO::OPLinit (const char *filename)
{
int numchips;
//size_t namelen;
// If the file extension is unknown or not present, the default format
// is RAW. Otherwise, you can use DRO. But not right now. The DRO format
// is still in a state of flux, so I don't want the hassle.
//namelen = strlen (filename);
RawFormat = 1; //(namelen < 5 || stricmp (filename + namelen - 4, ".dro") != 0);
File = fopen (filename, "wb");
if (File == NULL)
{
return -1;
}
if (RawFormat)
{
fwrite ("RAWADATA", 1, 8, File);
WORD clock = LittleShort(17045/2);
fwrite (&clock, 2, 1, File);
numchips = 1;
}
else
{
numchips = 2;
}
OPLchannels = OPL2CHANNELS*numchips;
for (int i = 0; i < numchips; ++i)
{
OPLwriteReg (i, 0x01, 0x20); // enable Waveform Select
OPLwriteReg (i, 0x0B, 0x40); // turn off CSW mode
OPLwriteReg (i, 0xBD, 0x00); // set vibrato/tremolo depth to low, set melodic mode
}
OPLshutup();
return 0;
}
void DiskWriterIO::OPLwriteReg(int which, uint reg, uchar data)
{
if (which == 10 || (reg != 0 && reg != 2 && reg != 0xFF))
{
struct { BYTE data, reg; } out = { data, reg };
fwrite (&out, 2, 1, File);
}
else
{
reg = reg;
}
}
CCMD (writeopl)
{
if (argv.argc() == 2)
{
OPLmusicWriter writer (NULL, argv[1]);
}
else if (argv.argc() == 3)
{
OPLmusicWriter writer (argv[1], argv[2]);
}
else
{
Printf ("Usage: writeopl [songname] <filename>");
}
}

View file

@ -9,13 +9,11 @@
#include "muslib.h" #include "muslib.h"
#include "files.h" #include "files.h"
#define OPL_SAMPLE_RATE 49716.0
class OPLmusicBlock : public musicBlock class OPLmusicBlock : public musicBlock
{ {
public: public:
OPLmusicBlock(); OPLmusicBlock();
~OPLmusicBlock(); virtual ~OPLmusicBlock();
bool ServiceStream(void *buff, int numbytes); bool ServiceStream(void *buff, int numbytes);
void ResetChips(); void ResetChips();
@ -43,16 +41,20 @@ protected:
class OPLmusicFile : public OPLmusicBlock class OPLmusicFile : public OPLmusicBlock
{ {
public: public:
OPLmusicFile(FILE *file, char *musiccache, int len, int maxSamples); OPLmusicFile(FILE *file, char *musiccache, int len);
~OPLmusicFile(); OPLmusicFile(const OPLmusicFile *source, const char *filename);
virtual ~OPLmusicFile();
bool IsValid() const; bool IsValid() const;
void SetLooping(bool loop); void SetLooping(bool loop);
void Restart(); void Restart();
void Dump();
protected: protected:
OPLmusicFile() {}
int PlayTick(); int PlayTick();
enum { NotRaw, RDosPlay, IMF } RawPlayer; enum { RDosPlay, IMF, DosBox } RawPlayer;
int ScoreLen; int ScoreLen;
int WhichChip;
}; };

View file

@ -556,7 +556,7 @@ void FBehavior::StaticLoadDefaultModules ()
while ((lump = Wads.FindLump ("LOADACS", &lastlump)) != -1) while ((lump = Wads.FindLump ("LOADACS", &lastlump)) != -1)
{ {
FScanner sc(lump, "LOADACS"); FScanner sc(lump);
while (sc.GetString()) while (sc.GetString())
{ {
int acslump = Wads.CheckNumForName (sc.String, ns_acslibrary); int acslump = Wads.CheckNumForName (sc.String, ns_acslibrary);

View file

@ -228,7 +228,7 @@ void P_RunEffect (AActor *actor, int effects)
particle_t *particle; particle_t *particle;
int i; int i;
if ((effects & FX_ROCKET) && cl_rockettrails) if ((effects & FX_ROCKET) && (cl_rockettrails & 1))
{ {
// Rocket trail // Rocket trail
@ -274,7 +274,7 @@ void P_RunEffect (AActor *actor, int effects)
break; break;
} }
} }
if ((effects & FX_GRENADE) && (cl_rockettrails)) if ((effects & FX_GRENADE) && (cl_rockettrails & 1))
{ {
// Grenade trail // Grenade trail

View file

@ -1884,7 +1884,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
} }
else else
{ {
actor->SetState (actor->SpawnState); actor->SetIdle();
actor->flags &= ~MF_INCHASE; actor->flags &= ~MF_INCHASE;
return; return;
} }
@ -1945,7 +1945,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
if (newgoal != NULL && delay != 0) if (newgoal != NULL && delay != 0)
{ {
actor->flags4 |= MF4_INCOMBAT; actor->flags4 |= MF4_INCOMBAT;
actor->SetState (actor->SpawnState); actor->SetIdle();
} }
actor->flags &= ~MF_INCHASE; actor->flags &= ~MF_INCHASE;
actor->goal = newgoal; actor->goal = newgoal;

View file

@ -90,13 +90,20 @@ void P_UnPredictPlayer ();
extern fixed_t FloatBobOffsets[64]; extern fixed_t FloatBobOffsets[64];
extern AActor *MissileActor; extern AActor *MissileActor;
void P_SpawnPlayer (mapthing2_t* mthing, bool tempplayer=false); APlayerPawn *P_SpawnPlayer (mapthing2_t* mthing, bool tempplayer=false);
void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move);
int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); int P_FaceMobj (AActor *source, AActor *target, angle_t *delta);
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax); bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax);
AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, bool hit=false, bool temporary=false); enum EPuffFlags
{
PF_HITTHING = 1,
PF_MELEERANGE = 2,
PF_TEMPORARY = 4
};
AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0);
void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator);
void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
@ -307,8 +314,8 @@ bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, boo
extern AActor* linetarget; // who got hit (or NULL) extern AActor* linetarget; // who got hit (or NULL)
fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange=0, bool forcenosmart=false); fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange=0, bool forcenosmart=false);
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, bool ismelee = false);
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false);
void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version

View file

@ -3070,7 +3070,7 @@ static bool CheckForSpectral (FTraceResults &res)
} }
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
int pitch, int damage, FName damageType, const PClass *pufftype) int pitch, int damage, FName damageType, const PClass *pufftype, bool ismeleeattack)
{ {
fixed_t vx, vy, vz, shootz; fixed_t vx, vy, vz, shootz;
FTraceResults trace; FTraceResults trace;
@ -3079,6 +3079,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
bool hitGhosts; bool hitGhosts;
bool killPuff = false; bool killPuff = false;
AActor *puff = NULL; AActor *puff = NULL;
int flags = ismeleeattack? PF_MELEERANGE : 0;
angle >>= ANGLETOFINESHIFT; angle >>= ANGLETOFINESHIFT;
pitch = (angle_t)(pitch) >> ANGLETOFINESHIFT; pitch = (angle_t)(pitch) >> ANGLETOFINESHIFT;
@ -3114,7 +3115,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
} }
if (puffDefaults->flags3 & MF3_ALWAYSPUFF) if (puffDefaults->flags3 & MF3_ALWAYSPUFF)
{ // Spawn the puff anyway { // Spawn the puff anyway
puff = P_SpawnPuff (pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2); puff = P_SpawnPuff (pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, flags);
} }
else else
{ {
@ -3133,7 +3134,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
fixed_t closer = trace.Distance - 4*FRACUNIT; fixed_t closer = trace.Distance - 4*FRACUNIT;
puff = P_SpawnPuff (pufftype, t1->x + FixedMul (vx, closer), puff = P_SpawnPuff (pufftype, t1->x + FixedMul (vx, closer),
t1->y + FixedMul (vy, closer), t1->y + FixedMul (vy, closer),
shootz + FixedMul (vz, closer), angle - ANG90, 0); shootz + FixedMul (vz, closer), angle - ANG90, 0, flags);
} }
// [RH] Spawn a decal // [RH] Spawn a decal
@ -3186,7 +3187,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
(trace.Actor->flags & MF_NOBLOOD) || (trace.Actor->flags & MF_NOBLOOD) ||
(trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) (trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT)))
{ {
puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true); puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING);
} }
if (!(GetDefaultByType(pufftype)->flags3&MF3_BLOODLESSIMPACT)) if (!(GetDefaultByType(pufftype)->flags3&MF3_BLOODLESSIMPACT))
{ {
@ -3233,7 +3234,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
{ {
// Since the puff is the damage inflictor we need it here // Since the puff is the damage inflictor we need it here
// regardless of whether it is displayed or not. // regardless of whether it is displayed or not.
puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true, true); puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY);
killPuff = true; killPuff = true;
} }
P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, flags); P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, flags);
@ -3244,7 +3245,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
if (puff == NULL) if (puff == NULL)
{ // Spawn puff just to get a mass for the splash { // Spawn puff just to get a mass for the splash
puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true, true); puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY);
killPuff = true; killPuff = true;
} }
SpawnDeepSplash (t1, trace, puff, vx, vy, vz); SpawnDeepSplash (t1, trace, puff, vx, vy, vz);
@ -3259,7 +3260,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
} }
AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
int pitch, int damage, FName damageType, FName pufftype) int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack)
{ {
const PClass * type = PClass::FindClass(pufftype); const PClass * type = PClass::FindClass(pufftype);
if (type == NULL) if (type == NULL)
@ -3268,7 +3269,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
} }
else else
{ {
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type); return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack);
} }
return NULL; return NULL;
} }
@ -3535,7 +3536,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
if ((RailHits[i].HitActor->flags & MF_NOBLOOD) || if ((RailHits[i].HitActor->flags & MF_NOBLOOD) ||
(RailHits[i].HitActor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE))) (RailHits[i].HitActor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE)))
{ {
if (puffclass != NULL) P_SpawnPuff (puffclass, x, y, z, source->angle - ANG180, 1, true); if (puffclass != NULL) P_SpawnPuff (puffclass, x, y, z, source->angle - ANG180, 1, PF_HITTHING);
} }
else else
{ {

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,7 @@
#include "p_lnspec.h" #include "p_lnspec.h"
#include "v_palette.h" #include "v_palette.h"
#include "c_console.h" #include "c_console.h"
#include "c_cvars.h"
#include "p_acs.h" #include "p_acs.h"
#include "vectors.h" #include "vectors.h"
#include "announcer.h" #include "announcer.h"
@ -64,7 +65,7 @@
#include "fragglescript/t_fs.h" #include "fragglescript/t_fs.h"
extern void P_SpawnMapThing (mapthing2_t *mthing, int position); extern AActor *P_SpawnMapThing (mapthing2_t *mthing, int position);
extern bool P_LoadBuildMap (BYTE *mapdata, size_t len, mapthing2_t **things, int *numthings); extern bool P_LoadBuildMap (BYTE *mapdata, size_t len, mapthing2_t **things, int *numthings);
extern void P_LoadTranslator(const char *lump); extern void P_LoadTranslator(const char *lump);
@ -283,7 +284,7 @@ MapData *P_OpenMapData(const char * mapname)
if (lumpfile != nextfile) if (lumpfile != nextfile)
{ {
// The following lump is from a different file so whatever this is, // The following lump is from a different file so whatever this is,
// it is not a multi-lump Doom level. // it is not a multi-lump Doom level so let's assume it is a Build map.
return map; return map;
} }
@ -383,6 +384,13 @@ MapData *P_OpenMapData(const char * mapname)
return map; return map;
} }
bool P_CheckMapData(const char *mapname)
{
MapData *mapd = P_OpenMapData(mapname);
if (mapd == NULL) return false;
delete mapd;
return true;
}
//=========================================================================== //===========================================================================
// //
@ -1251,6 +1259,24 @@ void P_LoadNodes (MapData * map)
delete[] mnp; delete[] mnp;
} }
//===========================================================================
//
// SpawnMapThing
//
//===========================================================================
CVAR(Bool, dumpspawnedthings, false, 0)
static void SpawnMapThing(int index, mapthing2_t *mt, int position)
{
AActor *spawned = P_SpawnMapThing(mt, position);
if (dumpspawnedthings)
{
Printf("%5d: (%5d, %5d, %5d), doomednum = %5d, flags = %04x, type = %s\n",
index, mt->x, mt->y, mt->z, mt->type, mt->flags,
spawned? spawned->GetClass()->TypeName.GetChars() : "(none)");
}
T_AddSpawnedThing(spawned);
}
//=========================================================================== //===========================================================================
// //
@ -1312,7 +1338,7 @@ void P_LoadThings (MapData * map, int position)
mt2.angle = LittleShort(mt->angle); mt2.angle = LittleShort(mt->angle);
mt2.type = LittleShort(mt->type); mt2.type = LittleShort(mt->type);
P_SpawnMapThing (&mt2, position); SpawnMapThing (i, &mt2, position);
} }
delete [] mtp; delete [] mtp;
} }
@ -1756,7 +1782,7 @@ void P_LoadThings2 (MapData * map, int position)
for (i=0, mt = (mapthing2_t*)mtp; i < numthings; i++,mt++) for (i=0, mt = (mapthing2_t*)mtp; i < numthings; i++,mt++)
{ {
P_SpawnMapThing (mt, position); SpawnMapThing (i, mt, position);
} }
delete[] mtp; delete[] mtp;
} }
@ -3869,7 +3895,7 @@ void P_SetupLevel (char *lumpname, int position)
{ {
for (i = 0; i < numbuildthings; ++i) for (i = 0; i < numbuildthings; ++i)
{ {
P_SpawnMapThing (&buildthings[i], 0); SpawnMapThing (i, &buildthings[i], 0);
} }
delete[] buildthings; delete[] buildthings;
} }

View file

@ -81,6 +81,7 @@ struct MapData
}; };
MapData * P_OpenMapData(const char * mapname); MapData * P_OpenMapData(const char * mapname);
bool P_CheckMapData(const char * mapname);
// NOT called by W_Ticker. Fixme. [RH] Is that bad? // NOT called by W_Ticker. Fixme. [RH] Is that bad?
// //

View file

@ -370,7 +370,7 @@ FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad)
thisframe.Time = ((max - min + 1) << 16) | min; thisframe.Time = ((max - min + 1) << 16) | min;
} }
else else
{ {
thisframe.Time = 0; // Shush, GCC. thisframe.Time = 0; // Shush, GCC.
sc.ScriptError ("Must specify a duration for switch frame"); sc.ScriptError ("Must specify a duration for switch frame");
} }
@ -475,6 +475,9 @@ static int TryFindSwitch (side_t *side, int Where)
// //
bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
{ {
// if this line is one sided this function must always return success.
if (line->sidenum[0] == NO_SIDE || line->sidenum[1] == NO_SIDE) return true;
fixed_t checktop; fixed_t checktop;
fixed_t checkbot; fixed_t checkbot;
side_t *side = &sides[line->sidenum[sideno]]; side_t *side = &sides[line->sidenum[sideno]];

View file

@ -267,7 +267,7 @@ void P_InitTerrainTypes ()
lastlump = 0; lastlump = 0;
while (-1 != (lump = Wads.FindLump ("TERRAIN", &lastlump)) ) while (-1 != (lump = Wads.FindLump ("TERRAIN", &lastlump)) )
{ {
FScanner sc(lump, "TERRAIN"); FScanner sc(lump);
ParseOuter (sc); ParseOuter (sc);
} }
Splashes.ShrinkToFit (); Splashes.ShrinkToFit ();

View file

@ -422,6 +422,7 @@ BEGIN_STATELESS_DEFAULTS (APlayerPawn, Any, -1, 0)
PROP_PlayerPawn_SideMove2 (FRACUNIT) PROP_PlayerPawn_SideMove2 (FRACUNIT)
PROP_PlayerPawn_ColorRange (0, 0) PROP_PlayerPawn_ColorRange (0, 0)
PROP_PlayerPawn_SoundClass ("player") PROP_PlayerPawn_SoundClass ("player")
PROP_PlayerPawn_Face ("None")
PROP_PlayerPawn_MorphWeapon ("None") PROP_PlayerPawn_MorphWeapon ("None")
END_DEFAULTS END_DEFAULTS

View file

@ -289,7 +289,7 @@ static void R_InitAnimDefs ()
while ((lump = Wads.FindLump ("ANIMDEFS", &lastlump)) != -1) while ((lump = Wads.FindLump ("ANIMDEFS", &lastlump)) != -1)
{ {
FScanner sc(lump, "ANIMDEFS"); FScanner sc(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {

View file

@ -1103,7 +1103,7 @@ class FPlayerSkin
{ {
public: public:
char name[17]; // 16 chars + NULL char name[17]; // 16 chars + NULL
char face[3]; char face[4]; // 3 chars ([MH] + NULL so can use as a C string)
BYTE gender; // This skin's gender (not really used) BYTE gender; // This skin's gender (not really used)
BYTE range0start; BYTE range0start;
BYTE range0end; BYTE range0end;

View file

@ -453,7 +453,7 @@ void R_InitSkins (void)
sndlumps[j] = -1; sndlumps[j] = -1;
skins[i].namespc = Wads.GetLumpNamespace (base); skins[i].namespc = Wads.GetLumpNamespace (base);
FScanner sc(base, "S_SKIN"); FScanner sc(base);
intname = 0; intname = 0;
crouchname = 0; crouchname = 0;
@ -501,6 +501,7 @@ void R_InitSkins (void)
{ {
for (j = 2; j >= 0; j--) for (j = 2; j >= 0; j--)
skins[i].face[j] = toupper (sc.String[j]); skins[i].face[j] = toupper (sc.String[j]);
skins[i].face[3] = '\0';
} }
else if (0 == stricmp (key, "gender")) else if (0 == stricmp (key, "gender"))
{ {
@ -886,11 +887,20 @@ void R_InitSprites ()
for (i = 0; i < PlayerClasses.Size (); i++) for (i = 0; i < PlayerClasses.Size (); i++)
{ {
const PClass *basetype = PlayerClasses[i].Type; const PClass *basetype = PlayerClasses[i].Type;
const char *pclassface = basetype->Meta.GetMetaString (APMETA_Face);
strcpy (skins[i].name, "Base"); strcpy (skins[i].name, "Base");
skins[i].face[0] = 'S'; if (strcmp(pclassface, "None") == 0)
skins[i].face[1] = 'T'; {
skins[i].face[2] = 'F'; skins[i].face[0] = 'S';
skins[i].face[1] = 'T';
skins[i].face[2] = 'F';
skins[i].face[3] = '\0';
}
else
{
strcpy(skins[i].face, pclassface);
}
skins[i].range0start = basetype->Meta.GetMetaInt (APMETA_ColorRange) & 255; skins[i].range0start = basetype->Meta.GetMetaInt (APMETA_ColorRange) & 255;
skins[i].range0end = basetype->Meta.GetMetaInt (APMETA_ColorRange) >> 8; skins[i].range0end = basetype->Meta.GetMetaInt (APMETA_ColorRange) >> 8;
skins[i].Scale = GetDefaultByType (basetype)->scaleX; skins[i].Scale = GetDefaultByType (basetype)->scaleX;

View file

@ -561,7 +561,6 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid,
if (lumpname) if (lumpname)
{ {
lump = Wads.CheckNumForFullName (lumpname, true, ns_sounds); lump = Wads.CheckNumForFullName (lumpname, true, ns_sounds);
if (lump == -1) lump = Wads.CheckNumForName (lumpname, ns_sounds);
} }
return S_AddPlayerSound (pclass, gender, refid, lump); return S_AddPlayerSound (pclass, gender, refid, lump);
@ -895,7 +894,7 @@ static void S_AddSNDINFO (int lump)
bool skipToEndIf; bool skipToEndIf;
TArray<WORD> list; TArray<WORD> list;
FScanner sc(lump, "SNDINFO"); FScanner sc(lump);
skipToEndIf = false; skipToEndIf = false;
while (sc.GetString ()) while (sc.GetString ())

View file

@ -465,7 +465,7 @@ FArchive &operator<< (FArchive &arc, ReverbContainer *&env)
return arc; return arc;
} }
static void ReadEAX (int lump, const char *lumpname) static void ReadEAX (int lump)
{ {
FScanner sc; FScanner sc;
const ReverbContainer *def; const ReverbContainer *def;
@ -476,7 +476,7 @@ static void ReadEAX (int lump, const char *lumpname)
bool inited[NUM_EAX_FIELDS]; bool inited[NUM_EAX_FIELDS];
BYTE bools[32]; BYTE bools[32];
sc.OpenLumpNum(lump, lumpname); sc.OpenLumpNum(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {
name = copystring (sc.String); name = copystring (sc.String);
@ -576,7 +576,7 @@ void S_ParseSndEax ()
while ((lump = Wads.FindLump ("SNDEAX", &lastlump)) != -1) while ((lump = Wads.FindLump ("SNDEAX", &lastlump)) != -1)
{ {
ReadEAX (lump, "SNDEAX"); ReadEAX (lump);
} }
} }

View file

@ -432,7 +432,7 @@ static void AssignHexenTranslations (void)
{ {
for (seq = 0; seq < Sequences.Size(); seq++) for (seq = 0; seq < Sequences.Size(); seq++)
{ {
if (HexenSequences[i].Name == Sequences[seq]->SeqName) if (Sequences[seq] != NULL && HexenSequences[i].Name == Sequences[seq]->SeqName)
break; break;
} }
if (seq == Sequences.Size()) if (seq == Sequences.Size())
@ -499,7 +499,7 @@ void S_ParseSndSeq (int levellump)
lump = levellump; lump = levellump;
levellump = -2; levellump = -2;
} }
FScanner sc(lump, "SNDSEQ"); FScanner sc(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {
bool bDoorSound = false; bool bDoorSound = false;
@ -514,7 +514,7 @@ void S_ParseSndSeq (int levellump)
seqtype = sc.String[0]; seqtype = sc.String[0];
for (curseq = 0; curseq < (int)Sequences.Size(); curseq++) for (curseq = 0; curseq < (int)Sequences.Size(); curseq++)
{ {
if (Sequences[curseq]->SeqName == seqname) if (Sequences[curseq] != NULL && Sequences[curseq]->SeqName == seqname)
{ {
M_Free (Sequences[curseq]); M_Free (Sequences[curseq]);
Sequences[curseq] = NULL; Sequences[curseq] = NULL;
@ -684,6 +684,10 @@ void S_ParseSndSeq (int levellump)
break; break;
} }
} }
if (curseq > 0)
{
sc.ScriptError("End of file encountered before the final sequence ended.");
}
} }
if (gameinfo.gametype == GAME_Hexen) if (gameinfo.gametype == GAME_Hexen)
@ -883,7 +887,7 @@ static int FindSequence (FName seqname)
for (i = Sequences.Size(); i-- > 0; ) for (i = Sequences.Size(); i-- > 0; )
{ {
if (seqname == Sequences[i]->SeqName) if (Sequences[i] != NULL && seqname == Sequences[i]->SeqName)
{ {
return i; return i;
} }

View file

@ -379,7 +379,7 @@ void S_Start ()
if (*LocalSndInfo) if (*LocalSndInfo)
{ {
// Now parse the local SNDINFO // Now parse the local SNDINFO
int j = Wads.CheckNumForName(LocalSndInfo); int j = Wads.CheckNumForFullName(LocalSndInfo, true);
if (j>=0) S_AddLocalSndInfo(j); if (j>=0) S_AddLocalSndInfo(j);
} }
@ -392,7 +392,7 @@ void S_Start ()
} }
if (parse_ss) if (parse_ss)
{ {
S_ParseSndSeq(*LocalSndSeq? Wads.CheckNumForName(LocalSndSeq) : -1); S_ParseSndSeq(*LocalSndSeq? Wads.CheckNumForFullName(LocalSndSeq, true) : -1);
} }
else else
@ -715,7 +715,8 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
// If this sound doesn't like playing near itself, don't play it if // If this sound doesn't like playing near itself, don't play it if
// that's what would happen. // that's what would happen.
if (NearLimit > 0 && pt != NULL && S_CheckSoundLimit(sfx, pos, NearLimit)) if (NearLimit > 0 && pt != NULL && mover != players[consoleplayer].camera &&
S_CheckSoundLimit(sfx, pos, NearLimit))
return; return;
// Make sure the sound is loaded. // Make sure the sound is loaded.

View file

@ -91,10 +91,10 @@ FScanner::FScanner(const FScanner &other)
// //
//========================================================================== //==========================================================================
FScanner::FScanner(int lumpnum, const char *name) FScanner::FScanner(int lumpnum)
{ {
ScriptOpen = false; ScriptOpen = false;
OpenLumpNum(lumpnum, name); OpenLumpNum(lumpnum);
} }
//========================================================================== //==========================================================================
@ -169,7 +169,7 @@ void FScanner::Open (const char *name)
{ {
I_Error("Could not find script lump '%s'\n", name); I_Error("Could not find script lump '%s'\n", name);
} }
OpenLumpNum(lump, name); OpenLumpNum(lump);
} }
//========================================================================== //==========================================================================
@ -219,14 +219,14 @@ void FScanner::OpenMem (const char *name, char *buffer, int size)
// //
//========================================================================== //==========================================================================
void FScanner :: OpenLumpNum (int lump, const char *name) void FScanner :: OpenLumpNum (int lump)
{ {
Close (); Close ();
{ {
FMemLump mem = Wads.ReadLump(lump); FMemLump mem = Wads.ReadLump(lump);
ScriptBuffer = mem.GetString(); ScriptBuffer = mem.GetString();
} }
ScriptName = name; ScriptName = Wads.GetLumpFullPath(lump);
PrepareScript (); PrepareScript ();
} }

View file

@ -13,7 +13,7 @@ public:
// Methods ------------------------------------------------------ // Methods ------------------------------------------------------
FScanner(); FScanner();
FScanner(const FScanner &other); FScanner(const FScanner &other);
FScanner(int lumpnum, const char *name); FScanner(int lumpnum);
~FScanner(); ~FScanner();
FScanner &operator=(const FScanner &other); FScanner &operator=(const FScanner &other);
@ -21,7 +21,7 @@ public:
void Open(const char *lumpname); void Open(const char *lumpname);
void OpenFile(const char *filename); void OpenFile(const char *filename);
void OpenMem(const char *name, char *buffer, int size); void OpenMem(const char *name, char *buffer, int size);
void OpenLumpNum(int lump, const char *name); void OpenLumpNum(int lump);
void Close(); void Close();
void SetCMode(bool cmode); void SetCMode(bool cmode);

View file

@ -1191,7 +1191,7 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
{ {
return oldmode; return oldmode;
} }
double cpos[3]; float cpos[3];
cpos[0] = FIXED2FLOAT(players[consoleplayer].camera->x); cpos[0] = FIXED2FLOAT(players[consoleplayer].camera->x);
cpos[2] = FIXED2FLOAT(players[consoleplayer].camera->y); cpos[2] = FIXED2FLOAT(players[consoleplayer].camera->y);
cpos[1] = FIXED2FLOAT(players[consoleplayer].camera->z); cpos[1] = FIXED2FLOAT(players[consoleplayer].camera->z);
@ -1226,11 +1226,11 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
return oldmode; return oldmode;
} }
else if (cpos[0] == pos[0] && cpos[1] == pos[1] && cpos[2] == pos[2]) else if (cpos[0] == pos[0] && cpos[1] == pos[1] && cpos[2] == pos[2])
{ { // Head relative
pos[2] = pos[1] = pos[0] = 0; return (oldmode & ~FMOD_3D) | FMOD_2D;
return (oldmode & ~FMOD_3D_WORLDRELATIVE) | FMOD_3D_HEADRELATIVE;
} }
return (oldmode & ~FMOD_3D_HEADRELATIVE) | FMOD_3D_WORLDRELATIVE; // World relative
return (oldmode & ~FMOD_2D) | FMOD_3D;
} }
//========================================================================== //==========================================================================
@ -1556,15 +1556,9 @@ void FMODSoundRenderer::DoLoad(void **slot, sfxinfo_t *sfx)
exinfo.length = size; exinfo.length = size;
} }
result = Sys->createSound((char *)sfxstart, samplemode, &exinfo, &sample); result = Sys->createSound((char *)sfxstart, samplemode, &exinfo, &sample);
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER && !(samplemode & FMOD_SOFTWARE))
{
DPrintf("Trying to fall back to software sample\n");
samplemode = (samplemode & ~FMOD_HARDWARE) | FMOD_SOFTWARE;
result = Sys->createSound((char *)sfxstart, samplemode, &exinfo, &sample);
}
if (result != FMOD_OK) if (result != FMOD_OK)
{ {
DPrintf("Failed to allocate sample: %d\n", result); DPrintf("Failed to allocate sample: Error %d\n", result);
errcount++; errcount++;
continue; continue;
} }

View file

@ -147,6 +147,11 @@ FString MusInfo::GetStats()
return "No stats available for this song"; return "No stats available for this song";
} }
MusInfo *MusInfo::GetOPLDumper(const char *filename)
{
return NULL;
}
void I_InitMusic (void) void I_InitMusic (void)
{ {
static bool setatterm = false; static bool setatterm = false;
@ -304,7 +309,6 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
/* MUS are played as: /* MUS are played as:
- OPL: - OPL:
- if explicitly selected by $mididevice - if explicitly selected by $mididevice
- when opl_enable is true and no midi device is set for the song
- when snd_mididevice is -3 and no midi device is set for the song - when snd_mididevice is -3 and no midi device is set for the song
Timidity: Timidity:
@ -321,9 +325,9 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
- when snd_mididevice is >= 0 and no midi device is set for the song - 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 - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0
*/ */
if (((opl_enable || snd_mididevice == -3) && device == MDEV_DEFAULT) || device == MDEV_OPL) if ((snd_mididevice == -3 && device == MDEV_DEFAULT) || device == MDEV_OPL)
{ {
info = new OPLMUSSong (file, musiccache, len); info = new MUSSong2 (file, musiccache, len, true);
} }
else if (device == MDEV_TIMIDITY || (device == MDEV_DEFAULT && snd_mididevice == -2)) else if (device == MDEV_TIMIDITY || (device == MDEV_DEFAULT && snd_mididevice == -2))
{ {
@ -369,7 +373,7 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
#ifdef _WIN32 #ifdef _WIN32
if (info == NULL) if (info == NULL)
{ {
info = new MUSSong2 (file, musiccache, len); info = new MUSSong2 (file, musiccache, len, false);
} }
#endif // _WIN32 #endif // _WIN32
} }
@ -384,7 +388,6 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
/* MIDI are played as: /* MIDI are played as:
OPL: OPL:
- if explicitly selected by $mididevice - if explicitly selected by $mididevice
- when opl_enable is true and no midi device is set for the song
- when snd_mididevice is -3 and no midi device is set for the song - when snd_mididevice is -3 and no midi device is set for the song
Timidity: Timidity:
@ -422,8 +425,11 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
} }
#endif // _WIN32 #endif // _WIN32
} }
// Check for RDosPlay raw OPL format // Check for various raw OPL formats
else if (id == MAKE_ID('R','A','W','A') && len >= 12) else if (len >= 12 &&
(id == MAKE_ID('R','A','W','A') || // Rdos Raw OPL
id == MAKE_ID('D','B','R','A') || // DosBox Raw OPL
id == MAKE_ID('A','D','L','I'))) // Martin Fernandez's modified IMF
{ {
DWORD fullsig[2]; DWORD fullsig[2];
@ -441,30 +447,9 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
memcpy(fullsig, musiccache, 8); memcpy(fullsig, musiccache, 8);
} }
if (fullsig[1] == MAKE_ID('D','A','T','A')) if ((fullsig[0] == MAKE_ID('R','A','W','A') && fullsig[1] == MAKE_ID('D','A','T','A')) ||
{ (fullsig[0] == MAKE_ID('D','B','R','A') && fullsig[1] == MAKE_ID('W','O','P','L')) ||
info = new OPLMUSSong (file, musiccache, len); (fullsig[0] == MAKE_ID('A','D','L','I') && (fullsig[1] & MAKE_ID(255,255,0,0)) == MAKE_ID('B',1,0,0)))
}
}
// Check for Martin Fernandez's modified IMF format
else if (id == MAKE_ID('A','D','L','I'))
{
char fullhead[6];
if (file != NULL)
{
if (fread (fullhead, 1, 6, file) != 6)
{
fclose (file);
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); info = new OPLMUSSong (file, musiccache, len);
} }
@ -597,3 +582,40 @@ ADD_STAT(music)
} }
return "No song playing"; return "No song playing";
} }
//==========================================================================
//
// CCMD writeopl
//
// If the current song can be played with OPL instruments, dump it to
// the specified file on disk.
//
//==========================================================================
CCMD (writeopl)
{
if (argv.argc() == 2)
{
if (currSong == NULL)
{
Printf ("No song is currently playing.\n");
}
else
{
MusInfo *dumper = currSong->GetOPLDumper(argv[1]);
if (dumper == NULL)
{
Printf ("Current song cannot be saved as OPL data.\n");
}
else
{
dumper->Play(false);
delete dumper;
}
}
}
else
{
Printf ("Usage: writeopl <filename>");
}
}

View file

@ -45,6 +45,7 @@ public:
virtual bool SetPosition (int order); virtual bool SetPosition (int order);
virtual void Update(); virtual void Update();
virtual FString GetStats(); virtual FString GetStats();
virtual MusInfo *GetOPLDumper(const char *filename);
enum EState enum EState
{ {
@ -152,7 +153,7 @@ protected:
// OPL implementation of a MIDI output device ------------------------------- // OPL implementation of a MIDI output device -------------------------------
class OPLMIDIDevice : public MIDIDevice, OPLmusicBlock class OPLMIDIDevice : public MIDIDevice, protected OPLmusicBlock
{ {
public: public:
OPLMIDIDevice(); OPLMIDIDevice();
@ -191,6 +192,17 @@ protected:
DWORD Position; DWORD Position;
}; };
// OPL dumper implementation of a MIDI output device ------------------------
class OPLDumperMIDIDevice : public OPLMIDIDevice
{
public:
OPLDumperMIDIDevice(const char *filename);
~OPLDumperMIDIDevice();
int Resume();
void Stop();
};
// Base class for streaming MUS and MIDI files ------------------------------ // Base class for streaming MUS and MIDI files ------------------------------
class MIDIStreamer : public MusInfo class MIDIStreamer : public MusInfo
@ -210,13 +222,15 @@ public:
void Update(); void Update();
protected: protected:
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2); MIDIStreamer(const char *dumpname);
void OutputVolume (DWORD volume); void OutputVolume (DWORD volume);
int FillBuffer(int buffer_num, int max_events, DWORD max_time); int FillBuffer(int buffer_num, int max_events, DWORD max_time);
bool ServiceEvent(); bool ServiceEvent();
int VolumeControllerChange(int channel, int volume); int VolumeControllerChange(int channel, int volume);
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
// Virtuals for subclasses to override // Virtuals for subclasses to override
virtual void CheckCaps(); virtual void CheckCaps();
virtual void DoInitialSetup() = 0; virtual void DoInitialSetup() = 0;
@ -261,6 +275,7 @@ protected:
DWORD Volume; DWORD Volume;
bool UseOPLDevice; bool UseOPLDevice;
bool CallbackIsThreaded; bool CallbackIsThreaded;
FString DumpFilename;
}; };
// MUS file played with a MIDI stream --------------------------------------- // MUS file played with a MIDI stream ---------------------------------------
@ -268,10 +283,14 @@ protected:
class MUSSong2 : public MIDIStreamer class MUSSong2 : public MIDIStreamer
{ {
public: public:
MUSSong2 (FILE *file, char *musiccache, int length); MUSSong2(FILE *file, char *musiccache, int length, bool opl);
~MUSSong2 (); ~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
protected: protected:
MUSSong2(const MUSSong2 *original, const char *filename); //OPL dump constructor
void DoInitialSetup(); void DoInitialSetup();
void DoRestart(); void DoRestart();
bool CheckDone(); bool CheckDone();
@ -288,10 +307,14 @@ protected:
class MIDISong2 : public MIDIStreamer class MIDISong2 : public MIDIStreamer
{ {
public: public:
MIDISong2 (FILE *file, char *musiccache, int length, bool opl); MIDISong2(FILE *file, char *musiccache, int length, bool opl);
~MIDISong2 (); ~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
protected: protected:
MIDISong2(const MIDISong2 *original, const char *filename); // OPL dump constructor
void CheckCaps(); void CheckCaps();
void DoInitialSetup(); void DoInitialSetup();
void DoRestart(); void DoRestart();
@ -307,6 +330,7 @@ protected:
void SetTempo(int new_tempo); void SetTempo(int new_tempo);
BYTE *MusHeader; BYTE *MusHeader;
int SongLen;
TrackInfo *Tracks; TrackInfo *Tracks;
TrackInfo *TrackDue; TrackInfo *TrackDue;
int NumTracks; int NumTracks;
@ -381,19 +405,29 @@ protected:
class OPLMUSSong : public StreamSong class OPLMUSSong : public StreamSong
{ {
public: public:
OPLMUSSong (FILE *file, char * musiccache, int length); OPLMUSSong (FILE *file, char *musiccache, int length);
~OPLMUSSong (); ~OPLMUSSong ();
void Play (bool looping); void Play (bool looping);
bool IsPlaying (); bool IsPlaying ();
bool IsValid () const; bool IsValid () const;
void ResetChips (); void ResetChips ();
MusInfo *GetOPLDumper(const char *filename);
protected: protected:
OPLMUSSong(const OPLMUSSong *original, const char *filename); // OPL dump constructor
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata); static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
OPLmusicFile *Music; OPLmusicFile *Music;
}; };
class OPLMUSDumper : public OPLMUSSong
{
public:
OPLMUSDumper(const OPLMUSSong *original, const char *filename);
void Play(bool looping);
};
// CD track/disk played through the multimedia system ----------------------- // CD track/disk played through the multimedia system -----------------------
class CDSong : public MusInfo class CDSong : public MusInfo
@ -430,4 +464,3 @@ extern MusInfo *currSong;
extern int nomusic; extern int nomusic;
EXTERN_CVAR (Float, snd_musicvolume) EXTERN_CVAR (Float, snd_musicvolume)
EXTERN_CVAR (Bool, opl_enable)

View file

@ -44,8 +44,6 @@
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
#define MAX_TIME (1000000/20) // Send out 1/20 of a sec of events at a time.
// Used by SendCommand to check for unexpected end-of-track conditions. // Used by SendCommand to check for unexpected end-of-track conditions.
#define CHECK_FINISHED \ #define CHECK_FINISHED \
if (track->TrackP >= track->MaxTrackP) \ if (track->TrackP >= track->MaxTrackP) \
@ -115,6 +113,7 @@ MIDISong2::MIDISong2 (FILE *file, char *musiccache, int len, bool opl)
} }
#endif #endif
MusHeader = new BYTE[len]; MusHeader = new BYTE[len];
SongLen = len;
if (file != NULL) if (file != NULL)
{ {
if (fread(MusHeader, 1, len, file) != (size_t)len) if (fread(MusHeader, 1, len, file) != (size_t)len)
@ -754,3 +753,43 @@ void MIDISong2::SetTempo(int new_tempo)
Tempo = new_tempo; Tempo = new_tempo;
} }
} }
//==========================================================================
//
// MIDISong2 :: GetOPLDumper
//
//==========================================================================
MusInfo *MIDISong2::GetOPLDumper(const char *filename)
{
return new MIDISong2(this, filename);
}
//==========================================================================
//
// MIDISong2 OPL Dumping Constructor
//
//==========================================================================
MIDISong2::MIDISong2(const MIDISong2 *original, const char *filename)
: MIDIStreamer(filename)
{
SongLen = original->SongLen;
MusHeader = new BYTE[original->SongLen];
memcpy(MusHeader, original->MusHeader, original->SongLen);
Format = original->Format;
NumTracks = original->NumTracks;
DesignationMask = 0;
Division = original->Division;
Tempo = InitialTempo = original->InitialTempo;
Tracks = new TrackInfo[NumTracks];
for (int i = 0; i < NumTracks; ++i)
{
TrackInfo *newtrack = &Tracks[i];
const TrackInfo *oldtrack = &original->Tracks[i];
newtrack->TrackBegin = MusHeader + (oldtrack->TrackBegin - original->MusHeader);
newtrack->TrackP = 0;
newtrack->MaxTrackP = oldtrack->MaxTrackP;
}
}

View file

@ -70,11 +70,11 @@ extern UINT mididevice;
//========================================================================== //==========================================================================
MIDIStreamer::MIDIStreamer(bool opl) MIDIStreamer::MIDIStreamer(bool opl)
: MIDI(0), :
#ifdef _WIN32 #ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0), PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif #endif
Division(0), InitialTempo(500000), UseOPLDevice(opl) MIDI(0), Division(0), InitialTempo(500000), UseOPLDevice(opl)
{ {
#ifdef _WIN32 #ifdef _WIN32
BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -91,6 +91,25 @@ MIDIStreamer::MIDIStreamer(bool opl)
#endif #endif
} }
//==========================================================================
//
// MIDIStreamer OPL Dumping Constructor
//
//==========================================================================
MIDIStreamer::MIDIStreamer(const char *dumpname)
:
#ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif
MIDI(0), Division(0), InitialTempo(500000), UseOPLDevice(true), DumpFilename(dumpname)
{
#ifdef _WIN32
BufferDoneEvent = NULL;
ExitEvent = NULL;
#endif
}
//========================================================================== //==========================================================================
// //
// MIDIStreamer Destructor // MIDIStreamer Destructor
@ -163,7 +182,7 @@ void MIDIStreamer::CheckCaps()
// //
//========================================================================== //==========================================================================
void MIDIStreamer::Play (bool looping) void MIDIStreamer::Play(bool looping)
{ {
DWORD tid; DWORD tid;
@ -175,6 +194,11 @@ void MIDIStreamer::Play (bool looping)
InitialPlayback = true; InitialPlayback = true;
assert(MIDI == NULL); assert(MIDI == NULL);
if (DumpFilename.IsNotEmpty())
{
MIDI = new OPLDumperMIDIDevice(DumpFilename);
}
else
#ifdef _WIN32 #ifdef _WIN32
if (!UseOPLDevice) if (!UseOPLDevice)
{ {
@ -188,7 +212,7 @@ void MIDIStreamer::Play (bool looping)
#ifndef _WIN32 #ifndef _WIN32
assert(MIDI->NeedThreadedCallback() == false); assert(MIDI->NeedThreadedCallback() == false);
#endif #endif
if (0 != MIDI->Open(Callback, this)) if (0 != MIDI->Open(Callback, this))
{ {
@ -281,7 +305,7 @@ void MIDIStreamer::Play (bool looping)
// //
//========================================================================== //==========================================================================
void MIDIStreamer::Pause () void MIDIStreamer::Pause()
{ {
if (m_Status == STATE_Playing) if (m_Status == STATE_Playing)
{ {
@ -302,7 +326,7 @@ void MIDIStreamer::Pause ()
// //
//========================================================================== //==========================================================================
void MIDIStreamer::Resume () void MIDIStreamer::Resume()
{ {
if (m_Status == STATE_Paused) if (m_Status == STATE_Paused)
{ {
@ -322,7 +346,7 @@ void MIDIStreamer::Resume ()
// //
//========================================================================== //==========================================================================
void MIDIStreamer::Stop () void MIDIStreamer::Stop()
{ {
EndQueued = 2; EndQueued = 2;
#ifdef _WIN32 #ifdef _WIN32
@ -355,7 +379,7 @@ void MIDIStreamer::Stop ()
// //
//========================================================================== //==========================================================================
bool MIDIStreamer::IsPlaying () bool MIDIStreamer::IsPlaying()
{ {
return m_Status != STATE_Stopped; return m_Status != STATE_Stopped;
} }
@ -369,7 +393,7 @@ bool MIDIStreamer::IsPlaying ()
// //
//========================================================================== //==========================================================================
void MIDIStreamer::MusicVolumeChanged () void MIDIStreamer::MusicVolumeChanged()
{ {
if (MIDI->FakeVolume()) if (MIDI->FakeVolume())
{ {
@ -676,7 +700,7 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, DWORD max_time)
//========================================================================== //==========================================================================
// //
// MIDIDevice constructor and desctructor stubs. // MIDIDevice stubs.
// //
//========================================================================== //==========================================================================

View file

@ -31,8 +31,6 @@
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
*/ */
#ifdef _WIN32
// HEADER FILES ------------------------------------------------------------ // HEADER FILES ------------------------------------------------------------
#include "i_musicinterns.h" #include "i_musicinterns.h"
@ -52,8 +50,6 @@
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern UINT mididevice;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
static const BYTE CtrlTranslate[15] = static const BYTE CtrlTranslate[15] =
@ -88,13 +84,15 @@ static const BYTE CtrlTranslate[15] =
// //
//========================================================================== //==========================================================================
MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len) MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len, bool opl)
: MIDIStreamer(false), MusHeader(0), MusBuffer(0) : MIDIStreamer(opl), MusHeader(0), MusBuffer(0)
{ {
#ifdef _WIN32
if (ExitEvent == NULL) if (ExitEvent == NULL)
{ {
return; return;
} }
#endif
MusHeader = (MUSHeader *)new BYTE[len]; MusHeader = (MUSHeader *)new BYTE[len];
if (file != NULL) if (file != NULL)
@ -304,4 +302,32 @@ end:
} }
return events; return events;
} }
#endif
//==========================================================================
//
// MUSSong2 :: GetOPLDumper
//
//==========================================================================
MusInfo *MUSSong2::GetOPLDumper(const char *filename)
{
return new MUSSong2(this, filename);
}
//==========================================================================
//
// MUSSong2 OPL Dumping Constructor
//
//==========================================================================
MUSSong2::MUSSong2(const MUSSong2 *original, const char *filename)
: MIDIStreamer(filename)
{
int songstart = LittleShort(original->MusHeader->SongStart);
MaxMusP = original->MaxMusP;
MusHeader = (MUSHeader *)new BYTE[songstart + MaxMusP];
memcpy(MusHeader, original->MusHeader, songstart + MaxMusP);
MusBuffer = (BYTE *)MusHeader + songstart;
Division = 140;
InitialTempo = 1000000;
}

View file

@ -1,7 +1,5 @@
#include "i_musicinterns.h" #include "i_musicinterns.h"
CVAR (Bool, opl_enable, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
static bool OPL_Active; static bool OPL_Active;
CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
@ -12,12 +10,11 @@ CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
} }
} }
OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len) OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len)
{ {
int samples = int(OPL_SAMPLE_RATE / 14); int samples = int(OPL_SAMPLE_RATE / 14);
Music = new OPLmusicFile (file, musiccache, len, samples); Music = new OPLmusicFile (file, musiccache, len);
m_Stream = GSnd->CreateStream (FillStream, samples*4, m_Stream = GSnd->CreateStream (FillStream, samples*4,
SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this); SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
@ -63,7 +60,7 @@ void OPLMUSSong::Play (bool looping)
Music->SetLooping (looping); Music->SetLooping (looping);
Music->Restart (); Music->Restart ();
if (m_Stream->Play (true, snd_musicvolume, false)) if (m_Stream == NULL || m_Stream->Play (true, snd_musicvolume, false))
{ {
m_Status = STATE_Playing; m_Status = STATE_Playing;
} }
@ -74,3 +71,24 @@ bool OPLMUSSong::FillStream (SoundStream *stream, void *buff, int len, void *use
OPLMUSSong *song = (OPLMUSSong *)userdata; OPLMUSSong *song = (OPLMUSSong *)userdata;
return song->Music->ServiceStream (buff, len); return song->Music->ServiceStream (buff, len);
} }
MusInfo *OPLMUSSong::GetOPLDumper(const char *filename)
{
return new OPLMUSDumper(this, filename);
}
OPLMUSSong::OPLMUSSong(const OPLMUSSong *original, const char *filename)
{
Music = new OPLmusicFile(original->Music, filename);
m_Stream = NULL;
}
OPLMUSDumper::OPLMUSDumper(const OPLMUSSong *original, const char *filename)
: OPLMUSSong(original, filename)
{
}
void OPLMUSDumper::Play(bool looping)
{
Music->Dump();
}

View file

@ -149,7 +149,7 @@ void FStringTable::LoadLanguage (int lumpnum, DWORD code, bool exactMatch, int p
code |= orMask; code |= orMask;
FScanner sc(lumpnum, "LANGUAGE"); FScanner sc(lumpnum);
sc.SetCMode (true); sc.SetCMode (true);
while (sc.GetString ()) while (sc.GetString ())
{ {

View file

@ -3,5 +3,5 @@
// This file was automatically generated by the // This file was automatically generated by the
// updaterevision tool. Do not edit by hand. // updaterevision tool. Do not edit by hand.
#define ZD_SVN_REVISION_STRING "871" #define ZD_SVN_REVISION_STRING "882"
#define ZD_SVN_REVISION_NUMBER 871 #define ZD_SVN_REVISION_NUMBER 882

View file

@ -84,7 +84,7 @@ void TEAMINFO_Init ()
while ((lump = Wads.FindLump ("TEAMINFO", &lastlump)) != -1) while ((lump = Wads.FindLump ("TEAMINFO", &lastlump)) != -1)
{ {
FScanner sc(lump, "TEAMINFO"); FScanner sc(lump);
while (sc.GetString ()) while (sc.GetString ())
{ {
if (sc.Compare("CLEARTEAMS")) if (sc.Compare("CLEARTEAMS"))

View file

@ -508,7 +508,7 @@ void FTextureManager::LoadHiresTex(int wadnum)
{ {
if (Wads.GetLumpFile(remapLump) == wadnum) if (Wads.GetLumpFile(remapLump) == wadnum)
{ {
FScanner sc(remapLump, "HIRESTEX"); FScanner sc(remapLump);
while (sc.GetString()) while (sc.GetString())
{ {
if (sc.Compare("remap")) // remap an existing texture if (sc.Compare("remap")) // remap an existing texture

View file

@ -1145,7 +1145,7 @@ void A_CustomPunch (AActor *self)
PuffType = PClass::FindClass(PuffTypeName); PuffType = PClass::FindClass(PuffTypeName);
if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff);
P_LineAttack (self, angle, Range, pitch, Damage, GetDefaultByType(PuffType)->DamageType, PuffType); P_LineAttack (self, angle, Range, pitch, Damage, GetDefaultByType(PuffType)->DamageType, PuffType, true);
// turn to face target // turn to face target
if (linetarget) if (linetarget)

View file

@ -150,7 +150,7 @@ void LoadDecorations ()
lastlump = 0; lastlump = 0;
while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1)
{ {
FScanner sc(lump, Wads.GetLumpFullName(lump)); FScanner sc(lump);
ParseDecorate (sc); ParseDecorate (sc);
} }
FinishThingdef(); FinishThingdef();

View file

@ -235,6 +235,7 @@ static flagdef ActorFlags[]=
DEFINE_FLAG(MF5, NEVERRESPAWN, AActor, flags5), DEFINE_FLAG(MF5, NEVERRESPAWN, AActor, flags5),
DEFINE_FLAG(MF5, DONTRIP, AActor, flags5), DEFINE_FLAG(MF5, DONTRIP, AActor, flags5),
DEFINE_FLAG(MF5, NOINFIGHTING, AActor, flags5), DEFINE_FLAG(MF5, NOINFIGHTING, AActor, flags5),
DEFINE_FLAG(MF5, NOINTERACTION, AActor, flags5),
// Effect flags // Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -2183,6 +2184,36 @@ static void PlayerSoundClass (FScanner &sc, APlayerPawn *defaults, Baggage &bag)
bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp); bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp);
} }
//==========================================================================
//
//==========================================================================
static void PlayerFace (FScanner &sc, APlayerPawn *defaults, Baggage &bag)
{
FString tmp;
sc.MustGetString ();
tmp = sc.String;
if (tmp.Len() != 3)
{
Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n",
sc.String, bag.Info->Class->TypeName.GetChars ());
}
tmp.ToUpper();
bool valid = (
(((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) &&
(((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) &&
(((tmp[2] >= 'A') && (tmp[2] <= 'Z')) || ((tmp[2] >= '0') && (tmp[2] <= '9')))
);
if (!valid)
{
Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n",
sc.String, bag.Info->Class->TypeName.GetChars ());
}
bag.Info->Class->Meta.SetMetaString (APMETA_Face, tmp);
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -2551,6 +2582,7 @@ static const ActorProps props[] =
{ "player.crouchsprite", (apf)PlayerCrouchSprite, RUNTIME_CLASS(APlayerPawn) }, { "player.crouchsprite", (apf)PlayerCrouchSprite, RUNTIME_CLASS(APlayerPawn) },
{ "player.damagescreencolor", (apf)PlayerDmgScreenColor, RUNTIME_CLASS(APlayerPawn) }, { "player.damagescreencolor", (apf)PlayerDmgScreenColor, RUNTIME_CLASS(APlayerPawn) },
{ "player.displayname", (apf)PlayerDisplayName, RUNTIME_CLASS(APlayerPawn) }, { "player.displayname", (apf)PlayerDisplayName, RUNTIME_CLASS(APlayerPawn) },
{ "player.face", (apf)PlayerFace, RUNTIME_CLASS(APlayerPawn) },
{ "player.forwardmove", (apf)PlayerForwardMove, RUNTIME_CLASS(APlayerPawn) }, { "player.forwardmove", (apf)PlayerForwardMove, RUNTIME_CLASS(APlayerPawn) },
{ "player.healradiustype", (apf)PlayerHealRadius, RUNTIME_CLASS(APlayerPawn) }, { "player.healradiustype", (apf)PlayerHealRadius, RUNTIME_CLASS(APlayerPawn) },
{ "player.hexenarmor", (apf)PlayerHexenArmor, RUNTIME_CLASS(APlayerPawn) }, { "player.hexenarmor", (apf)PlayerHexenArmor, RUNTIME_CLASS(APlayerPawn) },

View file

@ -218,12 +218,6 @@ FFont *V_GetFont(const char *name)
int lump = -1; int lump = -1;
lump = Wads.CheckNumForFullName(name, true); lump = Wads.CheckNumForFullName(name, true);
if (lump < 0 && strlen(name) > 8)
{
FString fullname;
fullname.Format("%s.fon", name);
lump = Wads.CheckNumForFullName(fullname);
}
if (lump != -1) if (lump != -1)
{ {
@ -293,6 +287,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
double *luminosity; double *luminosity;
int maxyoffs; int maxyoffs;
bool doomtemplate = gameinfo.gametype == GAME_Doom ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool doomtemplate = gameinfo.gametype == GAME_Doom ? strncmp (nametemplate, "STCFN", 5) == 0 : false;
bool stcfn121 = false;
Chars = new CharData[count]; Chars = new CharData[count];
charlumps = new int[count]; charlumps = new int[count];
@ -314,17 +309,22 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
lump = Wads.CheckNumForName (buffer, ns_graphics); lump = Wads.CheckNumForName (buffer, ns_graphics);
if (doomtemplate && lump >= 0 && i + start == 121) if (doomtemplate && lump >= 0 && i + start == 121)
{ // HACKHACK: Don't load STCFN121 in doom(2), because { // HACKHACK: Don't load STCFN121 in doom(2), because
// it's not really a lower-case 'y' but an upper-case 'I'. // it's not really a lower-case 'y' but a '|'.
// Because a lot of wads with their own font seem to foolishly // Because a lot of wads with their own font seem to foolishly
// copy STCFN121 and make it an 'I' themselves, wads must // copy STCFN121 and make it a '|' themselves, wads must
// provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load. // provide STCFN120 (x) and STCFN122 (z) for STCFN121 to load.
if (Wads.CheckNumForName ("STCFN120", ns_graphics) == -1 || if (Wads.CheckNumForName ("STCFN120", ns_graphics) == -1 ||
Wads.CheckNumForName ("STCFN122", ns_graphics) == -1) Wads.CheckNumForName ("STCFN122", ns_graphics) == -1)
{ {
// insert the incorrectly named '|' graphic in its correct position.
if (count > 124-start) charlumps[124-start] = lump;
lump = -1; lump = -1;
stcfn121 = true;
} }
} }
charlumps[i] = lump; if (lump != -1 || i != 124-start || !stcfn121)
charlumps[i] = lump;
if (lump >= 0) if (lump >= 0)
{ {
FTexture *pic = TexMan[buffer]; FTexture *pic = TexMan[buffer];
@ -1631,7 +1631,7 @@ void V_InitCustomFonts()
while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1)
{ {
sc.OpenLumpNum(llump, "FONTDEFS"); sc.OpenLumpNum(llump);
while (sc.GetString()) while (sc.GetString())
{ {
memset (lumplist, -1, sizeof(lumplist)); memset (lumplist, -1, sizeof(lumplist));
@ -1691,7 +1691,7 @@ void V_InitCustomFonts()
if (format == 1) goto wrong; if (format == 1) goto wrong;
int *p = &lumplist[*(unsigned char*)sc.String]; int *p = &lumplist[*(unsigned char*)sc.String];
sc.MustGetString(); sc.MustGetString();
*p = Wads.CheckNumForName (sc.String); *p = Wads.CheckNumForFullName (sc.String, true);
format=2; format=2;
} }
} }
@ -1759,7 +1759,7 @@ void V_InitFontColors ()
while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1) while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1)
{ {
FScanner sc(lump, "textcolors.txt"); FScanner sc(lump);
while (sc.GetString()) while (sc.GetString())
{ {
names.Clear(); names.Clear();

View file

@ -77,7 +77,7 @@
// SAVESIG should match SAVEVER. // SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded. // MINSAVEVER is the minimum level snapshot version that can be loaded.
#define MINSAVEVER 854 #define MINSAVEVER 879
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER #if ZD_SVN_REVISION_NUMBER < MINSAVEVER
// Never write a savegame with a version lower than what we need // Never write a savegame with a version lower than what we need

View file

@ -1617,6 +1617,25 @@ const char *FWadCollection::GetLumpFullName (int lump) const
return LumpInfo[lump].name; return LumpInfo[lump].name;
} }
//==========================================================================
//
// FWadCollection :: GetLumpFullPath
//
// Returns the name of the lump's wad prefixed to the lump's full name.
//
//==========================================================================
FString FWadCollection::GetLumpFullPath(int lump) const
{
FString foo;
if ((size_t) lump < NumLumps)
{
foo << GetWadName(LumpInfo[lump].wadnum) << ':' << GetLumpFullName(lump);
}
return foo;
}
//========================================================================== //==========================================================================
// //
// GetLumpNamespace // GetLumpNamespace

View file

@ -206,6 +206,7 @@ public:
int GetLumpFlags (int lump); // Return the flags for this lump int GetLumpFlags (int lump); // Return the flags for this lump
void GetLumpName (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy void GetLumpName (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy
const char *GetLumpFullName (int lump) const; // [RH] Returns the lump's full name const char *GetLumpFullName (int lump) const; // [RH] Returns the lump's full name
FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name
int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump
int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to
bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match

View file

@ -395,10 +395,10 @@ void WI_LoadBackground(bool isenterpic)
} }
else else
{ {
int lumpnum=Wads.GetNumForName(lumpname+1); int lumpnum=Wads.CheckNumForFullName(lumpname+1, true);
if (lumpnum>=0) if (lumpnum>=0)
{ {
FScanner sc(lumpnum,lumpname+1); FScanner sc(lumpnum);
while (sc.GetString()) while (sc.GetString())
{ {
memset(&an,0,sizeof(an)); memset(&an,0,sizeof(an));

View file

@ -2,7 +2,7 @@ ifeq (Windows_NT,$(OS))
WIN=1 WIN=1
WINCMD=1 WINCMD=1
endif endif
ifeq (msys,$(OSTYPE)) ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
WIN=1 WIN=1
WINCMD=0 WINCMD=0
endif endif

43
tools/lemon/Makefile Normal file
View file

@ -0,0 +1,43 @@
ifeq (Windows_NT,$(OS))
WIN=1
WINCMD=1
ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
WINCMD=0
endif
endif
ifeq (1,$(WIN))
EXE = lemon.exe
CFLAGS = $(LOC) -D_WIN32 -Os -Wall -Wno-implicit -fomit-frame-pointer
else
EXE = lemon
CFLAGS = -Os -Wall -Wno-implicit -fomit-frame-pointer
endif
CCDV = @../../ccdv
CC = gcc
LDFLAGS = -s
OBJS = lemon.o
all: $(EXE)
$(EXE): $(OBJS)
$(CCDV) $(CC) $(LDFLAGS) -o $(EXE) $(OBJS)
%.o: %.c
$(CCDV) $(CC) $(CFLAGS) -c -o $@ $<
.PHONY: clean
clean:
ifeq (1,$(WINCMD))
-del /q /f $(EXE) 2>nul
-del /q /f *.o 2>nul
else
rm -f $(EXE)
rm -f *.o
endif
lemon.o: lemon.c lempar.c

View file

@ -1,23 +0,0 @@
EXE = lemon.exe
CCDV = @../../ccdv
CC = gcc
CFLAGS = $(LOC) -D_WIN32 -Os -Wall -Wno-implicit -fomit-frame-pointer
OBJS = lemon.o
all: $(EXE)
.c.o:
$(CCDV) $(CC) $(CFLAGS) -c -o $@ $<
$(EXE): $(OBJS)
$(CCDV) $(CC) -o $(EXE) $(OBJS)
.PHONY: clean
clean:
-del /q /f $(EXE) 2>nul
-del /q /f *.o 2>nul
lemon.o: lemon.c lempar.c

View file

@ -1,11 +1,10 @@
ifeq (Windows_NT,$(OS)) ifeq (Windows_NT,$(OS))
WIN=1 WIN=1
WINCMD=1 WINCMD=1
endif ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
ifeq (msys,$(OSTYPE)) WINCMD=0
WIN=1 endif
WINCMD=0 endif
endif
ifeq (1,$(WIN)) ifeq (1,$(WIN))
EXE = makewad.exe EXE = makewad.exe

View file

@ -1,10 +1,9 @@
ifeq (Windows_NT,$(OS)) ifeq (Windows_NT,$(OS))
WIN=1 WIN=1
WINCMD=1 WINCMD=1
endif ifeq ($(findstring msys,$(shell sh --version 2>nul)),msys)
ifeq (msys,$(OSTYPE)) WINCMD=0
WIN=1 endif
WINCMD=0
endif endif
ifeq (1,$(WIN)) ifeq (1,$(WIN))

Some files were not shown because too many files have changed in this diff Show more