- 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

View file

@ -1,7 +1,350 @@
April 5, 2008 (Changes by Graf Zahl)
- 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.
April 5, 2008 (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()
April 4, 2008 (Changes by Graf Zahl)
- 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.
April 3, 2008
- Changed the Makefiles that are used by both Linux and MinGW so that msys
detection occurs only if $OS is Windows_NT. Otherwise, spurious nul files
are created when compiling on Linux.
April 3, 2008 (Changes by Graf Zahl)
- Fixed: The minimum parameter count for ACS_Execute and ACS_ExecuteAlways for
DECORATE was wrong (2 instead of 1.)
April 2, 2008 (Changes by Graf Zahl)
- 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.
April 2, 2008
- 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.
April 1, 2008
- Added support for DRO playback and dual-chip RAW playback.
March 30, 2008
- 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.
March 30, 2008 (Changes by Graf Zahl)
- Changed: When the screen is being deleted the 'screen' variable should be
set to NULL before performing the delete. Otherwise, in some abnormal
situations, it could happen that the destroyed screen object is still
being accessed.
- Fixed: V_Shutdown didn't set OF_YesReallyDelete before deleting screen.
- Fixed: The HIRESTEX parser didn't check if a graphic specified in a remap
command actually existed.
- Fixed: My $Limit fix from yesterday didn't work because NearLimit was
an unsigned byte and the comparisons with -1 didn't work. Made it a
signed word instead.
- Made sfxinfo_t::Link an unsigned int because it limited the amount of
usable sounds to 65535.
March 29, 2008
- Fixed: OPLMIDIDevice sent the wrong pitch wheel value to the player code.
Missimp.mid sounds a lot better now, though still a little off.
- Fixed: MIDI files that had ticks with nothing but meta-events did not play
properly. (fixes sonic3_finalboss.mid)
- Applied Const's Makefile.linux changes.
- Made the OPL MIDI synth available from Linux.
March 29, 2008 (Changes by Graf Zahl)
- Added SnowKate709's A_DamageMaster/A_DamageChildren patch.
- Added a SFX_TRANSFERAMBUSHFLAG for A_SpawnItemEx.
- Added "Shaded" as a valid parameter for DECORATE's RenderStyle.
- Added Karate Chris's patch for a MAPINFO option making Strife conversations
not halt the game.
- Extended the $limit fix that $alias and $random definitions can have their
own $limit now.
- Fixed: When resolving a linked sound the limit of the current sound was
ignored and the one of the referenced sound being used. This was particularly
noticable when using the chaingun in a group of Zombiemen.
- Added a namespc parameter to FWadCollection::CheckNumForFullName which is
used when a normal lump name has to be looked up and changed all
CheckNumForFullName/CheckNumForName combinations in the source to use
the extended version of CheckNumForFullName only to have consistent
behavior for lump name lookup.
March 28, 2008
- Moved sound sample rate, buffer size, and buffer count to the
advanced sound options menu. Removed opl_enable from the menu.
- Added OPL synth as MIDI device -3. Since this is based on the MUS player
code, it only supports those events and controllers supported by MUS.
Some of Duke's MIDIs sound awful, but I think that may be more because
it's using different instruments... There's a thread in the MIDI streamer
class that could be taken out for Linux, since it doesn't need to deal
with the Windows Multimedia API, but for now, this is still Windows-only.
- Changed the output of the OPL emulator from 32-bit integers to 32-bit
floats, so I can write its output directly to the stream buffer. In
addition, this lets me bring the OPL volume level much closer to the
standard MIDI volume.
March 27, 2008
- Did some restructuring of the OPL code in preparation for turning it
into a general MIDI player.
- Fixed: Passing false for a stream callback did not stop the stream.
- Removed opl_frequency, since the only time the emulation sounds good is
when it plays at the exact frequency of a real chip.
- Music no longer plays at all when snd_musicvolume is 0.
- Bumped up snd_sfxvolume and snd_musicvolume default values.
- Changed D3DFB to explicitly request double buffering instead of assuming
that the drivers will treat a BackBufferCount of 0 as a request for
double buffering.
- Fixed: Unsetting a cvar did not remove it from the list of tab
completions.
- Added "" as a synonym for "nullimage" in SBARINFO.
- Fixed: MAKESAVESIG's stringifier in version.h did not work as expected.
It stringified the passed macro name, not the value of the macro.
- Moved DCajunMaster off the DObject hierarchy.
- Changed DCajunMaster::getspawned into a TArray of FStrings. It was
mysteriously being left pointing to uninitialized memory during the
final GC at exit and crashing.
- Fixed: The code that removed hexdd.wad from the list of IWADs when
hexen.wad was not present did not work.
March 27, 2008 (Changes by Graf Zahl)
- Fixed: DCajunMaster::End was missing a write barrier for getspawned. The
same problem in D_DoomMain.
- Made bglobal a pointer because it was causing problems with the garbage
collector.
March 26, 2008
- Added uppercase copies of the IWAD names to the IWAD search for Unix land.
- Added FMOD_OPENONLY to the callback version of CreateStream() to prevent it
from doing prebuffering of the song. This was causing the Linux version to
hang while waiting for input from the pipe, since Timidity hadn't been
started yet. I tried using a select call in the FillStream() method, but it
always seems to return the pipe as having nothing available. Unfortunately,
the game still falls all over itself if Timidity isn't available. Instead
of execvp failing nicely, X errors kill the game. I don't know why it's
doing that. My advice for Linux music: Skip Timidity++ and get a DLS patch
set (/WINDOWS/system32/drivers/gm.dls is probably the most common by far)
and set the snd_midipatchset cvar to point to it. It's faster and also
sounds a whole lot better than the crappy freepats Ubuntu wants to install
with Timidity++ (thank goodness I have the official patches from a real
GUS so I don't need to use them).
- GCC fixes.
March 26, 2008 (Changes by Graf Zahl)
- Fixed: After starting new music the music volume has to be reset so that
the song's relative volume takes effect.
- Removed the arbitrary 1024 bytes limit when the file being played is a MIDI
file. I had a D_DM2TTL that's only 990 bytes.
- Restructured I_RegisterSong so that $mididevice works again and also supports
selecting FMOD.
- Added Jim' Linux fix.
- Added MartinHowe's fix for mugshot display in status bars.
March 25, 2008
- The garbage collector is now run one last time just before exiting the game.
- Removed movie volume from the sound menu and renamed some of the other
options to give the MIDI device name more room to display itself.
- Moved the midi device selection into the main sound menu.
- Added FMOD as MIDI device -1, to replace the MIDI mapper. This is still the
default device. By default, it uses exactly the same DLS instruments as the
Microsoft GS Wavetable Synth. If you have another set DLS level 1 patch set
you want to use, set the snd_midipatchset cvar to specify where it should
load the instruments from.
- Changed the ProduceMIDI function to store its output into a TArray<BYTE>.
An overloaded version wraps around it to continue to supply file-writing
support for external Timidity++ usage.
- Added an FMOD credits banner to comply with their non-commercial license.
- Reimplemented the snd_buffersize cvar for the FMOD Ex sound system. Rather
than a time in ms, this is now the length in samples of the DSP buffer.
Also added the snd_buffercount cvar to offer complete control over the
call to FMOD::System::setDSPBufferSize(). Note that with any snd_samplerate
below about 44kHz, you will need to set snd_buffersize to avoid long
latencies.
- Reimplemented the snd_output cvar for the FMOD Ex sound system.
- Changed snd_samplerate default to 0. This now means to use the default
sample rate.
- Made snd_output, snd_output_format, snd_speakermode, snd_resampler, and
snd_hrtf available through the menu.
- Split the HRTF effect selection into its own cvar: snd_hrtf.
- Removed 96000 Hz option from the menu. It's still available through the
cvar, if desired.
- Fixed: If Windows sound init failed, retry with DirectSound. (Apparently,
WASAPI doesn't work with more than two speakers and PCM-Float output at the
same time.)
- Fixed: Area sounds only played from the front speakers once you got within
the 2D panning area.
March 25, 2008 (Changes by Graf Zahl)
- Added Karate Chris's submission for multiplayer Strife conversations.
- Increased the limit for 'imp/active' to 6. This sound definitely benefits
from a higher limit.
- Fixed: $limit should not apply to sounds played from the menu.
- Fixed: The SNDSEQ parser tried to set bDoorSound before actually creating
the sound sequence data.
- Changed Lemon so that it always writes the header. It still kept recompiling
the grammar over and over again once it had been changed locally.
- Fixed: ANIMATED allowed animations between different texture types.
- Added a debuganimated CCMD that can be used to output some information
if a WAD shows broken animations.
March 24, 2008
- Removed xlat_parser.h from the repository. Lemon was always being run on
xlat_parser.y because both files had the same time stamp after an update,
and Lemon only rewrites the header file if it's changed.
- Added $volume SNDINFO command. This is multiplied with the volume the sound
is played at to arrive at the final volume (before distance attenuation).
- Added the CHAN_AREA flag to disable 3D panning within the min distance of a
sound. Sector sound sequences (except doors) use this flag.
- Added the CHAN_LOOP flag to replace the S_Looped* sound functions.
- Restored the sound limiting.
March 24, 2008 (Changes by Graf Zahl)
- Fixed: THe handling for enum values in Xlat was incorrect. The rule with
value assignment must set the counter one higher than the current value.
- Fixed: The definition of enums in the Xlat grammar was right-recursive
which could create stack overflows in the parser. Made it left-recursive as
recommended in Lemon's docs.
- Added Thomas's submissions for decal assignment to puffs and NOINFIGHTING flag.
- Reverted changes of r715 in v_collection.cpp because they broke loading
of status bar face graphics belonging to skins.
SBARINFO update #15
- Fixed: Monospacing fonts wasn't quite correct.
- Fixed: The new mug shot code forgot to use the first arg of drawmugshot (the
one that picks the default sprite prefix).
- Added: lowerHealthCap variable to SBarInfo, which is set to true by default.
- Added: ininventory event to SBarInfo to detect if one or two items are in (or
not in) the player's inventory.
- Added: The ability to print global vars using drawnumber. I need someone to
test it though.
- Added: aspectratio command to detect what the user's aspect ratio is.
- Added: missing spacing argument to drawstring.
- Changed the sbarinfo display routine for drawnumber to not use cmd.value to
store what it is about to display. Now it uses a new variable.
- More conversions from DrawImage to screen->DrawTexture. I think only the
inventory bar drawing functions have to be changed now.
March 23, 2008 (Changes by Graf Zahl)
- Fixed: The Sequence pointer in ASoundSequenceSlot was not declared as
a pointer and it was missing both read and write barriers.
- Fixed: The sector translators must clear unused bits because they might
render a sector's special inoperable.
- Expanded the args for MAPINFO special actions to 32 bit integers as in
the rest of the game.
- Fixed: The specialaction list was not copied properly when transferred
from the defaultinfo.
- Fixed: The defaultinfo for MAPINFO wasn't cleared fully after MAPINFO
parsing was completed.
- Made Doom-format linedef translators a map property so that it's easier
to define replacements or extensions.
March 22, 2008
- Changed MIDI playback to not bother playing super short songs that don't
contain enough music to fill the initial output buffers.
- Removed the read barrier around ADehackedPickup::RealPickup. If the real
pickup is picked up, it may very well destroy itself before the dehacked
wrapper's stubs that use it are called.
- Reverted revision 840. For a file we don't want end users to be touching,
making DEHSUPP plain text sends out mixed messages: "Don't mess with this.
Oh, by the way, it's plain text now to make it easier for you to edit."
Is there some reason other than a desire to do away with binary lumps to
make the distributed lump text?
- Added a new speakermode for Stereo + HRTF: "Headphones". This is the only
way to get the HRTF low pass filter effect now.
- Fixed: No more than one sector could make noise at once.
- Trying out sound without varying priorities again.
- Fixed: Need to use setSpeakerMix to let 2D sounds (aka streamed music) use
their full volume range.
March 22, 2008 (Changes by Graf Zahl)
- Changed DEHSUPP loader so that it reads the text file directly. As a result
the DEHSUPP compiler is gone now. Unlike XLATCC I'm using FScanner though.
A fully featured parser seems like overkill for this simple text file.
- Added sector type translation to xlat_parser and removed the old sectorx
lump.
- Added Line_SetTextureOffset special.
- Added 'allowprotection' keyword to terrain definitions to allow damaging
flats that don't damage players with a radiation suit.
@ -418,7 +761,7 @@ February 26, 2008
- More write barriers and pointer declarations. Here are rules I've come up
with so far for when write barriers can be ommitted:
* Initializing pointers for a newly created object: A new object can never
black, so none of its pointers that get set by the constructor (or code
be black, so none of its pointers that get set by the constructor (or code
just following its creation) need to be behind write barriers.
* Creating a new thinker and storing it in a pointer: The thinker
constructor already puts it behind a write barrier when it links it into
@ -5681,7 +6024,7 @@ February 9, 2005
took me a while to figure out the problem, ZDoom can now play raw OPL songs.
February 7, 2005
- Added the writeopl command to write a song in RDosPlay raw OPL format. It's usage is:
- Added the writeopl command to write a song in RDosPlay raw OPL format. Its usage is:
writeopl [songname] <filename>
If the currently playing song is a MUS song being played through the OPL emulation,
then you just need to specify the filename. Otherwise, you need to provide the

View file

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

View file

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

View file

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

View file

@ -72,7 +72,7 @@ DEFINE_SPECIAL(TeleportOther, 76, 3, 3)
DEFINE_SPECIAL(TeleportGroup, 77, 5, 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_Terminate, 82, 2, 2)
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_Ceiling, 224, 4, 4)
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(Plat_RaiseAndStayTx0, 228, 2, 2)
DEFINE_SPECIAL(Thing_SetGoal, 229, 3, 4)

View file

@ -299,6 +299,7 @@ enum
MF5_NEVERRESPAWN = 0x00040000, // never respawns, regardless of skill setting
MF5_DONTRIP = 0x00080000, // Ripping projectiles explode when hittin this actor
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 ---
@ -702,6 +703,7 @@ public:
//Added by MC:
SDWORD id; // Player ID (for items, # in list.)
BYTE smokecounter;
BYTE FloatBobPhase;
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
DWORD Translation;
@ -760,6 +762,7 @@ public:
bool SetStateNF (FState *newstate);
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
bool isFast();
void SetIdle();
FState *FindState (FName label) 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);
}
//static int WeightingScale;
CVAR (Int, am_rotate, 0, CVAR_ARCHIVE);
CVAR (Int, am_overlay, 0, 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_showtotaltime, false, 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_yourcolor, 0xfce8d8, 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;
/*
#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_rotate (fixed_t *x, fixed_t *y, angle_t an);
void AM_doFollowPlayer ();
@ -733,57 +720,6 @@ static void AM_initColors (bool overlayed)
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;
}
@ -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.
// This is LineDef based, not LineSeg based.
@ -1384,19 +1336,15 @@ void AM_drawWalls (bool allmap)
if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0)
continue;
if (!lines[i].backsector)
{
if (lines[i].frontsector->oldspecial &&
(am_map_secrets==2 || (am_map_secrets==1 && !(lines[i].frontsector->special&SECRET_MASK))))
if (AM_CheckSecret(&lines[i]))
{
// map secret sectors like Boom
AM_drawMline(&l, SecretSectorColor);
}
else
else if (!lines[i].backsector)
{
AM_drawMline(&l, WallColor);
}
}
else
{
if ((lines[i].special == Teleport ||
@ -1424,6 +1372,7 @@ void AM_drawWalls (bool allmap)
}
else if (lines[i].special == Door_LockedRaise ||
lines[i].special == ACS_LockedExecute ||
lines[i].special == ACS_LockedExecuteDoor ||
(lines[i].special == Generic_Door && lines[i].args[4]!=0))
{
if (am_usecustomcolors)
@ -1805,7 +1754,6 @@ void AM_Drawer ()
f_w = screen->GetWidth ();
f_h = ST_Y;
f_p = screen->GetPitch ();
//WeightingScale = 0;
AM_clearFB(Background);
}
@ -1816,13 +1764,6 @@ void AM_Drawer ()
f_w = realviewwidth;
f_h = realviewheight;
f_p = screen->GetPitch ();
/*
WeightingScale = (int)(am_ovtrans * 256.f);
if (WeightingScale < 0 || WeightingScale >= 256)
{
WeightingScale = 0;
}
*/
}
AM_activateNewScale();

