mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2024-11-14 00:10:37 +00:00
* Updated to ZDoom r3383:
- Added writemidi console command. If the currently playing song is a MIDI variant, this will write it to disk. - Fixed: XMISong::ProcessInitialMetaEvents() did not set the Division for tempo events. (Why does XMI modify the division based on the tempo?) - Fixed: UDMFParser::AddUserKey() checked against the wrong token types when determining the values type. Also, GetUDMFInt() performed a float-to-fixed conversion on the value it returned. - Fixed: The nodebuilder is highly likely to renumber vertices, so we need to remember how the original vertices map to the new ones until after vertex slopes are handled. - Added custom flechettes patch, with ArtiPoisonBag4 renamed to ArtiPoisonBagGiver and ArtiPoisonBag5 renamed to ArtiPoisonBagShooter. - Added thrupushups fix. - Added HMI/XMI division fixes, and partially the XMI tempo fix (not currently used). - Fix strife linetype 11 again. - Added startup screen customization. - Print named script's names for the scriptstat console command. - Added ACS_NamedExecuteWithResult for DECORATE expressions. Since this is a pretty long name, you can also use CallACS, if you wish. The two are synonyms. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@1287 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
parent
17f87f870f
commit
40af0eae39
25 changed files with 354 additions and 48 deletions
|
@ -1701,6 +1701,25 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
|
|||
sc.MustGetString();
|
||||
DoomStartupInfo.BkColor = V_GetColor(NULL, sc.String);
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("STARTUPTYPE"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
FString sttype = sc.String;
|
||||
if (!sttype.CompareNoCase("DOOM"))
|
||||
DoomStartupInfo.Type = FStartupInfo::DoomStartup;
|
||||
else if (!sttype.CompareNoCase("HERETIC"))
|
||||
DoomStartupInfo.Type = FStartupInfo::HereticStartup;
|
||||
else if (!sttype.CompareNoCase("HEXEN"))
|
||||
DoomStartupInfo.Type = FStartupInfo::HexenStartup;
|
||||
else if (!sttype.CompareNoCase("STRIFE"))
|
||||
DoomStartupInfo.Type = FStartupInfo::StrifeStartup;
|
||||
else DoomStartupInfo.Type = FStartupInfo::DefaultStartup;
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("STARTUPSONG"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
DoomStartupInfo.Song = sc.String;
|
||||
}
|
||||
}
|
||||
return iwad;
|
||||
}
|
||||
|
|
11
src/d_main.h
11
src/d_main.h
|
@ -94,6 +94,17 @@ struct FStartupInfo
|
|||
FString Name;
|
||||
DWORD FgColor; // Foreground color for title banner
|
||||
DWORD BkColor; // Background color for title banner
|
||||
FString Song;
|
||||
int Type;
|
||||
enum
|
||||
{
|
||||
DefaultStartup,
|
||||
DoomStartup,
|
||||
HereticStartup,
|
||||
HexenStartup,
|
||||
StrifeStartup,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
extern FStartupInfo DoomStartupInfo;
|
||||
|
|
|
@ -119,7 +119,7 @@ bool AArtiPoisonBag3::Use (bool pickup)
|
|||
*/
|
||||
|
||||
// When looking straight ahead, it uses a z velocity of 4 while the xy velocity
|
||||
// is as set by the projectile. To accomodate this with a proper trajectory, we
|
||||
// is as set by the projectile. To accommodate this with a proper trajectory, we
|
||||
// aim the projectile ~20 degrees higher than we're looking at and increase the
|
||||
// speed we fire at accordingly.
|
||||
angle_t orgpitch = angle_t(-Owner->pitch) >> ANGLETOFINESHIFT;
|
||||
|
@ -141,6 +141,72 @@ bool AArtiPoisonBag3::Use (bool pickup)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Poison Bag 4 (Generic Giver) ----------------------------------------------
|
||||
|
||||
class AArtiPoisonBagGiver : public AArtiPoisonBag
|
||||
{
|
||||
DECLARE_CLASS (AArtiPoisonBagGiver, AArtiPoisonBag)
|
||||
public:
|
||||
bool Use (bool pickup);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS (AArtiPoisonBagGiver)
|
||||
|
||||
bool AArtiPoisonBagGiver::Use (bool pickup)
|
||||
{
|
||||
const PClass *MissileType = PClass::FindClass((ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None));
|
||||
if (MissileType != NULL)
|
||||
{
|
||||
AActor *mo = Spawn (MissileType, Owner->x, Owner->y, Owner->z, ALLOW_REPLACE);
|
||||
if (mo != NULL)
|
||||
{
|
||||
if (mo->IsKindOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
AInventory *inv = static_cast<AInventory *>(mo);
|
||||
if (inv->CallTryPickup(Owner))
|
||||
return true;
|
||||
}
|
||||
mo->Destroy(); // Destroy if not inventory or couldn't be picked up
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Poison Bag 5 (Generic Thrower) ----------------------------------------------
|
||||
|
||||
class AArtiPoisonBagShooter : public AArtiPoisonBag
|
||||
{
|
||||
DECLARE_CLASS (AArtiPoisonBagShooter, AArtiPoisonBag)
|
||||
public:
|
||||
bool Use (bool pickup);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS (AArtiPoisonBagShooter)
|
||||
|
||||
bool AArtiPoisonBagShooter::Use (bool pickup)
|
||||
{
|
||||
const PClass *MissileType = PClass::FindClass((ENamedName) this->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_None));
|
||||
if (MissileType != NULL)
|
||||
{
|
||||
AActor *mo = P_SpawnPlayerMissile(Owner, MissileType);
|
||||
if (mo != NULL)
|
||||
{
|
||||
// automatic handling of seeker missiles
|
||||
if (mo->flags2 & MF2_SEEKERMISSILE)
|
||||
{
|
||||
mo->tracer = Owner->target;
|
||||
}
|
||||
// set the health value so that the missile works properly
|
||||
if (mo->flags4 & MF4_SPECTRAL)
|
||||
{
|
||||
mo->health = -2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// GetFlechetteType
|
||||
|
|
|
@ -270,6 +270,8 @@ xx(MomX)
|
|||
xx(MomY)
|
||||
xx(MomZ)
|
||||
xx(Abs)
|
||||
xx(ACS_NamedExecuteWithResult)
|
||||
xx(CallACS)
|
||||
|
||||
// Various actor names which are used internally
|
||||
xx(MapSpot)
|
||||
|
|
|
@ -65,8 +65,8 @@ const int AAPreference = 16;
|
|||
FNodeBuilder::FNodeBuilder(FLevel &level)
|
||||
: Level(level), GLNodes(false), SegsStuffed(0)
|
||||
{
|
||||
|
||||
VertexMap = NULL;
|
||||
OldVertexTable = NULL;
|
||||
}
|
||||
|
||||
FNodeBuilder::FNodeBuilder (FLevel &level,
|
||||
|
@ -84,10 +84,14 @@ FNodeBuilder::FNodeBuilder (FLevel &level,
|
|||
|
||||
FNodeBuilder::~FNodeBuilder()
|
||||
{
|
||||
if (VertexMap != 0)
|
||||
if (VertexMap != NULL)
|
||||
{
|
||||
delete VertexMap;
|
||||
}
|
||||
if (OldVertexTable != NULL)
|
||||
{
|
||||
delete OldVertexTable;
|
||||
}
|
||||
}
|
||||
|
||||
void FNodeBuilder::BuildMini(bool makeGLNodes)
|
||||
|
|
|
@ -209,6 +209,7 @@ public:
|
|||
seg_t *&segs, glsegextra_t *&glsegextras, int &segCount,
|
||||
subsector_t *&ssecs, int &subCount,
|
||||
vertex_t *&verts, int &vertCount);
|
||||
const int *GetOldVertexTable();
|
||||
|
||||
// These are used for building sub-BSP trees for polyobjects.
|
||||
void Clear();
|
||||
|
@ -227,6 +228,7 @@ public:
|
|||
|
||||
private:
|
||||
IVertexMap *VertexMap;
|
||||
int *OldVertexTable;
|
||||
|
||||
TArray<node_t> Nodes;
|
||||
TArray<subsector_t> Subsectors;
|
||||
|
|
|
@ -75,7 +75,7 @@ angle_t FNodeBuilder::PointToAngle (fixed_t x, fixed_t y)
|
|||
|
||||
void FNodeBuilder::FindUsedVertices (vertex_t *oldverts, int max)
|
||||
{
|
||||
int *map = (int *)alloca (max*sizeof(int));
|
||||
int *map = new int[max];
|
||||
int i;
|
||||
FPrivVert newvert;
|
||||
|
||||
|
@ -102,6 +102,17 @@ void FNodeBuilder::FindUsedVertices (vertex_t *oldverts, int max)
|
|||
Level.Lines[i].v1 = (vertex_t *)(size_t)map[v1];
|
||||
Level.Lines[i].v2 = (vertex_t *)(size_t)map[v2];
|
||||
}
|
||||
OldVertexTable = map;
|
||||
}
|
||||
|
||||
// Retrieves the original vertex -> current vertex table.
|
||||
// Doing so prevents the node builder from freeing it.
|
||||
|
||||
const int *FNodeBuilder::GetOldVertexTable()
|
||||
{
|
||||
int *table = OldVertexTable;
|
||||
OldVertexTable = NULL;
|
||||
return table;
|
||||
}
|
||||
|
||||
// For every sidedef in the map, create a corresponding seg.
|
||||
|
|
|
@ -7375,7 +7375,14 @@ void DACSThinker::DumpScriptStatus ()
|
|||
|
||||
while (script != NULL)
|
||||
{
|
||||
Printf ("%d: %s\n", script->script, stateNames[script->state]);
|
||||
if (script->script < 0)
|
||||
{
|
||||
Printf("\"%s\": %s\n", FName(ENamedName(-script->script)).GetChars(), stateNames[script->state]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("%d: %s\n", script->script, stateNames[script->state]);
|
||||
}
|
||||
script = script->next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4763,11 +4763,20 @@ int P_PushUp (AActor *thing, FChangePosition *cpos)
|
|||
{
|
||||
return 1;
|
||||
}
|
||||
// [GZ] Skip thing intersect test for THRUACTORS things.
|
||||
if (thing->flags2 & MF2_THRUACTORS)
|
||||
return 0;
|
||||
P_FindAboveIntersectors (thing);
|
||||
lastintersect = intersectors.Size ();
|
||||
for (; firstintersect < lastintersect; firstintersect++)
|
||||
{
|
||||
AActor *intersect = intersectors[firstintersect];
|
||||
// [GZ] Skip this iteration for THRUSPECIES things
|
||||
// Should there be MF2_THRUGHOST / MF3_GHOST checks there too for consistency?
|
||||
// Or would that risk breaking established behavior? THRUGHOST, like MTHRUSPECIES,
|
||||
// is normally for projectiles which would have exploded by now anyway...
|
||||
if (thing->flags6 & MF6_THRUSPECIES && thing->GetSpecies() == intersect->GetSpecies())
|
||||
continue;
|
||||
if (!(intersect->flags2 & MF2_PASSMOBJ) ||
|
||||
(!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) ||
|
||||
(intersect->flags4 & MF4_ACTLIKEBRIDGE)
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
|
||||
#define MISSING_TEXTURE_WARN_LIMIT 20
|
||||
|
||||
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt);
|
||||
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt, const int *oldvertextable);
|
||||
void P_SetSlopes ();
|
||||
void P_CopySlopes();
|
||||
void BloodCrypt (void *data, int key, int len);
|
||||
|
@ -3444,6 +3444,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
int numbuildthings;
|
||||
int i;
|
||||
bool buildmap;
|
||||
const int *oldvertextable = NULL;
|
||||
|
||||
// This is motivated as follows:
|
||||
|
||||
|
@ -3758,7 +3759,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
bool BuildGLNodes;
|
||||
if (ForceNodeBuild)
|
||||
{
|
||||
BuildGLNodes = Renderer->RequireGLNodes() || am_textured || multiplayer || demoplayback || demorecording || genglnodes;
|
||||
BuildGLNodes = RequireGLNodes || multiplayer || demoplayback || demorecording || genglnodes;
|
||||
|
||||
startTime = I_FPSTime ();
|
||||
TArray<FNodeBuilder::FPolyStart> polyspots, anchors;
|
||||
|
@ -3782,6 +3783,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
vertexes, numvertexes);
|
||||
endTime = I_FPSTime ();
|
||||
DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs);
|
||||
oldvertextable = builder.GetOldVertexTable();
|
||||
reloop = true;
|
||||
}
|
||||
else
|
||||
|
@ -3868,7 +3870,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
if (!buildmap)
|
||||
{
|
||||
// [RH] Spawn slope creating things first.
|
||||
P_SpawnSlopeMakers (&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()]);
|
||||
P_SpawnSlopeMakers (&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()], oldvertextable);
|
||||
P_CopySlopes();
|
||||
|
||||
// Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials
|
||||
|
@ -3898,6 +3900,10 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
delete[] buildthings;
|
||||
}
|
||||
delete map;
|
||||
if (oldvertextable != NULL)
|
||||
{
|
||||
delete[] oldvertextable;
|
||||
}
|
||||
|
||||
// set up world state
|
||||
P_SpawnSpecials ();
|
||||
|
|
|
@ -280,7 +280,7 @@ enum
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt)
|
||||
static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt, const int *oldvertextable)
|
||||
{
|
||||
TMap<int, fixed_t> vt_heights[2];
|
||||
FMapThing *mt;
|
||||
|
@ -311,15 +311,17 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt)
|
|||
|
||||
for(int i = 0; i < numvertexdatas; i++)
|
||||
{
|
||||
int ii = oldvertextable == NULL ? i : oldvertextable[i];
|
||||
|
||||
if (vertexdatas[i].flags & VERTEXFLAG_ZCeilingEnabled)
|
||||
{
|
||||
vt_heights[1][i] = vertexdatas[i].zCeiling;
|
||||
vt_heights[1][ii] = vertexdatas[i].zCeiling;
|
||||
vt_found = true;
|
||||
}
|
||||
|
||||
if (vertexdatas[i].flags & VERTEXFLAG_ZFloorEnabled)
|
||||
{
|
||||
vt_heights[0][i] = vertexdatas[i].zFloor;
|
||||
vt_heights[0][ii] = vertexdatas[i].zFloor;
|
||||
vt_found = true;
|
||||
}
|
||||
}
|
||||
|
@ -413,7 +415,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt)
|
||||
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt, const int *oldvertextable)
|
||||
{
|
||||
FMapThing *mt;
|
||||
|
||||
|
@ -421,7 +423,7 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt)
|
|||
{
|
||||
if ((mt->type >= THING_SlopeFloorPointLine &&
|
||||
mt->type <= THING_SetCeilingSlope) ||
|
||||
mt->type==THING_VavoomFloor || mt->type==THING_VavoomCeiling)
|
||||
mt->type == THING_VavoomFloor || mt->type == THING_VavoomCeiling)
|
||||
{
|
||||
fixed_t x, y, z;
|
||||
secplane_t *refplane;
|
||||
|
@ -439,7 +441,7 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt)
|
|||
refplane = &sec->floorplane;
|
||||
}
|
||||
z = refplane->ZatPoint (x, y) + (mt->z);
|
||||
if (mt->type==THING_VavoomFloor || mt->type==THING_VavoomCeiling)
|
||||
if (mt->type == THING_VavoomFloor || mt->type == THING_VavoomCeiling)
|
||||
{
|
||||
P_VavoomSlope(sec, mt->thingid, x, y, mt->z, mt->type & 1);
|
||||
}
|
||||
|
@ -465,7 +467,7 @@ void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt)
|
|||
}
|
||||
}
|
||||
|
||||
P_SetSlopesFromVertexHeights(firstmt, lastmt);
|
||||
P_SetSlopesFromVertexHeights(firstmt, lastmt, oldvertextable);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ int GetUDMFInt(int type, int index, const char *key)
|
|||
FUDMFKey *pKey = pKeys->Find(key);
|
||||
if (pKey != NULL)
|
||||
{
|
||||
return FLOAT2FIXED(pKey->IntVal);
|
||||
return pKey->IntVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -414,14 +414,14 @@ public:
|
|||
{
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_Int:
|
||||
case TK_IntConst:
|
||||
keyarray[i] = sc.Number;
|
||||
break;
|
||||
case TK_Float:
|
||||
case TK_FloatConst:
|
||||
keyarray[i] = sc.Float;
|
||||
break;
|
||||
default:
|
||||
case TK_String:
|
||||
case TK_StringConst:
|
||||
keyarray[i] = parsedString;
|
||||
break;
|
||||
case TK_True:
|
||||
|
@ -438,14 +438,14 @@ public:
|
|||
ukey.Key = key;
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_Int:
|
||||
case TK_IntConst:
|
||||
ukey = sc.Number;
|
||||
break;
|
||||
case TK_Float:
|
||||
case TK_FloatConst:
|
||||
ukey = sc.Float;
|
||||
break;
|
||||
default:
|
||||
case TK_String:
|
||||
case TK_StringConst:
|
||||
ukey = parsedString;
|
||||
break;
|
||||
case TK_True:
|
||||
|
|
|
@ -830,3 +830,51 @@ CCMD (writewave)
|
|||
Printf ("Usage: writewave <filename> [sample rate]");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD writemidi
|
||||
//
|
||||
// If the currently playing song is a MIDI variant, write it to disk.
|
||||
// If successful, the current song will restart, since MIDI file generation
|
||||
// involves a simulated playthrough of the song.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD (writemidi)
|
||||
{
|
||||
if (argv.argc() != 2)
|
||||
{
|
||||
Printf("Usage: writemidi <filename>");
|
||||
return;
|
||||
}
|
||||
if (currSong == NULL)
|
||||
{
|
||||
Printf("No song is currently playing.\n");
|
||||
return;
|
||||
}
|
||||
if (!currSong->IsMIDI())
|
||||
{
|
||||
Printf("Current song is not MIDI-based.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<BYTE> midi;
|
||||
FILE *f;
|
||||
bool success;
|
||||
|
||||
static_cast<MIDIStreamer *>(currSong)->CreateSMF(midi, 1);
|
||||
f = fopen(argv[1], "wb");
|
||||
if (f == NULL)
|
||||
{
|
||||
Printf("Could not open %s.\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size());
|
||||
fclose (f);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Printf("Could not write to music file.\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -425,7 +425,7 @@ public:
|
|||
void FluidSettingInt(const char *setting, int value);
|
||||
void FluidSettingNum(const char *setting, double value);
|
||||
void FluidSettingStr(const char *setting, const char *value);
|
||||
void CreateSMF(TArray<BYTE> &file);
|
||||
void CreateSMF(TArray<BYTE> &file, int looplimit=0);
|
||||
|
||||
protected:
|
||||
MIDIStreamer(const char *dumpname, EMidiDevice type);
|
||||
|
@ -637,6 +637,7 @@ protected:
|
|||
|
||||
int FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const;
|
||||
void FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const;
|
||||
void ScanForTempo(const TrackInfo *song);
|
||||
bool SetMIDISubsong(int subsong);
|
||||
void DoInitialSetup();
|
||||
void DoRestart();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** music_midi_midiout.cpp
|
||||
** music_hmi_midiout.cpp
|
||||
** Code to let ZDoom play HMI MIDI music through the MIDI streaming API.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
|
@ -54,7 +54,7 @@
|
|||
}
|
||||
|
||||
// In song header
|
||||
#define HMI_DIVISION_OFFSET 0xD2
|
||||
#define HMI_DIVISION_OFFSET 0xD4
|
||||
#define HMI_TRACK_COUNT_OFFSET 0xE4
|
||||
#define HMI_TRACK_DIR_PTR_OFFSET 0xE8
|
||||
|
||||
|
@ -202,7 +202,10 @@ void HMISong::SetupForHMI(int len)
|
|||
}
|
||||
|
||||
// The division is the number of pulses per quarter note (PPQN).
|
||||
Division = GetShort(MusHeader + HMI_DIVISION_OFFSET);
|
||||
// HMI files have two values here, a full value and a quarter value. Some games,
|
||||
// notably Quarantines, have identical values for some reason, so it's safer to
|
||||
// use the quarter value and multiply it by four than to trust the full value.
|
||||
Division = GetShort(MusHeader + HMI_DIVISION_OFFSET) << 2;
|
||||
InitialTempo = 4000000;
|
||||
|
||||
Tracks = new TrackInfo[NumTracks + 1];
|
||||
|
|
|
@ -1062,14 +1062,14 @@ void MIDIStreamer::Precache()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void MIDIStreamer::CreateSMF(TArray<BYTE> &file)
|
||||
void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
|
||||
{
|
||||
DWORD delay = 0;
|
||||
BYTE running_status = 0;
|
||||
|
||||
// Always create songs aimed at GM devices.
|
||||
CheckCaps(MOD_MIDIPORT);
|
||||
LoopLimit = EXPORT_LOOP_LIMIT;
|
||||
LoopLimit = looplimit <= 0 ? EXPORT_LOOP_LIMIT : looplimit;
|
||||
DoRestart();
|
||||
Tempo = InitialTempo;
|
||||
|
||||
|
|
|
@ -134,14 +134,16 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type)
|
|||
{
|
||||
return;
|
||||
}
|
||||
// The division is the number of pulses per quarter note (PPQN).
|
||||
// It is set by a specific MIDI event, but just in case these aren't used,
|
||||
// set a default value. Specs indicate it should be 120.
|
||||
Division = 120;
|
||||
Songs = new TrackInfo[NumSongs];
|
||||
memset(Songs, 0, sizeof(*Songs) * NumSongs);
|
||||
FindXMIDforms(MusHeader, len, Songs);
|
||||
CurrSong = Songs;
|
||||
DPrintf("XMI song count: %d\n", NumSongs);
|
||||
|
||||
// The division is the number of pulses per quarter note (PPQN).
|
||||
Division = 60;
|
||||
DPrintf("Divisions: %d\n", Division);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -198,6 +200,8 @@ int XMISong::FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const
|
|||
// IFF chunks are padded to even byte boundaries to avoid
|
||||
// unaligned reads on 68k processors.
|
||||
p += 8 + chunklen + (chunklen & 1);
|
||||
// Avoid crashes from corrupt chunks which indicate a negative size.
|
||||
if (chunklen < 0) p = len;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -233,6 +237,37 @@ void XMISong::FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// XMISong :: ScanForTempo
|
||||
//
|
||||
// Look through events chunk to find one that sets the tempo.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void XMISong::ScanForTempo(const TrackInfo *song)
|
||||
{
|
||||
const BYTE *chunk = song->EventChunk;
|
||||
|
||||
for (size_t q = 0; q < song->EventLen - 3; )
|
||||
{
|
||||
int r = q;
|
||||
int evmark = chunk[r];
|
||||
int evtype = chunk[r + 1];
|
||||
int evlen = chunk[r + 2];
|
||||
// Is it a tempo event? If so, length should be 3.
|
||||
if (evmark == MIDI_META && evtype == MIDI_META_TEMPO && evlen == 3)
|
||||
{
|
||||
// Tempo is given in microseconds per quarter notes, so for a base of
|
||||
// 120 per second, we have to divide by a million a multiply by 120 to
|
||||
// get the PPQN. This is simplified by 40 to manipulate smaller values.
|
||||
Tempo = (chunk[r + 3] << 16) | (chunk[r + 4] << 8) | chunk[r + 5];
|
||||
Division = Tempo * 3 / 25000;
|
||||
}
|
||||
q += 3 + evlen;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// XMISong :: SetMIDISubsong
|
||||
|
@ -304,7 +339,7 @@ bool XMISong::CheckDone()
|
|||
//
|
||||
// XMISong :: MakeEvents
|
||||
//
|
||||
// Copies MIDI events from the SMF and puts them into a MIDI stream
|
||||
// Copies MIDI events from the XMI and puts them into a MIDI stream
|
||||
// buffer. Returns the new position in the buffer.
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -542,6 +577,7 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay)
|
|||
events[1] = 0;
|
||||
events[2] = (MEVT_TEMPO << 24) | Tempo;
|
||||
events += 3;
|
||||
Division = Tempo * 3 / 25000;
|
||||
break;
|
||||
}
|
||||
track->EventP += len;
|
||||
|
@ -598,6 +634,7 @@ void XMISong::ProcessInitialMetaEvents ()
|
|||
(track->EventChunk[track->EventP+1]<<8) |
|
||||
(track->EventChunk[track->EventP+2])
|
||||
);
|
||||
Division = Tempo * 3 / 25000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
// This file was automatically generated by the
|
||||
// updaterevision tool. Do not edit by hand.
|
||||
|
||||
#define ZD_SVN_REVISION_STRING "3372"
|
||||
#define ZD_SVN_REVISION_NUMBER 3372
|
||||
#define ZD_SVN_REVISION_STRING "3383"
|
||||
#define ZD_SVN_REVISION_NUMBER 3383
|
||||
|
|
|
@ -336,6 +336,18 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls)
|
|||
{
|
||||
return new FxConstant(sc.Float, scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_NameConst))
|
||||
{
|
||||
return new FxConstant(sc.Name, scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_StringConst))
|
||||
{
|
||||
// String parameters are converted to names. Technically, this should be
|
||||
// done at a higher level, as needed, but since no functions take string
|
||||
// arguments and ACS_NamedExecuteWithResult/CallACS need names, this is
|
||||
// a cheap way to get them working when people use "name" instead of 'name'.
|
||||
return new FxConstant(FName(sc.String), scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_Random))
|
||||
{
|
||||
FRandom *rng;
|
||||
|
|
|
@ -1868,7 +1868,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
|||
newex = new FxCVar(cv, ScriptPosition);
|
||||
}
|
||||
*/
|
||||
// amd line specials
|
||||
// and line specials
|
||||
else if ((num = P_FindLineSpecial(Identifier, NULL, NULL)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num);
|
||||
|
@ -2293,9 +2293,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
return x->Resolve(ctx);
|
||||
}
|
||||
|
||||
int min, max;
|
||||
int special = P_FindLineSpecial(MethodName.GetChars(), &min, &max);
|
||||
if (special > 0 && min >= 0)
|
||||
int min, max, special;
|
||||
if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS)
|
||||
{
|
||||
special = -ACS_ExecuteWithResult;
|
||||
min = 1;
|
||||
max = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
special = P_FindLineSpecial(MethodName.GetChars(), &min, &max);
|
||||
}
|
||||
if (special != 0 && min >= 0)
|
||||
{
|
||||
int paramcount = ArgList? ArgList->Size() : 0;
|
||||
if (paramcount < min)
|
||||
|
@ -2326,7 +2335,10 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxActionSpecialCall
|
||||
//
|
||||
// If special is negative, then the first argument will be treated as a
|
||||
// name for ACS_NamedExecuteWithResult.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -2367,7 +2379,15 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
(*ArgList)[i] = (*ArgList)[i]->Resolve(ctx);
|
||||
if ((*ArgList)[i] == NULL) failed = true;
|
||||
if ((*ArgList)[i]->ValueType != VAL_Int)
|
||||
if (Special < 0 && i == 0)
|
||||
{
|
||||
if ((*ArgList)[i]->ValueType != VAL_Name)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i);
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
else if ((*ArgList)[i]->ValueType != VAL_Int)
|
||||
{
|
||||
if (ctx.lax && ((*ArgList)[i]->ValueType == VAL_Float))
|
||||
{
|
||||
|
@ -2400,6 +2420,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
|||
ExpVal FxActionSpecialCall::EvalExpression (AActor *self)
|
||||
{
|
||||
int v[5] = {0,0,0,0,0};
|
||||
int special = Special;
|
||||
|
||||
if (Self != NULL)
|
||||
{
|
||||
|
@ -2409,13 +2430,21 @@ ExpVal FxActionSpecialCall::EvalExpression (AActor *self)
|
|||
if (ArgList != NULL)
|
||||
{
|
||||
for(unsigned i = 0; i < ArgList->Size(); i++)
|
||||
{
|
||||
if (special < 0)
|
||||
{
|
||||
special = -special;
|
||||
v[i] = -(*ArgList)[i]->EvalExpression(self).GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
v[i] = (*ArgList)[i]->EvalExpression(self).GetInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
ExpVal ret;
|
||||
ret.Type = VAL_Int;
|
||||
ret.Int = P_ExecuteSpecial(Special, NULL, self, false, v[0], v[1], v[2], v[3], v[4]);
|
||||
ret.Int = P_ExecuteSpecial(special, NULL, self, false, v[0], v[1], v[2], v[3], v[4]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "w_wad.h"
|
||||
#include "s_sound.h"
|
||||
#include "m_argv.h"
|
||||
#include "d_main.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -276,15 +277,18 @@ FStartupScreen *FStartupScreen::CreateInstance(int max_progress)
|
|||
|
||||
if (!Args->CheckParm("-nostartup"))
|
||||
{
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
if (DoomStartupInfo.Type == FStartupInfo::HexenStartup ||
|
||||
(gameinfo.gametype == GAME_Hexen && DoomStartupInfo.Type == FStartupInfo::DefaultStartup))
|
||||
{
|
||||
scr = new FHexenStartupScreen(max_progress, hr);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Heretic)
|
||||
else if (DoomStartupInfo.Type == FStartupInfo::HereticStartup ||
|
||||
(gameinfo.gametype == GAME_Heretic && DoomStartupInfo.Type == FStartupInfo::DefaultStartup))
|
||||
{
|
||||
scr = new FHereticStartupScreen(max_progress, hr);
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
else if (DoomStartupInfo.Type == FStartupInfo::StrifeStartup ||
|
||||
(gameinfo.gametype == GAME_Strife && DoomStartupInfo.Type == FStartupInfo::DefaultStartup))
|
||||
{
|
||||
scr = new FStrifeStartupScreen(max_progress, hr);
|
||||
}
|
||||
|
@ -684,8 +688,14 @@ FHexenStartupScreen::FHexenStartupScreen(int max_progress, HRESULT &hr)
|
|||
LayoutMainWindow (Window, NULL);
|
||||
InvalidateRect (StartupScreen, NULL, TRUE);
|
||||
|
||||
if (DoomStartupInfo.Song.IsNotEmpty())
|
||||
{
|
||||
S_ChangeMusic(DoomStartupInfo.Song.GetChars(), true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
S_ChangeMusic ("orb", true, true);
|
||||
|
||||
}
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,17 @@ script << 0 >> (int type, int tag)
|
|||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
if (tag == 0)
|
||||
{
|
||||
Exit_Normal (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Teleport_NewMap (tag, 0, FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 52:
|
||||
tag /= 100;
|
||||
if (tag == 0)
|
||||
|
|
Binary file not shown.
|
@ -137,6 +137,22 @@ ACTOR ArtiPoisonBag3 : ArtiPoisonBag native
|
|||
Inventory.Icon "ARTIPSB3"
|
||||
Tag "$TAG_ARTIPOISONBAG3"
|
||||
}
|
||||
|
||||
|
||||
// Poison Bag 4 (Custom Giver) ----------------------------------------------
|
||||
|
||||
ACTOR ArtiPoisonBagGiver : ArtiPoisonBag native
|
||||
{
|
||||
Inventory.Icon "ARTIPSB4"
|
||||
}
|
||||
|
||||
// Poison Bag 5 (Custom Thrower) --------------------------------------------
|
||||
|
||||
ACTOR ArtiPoisonBagShooter : ArtiPoisonBag native
|
||||
{
|
||||
Inventory.Icon "ARTIPSB5"
|
||||
}
|
||||
|
||||
// Poison Cloud -------------------------------------------------------------
|
||||
|
||||
ACTOR PoisonCloud native
|
||||
|
|
|
@ -278,7 +278,7 @@ RetailOnly = 121
|
|||
235 = USE, ACS_ExecuteWithResult (0, 235, tag)
|
||||
|
||||
// Buttons
|
||||
11 = USE|REP, ACS_ExecuteWithResult (0, 52, tag)
|
||||
11 = USE|REP, ACS_ExecuteWithResult (0, 11, tag)
|
||||
42 = USE|REP, Door_Close (tag, D_SLOW)
|
||||
43 = USE|REP, Ceiling_LowerToFloor (tag, C_SLOW)
|
||||
45 = USE|REP, Floor_LowerToHighest (tag, F_SLOW, 128)
|
||||
|
@ -319,7 +319,7 @@ RetailOnly = 121
|
|||
155 = USE|REP, Plat_UpNearestWaitDownStay (tag, P_NORMAL, PLATWAIT)
|
||||
177 = USE|REP, ACS_LockedExecute (0, 0, 177, tag, 9)
|
||||
207 = USE|REP, Door_Animated (tag, 4, 3*35)
|
||||
214 = USE|REP, ACS_ExecuteWithResult (0, 214, tag)
|
||||
214 = USE|REP, Plat_DownWaitUpStayLip (tag, 8, 1050, 0, 1)
|
||||
229 = USE|REP, ACS_ExecuteWithResult (0, 229, tag)
|
||||
233 = USE|REP, ACS_ExecuteWithResult (0, 233, tag)
|
||||
234 = USE|REP, ACS_ExecuteWithResult (0, 234, tag)
|
||||
|
|
Loading…
Reference in a new issue