- scriptified Hexen's Banishment Device.

This commit is contained in:
Christoph Oelckers 2016-11-28 01:30:36 +01:00
parent ebd2c27e0a
commit d4427e696d
6 changed files with 149 additions and 210 deletions

View file

@ -861,7 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES
sc_man_scanner.re sc_man_scanner.re
g_hexen/a_heresiarch.cpp g_hexen/a_heresiarch.cpp
g_hexen/a_spike.cpp g_hexen/a_spike.cpp
g_hexen/a_teleportother.cpp
g_strife/a_acolyte.cpp g_strife/a_acolyte.cpp
g_strife/a_alienspectres.cpp g_strife/a_alienspectres.cpp
g_strife/a_coin.cpp g_strife/a_coin.cpp

View file

@ -1540,15 +1540,28 @@ DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
unsigned int selections = deathmatchstarts.Size(); unsigned int selections = deathmatchstarts.Size();
unsigned int i = pr_dmspawn() % selections; DVector3 pos;
int angle;
if (selections == 0)
{
angle = INT_MAX;
pos = DVector3(0, 0, 0);
}
else
{
unsigned int i = pr_dmspawn() % selections;
angle = deathmatchstarts[i].angle;
pos = deathmatchstarts[i].pos;
}
if (numret > 1) if (numret > 1)
{ {
ret[1].SetInt(deathmatchstarts[i].angle); ret[1].SetInt(angle);
numret = 2; numret = 2;
} }
if (numret > 0) if (numret > 0)
{ {
ret[0].SetVector(deathmatchstarts[i].pos); ret[0].SetVector(pos);
} }
return numret; return numret;
} }

View file

@ -26,4 +26,3 @@
// Include all the Hexen stuff here to reduce compile time // Include all the Hexen stuff here to reduce compile time
#include "a_heresiarch.cpp" #include "a_heresiarch.cpp"
#include "a_spike.cpp" #include "a_spike.cpp"
#include "a_teleportother.cpp"

View file

