- scriptified Oracle, Programmer and Rebels.

This commit is contained in:
Christoph Oelckers 2016-11-28 19:42:26 +01:00
parent 119bcb924d
commit 360cbfba2a
13 changed files with 233 additions and 314 deletions

View File

@ -861,9 +861,6 @@ set( NOT_COMPILED_SOURCE_FILES
sc_man_scanner.re
g_hexen/a_heresiarch.cpp
g_hexen/a_spike.cpp
g_strife/a_oracle.cpp
g_strife/a_programmer.cpp
g_strife/a_rebels.cpp
g_strife/a_sentinel.cpp
g_strife/a_stalker.cpp
g_strife/a_strifeitems.cpp

View File

@ -696,7 +696,7 @@ public:
bool UseInventory(AInventory *item);
// Tosses an item out of the inventory.
virtual AInventory *DropInventory (AInventory *item);
AInventory *DropInventory (AInventory *item);
// Removes all items from the inventory.
void ClearInventory();

View File

@ -1,26 +0,0 @@
/*
#include "actor.h"
#include "a_action.h"
#include "a_strifeglobal.h"
#include "p_enemy.h"
#include "r_defs.h"
#include "vm.h"
*/
DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre)
{
PARAM_SELF_PROLOGUE(AActor);
TThinkerIterator<AActor> it(NAME_AlienSpectre3);
AActor *spectre = it.Next();
if (spectre != NULL && spectre->health > 0 && self->target != spectre)
{
spectre->Sector->SoundTarget = spectre->LastHeard = self->LastHeard;
spectre->target = self->target;
spectre->SetState (spectre->SeeState);
}
return 0;
}

View File

@ -1,141 +0,0 @@
/*
#include "actor.h"
#include "m_random.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
#include "a_strifeglobal.h"
#include "vm.h"
#include "g_level.h"
#include "doomstat.h"
*/
static FRandom pr_prog ("Programmer");
// The Programmer level ending thing ----------------------------------------
// [RH] I took some liberties to make this "cooler" than it was in Strife.
class AProgLevelEnder : public AInventory
{
DECLARE_CLASS (AProgLevelEnder, AInventory)
public:
void Tick ();
PalEntry GetBlend ();
};
IMPLEMENT_CLASS(AProgLevelEnder, false, false)
//============================================================================
//
// AProgLevelEnder :: Tick
//
// Fade to black, end the level, then unfade.
//
//============================================================================
void AProgLevelEnder::Tick ()
{
if (special2 == 0)
{ // fade out over .66 second
special1 += 255 / (TICRATE*2/3);
if (++special1 >= 255)
{
special1 = 255;
special2 = 1;
G_ExitLevel (0, false);
}
}
else
{ // fade in over two seconds
special1 -= 255 / (TICRATE*2);
if (special1 <= 0)
{
Destroy ();
}
}
}
//============================================================================
//
// AProgLevelEnder :: GetBlend
//
//============================================================================
PalEntry AProgLevelEnder::GetBlend ()
{
return PalEntry ((BYTE)special1, 0, 0, 0);
}
//============================================================================
//
// A_ProgrammerMelee
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee)
{
PARAM_SELF_PROLOGUE(AActor);
int damage;
if (self->target == NULL)
return 0;
A_FaceTarget (self);
if (!self->CheckMeleeRange ())
return 0;
S_Sound (self, CHAN_WEAPON, "programmer/clank", 1, ATTN_NORM);
damage = ((pr_prog() % 10) + 1) * 6;
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
//============================================================================
//
// A_SpawnProgrammerBase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24.), ALLOW_REPLACE);
if (foo != NULL)
{
foo->Angles.Yaw = self->Angles.Yaw + 180. + pr_prog.Random2() * (360. / 1024.);
foo->VelFromAngle();
foo->Vel.Z = pr_prog() / 128.;
}
return 0;
}
//============================================================================
//
// A_ProgrammerDeath
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath)
{
PARAM_SELF_PROLOGUE(AActor);
if (!CheckBossDeath (self))
return 0;
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i] && players[i].health > 0)
{
players[i].mo->GiveInventoryType (RUNTIME_CLASS(AProgLevelEnder));
break;
}
}
// the sky change scripts are now done as special actions in MAPINFO
A_BossDeath(self);
return 0;
}

View File

@ -1,124 +0,0 @@
/*
#include "actor.h"
#include "m_random.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
#include "gi.h"
#include "a_sharedglobal.h"
#include "a_strifeglobal.h"
#include "vm.h"
#include "doomstat.h"
*/
static FRandom pr_shootgun ("ShootGun");
//============================================================================
//
// A_ShootGun
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ShootGun)
{
PARAM_SELF_PROLOGUE(AActor);
DAngle pitch;
if (self->target == NULL)
return 0;
S_Sound (self, CHAN_WEAPON, "monsters/rifle", 1, ATTN_NORM);
A_FaceTarget (self);
pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE);
P_LineAttack (self, self->Angles.Yaw + pr_shootgun.Random2() * (11.25 / 256),
MISSILERANGE, pitch,
3*(pr_shootgun() % 5 + 1), NAME_Hitscan, NAME_StrifePuff);
return 0;
}
// Teleporter Beacon --------------------------------------------------------
class ATeleporterBeacon : public AInventory
{
DECLARE_CLASS (ATeleporterBeacon, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS(ATeleporterBeacon, false, false)
bool ATeleporterBeacon::Use (bool pickup)
{
AInventory *drop;
// Increase the amount by one so that when DropInventory decrements it,
// the actor will have the same number of beacons that he started with.
// When we return to UseInventory, it will take care of decrementing
// Amount again and disposing of this item if there are no more.
Amount++;
drop = Owner->DropInventory (this);
if (drop == NULL)
{
Amount--;
return false;
}
else
{
drop->SetState(drop->FindState(NAME_Drop));
drop->target = Owner;
return true;
}
}
DEFINE_ACTION_FUNCTION(AActor, A_Beacon)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *owner = self->target;
AActor *rebel;
rebel = Spawn("Rebel1", self->PosAtZ(self->floorz), ALLOW_REPLACE);
if (!P_TryMove (rebel, rebel->Pos(), true))
{
rebel->Destroy ();
return 0;
}
// Once the rebels start teleporting in, you can't pick up the beacon anymore.
self->flags &= ~MF_SPECIAL;
static_cast<AInventory *>(self)->DropTime = 0;
// Set up the new rebel.
rebel->threshold = rebel->DefThreshold;
rebel->target = NULL;
rebel->flags4 |= MF4_INCOMBAT;
rebel->LastHeard = owner; // Make sure the rebels look for targets
if (deathmatch)
{
rebel->health *= 2;
}
if (owner != NULL)
{
// Rebels are the same color as their owner (but only in multiplayer)
if (multiplayer)
{
rebel->Translation = owner->Translation;
}
rebel->SetFriendPlayer(owner->player);
// Set the rebel's target to whatever last hurt the player, so long as it's not
// one of the player's other rebels.
if (owner->target != NULL && !rebel->IsFriend (owner->target))
{
rebel->target = owner->target;
}
}
rebel->SetState (rebel->SeeState);
rebel->Angles.Yaw = self->Angles.Yaw;
P_SpawnTeleportFog(rebel, rebel->Vec3Angle(20., self->Angles.Yaw, 0), false, true);
if (--self->health < 0)
{
self->SetState(self->FindState(NAME_Death));
}
return 0;
}

View File

@ -180,8 +180,18 @@ IMPLEMENT_CLASS(ARaiseAlarm, false, false)
bool ARaiseAlarm::TryPickup (AActor *&toucher)
{
P_NoiseAlert (toucher, toucher);
VMFrameStack stack1, *stack = &stack1;
CALL_ACTION(A_WakeOracleSpectre, toucher);
/*
ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3");
Actor spectre = Actor(it.Next());
if (spectre != NULL && spectre.health > 0 && toucher != spectre)
{
spectre.CurSector.SoundTarget = spectre.LastHeard = toucher;
spectre.target = toucher;
spectre.SetState (spectre.SeeState);
}
*/
GoAwayAndDie ();
return true;
}

View File

@ -24,9 +24,6 @@
#include "vm.h"
// Include all the other Strife stuff here to reduce compile time
#include "a_oracle.cpp"
#include "a_programmer.cpp"
#include "a_rebels.cpp"
#include "a_sentinel.cpp"
#include "a_stalker.cpp"
#include "a_strifeitems.cpp"

View File

@ -1018,6 +1018,13 @@ AInventory *AActor::DropInventory (AInventory *item)
return drop;
}
DEFINE_ACTION_FUNCTION(AActor, DropInventory)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(item, AInventory);
ACTION_RETURN_OBJECT(self->DropInventory(item));
}
//============================================================================
//
// AActor :: FindInventory

View File

@ -372,12 +372,13 @@ class Actor : Thinker native
native void PlayActiveSound();
native void Howl();
// DECORATE compatible functions
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 GiveInventoryType(class<Inventory> itemtype);
native Inventory DropInventory (Inventory item);
native bool GiveAmmo (Class<Ammo> type, int amount);
// DECORATE compatible functions
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
native double GetDistance(bool checkz, int ptr = AAPTR_TARGET);
native double GetAngle(int flags, int ptr = AAPTR_DEFAULT);
@ -701,7 +702,6 @@ class Actor : Thinker native
native void A_ClearLastHeard();
native bool A_SelectWeapon(class<Weapon> whichweapon, int flags = 0);
native void A_ClassBossHealth();
native void A_ShootGun();
native void A_RocketInFlight();
native void A_Bang4Cloud();
native void A_DropFire();

View File

@ -19,8 +19,6 @@ class Oracle : Actor
DropItem "Meat";
}
native void A_WakeOracleSpectre ();
States
{
Spawn:
@ -35,4 +33,19 @@ class Oracle : Actor
ORCL Q -1;
Stop;
}
void A_WakeOracleSpectre ()
{
ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3");
Actor spectre = Actor(it.Next());
if (spectre != NULL && spectre.health > 0 && self.target != spectre)
{
spectre.CurSector.SoundTarget = spectre.LastHeard = self.LastHeard;
spectre.target = self.target;
spectre.SetState (spectre.SeeState);
}
}
}

View File

