mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 14:51:40 +00:00
- scriptified Hexen's Bloodscourge and Serpent.
- merged the FrontBlock searcher for the Bloodscourge into RoughMonsterSearch. This also fixes the bug that the searcher was not initialized properly for the MageBoss.
This commit is contained in:
parent
f9a1388066
commit
ebd2c27e0a
17 changed files with 507 additions and 620 deletions
|
@ -860,8 +860,6 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
sc_man_scanner.h
|
||||
sc_man_scanner.re
|
||||
g_hexen/a_heresiarch.cpp
|
||||
g_hexen/a_magestaff.cpp
|
||||
g_hexen/a_serpent.cpp
|
||||
g_hexen/a_spike.cpp
|
||||
g_hexen/a_teleportother.cpp
|
||||
g_strife/a_acolyte.cpp
|
||||
|
|
|
@ -25,7 +25,5 @@
|
|||
|
||||
// Include all the Hexen stuff here to reduce compile time
|
||||
#include "a_heresiarch.cpp"
|
||||
#include "a_magestaff.cpp"
|
||||
#include "a_serpent.cpp"
|
||||
#include "a_spike.cpp"
|
||||
#include "a_teleportother.cpp"
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "p_local.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sound.h"
|
||||
#include "a_hexenglobal.h"
|
||||
#include "gstrings.h"
|
||||
#include "a_weaponpiece.h"
|
||||
#include "vm.h"
|
||||
#include "doomstat.h"
|
||||
*/
|
||||
|
||||
class AMageWeapon : public AWeapon
|
||||
{
|
||||
DECLARE_CLASS (AMageWeapon, AWeapon);
|
||||
public:
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AMageWeapon, false, false)
|
||||
|
||||
static FRandom pr_mstafftrack ("MStaffTrack");
|
||||
static FRandom pr_bloodscourgedrop ("BloodScourgeDrop");
|
||||
|
||||
void A_MStaffTrack (AActor *);
|
||||
void A_DropBloodscourgePieces (AActor *);
|
||||
void A_MStaffAttack (AActor *actor);
|
||||
void A_MStaffPalette (AActor *actor);
|
||||
|
||||
static AActor *FrontBlockCheck (AActor *mo, int index, void *);
|
||||
static divline_t BlockCheckLine;
|
||||
|
||||
//==========================================================================
|
||||
// The Mages's Staff (Bloodscourge) -----------------------------------------
|
||||
|
||||
class AMWeapBloodscourge : public AMageWeapon
|
||||
{
|
||||
DECLARE_CLASS (AMWeapBloodscourge, AMageWeapon)
|
||||
public:
|
||||
|
||||
void Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("mstaffcount", MStaffCount);
|
||||
}
|
||||
PalEntry GetBlend ()
|
||||
{
|
||||
if (paletteflash & PF_HEXENWEAPONS)
|
||||
{
|
||||
if (MStaffCount == 3)
|
||||
return PalEntry(128, 100, 73, 0);
|
||||
else if (MStaffCount == 2)
|
||||
return PalEntry(128, 125, 92, 0);
|
||||
else if (MStaffCount == 1)
|
||||
return PalEntry(128, 150, 110, 0);
|
||||
else
|
||||
return PalEntry(0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return PalEntry (MStaffCount * 128 / 3, 151, 110, 0);
|
||||
}
|
||||
}
|
||||
BYTE MStaffCount;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AMWeapBloodscourge, false, false)
|
||||
|
||||
// Mage Staff FX2 (Bloodscourge) --------------------------------------------
|
||||
|
||||
class AMageStaffFX2 : public AActor
|
||||
{
|
||||
DECLARE_CLASS(AMageStaffFX2, AActor)
|
||||
public:
|
||||
bool SpecialBlastHandling (AActor *source, double strength);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AMageStaffFX2, false, false)
|
||||
|
||||
bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength)
|
||||
{
|
||||
// Reflect to originator
|
||||
tracer = target;
|
||||
target = source;
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// MStaffSpawn
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void MStaffSpawn (AActor *pmo, DAngle angle, AActor *alttarget)
|
||||
{
|
||||
AActor *mo;
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
mo = P_SpawnPlayerMissile (pmo, 0, 0, 8, RUNTIME_CLASS(AMageStaffFX2), angle, &t);
|
||||
if (mo)
|
||||
{
|
||||
mo->target = pmo;
|
||||
if (t.linetarget && !t.unlinked)
|
||||
mo->tracer = t.linetarget;
|
||||
else
|
||||
mo->tracer = alttarget;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
|
||||
DAngle angle;
|
||||
player_t *player;
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
if (NULL == (player = self->player))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
return 0;
|
||||
}
|
||||
angle = self->Angles.Yaw;
|
||||
|
||||
// [RH] Let's try and actually track what the player aimed at
|
||||
P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, 32.);
|
||||
if (t.linetarget == NULL)
|
||||
{
|
||||
BlockCheckLine.x = self->X();
|
||||
BlockCheckLine.y = self->Y();
|
||||
BlockCheckLine.dx = -angle.Sin();
|
||||
BlockCheckLine.dy = -angle.Cos();
|
||||
t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck);
|
||||
}
|
||||
MStaffSpawn (self, angle, t.linetarget);
|
||||
MStaffSpawn (self, angle-5, t.linetarget);
|
||||
MStaffSpawn (self, angle+5, t.linetarget);
|
||||
S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
|
||||
weapon->MStaffCount = 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffPalette
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
|
||||
if (self->player != NULL)
|
||||
{
|
||||
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
|
||||
if (weapon != NULL && weapon->MStaffCount != 0)
|
||||
{
|
||||
weapon->MStaffCount--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffTrack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if ((self->tracer == 0) && (pr_mstafftrack()<50))
|
||||
{
|
||||
self->tracer = P_RoughMonsterSearch (self, 10, true);
|
||||
}
|
||||
P_SeekerMissile(self, 2, 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// FrontBlockCheck
|
||||
//
|
||||
// [RH] Like RoughBlockCheck, but it won't return anything behind a line.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
static AActor *FrontBlockCheck (AActor *mo, int index, void *)
|
||||
{
|
||||
FBlockNode *link;
|
||||
|
||||
for (link = blocklinks[index]; link != NULL; link = link->NextActor)
|
||||
{
|
||||
if (link->Me != mo)
|
||||
{
|
||||
if (P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &BlockCheckLine) == 0 &&
|
||||
mo->IsOkayToAttack (link->Me))
|
||||
{
|
||||
return link->Me;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// MStaffSpawn2 - for use by mage class boss
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void MStaffSpawn2 (AActor *actor, DAngle angle)
|
||||
{
|
||||
AActor *mo;
|
||||
|
||||
mo = P_SpawnMissileAngleZ (actor, actor->Z()+40, RUNTIME_CLASS(AMageStaffFX2), angle, 0.);
|
||||
if (mo)
|
||||
{
|
||||
mo->target = actor;
|
||||
mo->tracer = P_BlockmapSearch (mo, 10, FrontBlockCheck);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffAttack2 - for use by mage class boss
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MageAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (self->target == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
DAngle angle = self->Angles.Yaw;
|
||||
MStaffSpawn2(self, angle);
|
||||
MStaffSpawn2(self, angle - 5);
|
||||
MStaffSpawn2(self, angle + 5);
|
||||
S_Sound(self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
|
||||
return 0;
|
||||
}
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "p_local.h"
|
||||
#include "s_sound.h"
|
||||
#include "p_enemy.h"
|
||||
#include "a_action.h"
|
||||
#include "m_random.h"
|
||||
#include "p_terrain.h"
|
||||
#include "vm.h"
|
||||
*/
|
||||
|
||||
static FRandom pr_serpentchase ("SerpentChase");
|
||||
static FRandom pr_serpenthump ("SerpentHump");
|
||||
static FRandom pr_serpentattack ("SerpentAttack");
|
||||
static FRandom pr_serpentmeattack ("SerpentMeAttack");
|
||||
static FRandom pr_serpentgibs ("SerpentGibs");
|
||||
static FRandom pr_delaygib ("DelayGib");
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentUnHide
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->renderflags &= ~RF_INVISIBLE;
|
||||
self->Floorclip = 24;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHide
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->renderflags |= RF_INVISIBLE;
|
||||
self->Floorclip = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentRaiseHump
|
||||
//
|
||||
// Raises the hump above the surface by raising the floorclip level
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->Floorclip -= 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentLowerHump
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->Floorclip += 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHumpDecide
|
||||
//
|
||||
// Decided whether to hump up, or if the mobj is a serpent leader,
|
||||
// to missile attack
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (self->MissileState != NULL)
|
||||
{
|
||||
if (pr_serpenthump() > 30)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (pr_serpenthump() < 40)
|
||||
{ // Missile attack
|
||||
self->SetState (self->MeleeState);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (pr_serpenthump() > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!self->CheckMeleeRange ())
|
||||
{ // The hump shouldn't occur when within melee range
|
||||
if (self->MissileState != NULL && pr_serpenthump() < 128)
|
||||
{
|
||||
self->SetState (self->MeleeState);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->SetState (self->FindState ("Hump"));
|
||||
S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentCheckForAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (!self->target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (self->MissileState != NULL)
|
||||
{
|
||||
if (!self->CheckMeleeRange ())
|
||||
{
|
||||
self->SetState (self->FindState ("Attack"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (P_CheckMeleeRange2 (self))
|
||||
{
|
||||
self->SetState (self->FindState ("Walk"));
|
||||
}
|
||||
else if (self->CheckMeleeRange ())
|
||||
{
|
||||
if (pr_serpentattack() < 32)
|
||||
{
|
||||
self->SetState (self->FindState ("Walk"));
|
||||
}
|
||||
else
|
||||
{
|
||||
self->SetState (self->FindState ("Attack"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentChooseAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (!self->target || self->CheckMeleeRange())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (self->MissileState != NULL)
|
||||
{
|
||||
self->SetState (self->MissileState);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentMeleeAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (!self->target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (self->CheckMeleeRange ())
|
||||
{
|
||||
int damage = pr_serpentmeattack.HitDice (5);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM);
|
||||
}
|
||||
if (pr_serpentmeattack() < 96)
|
||||
{
|
||||
CALL_ACTION(A_SerpentCheckForAttack, self);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentSpawnGibs
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
static const char *GibTypes[] =
|
||||
{
|
||||
"SerpentGib3",
|
||||
"SerpentGib2",
|
||||
"SerpentGib1"
|
||||
};
|
||||
|
||||
for (int i = countof(GibTypes)-1; i >= 0; --i)
|
||||
{
|
||||
double x = (pr_serpentgibs() - 128) / 16.;
|
||||
double y = (pr_serpentgibs() - 128) / 16.;
|
||||
|
||||
mo = Spawn (GibTypes[i], self->Vec2OffsetZ(x, y, self->floorz + 1), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->Vel.X = (pr_serpentgibs() - 128) / 1024.f;
|
||||
mo->Vel.Y = (pr_serpentgibs() - 128) / 1024.f;
|
||||
mo->Floorclip = 6;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FloatGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FloatGib)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->Floorclip -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SinkGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SinkGib)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->Floorclip += 1;;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DelayGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DelayGib)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->tics -= pr_delaygib()>>2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHeadCheck
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (self->Z() <= self->floorz)
|
||||
{
|
||||
if (Terrains[P_GetThingFloorType(self)].IsLiquid)
|
||||
{
|
||||
P_HitFloor (self);
|
||||
self->SetState (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->SetState (self->FindState(NAME_Death));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -365,6 +365,12 @@ bool P_CheckMeleeRange2 (AActor *actor)
|
|||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange2)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_INT(P_CheckMeleeRange2(self));
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
|
|
|
@ -238,7 +238,7 @@ enum PCM
|
|||
|
||||
|
||||
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL);
|
||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false);
|
||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false);
|
||||
|
||||
//
|
||||
// P_MAP
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "templates.h"
|
||||
#include "po_man.h"
|
||||
|
||||
static AActor *RoughBlockCheck (AActor *mo, int index, void *);
|
||||
sector_t *P_PointInSectorBuggy(double x, double y);
|
||||
int P_VanillaPointOnDivlineSide(double x, double y, const divline_t* line);
|
||||
|
||||
|
@ -1685,19 +1684,6 @@ FPathTraverse::~FPathTraverse()
|
|||
// distance is in MAPBLOCKUNITS
|
||||
//===========================================================================
|
||||
|
||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable)
|
||||
{
|
||||
return P_BlockmapSearch (mo, distance, RoughBlockCheck, (void *)onlyseekable);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(distance);
|
||||
PARAM_BOOL_DEF(onlyseekable);
|
||||
ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable));
|
||||
}
|
||||
|
||||
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params)
|
||||
{
|
||||
int blockX;
|
||||
|
@ -1787,6 +1773,13 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct BlockCheckInfo
|
||||
{
|
||||
bool onlyseekable;
|
||||
bool frontonly;
|
||||
divline_t frontline;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// RoughBlockCheck
|
||||
|
@ -1795,14 +1788,19 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
|||
|
||||
static AActor *RoughBlockCheck (AActor *mo, int index, void *param)
|
||||
{
|
||||
bool onlyseekable = param != NULL;
|
||||
BlockCheckInfo *info = (BlockCheckInfo *)param;
|
||||
|
||||
FBlockNode *link;
|
||||
|
||||
for (link = blocklinks[index]; link != NULL; link = link->NextActor)
|
||||
{
|
||||
if (link->Me != mo)
|
||||
{
|
||||
if (onlyseekable && !mo->CanSeek(link->Me))
|
||||
if (info->onlyseekable && !mo->CanSeek(link->Me))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (info->frontonly && P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &info->frontline) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -1815,6 +1813,30 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly)
|
||||
{
|
||||
BlockCheckInfo info;
|
||||
info.onlyseekable = onlyseekable;
|
||||
if ((info.frontonly = frontonly))
|
||||
{
|
||||
info.frontline.x = mo->X();
|
||||
info.frontline.y = mo->Y();
|
||||
info.frontline.dx = -mo->Angles.Yaw.Sin();
|
||||
info.frontline.dy = -mo->Angles.Yaw.Cos();
|
||||
}
|
||||
|
||||
return P_BlockmapSearch(mo, distance, RoughBlockCheck, (void *)&info);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(distance);
|
||||
PARAM_BOOL_DEF(onlyseekable);
|
||||
PARAM_BOOL_DEF(frontonly);
|
||||
ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// [RH] LinkToWorldForMapThing
|
||||
|
|
|
@ -5908,6 +5908,13 @@ int P_GetThingFloorType (AActor *thing)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetFloorTerrain)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_POINTER(&Terrains[P_GetThingFloorType(self)]);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FUNC P_HitWater
|
||||
|
|
|
@ -724,3 +724,18 @@ FName P_GetTerrainName(int terrainnum)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_FIELD_NAMED(FTerrainDef, Name, TerrainName)
|
||||
DEFINE_FIELD(FTerrainDef, Splash)
|
||||
DEFINE_FIELD(FTerrainDef, DamageAmount)
|
||||
DEFINE_FIELD(FTerrainDef, DamageMOD)
|
||||
DEFINE_FIELD(FTerrainDef, DamageTimeMask)
|
||||
DEFINE_FIELD(FTerrainDef, FootClip)
|
||||
DEFINE_FIELD(FTerrainDef, StepVolume)
|
||||
DEFINE_FIELD(FTerrainDef, WalkStepTics)
|
||||
DEFINE_FIELD(FTerrainDef, RunStepTics)
|
||||
DEFINE_FIELD(FTerrainDef, LeftStepSound)
|
||||
DEFINE_FIELD(FTerrainDef, RightStepSound)
|
||||
DEFINE_FIELD(FTerrainDef, IsLiquid)
|
||||
DEFINE_FIELD(FTerrainDef, AllowProtection)
|
||||
DEFINE_FIELD(FTerrainDef, Friction)
|
||||
DEFINE_FIELD(FTerrainDef, MoveFactor)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "autosegs.h"
|
||||
#include "p_maputl.h"
|
||||
#include "gi.h"
|
||||
#include "p_terrain.h"
|
||||
|
||||
static TArray<FPropertyInfo*> properties;
|
||||
static TArray<AFuncDesc> AFTable;
|
||||
|
|
|
@ -1095,6 +1095,7 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self);
|
|||
|
||||
|
||||
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_GENERIC); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0)
|
||||
#define ACTION_RETURN_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0)
|
||||
|
|
|
@ -288,6 +288,7 @@ class Actor : Thinker native
|
|||
native void SetFriendPlayer(PlayerInfo player);
|
||||
native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0);
|
||||
native void ClearBounce();
|
||||
native TerrainDef GetFloorTerrain();
|
||||
|
||||
native void ExplodeMissile(line lin = null, Actor target = null);
|
||||
native void RestoreDamage();
|
||||
|
@ -310,7 +311,7 @@ class Actor : Thinker native
|
|||
native Actor SpawnMissileAngleZSpeed (double z, class<Actor> type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true);
|
||||
native Actor, Actor SpawnPlayerMissile(class<Actor> type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0);
|
||||
native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget);
|
||||
native Actor RoughMonsterSearch(int distance, bool onlyseekable = false);
|
||||
native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false);
|
||||
native int ApplyDamageFactor(Name damagetype, int damage);
|
||||
native int GetModifiedDamage(Name damagetype, int damage, bool passive);
|
||||
|
||||
|
@ -329,6 +330,7 @@ class Actor : Thinker native
|
|||
|
||||
native void SetIdle(bool nofunction = false);
|
||||
native bool CheckMeleeRange();
|
||||
native bool CheckMeleeRange2();
|
||||
native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0);
|
||||
native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null);
|
||||
native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class<Actor> pufftype, int flags = 0, out FTranslatedLineTarget victim = null);
|
||||
|
|
|
@ -248,3 +248,22 @@ struct Wads
|
|||
|
||||
native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false);
|
||||
}
|
||||
|
||||
struct TerrainDef native
|
||||
{
|
||||
native Name TerrainName;
|
||||
native int Splash;
|
||||
native int DamageAmount;
|
||||
native Name DamageMOD;
|
||||
native int DamageTimeMask;
|
||||
native double FootClip;
|
||||
native float StepVolume;
|
||||
native int WalkStepTics;
|
||||
native int RunStepTics;
|
||||
native Sound LeftStepSound;
|
||||
native Sound RightStepSound;
|
||||
native bool IsLiquid;
|
||||
native bool AllowProtection;
|
||||
native double Friction;
|
||||
native double MoveFactor;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ class ClericWeapon : Weapon
|
|||
}
|
||||
}
|
||||
|
||||
class MageWeapon : Weapon native
|
||||
class MageWeapon : Weapon
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
|
|
@ -18,8 +18,6 @@ class MageBoss : Actor
|
|||
Obituary "$OB_MBOSS";
|
||||
}
|
||||
|
||||
native void A_MageAttack();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -83,4 +81,39 @@ class MageBoss : Actor
|
|||
FDTH V 4 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// MStaffSpawn2 - for use by mage class boss
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void MStaffSpawn2 (double angle)
|
||||
{
|
||||
Actor mo = SpawnMissileAngleZ (pos.z + 40, "MageStaffFX2", angle, 0.);
|
||||
if (mo)
|
||||
{
|
||||
mo.target = self;
|
||||
mo.tracer = RoughMonsterSearch(10, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffAttack2 - for use by mage class boss
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_MageAttack()
|
||||
{
|
||||
if (target == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MStaffSpawn2(angle);
|
||||
MStaffSpawn2(angle - 5);
|
||||
MStaffSpawn2(angle + 5);
|
||||
A_PlaySound("MageStaffFire", CHAN_WEAPON);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,8 +76,10 @@ class BloodscourgeDrop : Actor
|
|||
|
||||
// The Mages's Staff (Bloodscourge) -----------------------------------------
|
||||
|
||||
class MWeapBloodscourge : MageWeapon native
|
||||
class MWeapBloodscourge : MageWeapon
|
||||
{
|
||||
int MStaffCount;
|
||||
|
||||
Default
|
||||
{
|
||||
Health 3;
|
||||
|
@ -97,9 +99,6 @@ class MWeapBloodscourge : MageWeapon native
|
|||
Tag "$TAG_MWEAPBLOODSCOURGE";
|
||||
}
|
||||
|
||||
action native void A_MStaffAttack();
|
||||
action native void A_MStaffPalette();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -123,11 +122,104 @@ class MWeapBloodscourge : MageWeapon native
|
|||
MSTF J 5 Offset (0, 36);
|
||||
Goto Ready;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
override Color GetBlend ()
|
||||
{
|
||||
if (paletteflash & PF_HEXENWEAPONS)
|
||||
{
|
||||
if (MStaffCount == 3)
|
||||
return Color(128, 100, 73, 0);
|
||||
else if (MStaffCount == 2)
|
||||
return Color(128, 125, 92, 0);
|
||||
else if (MStaffCount == 1)
|
||||
return Color(128, 150, 110, 0);
|
||||
else
|
||||
return Color(0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color (MStaffCount * 128 / 3, 151, 110, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// MStaffSpawn
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
private action void MStaffSpawn (double angle, Actor alttarget)
|
||||
{
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
Actor mo = SpawnPlayerMissile ("MageStaffFX2", angle, pLineTarget:t);
|
||||
if (mo)
|
||||
{
|
||||
mo.target = self;
|
||||
if (t.linetarget && !t.unlinked)
|
||||
mo.tracer = t.linetarget;
|
||||
else
|
||||
mo.tracer = alttarget;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
action void A_MStaffAttack()
|
||||
{
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Weapon weapon = player.ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
||||
return;
|
||||
}
|
||||
|
||||
// [RH] Let's try and actually track what the player aimed at
|
||||
AimLineAttack (angle, PLAYERMISSILERANGE, t, 32.);
|
||||
if (t.linetarget == NULL)
|
||||
{
|
||||
t.linetarget = RoughMonsterSearch(10, true, true);
|
||||
}
|
||||
MStaffSpawn (angle, t.linetarget);
|
||||
MStaffSpawn (angle-5, t.linetarget);
|
||||
MStaffSpawn (angle+5, t.linetarget);
|
||||
A_PlaySound ("MageStaffFire", CHAN_WEAPON);
|
||||
invoker.MStaffCount = 3;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffPalette
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
action void A_MStaffPalette()
|
||||
{
|
||||
if (invoker.MStaffCount > 0) invoker.MStaffCount--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mage Staff FX2 (Bloodscourge) --------------------------------------------
|
||||
|
||||
class MageStaffFX2 : Actor native
|
||||
class MageStaffFX2 : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
@ -143,7 +235,6 @@ class MageStaffFX2 : Actor native
|
|||
Obituary "$OB_MPMWEAPBLOODSCOURGE";
|
||||
}
|
||||
|
||||
native void A_MStaffTrack();
|
||||
|
||||
States
|
||||
{
|
||||
|
@ -158,6 +249,12 @@ class MageStaffFX2 : Actor native
|
|||
Stop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
override int SpecialMissileHit (Actor victim)
|
||||
{
|
||||
if (victim != target && !victim.player && !victim.bBoss)
|
||||
|
@ -168,5 +265,26 @@ class MageStaffFX2 : Actor native
|
|||
return -1;
|
||||
}
|
||||
|
||||
override bool SpecialBlastHandling (Actor source, double strength)
|
||||
{
|
||||
// Reflect to originator
|
||||
tracer = target;
|
||||
target = source;
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_MStaffTrack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_MStaffTrack()
|
||||
{
|
||||
if (tracer == null && random[MStaffTrack]() < 50)
|
||||
{
|
||||
tracer = RoughMonsterSearch (10, true);
|
||||
}
|
||||
A_SeekerMissile(2, 10);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,16 +24,6 @@ class Serpent : Actor
|
|||
HitObituary "$OB_SERPENTHIT";
|
||||
}
|
||||
|
||||
native void A_SerpentHumpDecide();
|
||||
native void A_SerpentHide();
|
||||
native void A_SerpentCheckForAttack();
|
||||
native void A_SerpentSpawnGibs();
|
||||
native void A_SerpentUnHide();
|
||||
native void A_SerpentRaiseHump();
|
||||
native void A_SerpentLowerHump();
|
||||
native void A_SerpentChooseAttack();
|
||||
native void A_SerpentMeleeAttack();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -99,6 +89,203 @@ class Serpent : Actor
|
|||
SSPT N 5 A_SerpentMeleeAttack;
|
||||
Goto Dive;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentUnHide
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentUnHide()
|
||||
{
|
||||
bInvisible = false;
|
||||
Floorclip = 24;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHide
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentHide()
|
||||
{
|
||||
bInvisible = true;
|
||||
Floorclip = 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentRaiseHump
|
||||
//
|
||||
// Raises the hump above the surface by raising the floorclip level
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentRaiseHump()
|
||||
{
|
||||
Floorclip -= 4;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentLowerHump
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentLowerHump()
|
||||
{
|
||||
Floorclip += 4;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHumpDecide
|
||||
//
|
||||
// Decided whether to hump up, or if the mobj is a serpent leader,
|
||||
// to missile attack
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentHumpDecide()
|
||||
{
|
||||
if (MissileState != NULL)
|
||||
{
|
||||
if (random[SerpentHump]() > 30)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (random[SerpentHump]() < 40)
|
||||
{ // Missile attack
|
||||
SetState (MeleeState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (random[SerpentHump]() > 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!CheckMeleeRange ())
|
||||
{ // The hump shouldn't occur when within melee range
|
||||
if (MissileState != NULL && random[SerpentHump]() < 128)
|
||||
{
|
||||
SetState (MeleeState);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStateLabel("Hump");
|
||||
A_PlaySound ("SerpentActive", CHAN_BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentCheckForAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentCheckForAttack()
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (MissileState != NULL)
|
||||
{
|
||||
if (!CheckMeleeRange ())
|
||||
{
|
||||
SetStateLabel ("Attack");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (CheckMeleeRange2 ())
|
||||
{
|
||||
SetStateLabel ("Walk");
|
||||
}
|
||||
else if (CheckMeleeRange ())
|
||||
{
|
||||
if (random[SerpentAttack]() < 32)
|
||||
{
|
||||
SetStateLabel ("Walk");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStateLabel ("Attack");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentChooseAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentChooseAttack()
|
||||
{
|
||||
if (!target || CheckMeleeRange())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (MissileState != NULL)
|
||||
{
|
||||
SetState (MissileState);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentMeleeAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentMeleeAttack()
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (CheckMeleeRange ())
|
||||
{
|
||||
int damage = random[SerpentAttack](1, 8) * 5;
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
A_PlaySound ("SerpentMeleeHit", CHAN_BODY);
|
||||
}
|
||||
if (random[SerpentAttack]() < 96)
|
||||
{
|
||||
A_SerpentCheckForAttack();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentSpawnGibs
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentSpawnGibs()
|
||||
{
|
||||
static const class<Actor> GibTypes[] =
|
||||
{
|
||||
"SerpentGib3",
|
||||
"SerpentGib2",
|
||||
"SerpentGib1"
|
||||
};
|
||||
|
||||
for (int i = 2; i >= 0; --i)
|
||||
{
|
||||
double x = (random[SerpentGibs]() - 128) / 16.;
|
||||
double y = (random[SerpentGibs]() - 128) / 16.;
|
||||
|
||||
Actor mo = Spawn (GibTypes[i], Vec2OffsetZ(x, y, floorz + 1), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo.Vel.X = (random[SerpentGibs]() - 128) / 1024.f;
|
||||
mo.Vel.Y = (random[SerpentGibs]() - 128) / 1024.f;
|
||||
mo.Floorclip = 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Serpent Leader -----------------------------------------------------------
|
||||
|
@ -159,8 +346,6 @@ class SerpentHead : Actor
|
|||
+NOBLOCKMAP
|
||||
}
|
||||
|
||||
native void A_SerpentHeadCheck();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -170,6 +355,28 @@ class SerpentHead : Actor
|
|||
SSXD S -1;
|
||||
Loop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SerpentHeadCheck
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SerpentHeadCheck()
|
||||
{
|
||||
if (pos.z <= floorz)
|
||||
{
|
||||
if (GetFloorTerrain().IsLiquid)
|
||||
{
|
||||
HitFloor ();
|
||||
Destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStateLabel ("NAME_Death");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Serpent Gib 1 ------------------------------------------------------------
|
||||
|
@ -183,10 +390,6 @@ class SerpentGib1 : Actor
|
|||
+NOBLOCKMAP +NOGRAVITY
|
||||
}
|
||||
|
||||
native void A_FloatGib();
|
||||
native void A_DelayGib();
|
||||
native void A_SinkGib();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -199,6 +402,41 @@ class SerpentGib1 : Actor
|
|||
SSXD QQQ 8 A_SinkGib;
|
||||
Stop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FloatGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_FloatGib()
|
||||
{
|
||||
Floorclip -= 1;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_SinkGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_SinkGib()
|
||||
{
|
||||
Floorclip += 1;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DelayGib
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DelayGib()
|
||||
{
|
||||
tics -= random[DelayGib]() >> 2;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Serpent Gib 2 ------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue