mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-08 14:01:32 +00:00
1502215009
so now larger scales than 4 can be done. SVN r381 (trunk)
312 lines
9.6 KiB
C++
312 lines
9.6 KiB
C++
#include "info.h"
|
|
#include "a_pickups.h"
|
|
#include "a_artifacts.h"
|
|
#include "gstrings.h"
|
|
#include "p_local.h"
|
|
#include "p_enemy.h"
|
|
#include "s_sound.h"
|
|
#include "p_lnspec.h"
|
|
#include "m_random.h"
|
|
|
|
#define TELEPORT_LIFE 1
|
|
|
|
static FRandom pr_telestarts ("TeleStarts");
|
|
static FRandom pr_teledm ("TeleDM");
|
|
|
|
void A_TeloSpawnA (AActor *);
|
|
void A_TeloSpawnB (AActor *);
|
|
void A_TeloSpawnC (AActor *);
|
|
void A_TeloSpawnD (AActor *);
|
|
void A_CheckTeleRing (AActor *);
|
|
void P_TeleportToPlayerStarts (AActor *victim);
|
|
void P_TeleportToDeathmatchStarts (AActor *victim);
|
|
|
|
// Teleport Other Artifact --------------------------------------------------
|
|
|
|
class AArtiTeleportOther : public AInventory
|
|
{
|
|
DECLARE_ACTOR (AArtiTeleportOther, AInventory)
|
|
public:
|
|
bool Use (bool pickup);
|
|
};
|
|
|
|
FState AArtiTeleportOther::States[] =
|
|
{
|
|
#define S_ARTI_TELOTHER1 0
|
|
S_NORMAL (TELO, 'A', 5, NULL , &States[S_ARTI_TELOTHER1+1]),
|
|
S_NORMAL (TELO, 'B', 5, NULL , &States[S_ARTI_TELOTHER1+2]),
|
|
S_NORMAL (TELO, 'C', 5, NULL , &States[S_ARTI_TELOTHER1+3]),
|
|
S_NORMAL (TELO, 'D', 5, NULL , &States[S_ARTI_TELOTHER1]),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AArtiTeleportOther, Hexen, 10040, 17)
|
|
PROP_Flags (MF_SPECIAL|MF_COUNTITEM)
|
|
PROP_Flags2 (MF2_FLOATBOB)
|
|
PROP_SpawnState (S_ARTI_TELOTHER1)
|
|
PROP_Inventory_DefMaxAmount
|
|
PROP_Inventory_FlagsSet (IF_INVBAR|IF_PICKUPFLASH|IF_FANCYPICKUPSOUND)
|
|
PROP_Inventory_Icon ("ARTITELO")
|
|
PROP_Inventory_PickupSound ("misc/p_pkup")
|
|
PROP_Inventory_PickupMessage("$TXT_ARTITELEPORTOTHER")
|
|
END_DEFAULTS
|
|
|
|
// Teleport Other FX --------------------------------------------------------
|
|
|
|
class ATelOtherFX1 : public AActor
|
|
{
|
|
DECLARE_ACTOR (ATelOtherFX1, AActor)
|
|
public:
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
};
|
|
|
|
FState ATelOtherFX1::States[] =
|
|
{
|
|
#define S_TELO_FX1 0
|
|
S_BRIGHT (TRNG, 'E', 5, NULL , &States[S_TELO_FX1+1]),
|
|
S_BRIGHT (TRNG, 'D', 4, NULL , &States[S_TELO_FX1+2]),
|
|
S_BRIGHT (TRNG, 'C', 3, A_TeloSpawnC , &States[S_TELO_FX1+3]),
|
|
S_BRIGHT (TRNG, 'B', 3, A_TeloSpawnB , &States[S_TELO_FX1+4]),
|
|
S_BRIGHT (TRNG, 'A', 3, A_TeloSpawnA , &States[S_TELO_FX1+5]),
|
|
S_BRIGHT (TRNG, 'B', 3, A_TeloSpawnB , &States[S_TELO_FX1+6]),
|
|
S_BRIGHT (TRNG, 'C', 3, A_TeloSpawnC , &States[S_TELO_FX1+7]),
|
|
S_BRIGHT (TRNG, 'D', 3, A_TeloSpawnD , &States[S_TELO_FX1+2]),
|
|
|
|
#define S_TELO_FX_DONE (S_TELO_FX1+8)
|
|
S_BRIGHT (TRNG, 'E', 3, NULL , NULL),
|
|
|
|
#define S_TELO_FX2 (S_TELO_FX_DONE+1)
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX2+1]),
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX2+2]),
|
|
S_BRIGHT (TRNG, 'D', 4, NULL , &States[S_TELO_FX2+3]),
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX2+4]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX2+5]),
|
|
S_BRIGHT (TRNG, 'A', 4, A_CheckTeleRing , &States[S_TELO_FX2+0]),
|
|
|
|
#define S_TELO_FX3 (S_TELO_FX2+6)
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX3+1]),
|
|
S_BRIGHT (TRNG, 'D', 4, NULL , &States[S_TELO_FX3+2]),
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX3+3]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX3+4]),
|
|
S_BRIGHT (TRNG, 'A', 4, NULL , &States[S_TELO_FX3+5]),
|
|
S_BRIGHT (TRNG, 'B', 4, A_CheckTeleRing , &States[S_TELO_FX3+0]),
|
|
|
|
#define S_TELO_FX4 (S_TELO_FX3+6)
|
|
S_BRIGHT (TRNG, 'D', 4, NULL , &States[S_TELO_FX4+1]),
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX4+2]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX4+3]),
|
|
S_BRIGHT (TRNG, 'A', 4, NULL , &States[S_TELO_FX4+4]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX4+5]),
|
|
S_BRIGHT (TRNG, 'C', 4, A_CheckTeleRing , &States[S_TELO_FX4+0]),
|
|
|
|
#define S_TELO_FX5 (S_TELO_FX4+6)
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX5+1]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX5+2]),
|
|
S_BRIGHT (TRNG, 'A', 4, NULL , &States[S_TELO_FX5+3]),
|
|
S_BRIGHT (TRNG, 'B', 4, NULL , &States[S_TELO_FX5+4]),
|
|
S_BRIGHT (TRNG, 'C', 4, NULL , &States[S_TELO_FX5+5]),
|
|
S_BRIGHT (TRNG, 'D', 4, A_CheckTeleRing , &States[S_TELO_FX5+0])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ATelOtherFX1, Any, -1, 0)
|
|
PROP_DamageLong (10001)
|
|
PROP_Flags (MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP)
|
|
PROP_Flags2 (MF2_NOTELEPORT)
|
|
PROP_Flags3 (MF3_BLOODLESSIMPACT)
|
|
PROP_RadiusFixed (16)
|
|
PROP_HeightFixed (16)
|
|
PROP_SpeedFixed (20)
|
|
|
|
PROP_SpawnState (S_TELO_FX1)
|
|
PROP_DeathState (S_TELO_FX_DONE)
|
|
END_DEFAULTS
|
|
|
|
class ATelOtherFX2 : public ATelOtherFX1
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ATelOtherFX2, ATelOtherFX1)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ATelOtherFX2, Any, -1, 0)
|
|
PROP_SpeedFixed (16)
|
|
PROP_SpawnState (S_TELO_FX2)
|
|
END_DEFAULTS
|
|
|
|
class ATelOtherFX3 : public ATelOtherFX1
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ATelOtherFX3, ATelOtherFX1)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ATelOtherFX3, Any, -1, 0)
|
|
PROP_SpeedFixed (16)
|
|
PROP_SpawnState (S_TELO_FX3)
|
|
END_DEFAULTS
|
|
|
|
class ATelOtherFX4 : public ATelOtherFX1
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ATelOtherFX4, ATelOtherFX1)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ATelOtherFX4, Any, -1, 0)
|
|
PROP_SpeedFixed (16)
|
|
PROP_SpawnState (S_TELO_FX4)
|
|
END_DEFAULTS
|
|
|
|
class ATelOtherFX5 : public ATelOtherFX1
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ATelOtherFX5, ATelOtherFX1)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ATelOtherFX5, Any, -1, 0)
|
|
PROP_SpeedFixed (16)
|
|
PROP_SpawnState (S_TELO_FX5)
|
|
END_DEFAULTS
|
|
|
|
static void TeloSpawn (AActor *source, const PClass *type)
|
|
{
|
|
AActor *fx;
|
|
|
|
fx = Spawn (type, source->x, source->y, source->z, ALLOW_REPLACE);
|
|
if (fx)
|
|
{
|
|
fx->special1 = TELEPORT_LIFE; // Lifetime countdown
|
|
fx->angle = source->angle;
|
|
fx->target = source->target;
|
|
fx->momx = source->momx >> 1;
|
|
fx->momy = source->momy >> 1;
|
|
fx->momz = source->momz >> 1;
|
|
}
|
|
}
|
|
|
|
void A_TeloSpawnA (AActor *actor)
|
|
{
|
|
TeloSpawn (actor, RUNTIME_CLASS(ATelOtherFX2));
|
|
}
|
|
|
|
void A_TeloSpawnB (AActor *actor)
|
|
{
|
|
TeloSpawn (actor, RUNTIME_CLASS(ATelOtherFX3));
|
|
}
|
|
|
|
void A_TeloSpawnC (AActor *actor)
|
|
{
|
|
TeloSpawn (actor, RUNTIME_CLASS(ATelOtherFX4));
|
|
}
|
|
|
|
void A_TeloSpawnD (AActor *actor)
|
|
{
|
|
TeloSpawn (actor, RUNTIME_CLASS(ATelOtherFX5));
|
|
}
|
|
|
|
void A_CheckTeleRing (AActor *actor)
|
|
{
|
|
if (actor->special1-- <= 0)
|
|
{
|
|
actor->SetState (actor->FindState(NAME_Death));
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Activate Teleport Other
|
|
//
|
|
//===========================================================================
|
|
|
|
bool AArtiTeleportOther::Use (bool pickup)
|
|
{
|
|
AActor *mo;
|
|
|
|
mo = P_SpawnPlayerMissile (Owner, RUNTIME_CLASS(ATelOtherFX1));
|
|
if (mo)
|
|
{
|
|
mo->target = Owner;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Perform Teleport Other
|
|
//
|
|
//===========================================================================
|
|
|
|
int ATelOtherFX1::DoSpecialDamage (AActor *target, int damage)
|
|
{
|
|
if ((target->flags3 & MF3_ISMONSTER || target->player != NULL) &&
|
|
!(target->flags2 & MF2_BOSS) &&
|
|
!(target->flags3 & MF3_NOTELEOTHER))
|
|
{
|
|
if (target->player)
|
|
{
|
|
if (deathmatch)
|
|
P_TeleportToDeathmatchStarts (target);
|
|
else
|
|
P_TeleportToPlayerStarts (target);
|
|
}
|
|
else
|
|
{
|
|
// If death action, run it upon teleport
|
|
if (target->flags3 & MF3_ISMONSTER && target->special)
|
|
{
|
|
target->RemoveFromHash ();
|
|
LineSpecials[target->special] (NULL, level.flags & LEVEL_ACTOWNSPECIAL
|
|
? target : this->target, false, target->args[0], target->args[1],
|
|
target->args[2], target->args[3], target->args[4]);
|
|
target->special = 0;
|
|
}
|
|
|
|
// Send all monsters to deathmatch spots
|
|
P_TeleportToDeathmatchStarts (target);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// P_TeleportToPlayerStarts
|
|
//
|
|
//===========================================================================
|
|
|
|
void P_TeleportToPlayerStarts (AActor *victim)
|
|
{
|
|
int i,selections=0;
|
|
fixed_t destX,destY;
|
|
angle_t destAngle;
|
|
|
|
for (i = 0; i < MAXPLAYERS;i++)
|
|
{
|
|
if (!playeringame[i]) continue;
|
|
selections++;
|
|
}
|
|
i = pr_telestarts() % selections;
|
|
destX = playerstarts[i].x << FRACBITS;
|
|
destY = playerstarts[i].y << FRACBITS;
|
|
destAngle = ANG45 * (playerstarts[i].angle/45);
|
|
P_Teleport (victim, destX, destY, ONFLOORZ, destAngle, true, true, false);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// P_TeleportToDeathmatchStarts
|
|
//
|
|
//===========================================================================
|
|
|
|
void P_TeleportToDeathmatchStarts (AActor *victim)
|
|
{
|
|
unsigned int i, selections;
|
|
fixed_t destX,destY;
|
|
angle_t destAngle;
|
|
|
|
selections = deathmatchstarts.Size ();
|
|
if (selections > 0)
|
|
{
|
|
i = pr_teledm() % selections;
|
|
destX = deathmatchstarts[i].x << FRACBITS;
|
|
destY = deathmatchstarts[i].y << FRACBITS;
|
|
destAngle = ANG45 * (deathmatchstarts[i].angle/45);
|
|
P_Teleport (victim, destX, destY, ONFLOORZ, destAngle, true, true, false);
|
|
}
|
|
else
|
|
{
|
|
P_TeleportToPlayerStarts (victim);
|
|
}
|
|
}
|