- scriptified Strife's dagger and crossbow.

This commit is contained in:
Christoph Oelckers 2016-11-29 13:00:07 +01:00
parent 3af9232fca
commit be5ba70ed2
10 changed files with 428 additions and 457 deletions

View file

@ -16,7 +16,6 @@
// hacking more stuff in the executable, be sure to give // hacking more stuff in the executable, be sure to give
// all Strife missiles the MF4_STRIFEDAMAGE flag. // all Strife missiles the MF4_STRIFEDAMAGE flag.
static FRandom pr_jabdagger ("JabDagger");
static FRandom pr_electric ("FireElectric"); static FRandom pr_electric ("FireElectric");
static FRandom pr_sgunshot ("StrifeGunShot"); static FRandom pr_sgunshot ("StrifeGunShot");
static FRandom pr_minimissile ("MiniMissile"); static FRandom pr_minimissile ("MiniMissile");
@ -29,252 +28,6 @@ static FRandom pr_phburn ("PhBurn");
void A_LoopActiveSound (AActor *); void A_LoopActiveSound (AActor *);
void A_Countdown (AActor *); void A_Countdown (AActor *);
// Punch Dagger -------------------------------------------------------------
//============================================================================
//
// P_DaggerAlert
//
//============================================================================
void P_DaggerAlert (AActor *target, AActor *emitter)
{
AActor *looker;
sector_t *sec = emitter->Sector;
if (emitter->LastHeard != NULL)
return;
if (emitter->health <= 0)
return;
if (!(emitter->flags3 & MF3_ISMONSTER))
return;
if (emitter->flags4 & MF4_INCOMBAT)
return;
emitter->flags4 |= MF4_INCOMBAT;
emitter->target = target;
FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger);
if (painstate != NULL)
{
emitter->SetState (painstate);
}
for (looker = sec->thinglist; looker != NULL; looker = looker->snext)
{
if (looker == emitter || looker == target)
continue;
if (looker->health <= 0)
continue;
if (!(looker->flags4 & MF4_SEESDAGGERS))
continue;
if (!(looker->flags4 & MF4_INCOMBAT))
{
if (!P_CheckSight (looker, target) && !P_CheckSight (looker, emitter))
continue;
looker->target = target;
if (looker->SeeSound)
{
S_Sound (looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM);
}
looker->SetState (looker->SeeState);
looker->flags4 |= MF4_INCOMBAT;
}
}
}
//============================================================================
//
// A_JabDagger
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_JabDagger)
{
PARAM_ACTION_PROLOGUE(AActor);
DAngle angle;
int damage;
DAngle pitch;
int power;
FTranslatedLineTarget t;
power = MIN(10, self->player->mo->stamina / 10);
damage = (pr_jabdagger() % (power + 8)) * (power + 2);
if (self->FindInventory<APowerStrength>())
{
damage *= 10;
}
angle = self->Angles.Yaw + pr_jabdagger.Random2() * (5.625 / 256);
pitch = P_AimLineAttack (self, angle, 80.);
P_LineAttack (self, angle, 80., pitch, damage, NAME_Melee, "StrifeSpark", true, &t);
// turn to face target
if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON,
t.linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit",
1, ATTN_NORM);
self->Angles.Yaw = t.angleFromSource;
self->flags |= MF_JUSTATTACKED;
P_DaggerAlert (self, t.linetarget);
}
else
{
S_Sound (self, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM);
}
return 0;
}
//============================================================================
//
// A_AlertMonsters
//
//============================================================================
enum
{
AMF_TARGETEMITTER = 1,
AMF_TARGETNONPLAYER = 2,
AMF_EMITFROMTARGET = 4,
};
DEFINE_ACTION_FUNCTION(AActor, A_AlertMonsters)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT_DEF(maxdist);
PARAM_INT_DEF(Flags);
AActor * target = NULL;
AActor * emitter = self;
if (self->player != NULL || (Flags & AMF_TARGETEMITTER))
{
target = self;
}
else if (self->target != NULL && (Flags & AMF_TARGETNONPLAYER))
{
target = self->target;
}
else if (self->target != NULL && self->target->player != NULL)
{
target = self->target;
}
if (Flags & AMF_EMITFROMTARGET) emitter = target;
if (target != NULL && emitter != NULL)
{
P_NoiseAlert(target, emitter, false, maxdist);
}
return 0;
}
// Poison Bolt --------------------------------------------------------------
class APoisonBolt : public AActor
{
DECLARE_CLASS (APoisonBolt, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(APoisonBolt, false, false)
int APoisonBolt::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
if (target->flags & MF_NOBLOOD)
{
return -1;
}
if (target->health < 1000000)
{
if (!(target->flags2 & MF2_BOSS))
return target->health + 10;
else
return 50;
}
return 1;
}
// Strife's Crossbow --------------------------------------------------------
//============================================================================
//
// A_ClearFlash
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash)
{
PARAM_ACTION_PROLOGUE(AActor);
player_t *player = self->player;
if (player == nullptr)
return 0;
P_SetPsprite (player, PSP_FLASH, nullptr);
return 0;
}
//============================================================================
//
// A_ShowElectricFlash
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash)
{
PARAM_ACTION_PROLOGUE(AActor);
if (self->player != nullptr)
{
P_SetPsprite (self->player, PSP_FLASH, self->player->ReadyWeapon->FindState(NAME_Flash));
}
return 0;
}
//============================================================================
//
// A_FireElectric
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FireArrow)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_CLASS(ti, AActor);
DAngle savedangle;
if (self->player == NULL)
return 0;
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
if (ti)
{
savedangle = self->Angles.Yaw;
self->Angles.Yaw += pr_electric.Random2() * (5.625/256) * self->player->mo->AccuracyFactor();
self->player->mo->PlayAttacking2 ();
P_SpawnPlayerMissile (self, ti);
self->Angles.Yaw = savedangle;
S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM);
}
return 0;
}
// Assault Gun -------------------------------------------------------------- // Assault Gun --------------------------------------------------------------
//============================================================================ //============================================================================

View file

@ -273,6 +273,70 @@ DEFINE_ACTION_FUNCTION(AActor, NoiseAlert)
return 0; return 0;
} }
//============================================================================
//
// P_DaggerAlert
//
//============================================================================
void P_DaggerAlert(AActor *target, AActor *emitter)
{
AActor *looker;
sector_t *sec = emitter->Sector;
if (emitter->LastHeard != NULL)
return;
if (emitter->health <= 0)
return;
if (!(emitter->flags3 & MF3_ISMONSTER))
return;
if (emitter->flags4 & MF4_INCOMBAT)
return;
emitter->flags4 |= MF4_INCOMBAT;
emitter->target = target;
FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger);
if (painstate != NULL)
{
emitter->SetState(painstate);
}
for (looker = sec->thinglist; looker != NULL; looker = looker->snext)
{
if (looker == emitter || looker == target)
continue;
if (looker->health <= 0)
continue;
if (!(looker->flags4 & MF4_SEESDAGGERS))
continue;
if (!(looker->flags4 & MF4_INCOMBAT))
{
if (!P_CheckSight(looker, target) && !P_CheckSight(looker, emitter))
continue;
looker->target = target;
if (looker->SeeSound)
{
S_Sound(looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM);
}
looker->SetState(looker->SeeState);
looker->flags4 |= MF4_INCOMBAT;
}
}
}
DEFINE_ACTION_FUNCTION(AActor, DaggerAlert)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(target, AActor);
// Note that the emitter is self, not the target of the alert! Target can be NULL.
P_DaggerAlert(target, self);
return 0;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// //

View file

@ -7598,6 +7598,11 @@ DEFINE_ACTION_FUNCTION(AActor, ClearBounce)
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION(AActor, AccuracyFactor)
{
PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_FLOAT(self->AccuracyFactor());
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// //

View file

@ -740,7 +740,7 @@ type_name(X) ::= DOT dottable_id(A).
/* Type names can also be used as identifiers in contexts where type names /* Type names can also be used as identifiers in contexts where type names
* are not normally allowed. */ * are not normally allowed. */
%fallback IDENTIFIER %fallback IDENTIFIER
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR UINT8 INT8 UINT16 INT16. SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16.
/* Aggregate types */ /* Aggregate types */
%type aggregate_type {ZCC_Type *} %type aggregate_type {ZCC_Type *}

View file

@ -189,6 +189,8 @@ zscript/strife/strifestuff.txt
zscript/strife/thingstoblowup.txt zscript/strife/thingstoblowup.txt
zscript/strife/templar.txt zscript/strife/templar.txt
zscript/strife/zombie.txt zscript/strife/zombie.txt
zscript/strife/weapondagger.txt
zscript/strife/weaponcrossbow.txt
zscript/strife/sigil.txt zscript/strife/sigil.txt
zscript/chex/chexmonsters.txt zscript/chex/chexmonsters.txt

View file

@ -288,6 +288,7 @@ class Actor : Thinker native
native int PlayerNumber(); native int PlayerNumber();
native void SetFriendPlayer(PlayerInfo player); native void SetFriendPlayer(PlayerInfo player);
native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0); native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0);
native void DaggerAlert(Actor target);
native void ClearBounce(); native void ClearBounce();
native TerrainDef GetFloorTerrain(); native TerrainDef GetFloorTerrain();
native Inventory DoDropItem(Class<Actor> type, int dropamount, int chance); native Inventory DoDropItem(Class<Actor> type, int dropamount, int chance);
@ -380,6 +381,7 @@ class Actor : Thinker native
native Inventory DropInventory (Inventory item); native Inventory DropInventory (Inventory item);
native bool UseInventory(Inventory item); native bool UseInventory(Inventory item);
native bool GiveAmmo (Class<Ammo> type, int amount); native bool GiveAmmo (Class<Ammo> type, int amount);
native float AccuracyFactor();
// DECORATE compatible functions // DECORATE compatible functions
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT); native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
@ -622,7 +624,6 @@ class Actor : Thinker native
native void A_Wander(int flags = 0); native void A_Wander(int flags = 0);
native void A_Look2(); native void A_Look2();
native void A_AlertMonsters(double maxdist = 0, int flags = 0);
deprecated native void A_MissileAttack(); deprecated native void A_MissileAttack();
deprecated native void A_MeleeAttack(); deprecated native void A_MeleeAttack();

View file

@ -71,7 +71,11 @@ extend class Actor
gib.Vel.Z = random[GibTosser]() & 15; gib.Vel.Z = random[GibTosser]() & 15;
} }
// A_ShootGun ------------------------------------------------------------- //==========================================================================
//
//
//
//==========================================================================
void A_ShootGun() void A_ShootGun()
{ {
@ -82,7 +86,11 @@ extend class Actor
LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff");
} }
// Kneeling Guy ------------------------------------------------------------- //==========================================================================
//
//
//
//==========================================================================
void A_SetShadow() void A_SetShadow()
{ {
@ -96,6 +104,12 @@ extend class Actor
A_SetRenderStyle(1, STYLE_Normal); A_SetRenderStyle(1, STYLE_Normal);
} }
//==========================================================================
//
//
//
//==========================================================================
void A_GetHurt() void A_GetHurt()
{ {
bInCombat = true; bInCombat = true;
@ -110,6 +124,12 @@ extend class Actor
} }
} }
//==========================================================================
//
//
//
//==========================================================================
void A_DropFire() void A_DropFire()
{ {
Actor drop = Spawn("FireDroplet", pos + (0,0,24), ALLOW_REPLACE); Actor drop = Spawn("FireDroplet", pos + (0,0,24), ALLOW_REPLACE);
@ -117,9 +137,45 @@ extend class Actor
A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire'); A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire');
} }
//==========================================================================
//
//
//
//==========================================================================
void A_RemoveForceField() void A_RemoveForceField()
{ {
bSpecial = false; bSpecial = false;
CurSector.RemoveForceField(); CurSector.RemoveForceField();
} }
//==========================================================================
//
//
//
//==========================================================================
void A_AlertMonsters(double maxdist = 0, int flags = 0)
{
Actor target = null;
Actor emitter = self;
if (player != null || (Flags & AMF_TARGETEMITTER))
{
target = self;
}
else if (target != null && (self.target.player != null || (Flags & AMF_TARGETNONPLAYER)))
{
target = self.target;
}
if (Flags & AMF_EMITFROMTARGET) emitter = target;
if (target != null && emitter != null)
{
emitter.NoiseAlert(target, false, maxdist);
}
}
} }

View file

@ -50,212 +50,6 @@ class StrifeSpark : StrifePuff
} }
} }
// Punch Dagger -------------------------------------------------------------
class PunchDagger : StrifeWeapon
{
Default
{
Weapon.SelectionOrder 3900;
+WEAPON.NOALERT
Obituary "$OB_MPPUNCHDAGGER";
Tag "$TAG_PUNCHDAGGER";
}
action native void A_JabDagger ();
States
{
Ready:
PNCH A 1 A_WeaponReady;
Loop;
Deselect:
PNCH A 1 A_Lower;
Loop;
Select:
PNCH A 1 A_Raise;
Loop;
Fire:
PNCH B 4;
PNCH C 4 A_JabDagger;
PNCH D 5;
PNCH C 4;
PNCH B 5 A_ReFire;
Goto Ready;
}
}
// The base for Strife projectiles that die with ZAP1 -----------------------
class StrifeZap1 : Actor
{
Default
{
+NOBLOCKMAP
+NOGRAVITY
+DROPOFF
}
States
{
Spawn:
Death:
ZAP1 A 3 A_AlertMonsters;
ZAP1 BCDEFE 3;
ZAP1 DCB 2;
ZAP1 A 1;
Stop;
}
}
// Electric Bolt ------------------------------------------------------------
class ElectricBolt : StrifeZap1
{
Default
{
Speed 30;
Radius 10;
Height 10;
Damage 10;
Projectile;
+STRIFEDAMAGE
MaxStepHeight 4;
SeeSound "misc/swish";
ActiveSound "misc/swish";
DeathSound "weapons/xbowhit";
Obituary "$OB_MPELECTRICBOLT";
}
States
{
Spawn:
AROW A 10 A_LoopActiveSound;
Loop;
}
}
// Poison Bolt --------------------------------------------------------------
class PoisonBolt : Actor native
{
Default
{
Speed 30;
Radius 10;
Height 10;
Damage 500;
Projectile;
+STRIFEDAMAGE
MaxStepHeight 4;
SeeSound "misc/swish";
ActiveSound "misc/swish";
Obituary "$OB_MPPOISONBOLT";
}
States
{
Spawn:
ARWP A 10 A_LoopActiveSound;
Loop;
Death:
AROW A 1;
Stop;
}
}
// Strife's Crossbow --------------------------------------------------------
class StrifeCrossbow : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 1200;
+WEAPON.NOALERT
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 8;
Weapon.AmmoType1 "ElectricBolts";
Weapon.SisterWeapon "StrifeCrossbow2";
Inventory.PickupMessage "$TXT_STRIFECROSSBOW";
Tag "$TAG_STRIFECROSSBOW1";
Inventory.Icon "CBOWA0";
}
action native void A_ClearFlash ();
action native void A_ShowElectricFlash ();
action native void A_FireArrow (class<Actor> proj);
States
{
Spawn:
CBOW A -1;
Stop;
Ready:
XBOW A 0 A_ShowElectricFlash;
XBOW A 1 A_WeaponReady;
Wait;
Deselect:
XBOW A 1 A_Lower;
Loop;
Select:
XBOW A 1 A_Raise;
Loop;
Fire:
XBOW A 3 A_ClearFlash;
XBOW B 6 A_FireArrow("ElectricBolt");
XBOW C 4;
XBOW D 6;
XBOW E 3;
XBOW F 5;
XBOW G 0 A_ShowElectricFlash;
XBOW G 5 A_CheckReload;
Goto Ready+1;
Flash:
XBOW KLM 5;
Loop;
}
}
class StrifeCrossbow2 : StrifeCrossbow
{
Default
{
Weapon.SelectionOrder 2700;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 0;
Weapon.AmmoType1 "PoisonBolts";
Weapon.SisterWeapon "StrifeCrossbow";
Tag "$TAG_STRIFECROSSBOW2";
}
States
{
Ready:
XBOW H 1 A_WeaponReady;
Loop;
Deselect:
XBOW H 1 A_Lower;
Loop;
Select:
XBOW H 1 A_Raise;
Loop;
Fire:
XBOW H 3;
XBOW B 6 A_FireArrow("PoisonBolt");
XBOW C 4;
XBOW D 6;
XBOW E 3;
XBOW I 5;
XBOW J 5 A_CheckReload;
Goto Ready;
Flash:
Stop;
}
}
// Assault Gun -------------------------------------------------------------- // Assault Gun --------------------------------------------------------------
class AssaultGun : StrifeWeapon class AssaultGun : StrifeWeapon

View file

@ -0,0 +1,227 @@
// Strife's Crossbow --------------------------------------------------------
class StrifeCrossbow : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 1200;
+WEAPON.NOALERT
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 8;
Weapon.AmmoType1 "ElectricBolts";
Weapon.SisterWeapon "StrifeCrossbow2";
Inventory.PickupMessage "$TXT_STRIFECROSSBOW";
Tag "$TAG_STRIFECROSSBOW1";
Inventory.Icon "CBOWA0";
}
States
{
Spawn:
CBOW A -1;
Stop;
Ready:
XBOW A 0 A_ShowElectricFlash;
XBOW A 1 A_WeaponReady;
Wait;
Deselect:
XBOW A 1 A_Lower;
Loop;
Select:
XBOW A 1 A_Raise;
Loop;
Fire:
XBOW A 3 A_ClearFlash;
XBOW B 6 A_FireArrow("ElectricBolt");
XBOW C 4;
XBOW D 6;
XBOW E 3;
XBOW F 5;
XBOW G 0 A_ShowElectricFlash;
XBOW G 5 A_CheckReload;
Goto Ready+1;
Flash:
XBOW KLM 5;
Loop;
}
//============================================================================
//
// A_ClearFlash
//
//============================================================================
action void A_ClearFlash ()
{
if (player == null)
return;
player.SetPsprite (PSP_FLASH, null);
}
//============================================================================
//
// A_ShowElectricFlash
//
//============================================================================
action void A_ShowElectricFlash ()
{
if (player != null)
{
player.SetPsprite (PSP_FLASH, player.ReadyWeapon.FindState('Flash'));
}
}
//============================================================================
//
// A_FireElectric
//
//============================================================================
action void A_FireArrow (class<Actor> proj)
{
if (player == null)
{
return;
}
Weapon weapon = player.ReadyWeapon;
if (weapon != null)
{
if (!weapon.DepleteAmmo (weapon.bAltFire))
return;
}
if (proj)
{
double savedangle = angle;
angle += Random2[Electric]() * (5.625/256) * AccuracyFactor();
player.mo.PlayAttacking2 ();
SpawnPlayerMissile (proj);
angle = savedangle;
A_PlaySound ("weapons/xbowshoot", CHAN_WEAPON);
}
}
}
class StrifeCrossbow2 : StrifeCrossbow
{
Default
{
Weapon.SelectionOrder 2700;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 0;
Weapon.AmmoType1 "PoisonBolts";
Weapon.SisterWeapon "StrifeCrossbow";
Tag "$TAG_STRIFECROSSBOW2";
}
States
{
Ready:
XBOW H 1 A_WeaponReady;
Loop;
Deselect:
XBOW H 1 A_Lower;
Loop;
Select:
XBOW H 1 A_Raise;
Loop;
Fire:
XBOW H 3;
XBOW B 6 A_FireArrow("PoisonBolt");
XBOW C 4;
XBOW D 6;
XBOW E 3;
XBOW I 5;
XBOW J 5 A_CheckReload;
Goto Ready;
Flash:
Stop;
}
}
// Electric Bolt ------------------------------------------------------------
class ElectricBolt : Actor
{
Default
{
Speed 30;
Radius 10;
Height 10;
Damage 10;
Projectile;
+STRIFEDAMAGE
+NOBLOCKMAP
+NOGRAVITY
+DROPOFF
MaxStepHeight 4;
SeeSound "misc/swish";
ActiveSound "misc/swish";
DeathSound "weapons/xbowhit";
Obituary "$OB_MPELECTRICBOLT";
}
States
{
Spawn:
AROW A 10 A_LoopActiveSound;
Loop;
Death:
ZAP1 A 3 A_AlertMonsters;
ZAP1 BCDEFE 3;
ZAP1 DCB 2;
ZAP1 A 1;
Stop;
}
}
// Poison Bolt --------------------------------------------------------------
class PoisonBolt : Actor
{
Default
{
Speed 30;
Radius 10;
Height 10;
Damage 500;
Projectile;
+STRIFEDAMAGE
MaxStepHeight 4;
SeeSound "misc/swish";
ActiveSound "misc/swish";
Obituary "$OB_MPPOISONBOLT";
}
States
{
Spawn:
ARWP A 10 A_LoopActiveSound;
Loop;
Death:
AROW A 1;
Stop;
}
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
{
if (target.bNoBlood)
{
return -1;
}
if (target.health < 1000000)
{
if (!target.bBoss)
return target.health + 10;
else
return 50;
}
return 1;
}
}

View file

@ -0,0 +1,69 @@
// Punch Dagger -------------------------------------------------------------
class PunchDagger : StrifeWeapon
{
Default
{
Weapon.SelectionOrder 3900;
+WEAPON.NOALERT
Obituary "$OB_MPPUNCHDAGGER";
Tag "$TAG_PUNCHDAGGER";
}
States
{
Ready:
PNCH A 1 A_WeaponReady;
Loop;
Deselect:
PNCH A 1 A_Lower;
Loop;
Select:
PNCH A 1 A_Raise;
Loop;
Fire:
PNCH B 4;
PNCH C 4 A_JabDagger;
PNCH D 5;
PNCH C 4;
PNCH B 5 A_ReFire;
Goto Ready;
}
//============================================================================
//
// A_JabDagger
//
//============================================================================
action void A_JabDagger ()
{
FTranslatedLineTarget t;
int power = MIN(10, stamina / 10);
int damage = (random[JabDagger]() % (power + 8)) * (power + 2);
if (FindInventory("PowerStrength"))
{
damage *= 10;
}
double angle = angle + random2[JabDagger]() * (5.625 / 256);
double pitch = AimLineAttack (angle, 80.);
LineAttack (angle, 80., pitch, damage, 'Melee', "StrifeSpark", true, t);
// turn to face target
if (t.linetarget)
{
S_Sound (t.linetarget.bNoBlood ? sound("misc/metalhit") : sound("misc/meathit"), CHAN_WEAPON);
angle = t.angleFromSource;
bJustAttacked = true;
t.linetarget.DaggerAlert (self);
}
else
{
A_PlaySound ("misc/swish", CHAN_WEAPON);
}
}
}