View file

@ -266,12 +266,10 @@ CCMD (idclev)
// Catch invalid maps.
mapname = CalcMapName (epsd, map);
MapData * mapd = P_OpenMapData(mapname);
if (mapd == NULL)
if (!P_CheckMapData(mapname))
return;
// So be it.
delete mapd;
Printf ("%s\n", GStrings("STSTR_CLEV"));
G_DeferedInitNew (mapname);
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.
MapData * map = P_OpenMapData(mapname);
if (map != NULL)
if (P_CheckMapData(mapname))
{
// So be it.
delete map;
Printf ("%s\n", GStrings("STSTR_CLEV"));
G_DeferedInitNew (mapname);
return;
@ -323,14 +319,12 @@ CCMD (changemap)
if (argv.argc() > 1)
{
MapData * map = P_OpenMapData(argv[1]);
if (map == NULL)
if (!P_CheckMapData(argv[1]))
{
Printf ("No map %s\n", argv[1]);
}
else
{
delete map;
if (argv.argc() > 2)
{
Net_WriteByte (DEM_CHANGEMAP2);

View file

@ -2184,8 +2184,15 @@ void DoDehPatch (const char *patchfile, bool autoloading)
if (!PatchFile)
{
// Couldn't find it on disk, try reading it from a lump
lump = Wads.CheckNumForFullName(patchfile, true);
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)
{
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
// and name it TITLEMAP. That map will be loaded and used as the title.
MapData * map = P_OpenMapData("TITLEMAP");
if (map != NULL)
if (P_CheckMapData("TITLEMAP"))
{
delete map;
G_InitNew ("TITLEMAP", true);
return;
}
@ -2281,14 +2279,12 @@ void D_DoomMain (void)
p = Args->CheckParm ("+map");
if (p && p < Args->NumArgs()-1)
{
MapData * map = P_OpenMapData(Args->GetArg (p+1));
if (map == NULL)
if (!P_CheckMapData(Args->GetArg (p+1)))
{
Printf ("Can't find map %s\n", Args->GetArg (p+1));
}
else
{
delete map;
strncpy (startmap, Args->GetArg (p+1), 8);
Args->GetArg (p)[0] = '-';
autostart = true;
@ -2355,10 +2351,6 @@ void D_DoomMain (void)
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
Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo ();

View file

@ -51,6 +51,7 @@ enum
APMETA_DisplayName, // display name (used in menus etc.)
APMETA_SoundClass, // sound class
APMETA_Face, // doom status bar face (when used)
APMETA_ColorRange, // skin color range
APMETA_InvulMode,
APMETA_HealingRadius,
@ -252,6 +253,7 @@ public:
int fixedcolormap; // can be set to REDCOLORMAP, etc.
pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc)
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
int chickenPeck; // chicken peck countdown
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)
{
FScanner sc(lump, "DECALDEF");
FScanner sc(lump);
ReadDecals (sc);
}
// Supporting code to allow specifying decals directly in the DECORATE lump

View file

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

View file

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

View file

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

View file

@ -304,31 +304,15 @@ void T_LoadScripts(MapData *map)
//-----------------------------------------------------------------------------
//
// Registers an entry in the SpawnedThings table
// If no actor is spawned it will remain NULL, otherwise T_RegisterSpawnThing
// will be called to set it
// Adds an actor to the list of spawned things
//
//-----------------------------------------------------------------------------
void T_PrepareSpawnThing()
{
if (DFraggleThinker::ActiveThinker)
{
DFraggleThinker::ActiveThinker->SpawnedThings.Push(NULL);
}
}
//-----------------------------------------------------------------------------
//
// Sets the last entry in the table to the passed actor
//
//-----------------------------------------------------------------------------
void T_RegisterSpawnThing(AActor * ac)
void T_AddSpawnedThing(AActor * ac)
{
if (DFraggleThinker::ActiveThinker)
{
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;
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 (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
{
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;
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
if (linetarget)

View file

@ -456,7 +456,7 @@ void A_M_Punch (AActor *self)
A_FaceTarget (self);
angle = self->angle + (pr_m_punch.Random2() << 18);
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
if (linetarget)
@ -486,7 +486,7 @@ void A_M_BerserkPunch (AActor *self)
A_FaceTarget (self);
angle = self->angle + (pr_m_punch.Random2() << 18);
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
if (linetarget)

View file

@ -2291,11 +2291,11 @@ void G_BeginRecording (const char *startmap)
// G_PlayDemo
//
char defdemoname[128];
FString defdemoname;
void G_DeferedPlayDemo (char *name)
{
strncpy (defdemoname, name, 127);
defdemoname = name;
gameaction = ga_playdemo;
}
@ -2457,7 +2457,7 @@ void G_DoPlayDemo (void)
gameaction = ga_nothing;
// [RH] Allow for demos not loaded as lumps
demolump = Wads.CheckNumForName (defdemoname);
demolump = Wads.CheckNumForFullName (defdemoname, true);
if (demolump >= 0)
{
int demolen = Wads.LumpLength (demolump);
@ -2472,7 +2472,7 @@ void G_DoPlayDemo (void)
}
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
@ -2520,7 +2520,7 @@ void G_TimeDemo (char* name)
timingdemo = true;
singletics = true;
strncpy (defdemoname, name, 128);
defdemoname = name;
gameaction = ga_playdemo;
}

View file

@ -412,7 +412,7 @@ void A_BeakAttackPL1 (AActor *actor)
damage = 1 + (pr_beakatkpl1()&3);
angle = player->mo->angle;
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)
{
player->mo->angle = R_PointToAngle2 (player->mo->x,
@ -444,7 +444,7 @@ void A_BeakAttackPL2 (AActor *actor)
damage = pr_beakatkpl2.HitDice (4);
angle = player->mo->angle;
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)
{
player->mo->angle = R_PointToAngle2 (player->mo->x,

View file

@ -217,7 +217,7 @@ void A_StaffAttackPL1 (AActor *actor)
angle = player->mo->angle;
angle += pr_sap.Random2() << 18;
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)
{
//S_StartSound(player->mo, sfx_stfhit);
@ -256,7 +256,7 @@ void A_StaffAttackPL2 (AActor *actor)
angle = player->mo->angle;
angle += pr_sap2.Random2() << 18;
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)
{
//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);
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);
// player->mo->angle = R_PointToAngle2(player->mo->x,
// player->mo->y, linetarget->x, linetarget->y);
@ -104,7 +104,7 @@ void A_CMaceAttack (AActor *actor)
slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE);
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);
// player->mo->angle = R_PointToAngle2(player->mo->x,
// player->mo->y, linetarget->x, linetarget->y);

View file

@ -352,7 +352,7 @@ void A_FAxeAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, AXERANGE);
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)
{
P_ThrustMobj (linetarget, angle, power);
@ -365,7 +365,7 @@ void A_FAxeAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, AXERANGE);
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)
{
P_ThrustMobj (linetarget, angle, power);
@ -380,7 +380,7 @@ void A_FAxeAttack (AActor *actor)
angle = pmo->angle;
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:
if (useMana == 2)

View file

@ -194,7 +194,7 @@ void A_FHammerAttack (AActor *actor)
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
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);
if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
{
@ -207,7 +207,7 @@ void A_FHammerAttack (AActor *actor)
slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
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);
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
angle = pmo->angle;
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;
}

View file

@ -258,7 +258,7 @@ void A_FPunchAttack (AActor *actor)
power = 6*FRACUNIT;
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)
{
P_ThrustMobj (linetarget, angle, power);
@ -277,7 +277,7 @@ void A_FPunchAttack (AActor *actor)
power = 6*FRACUNIT;
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)
{
P_ThrustMobj (linetarget, angle, power);
@ -291,7 +291,7 @@ void A_FPunchAttack (AActor *actor)
angle = pmo->angle;
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:
if (pmo->special1 == 3)

View file

@ -269,7 +269,7 @@ void A_SnoutAttack (AActor *actor)
damage = 3+(pr_snoutattack()&3);
angle = player->mo->angle;
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);
if(linetarget)
{

View file

@ -41,6 +41,7 @@
#include "gi.h"
#include "files.h"
#include "m_png.h"
#include "gstrings.h"
//==========================================================================
@ -101,8 +102,15 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
}
}
if (cluster->clustername)
{
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;
}
}

