mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
- scriptified Heretic's Skull Rod.
- Took the opportunity and fixed the logic for the Skull Rod's rain spawner. The old code which was part of the 3D floor submission was unable to work with portals at all. The new approach no longer tries to hide the dead projectile in the ceiling, it leaves it where it is and changes a few flags, so that its z-position can be used as reference to get the actual ceiling. This works for line portals, but for sector portals still requires some changes to sector_t::NextHighestCeilingAt to work, but at least this can be made to work unlike the old code. - added names for the player-related translations to A_SetTranslation. - fixed: Failure to resolve a function argument was checked for, too late. - made the parameter for A_SetTranslation a name instead of a string, because it is more efficient. We do not need full strings here.
This commit is contained in:
parent
c2f7ed7f1c
commit
8dba322775
16 changed files with 570 additions and 521 deletions
|
@ -759,7 +759,7 @@ public:
|
||||||
virtual FName GetSpecies();
|
virtual FName GetSpecies();
|
||||||
|
|
||||||
// set translation
|
// set translation
|
||||||
void SetTranslation(const char *trname);
|
void SetTranslation(FName trname);
|
||||||
|
|
||||||
double GetBobOffset(double ticfrac = 0) const
|
double GetBobOffset(double ticfrac = 0) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,305 +46,6 @@ void P_DSparilTeleport (AActor *actor);
|
||||||
extern bool P_AutoUseChaosDevice (player_t *player);
|
extern bool P_AutoUseChaosDevice (player_t *player);
|
||||||
|
|
||||||
|
|
||||||
// --- Skull rod ------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
// Rain pillar 1 ------------------------------------------------------------
|
|
||||||
|
|
||||||
class ARainPillar : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (ARainPillar, AActor)
|
|
||||||
public:
|
|
||||||
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(ARainPillar, false, false)
|
|
||||||
|
|
||||||
int ARainPillar::DoSpecialDamage (AActor *target, int damage, FName damagetype)
|
|
||||||
{
|
|
||||||
if (target->flags2 & MF2_BOSS)
|
|
||||||
{ // Decrease damage for bosses
|
|
||||||
damage = (pr_rp() & 7) + 1;
|
|
||||||
}
|
|
||||||
return damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rain tracker "inventory" item --------------------------------------------
|
|
||||||
|
|
||||||
class ARainTracker : public AInventory
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (ARainTracker, AInventory)
|
|
||||||
public:
|
|
||||||
|
|
||||||
void Serialize(FSerializer &arc);
|
|
||||||
TObjPtr<AActor> Rain1, Rain2;
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(ARainTracker, false, false)
|
|
||||||
|
|
||||||
void ARainTracker::Serialize(FSerializer &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc("rain1", Rain1)
|
|
||||||
("rain2", Rain2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_FireSkullRodPL1
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *mo;
|
|
||||||
player_t *player;
|
|
||||||
|
|
||||||
if (NULL == (player = self->player))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AWeapon *weapon = player->ReadyWeapon;
|
|
||||||
if (weapon != NULL)
|
|
||||||
{
|
|
||||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
mo = P_SpawnPlayerMissile (self, PClass::FindActor("HornRodFX1"));
|
|
||||||
// Randomize the first frame
|
|
||||||
if (mo && pr_fsr1() > 128)
|
|
||||||
{
|
|
||||||
mo->SetState (mo->state->GetNextState());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_FireSkullRodPL2
|
|
||||||
//
|
|
||||||
// The special2 field holds the player number that shot the rain missile.
|
|
||||||
// The special1 field holds the id of the rain sound.
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
player_t *player;
|
|
||||||
AActor *MissileActor;
|
|
||||||
FTranslatedLineTarget t;
|
|
||||||
|
|
||||||
if (NULL == (player = self->player))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
AWeapon *weapon = player->ReadyWeapon;
|
|
||||||
if (weapon != NULL)
|
|
||||||
{
|
|
||||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HornRodFX2"), self->Angles.Yaw, &t, &MissileActor);
|
|
||||||
// Use MissileActor instead of the return value from
|
|
||||||
// P_SpawnPlayerMissile because we need to give info to the mobj
|
|
||||||
// even if it exploded immediately.
|
|
||||||
if (MissileActor != NULL)
|
|
||||||
{
|
|
||||||
MissileActor->special2 = (int)(player - players);
|
|
||||||
if (t.linetarget && !t.unlinked)
|
|
||||||
{
|
|
||||||
MissileActor->tracer = t.linetarget;
|
|
||||||
}
|
|
||||||
S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_AddPlayerRain
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
ARainTracker *tracker;
|
|
||||||
|
|
||||||
if (self->target == NULL || self->target->health <= 0)
|
|
||||||
{ // Shooter is dead or nonexistant
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tracker = self->target->FindInventory<ARainTracker> ();
|
|
||||||
|
|
||||||
// They player is only allowed two rainstorms at a time. Shooting more
|
|
||||||
// than that will cause the oldest one to terminate.
|
|
||||||
if (tracker != NULL)
|
|
||||||
{
|
|
||||||
if (tracker->Rain1 && tracker->Rain2)
|
|
||||||
{ // Terminate an active rain
|
|
||||||
if (tracker->Rain1->health < tracker->Rain2->health)
|
|
||||||
{
|
|
||||||
if (tracker->Rain1->health > 16)
|
|
||||||
{
|
|
||||||
tracker->Rain1->health = 16;
|
|
||||||
}
|
|
||||||
tracker->Rain1 = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (tracker->Rain2->health > 16)
|
|
||||||
{
|
|
||||||
tracker->Rain2->health = 16;
|
|
||||||
}
|
|
||||||
tracker->Rain2 = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tracker = static_cast<ARainTracker *> (self->target->GiveInventoryType (RUNTIME_CLASS(ARainTracker)));
|
|
||||||
}
|
|
||||||
// Add rain mobj to list
|
|
||||||
if (tracker->Rain1)
|
|
||||||
{
|
|
||||||
tracker->Rain2 = self;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tracker->Rain1 = self;
|
|
||||||
}
|
|
||||||
self->special1 = S_FindSound ("misc/rain");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_SkullRodStorm
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *mo;
|
|
||||||
ARainTracker *tracker;
|
|
||||||
|
|
||||||
if (self->health-- == 0)
|
|
||||||
{
|
|
||||||
S_StopSound (self, CHAN_BODY);
|
|
||||||
if (self->target == NULL)
|
|
||||||
{ // Player left the game
|
|
||||||
self->Destroy ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
tracker = self->target->FindInventory<ARainTracker> ();
|
|
||||||
if (tracker != NULL)
|
|
||||||
{
|
|
||||||
if (tracker->Rain1 == self)
|
|
||||||
{
|
|
||||||
tracker->Rain1 = NULL;
|
|
||||||
}
|
|
||||||
else if (tracker->Rain2 == self)
|
|
||||||
{
|
|
||||||
tracker->Rain2 = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self->Destroy ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (pr_storm() < 25)
|
|
||||||
{ // Fudge rain frequency
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
double xo = ((pr_storm() & 127) - 64);
|
|
||||||
double yo = ((pr_storm() & 127) - 64);
|
|
||||||
DVector3 pos = self->Vec2OffsetZ(xo, yo, ONCEILINGZ);
|
|
||||||
mo = Spawn<ARainPillar> (pos, ALLOW_REPLACE);
|
|
||||||
// We used bouncecount to store the 3D floor index in A_HideInCeiling
|
|
||||||
if (!mo) return 0;
|
|
||||||
if (mo->Sector->PortalGroup != self->Sector->PortalGroup)
|
|
||||||
{
|
|
||||||
// spawning this through a portal will never work right so abort right away.
|
|
||||||
mo->Destroy();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (self->bouncecount >= 0 && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size())
|
|
||||||
pos.Z = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(mo);
|
|
||||||
else
|
|
||||||
pos.Z = self->Sector->ceilingplane.ZatPoint(mo);
|
|
||||||
int moceiling = P_Find3DFloor(NULL, pos, false, false, pos.Z);
|
|
||||||
if (moceiling >= 0) mo->SetZ(pos.Z - mo->Height);
|
|
||||||
mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_RainPillar,self->special2) : 0;
|
|
||||||
mo->target = self->target;
|
|
||||||
mo->Vel.X = MinVel; // Force collision detection
|
|
||||||
mo->Vel.Z = -mo->Speed;
|
|
||||||
mo->special2 = self->special2; // Transfer player number
|
|
||||||
P_CheckMissileSpawn (mo, self->radius);
|
|
||||||
if (self->special1 != -1 && !S_IsActorPlayingSomething (self, CHAN_BODY, -1))
|
|
||||||
{
|
|
||||||
S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_RainImpact
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_RainImpact)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
if (self->Z() > self->floorz)
|
|
||||||
{
|
|
||||||
self->SetState (self->FindState("NotFloor"));
|
|
||||||
}
|
|
||||||
else if (pr_impact() < 40)
|
|
||||||
{
|
|
||||||
P_HitFloor (self);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// PROC A_HideInCeiling
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
// We use bouncecount to store the 3D floor index
|
|
||||||
double foo;
|
|
||||||
for (int i = self->Sector->e->XFloor.ffloors.Size() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
|
|
||||||
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
|
|
||||||
|
|
||||||
if ((foo = rover->bottom.plane->ZatPoint(self)) >= self->Top())
|
|
||||||
{
|
|
||||||
self->SetZ(foo + 4, false);
|
|
||||||
self->bouncecount = i;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self->bouncecount = -1;
|
|
||||||
self->SetZ(self->ceilingz + 4, false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Phoenix Rod ----------------------------------------------------------
|
// --- Phoenix Rod ----------------------------------------------------------
|
||||||
|
|
||||||
class APhoenixRod : public AWeapon
|
class APhoenixRod : public AWeapon
|
||||||
|
|
|
@ -764,3 +764,22 @@ xx(a)
|
||||||
xx(r)
|
xx(r)
|
||||||
xx(g)
|
xx(g)
|
||||||
xx(b)
|
xx(b)
|
||||||
|
|
||||||
|
// Special translation names
|
||||||
|
xx(RainPillar1)
|
||||||
|
xx(RainPillar2)
|
||||||
|
xx(RainPillar3)
|
||||||
|
xx(RainPillar4)
|
||||||
|
xx(RainPillar5)
|
||||||
|
xx(RainPillar6)
|
||||||
|
xx(RainPillar7)
|
||||||
|
xx(RainPillar8)
|
||||||
|
|
||||||
|
xx(Player1)
|
||||||
|
xx(Player2)
|
||||||
|
xx(Player3)
|
||||||
|
xx(Player4)
|
||||||
|
xx(Player5)
|
||||||
|
xx(Player6)
|
||||||
|
xx(Player7)
|
||||||
|
xx(Player8)
|
||||||
|
|
|
@ -6802,7 +6802,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetVisibleRotation)
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation)
|
DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
PARAM_STRING(trname);
|
PARAM_NAME(trname);
|
||||||
|
|
||||||
self->SetTranslation(trname);
|
self->SetTranslation(trname);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1089,6 +1089,14 @@ AInventory *AActor::GiveInventoryType (PClassActor *type)
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_CLASS(type, AInventory);
|
||||||
|
ACTION_RETURN_OBJECT(self->GiveInventoryType(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// AActor :: GiveAmmo
|
// AActor :: GiveAmmo
|
||||||
|
@ -7098,9 +7106,10 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AActor::SetTranslation(const char *trname)
|
void AActor::SetTranslation(FName trname)
|
||||||
{
|
{
|
||||||
if (*trname == 0)
|
// There is no constant for the empty name...
|
||||||
|
if (trname.GetChars()[0] == 0)
|
||||||
{
|
{
|
||||||
// an empty string resets to the default
|
// an empty string resets to the default
|
||||||
Translation = GetDefault()->Translation;
|
Translation = GetDefault()->Translation;
|
||||||
|
@ -7341,6 +7350,12 @@ DEFINE_ACTION_FUNCTION(AActor, RestoreDamage)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, PlayerNumber)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
ACTION_RETURN_INT(self->player ? int(self->player - players) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// DropItem handling
|
// DropItem handling
|
||||||
|
|
|
@ -960,7 +960,7 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->GetPortalPlaneZ(ceiling))
|
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->GetPortalPlaneZ(ceiling))
|
||||||
{ // Use sector's floor
|
{ // Use sector's ceiling
|
||||||
if (resultffloor) *resultffloor = NULL;
|
if (resultffloor) *resultffloor = NULL;
|
||||||
if (resultsec) *resultsec = sec;
|
if (resultsec) *resultsec = sec;
|
||||||
return realceil;
|
return realceil;
|
||||||
|
@ -976,6 +976,34 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
|
||||||
|
PARAM_FLOAT(x);
|
||||||
|
PARAM_FLOAT(y);
|
||||||
|
PARAM_FLOAT(bottomz);
|
||||||
|
PARAM_FLOAT(topz);
|
||||||
|
PARAM_INT_DEF(flags);
|
||||||
|
sector_t *resultsec;
|
||||||
|
F3DFloor *resultff;
|
||||||
|
double resultheight = self->NextHighestCeilingAt(x, y, bottomz, topz, flags, &resultsec, &resultff);
|
||||||
|
|
||||||
|
if (numret > 2)
|
||||||
|
{
|
||||||
|
ret[2].SetPointer(resultff, ATAG_GENERIC);
|
||||||
|
numret = 3;
|
||||||
|
}
|
||||||
|
if (numret > 1)
|
||||||
|
{
|
||||||
|
ret[1].SetPointer(resultsec, ATAG_GENERIC);
|
||||||
|
}
|
||||||
|
if (numret > 0)
|
||||||
|
{
|
||||||
|
ret[0].SetFloat(resultheight);
|
||||||
|
}
|
||||||
|
return numret;
|
||||||
|
}
|
||||||
|
|
||||||
double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, double steph, sector_t **resultsec, F3DFloor **resultffloor)
|
double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, double steph, sector_t **resultsec, F3DFloor **resultffloor)
|
||||||
{
|
{
|
||||||
sector_t *sec = this;
|
sector_t *sec = this;
|
||||||
|
|
|
@ -1196,20 +1196,37 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
static TMap<FName, int> customTranslationMap;
|
static TMap<FName, int> customTranslationMap;
|
||||||
|
|
||||||
int R_FindCustomTranslation(const char *name)
|
int R_FindCustomTranslation(FName name)
|
||||||
{
|
{
|
||||||
if (name == nullptr)
|
switch (name)
|
||||||
{
|
{
|
||||||
return -1;
|
case NAME_Ice:
|
||||||
}
|
|
||||||
// Ice is a special case which will remain in its original slot.
|
// Ice is a special case which will remain in its original slot.
|
||||||
if (!stricmp(name, "Ice"))
|
|
||||||
{
|
|
||||||
return TRANSLATION(TRANSLATION_Standard, 7);
|
return TRANSLATION(TRANSLATION_Standard, 7);
|
||||||
}
|
|
||||||
else if (!stricmp(name, "None"))
|
case NAME_None:
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case NAME_RainPillar1:
|
||||||
|
case NAME_RainPillar2:
|
||||||
|
case NAME_RainPillar3:
|
||||||
|
case NAME_RainPillar4:
|
||||||
|
case NAME_RainPillar5:
|
||||||
|
case NAME_RainPillar6:
|
||||||
|
case NAME_RainPillar7:
|
||||||
|
case NAME_RainPillar8:
|
||||||
|
return TRANSLATION(TRANSLATION_RainPillar, name.GetIndex() - NAME_RainPillar1);
|
||||||
|
|
||||||
|
case NAME_Player1:
|
||||||
|
case NAME_Player2:
|
||||||
|
case NAME_Player3:
|
||||||
|
case NAME_Player4:
|
||||||
|
case NAME_Player5:
|
||||||
|
case NAME_Player6:
|
||||||
|
case NAME_Player7:
|
||||||
|
case NAME_Player8:
|
||||||
|
return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1);
|
||||||
|
|
||||||
}
|
}
|
||||||
int *t = customTranslationMap.CheckKey(FName(name, true));
|
int *t = customTranslationMap.CheckKey(FName(name, true));
|
||||||
return (t != nullptr)? *t : -1;
|
return (t != nullptr)? *t : -1;
|
||||||
|
|
|
@ -110,7 +110,7 @@ extern TArray<PalEntry> BloodTranslationColors;
|
||||||
|
|
||||||
int CreateBloodTranslation(PalEntry color);
|
int CreateBloodTranslation(PalEntry color);
|
||||||
|
|
||||||
int R_FindCustomTranslation(const char *name);
|
int R_FindCustomTranslation(FName name);
|
||||||
void R_ParseTrnslate();
|
void R_ParseTrnslate();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7609,7 +7609,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
bool writable;
|
bool writable;
|
||||||
ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested.
|
ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested.
|
||||||
if (ArgList[i]->ValueType != TypeNullPtr)
|
if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr)
|
||||||
{
|
{
|
||||||
ArgList[i]->RequestAddress(ctx, &writable);
|
ArgList[i]->RequestAddress(ctx, &writable);
|
||||||
ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType);
|
ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType);
|
||||||
|
|
|
@ -701,6 +701,10 @@ void InitThingdef()
|
||||||
auto sptr = NewPointer(sstruct);
|
auto sptr = NewPointer(sstruct);
|
||||||
sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget));
|
sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget));
|
||||||
|
|
||||||
|
// expose the glibal Multiplayer variable.
|
||||||
|
PField *multif = new PField("multiplayer", TypeBool, VARF_Native | VARF_ReadOnly | VARF_Static, (intptr_t)&multiplayer);
|
||||||
|
GlobalSymbols.AddSymbol(multif);
|
||||||
|
|
||||||
// set up a variable for the global level data structure
|
// set up a variable for the global level data structure
|
||||||
PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr);
|
PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr);
|
||||||
PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level);
|
PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level);
|
||||||
|
@ -708,8 +712,9 @@ void InitThingdef()
|
||||||
|
|
||||||
// set up a variable for the DEH data
|
// set up a variable for the DEH data
|
||||||
PStruct *dstruct = NewNativeStruct("DehInfo", nullptr);
|
PStruct *dstruct = NewNativeStruct("DehInfo", nullptr);
|
||||||
PField *dehi = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
|
PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
|
||||||
GlobalSymbols.AddSymbol(dehi);
|
|
||||||
|
GlobalSymbols.AddSymbol(dehf);
|
||||||
|
|
||||||
// set up a variable for the global players array.
|
// set up a variable for the global players array.
|
||||||
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
|
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
|
||||||
|
|
|
@ -102,6 +102,7 @@ zscript/heretic/weaponcrossbow.txt
|
||||||
zscript/heretic/weapongauntlets.txt
|
zscript/heretic/weapongauntlets.txt
|
||||||
zscript/heretic/weaponmace.txt
|
zscript/heretic/weaponmace.txt
|
||||||
zscript/heretic/weaponblaster.txt
|
zscript/heretic/weaponblaster.txt
|
||||||
|
zscript/heretic/weaponskullrod.txt
|
||||||
|
|
||||||
zscript/hexen/baseweapons.txt
|
zscript/hexen/baseweapons.txt
|
||||||
zscript/hexen/korax.txt
|
zscript/hexen/korax.txt
|
||||||
|
|
|
@ -5,6 +5,7 @@ class Actor : Thinker native
|
||||||
const ONCEILINGZ = 2147483647.0;
|
const ONCEILINGZ = 2147483647.0;
|
||||||
const FLOATRANDZ = ONCEILINGZ-1;
|
const FLOATRANDZ = ONCEILINGZ-1;
|
||||||
const TELEFRAG_DAMAGE = 1000000;
|
const TELEFRAG_DAMAGE = 1000000;
|
||||||
|
const MinVel = 1./65536;
|
||||||
|
|
||||||
|
|
||||||
// flags are not defined here, the native fields for those get synthesized from the internal tables.
|
// flags are not defined here, the native fields for those get synthesized from the internal tables.
|
||||||
|
@ -263,6 +264,7 @@ class Actor : Thinker native
|
||||||
virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype);
|
virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype);
|
||||||
virtual native bool UseInventory(Inventory item);
|
virtual native bool UseInventory(Inventory item);
|
||||||
|
|
||||||
|
|
||||||
native void AdjustPlayerAngle(FTranslatedLineTarget t);
|
native void AdjustPlayerAngle(FTranslatedLineTarget t);
|
||||||
native static readonly<Actor> GetDefaultByType(class<Actor> cls);
|
native static readonly<Actor> GetDefaultByType(class<Actor> cls);
|
||||||
native static double GetDefaultSpeed(class<Actor> type);
|
native static double GetDefaultSpeed(class<Actor> type);
|
||||||
|
@ -273,6 +275,7 @@ class Actor : Thinker native
|
||||||
native bool GiveBody (int num, int max=0);
|
native bool GiveBody (int num, int max=0);
|
||||||
native bool HitFloor();
|
native bool HitFloor();
|
||||||
native bool isTeammate(Actor other);
|
native bool isTeammate(Actor other);
|
||||||
|
native int PlayerNumber();
|
||||||
|
|
||||||
native void RestoreDamage();
|
native void RestoreDamage();
|
||||||
native int SpawnHealth();
|
native int SpawnHealth();
|
||||||
|
@ -342,6 +345,7 @@ class Actor : Thinker native
|
||||||
// DECORATE compatible functions
|
// DECORATE compatible functions
|
||||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
||||||
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false);
|
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false);
|
||||||
|
native Inventory GiveInventoryType(class<Inventory> itemtype);
|
||||||
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
|
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
|
||||||
native double GetDistance(bool checkz, int ptr = AAPTR_TARGET);
|
native double GetDistance(bool checkz, int ptr = AAPTR_TARGET);
|
||||||
native double GetAngle(int flags, int ptr = AAPTR_DEFAULT);
|
native double GetAngle(int flags, int ptr = AAPTR_DEFAULT);
|
||||||
|
@ -720,7 +724,7 @@ class Actor : Thinker native
|
||||||
native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true);
|
native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true);
|
||||||
native bool A_CopySpriteFrame(int from, int to, int flags = 0);
|
native bool A_CopySpriteFrame(int from, int to, int flags = 0);
|
||||||
native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||||
native void A_SetTranslation(string transname);
|
native void A_SetTranslation(name transname);
|
||||||
|
|
||||||
native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
|
native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
|
||||||
native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);
|
native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);
|
||||||
|
|
|
@ -122,6 +122,12 @@ struct State native
|
||||||
native bool bDehacked;
|
native bool bDehacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sector native
|
struct F3DFloor native
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Sector native
|
||||||
|
{
|
||||||
|
native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -954,3 +954,31 @@ enum EWeaponPos
|
||||||
WEAPONBOTTOM = 128,
|
WEAPONBOTTOM = 128,
|
||||||
WEAPONTOP = 32
|
WEAPONTOP = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ETranslationTable
|
||||||
|
{
|
||||||
|
TRANSLATION_Invalid,
|
||||||
|
TRANSLATION_Players,
|
||||||
|
TRANSLATION_PlayersExtra,
|
||||||
|
TRANSLATION_Standard,
|
||||||
|
TRANSLATION_LevelScripted,
|
||||||
|
TRANSLATION_Decals,
|
||||||
|
TRANSLATION_PlayerCorpses,
|
||||||
|
TRANSLATION_Decorate,
|
||||||
|
TRANSLATION_Blood,
|
||||||
|
TRANSLATION_RainPillar,
|
||||||
|
TRANSLATION_Custom,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EFindFloorCeiling
|
||||||
|
{
|
||||||
|
FFCF_ONLYSPAWNPOS = 1,
|
||||||
|
FFCF_SAMESECTOR = 2,
|
||||||
|
FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes
|
||||||
|
FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z
|
||||||
|
FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.)
|
||||||
|
FFCF_NOFLOOR = 32,
|
||||||
|
FFCF_NOCEILING = 64,
|
||||||
|
FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.)
|
||||||
|
FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals)
|
||||||
|
};
|
||||||
|
|
|
@ -8,206 +8,6 @@ class HereticWeapon : Weapon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Skull (Horn) Rod ---------------------------------------------------------
|
|
||||||
|
|
||||||
class SkullRod : HereticWeapon
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
Weapon.SelectionOrder 200;
|
|
||||||
Weapon.AmmoUse1 1;
|
|
||||||
Weapon.AmmoGive1 50;
|
|
||||||
Weapon.YAdjust 15;
|
|
||||||
Weapon.AmmoType1 "SkullRodAmmo";
|
|
||||||
Weapon.SisterWeapon "SkullRodPowered";
|
|
||||||
Inventory.PickupMessage "$TXT_WPNSKULLROD";
|
|
||||||
Tag "$TAG_SKULLROD";
|
|
||||||
}
|
|
||||||
|
|
||||||
action native void A_FireSkullRodPL1();
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
|
||||||
Spawn:
|
|
||||||
WSKL A -1;
|
|
||||||
Stop;
|
|
||||||
Ready:
|
|
||||||
HROD A 1 A_WeaponReady;
|
|
||||||
Loop;
|
|
||||||
Deselect:
|
|
||||||
HROD A 1 A_Lower;
|
|
||||||
Loop;
|
|
||||||
Select:
|
|
||||||
HROD A 1 A_Raise;
|
|
||||||
Loop;
|
|
||||||
Fire:
|
|
||||||
HROD AB 4 A_FireSkullRodPL1;
|
|
||||||
HROD B 0 A_ReFire;
|
|
||||||
Goto Ready;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SkullRodPowered : SkullRod
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
+WEAPON.POWERED_UP
|
|
||||||
Weapon.AmmoUse1 5;
|
|
||||||
Weapon.AmmoGive1 0;
|
|
||||||
Weapon.SisterWeapon "SkullRod";
|
|
||||||
Tag "$TAG_SKULLRODP";
|
|
||||||
}
|
|
||||||
|
|
||||||
action native void A_FireSkullRodPL2();
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
|
||||||
Fire:
|
|
||||||
HROD C 2;
|
|
||||||
HROD D 3;
|
|
||||||
HROD E 2;
|
|
||||||
HROD F 3;
|
|
||||||
HROD G 4 A_FireSkullRodPL2;
|
|
||||||
HROD F 2;
|
|
||||||
HROD E 3;
|
|
||||||
HROD D 2;
|
|
||||||
HROD C 2 A_ReFire;
|
|
||||||
Goto Ready;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Horn Rod FX 1 ------------------------------------------------------------
|
|
||||||
|
|
||||||
class HornRodFX1 : Actor
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
Radius 12;
|
|
||||||
Height 8;
|
|
||||||
Speed 22;
|
|
||||||
Damage 3;
|
|
||||||
Projectile;
|
|
||||||
+WINDTHRUST
|
|
||||||
-NOBLOCKMAP
|
|
||||||
RenderStyle "Add";
|
|
||||||
SeeSound "weapons/hornrodshoot";
|
|
||||||
DeathSound "weapons/hornrodhit";
|
|
||||||
Obituary "$OB_MPSKULLROD";
|
|
||||||
}
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
|
||||||
Spawn:
|
|
||||||
FX00 AB 6 BRIGHT;
|
|
||||||
Loop;
|
|
||||||
Death:
|
|
||||||
FX00 HI 5 BRIGHT;
|
|
||||||
FX00 JK 4 BRIGHT;
|
|
||||||
FX00 LM 3 BRIGHT;
|
|
||||||
Stop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Horn Rod FX 2 ------------------------------------------------------------
|
|
||||||
|
|
||||||
class HornRodFX2 : Actor
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
Radius 12;
|
|
||||||
Height 8;
|
|
||||||
Speed 22;
|
|
||||||
Damage 10;
|
|
||||||
Health 140;
|
|
||||||
Projectile;
|
|
||||||
RenderStyle "Add";
|
|
||||||
SeeSound "weapons/hornrodpowshoot";
|
|
||||||
DeathSound "weapons/hornrodpowhit";
|
|
||||||
Obituary "$OB_MPPSKULLROD";
|
|
||||||
}
|
|
||||||
|
|
||||||
native void A_AddPlayerRain();
|
|
||||||
native void A_HideInCeiling();
|
|
||||||
native void A_SkullRodStorm();
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
|
||||||
Spawn:
|
|
||||||
FX00 C 3 BRIGHT;
|
|
||||||
FX00 D 3 BRIGHT A_SeekerMissile(10, 30);
|
|
||||||
FX00 E 3 BRIGHT;
|
|
||||||
FX00 F 3 BRIGHT A_SeekerMissile(10, 30);
|
|
||||||
Loop;
|
|
||||||
Death:
|
|
||||||
FX00 H 5 BRIGHT A_AddPlayerRain;
|
|
||||||
FX00 I 5 BRIGHT;
|
|
||||||
FX00 J 4 BRIGHT;
|
|
||||||
FX00 KLM 3 BRIGHT;
|
|
||||||
FX00 G 1 A_HideInCeiling;
|
|
||||||
FX00 G 1 A_SkullRodStorm;
|
|
||||||
Wait;
|
|
||||||
}
|
|
||||||
|
|
||||||
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
|
|
||||||
{
|
|
||||||
Sorcerer2 s2 = Sorcerer2(target);
|
|
||||||
if (s2 != null && random[HornRodFX2]() < 96)
|
|
||||||
{ // D'Sparil teleports away
|
|
||||||
s2.DSparilTeleport ();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rain pillar 1 ------------------------------------------------------------
|
|
||||||
|
|
||||||
class RainPillar : Actor native
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
Radius 5;
|
|
||||||
Height 12;
|
|
||||||
Speed 12;
|
|
||||||
Damage 5;
|
|
||||||
Mass 5;
|
|
||||||
Projectile;
|
|
||||||
-ACTIVATEPCROSS
|
|
||||||
-ACTIVATEIMPACT
|
|
||||||
RenderStyle "Add";
|
|
||||||
Obituary "$OB_MPPSKULLROD";
|
|
||||||
}
|
|
||||||
|
|
||||||
native void A_RainImpact();
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
|
||||||
Spawn:
|
|
||||||
FX22 A -1 BRIGHT;
|
|
||||||
Stop;
|
|
||||||
Death:
|
|
||||||
FX22 B 4 BRIGHT A_RainImpact;
|
|
||||||
FX22 CDEF 4 BRIGHT;
|
|
||||||
Stop;
|
|
||||||
NotFloor:
|
|
||||||
FX22 GHI 4 BRIGHT;
|
|
||||||
Stop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rain tracker "inventory" item --------------------------------------------
|
|
||||||
|
|
||||||
class RainTracker : Inventory native
|
|
||||||
{
|
|
||||||
Default
|
|
||||||
{
|
|
||||||
+INVENTORY.UNDROPPABLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Phoenix Rod --------------------------------------------------------------
|
// Phoenix Rod --------------------------------------------------------------
|
||||||
|
|
||||||
class PhoenixRod : Weapon native
|
class PhoenixRod : Weapon native
|
||||||
|
|
425
wadsrc/static/zscript/heretic/weaponskullrod.txt
Normal file
425
wadsrc/static/zscript/heretic/weaponskullrod.txt
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
// Skull (Horn) Rod ---------------------------------------------------------
|
||||||
|
|
||||||
|
class SkullRod : HereticWeapon
|
||||||
|
{
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
Weapon.SelectionOrder 200;
|
||||||
|
Weapon.AmmoUse1 1;
|
||||||
|
Weapon.AmmoGive1 50;
|
||||||
|
Weapon.YAdjust 15;
|
||||||
|
Weapon.AmmoType1 "SkullRodAmmo";
|
||||||
|
Weapon.SisterWeapon "SkullRodPowered";
|
||||||
|
Inventory.PickupMessage "$TXT_WPNSKULLROD";
|
||||||
|
Tag "$TAG_SKULLROD";
|
||||||
|
}
|
||||||
|
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
WSKL A -1;
|
||||||
|
Stop;
|
||||||
|
Ready:
|
||||||
|
HROD A 1 A_WeaponReady;
|
||||||
|
Loop;
|
||||||
|
Deselect:
|
||||||
|
HROD A 1 A_Lower;
|
||||||
|
Loop;
|
||||||
|
Select:
|
||||||
|
HROD A 1 A_Raise;
|
||||||
|
Loop;
|
||||||
|
Fire:
|
||||||
|
HROD AB 4 A_FireSkullRodPL1;
|
||||||
|
HROD B 0 A_ReFire;
|
||||||
|
Goto Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_FireSkullRodPL1
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
action void A_FireSkullRodPL1()
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Weapon weapon = player.ReadyWeapon;
|
||||||
|
if (weapon != null)
|
||||||
|
{
|
||||||
|
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Actor mo = SpawnPlayerMissile ("HornRodFX1");
|
||||||
|
// Randomize the first frame
|
||||||
|
if (mo && random[FireSkullRod]() > 128)
|
||||||
|
{
|
||||||
|
mo.SetState (mo.CurState.NextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SkullRodPowered : SkullRod
|
||||||
|
{
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
+WEAPON.POWERED_UP
|
||||||
|
Weapon.AmmoUse1 5;
|
||||||
|
Weapon.AmmoGive1 0;
|
||||||
|
Weapon.SisterWeapon "SkullRod";
|
||||||
|
Tag "$TAG_SKULLRODP";
|
||||||
|
}
|
||||||
|
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Fire:
|
||||||
|
HROD C 2;
|
||||||
|
HROD D 3;
|
||||||
|
HROD E 2;
|
||||||
|
HROD F 3;
|
||||||
|
HROD G 4 A_FireSkullRodPL2;
|
||||||
|
HROD F 2;
|
||||||
|
HROD E 3;
|
||||||
|
HROD D 2;
|
||||||
|
HROD C 2 A_ReFire;
|
||||||
|
Goto Ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_FireSkullRodPL2
|
||||||
|
//
|
||||||
|
// The special2 field holds the player number that shot the rain missile.
|
||||||
|
// The special1 field holds the id of the rain sound.
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
action void A_FireSkullRodPL2()
|
||||||
|
{
|
||||||
|
FTranslatedLineTarget t;
|
||||||
|
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Weapon weapon = player.ReadyWeapon;
|
||||||
|
if (weapon != null)
|
||||||
|
{
|
||||||
|
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Use MissileActor instead of the first return value from P_SpawnPlayerMissile
|
||||||
|
// because we need to give info to it, even if it exploded immediately.
|
||||||
|
Actor mo, MissileActor;
|
||||||
|
[mo, MissileActor] = SpawnPlayerMissile ("HornRodFX2", angle, pLineTarget: t);
|
||||||
|
if (MissileActor != null)
|
||||||
|
{
|
||||||
|
if (t.linetarget && !t.unlinked)
|
||||||
|
{
|
||||||
|
MissileActor.tracer = t.linetarget;
|
||||||
|
}
|
||||||
|
MissileActor.A_PlaySound ("weapons/hornrodpowshoot", CHAN_WEAPON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horn Rod FX 1 ------------------------------------------------------------
|
||||||
|
|
||||||
|
class HornRodFX1 : Actor
|
||||||
|
{
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
Radius 12;
|
||||||
|
Height 8;
|
||||||
|
Speed 22;
|
||||||
|
Damage 3;
|
||||||
|
Projectile;
|
||||||
|
+WINDTHRUST
|
||||||
|
-NOBLOCKMAP
|
||||||
|
RenderStyle "Add";
|
||||||
|
SeeSound "weapons/hornrodshoot";
|
||||||
|
DeathSound "weapons/hornrodhit";
|
||||||
|
Obituary "$OB_MPSKULLROD";
|
||||||
|
}
|
||||||
|
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
FX00 AB 6 BRIGHT;
|
||||||
|
Loop;
|
||||||
|
Death:
|
||||||
|
FX00 HI 5 BRIGHT;
|
||||||
|
FX00 JK 4 BRIGHT;
|
||||||
|
FX00 LM 3 BRIGHT;
|
||||||
|
Stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Horn Rod FX 2 ------------------------------------------------------------
|
||||||
|
|
||||||
|
class HornRodFX2 : Actor
|
||||||
|
{
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
Radius 12;
|
||||||
|
Height 8;
|
||||||
|
Speed 22;
|
||||||
|
Damage 10;
|
||||||
|
Health 140;
|
||||||
|
Projectile;
|
||||||
|
RenderStyle "Add";
|
||||||
|
SeeSound "weapons/hornrodpowshoot";
|
||||||
|
DeathSound "weapons/hornrodpowhit";
|
||||||
|
Obituary "$OB_MPPSKULLROD";
|
||||||
|
}
|
||||||
|
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
FX00 C 3 BRIGHT;
|
||||||
|
FX00 D 3 BRIGHT A_SeekerMissile(10, 30);
|
||||||
|
FX00 E 3 BRIGHT;
|
||||||
|
FX00 F 3 BRIGHT A_SeekerMissile(10, 30);
|
||||||
|
Loop;
|
||||||
|
Death:
|
||||||
|
FX00 H 5 BRIGHT A_AddPlayerRain;
|
||||||
|
FX00 I 5 BRIGHT;
|
||||||
|
FX00 J 4 BRIGHT;
|
||||||
|
FX00 KLM 3 BRIGHT;
|
||||||
|
FX00 G 1 A_HideInCeiling;
|
||||||
|
FX00 G 1 A_SkullRodStorm;
|
||||||
|
Wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
|
||||||
|
{
|
||||||
|
Sorcerer2 s2 = Sorcerer2(target);
|
||||||
|
if (s2 != null && random[HornRodFX2]() < 96)
|
||||||
|
{ // D'Sparil teleports away
|
||||||
|
s2.DSparilTeleport ();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_AddPlayerRain
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void A_AddPlayerRain()
|
||||||
|
{
|
||||||
|
RainTracker tracker;
|
||||||
|
|
||||||
|
if (target == null || target.health <= 0)
|
||||||
|
{ // Shooter is dead or nonexistant
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker = RainTracker(target.FindInventory("RainTracker"));
|
||||||
|
|
||||||
|
// They player is only allowed two rainstorms at a time. Shooting more
|
||||||
|
// than that will cause the oldest one to terminate.
|
||||||
|
if (tracker != null)
|
||||||
|
{
|
||||||
|
if (tracker.Rain1 && tracker.Rain2)
|
||||||
|
{ // Terminate an active rain
|
||||||
|
if (tracker.Rain1.health < tracker.Rain2.health)
|
||||||
|
{
|
||||||
|
if (tracker.Rain1.health > 16)
|
||||||
|
{
|
||||||
|
tracker.Rain1.health = 16;
|
||||||
|
}
|
||||||
|
tracker.Rain1 = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tracker.Rain2.health > 16)
|
||||||
|
{
|
||||||
|
tracker.Rain2.health = 16;
|
||||||
|
}
|
||||||
|
tracker.Rain2 = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tracker = RainTracker(target.GiveInventoryType("RainTracker"));
|
||||||
|
}
|
||||||
|
// Add rain mobj to list
|
||||||
|
if (tracker.Rain1)
|
||||||
|
{
|
||||||
|
tracker.Rain2 = self;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tracker.Rain1 = self;
|
||||||
|
}
|
||||||
|
ActiveSound = "misc/rain";
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_HideInCeiling
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void A_HideInCeiling()
|
||||||
|
{
|
||||||
|
// This no longer hides in the ceiling. It just makes the actor invisible and keeps it in place.
|
||||||
|
// We need its actual position to determine the correct ceiling height in A_SkullRodStorm.
|
||||||
|
bInvisible = true;
|
||||||
|
bSolid = false;
|
||||||
|
bMissile = false;
|
||||||
|
Vel = (0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_SkullRodStorm
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void A_SkullRodStorm()
|
||||||
|
{
|
||||||
|
static const Name translations[] =
|
||||||
|
{
|
||||||
|
"RainPillar1", "RainPillar2", "RainPillar3", "RainPillar4",
|
||||||
|
"RainPillar5", "RainPillar6", "RainPillar7", "RainPillar8"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (health-- == 0)
|
||||||
|
{
|
||||||
|
A_StopSound (CHAN_BODY);
|
||||||
|
if (target == null)
|
||||||
|
{ // Player left the game
|
||||||
|
Destroy ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RainTracker tracker = RainTracker(target.FindInventory("RainTracker"));
|
||||||
|
if (tracker != null)
|
||||||
|
{
|
||||||
|
if (tracker.Rain1 == self)
|
||||||
|
{
|
||||||
|
tracker.Rain1 = null;
|
||||||
|
}
|
||||||
|
else if (tracker.Rain2 == self)
|
||||||
|
{
|
||||||
|
tracker.Rain2 = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Destroy ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Random[SkullRodStorm]() < 25)
|
||||||
|
{ // Fudge rain frequency
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double xo = ((Random[SkullRodStorm]() & 127) - 64);
|
||||||
|
double yo = ((Random[SkullRodStorm]() & 127) - 64);
|
||||||
|
Vector3 spawnpos = Vec2OffsetZ(xo, yo, pos.z);
|
||||||
|
Actor mo = Spawn("RainPillar", spawnpos, ALLOW_REPLACE);
|
||||||
|
if (!mo) return;
|
||||||
|
|
||||||
|
// Find the ceiling above the spawn location. This may come from 3D floors but will not reach through portals.
|
||||||
|
// (should probably be fixed for portals, too.)
|
||||||
|
double newz = mo.CurSector.NextHighestCeilingAt(mo.pos.x, mo.pos.y, mo.pos.z, mo.pos.z, FFCF_NOPORTALS) - mo.height;
|
||||||
|
mo.SetZ(newz);
|
||||||
|
|
||||||
|
if (multiplayer && target.player)
|
||||||
|
{
|
||||||
|
mo.A_SetTranslation(translations[target.PlayerNumber()]);
|
||||||
|
}
|
||||||
|
mo.target = target;
|
||||||
|
mo.Vel.X = MinVel; // Force collision detection
|
||||||
|
mo.Vel.Z = -mo.Speed;
|
||||||
|
mo.CheckMissileSpawn (radius);
|
||||||
|
if (ActiveSound > 0) A_PlaySound(ActiveSound, CHAN_BODY, 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rain pillar 1 ------------------------------------------------------------
|
||||||
|
|
||||||
|
class RainPillar : Actor
|
||||||
|
{
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
Radius 5;
|
||||||
|
Height 12;
|
||||||
|
Speed 12;
|
||||||
|
Damage 5;
|
||||||
|
Mass 5;
|
||||||
|
Projectile;
|
||||||
|
-ACTIVATEPCROSS
|
||||||
|
-ACTIVATEIMPACT
|
||||||
|
RenderStyle "Add";
|
||||||
|
Obituary "$OB_MPPSKULLROD";
|
||||||
|
}
|
||||||
|
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
FX22 A -1 BRIGHT;
|
||||||
|
Stop;
|
||||||
|
Death:
|
||||||
|
FX22 B 4 BRIGHT A_RainImpact;
|
||||||
|
FX22 CDEF 4 BRIGHT;
|
||||||
|
Stop;
|
||||||
|
NotFloor:
|
||||||
|
FX22 GHI 4 BRIGHT;
|
||||||
|
Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// PROC A_RainImpact
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void A_RainImpact()
|
||||||
|
{
|
||||||
|
if (pos.z > floorz)
|
||||||
|
{
|
||||||
|
SetStateLabel("NotFloor");
|
||||||
|
}
|
||||||
|
else if (random[RainImpact]() < 40)
|
||||||
|
{
|
||||||
|
HitFloor ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rain pillar 1 ------------------------------------------------------------
|
||||||
|
|
||||||
|
int DoSpecialDamage (Actor target, int damage, Name damagetype)
|
||||||
|
{
|
||||||
|
if (target.bBoss)
|
||||||
|
{ // Decrease damage for bosses
|
||||||
|
damage = random[RainDamage](1, 8);
|
||||||
|
}
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rain tracker "inventory" item --------------------------------------------
|
||||||
|
|
||||||
|
class RainTracker : Inventory
|
||||||
|
{
|
||||||
|
Actor Rain1, Rain2;
|
||||||
|
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
+INVENTORY.UNDROPPABLE
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue