* Updated to ZDoom r2280:

- Added a Sector_CopyScroller special to allow setting scrollers to sectors with special tags.
- Extended compatibility text to allow changing line flags and setting line specials on specific linedefs.
- Removed Strain MAP07 hack and replaced it by a clean 'clearlineflags' option.
- Added Doomo format translations for Sector_CopyScroller because this looks like something that might be useful for making
some Boom maps work without having to resort to compatibility.txt.
- Added a compatibility setting for UAC Ultra MAP07 which exploited some undefined scrolling behavior in Boom.
(What lengths are we going to make sloppily created maps work? This entire commit was just to address this particular problem...)
- Added a few NULL pointer checks to protect against problems caused by actors being spawned during engine shutdown.
- Made the recent change to P_SeekerMissile an option because it affected critical gameplay behavior and may not be used for existing actors.
- Changed P_SeekerMissile() to compute a proper 3D trajectory.
- Fixed: maxitems calculation for MKEY_Up in M_OptButtonHandler() used the unscaled text height instead of the scaled text height to calculate the bottom-most usable row.
- Added MUS header scan to mus2midi.
- Fixed buffer overflow when reading a MUS song from a compressed file.
* Plugged a few memory leaks.

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@770 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
gez 2010-04-16 15:31:06 +00:00
parent 4bdedbc709
commit ed914c8ffe
25 changed files with 382 additions and 117 deletions

View file

@ -56,6 +56,7 @@ DEFINE_SPECIAL(Sector_ChangeFlags, 54, 3, 3, 3)
DEFINE_SPECIAL(Line_SetBlocking, 55, 3, 3, 3)
DEFINE_SPECIAL(Line_SetTextureScale, 56, 5, 5, 5)
DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5)
DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2)
DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3)
DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1)

View file

@ -43,10 +43,13 @@
#include "sc_man.h"
#include "cmdlib.h"
#include "doomdef.h"
#include "doomdata.h"
#include "doomstat.h"
#include "c_dispatch.h"
#include "gi.h"
#include "g_level.h"
#include "p_lnspec.h"
#include "r_state.h"
// MACROS ------------------------------------------------------------------
@ -59,6 +62,14 @@ struct FCompatOption
int BCompatFlags;
};
enum
{
CP_END,
CP_CLEARFLAGS,
CP_SETFLAGS,
CP_SETSPECIAL
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -77,7 +88,6 @@ static FCompatOption Options[] =
{
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
{ "spechitoverflow", 0, BCOMPATF_SPECHITOVERFLOW },
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
// list copied from g_mapinfo.cpp
@ -109,6 +119,9 @@ static FCompatOption Options[] =
{ NULL, 0, 0 }
};
static TArray<int> CompatParams;
static int ii_compatparams;
// CODE --------------------------------------------------------------------
//==========================================================================
@ -170,12 +183,57 @@ void ParseCompatibility()
} while (!sc.Compare("{"));
flags.CompatFlags = 0;
flags.BCompatFlags = 0;
while (sc.MustGetString(), (i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0)
flags.ExtCommandIndex = -1;
while (sc.GetString())
{
flags.CompatFlags |= Options[i].CompatFlags;
flags.BCompatFlags |= Options[i].BCompatFlags;
if ((i = sc.MatchString(&Options[0].Name, sizeof(*Options))) >= 0)
{
flags.CompatFlags |= Options[i].CompatFlags;
flags.BCompatFlags |= Options[i].BCompatFlags;
}
else if (sc.Compare("clearlineflags"))
{
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_CLEARFLAGS);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
}
else if (sc.Compare("setlineflags"))
{
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_SETFLAGS);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
}
else if (sc.Compare("setlinespecial"))
{
if (flags.ExtCommandIndex == -1) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_SETSPECIAL);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
sc.MustGetString();
CompatParams.Push(P_FindLineSpecial(sc.String, NULL, NULL));
for(int i=0;i<5;i++)
{
sc.MustGetNumber();
CompatParams.Push(sc.Number);
}
}
else
{
sc.UnGet();
break;
}
}
if (flags.ExtCommandIndex != -1)
{
CompatParams.Push(CP_END);
}
sc.UnGet();
sc.MustGetStringName("}");
for (j = 0; j < md5array.Size(); ++j)
{
@ -201,6 +259,7 @@ void CheckCompatibility(MapData *map)
{
ii_compatflags = COMPATF_SHORTTEX;
ib_compatflags = 0;
ii_compatparams = -1;
}
else
{
@ -223,17 +282,74 @@ void CheckCompatibility(MapData *map)
{
ii_compatflags = flags->CompatFlags;
ib_compatflags = flags->BCompatFlags;
ii_compatparams = flags->ExtCommandIndex;
}
else
{
ii_compatflags = 0;
ib_compatflags = 0;
ii_compatparams = -1;
}
}
// Reset i_compatflags
compatflags.Callback();
}
//==========================================================================
//
// SetCompatibilityParams
//
//==========================================================================
void SetCompatibilityParams()
{
if (ii_compatparams != -1)
{
unsigned i = ii_compatparams;
while (CompatParams[i] != CP_END && i < CompatParams.Size())
{
switch (CompatParams[i])
{
case CP_CLEARFLAGS:
{
if (CompatParams[i+1] < numlines)
{
line_t *line = &lines[CompatParams[i+1]];
line->flags &= ~CompatParams[i+2];
}
i+=3;
break;
}
case CP_SETFLAGS:
{
if (CompatParams[i+1] < numlines)
{
line_t *line = &lines[CompatParams[i+1]];
line->flags |= CompatParams[i+2];
}
i+=3;
break;
}
case CP_SETSPECIAL:
{
if (CompatParams[i+1] < numlines)
{
line_t *line = &lines[CompatParams[i+1]];
line->special = CompatParams[i+2];
for(int ii=0;ii<5;ii++)
{
line->args[ii] = CompatParams[i+ii+3];
}
}
i+=8;
break;
}
}
}
}
}
//==========================================================================
//
// CCMD mapchecksum

View file

@ -16,6 +16,7 @@ struct FCompatValues
{
int CompatFlags;
int BCompatFlags;
unsigned int ExtCommandIndex;
};
struct FMD5HashTraits
@ -37,5 +38,6 @@ extern TMap<FMD5Holder, FCompatValues, FMD5HashTraits> BCompatMap;
void ParseCompatibility();
void CheckCompatibility(MapData *map);
void SetCompatibilityParams();
#endif

View file

@ -333,8 +333,7 @@ enum
{
BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow
BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps
BCOMPATF_SPECHITOVERFLOW = 1 << 2, // Emulate spechit overflow (e.g. Strain MAP07)
BCOMPATF_VILEGHOSTS = 1 << 3, // Monsters' radius and height aren't restored properly when resurrected.
BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected.
};
// phares 3/20/98:

View file

@ -272,7 +272,7 @@ static bool gl_LoadVertexes(FileReader * f, wadlump_t * lump)
vertexes[i].y = LittleLong(mgl->y);
mgl++;
}
delete gldata;
delete[] gldata;
return true;
}

View file

@ -447,12 +447,12 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int cm, int clampmode, int
if (!hwtex->CreateTexture(buffer, w, h, true, texunit, cm, translation))
{
// could not create texture
delete buffer;
delete[] buffer;
return NULL;
}
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (clampmode & GLT_CLAMPX)? GL_CLAMP_TO_EDGE : GL_REPEAT);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (clampmode & GLT_CLAMPY)? GL_CLAMP_TO_EDGE : GL_REPEAT);
delete buffer;
delete[] buffer;
}
if (tex->bHasCanvas) static_cast<FCanvasTexture*>(tex)->NeedUpdate();
@ -504,10 +504,10 @@ const FHardwareTexture * FGLTexture::BindPatch(int texunit, int cm, int translat
if (!glpatch->CreateTexture(buffer, w, h, false, texunit, cm, translation))
{
// could not create texture
delete buffer;
delete[] buffer;
return NULL;
}
delete buffer;
delete[] buffer;
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

View file

@ -351,7 +351,7 @@ void FTexture::GetGlowColor(float *data)
if (buffer)
{
gl_info.GlowColor = averageColor((DWORD *) buffer, w*h, 6*FRACUNIT/10);
delete buffer;
delete[] buffer;
}
// Black glow equals nothing so switch glowing off
@ -388,7 +388,7 @@ PalEntry FTexture::GetSkyCapColor(bool bottom)
gl_info.FloorSkyColor = averageColor(((DWORD *) buffer)+(h-30)*w, w * 30, 0);
}
else gl_info.FloorSkyColor = gl_info.CeilingSkyColor;
delete buffer;
delete[] buffer;
}
}
return bottom? gl_info.FloorSkyColor : gl_info.CeilingSkyColor;

View file

@ -2332,7 +2332,8 @@ void M_OptButtonHandler(EMenuKey key, bool repeat)
}
ytop *= CleanYfac_1;
rowheight *= CleanYfac_1;
maxitems = (screen->GetHeight() - SmallFont->GetHeight() - ytop) / rowheight + 1;
maxitems = (screen->GetHeight() - rowheight - ytop) / rowheight + 1;
CurrentMenu->scrollpos = MAX (0,CurrentMenu->numitems - maxitems + CurrentMenu->scrolltop);
CurrentItem = CurrentMenu->numitems - 1;

View file

@ -53,7 +53,7 @@ static const BYTE StaticMIDIhead[] =
0, 255, 81, 3, 0x07, 0xa1, 0x20
};
static const DWORD MUSMagic = MAKE_ID('M','U','S',0x1a);
extern int MUSHeaderSearch(const BYTE *head, int len);
static const BYTE CtrlTranslate[15] =
{
@ -110,23 +110,30 @@ static size_t WriteVarLen (TArray<BYTE> &file, int time)
return ofs;
}
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile)
bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile)
{
BYTE midStatus, midArgs, mid1, mid2;
size_t mus_p, maxmus_p;
BYTE event;
int deltaTime;
const MUSHeader *musHead = (const MUSHeader *)musBuf;
const MUSHeader *musHead;
BYTE status;
BYTE chanUsed[16];
BYTE lastVel[16];
long trackLen;
bool no_op;
// Do some validation of the MUS file
if (MUSMagic != musHead->Magic)
// Find the header
int offset = MUSHeaderSearch(musBuf, len);
if (offset < 0 || offset + (int)sizeof(MUSHeader) >= len)
return false;
musBuf += offset;
len -= offset;
musHead = (const MUSHeader *)musBuf;
// Do some validation of the MUS file
if (LittleShort(musHead->NumChans) > 15)
return false;
@ -136,8 +143,12 @@ bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile)
memcpy(&outFile[0], StaticMIDIhead, sizeof(StaticMIDIhead));
musBuf += LittleShort(musHead->SongStart);
maxmus_p = LittleShort(musHead->SongLen);
mus_p = 0;
maxmus_p = LittleShort(musHead->SongLen);
if ((size_t)len - LittleShort(musHead->SongStart) < maxmus_p)
{
maxmus_p = len - LittleShort(musHead->SongStart);
}
memset (lastVel, 100, 16);
memset (chanUsed, 0, 16);
@ -287,10 +298,10 @@ bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile)
return true;
}
bool ProduceMIDI(const BYTE *musBuf, FILE *outFile)
bool ProduceMIDI(const BYTE *musBuf, int len, FILE *outFile)
{
TArray<BYTE> work;
if (ProduceMIDI(musBuf, work))
if (ProduceMIDI(musBuf, len, work))
{
return fwrite(&work[0], 1, work.Size(), outFile) == work.Size();
}

View file

@ -75,7 +75,7 @@ typedef struct
// WORD UsedInstruments[NumInstruments];
} MUSHeader;
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);
bool ProduceMIDI (const BYTE *musBuf, FILE *outFile);
bool ProduceMIDI (const BYTE *musBuf, int len, TArray<BYTE> &outFile);
bool ProduceMIDI (const BYTE *musBuf, int len, FILE *outFile);
#endif //__MUS2MIDI_H__

View file

@ -94,7 +94,7 @@ APlayerPawn *P_SpawnPlayer (FMapThing *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);
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false);
enum EPuffFlags
{

View file

@ -593,7 +593,10 @@ bool AActor::SetState (FState *newstate)
newstate = newstate->GetNextState();
} while (tics == 0);
screen->StateChanged(this);
if (screen != NULL)
{
screen->StateChanged(this);
}
return true;
}
@ -653,7 +656,10 @@ bool AActor::SetStateNF (FState *newstate)
newstate = newstate->GetNextState();
} while (tics == 0);
screen->StateChanged(this);
if (screen != NULL)
{
screen->StateChanged(this);
}
return true;
}
@ -1543,7 +1549,7 @@ bool AActor::CanSeek(AActor *target) const
//
//----------------------------------------------------------------------------
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise)
{
int dir;
int dist;
@ -1579,28 +1585,54 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
actor->angle -= delta;
}
angle = actor->angle>>ANGLETOFINESHIFT;
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
actor->vely = FixedMul (actor->Speed, finesine[angle]);
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
if (!precise)
{
if (actor->z + actor->height < target->z ||
target->z + target->height < actor->z)
{ // Need to seek vertically
dist = P_AproxDistance (target->x - actor->x, target->y - actor->y);
dist = dist / actor->Speed;
if (dist < 1)
{
dist = 1;
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
actor->vely = FixedMul (actor->Speed, finesine[angle]);
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
if (actor->z + actor->height < target->z ||
target->z + target->height < actor->z)
{ // Need to seek vertically
dist = P_AproxDistance (target->x - actor->x, target->y - actor->y);
dist = dist / actor->Speed;
if (dist < 1)
{
dist = 1;
}
actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist;
}
actor->velz = ((target->z+target->height/2) - (actor->z+actor->height/2)) / dist;
}
}
else
{
angle_t pitch;
if (!(actor->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{ // Need to seek vertically
double dist = MAX(1.0, FVector2(target->x - actor->x, target->y - actor->y).Length());
// Aim at a player's eyes and at the middle of the actor for everything else.
fixed_t aimheight = target->height/2;
if (target->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
aimheight = static_cast<APlayerPawn *>(target)->ViewHeight;
}
pitch = R_PointToAngle2(0, actor->z + actor->height/2, xs_CRoundToInt(dist), target->z + aimheight);
pitch >>= ANGLETOFINESHIFT;
}
fixed_t xyscale = FixedMul(actor->Speed, finecosine[pitch]);
actor->velz = FixedMul(actor->Speed, finesine[pitch]);
actor->velx = FixedMul(xyscale, finecosine[angle]);
actor->vely = FixedMul(xyscale, finesine[angle]);
}
return true;
}
//
// P_XYMovement
//
@ -3667,7 +3699,10 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t
{
level.total_items++;
}
screen->StateChanged(actor);
if (screen != NULL)
{
screen->StateChanged(actor);
}
return actor;
}

View file

@ -3558,15 +3558,7 @@ void P_SetupLevel (char *lumpname, int position)
else
P_LoadThings2 (map); // [RH] Load Hexen-style things
if (ib_compatflags & BCOMPATF_SPECHITOVERFLOW)
{
// restoring the original behavior doesn't work so we have to patch the levels in other ways.
// Fortunately the only known level depending on this bug is Strain's MAP07 and that's easy to fix.
if (numlines == 1022)
{
lines[1021].flags &= ~ML_BLOCKING;
}
}
SetCompatibilityParams();
}
else
{

View file

@ -1501,6 +1501,20 @@ static void P_SpawnScrollers(void)
{
int i;
line_t *l = lines;
TArray<int> copyscrollers;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (lines[i].args[0] != lines[i].frontsector->tag)
{
copyscrollers.Push(i);
}
lines[i].special = 0;
}
}
for (i = 0; i < numlines; i++, l++)
{
@ -1571,20 +1585,53 @@ static void P_SpawnScrollers(void)
case Scroll_Ceiling:
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;)
{
new DScroller (DScroller::sc_ceiling, -dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 1))
{
new DScroller (DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector-sectors), accel);
}
}
break;
case Scroll_Floor:
if (l->args[2] != 1)
{ // scroll the floor texture
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;)
{
new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 2))
{
new DScroller (DScroller::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
if (l->args[2] > 0)
{ // carry objects on the floor
for (s=-1; (s = P_FindSectorFromTag (l->args[0],s)) >= 0;)
{
new DScroller (DScroller::sc_carry, dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 4))
{
new DScroller (DScroller::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
break;

View file

@ -1671,10 +1671,10 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
chan->setReverbProperties(&reverb);
}
}
chan->setPaused(false);
chan->getPriority(&def_priority);
FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan);
schan->Rolloff = *rolloff;
chan->setPaused(false);
return schan;
}

View file

@ -84,6 +84,8 @@ extern void ChildSigHandler (int signum);
#define GZIP_FNAME 8
#define GZIP_FCOMMENT 16
extern int MUSHeaderSearch(const BYTE *head, int len);
EXTERN_CVAR (Int, snd_samplerate)
EXTERN_CVAR (Int, snd_mididevice)
@ -295,9 +297,14 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
{
FILE *file;
MusInfo *info = NULL;
DWORD id;
union
{
DWORD id[32/4];
BYTE idstr[32];
};
const char *fmt;
BYTE *ungzipped;
int i;
if (nomusic)
{
@ -322,22 +329,32 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
{
fseek (file, offset, SEEK_SET);
}
if (fread (&id, 4, 1, file) != 1)
if (len < 32)
{
return 0;
}
if (fread (id, 4, 32/4, file) != 32/4)
{
fclose (file);
return 0;
}
fseek (file, -4, SEEK_CUR);
fseek (file, -32, SEEK_CUR);
}
else
{
file = NULL;
id = *(DWORD *)musiccache;
if (len < 32)
{
return 0;
}
for (i = 0; i < 32/4; ++i)
{
id[i] = ((DWORD *)musiccache)[i];
}
}
#ifndef _WIN32
// non-windows platforms don't support MDEV_MIDI so map to MDEV_FMOD
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD
if (device == MDEV_MMAPI)
device = MDEV_FMOD;
#endif
@ -346,7 +363,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
// that can handle it, so it simplifies things if we make all songs
// gzippable.
ungzipped = NULL;
if ((id & MAKE_ID(255,255,255,0)) == GZIP_ID)
if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID)
{
if (offset != -1)
{
@ -370,11 +387,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
return NULL;
}
musiccache = ungzipped;
id = *(DWORD *)ungzipped;
for (i = 0; i < 32/4; ++i)
{
id[i] = ((DWORD *)musiccache)[i];
}
}
// Check for MUS format
if (id == MAKE_ID('M','U','S',0x1a))
// Tolerate sloppy wads by searching up to 32 bytes for the header
if (MUSHeaderSearch(idstr, sizeof(idstr)) >= 0)
{
/* MUS are played as:
- OPL:
@ -420,7 +441,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
if (file == NULL)
{
midi_made = ProduceMIDI((BYTE *)musiccache, midi);
midi_made = ProduceMIDI((BYTE *)musiccache, len, midi);
}
else
{
@ -428,7 +449,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
size_t did_read = fread(mus, 1, len, file);
if (did_read == (size_t)len)
{
midi_made = ProduceMIDI(mus, midi);
midi_made = ProduceMIDI(mus, len, midi);
}
fseek(file, -(long)did_read, SEEK_CUR);
delete[] mus;
@ -453,7 +474,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
// Check for MIDI format
else
{
if (id == MAKE_ID('M','T','h','d'))
if (id[0] == MAKE_ID('M','T','h','d'))
{
// This is a midi file
@ -502,36 +523,15 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
#endif // _WIN32
}
// 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
else if (
(id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
{
DWORD fullsig[2];
if (file != NULL)
{
if (fread (fullsig, 4, 2, file) != 2)
{
fclose (file);
return 0;
}
fseek (file, -8, SEEK_CUR);
}
else
{
memcpy(fullsig, musiccache, 8);
}
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);
}
info = new OPLMUSSong (file, musiccache, len);
}
// Check for game music
else if ((fmt = GME_CheckFormat(id)) != NULL && fmt[0] != '\0')
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')
{
info = GME_OpenSong(file, musiccache, len, fmt);
}
@ -545,7 +545,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
if (info == NULL)
{
// Check for CDDA "format"
if (id == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
{
if (file != NULL)
{
@ -572,7 +572,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
// smaller than this can't possibly be a valid music file if it hasn't
// been identified already, so don't even bother trying to load it.
// Of course MIDIs shorter than 1024 bytes should pass.
if (info == NULL && (len >= 1024 || id == MAKE_ID('M','T','h','d')))
if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d')))
{
// Let FMOD figure out what it is.
if (file != NULL)

View file

@ -227,7 +227,7 @@ TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len)
}
else
{
success = ProduceMIDI (buf, f);
success = ProduceMIDI (buf, len, f);
}
fclose (f);
if (file != NULL)

View file

@ -51,6 +51,8 @@
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
int MUSHeaderSearch(const BYTE *head, int len);
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -99,32 +101,56 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type)
}
#endif
MusHeader = (MUSHeader *)new BYTE[len];
if (file != NULL)
BYTE front[32];
int start;
if (file == NULL)
{
if (fread(MusHeader, 1, len, file) != (size_t)len)
memcpy(front, musiccache, sizeof(front));
}
else if (fread(front, 1, sizeof(front), file) != sizeof(front))
{
return;
}
// To tolerate sloppy wads (diescum.wad, I'm looking at you), we search
// the first 32 bytes of the file for a signature. My guess is that DMX
// does no validation whatsoever and just assumes it was passed a valid
// MUS file, since where the header is offset affects how it plays.
start = MUSHeaderSearch(front, sizeof(front));
if (start < 0)
{
return;
}
// Read the remainder of the song.
len = int(len - start);
if (len < sizeof(MusHeader))
{ // It's too short.
return;
}
MusHeader = (MUSHeader *)new BYTE[len];
if (file == NULL)
{
memcpy(MusHeader, musiccache + start, len);
}
else
{
memcpy(MusHeader, front + start, sizeof(front) - start);
if (fread((BYTE *)MusHeader + sizeof(front) - start, 1, len - (sizeof(front) - start), file) != (size_t)(len - (32 - start)))
{
return;
}
}
else
{
memcpy(MusHeader, musiccache, len);
}
// Do some validation of the MUS file
if (MusHeader->Magic != MAKE_ID('M','U','S','\x1a'))
{
return;
}
// Do some validation of the MUS file.
if (LittleShort(MusHeader->NumChans) > 15)
{
return;
}
MusBuffer = (BYTE *)MusHeader + LittleShort(MusHeader->SongStart);
MaxMusP = MIN<int> (LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart));
MaxMusP = MIN<int>(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart));
Division = 140;
InitialTempo = 1000000;
}
@ -376,3 +402,25 @@ MUSSong2::MUSSong2(const MUSSong2 *original, const char *filename, EMIDIDevice t
Division = 140;
InitialTempo = 1000000;
}
//==========================================================================
//
// MUSHeaderSearch
//
// Searches for the MUS header within the given memory block, returning
// the offset it was found at, or -1 if not present.
//
//==========================================================================
int MUSHeaderSearch(const BYTE *head, int len)
{
len -= 4;
for (int i = 0; i <= len; ++i)
{
if (head[i+0] == 'M' && head[i+1] == 'U' && head[i+2] == 'S' && head[i+3] == 0x1A)
{
return i;
}
}
return -1;
}

View file

@ -35,7 +35,7 @@
** lists for different types of thinkers is taken from Build. Every thinker
** is ticked by statnum, so a thinker with a low statnum will always tick
** before a thinker with a high statnum. If a thinker is not explicitly
** created with a statnum, it will be given MAX_STATNUM.
** created with a statnum, it will be given STAT_DEFAULT
*/
enum
@ -59,10 +59,10 @@ enum
STAT_EARTHQUAKE, // Earthquake actors
STAT_MAPMARKER, // Map marker actors
STAT_DEFAULT = 100,
STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise.
STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement
STAT_ACTORMOVER, // actor movers
STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors calles PostBeginPlay
STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay
};
#endif

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 "2272"
#define ZD_SVN_REVISION_NUMBER 2272
#define ZD_SVN_REVISION_STRING "2280"
#define ZD_SVN_REVISION_NUMBER 2280

View file

@ -614,6 +614,7 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota
FBitmap bmp1;
if (bmp1.Create(Parts[i].Texture->GetWidth(), Parts[i].Texture->GetHeight()))
{
bmp1.Zero();
bmp1.Zero();
Parts[i].Texture->CopyTrueColorPixels(&bmp1, 0, 0);
bmp->CopyPixelDataRGB(x+Parts[i].OriginX, y+Parts[i].OriginY, bmp1.GetPixels(),

View file

@ -346,6 +346,7 @@ static FRandom pr_seekermissile ("SeekerMissile");
enum
{
SMF_LOOK = 1,
SMF_PRECISE = 2,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile)
{
@ -360,7 +361,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile)
{
self->tracer = P_RoughMonsterSearch (self, distance);
}
P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1);
P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1, !!(flags & SMF_PRECISE));
}
//==========================================================================

View file

@ -79,6 +79,7 @@ const int BF_AFFECTBOSSES = 4;
// Flags for A_SeekerMissile
const int SMF_LOOK = 1;
const int SMF_PRECISE = 2;
// Activation flags
enum

View file

@ -58,7 +58,7 @@ F84AB4557464A383E93F37CD3A82AC48 // MM2 map03
9D50EBE17CEC78938C7A668DB0768611 // Strain map07: Make the exit accessible
{
spechitoverflow
clearlineflags 1021 1
}
71C2E6D9CFA3D8750C6A9599FB2453BD // Hacx map03: There are some switches behind
@ -128,3 +128,9 @@ CA267398C9B3A8F79349D3394F8B2106 // map20
{
spritesort
}
DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller depending on Boom side effects
{
setlinespecial 391 Sector_CopyScroller 99 6 0 0 0
}

View file

@ -336,6 +336,10 @@ include "xlat/defines.i"
350 = 0, Transfer_Heights (tag, 2) // Just fake the floor
351 = 0, Transfer_Heights (tag, 6) // Just fake the floor and clip it too
352 = 0, Sector_CopyScroller(tag, 1) // copy ceiling scroller
353 = 0, Sector_CopyScroller(tag, 2) // copy floor scroller
354 = 0, Sector_CopyScroller(tag, 6) // copy carrying floor scroller
/****** EDGE linetypes ******/
400 = 0, Sector_Set3DFloor(tag, 1, 0, 255)