Merge remote-tracking branch 'gzdoom/master' into materials

This commit is contained in:
Magnus Norddahl 2018-02-28 22:12:12 +01:00
commit 6652df40c1
36 changed files with 227 additions and 58 deletions

1
.gitignore vendored
View file

@ -54,3 +54,4 @@
.vs
/src/gl/unused
/mapfiles_release/*.map
.DS_Store

View file

@ -886,6 +886,12 @@ public:
// a full 3D version of the above
double Distance3DSquared(AActor *other, bool absolute = false)
{
DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return (Pos() - otherpos).LengthSquared();
}
double Distance3D(AActor *other, bool absolute = false)
{
DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this);

View file

@ -92,6 +92,7 @@ enum
CP_SETTHINGSKILLS,
CP_SETSECTORTEXTURE,
CP_SETSECTORLIGHT,
CP_SETLINESECTORREF,
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -283,6 +284,18 @@ void ParseCompatibility()
CompatParams.Push(sc.Number);
}
}
else if (sc.Compare("setlinesectorref"))
{
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_SETLINESECTORREF);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
sc.MustGetString();
CompatParams.Push(sc.MustMatchString(LineSides));
sc.MustGetNumber();
CompatParams.Push(sc.Number);
flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES;
}
else if (sc.Compare("clearlinespecial"))
{
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
@ -719,6 +732,22 @@ void SetCompatibilityParams()
i += 3;
break;
}
case CP_SETLINESECTORREF:
{
if ((unsigned)CompatParams[i + 1] < level.lines.Size())
{
line_t *line = &level.lines[CompatParams[i + 1]];
assert(line != nullptr);
side_t *side = line->sidedef[CompatParams[i + 2]];
if (side != nullptr && (unsigned)CompatParams[i + 3] < level.sectors.Size())
{
side->sector = &level.sectors[CompatParams[i + 3]];
}
}
i += 4;
break;
}
}
}
}

View file

@ -1196,6 +1196,10 @@ static int PatchThing (int thingy)
// triggering line effects and can teleport when the missile flag is removed.
info->flags2 &= ~MF2_NOTELEPORT;
}
if (thingy == 1) // [SP] special handling for players - always be friendly!
{
value[0] |= MF_FRIENDLY;
}
info->flags = ActorFlags::FromInt (value[0]);
}
if (vchanged[1])
@ -2836,14 +2840,14 @@ static bool LoadDehSupp ()
sc.MustGetString();
PClassActor *actortype = static_cast<PClassActor *>(type);
s.State = actortype->FindState(sc.String);
if (s.State == NULL)
if (s.State == NULL && addit)
{
sc.ScriptError("Invalid state '%s' in '%s'", sc.String, type->TypeName.GetChars());
}
sc.MustGetStringName(",");
sc.MustGetNumber();
if (s.State == NULL || sc.Number < 1 || !actortype->OwnsState(s.State + sc.Number - 1))
if (addit && (s.State == NULL || sc.Number < 1 || !actortype->OwnsState(s.State + sc.Number - 1)))
{
sc.ScriptError("Invalid state range in '%s'", type->TypeName.GetChars());
}

View file

@ -149,6 +149,7 @@ FGameConfigFile::FGameConfigFile ()
SetValueForKey ("Path", "$PROGDIR", true);
#else
SetValueForKey ("Path", "$HOME/" GAME_DIR, true);
SetValueForKey ("Path", SHARE_DIR, true);
SetValueForKey ("Path", "/usr/local/share/doom", true);
SetValueForKey ("Path", "/usr/local/share/games/doom", true);
SetValueForKey ("Path", "/usr/share/doom", true);

View file

@ -1211,7 +1211,7 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s
}
double timefrac = r_viewpoint.TicFrac;
if (paused || bglobal.freeze)
if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN))
timefrac = 0.;
float xvf = (particle->Vel.X) * timefrac;
float yvf = (particle->Vel.Y) * timefrac;

View file

@ -1060,8 +1060,8 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
// Draw the stuff
//
//
if (realfront->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) split.PutWall(translucent);
else split.SplitWall(realfront, translucent);
if (front->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) split.PutWall(translucent);
else split.SplitWall(front, translucent);
t=1;
}
@ -1074,8 +1074,8 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
// Draw the stuff without splitting
//
//
if (realfront->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) PutWall(translucent);
else SplitWall(realfront, translucent);
if (front->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) PutWall(translucent);
else SplitWall(front, translucent);
}
alpha=1.0f;
}
@ -1437,7 +1437,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
sector_t * segback;
#ifdef _DEBUG
if (seg->linedef->Index() == 1)
if (seg->linedef->Index() == 10)
{
int a = 0;
}

View file

@ -244,6 +244,7 @@ struct FActorInfo
PClassActor *Replacee = nullptr;
FState *OwnedStates = nullptr;
int NumOwnedStates = 0;
bool SkipSuperSet = false;
uint8_t GameFilter = GAME_Any;
uint16_t SpawnID = 0;
uint16_t ConversationID = 0;
@ -287,7 +288,7 @@ struct FActorInfo
};
// This is now merely a wrapper that adds actor-specific functionality to PClass.
// No objects of this type will be created ever - its only use is to static_casr
// No objects of this type will be created ever - its only use is to static_cast
// PClass to it.
class PClassActor : public PClass
{

View file

@ -377,6 +377,8 @@ xx(MomZ)
xx(Threshold)
xx(DefThreshold)
xx(Abs)
xx(TeleportSpecial)
xx(Teleport)
xx(ACS_NamedExecuteWithResult)
xx(CallACS)
xx(Sqrt)

View file

@ -814,8 +814,8 @@ void FNodeBuilder::SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uin
frac = InterceptVector (node, *seg);
newvert.x = Vertices[seg->v1].x;
newvert.y = Vertices[seg->v1].y;
newvert.x += fixed_t(frac * double(Vertices[seg->v2].x - newvert.x));
newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y));
newvert.x += fixed_t(frac * (double(Vertices[seg->v2].x) - newvert.x));
newvert.y += fixed_t(frac * (double(Vertices[seg->v2].y) - newvert.y));
vertnum = VertexMap->SelectVertexClose (newvert);
if (vertnum != (unsigned int)seg->v1 && vertnum != (unsigned int)seg->v2)

View file

@ -91,6 +91,8 @@ struct FSimpleVert
fixed_t x, y;
};
typedef int64_t fixed64_t;
class FNodeBuilder
{
struct FPrivSeg
@ -167,14 +169,14 @@ class FNodeBuilder
FNodeBuilder &MyBuilder;
TArray<int> *VertexGrid;
fixed_t MinX, MinY, MaxX, MaxY;
fixed64_t MinX, MinY, MaxX, MaxY;
int BlocksWide, BlocksTall;
enum { BLOCK_SHIFT = 8 + FRACBITS };
enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
int InsertVertex (FPrivVert &vert);
inline int GetBlock (fixed_t x, fixed_t y)
inline int GetBlock (fixed64_t x, fixed64_t y)
{
assert (x >= MinX);
assert (y >= MinY);

View file

@ -641,8 +641,8 @@ FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
MinY = miny;
BlocksWide = int(((double(maxx) - minx + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
BlocksTall = int(((double(maxy) - miny + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
MaxX = MinX + BlocksWide * BLOCK_SIZE - 1;
MaxY = MinY + BlocksTall * BLOCK_SIZE - 1;
MaxX = MinX + fixed64_t(BlocksWide) * BLOCK_SIZE - 1;
MaxY = MinY + fixed64_t(BlocksTall) * BLOCK_SIZE - 1;
VertexGrid = new TArray<int>[BlocksWide * BlocksTall];
}
@ -703,10 +703,10 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
// If a vertex is near a block boundary, then it will be inserted on
// both sides of the boundary so that SelectVertexClose can find
// it by checking in only one block.
fixed_t minx = MAX (MinX, vert.x - VERTEX_EPSILON);
fixed_t maxx = MIN (MaxX, vert.x + VERTEX_EPSILON);
fixed_t miny = MAX (MinY, vert.y - VERTEX_EPSILON);
fixed_t maxy = MIN (MaxY, vert.y + VERTEX_EPSILON);
fixed64_t minx = MAX (MinX, fixed64_t(vert.x) - VERTEX_EPSILON);
fixed64_t maxx = MIN (MaxX, fixed64_t(vert.x) + VERTEX_EPSILON);
fixed64_t miny = MAX (MinY, fixed64_t(vert.y) - VERTEX_EPSILON);
fixed64_t maxy = MIN (MaxY, fixed64_t(vert.y) + VERTEX_EPSILON);
int blk[4] =
{

View file

@ -898,7 +898,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
}
// check if the actor can step through the ceiling portal. In this case one-sided lines in the current area should not block
if (!cres.line->frontsector->PortalBlocksMovement(sector_t::ceiling))
// Use the same rules for stepping through a portal as for non-portal case.
bool ismissile = (tm.thing->flags & MF_MISSILE) && !(tm.thing->flags6 & MF6_STEPMISSILE) && !(tm.thing->flags3 & MF3_FLOORHUGGER);
if (!ismissile && !cres.line->frontsector->PortalBlocksMovement(sector_t::ceiling))
{
double portz = cres.line->frontsector->GetPortalPlaneZ(sector_t::ceiling);
if (tm.thing->Z() < portz && tm.thing->Z() + tm.thing->MaxStepHeight >= portz && tm.floorz < portz)
@ -1008,7 +1010,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
FLineOpening open;
P_LineOpening(open, tm.thing, ld, ref, &cres.Position, cres.portalflags);
if (!tm.thing->Sector->PortalBlocksMovement(sector_t::ceiling))
// Use the same rules for stepping through a portal as for non-portal case.
bool ismissile = (tm.thing->flags & MF_MISSILE) && !(tm.thing->flags6 & MF6_STEPMISSILE) && !(tm.thing->flags3 & MF3_FLOORHUGGER);
if (!ismissile && !tm.thing->Sector->PortalBlocksMovement(sector_t::ceiling))
{
sector_t *oppsec = cres.line->frontsector == tm.thing->Sector ? cres.line->backsector : cres.line->frontsector;
if (oppsec->PortalBlocksMovement(sector_t::ceiling))
@ -2707,8 +2711,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
FLinkContext ctx;
DVector3 oldpos = thing->Pos();
thing->UnlinkFromWorld(&ctx);
thing->SetXYZ(thing->PosRelative(thing->Sector->GetOppositePortalGroup(sector_t::ceiling)));
thing->Prev = thing->Pos() - oldpos;
thing->SetXYZ(thing->PosRelative(tm.portalgroup));
thing->Prev += thing->Pos() - oldpos;
thing->Sector = P_PointInSector(thing->Pos());
thing->PrevPortalGroup = thing->Sector->PortalGroup;
thing->LinkToWorld(&ctx);

View file

@ -8127,6 +8127,20 @@ DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global?
ACTION_RETURN_FLOAT(absangle(DAngle(a1), DAngle(a2)).Degrees);
}
DEFINE_ACTION_FUNCTION(AActor, Distance2DSquared)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_FLOAT(self->Distance2DSquared(other));
}
DEFINE_ACTION_FUNCTION(AActor, Distance3DSquared)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT_NOT_NULL(other, AActor);
ACTION_RETURN_FLOAT(self->Distance3DSquared(other));
}
DEFINE_ACTION_FUNCTION(AActor, Distance2D)
{
PARAM_SELF_PROLOGUE(AActor);

View file

@ -4138,15 +4138,18 @@ void P_SetupLevel (const char *lumpname, int position)
// [SP] move unfriendly players around
// horribly hacky - yes, this needs rewritten.
for (i = 0; i < MAXPLAYERS; ++i)
if (level.deathmatchstarts.Size () > 0)
{
if (playeringame[i] && players[i].mo != NULL)
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!(players[i].mo->flags & MF_FRIENDLY))
if (playeringame[i] && players[i].mo != NULL)
{
AActor * oldSpawn = players[i].mo;
G_DeathMatchSpawnPlayer (i);
oldSpawn->Destroy();
if (!(players[i].mo->flags & MF_FRIENDLY))
{
AActor * oldSpawn = players[i].mo;
G_DeathMatchSpawnPlayer (i);
oldSpawn->Destroy();
}
}
}
}

View file

@ -35,7 +35,7 @@ EXTERN_CVAR(Int, gl_particles_style)
void RenderPolyParticle::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t stencilValue)
{
double timefrac = r_viewpoint.TicFrac;
if (paused || bglobal.freeze)
if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN))
timefrac = 0.;
DVector3 pos = particle->Pos + (particle->Vel * timefrac);
double psize = particle->size / 8.0;

View file

@ -677,7 +677,7 @@ void S_UnloadReverbDef ()
Environments = &Off;
}
CUSTOM_CVAR(Bool, eaxedit_test, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CUSTOM_CVAR(Bool, eaxedit_test, false, CVAR_NOINITCALL)
{
if (self)
{

View file

@ -7758,6 +7758,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
else
{
// This alias is needed because Actor has a Teleport function.
if (MethodName == NAME_TeleportSpecial) MethodName = NAME_Teleport;
special = P_FindLineSpecial(MethodName.GetChars(), &min, &max);
}
if (special != 0 && min >= 0)

View file

@ -540,7 +540,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
if (info->Size != actorclass->Size)
{
bag.ScriptPosition.Message(MSG_OPTERROR,
"'skip_super' is only allowed in subclasses of AActor with no additional fields and will be ignored in type %s.", info->TypeName.GetChars());
"'skip_super' is only allowed in subclasses of Actor with no additional fields and will be ignored in type %s.", info->TypeName.GetChars());
return;
}
if (bag.StateSet)
@ -552,6 +552,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
*defaults = *GetDefault<AActor>();
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
static_cast<PClassActor*>(bag.Info)->ActorInfo()->SkipSuperSet = true; // ZScript processes the states later so this property must be flagged for later handling.
}
//==========================================================================

View file

@ -1968,7 +1968,10 @@ void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *spe
void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const
{
FArray *aray = (FArray*)addr;
if (aray->Count > 0)
// We may skip an empty array only if it gets stored under a named key.
// If no name is given, i.e. it's part of an outer array's element list, even empty arrays must be stored,
// because otherwise the array would lose its entry.
if (aray->Count > 0 || key == nullptr)
{
if (ar.BeginArray(key))
{

View file

@ -2872,7 +2872,18 @@ void ZCCCompiler::CompileStates()
FString statename; // The state builder wants the label as one complete string, not separated into tokens.
FStateDefinitions statedef;
statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass));
if (static_cast<PClassActor*>(c->ClassType())->ActorInfo()->SkipSuperSet)
{
// SKIP_SUPER'ed actors only get the base states from AActor.
statedef.MakeStateDefines(RUNTIME_CLASS(AActor));
}
else
{
statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass));
}
int numframes = 0;
for (auto s : c->States)

View file

@ -267,6 +267,7 @@ static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void
while (sc.GetToken())
{
value.Largest = 0;
value.SourceLoc = sc.GetMessageLine();
switch (sc.TokenType)
{

View file

@ -7,11 +7,31 @@
struct ZCCToken
{
template <typename... Ts>
struct TLargest;
template <typename T>
struct TLargest<T>
{
using Type = T;
};
template <typename T, typename U, typename... Ts>
struct TLargest<T, U, Ts...>
{
using Type = typename TLargest<
typename std::conditional<
(sizeof(T) > sizeof(U)), T, U
>::type, Ts...
>::Type;
};
union
{
int Int;
double Float;
FString *String;
TLargest<decltype(Int), decltype(Float), decltype(String)>::Type Largest;
};
int SourceLoc;

View file

@ -692,6 +692,10 @@ bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len,
}
break;
}
else if (r == 0 && errno != 0)
{
break;
}
got += r;
} while(got < len);
if(got < len)

View file

@ -745,6 +745,14 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time)
if (InitialPlayback)
{
InitialPlayback = false;
// Send the GS System Reset SysEx message.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID
events[2] = (MEVENT_LONGMSG << 24) | 6; // dwEvent
events[3] = MAKE_ID(0xf0, 0x7e, 0x7f, 0x09); // dwParms[0]
events[4] = MAKE_ID(0x01, 0xf7, 0x00, 0x00); // dwParms[1]
events += 5;
// Send the full master volume SysEx message.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID
@ -752,6 +760,7 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time)
events[3] = MAKE_ID(0xf0,0x7f,0x7f,0x04); // dwParms[0]
events[4] = MAKE_ID(0x01,0x7f,0x7f,0xf7); // dwParms[1]
events += 5;
DoInitialSetup();
}

View file

@ -79,7 +79,7 @@ namespace swrenderer
sector_t* heightsec = NULL;
double timefrac = r_viewpoint.TicFrac;
if (paused || bglobal.freeze)
if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN))
timefrac = 0.;
double ippx = particle->Pos.X + particle->Vel.X * timefrac;

View file

@ -35,6 +35,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <wctype.h>
#include "v_text.h"
@ -387,7 +388,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo
continue;
}
if (isspace(c))
if (iswspace(c))
{
if (!lastWasSpace)
{
@ -420,12 +421,12 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo
start = space;
space = NULL;
while (*start && isspace (*start) && *start != '\n')
while (*start && iswspace (*start) && *start != '\n')
start++;
if (*start == '\n')
start++;
else
while (*start && isspace (*start))
while (*start && iswspace (*start))
start++;
string = start;
}
@ -443,7 +444,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo
while (s < string)
{
// If there is any non-white space in the remainder of the string, add it.
if (!isspace (*s++))
if (!iswspace (*s++))
{
auto i = Lines.Reserve(1);
breakit (&Lines[i], font, start, string, linecolor);

View file

@ -868,3 +868,17 @@ CA3773ED313E8899311F3DD0CA195A68 // e3m6
{
shorttex
}
FCCA97FC851F6473EAA069F74247B317 // pg-raw.wad map31
{
setlinesectorref 331 front 74
setlinesectorref 326 front 74
setlinesectorref 497 front 74
setlinesectorref 474 front 74
setlinesectorref 471 front 74
setlinesectorref 327 front 74
setlinesectorref 328 front 74
setlinesectorref 329 front 74
setsectortag 74 4
setlinespecial 357 Transfer_Heights 4 2 0 0 0
}

View file

@ -580,6 +580,8 @@ class Actor : Thinker native
native void SetDamage(int dmg);
native clearscope double Distance2D(Actor other) const;
native clearscope double Distance3D(Actor other) const;
native clearscope double Distance2DSquared(Actor other) const;
native clearscope double Distance3DSquared(Actor other) const;
native void SetOrigin(vector3 newpos, bool moving);
native void SetXYZ(vector3 newpos);
native Actor GetPointer(int aaptr);
@ -1185,6 +1187,10 @@ class Actor : Thinker native
{
return ACS_ExecuteAlways(-int(script), mapnum, arg1, arg2, arg3);
}
int ACS_ScriptCall(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0)
{
return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4);
}
States(Actor, Overlay, Weapon, Item)
{

View file

@ -416,6 +416,7 @@ enum ESoundFlags
CHAN_MAYBE_LOCAL = 16,
CHAN_UI = 32,
CHAN_NOPAUSE = 64,
CHAN_LOOP = 256,
CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL),
CHAN_NOSTOP = 4096

View file

@ -70,8 +70,13 @@ extend class Actor
{
if (mo.health > 0 && mo != self)
{
// other Keen not dead
return;
// Added check for Dehacked and repurposed inventory items.
let inv = Inventory(mo);
if (inv == null || inv.Owner == null)
{
// other Keen not dead
return;
}
}
}
Door_Open(doortag, 16);

View file

@ -244,6 +244,11 @@ class Korax : Actor
void A_KoraxMissile()
{
if (!target)
{
return;
}
static const class<Actor> choices[] =
{
"WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX"
@ -282,6 +287,11 @@ class Korax : Actor
void KoraxFire (Class<Actor> type, int arm)
{
if (!target)
{
return;
}
static const int extension[] =
{
KORAX_ARM_EXTENSION_SHORT,

View file

@ -1931,22 +1931,6 @@ class PowerMorph : Powerup
int savedMorphTics = MorphedPlayer.morphTics;
MorphedPlayer.UndoPlayerMorph (MorphedPlayer, 0, !!(MorphedPlayer.MorphStyle & MRF_UNDOALWAYS));
// Abort if unmorph failed; in that case,
// set the usual retry timer and return.
if (MorphedPlayer != null && MorphedPlayer.morphTics)
{
// Transfer retry timeout
// to the powerup's timer.
EffectTics = MorphedPlayer.morphTics;
// Reload negative morph tics;
// use actual value; it may
// be in use for animation.
MorphedPlayer.morphTics = savedMorphTics;
// Try again some time later
return;
}
// Unmorph suceeded
MorphedPlayer = null;
}

View file

@ -66,7 +66,7 @@ class FastProjectile : Actor
int count = 8;
if (radius > 0)
{
while ( abs(Vel.X) > radius * count || abs(Vel.Y) > radius * count)
while ( abs(Vel.X) >= radius * count || abs(Vel.Y) >= radius * count || abs(Vel.Z) >= height * count)
{
// we need to take smaller steps.
count += count;

View file

@ -559,6 +559,21 @@ object SoulSphere
frame SOUL { light SOULSPHERE }
}
pulselight MEGASPHERE
{
color 0.5 0.5 0.4
size 60
secondarySize 63
interval 2.0
offset 0 16 0
attenuate 1
}
object MegaSphere
{
frame MEGA { light MEGASPHERE }
}
// Invulnerability Sphere
pulselight INVULN
{

View file

@ -559,6 +559,21 @@ object SoulSphere
frame SOUL { light SOULSPHERE }
}
pulselight MEGASPHERE
{
color 0.5 0.5 0.4
size 60
secondarySize 63
interval 2.0
offset 0 16 0
attenuate 1
}
object MegaSphere
{
frame MEGA { light MEGASPHERE }
}
// Invulnerability Sphere
pulselight INVULN
{