2008-09-15 14:11:05 +00:00
|
|
|
/*
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "a_hexenglobal.h"
|
|
|
|
#include "gstrings.h"
|
2008-08-08 10:24:08 +00:00
|
|
|
#include "a_weaponpiece.h"
|
2008-08-10 20:48:55 +00:00
|
|
|
#include "thingdef/thingdef.h"
|
2008-09-14 23:54:38 +00:00
|
|
|
#include "doomstat.h"
|
2008-09-15 14:11:05 +00:00
|
|
|
*/
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
static FRandom pr_mstafftrack ("MStaffTrack");
|
|
|
|
static FRandom pr_bloodscourgedrop ("BloodScourgeDrop");
|
|
|
|
|
|
|
|
void A_MStaffTrack (AActor *);
|
|
|
|
void A_DropBloodscourgePieces (AActor *);
|
|
|
|
void A_MStaffAttack (AActor *actor);
|
|
|
|
void A_MStaffPalette (AActor *actor);
|
|
|
|
|
|
|
|
static AActor *FrontBlockCheck (AActor *mo, int index);
|
|
|
|
static divline_t BlockCheckLine;
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
//==========================================================================
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-08 10:24:08 +00:00
|
|
|
class AMageWeaponPiece : public AWeaponPiece
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-08 10:24:08 +00:00
|
|
|
DECLARE_CLASS (AMageWeaponPiece, AWeaponPiece)
|
2006-02-24 04:48:15 +00:00
|
|
|
protected:
|
2008-09-13 22:08:41 +00:00
|
|
|
bool TryPickup (AActor *&toucher);
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS (AMageWeaponPiece)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-09-13 22:08:41 +00:00
|
|
|
bool AMageWeaponPiece::TryPickup (AActor *&toucher)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-08 10:24:08 +00:00
|
|
|
if (!toucher->IsKindOf (PClass::FindClass(NAME_ClericPlayer)) &&
|
|
|
|
!toucher->IsKindOf (PClass::FindClass(NAME_FighterPlayer)))
|
|
|
|
{
|
|
|
|
return Super::TryPickup(toucher);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Wrong class, but try to pick up for ammo
|
|
|
|
if (ShouldStay())
|
|
|
|
{
|
|
|
|
// Can't pick up weapons for other classes in coop netplay
|
|
|
|
return false;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-08 10:24:08 +00:00
|
|
|
AWeapon * Defaults=(AWeapon*)GetDefaultByType(WeaponClass);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-08 10:24:08 +00:00
|
|
|
bool gaveSome = !!(toucher->GiveAmmo (Defaults->AmmoType1, Defaults->AmmoGive1) +
|
|
|
|
toucher->GiveAmmo (Defaults->AmmoType2, Defaults->AmmoGive2));
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-08 10:24:08 +00:00
|
|
|
if (gaveSome)
|
|
|
|
{
|
|
|
|
GoAwayAndDie ();
|
|
|
|
}
|
|
|
|
return gaveSome;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The Mages's Staff (Bloodscourge) -----------------------------------------
|
|
|
|
|
|
|
|
class AMWeapBloodscourge : public AMageWeapon
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
DECLARE_CLASS (AMWeapBloodscourge, AMageWeapon)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
void Serialize (FArchive &arc)
|
|
|
|
{
|
|
|
|
Super::Serialize (arc);
|
|
|
|
arc << MStaffCount;
|
|
|
|
}
|
|
|
|
PalEntry GetBlend ()
|
|
|
|
{
|
|
|
|
return PalEntry (MStaffCount * 128 / 3, 151, 110, 0);
|
|
|
|
}
|
|
|
|
BYTE MStaffCount;
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS (AMWeapBloodscourge)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Mage Staff FX2 (Bloodscourge) --------------------------------------------
|
|
|
|
|
|
|
|
class AMageStaffFX2 : public AActor
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
DECLARE_CLASS(AMageStaffFX2, AActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
int SpecialMissileHit (AActor *victim);
|
|
|
|
bool IsOkayToAttack (AActor *link);
|
|
|
|
bool SpecialBlastHandling (AActor *source, fixed_t strength);
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS (AMageStaffFX2)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
int AMageStaffFX2::SpecialMissileHit (AActor *victim)
|
|
|
|
{
|
|
|
|
if (victim != target &&
|
|
|
|
!victim->player &&
|
|
|
|
!(victim->flags2 & MF2_BOSS))
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (victim, this, target, 10, NAME_Fire);
|
2006-02-24 04:48:15 +00:00
|
|
|
return 1; // Keep going
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AMageStaffFX2::IsOkayToAttack (AActor *link)
|
|
|
|
{
|
|
|
|
if (((link->flags3&MF3_ISMONSTER) || link->player)
|
|
|
|
&& !(link->flags2&MF2_DORMANT))
|
|
|
|
{
|
|
|
|
if (!(link->flags&MF_SHOOTABLE))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (multiplayer && !deathmatch && link->player && target->player)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (link == target)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (P_CheckSight (this, link))
|
|
|
|
{
|
|
|
|
AActor *master = target;
|
2008-05-14 07:45:40 +00:00
|
|
|
angle_t angle = R_PointToAngle2 (master->x, master->y,
|
2006-02-24 04:48:15 +00:00
|
|
|
link->x, link->y) - master->angle;
|
|
|
|
angle >>= 24;
|
|
|
|
if (angle>226 || angle<30)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AMageStaffFX2::SpecialBlastHandling (AActor *source, fixed_t strength)
|
|
|
|
{
|
|
|
|
// Reflect to originator
|
|
|
|
tracer = target;
|
|
|
|
target = source;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// MStaffSpawn
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void MStaffSpawn (AActor *pmo, angle_t angle)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
2008-04-10 14:38:43 +00:00
|
|
|
AActor *linetarget;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2007-03-07 17:31:40 +00:00
|
|
|
mo = P_SpawnPlayerMissile (pmo, 0, 0, 8*FRACUNIT,
|
2008-04-10 14:38:43 +00:00
|
|
|
RUNTIME_CLASS(AMageStaffFX2), angle, &linetarget);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->target = pmo;
|
|
|
|
mo->tracer = linetarget;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MStaffAttack
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack)
|
2006-06-17 20:29:41 +00:00
|
|
|
{
|
|
|
|
angle_t angle;
|
2006-02-24 04:48:15 +00:00
|
|
|
player_t *player;
|
2008-04-10 14:38:43 +00:00
|
|
|
AActor *linetarget;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
if (NULL == (player = self->player))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2006-06-17 20:29:41 +00:00
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (weapon != NULL)
|
|
|
|
{
|
|
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
angle = self->angle;
|
2006-06-17 20:29:41 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
// [RH] Let's try and actually track what the player aimed at
|
2008-08-10 20:48:55 +00:00
|
|
|
P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &linetarget, ANGLE_1*32);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (linetarget == NULL)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
BlockCheckLine.x = self->x;
|
|
|
|
BlockCheckLine.y = self->y;
|
2006-02-24 04:48:15 +00:00
|
|
|
BlockCheckLine.dx = -finesine[angle >> ANGLETOFINESHIFT];
|
|
|
|
BlockCheckLine.dy = -finecosine[angle >> ANGLETOFINESHIFT];
|
2008-08-10 20:48:55 +00:00
|
|
|
linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
MStaffSpawn (self, angle);
|
|
|
|
MStaffSpawn (self, angle-ANGLE_1*5);
|
|
|
|
MStaffSpawn (self, angle+ANGLE_1*5);
|
|
|
|
S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
|
2006-06-17 20:29:41 +00:00
|
|
|
weapon->MStaffCount = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MStaffPalette
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette)
|
2006-06-17 20:29:41 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->player != NULL)
|
2006-06-17 20:29:41 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (weapon != NULL && weapon->MStaffCount != 0)
|
|
|
|
{
|
|
|
|
weapon->MStaffCount--;
|
|
|
|
}
|
2006-06-17 20:29:41 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MStaffTrack
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if ((self->tracer == 0) && (pr_mstafftrack()<50))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->tracer = P_RoughMonsterSearch (self, 10);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
P_SeekerMissile (self, ANGLE_1*2, ANGLE_1*10);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// FrontBlockCheck
|
|
|
|
//
|
|
|
|
// [RH] Like RoughBlockCheck, but it won't return anything behind a line.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
static AActor *FrontBlockCheck (AActor *mo, int index)
|
|
|
|
{
|
|
|
|
FBlockNode *link;
|
|
|
|
|
|
|
|
for (link = blocklinks[index]; link != NULL; link = link->NextActor)
|
|
|
|
{
|
|
|
|
if (link->Me != mo)
|
|
|
|
{
|
|
|
|
if (P_PointOnDivlineSide (link->Me->x, link->Me->y, &BlockCheckLine) == 0 &&
|
|
|
|
mo->IsOkayToAttack (link->Me))
|
|
|
|
{
|
|
|
|
return link->Me;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-08-03 16:13:23 +00:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// MStaffSpawn2 - for use by mage class boss
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void MStaffSpawn2 (AActor *actor, angle_t angle)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = P_SpawnMissileAngleZ (actor, actor->z+40*FRACUNIT,
|
|
|
|
RUNTIME_CLASS(AMageStaffFX2), angle, 0);
|
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->target = actor;
|
|
|
|
mo->tracer = P_BlockmapSearch (mo, 10, FrontBlockCheck);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MStaffAttack2 - for use by mage class boss
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_MageAttack)
|
2008-08-03 16:13:23 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (!self->target) return;
|
2008-08-03 16:13:23 +00:00
|
|
|
|
|
|
|
angle_t angle;
|
2008-08-10 20:48:55 +00:00
|
|
|
angle = self->angle;
|
|
|
|
MStaffSpawn2 (self, angle);
|
|
|
|
MStaffSpawn2 (self, angle-ANGLE_1*5);
|
|
|
|
MStaffSpawn2 (self, angle+ANGLE_1*5);
|
|
|
|
S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
|
2008-08-03 16:13:23 +00:00
|
|
|
}
|
|
|
|
|