- Added a type check to Spawn(actorname,...) to allow it to print a

meaningful message instead of the nondescript 
  'Tried to spawn a class-less actor'.
- Converted AGlassJunk to DECORATE and made the spawn function a little
  more flexible so that replacing the shard is easier.
- Converted ABloodSplatter to DECORATE.
- Removed A_Jiggle because it never worked properly.
- Changed DECORATE parser to allow commas between arguments for multi-
  argument properties. For all newly added properties this format will
  become mandatory but for backwards compatibility it is optional for
  old ones.
- Added a check for negative indices to TAutoGrowArray::SetVal to prevent
  passing an index of -1 from crashing the game.
- Fixed: Morphing must clear the weapon's flash sprite.
- Fixed: Resurrecting a morphed player caused a crash.
- Fixed: Random sounds that recursively refer to themselves caused a stack
  overflow. Now they print a warning and get ignored.


SVN r277 (trunk)
This commit is contained in:
Christoph Oelckers 2006-07-31 10:22:53 +00:00
parent f94cdaf782
commit 5ac0789e6e
16 changed files with 156 additions and 113 deletions

View file

@ -1,3 +1,22 @@
July 31, 2006 (Changes by Graf Zahl)
- Added a type check to Spawn(actorname,...) to allow it to print a
meaningful message instead of the nondescript
'Tried to spawn a class-less actor'.
- Converted AGlassJunk to DECORATE and made the spawn function a little
more flexible so that replacing the shard is easier.
- Converted ABloodSplatter to DECORATE.
- Removed A_Jiggle because it never worked properly.
- Changed DECORATE parser to allow commas between arguments for multi-
argument properties. For all newly added properties this format will
become mandatory but for backwards compatibility it is optional for
old ones.
- Added a check for negative indices to TAutoGrowArray::SetVal to prevent
passing an index of -1 from crashing the game.
- Fixed: Morphing must clear the weapon's flash sprite.
- Fixed: Resurrecting a morphed player caused a crash.
- Fixed: Random sounds that recursively refer to themselves caused a stack
overflow. Now they print a warning and get ignored.
July 30, 2006 (Changes by Graf Zahl) July 30, 2006 (Changes by Graf Zahl)
- Added Grubber's GetPlayerInfo ACS function. - Added Grubber's GetPlayerInfo ACS function.
- Fixed: Starting a game without skill menu always started the first episode. - Fixed: Starting a game without skill menu always started the first episode.

View file

@ -800,10 +800,7 @@ inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, repla
return AActor::StaticSpawn (type, x, y, z, allowreplacement); return AActor::StaticSpawn (type, x, y, z, allowreplacement);
} }
inline AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement);
{
return AActor::StaticSpawn (PClass::FindClass(type), x, y, z, allowreplacement);
}
template<class T> template<class T>
inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) inline T *Spawn (fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)

View file

@ -212,6 +212,11 @@ void AChickenPlayer::ActivateMorphWeapon ()
{ {
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState());
} }
else
{
P_SetPsprite (player, ps_weapon, NULL);
}
P_SetPsprite (player, ps_flash, NULL);
} }
// Chicken (non-player) ----------------------------------------------------- // Chicken (non-player) -----------------------------------------------------

View file

@ -194,6 +194,7 @@ void APigPlayer::ActivateMorphWeapon ()
{ {
P_SetPsprite (player, ps_weapon, NULL); P_SetPsprite (player, ps_weapon, NULL);
} }
P_SetPsprite (player, ps_flash, NULL);
} }
// Pig (non-player) --------------------------------------------------------- // Pig (non-player) ---------------------------------------------------------

View file

@ -279,15 +279,6 @@ void cht_DoCheat (player_t *player, int cheat)
else else
{ {
player->playerstate = PST_LIVE; player->playerstate = PST_LIVE;
if (player->mo->tracer != NULL)
{
APlayerPawn * pmo = player->mo;
player->mo = (APlayerPawn*)player->mo->tracer;
pmo->Destroy();
player->mo->player=player;
player->mo->renderflags &= ~RF_INVISIBLE;
player->morphTics = 0;
}
player->health = player->mo->health = player->mo->GetDefault()->health; player->health = player->mo->health = player->mo->GetDefault()->health;
player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight;
player->mo->flags = player->mo->GetDefault()->flags; player->mo->flags = player->mo->GetDefault()->flags;
@ -296,8 +287,17 @@ void cht_DoCheat (player_t *player, int cheat)
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
player->mo->DamageType = MOD_UNKNOWN; player->mo->DamageType = MOD_UNKNOWN;
// player->mo->GiveDefaultInventory(); // player->mo->GiveDefaultInventory();
if (player->ReadyWeapon != NULL)
{
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->UpState); P_SetPsprite(player, ps_weapon, player->ReadyWeapon->UpState);
} }
if (player->morphTics > 0)
{
P_UndoPlayerMorph(player);
}
}
} }
break; break;

View file

@ -2523,41 +2523,6 @@ FUNC(LS_ClearForceField)
return rtn; return rtn;
} }
class AGlassJunk : public AActor
{
DECLARE_ACTOR (AGlassJunk, AActor);
};
// [RH] Slowly fade the shards away instead of abruptly removing them.
void A_GlassAway (AActor *self)
{
self->alpha -= FRACUNIT/32;
if (self->alpha <= 0)
{
self->Destroy ();
}
}
FState AGlassJunk::States[] =
{
// Are the first three frames used anywhere?
S_NORMAL (SHAR, 'A', 128, NULL, &States[6]),
S_NORMAL (SHAR, 'B', 128, NULL, &States[6]),
S_NORMAL (SHAR, 'C', 128, NULL, &States[6]),
S_NORMAL (SHAR, 'D', 128, NULL, &States[6]),
S_NORMAL (SHAR, 'E', 128, NULL, &States[6]),
S_NORMAL (SHAR, 'F', 128, NULL, &States[6]),
S_NORMAL (----, 'A', 1, A_GlassAway, &States[6])
};
IMPLEMENT_ACTOR (AGlassJunk, Any, -1, 0)
PROP_SpawnState (0)
PROP_Flags (MF_NOCLIP | MF_NOBLOCKMAP | MF_STRIFEx8000000)
PROP_RenderStyle (STYLE_Translucent)
PROP_Alpha (HX_SHADOW)
END_DEFAULTS
FUNC(LS_GlassBreak) FUNC(LS_GlassBreak)
// GlassBreak (bNoJunk) // GlassBreak (bNoJunk)
{ {
@ -2591,10 +2556,10 @@ FUNC(LS_GlassBreak)
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i)
{ {
glass = Spawn<AGlassJunk> (x, y, ONFLOORZ, ALLOW_REPLACE); glass = Spawn("GlassJunk", x, y, ONFLOORZ, ALLOW_REPLACE);
glass->z += 24 * FRACUNIT; glass->z += 24 * FRACUNIT;
glass->SetState (&AGlassJunk::States[3 + pr_glass() % 3]); glass->SetState (glass->SpawnState + (pr_glass() % glass->health));
an = pr_glass() << (32-8); an = pr_glass() << (32-8);
glass->angle = an; glass->angle = an;
an >>= ANGLETOFINESHIFT; an >>= ANGLETOFINESHIFT;

View file

@ -3150,6 +3150,16 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t
return actor; return actor;
} }
AActor *Spawn (const char *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement)
{
const PClass *cls = PClass::FindClass(type);
if (cls == NULL)
{
I_Error("Attempt to spawn actor of unknown type '%s'\n", type);
}
return AActor::StaticSpawn (cls, x, y, z, allowreplacement);
}
void AActor::LevelSpawned () void AActor::LevelSpawned ()
{ {
if (tics > 0 && !(flags4 & MF4_SYNCHRONIZED)) if (tics > 0 && !(flags4 & MF4_SYNCHRONIZED))
@ -3906,34 +3916,6 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
P_DrawSplash2 (40, x, y, z, dir, 2, bloodcolor); P_DrawSplash2 (40, x, y, z, dir, 2, bloodcolor);
} }
// Blood splatter -----------------------------------------------------------
class ABloodSplatter : public AActor
{
DECLARE_ACTOR (ABloodSplatter, AActor)
};
FState ABloodSplatter::States[] =
{
#define S_BLOODSPLATTER 0
S_NORMAL (BLUD, 'C', 8, NULL, &States[S_BLOODSPLATTER+1]),
S_NORMAL (BLUD, 'B', 8, NULL, &States[S_BLOODSPLATTER+2]),
S_NORMAL (BLUD, 'A', 8, NULL, NULL),
#define S_BLOODSPLATTERX (S_BLOODSPLATTER+3)
S_NORMAL (BLUD, 'A', 6, NULL, NULL)
};
IMPLEMENT_ACTOR (ABloodSplatter, Raven, -1, 0)
PROP_SpawnState (S_BLOODSPLATTER)
PROP_DeathState (S_BLOODSPLATTERX)
PROP_RadiusFixed (2)
PROP_HeightFixed (4)
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
PROP_Flags2 (MF2_NOTELEPORT|MF2_CANNOTPUSH)
PROP_Mass (5)
END_DEFAULTS
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// PROC P_BloodSplatter // PROC P_BloodSplatter
@ -3948,7 +3930,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
{ {
AActor *mo; AActor *mo;
mo = Spawn<ABloodSplatter> (x, y, z, ALLOW_REPLACE); mo = Spawn("BloodSplatter", x, y, z, ALLOW_REPLACE);
mo->target = originator; mo->target = originator;
mo->momx = pr_splatter.Random2 () << 10; mo->momx = pr_splatter.Random2 () << 10;
mo->momy = pr_splatter.Random2 () << 10; mo->momy = pr_splatter.Random2 () << 10;

View file

@ -966,6 +966,11 @@ static void S_AddSNDINFO (int lump)
while (SC_GetString () && !SC_Compare ("}")) while (SC_GetString () && !SC_Compare ("}"))
{ {
WORD sfxto = S_FindSoundTentative (sc_String); WORD sfxto = S_FindSoundTentative (sc_String);
if (sfxto == random.SfxHead)
{
Printf("Definition of random sound '%s' refers to itself recursively.", sc_String);
continue;
}
list.Push (sfxto); list.Push (sfxto);
} }
if (list.Size() == 1) if (list.Size() == 1)

View file

@ -288,6 +288,8 @@ public:
} }
void SetVal (unsigned int index, T val) void SetVal (unsigned int index, T val)
{ {
if ((int)index < 0) return; // These always result in an out of memory condition.
if (index >= this->Size()) if (index >= this->Size())
{ {
this->Resize (index + 1); this->Resize (index + 1);

View file

@ -485,7 +485,6 @@ ACTOR(BishopMissileWeave)
ACTOR(CStaffMissileSlither) ACTOR(CStaffMissileSlither)
ACTOR(CheckSight) ACTOR(CheckSight)
ACTOR(ExtChase) ACTOR(ExtChase)
ACTOR(Jiggle)
ACTOR(DropInventory) ACTOR(DropInventory)
ACTOR(SetBlend) ACTOR(SetBlend)
ACTOR(JumpIf) ACTOR(JumpIf)
@ -675,7 +674,6 @@ AFuncDesc AFTable[]=
FUNC(A_SpawnDebris, "M") FUNC(A_SpawnDebris, "M")
FUNC(A_CheckSight, "L") FUNC(A_CheckSight, "L")
FUNC(A_ExtChase, "XXyx") FUNC(A_ExtChase, "XXyx")
FUNC(A_Jiggle, "XX")
FUNC(A_DropInventory, "M") FUNC(A_DropInventory, "M")
FUNC(A_SetBlend, "CXXc") FUNC(A_SetBlend, "CXXc")
FUNC(A_ChangeFlag, "TX") FUNC(A_ChangeFlag, "TX")
@ -2034,7 +2032,36 @@ static FState *CheckState(int statenum, PClass *type)
} }
//==========================================================================
//
// Checks for a numeric parameter which may or may not be preceded by a comma
//
//==========================================================================
static bool CheckNumParm()
{
if (SC_CheckString(","))
{
SC_MustGetNumber();
return true;
}
else
{
return !!SC_CheckNumber();
}
}
static bool CheckFloatParm()
{
if (SC_CheckString(","))
{
SC_MustGetFloat();
return true;
}
else
{
return !!SC_CheckFloat();
}
}
//========================================================================== //==========================================================================
// //
@ -2464,6 +2491,8 @@ static void ActorActiveSound (AActor *defaults, Baggage &bag)
//========================================================================== //==========================================================================
static void ActorDropItem (AActor *defaults, Baggage &bag) static void ActorDropItem (AActor *defaults, Baggage &bag)
{ {
bool res;
// create a linked list of dropitems // create a linked list of dropitems
if (!bag.DropItemSet) if (!bag.DropItemSet)
{ {
@ -2477,10 +2506,11 @@ static void ActorDropItem (AActor *defaults, Baggage &bag)
di->Name=sc_String; di->Name=sc_String;
di->probability=255; di->probability=255;
di->amount=-1; di->amount=-1;
if (SC_CheckNumber())
if (CheckNumParm())
{ {
di->probability=sc_Number; di->probability=sc_Number;
if (SC_CheckNumber()) if (CheckNumParm())
{ {
di->amount=sc_Number; di->amount=sc_Number;
} }
@ -2817,8 +2847,10 @@ static void ActorBloodColor (AActor *defaults, Baggage &bag)
{ {
SC_MustGetNumber(); SC_MustGetNumber();
r=clamp<int>(sc_Number, 0, 255); r=clamp<int>(sc_Number, 0, 255);
SC_CheckString(",");
SC_MustGetNumber(); SC_MustGetNumber();
g=clamp<int>(sc_Number, 0, 255); g=clamp<int>(sc_Number, 0, 255);
SC_CheckString(",");
SC_MustGetNumber(); SC_MustGetNumber();
b=clamp<int>(sc_Number, 0, 255); b=clamp<int>(sc_Number, 0, 255);
} }
@ -3159,7 +3191,7 @@ static void InventoryPickupmsg (AInventory *defaults, Baggage &bag)
SC_MustGetString(); SC_MustGetString();
int game = SC_MatchString(games); int game = SC_MatchString(games);
if (game!=-1) if (game!=-1 && SC_CheckString(","))
{ {
SC_MustGetString(); SC_MustGetString();
if (!(gameinfo.gametype&gamemode[game])) return; if (!(gameinfo.gametype&gamemode[game])) return;
@ -3368,8 +3400,10 @@ static void PowerupColor (APowerupGiver *defaults, Baggage &bag)
if (SC_CheckNumber()) if (SC_CheckNumber())
{ {
r=clamp<int>(sc_Number, 0, 255); r=clamp<int>(sc_Number, 0, 255);
SC_CheckString(",");
SC_MustGetNumber(); SC_MustGetNumber();
g=clamp<int>(sc_Number, 0, 255); g=clamp<int>(sc_Number, 0, 255);
SC_CheckString(",");
SC_MustGetNumber(); SC_MustGetNumber();
b=clamp<int>(sc_Number, 0, 255); b=clamp<int>(sc_Number, 0, 255);
} }
@ -3393,6 +3427,7 @@ static void PowerupColor (APowerupGiver *defaults, Baggage &bag)
g=GPART(c); g=GPART(c);
b=BPART(c); b=BPART(c);
} }
SC_CheckString(",");
SC_MustGetFloat(); SC_MustGetFloat();
alpha=int(sc_Float*255); alpha=int(sc_Float*255);
alpha=clamp<int>(alpha, 0, 255); alpha=clamp<int>(alpha, 0, 255);
@ -3470,6 +3505,7 @@ static void PlayerColorRange (APlayerPawn *defaults, Baggage &bag)
SC_MustGetNumber (); SC_MustGetNumber ();
start = sc_Number; start = sc_Number;
SC_CheckString(",");
SC_MustGetNumber (); SC_MustGetNumber ();
end = sc_Number; end = sc_Number;
@ -3525,7 +3561,7 @@ static void PlayerForwardMove (APlayerPawn *defaults, Baggage &bag)
{ {
SC_MustGetFloat (); SC_MustGetFloat ();
defaults->ForwardMove1 = defaults->ForwardMove2 = FLOAT2FIXED (sc_Float); defaults->ForwardMove1 = defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
if (SC_CheckFloat ()) if (CheckFloatParm ())
defaults->ForwardMove2 = FLOAT2FIXED (sc_Float); defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
} }
@ -3536,7 +3572,7 @@ static void PlayerSideMove (APlayerPawn *defaults, Baggage &bag)
{ {
SC_MustGetFloat (); SC_MustGetFloat ();
defaults->SideMove1 = defaults->SideMove2 = FLOAT2FIXED (sc_Float); defaults->SideMove1 = defaults->SideMove2 = FLOAT2FIXED (sc_Float);
if (SC_CheckFloat ()) if (CheckFloatParm ())
defaults->SideMove2 = FLOAT2FIXED (sc_Float); defaults->SideMove2 = FLOAT2FIXED (sc_Float);
} }
@ -3596,7 +3632,7 @@ static void PlayerStartItem (APlayerPawn *defaults, Baggage &bag)
di->Name = sc_String; di->Name = sc_String;
di->probability=255; di->probability=255;
di->amount=0; di->amount=0;
if (SC_CheckNumber()) if (CheckNumParm())
{ {
di->amount=sc_Number; di->amount=sc_Number;
} }

View file

@ -77,7 +77,6 @@ static FRandom pr_cwpunch ("CustomWpPunch");
static FRandom pr_grenade ("ThrowGrenade"); static FRandom pr_grenade ("ThrowGrenade");
static FRandom pr_crailgun ("CustomRailgun"); static FRandom pr_crailgun ("CustomRailgun");
static FRandom pr_spawndebris ("SpawnDebris"); static FRandom pr_spawndebris ("SpawnDebris");
static FRandom pr_jiggle ("Jiggle");
static FRandom pr_burst ("Burst"); static FRandom pr_burst ("Burst");
@ -1471,29 +1470,6 @@ void A_ExtChase(AActor * self)
} }
//===========================================================================
//
// Weapon jiggling
//
//===========================================================================
void A_Jiggle(AActor * self)
{
int index=CheckIndex(2, &CallingState);
if (index<0) return;
int xmax = EvalExpressionI (StateParameters[index], self);
int ymax = EvalExpressionI (StateParameters[index+1], self);
if (self->player)
{
int rand_x = (pr_jiggle()%(xmax*2))-xmax;
int rand_y = (pr_jiggle()%(ymax*2))-ymax;
self->player->psprites[0].sx += rand_x;
self->player->psprites[0].sy += rand_y;
self->player->psprites[1].sx += rand_x;
self->player->psprites[1].sy += rand_y;
}
}
//=========================================================================== //===========================================================================
// //
// Inventory drop // Inventory drop

View file

@ -1,3 +1,4 @@
#include "actors/shared/blood.txt"
#include "actors/shared/debris.txt" #include "actors/shared/debris.txt"
#include "actors/shared/splashes.txt" #include "actors/shared/splashes.txt"

View file

@ -77,7 +77,7 @@ ACTOR ArtiInvulnerability : PowerupGiver 84
Inventory.RespawnTics 4230 Inventory.RespawnTics 4230
Inventory.Icon ARTIINVU Inventory.Icon ARTIINVU
Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY" Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY"
Inventory.PickupMessage Hexen "$TXT_ARTIINVULNERABILITY2" Inventory.PickupMessage Hexen, "$TXT_ARTIINVULNERABILITY2"
Powerup.Type Invulnerable Powerup.Type Invulnerable
States States
{ {

View file

@ -0,0 +1,25 @@
// Blood splatter -----------------------------------------------------------
ACTOR BloodSplatter
{
Game Raven
Radius 2
Height 4
+NOBLOCKMAP
+MISSILE
+DROPOFF
+NOTELEPORT
+CANNOTPUSH
Mass 5
States
{
Spawn:
BLUD CBA 8
Stop
Death:
BLUD A 6
Stop
}
}

View file

@ -370,3 +370,31 @@ ACTOR SGShard0 : GlassShard
} }
} }
ACTOR GlassJunk
{
+NOCLIP
+NOBLOCKMAP
RenderStyle Translucent
Alpha 0.4
Health 3 // Number of different shards
States
{
// Are the first three frames used anywhere?
SHAR A 128
Goto Death
SHAR B 128
Goto Death
SHAR C 128
Goto Death
Spawn:
SHAR D 128
Goto Death
SHAR E 128
Goto Death
SHAR F 128
Goto Death
Death:
"----" A 1 A_FadeOut(0.03)
Wait
}
}

View file

@ -236,6 +236,7 @@ acs/strfhelp.o strfhelp.o
decorate.txt decorate/decorate.txt decorate.txt decorate/decorate.txt
actors/shared/blood.txt decorate/shared/blood.txt
actors/shared/debris.txt decorate/shared/debris.txt actors/shared/debris.txt decorate/shared/debris.txt
actors/shared/splashes.txt decorate/shared/splashes.txt actors/shared/splashes.txt decorate/shared/splashes.txt