View file

@ -137,7 +137,7 @@ extern const AInventory *SendItemUse, *SendItemDrop;
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;
TArray<level_info_t> wadlevelinfos;
@ -180,6 +180,7 @@ static const char *MapInfoTopLevel[] =
"clearepisodes",
"skill",
"clearskills",
"adddefaultmap",
NULL
};
@ -192,6 +193,7 @@ enum
MITL_CLEAREPISODES,
MITL_SKILL,
MITL_CLEARSKILLS,
MITL_ADDDEFAULTMAP,
};
static const char *MapInfoMapLevel[] =
@ -337,7 +339,6 @@ enum EMIType
MITYPE_REDIRECT,
MITYPE_SPECIALACTION,
MITYPE_COMPATFLAG,
MITYPE_F1, // [RC] F1 help
};
struct MapInfoHandler
@ -414,18 +415,18 @@ MapHandlers[] =
{ MITYPE_CLRFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_SETFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(enterpic), 0 },
{ MITYPE_STRING, lioffset(exitpic), 0 },
{ MITYPE_STRING, lioffset(exitpic), 0 },
{ MITYPE_STRING, lioffset(enterpic), 0 },
{ MITYPE_MUSIC, lioffset(intermusic), lioffset(intermusicorder) },
{ MITYPE_INT, lioffset(airsupply), 0 },
{ MITYPE_SPECIALACTION, lioffset(specialactions), 0 },
{ MITYPE_SETFLAG, LEVEL_KEEPFULLINVENTORY, 0 },
{ MITYPE_SETFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
{ MITYPE_CLRFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
{ MITYPE_LUMPNAME, lioffset(sndseq), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 0 },
{ MITYPE_STRING, lioffset(sndseq), 0 },
{ MITYPE_STRING, lioffset(soundinfo), 0 },
{ MITYPE_STRING, lioffset(soundinfo), 0 },
{ MITYPE_SETFLAG, LEVEL_CLIPMIDTEX, 0 },
{ MITYPE_SETFLAG, LEVEL_WRAPMIDTEX, 0 },
{ MITYPE_CLRFLAG, LEVEL_CROUCH_NO, 0 },
@ -446,7 +447,7 @@ MapHandlers[] =
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
{ MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
{ MITYPE_F1, lioffset(f1), 0, },
{ MITYPE_LUMPNAME, lioffset(f1), 0, },
{ MITYPE_SCFLAGS, LEVEL_NOINFIGHTING, ~LEVEL_TOTALINFIGHTING },
{ MITYPE_SCFLAGS, 0, ~(LEVEL_NOINFIGHTING|LEVEL_TOTALINFIGHTING)},
{ MITYPE_SCFLAGS, LEVEL_TOTALINFIGHTING, ~LEVEL_NOINFIGHTING },
@ -493,7 +494,7 @@ MapInfoHandler ClusterHandlers[] =
{ MITYPE_HEX, cioffset(cdid), 0 },
{ MITYPE_SETFLAG, CLUSTER_ENTERTEXTINLUMP, 0 },
{ MITYPE_SETFLAG, CLUSTER_EXITTEXTINLUMP, 0 },
{ MITYPE_STRING, cioffset(clustername), 0 },
{ MITYPE_STRING, cioffset(clustername), CLUSTER_LOOKUPNAME },
};
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.
levelinfo->flags |= LEVEL_LAXMONSTERACTIVATION;
}
else
{
levelinfo->flags |= LEVEL_MONSTERFALLINGDAMAGE;
}
levelinfo->airsupply = 10;
// new
@ -627,6 +624,48 @@ static FSpecialAction *CopySpecialActions(FSpecialAction *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)
{
level_info_t defaultinfo;
@ -636,7 +675,7 @@ static void G_DoParseMapInfo (int lump)
int clusterindex;
QWORD levelflags;
FScanner sc(lump, Wads.GetLumpFullName(lump));
FScanner sc(lump);
SetLevelDefaults (&defaultinfo);
HexenHack = false;
@ -651,6 +690,11 @@ static void G_DoParseMapInfo (int lump)
ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags);
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>
levelflags = defaultinfo.flags;
sc.MustGetString ();
@ -668,7 +712,8 @@ static void G_DoParseMapInfo (int lump)
| LEVEL_FALLDMG_HX
| LEVEL_ACTOWNSPECIAL
| LEVEL_MISSILESACTIVATEIMPACT
| LEVEL_INFINITE_FLIGHT;
| LEVEL_INFINITE_FLIGHT
| LEVEL_MONSTERFALLINGDAMAGE;
}
levelindex = FindWadLevelInfo (sc.String);
if (levelindex == -1)
@ -681,18 +726,13 @@ static void G_DoParseMapInfo (int lump)
}
levelinfo = &wadlevelinfos[levelindex];
memcpy (levelinfo, &defaultinfo, sizeof(*levelinfo));
if (levelinfo->music != NULL)
{
levelinfo->music = copystring (levelinfo->music);
}
if (levelinfo->intermusic != NULL)
{
levelinfo->intermusic = copystring (levelinfo->intermusic);
}
if (levelinfo->translator != NULL)
{
levelinfo->translator = copystring (levelinfo->translator);
}
CopyString(levelinfo->music);
CopyString(levelinfo->intermusic);
CopyString(levelinfo->translator);
CopyString(levelinfo->enterpic);
CopyString(levelinfo->exitpic);
CopyString(levelinfo->soundinfo);
CopyString(levelinfo->sndseq);
levelinfo->specialactions = CopySpecialActions(levelinfo->specialactions);
if (HexenHack)
{
@ -700,14 +740,19 @@ static void G_DoParseMapInfo (int lump)
}
uppercopy (levelinfo->mapname, sc.String);
sc.MustGetString ();
if (sc.Compare ("lookup"))
if (sc.String[0] == '$')
{
sc.MustGetString ();
ReplaceString (&levelinfo->level_name, sc.String);
// For consistency with other definitions allow $Stringtablename here, too.
levelflags |= LEVEL_LOOKUPLEVELNAME;
ReplaceString (&levelinfo->level_name, sc.String+1);
}
else
{
if (sc.Compare ("lookup"))
{
sc.MustGetString ();
levelflags |= LEVEL_LOOKUPLEVELNAME;
}
ReplaceString (&levelinfo->level_name, sc.String);
}
// 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);
}
if (levelinfo->f1 != NULL)
{
levelinfo->f1 = copystring (levelinfo->f1);
}
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
if (levelinfo->pname[0] != 0)
{
@ -759,22 +800,7 @@ static void G_DoParseMapInfo (int lump)
else
{
clusterinfo = &wadclusterinfos[clusterindex];
if (clusterinfo->entertext != NULL)
{
delete[] clusterinfo->entertext;
}
if (clusterinfo->exittext != NULL)
{
delete[] clusterinfo->exittext;
}
if (clusterinfo->messagemusic != NULL)
{
delete[] clusterinfo->messagemusic;
}
if (clusterinfo->clustername != NULL)
{
delete[] clusterinfo->clustername;
}
ClearClusterInfoStrings(clusterinfo);
}
memset (clusterinfo, 0, sizeof(cluster_info_t));
clusterinfo->cluster = sc.Number;
@ -802,60 +828,6 @@ static void G_DoParseMapInfo (int lump)
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()
{
for (int i = 0; i < EpiDef.numitems; ++i)
@ -920,13 +892,6 @@ static void ParseMapInfoLower (FScanner &sc,
case MITYPE_REDIRECT:
sc.MustGetString ();
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
case MITYPE_MAPNAME: {
@ -1064,7 +1029,7 @@ static void ParseMapInfoLower (FScanner &sc,
clusterinfo = &wadclusterinfos[clusterindex];
memset (clusterinfo, 0, sizeof(cluster_info_t));
clusterinfo->cluster = sc.Number;
if (gameinfo.gametype == GAME_Hexen)
if (HexenHack)
{
clusterinfo->flags |= CLUSTER_HUB;
}
@ -1073,23 +1038,20 @@ static void ParseMapInfoLower (FScanner &sc,
case MITYPE_STRING:
sc.MustGetString ();
if (sc.String[0] == '$')
{
// For consistency with other definitions allow $Stringtablename here, too.
flags |= handler->data2;
ReplaceString ((char **)(info + handler->data1), sc.String+1);
}
else
{
if (sc.Compare ("lookup"))
{
flags |= handler->data2;
sc.MustGetString ();
}
ReplaceString ((char **)(info + handler->data1), sc.String);
break;
case MITYPE_F1:
sc.MustGetString ();
{
char *colon = strchr (sc.String, ':');
if (colon)
{
*colon = 0;
}
ReplaceString ((char **)(info + handler->data1), sc.String);
}
break;
@ -1194,6 +1156,7 @@ static void ParseEpisodeInfo (FScanner &sc)
bool remove = false;
char key = 0;
bool noskill = false;
bool optional = false;
// Get map name
sc.MustGetString ();
@ -1212,7 +1175,12 @@ static void ParseEpisodeInfo (FScanner &sc)
}
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 ();
ReplaceString (&pic, sc.String);
@ -1245,6 +1213,17 @@ static void ParseEpisodeInfo (FScanner &sc)
}
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)
{
if (strncmp (EpisodeMaps[i], map, 8) == 0)
@ -1412,8 +1391,8 @@ void P_RemoveDefereds (void)
bool CheckWarpTransMap (char mapname[9], bool substitute)
{
if (mapname[0] == '&' && mapname[1] == 'w' &&
mapname[2] == 't' && mapname[3] == '@')
if (mapname[0] == '&' && (mapname[1]&223) == 'W' &&
(mapname[2]&223) == 'T' && mapname[3] == '@')
{
level_info_t *lev = FindLevelByWarpTrans (atoi (mapname + 4));
if (lev != NULL)
@ -1461,12 +1440,12 @@ CCMD (map)
}
if (argv.argc() > 1)
{
MapData * map = P_OpenMapData(argv[1]);
if (map == NULL)
if (!P_CheckMapData(argv[1]))
{
Printf ("No map %s\n", argv[1]);
}
else
{
delete map;
G_DeferedInitNew (argv[1]);
}
}
@ -1486,12 +1465,12 @@ CCMD (open)
if (argv.argc() > 1)
{
sprintf(d_mapname, "file:%s", argv[1]);
MapData * map = P_OpenMapData(d_mapname);
if (map == NULL)
if (!P_CheckMapData(d_mapname))
{
Printf ("No map %s\n", d_mapname);
}
else
{
delete map;
gameaction = ga_newgame2;
d_skill = -1;
}
@ -1642,12 +1621,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
}
// [RH] If this map doesn't exist, bomb out
MapData * map = P_OpenMapData(mapname);
if (!map)
if (!P_CheckMapData(mapname))
{
I_Error ("Could not find map %s\n", mapname);
}
delete map;
oldSpeed = GameSpeed;
wantFast = !!G_SkillProperty(SKILLP_FastMonsters);
@ -1819,10 +1796,8 @@ const char *G_GetSecretExitMap()
if (level.secretmap[0] != 0)
{
MapData *map = P_OpenMapData(level.secretmap);
if (map != NULL)
if (P_CheckMapData(level.secretmap))
{
delete map;
nextmap = level.secretmap;
}
}
@ -2067,7 +2042,7 @@ void G_DoLoadLevel (int position, bool autosave)
// DOOM determines the sky texture to be used
// 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);
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
// must not start any ENTER script or big problems will happen.
P_SpawnPlayer (&playerstarts[pawn->player - players], true);
pawndup = pawn->player->mo;
pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], true);
if (!startkeepfacing)
{
pawn->angle = pawndup->angle;
@ -2431,7 +2404,6 @@ void G_InitLevelLocals ()
level.levelnum = info->levelnum;
level.music = info->music;
level.musicorder = info->musicorder;
level.f1 = info->f1; // [RC] And import the f1 name
strncpy (level.level_name, info->level_name, 63);
G_MaybeLookupLevelName (NULL);
@ -2467,7 +2439,7 @@ void G_InitLevelLocals ()
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)
return false;
@ -2476,7 +2448,7 @@ bool level_locals_s::IsJumpingAllowed() const
return !(level.flags & LEVEL_JUMP_NO);
}
bool level_locals_s::IsCrouchingAllowed() const
bool FLevelLocals::IsCrouchingAllowed() const
{
if (dmflags & DF_NO_CROUCH)
return false;
@ -2485,7 +2457,7 @@ bool level_locals_s::IsCrouchingAllowed() const
return !(level.flags & LEVEL_CROUCH_NO);
}
bool level_locals_s::IsFreelookAllowed() const
bool FLevelLocals::IsFreelookAllowed() const
{
if (level.flags & LEVEL_FREELOOK_NO)
return false;
@ -2544,10 +2516,8 @@ level_info_t *CheckLevelRedirect (level_info_t *info)
if (playeringame[i] && players[i].mo->FindInventory (type))
{
// check for actual presence of the map.
MapData * map = P_OpenMapData(info->RedirectMap);
if (map != NULL)
if (P_CheckMapData(info->RedirectMap))
{
delete map;
return FindLevelInfo(info->RedirectMap);
}
break;
@ -2634,90 +2604,6 @@ const char *G_MaybeLookupLevelName (level_info_t *ininfo)
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 ()
{
if (level.aircontrol <= 256)
@ -3166,7 +3052,7 @@ void P_ReadACSDefereds (PNGHandle *png)
}
void level_locals_s::Tick ()
void FLevelLocals::Tick ()
{
// Reset carry sectors
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)
{

View file

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

View file

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

View file

@ -8,6 +8,7 @@
#include "s_sound.h"
#include "m_random.h"
#include "a_sharedglobal.h"
#include "sbar.h"
#define MORPHTICS (40*TICRATE)
@ -56,6 +57,10 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
{
return false;
}
if (spawntype == p->mo->GetClass())
{
return false;
}
morphed = static_cast<APlayerPawn *>(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE));
DObject::StaticPointerSubstitution (actor, morphed);
@ -78,6 +83,18 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
actor->flags |= MF_UNMORPHED;
actor->renderflags |= RF_INVISIBLE;
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->mo = morphed;
p->momx = p->momy = 0;
@ -116,6 +133,18 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype)
p->camera = morphed;
}
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;
}
@ -182,6 +211,39 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
{
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;
Spawn<ATeleportFog> (pmo->x + 20*finecosine[angle],
pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE);

View file

@ -183,22 +183,24 @@ enum //drawimage flags
enum //drawnumber flags
{
DRAWNUMBER_HEALTH = 1,
DRAWNUMBER_ARMOR = 2,
DRAWNUMBER_AMMO1 = 4,
DRAWNUMBER_AMMO2 = 8,
DRAWNUMBER_AMMO = 16,
DRAWNUMBER_AMMOCAPACITY = 32,
DRAWNUMBER_FRAGS = 64,
DRAWNUMBER_INVENTORY = 128,
DRAWNUMBER_KILLS = 256,
DRAWNUMBER_MONSTERS = 512,
DRAWNUMBER_ITEMS = 1024,
DRAWNUMBER_TOTALITEMS = 2048,
DRAWNUMBER_SECRETS = 4096,
DRAWNUMBER_TOTALSECRETS = 8192,
DRAWNUMBER_ARMORCLASS = 16384,
DRAWNUMBER_GLOBALVAR = 32768,
DRAWNUMBER_HEALTH = 0x1,
DRAWNUMBER_ARMOR = 0x2,
DRAWNUMBER_AMMO1 = 0x4,
DRAWNUMBER_AMMO2 = 0x8,
DRAWNUMBER_AMMO = 0x10,
DRAWNUMBER_AMMOCAPACITY = 0x20,
DRAWNUMBER_FRAGS = 0x40,
DRAWNUMBER_INVENTORY = 0x80,
DRAWNUMBER_KILLS = 0x100,
DRAWNUMBER_MONSTERS = 0x200,
DRAWNUMBER_ITEMS = 0x400,
DRAWNUMBER_TOTALITEMS = 0x800,
DRAWNUMBER_SECRETS = 0x1000,
DRAWNUMBER_TOTALSECRETS = 0x2000,
DRAWNUMBER_ARMORCLASS = 0x4000,
DRAWNUMBER_GLOBALVAR = 0x8000,
DRAWNUMBER_GLOBALARRAY = 0x10000,
DRAWNUMBER_FILLZEROS = 0x20000,
};
enum //drawbar flags (will go into special2)
@ -305,6 +307,7 @@ enum //Bar key words
SBARINFO_GAMEMODE,
SBARINFO_PLAYERCLASS,
SBARINFO_ASPECTRATIO,
SBARINFO_ISSELECTED,
SBARINFO_WEAPONAMMO,
SBARINFO_ININVENTORY,
};
@ -338,9 +341,9 @@ public:
void SetMugShotState(const char* stateName, bool waitTillDone=false);
private:
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 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);
int updateState(bool xdth, bool animatedgodmode);
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);
}
else
else if(cmd.sprite != -1)
{
DrawGraphic(Images[cmd.sprite], cmd.x, cmd.y, cmd.flags);
}
@ -571,7 +571,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
{
drawingFont = cmd.font;
}
if(cmd.flags == DRAWNUMBER_HEALTH)
if(cmd.flags & DRAWNUMBER_HEALTH)
{
value = health;
if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives
@ -579,11 +579,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0;
}
}
else if(cmd.flags == DRAWNUMBER_ARMOR)
else if(cmd.flags & DRAWNUMBER_ARMOR)
{
value = armorAmount;
}
else if(cmd.flags == DRAWNUMBER_AMMO1)
else if(cmd.flags & DRAWNUMBER_AMMO1)
{
value = ammocount1;
if(ammo1 == NULL) //no ammo, do not draw
@ -591,7 +591,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
continue;
}
}
else if(cmd.flags == DRAWNUMBER_AMMO2)
else if(cmd.flags & DRAWNUMBER_AMMO2)
{
value = ammocount2;
if(ammo2 == NULL) //no ammo, do not draw
@ -599,7 +599,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
continue;
}
}
else if(cmd.flags == DRAWNUMBER_AMMO)
else if(cmd.flags & DRAWNUMBER_AMMO)
{
const PClass* ammo = PClass::FindClass(cmd.string[0]);
AInventory* item = CPlayer->mo->FindInventory(ammo);
@ -612,7 +612,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0;
}
}
else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY)
else if(cmd.flags & DRAWNUMBER_AMMOCAPACITY)
{
const PClass* ammo = PClass::FindClass(cmd.string[0]);
AInventory* item = CPlayer->mo->FindInventory(ammo);
@ -625,21 +625,21 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
}
}
else if(cmd.flags == DRAWNUMBER_FRAGS)
else if(cmd.flags & DRAWNUMBER_FRAGS)
value = CPlayer->fragcount;
else if(cmd.flags == DRAWNUMBER_KILLS)
else if(cmd.flags & DRAWNUMBER_KILLS)
value = level.killed_monsters;
else if(cmd.flags == DRAWNUMBER_MONSTERS)
else if(cmd.flags & DRAWNUMBER_MONSTERS)
value = level.total_monsters;
else if(cmd.flags == DRAWNUMBER_ITEMS)
else if(cmd.flags & DRAWNUMBER_ITEMS)
value = level.found_items;
else if(cmd.flags == DRAWNUMBER_TOTALITEMS)
else if(cmd.flags & DRAWNUMBER_TOTALITEMS)
value = level.total_items;
else if(cmd.flags == DRAWNUMBER_SECRETS)
else if(cmd.flags & DRAWNUMBER_SECRETS)
value = level.found_secrets;
else if(cmd.flags == DRAWNUMBER_TOTALSECRETS)
else if(cmd.flags & DRAWNUMBER_TOTALSECRETS)
value = level.total_secrets;
else if(cmd.flags == DRAWNUMBER_ARMORCLASS)
else if(cmd.flags & DRAWNUMBER_ARMORCLASS)
{
AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
if(harmor != NULL)
@ -654,9 +654,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
}
value /= (5*FRACUNIT);
}
else if(cmd.flags == DRAWNUMBER_GLOBALVAR)
else if(cmd.flags & DRAWNUMBER_GLOBALVAR)
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]));
if(item != NULL)
@ -668,12 +670,13 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
value = 0;
}
}
if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2);
else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2);
bool fillzeros = !!(cmd.flags & DRAWNUMBER_FILLZEROS);
if(cmd.special3 != -1 && value <= cmd.special3) //low
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2, fillzeros);
else if(cmd.special4 != -1 && value >= cmd.special4) //high
DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2, fillzeros);
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;
}
case SBARINFO_DRAWMUGSHOT:
@ -1079,6 +1082,27 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
doCommands(cmd.subBlock);
}
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:
if(CPlayer->ReadyWeapon != NULL)
{
@ -1154,6 +1178,10 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
//draws an image with the specified flags
void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
{
if (texture == NULL)
{
return;
}
if((flags & DRAWIMAGE_OFFSET_CENTER))
{
x -= (texture->GetWidth()/2)-texture->LeftOffset;
@ -1162,8 +1190,9 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
x += ST_X;
y += ST_Y;
int w = texture->GetScaledWidth();
int h = texture->GetScaledHeight();
int h = texture->GetScaledHeight() + y;
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
h -= y;
if((flags & DRAWIMAGE_TRANSLATABLE))
{
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
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;
int maxval = (int) ceil(pow(10., len))-1;
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);
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')
x -= int(drawingFont->StringWidth(value)+(spacing * value.Len()));
else //monospaced so just multiplay the character size
@ -1245,7 +1289,10 @@ void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool ani
for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++);
if(currentState != NULL)
{
FTexture *face = currentState->getCurrentFrameTexture(defaultFace, &skins[CPlayer->userinfo.skin], level, angle);
FPlayerSkin *skin = &skins[CPlayer->morphTics ? CPlayer->MorphedPlayerClass : CPlayer->userinfo.skin];
FTexture *face = currentState->getCurrentFrameTexture(defaultFace, skin, level, angle);
if (face != NULL)
{
x += ST_X;
y += ST_Y;
int w = face->GetScaledWidth();
@ -1256,6 +1303,7 @@ void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool ani
DTA_DestHeight, h,
TAG_DONE);
}
}
}
int DSBarInfo::updateState(bool xdth, bool animatedgodmode)
@ -1391,7 +1439,7 @@ void DSBarInfo::DrawInventoryBar(int type, int num, int x, int y, bool alwayssho
{
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);
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)
{
DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29);
DrawGraphic(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29);
}
else
{
DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y);
DrawGraphic(Images[invBarOffset + imgSELECTBOX], x+i*31, y);
}
}
}
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?
if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst)
{
DrawImage (Images[!(gametic & 4) ?
DrawGraphic(Images[!(gametic & 4) ?
invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x-12, y);
}
// Is there something to the right?
if (!noArrows && item != NULL)
{
DrawImage (Images[!(gametic & 4) ?
DrawGraphic(Images[!(gametic & 4) ?
invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x+num*31+2, y);
}
}

View file

@ -93,6 +93,7 @@ static const char *SBarInfoRoutineLevel[] =
"gamemode",
"playerclass",
"aspectratio",
"isselected",
"weaponammo", //event
"ininventory",
NULL
@ -130,17 +131,14 @@ void SBarInfo::ParseSBarInfo(int lump)
{
gameType = gameinfo.gametype;
bool baseSet = false;
FScanner sc(lump, Wads.GetLumpFullName(lump));
FScanner sc(lump);
sc.SetCMode(true);
while(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_Include))
{
if(sc.TokenType == TK_Include)
{
sc.MustGetToken(TK_StringConst);
int lump = Wads.CheckNumForFullName(sc.String); //zip/pk3
//Do a normal wad lookup.
if (lump == -1 && sc.StringLen <= 8 && !strchr(sc.String, '/'))
lump = Wads.CheckNumForName(sc.String);
int lump = Wads.CheckNumForFullName(sc.String, true);
if (lump == -1)
sc.ScriptError("Lump '%s' not found", sc.String);
ParseSBarInfo(lump);
@ -493,6 +491,14 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.ScriptError("Global variable number out of range: %d", 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
{
cmd.flags = DRAWNUMBER_INVENTORY;
@ -506,6 +512,18 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
}
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);
if(sc.CheckToken(','))
{
@ -951,6 +969,33 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.MustGetToken('{');
this->ParseSBarInfoBlock(sc, cmd.subBlock);
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:
sc.MustGetToken(TK_Identifier);
if(sc.Compare("not"))
@ -983,7 +1028,6 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
this->ParseSBarInfoBlock(sc, cmd.subBlock);
break;
case SBARINFO_ININVENTORY:
{
sc.MustGetToken(TK_Identifier);
if(sc.Compare("not"))
{
@ -1015,7 +1059,6 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
this->ParseSBarInfoBlock(sc, cmd.subBlock);
break;
}
}
block.commands.Push(cmd);
}
sc.MustGetToken('}');

View file

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

View file

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

View file

@ -210,7 +210,7 @@ void A_JabDagger (AActor *actor)
angle = actor->angle + (pr_jabdagger.Random2() << 18);
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
if (linetarget)
@ -934,7 +934,7 @@ void A_RocketInFlight (AActor *self)
AActor *trail;
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);
if (trail != NULL)
{

View file

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

View file

@ -247,7 +247,7 @@ void gl_InitModels()
memset(&smf, 0, sizeof(smf));
while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1)
{
FScanner sc(Lump, "MODELDEF");
FScanner sc(Lump);
while (sc.GetString())
{
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
{
fU2=pti->GetUL();
fV2=pti->GetVT();
fV1=pti->GetVT();
fU1=pti->GetUR();
fV1=pti->GetVB();
fV2=pti->GetVB();
}
gl.Begin(GL_TRIANGLE_STRIP);

View file

@ -247,6 +247,7 @@ enum
ADEF_PlayerPawn_CrouchSprite,
ADEF_PlayerPawn_DisplayName,
ADEF_PlayerPawn_SoundClass,
ADEF_PlayerPawn_Face,
ADEF_PlayerPawn_ScoreIcon,
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:
sgClass->Meta.SetMetaString (APMETA_SoundClass, datastr);
break;
case ADEF_PlayerPawn_Face:
sgClass->Meta.SetMetaString (APMETA_Face, datastr);
break;
case ADEF_PlayerPawn_ScoreIcon:
player->ScoreIcon = TexMan.AddPatch (datastr);
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_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_ScoreIcon(x) ADD_STRING_PROP(ADEF_PlayerPawn_ScoreIcon,"\27",x)
#define PROP_PlayerPawn_MorphWeapon(x) ADD_STRING_PROP(ADEF_PlayerPawn_MorphWeapon,"\30",x)
#define PROP_PlayerPawn_Face(x) ADD_STRING_PROP(ADEF_PlayerPawn_Face,"\27",x) // Octal - 'tis quaint!
#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_YScale(x) ADD_LONG_PROP(ADEF_YScale,x)

View file

@ -1446,7 +1446,7 @@ void M_QuickLoad ()
//
void M_DrawReadThis ()
{
FTexture *tex, *prevpic = NULL;
FTexture *tex = NULL, *prevpic = NULL;
fixed_t alpha;
if (gameinfo.flags & GI_INFOINDEXED)
@ -1463,11 +1463,15 @@ void M_DrawReadThis ()
}
else
{
tex = TexMan[gameinfo.info.infoPage[InfoType-1]];
// 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)

View file

@ -492,6 +492,13 @@ static value_t ColumnMethods[] = {
{ 1.0, "Optimized" }
};
static value_t RocketTrailTypes[] = {
{ 0.0, "Off" },
{ 1.0, "Particles" },
{ 2.0, "Sprites" },
{ 3.0, "Sprites & Particles" }
};
static value_t BloodTypes[] = {
{ 0.0, "Sprites" },
{ 1.0, "Sprites & Particles" },
@ -540,7 +547,7 @@ static menuitem_t VideoItems[] = {
#endif
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ 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, "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)
static menuitem_t AdvSoundItems[] =
@ -3465,7 +3471,7 @@ void InitCrosshairsList()
while ((lump = Wads.FindLump("XHAIRS", &lastlump)) != -1)
{
FScanner sc(lump, "XHAIRS");
FScanner sc(lump);
while (sc.GetNumber())
{
value.value = float(sc.Number);

View file

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

View file

@ -75,17 +75,6 @@ Revision History:
#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 EG_SH 16 /* 16.16 fixed point (EG timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */

View file

@ -3,8 +3,8 @@
#include "zstring.h"
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
// Multiplying OPL_SAMPLE_RATE by ADLIB_CLOCK_MUL gives the number
// Adlib clocks per second, as used by the RAWADATA file format.
/* compiler dependence */
#ifndef OSD_CPU_H
@ -17,13 +17,6 @@ typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#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_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 "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)
{
YM3812Write (which, 0, reg);
@ -106,64 +118,73 @@ static WORD frequencies[] =
0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3,
0x1e4, 0x1e5, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed,
0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f6, 0x1f7, 0x1f8,
0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203,
0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f,
0x210, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a,
0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226,
0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232,
0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e,
0x23f, 0x240, 0x241, 0x242, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b,
0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x256, 0x257, 0x258,
0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265,
0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272,
0x273, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280,
0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28b, 0x28c, 0x28d, 0x28e,
0x28f, 0x290, 0x292, 0x293, 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c,
0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a9, 0x2aa, 0x2ab,
0x2ac, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba,
0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c7, 0x2c8, 0x2c9,
0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9,
0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, 0x2e5, 0x2e6, 0x2e8, 0x2e9,
0x2ea, 0x2ec, 0x2ed, 0x2ee, 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9,
0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, 0x306, 0x307, 0x309, 0x30a,
0x30b, 0x30d, 0x30e, 0x310, 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b,
0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, 0x328, 0x329, 0x32b, 0x32c,
0x32e, 0x32f, 0x331, 0x332, 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e,
0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, 0x34c, 0x34d, 0x34f, 0x350,
0x352, 0x353, 0x355, 0x357, 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363,
0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, 0x371, 0x373, 0x374, 0x376,
0x378, 0x379, 0x37b, 0x37c, 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389,
0x38b, 0x38d, 0x38e, 0x390, 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, 0x388
0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200,
0x201, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f,
0x210, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e,
0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e,
0x22f, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e,
0x23f, 0x240, 0x241, 0x242, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, 0x24f,
0x250, 0x251, 0x252, 0x253, 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260,
0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272,
0x273, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x284, 0x285,
0x286, 0x287, 0x288, 0x289, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, 0x294, 0x295, 0x296, 0x298,
0x299, 0x29a, 0x29b, 0x29c, 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a9, 0x2aa, 0x2ab,
0x2ac, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, 0x2bb, 0x2bd, 0x2be, 0x2bf,
0x2c0, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2d0, 0x2d1, 0x2d2, 0x2d4,
0x2d5, 0x2d6, 0x2d8, 0x2d9, 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, 0x2e5, 0x2e6, 0x2e8, 0x2e9,
0x2ea, 0x2ec, 0x2ed, 0x2ee, 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, 0x2fb, 0x2fc, 0x2fd, 0x2ff,
0x300, 0x302, 0x303, 0x304, 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, 0x311, 0x312, 0x314, 0x315,
0x317, 0x318, 0x31a, 0x31b, 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, 0x328, 0x329, 0x32b, 0x32c,
0x32e, 0x32f, 0x331, 0x332, 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, 0x340, 0x341, 0x343, 0x344,
0x346, 0x347, 0x349, 0x34a, 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, 0x358, 0x35a, 0x35b, 0x35d,
0x35e, 0x360, 0x361, 0x363, 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, 0x371, 0x373, 0x374, 0x376,
0x378, 0x379, 0x37b, 0x37c, 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, 0x38b, 0x38d, 0x38e, 0x390,
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
* [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 j = (freq<<5) + octave;
i = 0;
int octave = 0;
int j = (note << 5) + pitch;
if (j < 0)
{
j = 0;
}
else if (j >= 0x11C)
else if (j >= 284)
{
j -= 0x11C;
i = j / 0x180;
if (i > 7)
j -= 284;
octave = j / (32*12);
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 (0xB0, channel, (BYTE)(i>>8)|(keyon<<5));
@ -277,20 +298,12 @@ void OPLio::OPLshutup(void)
/*
* 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;
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();
OPLchannels = OPL2CHANNELS * numchips;
OPLwriteInitState();
return 0;
}
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
*/

View file

@ -40,6 +40,7 @@
#include "doomdef.h"
#include "m_swap.h"
#include "w_wad.h"
#include "fmopl.h"
// MACROS ------------------------------------------------------------------
@ -105,7 +106,7 @@ OPLMIDIDevice::~OPLMIDIDevice()
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;
}
@ -209,6 +210,7 @@ int OPLMIDIDevice::SetTimeDiv(int timediv)
void OPLMIDIDevice::CalcTickRate()
{
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

@ -160,7 +160,7 @@ struct OPLdata {
};
struct OPLio {
virtual ~OPLio() {}
virtual ~OPLio();
void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2);
void OPLwriteValue(uint regbase, uint channel, uchar value);
@ -171,14 +171,43 @@ struct OPLio {
void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan);
void OPLwriteInstrument(uint channel, struct OPL2instrument *instr);
void OPLshutup(void);
void OPLwriteInitState();
virtual int OPLinit(uint numchips, uint rate);
virtual int OPLinit(uint numchips);
virtual void OPLdeinit(void);
virtual void OPLwriteReg(int which, uint reg, uchar data);
virtual void SetClockRate(double samples_per_tick);
virtual void WriteDelay(int ticks);
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 {
musicBlock();
~musicBlock();
@ -193,8 +222,6 @@ struct musicBlock {
ulong MLtime;
int playTick();
void OPLplayNote(uint channel, uchar note, int volume);
void OPLreleaseNote(uint channel, uchar note);
void OPLpitchWheel(uint channel, int pitch);
@ -254,4 +281,7 @@ enum MUSctrl {
ctrlResetCtrls
};
#define OPL_SAMPLE_RATE 49716.0
#define ADLIB_CLOCK_MUL 24.0
#endif // __MUSLIB_H_

View file

@ -79,7 +79,7 @@ void OPLmusicBlock::ResetChips ()
TwoChips = !opl_onechip;
Serialize();
io->OPLdeinit ();
io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE));
io->OPLinit (TwoChips + 1);
Unserialize();
}
@ -91,7 +91,7 @@ void OPLmusicBlock::Restart()
playingcount = 0;
}
OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSamples)
OPLmusicFile::OPLmusicFile (FILE *file, char *musiccache, int len)
: ScoreLen (len)
{
if (io == NULL)
@ -115,29 +115,15 @@ OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSampl
memcpy(scoredata, &musiccache[0], len);
}
if (io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE)))
if (io->OPLinit (TwoChips + 1))
{
delete[] scoredata;
scoredata = NULL;
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
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'))
{
RawPlayer = RDosPlay;
@ -145,7 +131,16 @@ OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSampl
{ // A clock speed of 0 is bad
*(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)
else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') &&
@ -202,14 +197,16 @@ void OPLmusicFile::SetLooping (bool loop)
void OPLmusicFile::Restart ()
{
OPLmusicBlock::Restart();
if (RawPlayer == NotRaw)
{
score = scoredata + ((MUSheader *)scoredata)->scoreStart;
}
else if (RawPlayer == RDosPlay)
WhichChip = 0;
if (RawPlayer == RDosPlay)
{
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)
{
@ -226,6 +223,7 @@ void OPLmusicFile::Restart ()
score += 4; // Skip song length
}
}
io->SetClockRate(SamplesPerTick);
}
bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
@ -289,6 +287,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
else
{
prevEnded = false;
io->WriteDelay(next);
NextTickIn += SamplesPerTick * next;
assert (NextTickIn >= 0);
MLtime += next;
@ -303,11 +302,7 @@ int OPLmusicFile::PlayTick ()
{
BYTE reg, data;
if (RawPlayer == NotRaw)
{
return playTick ();
}
else if (RawPlayer == RDosPlay)
if (RawPlayer == RDosPlay)
{
while (score < scoredata + ScoreLen)
{
@ -325,9 +320,18 @@ int OPLmusicFile::PlayTick ()
case 2: // Speed change or OPL3 switch
if (data == 0)
{
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(score)) / 1193180.0;
SamplesPerTick = LittleShort(*(WORD *)(score)) / ADLIB_CLOCK_MUL;
io->SetClockRate(SamplesPerTick);
score += 2;
}
else if (data == 1)
{
WhichChip = 0;
}
else if (data == 2)
{
WhichChip = 1;
}
break;
case 0xFF: // End of song
@ -338,11 +342,55 @@ int OPLmusicFile::PlayTick ()
break;
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;
}
}
}
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)
{
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) {}
virtual ~DiskWriterIO () { if (File != NULL) fclose (File); }
int OPLinit(const char *filename);
virtual void OPLwriteReg(int which, uint reg, uchar data);
FILE *File;
bool RawFormat;
};
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)
ScoreLen = source->ScoreLen;
scoredata = new BYTE[ScoreLen];
memcpy(scoredata, source->scoredata, ScoreLen);
SamplesPerTick = source->SamplesPerTick;
RawPlayer = source->RawPlayer;
score = source->score;
TwoChips = source->TwoChips;
WhichChip = 0;
if (io != NULL)
{
if (BlockForStats == NULL)
{
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 ();
delete io;
}
io = new DiskWriterIO(filename);
io->OPLinit(TwoChips);
Restart();
}
OPLmusicWriter::~OPLmusicWriter ()
void OPLmusicFile::Dump()
{
if (io != NULL) delete io;
if (!SharingData)
int time;
time = PlayTick();
while (time != 0)
{
delete scoredata;
}
else
{
OPLinstruments = NULL;
io->WriteDelay(time);
time = PlayTick();
}
}
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 "files.h"
#define OPL_SAMPLE_RATE 49716.0
class OPLmusicBlock : public musicBlock
{
public:
OPLmusicBlock();
~OPLmusicBlock();
virtual ~OPLmusicBlock();
bool ServiceStream(void *buff, int numbytes);
void ResetChips();
@ -43,16 +41,20 @@ protected:
class OPLmusicFile : public OPLmusicBlock
{
public:
OPLmusicFile(FILE *file, char *musiccache, int len, int maxSamples);
~OPLmusicFile();
OPLmusicFile(FILE *file, char *musiccache, int len);
OPLmusicFile(const OPLmusicFile *source, const char *filename);
virtual ~OPLmusicFile();
bool IsValid() const;
void SetLooping(bool loop);
void Restart();
void Dump();
protected:
OPLmusicFile() {}
int PlayTick();
enum { NotRaw, RDosPlay, IMF } RawPlayer;
enum { RDosPlay, IMF, DosBox } RawPlayer;
int ScoreLen;
int WhichChip;
};

View file

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

View file

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

View file

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

View file

@ -90,13 +90,20 @@ void P_UnPredictPlayer ();
extern fixed_t FloatBobOffsets[64];
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);
int P_FaceMobj (AActor *source, AActor *target, angle_t *delta);
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_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);
@ -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)
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, FName 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, 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, AActor *target, angle_t angle, int pitch);
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,
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;
FTraceResults trace;
@ -3079,6 +3079,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
bool hitGhosts;
bool killPuff = false;
AActor *puff = NULL;
int flags = ismeleeattack? PF_MELEERANGE : 0;
angle >>= 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)
{ // 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
{
@ -3133,7 +3134,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
fixed_t closer = trace.Distance - 4*FRACUNIT;
puff = P_SpawnPuff (pufftype, t1->x + FixedMul (vx, 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
@ -3186,7 +3187,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
(trace.Actor->flags & MF_NOBLOOD) ||
(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))
{
@ -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
// 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;
}
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)
{ // 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;
}
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,
int pitch, int damage, FName damageType, FName pufftype)
int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack)
{
const PClass * type = PClass::FindClass(pufftype);
if (type == NULL)
@ -3268,7 +3269,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
}
else
{
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type);
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack);
}
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) ||
(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
{

View file

@ -81,9 +81,8 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
extern cycle_t BotSupportCycles;
extern cycle_t BotWTG;
extern fixed_t attackrange;
extern int tmfloorpic;
extern sector_t *tmfloorsector;
EXTERN_CVAR (Bool, r_drawfuzz);
EXTERN_CVAR (Int, cl_rockettrails)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -108,7 +107,6 @@ static FRandom pr_missiledamage ("MissileDamage");
static FRandom pr_multiclasschoice ("MultiClassChoice");
static FRandom pr_rockettrail("RocketTrail");
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FRandom pr_spawnmobj ("SpawnActor");
@ -327,7 +325,8 @@ void AActor::Serialize (FArchive &arc)
<< DamageType
<< gravity
<< FastChaseStrafeCount
<< master;
<< master
<< smokecounter;
if (arc.IsStoring ())
{
@ -1461,11 +1460,12 @@ void P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
mo->momx = mo->momy = mo->momz = 0;
if (!(mo->flags2 & MF2_DORMANT))
{
mo->SetState (mo->SeeState != NULL ? mo->SeeState : mo->SpawnState);
if (mo->SeeState != NULL) mo->SetState (mo->SeeState);
else mo->SetIdle();
}
else
{
mo->SetState (mo->SpawnState);
mo->SetIdle();
mo->tics = -1;
}
}
@ -2462,11 +2462,12 @@ bool AActor::Slam (AActor *thing)
int dam = GetMissileDamage (7, 1);
P_DamageMobj (thing, this, this, dam, NAME_Melee);
P_TraceBleed (dam, thing, this);
SetState (SeeState != NULL ? SeeState : SpawnState);
if (SeeState != NULL) SetState (SeeState);
else SetIdle();
}
else
{
SetState (SpawnState);
SetIdle();
tics = -1;
}
}
@ -2572,25 +2573,8 @@ void AActor::SetShade (int r, int g, int b)
//
// P_MobjThinker
//
CVAR(Bool, sv_rocketsmoke, false, CVAR_ARCHIVE|CVAR_SERVERINFO)
void AActor::Tick ()
{
if (effects&FX_ROCKET && sv_rocketsmoke && ++visdir==4)
{
// add some smoke behind the rocket
visdir=0;
AActor * th = Spawn("RocketSmokeTrail", x-momx, y-momy, z, ALLOW_REPLACE);
if (th)
{
th->momz = FRACUNIT;
th->tics -= pr_rockettrail()&3;
if (th->tics < 1) th->tics = 1;
}
}
// [RH] Data for Heretic/Hexen scrolling sectors
static const BYTE HexenScrollDirs[8] = { 64, 0, 192, 128, 96, 32, 224, 160 };
static const BYTE HexenSpeedMuls[3] = { 5, 10, 25 };
@ -2623,6 +2607,19 @@ void AActor::Tick ()
PrevY = y;
PrevZ = z;
if (flags5 & MF5_NOINTERACTION)
{
// only do the minimally necessary things here to save time.
UnlinkFromWorld ();
flags |= MF_NOBLOCKMAP;
x += momx;
y += momy;
z += momz;
LinkToWorld ();
}
else
{
AInventory * item = Inventory;
// Handle powerup effects here so that the order is controlled
@ -2650,12 +2647,46 @@ void AActor::Tick ()
return;
}
if (cl_rockettrails & 2)
{
if (effects & FX_ROCKET)
{
if (++smokecounter==4)
{
// add some smoke behind the rocket
smokecounter = 0;
AActor * th = Spawn("RocketSmokeTrail", x-momx, y-momy, z-momz, ALLOW_REPLACE);
if (th)
{
th->tics -= pr_rockettrail()&3;
if (th->tics < 1) th->tics = 1;
}
}
}
else if (effects & FX_GRENADE)
{
if (++smokecounter==8)
{
smokecounter = 0;
angle_t moveangle = R_PointToAngle2(0,0,momx,momy);
AActor * th = Spawn("GrenadeSmokeTrail",
x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10),
y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10),
z - (height>>3) * (momz>>16) + (2*height)/3, ALLOW_REPLACE);
if (th)
{
th->tics -= pr_rockettrail()&3;
if (th->tics < 1) th->tics = 1;
}
}
}
}
fixed_t oldz = z;
// [RH] Give the pain elemental vertical friction
// This used to be in APainElemental::Tick but in order to use
// A_PainAttack with other monsters it has to be here!
// A_PainAttack with other monsters it has to be here
if (flags4 & MF4_VFRICTION)
{
if (health >0)
@ -3039,6 +3070,7 @@ void AActor::Tick ()
{
return;
}
}
// cycle through states, calling action functions at transitions
if (tics != -1)
@ -3326,7 +3358,7 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t
actor->ceilingsector = actor->Sector;
actor->ceilingpic = actor->ceilingsector->ceilingpic;
}
else
else if (!(actor->flags5 & MF5_NOINTERACTION))
{
P_FindFloorCeiling (actor);
actor->floorz = tmffloorz;
@ -3337,6 +3369,16 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t
actor->ceilingpic = tmfceilingpic;
actor->ceilingsector = tmfceilingsector;
}
else
{
actor->floorz = FIXED_MIN;
actor->dropoffz = FIXED_MIN;
actor->ceilingz = FIXED_MAX;
actor->floorpic = 0;
actor->floorsector = actor->Sector;
actor->ceilingpic = 0;
actor->ceilingsector = actor->Sector;
}
actor->SpawnPoint[0] = ix >> FRACBITS;
actor->SpawnPoint[1] = iy >> FRACBITS;
@ -3599,7 +3641,7 @@ EXTERN_CVAR (Bool, chasedemo)
extern bool demonew;
void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
APlayerPawn *P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
{
int playernum;
player_t *p;
@ -3626,7 +3668,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
// not playing?
if (playernum >= MAXPLAYERS || !playeringame[playernum])
return;
return NULL;
p = &players[playernum];
@ -3823,6 +3865,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
FBehavior::StaticStartTypedScripts (SCRIPT_Respawn, p->mo, true);
}
}
return mobj;
}
@ -3832,23 +3875,21 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
// already be in host byte order.
//
// [RH] position is used to weed out unwanted start spots
void P_SpawnMapThing (mapthing2_t *mthing, int position)
AActor *P_SpawnMapThing (mapthing2_t *mthing, int position)
{
const PClass *i;
int mask;
AActor *mobj;
fixed_t x, y, z;
T_PrepareSpawnThing();
if (mthing->type == 0 || mthing->type == -1)
return;
return NULL;
// count deathmatch start positions
if (mthing->type == 11)
{
deathmatchstarts.Push (*mthing);
return;
return NULL;
}
// Convert Strife starts to Hexen-style starts
@ -3889,7 +3930,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
polyspawns = polyspawn;
if (mthing->type != PO_ANCHOR_TYPE)
po_NumPolyobjs++;
return;
return NULL;
}
// check for players specially
@ -3927,13 +3968,13 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
}
if (!(mthing->flags & mask))
{
return;
return NULL;
}
mask = G_SkillProperty(SKILLP_SpawnFilter);
if (!(mthing->flags & mask))
{
return;
return NULL;
}
// Check class spawn masks. Now with player classes available
@ -3943,7 +3984,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
int spawnmask = players[consoleplayer].GetSpawnClass();
if (spawnmask != 0 && (mthing->flags & spawnmask) == 0)
{ // Not for current class
return;
return NULL;
}
}
else if (!deathmatch)
@ -3962,7 +4003,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
}
if (mask != -1 && (mthing->flags & mask) == 0)
{
return;
return NULL;
}
}
}
@ -3971,14 +4012,14 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
{
// [RH] Only spawn spots that match position.
if (mthing->args[0] != position)
return;
return NULL;
// save spots for respawning in network games
playerstarts[pnum] = *mthing;
if (!deathmatch)
P_SpawnPlayer (mthing);
return P_SpawnPlayer (mthing);
return;
return NULL;
}
// [RH] sound sequence overriders
@ -3986,7 +4027,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
{
P_PointInSector (mthing->x<<FRACBITS,
mthing->y<<FRACBITS)->seqType = mthing->type - 1400;
return;
return NULL;
}
else if (mthing->type == 1411)
{
@ -4006,7 +4047,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
P_PointInSector (mthing->x << FRACBITS,
mthing->y << FRACBITS)->seqType = type;
}
return;
return NULL;
}
// [RH] Determine if it is an old ambient thing, and if so,
@ -4053,7 +4094,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
// don't spawn keycards and players in deathmatch
if (deathmatch && info->flags & MF_NOTDMATCH)
return;
return NULL;
// [RH] don't spawn extra weapons in coop if so desired
if (multiplayer && !deathmatch && (dmflags & DF_NO_COOP_WEAPON_SPAWN))
@ -4061,14 +4102,14 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
if (i->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
{
if ((mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH)
return;
return NULL;
}
}
// don't spawn any monsters if -nomonsters
if (((level.flags & LEVEL_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) && info->flags3 & MF3_ISMONSTER )
{
return;
return NULL;
}
// [RH] Other things that shouldn't be spawned depending on dmflags
@ -4077,13 +4118,11 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
if (dmflags & DF_NO_HEALTH)
{
if (i->IsDescendantOf (RUNTIME_CLASS(AHealth)))
return;
return NULL;
if (i->TypeName == NAME_Berserk)
return;
if (i->TypeName == NAME_Soulsphere)
return;
return NULL;
if (i->TypeName == NAME_Megasphere)
return;
return NULL;
}
if (dmflags & DF_NO_ITEMS)
{
@ -4093,9 +4132,9 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
if (dmflags & DF_NO_ARMOR)
{
if (i->IsDescendantOf (RUNTIME_CLASS(AArmor)))
return;
return NULL;
if (i->TypeName == NAME_Megasphere)
return;
return NULL;
}
}
@ -4138,13 +4177,11 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360);
mobj->BeginPlay ();
if (mobj->ObjectFlags & OF_EuthanizeMe)
if (!(mobj->ObjectFlags & OF_EuthanizeMe))
{
return;
}
mobj->LevelSpawned ();
T_RegisterSpawnThing(mobj);
}
return mobj;
}
@ -4158,7 +4195,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
// P_SpawnPuff
//
AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, bool hitthing, bool temporary)
AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags)
{
AActor *puff;
@ -4170,26 +4207,26 @@ AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, an
// it will enter the crash state. This is used by the StrifeSpark
// and BlasterPuff.
FState *crashstate;
if (hitthing == false && (crashstate = puff->FindState(NAME_Crash)) != NULL)
if (!(flags & PF_HITTHING) && (crashstate = puff->FindState(NAME_Crash)) != NULL)
{
puff->SetState (crashstate);
}
else if (attackrange == MELEERANGE && puff->MeleeState != NULL)
else if ((flags & PF_MELEERANGE) && puff->MeleeState != NULL)
{
// handle the hard coded state jump of Doom's bullet puff
// in a more flexible manner.
puff->SetState (puff->MeleeState);
}
if (cl_pufftype && updown != 3 && !temporary && (puff->flags4 & MF4_ALLOWPARTICLES))
if (!(flags & PF_TEMPORARY))
{
if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES))
{
P_DrawSplash2 (32, x, y, z, dir, updown, 1);
puff->renderflags |= RF_INVISIBLE;
}
if (!temporary)
{
if (hitthing && puff->SeeSound)
if ((flags & PF_HITTHING) && puff->SeeSound)
{ // Hit thing sound
S_SoundID (puff, CHAN_BODY, puff->SeeSound, 1, ATTN_NORM);
}
@ -5099,6 +5136,13 @@ void AActor::Crash()
}
}
void AActor::SetIdle()
{
FState *idle = FindState (NAME_Idle);
if (idle == NULL) idle = SpawnState;
SetState(idle);
}
FArchive &operator<< (FArchive &arc, FSoundIndex &snd)
{
if (arc.IsStoring ())

View file

@ -46,6 +46,7 @@
#include "p_lnspec.h"
#include "v_palette.h"
#include "c_console.h"
#include "c_cvars.h"
#include "p_acs.h"
#include "vectors.h"
#include "announcer.h"
@ -64,7 +65,7 @@
#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 void P_LoadTranslator(const char *lump);
@ -283,7 +284,7 @@ MapData *P_OpenMapData(const char * mapname)
if (lumpfile != nextfile)
{
// 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;
}
@ -383,6 +384,13 @@ MapData *P_OpenMapData(const char * mapname)
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;
}
//===========================================================================
//
// 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.type = LittleShort(mt->type);
P_SpawnMapThing (&mt2, position);
SpawnMapThing (i, &mt2, position);
}
delete [] mtp;
}
@ -1756,7 +1782,7 @@ void P_LoadThings2 (MapData * map, int position)
for (i=0, mt = (mapthing2_t*)mtp; i < numthings; i++,mt++)
{
P_SpawnMapThing (mt, position);
SpawnMapThing (i, mt, position);
}
delete[] mtp;
}
@ -3869,7 +3895,7 @@ void P_SetupLevel (char *lumpname, int position)
{
for (i = 0; i < numbuildthings; ++i)
{
P_SpawnMapThing (&buildthings[i], 0);
SpawnMapThing (i, &buildthings[i], 0);
}
delete[] buildthings;
}