@ -33,10 +33,6 @@ class Programmer : Actor
DropItem "Sigil1";
}
native void A_ProgrammerMelee ();
native void A_SpawnProgrammerBase ();
native void A_ProgrammerDeath ();
States
{
Spawn:
@ -80,6 +76,69 @@ class Programmer : Actor
Stop;
}
//============================================================================
//
// A_ProgrammerMelee
//
//============================================================================
void A_ProgrammerMelee ()
{
if (target == null)
return;
A_FaceTarget ();
if (!CheckMeleeRange ())
return;
A_PlaySound("programmer/clank", CHAN_WEAPON);
int damage = ((random[Programmer]() % 10) + 1) * 6;
int newdam = DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
}
//============================================================================
//
// A_SpawnProgrammerBase
//
//============================================================================
void A_SpawnProgrammerBase ()
{
Actor foo = Spawn("ProgrammerBase", Pos + (0,0,24), ALLOW_REPLACE);
if (foo != null)
{
foo.Angle = Angle + 180. + Random2[Programmer]() * (360. / 1024.);
foo.VelFromAngle();
foo.Vel.Z = random[Programmer]() / 128.;
}
}
//============================================================================
//
// A_ProgrammerDeath
//
//============================================================================
void A_ProgrammerDeath ()
{
if (!CheckBossDeath ())
return;
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i] && players[i].health > 0)
{
players[i].mo.GiveInventoryType ("ProgLevelEnder");
break;
}
}
// the sky change scripts are now done as special actions in MAPINFO
A_BossDeath();
}
//============================================================================
//
// A_SpotLightning
@ -88,10 +147,10 @@ class Programmer : Actor
void A_SpotLightning()
{
if (target == NULL) return;
if (target == null) return;
Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE);
if (spot != NULL)
if (spot != null)
{
spot.threshold = 25;
spot.target = self;
@ -127,10 +186,52 @@ class ProgrammerBase : Actor
// The Programmer level ending thing ----------------------------------------
class ProgLevelEnder : Inventory native
class ProgLevelEnder : Inventory
{
Default
{
+INVENTORY.UNDROPPABLE
}
//============================================================================
//
// AProgLevelEnder :: Tick
//
// Fade to black, end the level, then unfade.
//
//============================================================================
override void Tick ()
{
if (special2 == 0)
{ // fade out over .66 second
special1 += 255 / (TICRATE*2/3);
if (++special1 >= 255)
{
special1 = 255;
special2 = 1;
Exit_Normal(0);
}
}
else
{ // fade in over two seconds
special1 -= 255 / (TICRATE*2);
if (special1 <= 0)
{
Destroy ();
}
}
}
//============================================================================
//
// AProgLevelEnder :: GetBlend
//
//============================================================================
override Color GetBlend ()
{
return Color(special1, 0, 0, 0);
}
}

View File

@ -107,7 +107,7 @@ class Rebel6 : Rebel
// Teleporter Beacon --------------------------------------------------------
class TeleporterBeacon : Inventory native
class TeleporterBeacon : Inventory
{
Default
{
@ -122,8 +122,6 @@ class TeleporterBeacon : Inventory native
Inventory.PickupMessage "$TXT_BEACON";
}
native void A_Beacon ();
States
{
Spawn:
@ -137,4 +135,73 @@ class TeleporterBeacon : Inventory native
BEAC A 1 A_FadeOut(0.015);
Loop;
}
// Teleporter Beacon --------------------------------------------------------
override bool Use (bool pickup)
{
// Increase the amount by one so that when DropInventory decrements it,
// the actor will have the same number of beacons that he started with.
// When we return to UseInventory, it will take care of decrementing
// Amount again and disposing of self item if there are no more.
Amount++;
Inventory drop = Owner.DropInventory (self);
if (drop == null)
{
Amount--;
return false;
}
else
{
drop.SetStateLabel("Drop");
drop.target = Owner;
return true;
}
}
void A_Beacon()
{
Actor owner = target;
Actor rebel = Spawn("Rebel1", (pos.xy, floorz), ALLOW_REPLACE);
if (!rebel.TryMove (rebel.Pos.xy, true))
{
rebel.Destroy ();
return;
}
// Once the rebels start teleporting in, you can't pick up the beacon anymore.
bSpecial = false;
Inventory(self).DropTime = 0;
// Set up the new rebel.
rebel.threshold = rebel.DefThreshold;
rebel.target = null;
rebel.bInCombat = true;
rebel.LastHeard = owner; // Make sure the rebels look for targets
if (deathmatch)
{
rebel.health *= 2;
}
if (owner != null)
{
// Rebels are the same color as their owner (but only in multiplayer)
if (multiplayer)
{
rebel.Translation = owner.Translation;
}
rebel.SetFriendPlayer(owner.player);
// Set the rebel's target to whatever last hurt the player, so long as it's not
// one of the player's other rebels.
if (owner.target != null && !rebel.IsFriend (owner.target))
{
rebel.target = owner.target;
}
}
rebel.SetState (rebel.SeeState);
rebel.Angle = Angle;
rebel.SpawnTeleportFog(rebel.Vec3Angle(20., Angle, 0), false, true);
if (--health < 0)
{
SetStateLabel("Death");
}
}
}

View File

@ -56,3 +56,21 @@ class FireDroplet : Actor
}
extend class Actor
{
//============================================================================
//
// A_ShootGun
//
//============================================================================
void A_ShootGun()
{
if (!target) return;
A_PlaySound ("monsters/rifle", CHAN_WEAPON);
A_FaceTarget ();
double pitch = AimLineAttack (angle, MISSILERANGE);
LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff");
}
}