@ -1,198 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_lnspec.h"
#include "m_random.h"
#include "vm.h"
#include "g_level.h"
#include "doomstat.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_CLASS (AArtiTeleportOther, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS(AArtiTeleportOther, false, false)
// Teleport Other FX --------------------------------------------------------
class ATelOtherFX1 : public AActor
{
DECLARE_CLASS (ATelOtherFX1, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(ATelOtherFX1, false, false)
static void TeloSpawn (AActor *source, const char *type)
{
AActor *fx;
fx = Spawn (type, source->Pos(), ALLOW_REPLACE);
if (fx)
{
fx->special1 = TELEPORT_LIFE; // Lifetime countdown
fx->Angles.Yaw = source->Angles.Yaw;
fx->target = source->target;
fx->Vel = source->Vel / 2;
}
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnA)
{
PARAM_SELF_PROLOGUE(AActor);
TeloSpawn (self, "TelOtherFX2");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnB)
{
PARAM_SELF_PROLOGUE(AActor);
TeloSpawn (self, "TelOtherFX3");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnC)
{
PARAM_SELF_PROLOGUE(AActor);
TeloSpawn (self, "TelOtherFX4");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnD)
{
PARAM_SELF_PROLOGUE(AActor);
TeloSpawn (self, "TelOtherFX5");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CheckTeleRing)
{
PARAM_SELF_PROLOGUE(AActor);
if (self->special1-- <= 0)
{
self->SetState (self->FindState(NAME_Death));
}
return 0;
}
//===========================================================================
//
// 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, FName damagetype)
{
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 ();
P_ExecuteSpecial(target->special, NULL, level.flags & LEVEL_ACTOWNSPECIAL
? target : (AActor *)(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)
{
DVector3 dest;
FPlayerStart *start = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK);
dest = start->pos;
dest.Z = ONFLOORZ;
P_Teleport (victim, dest, (double)start->angle, TELF_SOURCEFOG | TELF_DESTFOG);
}
//===========================================================================
//
// P_TeleportToDeathmatchStarts
//
//===========================================================================
void P_TeleportToDeathmatchStarts (AActor *victim)
{
unsigned int i, selections;
DVector3 dest;
selections = deathmatchstarts.Size ();
if (selections > 0)
{
i = pr_teledm() % selections;
dest = deathmatchstarts[i].pos;
dest.Z = ONFLOORZ;
P_Teleport (victim, dest, (double)deathmatchstarts[i].angle, TELF_SOURCEFOG | TELF_DESTFOG);
}
else
{
P_TeleportToPlayerStarts (victim);
}
}

View file

@ -267,3 +267,9 @@ struct TerrainDef native
native double Friction; native double Friction;
native double MoveFactor; native double MoveFactor;
}; };
enum EPickStart
{
PPS_FORCERANDOM = 1,
PPS_NOBLOCKINGCHECK = 2,
}

View file

@ -1,7 +1,7 @@
// Teleport Other Artifact -------------------------------------------------- // Teleport Other Artifact --------------------------------------------------
class ArtiTeleportOther : Inventory native class ArtiTeleportOther : Inventory
{ {
Default Default
{ {
@ -22,13 +22,29 @@ class ArtiTeleportOther : Inventory native
TELO ABCD 5; TELO ABCD 5;
Loop; Loop;
} }
//===========================================================================
//
// Activate Teleport Other
//
//===========================================================================
override bool Use (bool pickup)
{
Owner.SpawnPlayerMissile ("TelOtherFX1");
return true;
}
} }
// Teleport Other FX -------------------------------------------------------- // Teleport Other FX --------------------------------------------------------
class TelOtherFX1 : Actor native class TelOtherFX1 : Actor
{ {
const TELEPORT_LIFE = 1;
Default Default
{ {
Damage 10001; Damage 10001;
@ -41,11 +57,6 @@ class TelOtherFX1 : Actor native
Speed 20; Speed 20;
} }
native void A_TeloSpawnA();
native void A_TeloSpawnB();
native void A_TeloSpawnC();
native void A_TeloSpawnD();
native void A_CheckTeleRing ();
States States
{ {
@ -63,6 +74,115 @@ class TelOtherFX1 : Actor native
TRNG E 3 Bright; TRNG E 3 Bright;
Stop; Stop;
} }
private void TeloSpawn (class<Actor> type)
{
Actor fx = Spawn (type, pos, ALLOW_REPLACE);
if (fx)
{
fx.special1 = TELEPORT_LIFE; // Lifetime countdown
fx.angle = angle;
fx.target = target;
fx.Vel = Vel / 2;
}
}
void A_TeloSpawnA()
{
TeloSpawn ("TelOtherFX2");
}
void A_TeloSpawnB()
{
TeloSpawn ("TelOtherFX3");
}
void A_TeloSpawnC()
{
TeloSpawn ("TelOtherFX4");
}
void A_TeloSpawnD()
{
TeloSpawn ("TelOtherFX5");
}
void A_CheckTeleRing ()
{
if (self.special1-- <= 0)
{
self.SetStateLabel("Death");
}
}
//===========================================================================
//
// Perform Teleport Other
//
//===========================================================================
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
{
if ((target.bIsMonster || target.player != NULL) &&
!target.bBoss && !target.bNoTeleOther)
{
if (target.player)
{
if (deathmatch)
P_TeleportToDeathmatchStarts (target);
else
P_TeleportToPlayerStarts (target);
}
else
{
// If death action, run it upon teleport
if (target.bIsMonster && target.special)
{
target.RemoveFromHash ();
Actor caller = level.ActOwnSpecial? target : self.target;
caller.A_CallSpecial(target.special, 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
//
//===========================================================================
private static void P_TeleportToPlayerStarts (Actor victim)
{
Vector3 dest;
double destAngle;
[dest, destAngle] = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK);
dest.Z = ONFLOORZ;
victim.Teleport ((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG);
}
//===========================================================================
//
// P_TeleportToDeathmatchStarts
//
//===========================================================================
private void P_TeleportToDeathmatchStarts (Actor victim)
{
Vector3 dest;
double destAngle;
[dest, destAngle] = G_PickDeathmatchStart();
if (destAngle < 65536) victim.Teleport((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG);
else P_TeleportToPlayerStarts(victim);
}
} }