scripted_sequences: They sorta work now, needs an engine with
ENGINE_ROUTING enabled however
This commit is contained in:
parent
bb0b4d8f6c
commit
e9326f4e1d
8 changed files with 540 additions and 51 deletions
|
@ -14,11 +14,26 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vector dest;
|
||||
int linkflags;
|
||||
} nodeslist_t;
|
||||
|
||||
/* Begin calculating a route. The callback function will be called once the
|
||||
* route has finished being calculated. The route must be memfreed once it is
|
||||
* no longer needed. The route must be followed in reverse order (ie: the
|
||||
* first node that must be reached is at index numnodes-1).
|
||||
* If no route is available then the callback will be called with no nodes. */
|
||||
void(entity, vector, int, void(entity, vector, int, nodeslist_t *)) route_calculate = #0:route_calculate;
|
||||
|
||||
enum {
|
||||
MONSTER_IDLE,
|
||||
MONSTER_WALK,
|
||||
MONSTER_RUN,
|
||||
MONSTER_DEAD
|
||||
MONSTER_DEAD,
|
||||
MONSTER_INSEQUENCE
|
||||
};
|
||||
|
||||
enumflags {
|
||||
|
@ -44,6 +59,15 @@ class CBaseMonster:CBaseEntity
|
|||
vector base_mins;
|
||||
vector base_maxs;
|
||||
int base_health;
|
||||
float m_flSequenceSpeed;
|
||||
|
||||
/* pathfinding */
|
||||
int m_iNodes;
|
||||
int m_iCurNode;
|
||||
nodeslist_t *m_pRoute;
|
||||
|
||||
/* sequences */
|
||||
string m_strRouteEnded;
|
||||
|
||||
void() CBaseMonster;
|
||||
|
||||
|
@ -59,6 +83,11 @@ class CBaseMonster:CBaseEntity
|
|||
virtual void(string) Sound;
|
||||
virtual float(entity, float) SendEntity;
|
||||
virtual void() ParentUpdate;
|
||||
|
||||
virtual void() ClearRoute;
|
||||
virtual void() CheckRoute;
|
||||
virtual void() WalkRoute;
|
||||
virtual void(vector) NewRoute;
|
||||
};
|
||||
|
||||
void CBaseMonster::Sound(string msg)
|
||||
|
@ -117,6 +146,87 @@ void CBaseMonster::IdleNoise(void)
|
|||
|
||||
}
|
||||
|
||||
void CBaseMonster::ClearRoute(void)
|
||||
{
|
||||
if (m_iNodes) {
|
||||
m_iNodes = 0;
|
||||
memfree(m_pRoute);
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMonster::CheckRoute(void)
|
||||
{
|
||||
float flDist;
|
||||
|
||||
if (!m_iNodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
flDist = floor( vlen( m_pRoute[m_iCurNode].dest - origin ) );
|
||||
|
||||
if ( flDist < 64 ) {
|
||||
print(sprintf("CBaseMonster::CheckNode: %s reached node\n", this.netname));
|
||||
m_iCurNode--;
|
||||
velocity = [0,0,0]; /* clamp friction */
|
||||
}
|
||||
|
||||
if (m_iCurNode < 0) {
|
||||
print(sprintf("CBaseMonster::CheckNode: %s reached end\n", this.netname));
|
||||
/* trigger when required */
|
||||
if (m_strRouteEnded) {
|
||||
for ( entity t = world; ( t = find( t, CBaseTrigger::m_strTargetName, m_strRouteEnded) ); ) {
|
||||
CBaseTrigger trigger = (CBaseTrigger) t;
|
||||
if (trigger.Trigger != __NULL__) {
|
||||
trigger.Trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
ClearRoute();
|
||||
}
|
||||
|
||||
/*if ( flDist == m_flLastDist ) {
|
||||
m_flNodeGiveup += frametime;
|
||||
} else {
|
||||
m_flNodeGiveup = bound( 0, m_flNodeGiveup - frametime, 1.0 );
|
||||
}
|
||||
|
||||
m_flLastDist = flDist;
|
||||
|
||||
if ( m_flNodeGiveup >= 1.0f ) {
|
||||
print(sprintf("CBaseMonster::CheckNode: %s gave up route\n",
|
||||
this.netname));
|
||||
ClearRoute();
|
||||
}*/
|
||||
}
|
||||
|
||||
void CBaseMonster::WalkRoute(void)
|
||||
{
|
||||
if (m_iNodes) {
|
||||
vector endangles;
|
||||
endangles = vectoangles(m_pRoute[m_iCurNode].dest - origin);
|
||||
input_angles[1] = endangles[1];
|
||||
input_movevalues = [m_flSequenceSpeed, 0, 0];
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMonster::NewRoute(vector destination)
|
||||
{
|
||||
/* engine calls this upon successfully creating a route */
|
||||
static void NewRoute_RouteCB(entity ent, vector dest, int numnodes, nodeslist_t *nodelist)
|
||||
{
|
||||
CBaseMonster p = (CBaseMonster)ent;
|
||||
p.m_iNodes = numnodes;
|
||||
p.m_iCurNode = numnodes - 1;
|
||||
p.m_pRoute = nodelist;
|
||||
}
|
||||
|
||||
ClearRoute();
|
||||
|
||||
if (!m_iNodes) {
|
||||
route_calculate(this, destination, 0, NewRoute_RouteCB);
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMonster::Physics(void)
|
||||
{
|
||||
input_movevalues = [0,0,0];
|
||||
|
@ -127,10 +237,19 @@ void CBaseMonster::Physics(void)
|
|||
input_timelength = frametime;
|
||||
movetype = MOVETYPE_WALK;
|
||||
|
||||
CheckRoute();
|
||||
WalkRoute();
|
||||
runstandardplayerphysics(this);
|
||||
movetype = MOVETYPE_NONE;
|
||||
|
||||
IdleNoise();
|
||||
|
||||
/* support for think/nextthink */
|
||||
if (think && nextthink > 0) {
|
||||
if (nextthink < time) {
|
||||
think();
|
||||
nextthink = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseMonster::touch(void)
|
||||
|
|
|
@ -472,6 +472,8 @@ CBaseNPC::Physics(void)
|
|||
}
|
||||
|
||||
input_angles = angles = v_angle;
|
||||
CheckRoute();
|
||||
WalkRoute();
|
||||
input_timelength = frametime;
|
||||
|
||||
runstandardplayerphysics(this);
|
||||
|
|
|
@ -22,18 +22,6 @@
|
|||
Decorative, does nothing yet.
|
||||
*/
|
||||
|
||||
enumflags
|
||||
{
|
||||
MF_WAITTILLSEEN,
|
||||
MF_GAG,
|
||||
MF_MONSTERCLIP,
|
||||
MF_PRISONER,
|
||||
MF_UNUSED,
|
||||
MF_WAITFORSCRIPT,
|
||||
MF_PREDISASTER,
|
||||
MF_FADECORPSE
|
||||
};
|
||||
|
||||
class monster_generic:CBaseEntity
|
||||
{
|
||||
void() monster_generic;
|
||||
|
|
|
@ -85,7 +85,7 @@ class scripted_sequence:CBaseTrigger
|
|||
float m_flSearchRadius;
|
||||
/* How we move to perform m_iActionAnim */
|
||||
int m_iMove;
|
||||
|
||||
|
||||
void() scripted_sequence;
|
||||
virtual void() Trigger;
|
||||
virtual void() Respawn;
|
||||
|
@ -93,7 +93,26 @@ class scripted_sequence:CBaseTrigger
|
|||
|
||||
void scripted_sequence::Trigger(void)
|
||||
{
|
||||
|
||||
CBaseMonster f;
|
||||
|
||||
print(sprintf("^2scripted_sequence::Trigger^7: with spawnflags %d\n", spawnflags));
|
||||
if (m_iMove == SS_WALK) {
|
||||
f = (CBaseMonster)find(world, CBaseEntity::m_strTargetName, m_strMonster);
|
||||
if (f) {
|
||||
f.NewRoute(origin);
|
||||
f.style = MONSTER_INSEQUENCE;
|
||||
f.m_flSequenceSpeed = 64;
|
||||
f.m_strRouteEnded = m_strTarget;
|
||||
}
|
||||
} else if (m_iMove == SS_RUN) {
|
||||
f = (CBaseMonster)find(world, CBaseEntity::m_strTargetName, m_strMonster);
|
||||
if (f) {
|
||||
f.NewRoute(origin);
|
||||
f.style = MONSTER_INSEQUENCE;
|
||||
f.m_flSequenceSpeed = 256;
|
||||
f.m_strRouteEnded = m_strTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scripted_sequence::Respawn(void)
|
||||
|
@ -106,6 +125,9 @@ void scripted_sequence::scripted_sequence(void)
|
|||
int nfields = tokenize(__fullspawndata);
|
||||
for (int i = 1; i < (nfields-1); i += 2) {
|
||||
switch (argv(i)) {
|
||||
case "target":
|
||||
m_strTarget = argv(i+1);
|
||||
break;
|
||||
case "m_iszEntity":
|
||||
m_strMonster = argv(i+1);
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
/* parse info_node entities and convert them to FTE compatible routing data */
|
||||
#define NODE_DEBUG 1
|
||||
|
||||
typedef struct node_s {
|
||||
vector origin;
|
||||
|
@ -76,6 +77,45 @@ Nodes_Save(string filename)
|
|||
fclose(wayfile);
|
||||
}
|
||||
|
||||
void
|
||||
Nodes_Load(string filename)
|
||||
{
|
||||
float wayfile = fopen(filename, FILE_READ);
|
||||
|
||||
if (wayfile < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* wipe whatever we've got */
|
||||
for (int i = 0; i < g_iNodes; i++) {
|
||||
memfree(g_pNodes[i].nb);
|
||||
}
|
||||
memfree(g_pNodes);
|
||||
g_iNodes = 0;
|
||||
|
||||
tokenize(fgets(wayfile));
|
||||
g_iNodes = stoi(argv(0));
|
||||
g_pNodes = memalloc(sizeof(*g_pNodes) * g_iNodes);
|
||||
|
||||
for (int i = 0; i < g_iNodes; i++) {
|
||||
tokenize(fgets(wayfile));
|
||||
g_pNodes[i].origin[0] = stof(argv(0));
|
||||
g_pNodes[i].origin[1] = stof(argv(1));
|
||||
g_pNodes[i].origin[2] = stof(argv(2));
|
||||
g_pNodes[i].radius = stof(argv(3));
|
||||
g_pNodes[i].nb_count = stoi(argv(4));
|
||||
g_pNodes[i].nb = memalloc(sizeof(*g_pNodes[i].nb) * g_pNodes[i].nb_count);
|
||||
|
||||
for (int j = 0; j < g_pNodes[i].nb_count; j++) {
|
||||
tokenize(fgets(wayfile));
|
||||
g_pNodes[i].nb[j].node = stoi(argv(0));
|
||||
g_pNodes[i].nb[j].dist = stof(argv(1));
|
||||
g_pNodes[i].nb[j].flags = stoh(argv(2));
|
||||
}
|
||||
}
|
||||
fclose(wayfile);
|
||||
}
|
||||
|
||||
/* link two nodes together */
|
||||
static void
|
||||
Node_Link(node_t *n1, node_t *n2)
|
||||
|
@ -138,6 +178,9 @@ Nodes_Init(void)
|
|||
/* skip if present. TODO: check if they're out of date? */
|
||||
if (whichpack(sprintf("data/%s.way", mapname))) {
|
||||
g_nodes_present = TRUE;
|
||||
#ifdef NODE_DEBUG
|
||||
Nodes_Load(sprintf("%s.way", mapname));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -159,8 +202,8 @@ Nodes_Init(void)
|
|||
|
||||
Nodes_Save(sprintf("%s.way", mapname));
|
||||
|
||||
#ifndef GS_DEVELOPER
|
||||
/* we don't need these any longer */
|
||||
#ifndef NODE_DEBUG
|
||||
for (int i = 0; i < g_iNodes; i++) {
|
||||
memfree(g_pNodes[i].nb);
|
||||
}
|
||||
|
@ -169,11 +212,11 @@ Nodes_Init(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef NODE_DEBUG
|
||||
/* draws debug graphics of our node tree */
|
||||
void
|
||||
SV_AddDebugPolygons(void)
|
||||
{
|
||||
#ifdef GS_DEVELOPER
|
||||
if (!g_iNodes) {
|
||||
return;
|
||||
}
|
||||
|
@ -232,5 +275,5 @@ SV_AddDebugPolygons(void)
|
|||
R_EndPolygon();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,18 +20,172 @@ Gonarch
|
|||
|
||||
*/
|
||||
|
||||
enum {
|
||||
GON_IDLE,
|
||||
GON_IDLE2,
|
||||
GON_WALK,
|
||||
GON_RUN,
|
||||
GON_DIE,
|
||||
GON_CLAW,
|
||||
GON_CLAW2,
|
||||
GON_CLAW3,
|
||||
GON_SPAWN,
|
||||
GON_SHOOT,
|
||||
GON_FLINCH,
|
||||
GON_DEFEND,
|
||||
GON_JUMP,
|
||||
GON_ANGRY,
|
||||
GON_ANGRY2,
|
||||
GON_ANGRY3,
|
||||
GON_BREAKWALL,
|
||||
GON_FALL,
|
||||
GON_FALL2,
|
||||
GON_FALLDIE
|
||||
};
|
||||
|
||||
/* the attack sounds are for when she spits? */
|
||||
string gon_sndattack[] = {
|
||||
"gonarch/gon_attack1.wav",
|
||||
"gonarch/gon_attack2.wav",
|
||||
"gonarch/gon_attack3.wav"
|
||||
};
|
||||
|
||||
/* mourns the death of her children */
|
||||
string gon_sndchild[] = {
|
||||
"gonarch/gon_childdie1.wav",
|
||||
"gonarch/gon_childdie2.wav",
|
||||
"gonarch/gon_childdie3.wav"
|
||||
};
|
||||
|
||||
string gon_snddie[] = {
|
||||
"gonarch/gon_die1.wav",
|
||||
"gonarch/gon_die2.wav",
|
||||
"gonarch/gon_die3.wav"
|
||||
};
|
||||
|
||||
string gon_sndidle[] = {
|
||||
"gonarch/gon_sack1.wav",
|
||||
"gonarch/gon_sack2.wav",
|
||||
"gonarch/gon_sack3.wav"
|
||||
};
|
||||
|
||||
string gon_sndpain[] = {
|
||||
"gonarch/gon_pain2.wav",
|
||||
"gonarch/gon_pain3.wav",
|
||||
"gonarch/gon_pain4.wav",
|
||||
"gonarch/gon_pain5.wav"
|
||||
};
|
||||
|
||||
string gon_sndsee[] = {
|
||||
"gonarch/gon_alert1.wav",
|
||||
"gonarch/gon_alert2.wav",
|
||||
"gonarch/gon_alert3.wav"
|
||||
};
|
||||
|
||||
/* has unique foot step sounds */
|
||||
string gon_sndstep[] = {
|
||||
"gonarch/gon_step1.wav",
|
||||
"gonarch/gon_step2.wav",
|
||||
"gonarch/gon_step3.wav"
|
||||
};
|
||||
|
||||
class monster_bigmomma:CBaseMonster
|
||||
{
|
||||
float m_flIdleTime;
|
||||
float m_flPainTime;
|
||||
|
||||
void() monster_bigmomma;
|
||||
|
||||
virtual void(int) Death;
|
||||
virtual void(int) Pain;
|
||||
virtual void(void) IdleNoise;
|
||||
virtual void(void) Respawn;
|
||||
};
|
||||
|
||||
void
|
||||
monster_bigmomma::IdleNoise(void)
|
||||
{
|
||||
/* don't make noise if we're dead (corpse) */
|
||||
if (style == MONSTER_DEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_flIdleTime > time) {
|
||||
return;
|
||||
}
|
||||
/* timing needs to adjusted as sounds conflict */
|
||||
m_flIdleTime = time + 2.0f + random(0,5);
|
||||
|
||||
int rand = floor(random(0, gon_sndidle.length));
|
||||
Sound(gon_sndidle[rand]);
|
||||
}
|
||||
|
||||
void
|
||||
monster_bigmomma::Pain(int iHitBody)
|
||||
{
|
||||
CBaseMonster::Pain(iHitBody);
|
||||
|
||||
if (m_flPainTime > time) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (random() < 0.25f) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rand = floor(random(0,gon_sndpain.length));
|
||||
Sound(gon_sndpain[rand]);
|
||||
frame = GON_FLINCH;
|
||||
m_flPainTime = time + 0.25f;
|
||||
}
|
||||
|
||||
void
|
||||
monster_bigmomma::Death(int iHitBody)
|
||||
{
|
||||
/* if we're already dead (corpse) don't change animations */
|
||||
if (style != MONSTER_DEAD) {
|
||||
frame = GON_DIE;
|
||||
Sound("gonarch/gon_die1.wav");
|
||||
}
|
||||
|
||||
/* set the functional differences */
|
||||
CBaseMonster::Death(iHitBody);
|
||||
}
|
||||
|
||||
void
|
||||
monster_bigmomma::Respawn(void)
|
||||
{
|
||||
CBaseMonster::Respawn();
|
||||
frame = GON_IDLE;
|
||||
}
|
||||
|
||||
void monster_bigmomma::monster_bigmomma(void)
|
||||
{
|
||||
for (int i = 0; i <gon_sndattack.length; i++) {
|
||||
precache_sound(gon_sndattack[i]);
|
||||
}
|
||||
for (int i = 0; i <gon_sndchild.length; i++) {
|
||||
precache_sound(gon_sndchild[i]);
|
||||
}
|
||||
for (int i = 0; i < gon_sndidle.length; i++) {
|
||||
precache_sound(gon_sndidle[i]);
|
||||
}
|
||||
for (int i = 0; i < gon_sndpain.length; i++) {
|
||||
precache_sound(gon_sndpain[i]);
|
||||
}
|
||||
for (int i = 0; i <gon_sndsee.length; i++) {
|
||||
precache_sound(gon_sndsee[i]);
|
||||
}
|
||||
for (int i = 0; i <gon_sndstep.length; i++) {
|
||||
precache_sound(gon_sndstep[i]);
|
||||
}
|
||||
|
||||
precache_sound("gonarch/gon_die1.wav");
|
||||
|
||||
netname = "Gonarch";
|
||||
model = "models/big_mom.mdl";
|
||||
/* health is based on factor, for it's not killable until last stage
|
||||
* base_health = Skill_GetValue("bigmomma_health");
|
||||
*/
|
||||
/* health is based on factor, for it's not killable until last stage */
|
||||
base_health = Skill_GetValue("bigmomma_health_factor") * 300;
|
||||
base_mins = [-95,-95,0];
|
||||
base_maxs = [95,95,190];
|
||||
CBaseMonster::CBaseMonster();
|
||||
|
|
|
@ -21,23 +21,75 @@ Leech
|
|||
*/
|
||||
|
||||
enum {
|
||||
LE_SWIM,
|
||||
LE_SWIM2,
|
||||
LE_ATTACK,
|
||||
LE_HOVER,
|
||||
LE_LEFT,
|
||||
LE_RIGHT,
|
||||
LE_DIE,
|
||||
LE_DIEEND
|
||||
LEECH_SWIM,
|
||||
LEECH_SWIM2,
|
||||
LEECH_ATTACK,
|
||||
LEECH_HOVER,
|
||||
LEECH_LEFT,
|
||||
LEECH_RIGHT,
|
||||
LEECH_DIE,
|
||||
LEECH_DIEEND
|
||||
};
|
||||
|
||||
string leech_sndattack[] = {
|
||||
"leech/leech_bite1.wav",
|
||||
"leech/leech_bite2.wav",
|
||||
"leech/leech_bite3.wav"
|
||||
};
|
||||
|
||||
string leech_sndsee[] = {
|
||||
"leech/leech_alert1.wav",
|
||||
"leech/leech_alert2.wav"
|
||||
};
|
||||
|
||||
class monster_leech:CBaseMonster
|
||||
{
|
||||
float m_flIdleTime;
|
||||
float m_flPainTime;
|
||||
|
||||
void() monster_leech;
|
||||
|
||||
virtual void(int) Death;
|
||||
virtual void() DeathEnd;
|
||||
virtual void() Respawn;
|
||||
};
|
||||
|
||||
void
|
||||
monster_leech::DeathEnd(void)
|
||||
{
|
||||
frame = LEECH_DIEEND;
|
||||
}
|
||||
|
||||
void
|
||||
monster_leech::Death(int iHitBody)
|
||||
{
|
||||
/* if we're already dead (corpse) don't change animations */
|
||||
if (style != MONSTER_DEAD) {
|
||||
frame = LEECH_DIE;
|
||||
think = DeathEnd;
|
||||
nextthink = time + 1.0f;
|
||||
}
|
||||
|
||||
/* set the functional differences */
|
||||
CBaseMonster::Death(iHitBody);
|
||||
}
|
||||
|
||||
void
|
||||
monster_leech::Respawn(void)
|
||||
{
|
||||
CBaseMonster::Respawn();
|
||||
frame = LEECH_SWIM;
|
||||
}
|
||||
|
||||
void monster_leech::monster_leech(void)
|
||||
{
|
||||
for (int i = 0; i <leech_sndattack.length; i++) {
|
||||
precache_sound(leech_sndattack[i]);
|
||||
}
|
||||
for (int i = 0; i < leech_sndsee.length; i++) {
|
||||
precache_sound(leech_sndsee[i]);
|
||||
}
|
||||
|
||||
netname = "Leech";
|
||||
model = "models/leech.mdl";
|
||||
base_mins = [-6,-6,0];
|
||||
|
|
|
@ -21,36 +21,145 @@ Nihilanth
|
|||
*/
|
||||
|
||||
enum {
|
||||
NIH_IDLE,
|
||||
NIH_ATTACK,
|
||||
NIH_ATTACK2,
|
||||
NIH_THROW,
|
||||
NIH_BLOCK,
|
||||
NIH_RECHARGE,
|
||||
NIH_IDLEOPEN,
|
||||
NIH_ATTACKOPEN,
|
||||
NIH_ATTACKOPEN2,
|
||||
NIH_FLINCH,
|
||||
NIH_FLINCH2,
|
||||
NIH_FALL,
|
||||
NIH_DIE,
|
||||
NIH_FORWARD,
|
||||
NIH_BACK,
|
||||
NIH_UP,
|
||||
NIH_DOWN,
|
||||
NIH_RIGHT,
|
||||
NIH_LEFT,
|
||||
NIH_WALK2,
|
||||
NIH_SHOOT
|
||||
NIL_IDLE,
|
||||
NIL_ATTACK,
|
||||
NIL_ATTACK2,
|
||||
NIL_THROW,
|
||||
NIL_BLOCK,
|
||||
NIL_RECHARGE,
|
||||
NIL_IDLEOPEN,
|
||||
NIL_ATTACKOPEN,
|
||||
NIL_ATTACKOPEN2,
|
||||
NIL_FLINCH,
|
||||
NIL_FLINCH2,
|
||||
NIL_FALL,
|
||||
NIL_DIE,
|
||||
NIL_FORWARD,
|
||||
NIL_BACK,
|
||||
NIL_UP,
|
||||
NIL_DOWN,
|
||||
NIL_RIGHT,
|
||||
NIL_LEFT,
|
||||
NIL_WALK2,
|
||||
NIL_SHOOT
|
||||
};
|
||||
|
||||
/* other sounds
|
||||
* x_ballattack1 - the portal he casts
|
||||
* x_shoot1 - ?
|
||||
* x_teleattack1 - portal's move sound
|
||||
* nih_die2 - used in map not code? */
|
||||
|
||||
/* these attack sounds are his growls */
|
||||
string nil_sndattack[] = {
|
||||
"x/x_attack1.wav",
|
||||
"x/x_attack2.wav",
|
||||
"x/x_attack3.wav"
|
||||
};
|
||||
|
||||
string nil_sndidle[] = {
|
||||
"x/x_laugh1.wav",
|
||||
"x/x_laugh2.wav"
|
||||
};
|
||||
|
||||
string nil_sndpain[] = {
|
||||
"x/x_pain1.wav",
|
||||
"x/x_pain2.wav",
|
||||
"x/x_pain3.wav"
|
||||
};
|
||||
|
||||
string nil_sndrecharge[] = {
|
||||
"x/x_recharge1.wav",
|
||||
"x/x_recharge2.wav",
|
||||
"x/x_recharge3.wav"
|
||||
};
|
||||
|
||||
class monster_nihilanth:CBaseMonster
|
||||
{
|
||||
float m_flIdleTime;
|
||||
float m_flPainTime;
|
||||
|
||||
void() monster_nihilanth;
|
||||
|
||||
virtual void(int) Death;
|
||||
virtual void(int) Pain;
|
||||
virtual void(void) IdleNoise;
|
||||
virtual void(void) Respawn;
|
||||
};
|
||||
|
||||
void
|
||||
monster_nihilanth::IdleNoise(void)
|
||||
{
|
||||
/* don't make noise if we're dead (corpse) */
|
||||
if (style == MONSTER_DEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_flIdleTime > time) {
|
||||
return;
|
||||
}
|
||||
/* timing needs to adjusted as sounds conflict */
|
||||
m_flIdleTime = time + 2.0f + random(0,5);
|
||||
|
||||
int rand = floor(random(0, nil_sndidle.length));
|
||||
Sound(nil_sndidle[rand]);
|
||||
}
|
||||
|
||||
void
|
||||
monster_nihilanth::Pain(int iHitBody)
|
||||
{
|
||||
CBaseMonster::Pain(iHitBody);
|
||||
|
||||
if (m_flPainTime > time) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (random() < 0.25f) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rand = floor(random(0,nil_sndpain.length));
|
||||
Sound(nil_sndpain[rand]);
|
||||
|
||||
frame = (random() < 0.5) ? NIL_FLINCH : NIL_FLINCH2;
|
||||
m_flPainTime = time + 0.25f;
|
||||
}
|
||||
|
||||
void
|
||||
monster_nihilanth::Death(int iHitBody)
|
||||
{
|
||||
/* if we're already dead (corpse) don't change animations */
|
||||
if (style != MONSTER_DEAD) {
|
||||
frame = NIL_DIE;
|
||||
Sound("x/x_die1.wav");
|
||||
}
|
||||
|
||||
/* set the functional differences */
|
||||
CBaseMonster::Death(iHitBody);
|
||||
}
|
||||
|
||||
void
|
||||
monster_nihilanth::Respawn(void)
|
||||
{
|
||||
CBaseMonster::Respawn();
|
||||
frame = NIL_IDLE;
|
||||
}
|
||||
|
||||
void monster_nihilanth::monster_nihilanth(void)
|
||||
{
|
||||
for (int i = 0; i <nil_sndattack.length; i++) {
|
||||
precache_sound(nil_sndattack[i]);
|
||||
}
|
||||
for (int i = 0; i < nil_sndidle.length; i++) {
|
||||
precache_sound(nil_sndidle[i]);
|
||||
}
|
||||
for (int i = 0; i < nil_sndpain.length; i++) {
|
||||
precache_sound(nil_sndpain[i]);
|
||||
}
|
||||
for (int i = 0; i < nil_sndrecharge.length; i++) {
|
||||
precache_sound(nil_sndrecharge[i]);
|
||||
}
|
||||
|
||||
netname = "Nihilanth";
|
||||
model = "models/nihilanth.mdl";
|
||||
base_health = Skill_GetValue("nihilanth_health");
|
||||
|
|
Loading…
Reference in a new issue