View file

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

View file

@ -475,6 +475,9 @@ static int TryFindSwitch (side_t *side, int Where)
//
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 checkbot;
side_t *side = &sides[line->sidenum[sideno]];

View file

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

View file

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

View file

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

View file

@ -1103,7 +1103,7 @@ class FPlayerSkin
{
public:
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 range0start;
BYTE range0end;

View file

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

View file

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

View file

@ -465,7 +465,7 @@ FArchive &operator<< (FArchive &arc, ReverbContainer *&env)
return arc;
}
static void ReadEAX (int lump, const char *lumpname)
static void ReadEAX (int lump)
{
FScanner sc;
const ReverbContainer *def;
@ -476,7 +476,7 @@ static void ReadEAX (int lump, const char *lumpname)
bool inited[NUM_EAX_FIELDS];
BYTE bools[32];
sc.OpenLumpNum(lump, lumpname);
sc.OpenLumpNum(lump);
while (sc.GetString ())
{
name = copystring (sc.String);
@ -576,7 +576,7 @@ void S_ParseSndEax ()
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++)
{
if (HexenSequences[i].Name == Sequences[seq]->SeqName)
if (Sequences[seq] != NULL && HexenSequences[i].Name == Sequences[seq]->SeqName)
break;
}
if (seq == Sequences.Size())
@ -499,7 +499,7 @@ void S_ParseSndSeq (int levellump)
lump = levellump;
levellump = -2;
}
FScanner sc(lump, "SNDSEQ");
FScanner sc(lump);
while (sc.GetString ())
{
bool bDoorSound = false;
@ -514,7 +514,7 @@ void S_ParseSndSeq (int levellump)
seqtype = sc.String[0];
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]);
Sequences[curseq] = NULL;
@ -684,6 +684,10 @@ void S_ParseSndSeq (int levellump)
break;
}
}
if (curseq > 0)
{
sc.ScriptError("End of file encountered before the final sequence ended.");
}
}
if (gameinfo.gametype == GAME_Hexen)
@ -883,7 +887,7 @@ static int FindSequence (FName seqname)
for (i = Sequences.Size(); i-- > 0; )
{
if (seqname == Sequences[i]->SeqName)
if (Sequences[i] != NULL && seqname == Sequences[i]->SeqName)
{
return i;
}

View file

@ -379,7 +379,7 @@ void S_Start ()
if (*LocalSndInfo)
{
// Now parse the local SNDINFO
int j = Wads.CheckNumForName(LocalSndInfo);
int j = Wads.CheckNumForFullName(LocalSndInfo, true);
if (j>=0) S_AddLocalSndInfo(j);
}
@ -392,7 +392,7 @@ void S_Start ()
}
if (parse_ss)
{
S_ParseSndSeq(*LocalSndSeq? Wads.CheckNumForName(LocalSndSeq) : -1);
S_ParseSndSeq(*LocalSndSeq? Wads.CheckNumForFullName(LocalSndSeq, true) : -1);
}
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
// 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;
// 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;
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);
}
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 ();
{
FMemLump mem = Wads.ReadLump(lump);
ScriptBuffer = mem.GetString();
}
ScriptName = name;
ScriptName = Wads.GetLumpFullPath(lump);
PrepareScript ();
}

