mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
- scriptified Oracle, Programmer and Rebels.
This commit is contained in:
parent
119bcb924d
commit
360cbfba2a
13 changed files with 233 additions and 314 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue