// Angle of the sight cone where the enemy can see Link
CONFIG REDEAD_SIGHT_CONE = 60;
// Random range of colors for scream particles
CONFIG C_REDEAD_SCREAM_PARTICLE_MIN = 0xA1;
CONFIG C_REDEAD_SCREAM_PARTICLE_MAX = 0xA3;
// How frequently status damage ticks
CONFIG REDEAD_STATUS_FREQ = 10;
// Distance from the edge of the scream radius where status will vary
CONFIG REDEAD_STATUS_RANGE = 32;
// Range of stun, being on the edge of the range inflicts less
CONFIG REDEAD_STUN_MIN = 30;
CONFIG REDEAD_STUN_MAX = 120;
// Range of curse, being on the edge of the range inflicts less
CONFIG REDEAD_CURSE_MIN = 2;
CONFIG REDEAD_CURSE_MAX = 5;
// How long redead curse lasts for, -1 for infinite
CONFIG REDEAD_CURSE_DURATION = -1;
// Sounds for each tick of status
CONFIG SFX_REDEAD_STUN_TICK = SFX_EHIT;
CONFIG SFX_REDEAD_CURSE_TICK = SFX_OUCH;
namespace DarkSoulsStatus
{
// Uncomment the following if not using Dark Souls Status
// enum StatusType {POISON, TOXIC, BLEED, FROST, CURSE, NUMSTATUS};
// void FillStatus(int status, int amount, int maxTime)
// {
//
// }
}
@InitD0("Detection Radius"),
@InitDHelp0("How far away you can be when the enemy screams."),
@InitD1("Scream Delay"),
@InitDHelp1("How many frames the enemy pauses before screaming."),
@InitD2("Scream Radius"),
@InitDHelp2("How far the scream extends for."),
@InitD3("Scream Duration"),
@InitDHelp3("How many frames the scream lasts for."),
@InitD4("Scream cooldown"),
@InitDHelp4("How many frames after a scream before the enemy can scream again, with a 1 second random variance added."),
@InitD5("Scream SFX"),
@InitDHelp5("Sound to play when screaming"),
@InitD6("Do Curse?"),
@InitDHelp6("If >0, will inflict curse instead of stun.")
npc script Redead
{
enum Animations
{
ANIM_WALK,
ANIM_SCREAM
};
using namespace NPCAnim;
using namespace GhostBasedMovement;
using namespace DarkSoulsStatus;
void run(int detectionRadius, int screamDelay, int screamRadius, int screamDuration, int screamCooldown, int sfx, bool doCurse)
{
if(!detectionRadius)
detectionRadius = 80;
if(!screamDelay)
screamDelay = 40;
if(!screamRadius)
screamRadius = 64;
if(!screamDuration)
screamDuration = 120;
if(!screamCooldown)
screamCooldown = 180;
AnimHandler aptr = new AnimHandler(this);
aptr->AddAnim(ANIM_WALK, 0, 4, 4, ADF_4WAY);
aptr->AddAnim(ANIM_SCREAM, 20, 4, 4, ADF_4WAY);
Waitspawn(this);
int pDist[64];
int pAng[64];
int pStep[64];
int pTimer[64];
int pColor[64];
int particles[] = {pDist, pAng, pStep, pTimer, pColor};
aptr->PlayAnim(ANIM_WALK);
int cooldown = Floor(screamCooldown/2+Rand(60));
int counter = -1;
while(true)
{
if(cooldown)
--cooldown;
counter = ConstWalk4(this, counter);
if(Distance(this->X, this->Y, Link->X, Link->Y)<detectionRadius&&Sighted(this, REDEAD_SIGHT_CONE/2)&&!cooldown)
{
int dir = this->Dir;
aptr->SetAnimSpeedMultiplier(0);
for(int i=0; i<screamDelay; ++i)
{
this->Dir = AngleDir4(Angle(this->X, this->Y, Link->X, Link->Y));
this->Slide();
Waitframe(this);
}
aptr->SetAnimSpeedMultiplier(1);
UpdateParticles(this, particles, screamRadius, true, 0);
Audio->PlaySound(sfx);
for(int i=0; i<screamDuration; ++i)
{
int dist = Distance(this->X, this->Y, Link->X, Link->Y);
if(dist<screamRadius)
{
int pct = Clamp((screamRadius-dist)/REDEAD_STATUS_RANGE, 0, 1);
if(i%REDEAD_STATUS_FREQ==0)
{
if(doCurse)
{
Audio->PlaySound(SFX_REDEAD_CURSE_TICK);
FillStatus(CURSE, Lerp(REDEAD_CURSE_MIN, REDEAD_CURSE_MAX, pct), REDEAD_CURSE_DURATION);
}
else
{
Audio->PlaySound(SFX_REDEAD_STUN_TICK);
Link->Stun = Floor(Lerp(REDEAD_STUN_MIN, REDEAD_STUN_MAX, pct));
}
}
}
UpdateParticles(this, particles, screamRadius, false, i%4==0?3:0);
this->Slide();
Waitframe(this);
}
this->Dir = dir;
cooldown = screamCooldown+Rand(60);
}
UpdateParticles(this, particles, screamRadius, false, 0);
this->Slide();
Waitframe(this);
}
}
void UpdateParticles(npc this, int[] particles, int radius, bool clear, int create)
{
int pDist = particles[0];
int pAng = particles[1];
int pStep = particles[2];
int pTimer = particles[3];
int pColor = particles[4];
for(int i=0; i<64; ++i)
{
if(pColor[i])
{
pTimer[i] = (pTimer[i]+1)%360;
pDist[i] = Min(pDist[i]+pStep[i], 100);
int dist = (radius+16)*(pDist[i]/100);
int sz = Lerp(2, 0, pDist[i]/100);
int perpDist = Lerp(0, 32, pDist[i]/100)*Sin(pTimer[i]*32);
int x = this->X+8+VectorX(dist, pAng[i])+VectorX(perpDist, pAng[i]+90);
int y = this->Y+8+VectorY(dist, pAng[i])+VectorY(perpDist, pAng[i]+90);
Screen->Circle(6, x, y, sz, pColor[i], 1, 0, 0, 0, true, OP_OPAQUE);
if(pDist[i]>=100)
pColor[i] = 0;
}
else if(create)
{
--create;
pDist[i] = 0;
pAng[i] = Rand(360);
pStep[i] = Rand(5, 10);
pTimer[i] = Rand(360);
pColor[i] = Rand(C_REDEAD_SCREAM_PARTICLE_MIN, C_REDEAD_SCREAM_PARTICLE_MAX);
}
if(clear)
pColor[i] = 0;
}
}
bool Sighted(npc this, int sightAngle)
{
int angLink = Angle(this->X, this->Y, Link->X, Link->Y);
int ang = DirAngle(this->Dir);
return Abs(WrapDegrees(angLink-ang))<=sightAngle;
}
}
Will this work?