View file

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

View file

@ -1191,7 +1191,7 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
{
return oldmode;
}
double cpos[3];
float cpos[3];
cpos[0] = FIXED2FLOAT(players[consoleplayer].camera->x);
cpos[2] = FIXED2FLOAT(players[consoleplayer].camera->y);
cpos[1] = FIXED2FLOAT(players[consoleplayer].camera->z);
@ -1226,11 +1226,11 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t
return oldmode;
}
else if (cpos[0] == pos[0] && cpos[1] == pos[1] && cpos[2] == pos[2])
{
pos[2] = pos[1] = pos[0] = 0;
return (oldmode & ~FMOD_3D_WORLDRELATIVE) | FMOD_3D_HEADRELATIVE;
{ // Head relative
return (oldmode & ~FMOD_3D) | FMOD_2D;
}
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;
}
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)
{
DPrintf("Failed to allocate sample: %d\n", result);
DPrintf("Failed to allocate sample: Error %d\n", result);
errcount++;
continue;
}

View file

@ -147,6 +147,11 @@ FString MusInfo::GetStats()
return "No stats available for this song";
}
MusInfo *MusInfo::GetOPLDumper(const char *filename)
{
return NULL;
}
void I_InitMusic (void)
{
static bool setatterm = false;
@ -304,7 +309,6 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
/* MUS are played as:
- OPL:
- 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
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
- 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))
{
@ -369,7 +373,7 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
#ifdef _WIN32
if (info == NULL)
{
info = new MUSSong2 (file, musiccache, len);
info = new MUSSong2 (file, musiccache, len, false);
}
#endif // _WIN32
}
@ -384,7 +388,6 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
/* MIDI are played as:
OPL:
- 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
Timidity:
@ -422,8 +425,11 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
}
#endif // _WIN32
}
// Check for RDosPlay raw OPL format
else if (id == MAKE_ID('R','A','W','A') && len >= 12)
// Check for various raw OPL formats
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];
@ -441,30 +447,9 @@ void *I_RegisterSong (const char *filename, char *musiccache, int offset, int le
memcpy(fullsig, musiccache, 8);
}
if (fullsig[1] == MAKE_ID('D','A','T','A'))
{
info = new OPLMUSSong (file, musiccache, len);
}
}
// Check for Martin Fernandez's modified IMF format
else if (id == MAKE_ID('A','D','L','I'))
{
char fullhead[6];
if (file != NULL)
{
if (fread (fullhead, 1, 6, file) != 6)
{
fclose (file);
return 0;
}
fseek (file, -6, SEEK_CUR);
}
else
{
memcpy(fullhead, musiccache, 6);
}
if (fullhead[4] == 'B' && fullhead[5] == 1)
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')) ||
(fullsig[0] == MAKE_ID('A','D','L','I') && (fullsig[1] & MAKE_ID(255,255,0,0)) == MAKE_ID('B',1,0,0)))
{
info = new OPLMUSSong (file, musiccache, len);
}
@ -597,3 +582,40 @@ ADD_STAT(music)
}
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 void Update();
virtual FString GetStats();
virtual MusInfo *GetOPLDumper(const char *filename);
enum EState
{
@ -152,7 +153,7 @@ protected:
// OPL implementation of a MIDI output device -------------------------------
class OPLMIDIDevice : public MIDIDevice, OPLmusicBlock
class OPLMIDIDevice : public MIDIDevice, protected OPLmusicBlock
{
public:
OPLMIDIDevice();
@ -191,6 +192,17 @@ protected:
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 ------------------------------
class MIDIStreamer : public MusInfo
@ -210,13 +222,15 @@ public:
void Update();
protected:
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
MIDIStreamer(const char *dumpname);
void OutputVolume (DWORD volume);
int FillBuffer(int buffer_num, int max_events, DWORD max_time);
bool ServiceEvent();
int VolumeControllerChange(int channel, int volume);
static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
// Virtuals for subclasses to override
virtual void CheckCaps();
virtual void DoInitialSetup() = 0;
@ -261,6 +275,7 @@ protected:
DWORD Volume;
bool UseOPLDevice;
bool CallbackIsThreaded;
FString DumpFilename;
};
// MUS file played with a MIDI stream ---------------------------------------
@ -268,10 +283,14 @@ protected:
class MUSSong2 : public MIDIStreamer
{
public:
MUSSong2 (FILE *file, char *musiccache, int length);
~MUSSong2 ();
MUSSong2(FILE *file, char *musiccache, int length, bool opl);
~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
protected:
MUSSong2(const MUSSong2 *original, const char *filename); //OPL dump constructor
void DoInitialSetup();
void DoRestart();
bool CheckDone();
@ -288,10 +307,14 @@ protected:
class MIDISong2 : public MIDIStreamer
{
public:
MIDISong2 (FILE *file, char *musiccache, int length, bool opl);
~MIDISong2 ();
MIDISong2(FILE *file, char *musiccache, int length, bool opl);
~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
protected:
MIDISong2(const MIDISong2 *original, const char *filename); // OPL dump constructor
void CheckCaps();
void DoInitialSetup();
void DoRestart();
@ -307,6 +330,7 @@ protected:
void SetTempo(int new_tempo);
BYTE *MusHeader;
int SongLen;
TrackInfo *Tracks;
TrackInfo *TrackDue;
int NumTracks;
@ -381,19 +405,29 @@ protected:
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FILE *file, char * musiccache, int length);
OPLMUSSong (FILE *file, char *musiccache, int length);
~OPLMUSSong ();
void Play (bool looping);
bool IsPlaying ();
bool IsValid () const;
void ResetChips ();
MusInfo *GetOPLDumper(const char *filename);
protected:
OPLMUSSong(const OPLMUSSong *original, const char *filename); // OPL dump constructor
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
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 -----------------------
class CDSong : public MusInfo
@ -430,4 +464,3 @@ extern MusInfo *currSong;
extern int nomusic;
EXTERN_CVAR (Float, snd_musicvolume)
EXTERN_CVAR (Bool, opl_enable)

View file

@ -44,8 +44,6 @@
// 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.
#define CHECK_FINISHED \
if (track->TrackP >= track->MaxTrackP) \
@ -115,6 +113,7 @@ MIDISong2::MIDISong2 (FILE *file, char *musiccache, int len, bool opl)
}
#endif
MusHeader = new BYTE[len];
SongLen = len;
if (file != NULL)
{
if (fread(MusHeader, 1, len, file) != (size_t)len)
@ -754,3 +753,43 @@ void MIDISong2::SetTempo(int 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)
: MIDI(0),
:
#ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif
Division(0), InitialTempo(500000), UseOPLDevice(opl)
MIDI(0), Division(0), InitialTempo(500000), UseOPLDevice(opl)
{
#ifdef _WIN32
BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -91,6 +91,25 @@ MIDIStreamer::MIDIStreamer(bool opl)
#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
@ -163,7 +182,7 @@ void MIDIStreamer::CheckCaps()
//
//==========================================================================
void MIDIStreamer::Play (bool looping)
void MIDIStreamer::Play(bool looping)
{
DWORD tid;
@ -175,6 +194,11 @@ void MIDIStreamer::Play (bool looping)
InitialPlayback = true;
assert(MIDI == NULL);
if (DumpFilename.IsNotEmpty())
{
MIDI = new OPLDumperMIDIDevice(DumpFilename);
}
else
#ifdef _WIN32
if (!UseOPLDevice)
{
@ -281,7 +305,7 @@ void MIDIStreamer::Play (bool looping)
//
//==========================================================================
void MIDIStreamer::Pause ()
void MIDIStreamer::Pause()
{
if (m_Status == STATE_Playing)
{
@ -302,7 +326,7 @@ void MIDIStreamer::Pause ()
//
//==========================================================================
void MIDIStreamer::Resume ()
void MIDIStreamer::Resume()
{
if (m_Status == STATE_Paused)
{
@ -322,7 +346,7 @@ void MIDIStreamer::Resume ()
//
//==========================================================================
void MIDIStreamer::Stop ()
void MIDIStreamer::Stop()
{
EndQueued = 2;
#ifdef _WIN32
@ -355,7 +379,7 @@ void MIDIStreamer::Stop ()
//
//==========================================================================
bool MIDIStreamer::IsPlaying ()
bool MIDIStreamer::IsPlaying()
{
return m_Status != STATE_Stopped;
}
@ -369,7 +393,7 @@ bool MIDIStreamer::IsPlaying ()
//
//==========================================================================
void MIDIStreamer::MusicVolumeChanged ()
void MIDIStreamer::MusicVolumeChanged()
{
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 ------------------------------------------------------------
#include "i_musicinterns.h"
@ -52,8 +50,6 @@
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern UINT mididevice;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const BYTE CtrlTranslate[15] =
@ -88,13 +84,15 @@ static const BYTE CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len)
: MIDIStreamer(false), MusHeader(0), MusBuffer(0)
MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len, bool opl)
: MIDIStreamer(opl), MusHeader(0), MusBuffer(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)
{
return;
}
#endif
MusHeader = (MUSHeader *)new BYTE[len];
if (file != NULL)
@ -304,4 +302,32 @@ end:
}
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"
CVAR (Bool, opl_enable, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
static bool OPL_Active;
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)
{
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,
SoundStream::Mono | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
@ -63,7 +60,7 @@ void OPLMUSSong::Play (bool looping)
Music->SetLooping (looping);
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;
}
@ -74,3 +71,24 @@ bool OPLMUSSong::FillStream (SoundStream *stream, void *buff, int len, void *use
OPLMUSSong *song = (OPLMUSSong *)userdata;
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;
FScanner sc(lumpnum, "LANGUAGE");
FScanner sc(lumpnum);
sc.SetCMode (true);
while (sc.GetString ())
{

View file

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

View file

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

View file

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

View file

@ -1145,7 +1145,7 @@ void A_CustomPunch (AActor *self)
PuffType = PClass::FindClass(PuffTypeName);
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
if (linetarget)

View file

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

View file

@ -235,6 +235,7 @@ static flagdef ActorFlags[]=
DEFINE_FLAG(MF5, NEVERRESPAWN, AActor, flags5),
DEFINE_FLAG(MF5, DONTRIP, AActor, flags5),
DEFINE_FLAG(MF5, NOINFIGHTING, AActor, flags5),
DEFINE_FLAG(MF5, NOINTERACTION, AActor, flags5),
// Effect flags
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);
}
//==========================================================================
//
//==========================================================================
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.damagescreencolor", (apf)PlayerDmgScreenColor, 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.healradiustype", (apf)PlayerHealRadius, 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;
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)
{
@ -293,6 +287,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
double *luminosity;
int maxyoffs;
bool doomtemplate = gameinfo.gametype == GAME_Doom ? strncmp (nametemplate, "STCFN", 5) == 0 : false;
bool stcfn121 = false;
Chars = new CharData[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);
if (doomtemplate && lump >= 0 && i + start == 121)
{ // 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
// 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.
if (Wads.CheckNumForName ("STCFN120", 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;
stcfn121 = true;
}
}
if (lump != -1 || i != 124-start || !stcfn121)
charlumps[i] = lump;
if (lump >= 0)
{
FTexture *pic = TexMan[buffer];
@ -1631,7 +1631,7 @@ void V_InitCustomFonts()
while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1)
{
sc.OpenLumpNum(llump, "FONTDEFS");
sc.OpenLumpNum(llump);
while (sc.GetString())
{
memset (lumplist, -1, sizeof(lumplist));
@ -1691,7 +1691,7 @@ void V_InitCustomFonts()
if (format == 1) goto wrong;
int *p = &lumplist[*(unsigned char*)sc.String];
sc.MustGetString();
*p = Wads.CheckNumForName (sc.String);
*p = Wads.CheckNumForFullName (sc.String, true);
format=2;
}
}
@ -1759,7 +1759,7 @@ void V_InitFontColors ()
while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1)
{
FScanner sc(lump, "textcolors.txt");
FScanner sc(lump);
while (sc.GetString())
{
names.Clear();

View file

@ -77,7 +77,7 @@
// SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded.
#define MINSAVEVER 854
#define MINSAVEVER 879
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
// 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;
}
//==========================================================================
//
// 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

View file

@ -206,6 +206,7 @@ public:
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
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 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

View file

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

View file

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

View file

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

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