mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
8401c475f6
Added powerarmortype field to default Lazaus DLL. This changes the savegame version. Added support for blood_type value of 4 to default Lazaurus, missionpack, and Zaero DLLs. Added support for Lazarus initially dead monsters (health < 0) to missionpack DLL. Added support for Lazarus monsterjump cvar (berserk, gunner, infantry, mutant, parasite) to missionpack DLL. Cleaned up surface rendering code from mpolyvertex_t refactoring.
1314 lines
32 KiB
C
1314 lines
32 KiB
C
/*
|
|
==============================================================================
|
|
|
|
SETNTIEN
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#include "g_local.h"
|
|
#include "z_anim.h"
|
|
#include "z_sentien.h"
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien laser routines ... adapted from Zaero g_target.c
|
|
=========================================================================*/
|
|
void sentien_laser_think (edict_t *self)
|
|
{
|
|
edict_t *ignore;
|
|
vec3_t start;
|
|
vec3_t end;
|
|
trace_t tr;
|
|
vec3_t point;
|
|
vec3_t last_movedir;
|
|
int count;
|
|
|
|
if (self->spawnflags & 0x80000000)
|
|
count = 8;
|
|
else
|
|
count = 4;
|
|
|
|
if (self->enemy)
|
|
{
|
|
VectorCopy (self->movedir, last_movedir);
|
|
VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
|
|
VectorSubtract (point, self->s.origin, self->movedir);
|
|
VectorNormalize (self->movedir);
|
|
if (!VectorCompare(self->movedir, last_movedir))
|
|
self->spawnflags |= 0x80000000;
|
|
}
|
|
|
|
ignore = self;
|
|
VectorCopy (self->s.origin, start);
|
|
VectorMA (start, 2048, self->movedir, end);
|
|
while(1)
|
|
{
|
|
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
|
|
|
|
if (!tr.ent)
|
|
break;
|
|
|
|
// hurt it if we can
|
|
if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
|
|
T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER);
|
|
|
|
// if we hit something that's not a monster or player or is immune to lasers, we're done
|
|
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
|
|
{
|
|
if (self->spawnflags & 0x80000000)
|
|
{
|
|
self->spawnflags &= ~0x80000000;
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_LASER_SPARKS);
|
|
gi.WriteByte (count);
|
|
gi.WritePosition (tr.endpos);
|
|
gi.WriteDir (tr.plane.normal);
|
|
gi.WriteByte (self->s.skinnum);
|
|
gi.multicast (tr.endpos, MULTICAST_PVS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
ignore = tr.ent;
|
|
VectorCopy (tr.endpos, start);
|
|
}
|
|
|
|
VectorCopy (tr.endpos, self->s.old_origin);
|
|
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
|
|
void sentien_laser_on (edict_t *self)
|
|
{
|
|
if (!self->activator)
|
|
self->activator = self;
|
|
self->spawnflags |= 0x80000001;
|
|
self->svflags &= ~SVF_NOCLIENT;
|
|
sentien_laser_think (self);
|
|
}
|
|
|
|
void sentien_laser_off (edict_t *self)
|
|
{
|
|
self->spawnflags &= ~1;
|
|
self->svflags |= SVF_NOCLIENT;
|
|
self->nextthink = 0;
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien sound routines ... used from animation frames (and code).
|
|
=========================================================================*/
|
|
static int sound_idle1;
|
|
static int sound_idle2;
|
|
static int sound_idle3;
|
|
static int sound_walk;
|
|
static int sound_fend;
|
|
static int sound_pain1;
|
|
static int sound_pain2;
|
|
static int sound_pain3;
|
|
static int sound_die1;
|
|
static int sound_die2;
|
|
static int sound_att1;
|
|
static int sound_att2;
|
|
static int sound_att3;
|
|
|
|
void sentien_sound_footstep (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_walk, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentien_sound_idle1 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_idle1, 1, ATTN_IDLE, 0);
|
|
}
|
|
|
|
void sentien_sound_idle2 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_idle2, 1, ATTN_IDLE, 0);
|
|
}
|
|
|
|
void sentien_sound_idle3 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_idle3, 1, ATTN_IDLE, 0);
|
|
}
|
|
|
|
void sentian_sound_att1 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_att1, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_att2 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_att2, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_att3 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_att3, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_fend (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_fend, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_pain1 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_pain1, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_pain2 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_pain2, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_pain3 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_pain3, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_die1 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_die1, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void sentian_sound_die2 (edict_t *self)
|
|
{
|
|
gi.sound(self, CHAN_BODY, sound_die2, 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien standing frames
|
|
=========================================================================*/
|
|
mframe_t sentien_frames_stand1 []=
|
|
{
|
|
ai_stand, 0, sentien_sound_idle1,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_stand2 []=
|
|
{
|
|
ai_stand, 0, sentien_sound_idle2,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
};
|
|
|
|
mframe_t sentien_frames_stand3 []=
|
|
{
|
|
ai_stand, 0, sentien_sound_idle1,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
};
|
|
|
|
void sentien_stand(edict_t *self);
|
|
void sentien_stand_whatnow(edict_t *self);
|
|
void sentien_stand_earwax(edict_t *self);
|
|
|
|
mmove_t sentien_move_stand1 = {FRAME_stand1start, FRAME_stand1end,
|
|
sentien_frames_stand1, sentien_stand_whatnow};
|
|
|
|
mmove_t sentien_move_stand2 = {FRAME_stand2start, FRAME_stand2end,
|
|
sentien_frames_stand2, sentien_stand_whatnow};
|
|
|
|
mmove_t sentien_move_stand3 = {FRAME_stand3start, FRAME_stand3end,
|
|
sentien_frames_stand3, sentien_stand_earwax};
|
|
|
|
void sentien_stand(edict_t *self)
|
|
{
|
|
sentien_laser_off (self->flash);
|
|
|
|
self->monsterinfo.currentmove = &sentien_move_stand1;
|
|
}
|
|
|
|
void sentien_stand_whatnow (edict_t *self)
|
|
{
|
|
float r;
|
|
r = random();
|
|
|
|
if (r < self->random)
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_stand1;
|
|
self->random -= 0.05;
|
|
}
|
|
else
|
|
{
|
|
r = random();
|
|
if (r < 0.5)
|
|
self->monsterinfo.currentmove = &sentien_move_stand2;
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_stand3;
|
|
|
|
self->random = 1;
|
|
}
|
|
}
|
|
|
|
void sentien_stand_earwax (edict_t *self)
|
|
{
|
|
if (random() > 0.80)
|
|
{
|
|
//more ear wax damn it, try again
|
|
self->monsterinfo.currentmove = &sentien_move_stand3;
|
|
//gi.sound ... some frustration maybe
|
|
}
|
|
else
|
|
sentien_stand_whatnow(self);
|
|
}
|
|
|
|
/*=========================================================================
|
|
Sentien walking frames
|
|
=========================================================================*/
|
|
mframe_t sentien_frames_walk_start []=
|
|
{
|
|
ai_walk, 0.0, NULL,
|
|
ai_walk, 1.5, NULL,
|
|
ai_walk, 2.9, NULL,
|
|
ai_walk, 2.4, NULL,
|
|
ai_walk, 2.1, NULL,
|
|
ai_walk, 2.6, NULL,
|
|
ai_walk, 2.1, NULL,
|
|
ai_walk, 1.8, sentien_sound_footstep,
|
|
//ai_walk, 0.3, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_walk []=
|
|
{
|
|
ai_walk, 0.3, NULL,
|
|
ai_walk, 2.4, NULL,
|
|
ai_walk, 4.0, NULL,
|
|
ai_walk, 3.5, NULL,
|
|
ai_walk, 3.6, NULL,
|
|
ai_walk, 3.7 * 1.1, NULL,
|
|
ai_walk, 3.1 * 1.3, NULL,
|
|
ai_walk, 4.1 * 1.2, sentien_sound_footstep,
|
|
//ai_walk, 2.0, NULL, // change leg
|
|
|
|
ai_walk, 2.0, NULL,
|
|
ai_walk, 2.6, NULL, // 2.4
|
|
ai_walk, 3.8, NULL, // 3.9
|
|
ai_walk, 3.6, NULL,
|
|
ai_walk, 3.6, NULL,
|
|
ai_walk, 4.3, NULL,
|
|
ai_walk, 4.2 * 1.2, NULL,
|
|
ai_walk, 5.2, sentien_sound_footstep, // 4.1
|
|
//ai_walk, 0.8, NULL // 2.0 change leg
|
|
};
|
|
|
|
mframe_t sentien_frames_walk_end []=
|
|
{
|
|
ai_walk, 0.8, NULL,
|
|
ai_walk, 1.0, NULL,
|
|
ai_walk, 1.6, NULL,
|
|
ai_walk, 1.4, NULL,
|
|
ai_walk, 1.5, NULL,
|
|
ai_walk, 1.4, NULL,
|
|
ai_walk, 1.5, NULL,
|
|
ai_walk, 1.8, sentien_sound_footstep,
|
|
//ai_walk, 2.3, NULL // ??? I dunno about that one (Max)
|
|
};
|
|
|
|
void sentien_walk (edict_t *self);
|
|
|
|
mmove_t sentien_move_walk_start = {FRAME_walkStartStart, FRAME_walkStartEnd,
|
|
sentien_frames_walk_start, sentien_walk};
|
|
|
|
mmove_t sentien_move_walk = {FRAME_walkLoopStart, FRAME_walkLoopEnd,
|
|
sentien_frames_walk, NULL};
|
|
|
|
mmove_t sentien_move_walk_end = {FRAME_walkEndStart, FRAME_walkEndEnd,
|
|
sentien_frames_walk_end, sentien_stand};
|
|
|
|
void sentien_walk (edict_t *self)
|
|
{
|
|
sentien_laser_off (self->flash);
|
|
|
|
if (self->monsterinfo.currentmove == &sentien_move_walk)
|
|
return;
|
|
|
|
if (self->monsterinfo.currentmove == &sentien_move_stand1 ||
|
|
self->monsterinfo.currentmove == &sentien_move_stand2 ||
|
|
self->monsterinfo.currentmove == &sentien_move_stand3)
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_walk_start;
|
|
}
|
|
else
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_walk;
|
|
}
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien running frames
|
|
=========================================================================*/
|
|
mframe_t sentien_frames_run_start []=
|
|
{
|
|
ai_run, 0.0, NULL,
|
|
ai_run, 1.5, NULL,
|
|
ai_run, 2.9, NULL,
|
|
ai_run, 2.4, NULL,
|
|
ai_run, 2.1, NULL,
|
|
ai_run, 2.6, NULL,
|
|
ai_run, 2.1, NULL,
|
|
ai_run, 1.8, sentien_sound_footstep,
|
|
//ai_run, 0.3, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_run []=
|
|
{
|
|
ai_run, 0.3 * 1.2, NULL,
|
|
ai_run, 2.4, NULL,
|
|
ai_run, 4.0, NULL,
|
|
ai_run, 3.5, NULL,
|
|
ai_run, 3.6, NULL,
|
|
ai_run, 3.7 * 1.1, NULL,
|
|
ai_run, 3.1 * 1.3, NULL,
|
|
ai_run, 4.1 * 1.2, sentien_sound_footstep,
|
|
//ai_run, 2.0, NULL, // change leg
|
|
|
|
ai_run, 2.0, NULL,
|
|
ai_run, 2.6, NULL, // 2.4
|
|
ai_run, 3.8, NULL, // 3.9
|
|
ai_run, 3.6, NULL,
|
|
ai_run, 3.6, NULL,
|
|
ai_run, 4.3, NULL,
|
|
ai_run, 4.2 * 1.2, NULL,
|
|
ai_run, 5.2, sentien_sound_footstep, // 4.1
|
|
//ai_run, 0.8, NULL // 2.0 change leg
|
|
};
|
|
|
|
mframe_t sentien_frames_run_end []=
|
|
{
|
|
ai_run, 0.8, NULL,
|
|
ai_run, 1.0, NULL,
|
|
ai_run, 1.6, NULL,
|
|
ai_run, 1.4, NULL,
|
|
ai_run, 1.5, NULL,
|
|
ai_run, 1.4, NULL,
|
|
ai_run, 1.5, NULL,
|
|
ai_run, 1.8, sentien_sound_footstep,
|
|
//ai_run, 2.3, NULL // ??? I dunno about that one (Max)
|
|
};
|
|
|
|
void sentien_run(edict_t *self);
|
|
|
|
mmove_t sentien_move_run_start = {FRAME_walkStartStart, FRAME_walkStartEnd,
|
|
sentien_frames_run_start, sentien_run};
|
|
|
|
mmove_t sentien_move_run = {FRAME_walkLoopStart, FRAME_walkLoopEnd,
|
|
sentien_frames_run, NULL};
|
|
|
|
mmove_t sentien_move_run_end = {FRAME_walkEndStart, FRAME_walkEndEnd,
|
|
sentien_frames_run_end, sentien_stand};
|
|
|
|
void sentien_run (edict_t *self)
|
|
{
|
|
sentien_laser_off (self->flash);
|
|
|
|
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_stand1;
|
|
return;
|
|
}
|
|
|
|
if (self->monsterinfo.currentmove == &sentien_move_run)
|
|
return;
|
|
|
|
if (self->monsterinfo.currentmove == &sentien_move_walk ||
|
|
self->monsterinfo.currentmove == &sentien_move_run_start)
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_run;
|
|
}
|
|
else
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_run_start;
|
|
}
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien blaster attack.
|
|
=========================================================================*/
|
|
void sentien_do_blast(edict_t *self);
|
|
|
|
mframe_t sentien_frames_pre_blast_attack []=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_blast_attack []=
|
|
{
|
|
ai_charge, 0, sentien_do_blast,
|
|
ai_charge, 0, sentien_do_blast,
|
|
ai_charge, 0, sentien_do_blast,
|
|
ai_charge, 0, sentien_do_blast,
|
|
ai_charge, 0, sentien_do_blast,
|
|
ai_charge, 0, sentien_do_blast,
|
|
};
|
|
|
|
mframe_t sentien_frames_post_blast_attack []=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
};
|
|
|
|
void sentien_blast_attack(edict_t *self);
|
|
void sentien_post_blast_attack(edict_t *self);
|
|
|
|
mmove_t sentien_move_pre_blast_attack = { FRAME_blastPreStart, FRAME_blastPreEnd,
|
|
sentien_frames_pre_blast_attack, sentien_blast_attack};
|
|
|
|
void sentien_post_blast_attack(edict_t *self);
|
|
mmove_t sentien_move_blast_attack = { FRAME_blastStart, FRAME_blastEnd,
|
|
sentien_frames_blast_attack, sentien_post_blast_attack};
|
|
|
|
mmove_t sentien_move_post_blast_attack = { FRAME_blastPostStart, FRAME_blastPostEnd,
|
|
sentien_frames_post_blast_attack, sentien_run};
|
|
|
|
void sentien_blast_attack (edict_t *self)
|
|
{
|
|
sentien_laser_off (self->flash);
|
|
|
|
self->monsterinfo.currentmove = &sentien_move_blast_attack;
|
|
|
|
// is a player right infront?
|
|
if (visible(self, self->enemy) &&
|
|
infront(self, self->enemy))
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_blast_attack;
|
|
}
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_post_blast_attack;
|
|
}
|
|
|
|
|
|
void sentien_post_blast_attack (edict_t *self)
|
|
{
|
|
float refire = 0.25;
|
|
|
|
if (visible(self, self->enemy) &&
|
|
infront(self, self->enemy))
|
|
{
|
|
if (skill->value == 1)
|
|
refire = 0.40;
|
|
else if (skill->value == 2)
|
|
refire = 0.60;
|
|
else if (skill->value >= 3)
|
|
refire = 0.75;
|
|
|
|
if (random() > refire)
|
|
self->monsterinfo.currentmove = &sentien_move_post_blast_attack;
|
|
}
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_post_blast_attack;
|
|
}
|
|
|
|
void sentien_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage)
|
|
{
|
|
if (EMPNukeCheck(self, self->s.origin))
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
|
|
ANIM_AIM(self, dir);
|
|
fire_bullet (self, start, dir, 2, 4,
|
|
DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD,
|
|
MOD_UNKNOWN);
|
|
|
|
sentian_sound_att1(self);
|
|
}
|
|
|
|
vec3_t sentien_flash_offset [] =
|
|
{
|
|
// frames 116+ (hex fire)
|
|
23.7, 25.4, 29.6,
|
|
23.7, 25.3, 26.7,
|
|
23.7, 27.7, 28.1,
|
|
23.7, 27.4, 31.2,
|
|
23.7, 24.9, 32.3,
|
|
23.7, 22.5, 30.6,
|
|
23.7, 22.7, 27.8
|
|
};
|
|
|
|
void sentien_do_blast (edict_t *self)
|
|
{
|
|
vec3_t start;
|
|
vec3_t forward, right;
|
|
vec3_t aim;
|
|
vec3_t end;
|
|
int idx;
|
|
|
|
idx = self->s.frame - FRAME_blastStart + 1;
|
|
|
|
AngleVectors (self->s.angles, forward, right, NULL);
|
|
|
|
G_ProjectSource (self->s.origin, sentien_flash_offset[0],
|
|
forward, right, start);
|
|
|
|
VectorCopy (self->enemy->s.origin, end);
|
|
end[2] += self->enemy->viewheight;
|
|
VectorSubtract (end, start, aim);
|
|
|
|
//need to compare aim with facing to make sure we are not
|
|
//aiming too far sideways and correct if we are.
|
|
|
|
G_ProjectSource (self->s.origin, sentien_flash_offset[idx],
|
|
forward, right, start);
|
|
|
|
//monster_fire_blaster(self, start, aim, 2, 1000,
|
|
// MZ2_MEDIC_BLASTER_1, EF_BLUEHYPERBLASTER, BLASTER_BLUE);
|
|
|
|
if (EMPNukeCheck(self, start))
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
|
|
sentien_fire_bullet(self, start, aim, 5);
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien laser attack.
|
|
=========================================================================*/
|
|
void sentien_do_laser (edict_t *self);
|
|
|
|
mframe_t sentien_frames_pre_laser_attack []=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_laser_attack []=
|
|
{
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser,
|
|
NULL, 0, sentien_do_laser
|
|
};
|
|
|
|
mframe_t sentien_frames_post_laser_attack []=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL
|
|
};
|
|
|
|
void sentien_laser_attack(edict_t *self);
|
|
void sentien_post_laser_attack(edict_t *self);
|
|
|
|
mmove_t sentien_move_pre_laser_attack = { FRAME_laserPreStart, FRAME_laserPreEnd,
|
|
sentien_frames_pre_laser_attack, sentien_laser_attack};
|
|
|
|
mmove_t sentien_move_laser_attack = { FRAME_laserStart, FRAME_laserEnd,
|
|
sentien_frames_laser_attack, sentien_post_laser_attack};
|
|
|
|
mmove_t sentien_move_post_laser_attack = { FRAME_laserPostStart, FRAME_laserPostEnd,
|
|
sentien_frames_post_laser_attack, sentien_run};
|
|
|
|
void sentien_laser_attack (edict_t *self)
|
|
{
|
|
// is a player right infront?
|
|
if (visible(self, self->enemy) &&
|
|
infront(self, self->enemy))
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_laser_attack;
|
|
}
|
|
else
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_post_laser_attack;
|
|
sentien_laser_off (self->flash);
|
|
}
|
|
}
|
|
|
|
void sentien_post_laser_attack (edict_t *self)
|
|
{
|
|
self->monsterinfo.currentmove = &sentien_move_post_laser_attack;
|
|
sentien_laser_off (self->flash);
|
|
}
|
|
|
|
void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
|
|
|
|
vec3_t sentien_laser_offset [] =
|
|
{
|
|
43.8, -22.8 + 1, 43.6 - 0.8,
|
|
44.2, -22.9 + 1, 43.9 - 0.8,
|
|
43.9, -22.8 + 1, 44.0 - 0.8,
|
|
43.2, -23.0 + 1, 44.0 - 0.8,
|
|
42.4, -23.4 + 1, 43.9 - 0.8,
|
|
42.0, -23.5 + 1, 44.0 - 0.8,
|
|
42.4, -23.3 + 1, 44.0 - 0.8,
|
|
43.1, -23.1 + 1, 43.9 - 0.8,
|
|
43.8, -22.9 + 1, 43.9 - 0.8,
|
|
44.2, -22.8 + 1, 44.1 - 0.8,
|
|
43.8, -22.8 + 1, 43.5 - 0.8
|
|
};
|
|
|
|
void sentien_do_laser (edict_t *self)
|
|
{
|
|
vec3_t start, end, forward, right, up;
|
|
vec3_t aim, ang;
|
|
float r;
|
|
int idx;
|
|
|
|
if (EMPNukeCheck(self, self->s.origin))
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
|
|
// if enemy isn't in range anymore, then get to the post laser routine
|
|
if (self->s.frame == FRAME_laserStart)
|
|
{
|
|
sentien_laser_off (self->flash);
|
|
self->flash->s.skinnum = 0xf2f2f0f0;
|
|
sentien_laser_on (self->flash);
|
|
}
|
|
|
|
idx = (self->s.frame - FRAME_laserStart);
|
|
|
|
AngleVectors (self->s.angles, forward, right, up);
|
|
G_ProjectSource (self->s.origin, sentien_laser_offset[idx],
|
|
forward, right, start);
|
|
VectorCopy (start, self->flash->s.origin);
|
|
|
|
if (self->s.frame == FRAME_laserStart)
|
|
{
|
|
VectorCopy (self->enemy->s.origin, end);
|
|
end[2] += self->enemy->viewheight * 66/100;
|
|
|
|
r = crandom() * 20;
|
|
VectorMA (end, r, right, end);
|
|
|
|
VectorSubtract (end, start, aim);
|
|
VectorNormalize(aim);
|
|
ANIM_AIM(self, aim);
|
|
|
|
vectoangles (aim, ang);
|
|
|
|
VectorCopy (ang, self->flash->s.angles);
|
|
|
|
G_SetMovedir (self->flash->s.angles, self->flash->movedir);
|
|
|
|
sentian_sound_att2 (self);
|
|
}
|
|
}
|
|
|
|
|
|
void sentien_attack (edict_t *self)
|
|
{
|
|
|
|
vec3_t vec;
|
|
float range;
|
|
float r;
|
|
|
|
sentien_laser_off (self->flash);
|
|
|
|
// sentien_run(self); // to test walking
|
|
// return;
|
|
|
|
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
|
|
range = VectorLength (vec);
|
|
|
|
r = random();
|
|
|
|
if (range <= 128)
|
|
self->monsterinfo.currentmove = &sentien_move_pre_blast_attack;
|
|
else if (range <= 500)
|
|
{
|
|
if (r < 0.50)
|
|
self->monsterinfo.currentmove = &sentien_move_pre_blast_attack;
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_pre_laser_attack;
|
|
}
|
|
else
|
|
{
|
|
if (r < 0.25)
|
|
self->monsterinfo.currentmove = &sentien_move_pre_blast_attack;
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_pre_laser_attack;
|
|
}
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Sentien fending.
|
|
=========================================================================*/
|
|
|
|
void sentien_fend_ready (edict_t *self)
|
|
{
|
|
if (self->monsterinfo.aiflags2 & AI2_REDUCEDDAMAGE)
|
|
return;
|
|
self->monsterinfo.pausetime = level.time + 1;
|
|
}
|
|
|
|
void sentien_fend_hold (edict_t *self)
|
|
{
|
|
if (level.time >= self->monsterinfo.pausetime)
|
|
{
|
|
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
|
|
self->monsterinfo.aiflags2 &= ~AI2_REDUCEDDAMAGE;
|
|
}
|
|
else
|
|
{
|
|
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
|
|
self->monsterinfo.aiflags2 |= AI2_REDUCEDDAMAGE;
|
|
}
|
|
}
|
|
|
|
|
|
mframe_t sentien_frames_fend [] =
|
|
{
|
|
ai_move, 0, sentian_sound_fend,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, sentien_fend_ready,
|
|
ai_move, 0, sentien_fend_hold,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t sentien_move_fend = {FRAME_dodgeStart, FRAME_dodgeEnd, sentien_frames_fend, sentien_run};
|
|
|
|
void sentien_fend (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
|
|
{
|
|
// don't flinch if attacking
|
|
if (self->monsterinfo.currentmove == &sentien_move_laser_attack ||
|
|
self->monsterinfo.currentmove == &sentien_move_blast_attack)
|
|
return;
|
|
|
|
if (skill->value == 0)
|
|
{
|
|
if (random() > 0.45)
|
|
return;
|
|
}
|
|
else if (skill->value == 1)
|
|
{
|
|
if (random() > 0.60)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (random() > 0.80)
|
|
return;
|
|
}
|
|
|
|
if (!self->enemy)
|
|
self->enemy = attacker;
|
|
|
|
self->monsterinfo.currentmove = &sentien_move_fend;
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Touch me sentien.
|
|
=========================================================================*/
|
|
mframe_t sentien_frames_pain1 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_pain2 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_pain3 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
|
|
mmove_t sentien_move_pain1 = {FRAME_pain1Start, FRAME_pain1End,
|
|
sentien_frames_pain1, sentien_run};
|
|
mmove_t sentien_move_pain2 = {FRAME_pain2Start, FRAME_pain2End,
|
|
sentien_frames_pain2, sentien_run};
|
|
mmove_t sentien_move_pain3 = {FRAME_pain3Start, FRAME_pain3End,
|
|
sentien_frames_pain3, sentien_run};
|
|
|
|
void sentien_pain (edict_t *self, edict_t *other, float kick, int damage)
|
|
{
|
|
float r;
|
|
|
|
if (self->health < (self->max_health / 2))
|
|
{
|
|
self->s.skinnum |= 1;
|
|
if (!(self->fogclip & 2)) // custom bloodtype flag check
|
|
self->blood_type = 3; // sparks and blood
|
|
}
|
|
|
|
// less than this we don't flinch
|
|
if (damage <= 10)
|
|
return;
|
|
|
|
r = random();
|
|
if (r < 0.33)
|
|
sentian_sound_pain1(self);
|
|
else if (r < 0.66)
|
|
sentian_sound_pain2(self);
|
|
else
|
|
{
|
|
// sentian_sound_pain3(self);
|
|
}
|
|
|
|
if (level.time < self->pain_debounce_time)
|
|
return;
|
|
|
|
if (self->monsterinfo.aiflags & AI_HOLD_FRAME)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (skill->value >= 1)
|
|
{
|
|
// don't flinch if attacking
|
|
if (self->monsterinfo.currentmove == &sentien_move_laser_attack ||
|
|
self->monsterinfo.currentmove == &sentien_move_blast_attack)
|
|
return;
|
|
}
|
|
if (skill->value == 3)
|
|
return; // no pain anims in nightmare
|
|
|
|
sentien_laser_off (self->flash);
|
|
|
|
r = random();
|
|
if (damage > 60 && r < 0.3)
|
|
self->monsterinfo.currentmove = &sentien_move_pain3;
|
|
else if (damage > 30 && r < 0.5)
|
|
self->monsterinfo.currentmove = &sentien_move_pain2;
|
|
else if (r < 0.7)
|
|
self->monsterinfo.currentmove = &sentien_move_pain1;
|
|
|
|
self->pain_debounce_time = level.time + 3;
|
|
}
|
|
|
|
/*=========================================================================
|
|
Kill me Elmo.
|
|
=========================================================================*/
|
|
mframe_t sentien_frames_death1 [] =
|
|
{
|
|
ai_move, 0, sentian_sound_die1,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
|
|
mframe_t sentien_frames_death2 [] =
|
|
{
|
|
ai_move, 0, sentian_sound_die2,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
|
|
void sentien_dead (edict_t *self);
|
|
|
|
mmove_t sentien_move_death1 = {FRAME_die1Start, FRAME_die1End,
|
|
sentien_frames_death1, sentien_dead};
|
|
mmove_t sentien_move_death2 = {FRAME_die2Start, FRAME_die2End,
|
|
sentien_frames_death2, sentien_dead};
|
|
|
|
vec3_t sentien_death_offset [] =
|
|
{
|
|
// right, forward
|
|
// VectorSet (self->mins, -50, 6, -16);
|
|
// VectorSet (self->maxs, -12, 44, 0);
|
|
6, -50, 0,
|
|
44, -12, 0
|
|
};
|
|
|
|
#define MIN(x, y) (x < y) ? x: y
|
|
#define MAX(x, y) (x < y) ? y: x
|
|
|
|
void sentien_dead (edict_t *self)
|
|
{
|
|
vec3_t start, end, point;
|
|
vec3_t forward, right;
|
|
|
|
AngleVectors (self->s.angles, forward, right, NULL);
|
|
G_ProjectSource (self->s.origin, sentien_death_offset[0],
|
|
forward, right, point);
|
|
VectorSubtract (point, self->s.origin, start);
|
|
|
|
G_ProjectSource (self->s.origin, sentien_death_offset[1],
|
|
forward, right, point);
|
|
VectorSubtract (point, self->s.origin, end);
|
|
|
|
VectorSet (self->mins, min(start[0], end[0]), min(start[1], end[1]), -16);
|
|
VectorSet (self->maxs, max(start[0], end[0]), max(start[1], end[1]), 0);
|
|
|
|
self->movetype = MOVETYPE_TOSS;
|
|
self->svflags |= SVF_DEADMONSTER;
|
|
self->nextthink = 0;
|
|
gi.linkentity(self);
|
|
}
|
|
|
|
void sentien_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
int n;
|
|
|
|
// sentien_laser_off (self->flash);
|
|
// Knightmare- free laser on death, as resurrection by a medic will call
|
|
// the spawn function again, and would leak the exisiting laser entity.
|
|
if (self->flash) {
|
|
// gi.dprintf ("removing sentien laser on death.\n");
|
|
sentien_laser_off (self->flash);
|
|
G_FreeEdict (self->flash);
|
|
self->flash = NULL;
|
|
}
|
|
// end Knightmare
|
|
|
|
// check for gib
|
|
if (self->health <= self->gib_health && !(self->spawnflags & SF_MONSTER_NOGIB))
|
|
{
|
|
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
|
|
for (n = 0; n < 12; n++)
|
|
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", 0, 0, damage, GIB_ORGANIC);
|
|
for (n = 0; n < 12; n++)
|
|
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", 0, 0, damage, GIB_METALLIC);
|
|
for (n = 0; n < 6; n++)
|
|
ThrowGib (self, "models/objects/gibs/gear/tris.md2", 0, 0, damage, GIB_METALLIC);
|
|
ThrowGib (self, "models/objects/gibs/chest/tris.md2", 0, 0, damage, GIB_ORGANIC);
|
|
ThrowHead (self, "models/objects/gibs/gear/tris.md2", 0, 0, damage, GIB_METALLIC);
|
|
self->deadflag = DEAD_DEAD;
|
|
return;
|
|
}
|
|
|
|
if (self->deadflag == DEAD_DEAD)
|
|
return;
|
|
|
|
// regular death
|
|
self->deadflag = DEAD_DEAD;
|
|
self->takedamage = DAMAGE_YES;
|
|
self->s.skinnum |= 1;
|
|
if (!(self->fogclip & 2)) // custom bloodtype flag check
|
|
self->blood_type = 3; // sparks and blood
|
|
|
|
if (random() < 0.80)
|
|
self->monsterinfo.currentmove = &sentien_move_death1;
|
|
else
|
|
self->monsterinfo.currentmove = &sentien_move_death2;
|
|
}
|
|
|
|
|
|
/*=========================================================================
|
|
Spawn code.
|
|
=========================================================================*/
|
|
void create_sentien_laser (edict_t *self)
|
|
{
|
|
vec3_t start;
|
|
vec3_t forward, right;
|
|
|
|
self->flash = G_Spawn();
|
|
self->flash->movetype = MOVETYPE_NONE;
|
|
self->flash->solid = SOLID_BBOX;//SOLID_NOT;
|
|
self->flash->s.renderfx = RF_BEAM|RF_TRANSLUCENT;
|
|
self->flash->s.modelindex = 2;
|
|
// self->flash->s.sound = gi.soundindex ("world/laser.wav");
|
|
self->flash->classname = "laser_yaya";
|
|
self->flash->s.frame = 2;
|
|
self->flash->owner = self;
|
|
self->flash->s.skinnum = 0xd0d1d2d3;
|
|
self->flash->dmg = 8;
|
|
self->flash->think = sentien_laser_think;
|
|
|
|
AngleVectors(self->s.angles, forward, right, NULL);
|
|
G_ProjectSource(self->s.origin, sentien_laser_offset[0],
|
|
forward, right, start);
|
|
|
|
VectorCopy(start, self->flash->s.origin);
|
|
VectorCopy(self->s.angles, self->flash->s.angles);
|
|
|
|
G_SetMovedir(self->flash->s.angles, self->flash->movedir);
|
|
|
|
gi.linkentity (self->flash);
|
|
sentien_laser_off (self->flash);
|
|
}
|
|
|
|
|
|
void SP_monster_sentien_precache (void)
|
|
{
|
|
|
|
sound_idle1 = gi.soundindex("monsters/sentien/sen_idle1.wav");
|
|
sound_idle2 = gi.soundindex("monsters/sentien/sen_idle2.wav");
|
|
// sound_idle3 = gi.soundindex("monsters/sentien/sen_idle3.wav");
|
|
sound_walk = gi.soundindex("monsters/sentien/sen_walk.wav");
|
|
sound_fend = gi.soundindex("monsters/sentien/sen_fend.wav");
|
|
sound_pain1 = gi.soundindex("monsters/sentien/sen_pain1.wav");
|
|
sound_pain2 = gi.soundindex("monsters/sentien/sen_pain2.wav");
|
|
// sound_pain3 = gi.soundindex("monsters/sentien/sen_pain3.wav");
|
|
sound_die1 = gi.soundindex("monsters/sentien/sen_die1.wav");
|
|
sound_die2 = gi.soundindex("monsters/sentien/sen_die2.wav");
|
|
sound_att1 = gi.soundindex("monsters/sentien/sen_att1.wav");
|
|
sound_att2 = gi.soundindex("monsters/sentien/sen_att2.wav");
|
|
// sound_att3 = gi.soundindex("monsters/sentien/sen_att3.wav");
|
|
}
|
|
|
|
|
|
/*QUAKED monster_sentien (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight GoodGuy NoGib
|
|
model="models/monsters/sentien/"
|
|
*/
|
|
void SP_monster_sentien (edict_t *self)
|
|
{
|
|
if (deathmatch->value)
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
SP_monster_sentien_precache();
|
|
|
|
if (!self->health)
|
|
self->health = 900;
|
|
if (!self->gib_health)
|
|
self->gib_health = -425;
|
|
if (!self->mass)
|
|
self->mass = 500;
|
|
|
|
// Lazarus: special purpose skins
|
|
if ( self->style )
|
|
{
|
|
PatchMonsterModel("models/monsters/sentien/tris.md2");
|
|
self->s.skinnum = self->style * 2;
|
|
}
|
|
|
|
self->s.modelindex = gi.modelindex ("models/monsters/sentien/tris.md2");
|
|
VectorSet (self->mins, -32, -32, -16);
|
|
VectorSet (self->maxs, 32, 32, 72);
|
|
self->movetype = MOVETYPE_STEP;
|
|
self->solid = SOLID_BBOX;
|
|
self->yaw_speed = 10;
|
|
self->random = 1;
|
|
|
|
// setup the functions
|
|
self->pain = sentien_pain;
|
|
self->die = sentien_die;
|
|
self->monsterinfo.stand = sentien_stand;
|
|
self->monsterinfo.walk = sentien_walk;
|
|
self->monsterinfo.run = sentien_run;
|
|
self->monsterinfo.dodge = sentien_fend;
|
|
self->monsterinfo.attack = sentien_attack;
|
|
self->monsterinfo.melee = NULL;
|
|
self->monsterinfo.sight = NULL;
|
|
self->monsterinfo.idle = NULL;
|
|
|
|
self->monsterinfo.reducedDamageAmount = 0.85;
|
|
|
|
// Lazarus
|
|
if (!self->blood_type)
|
|
self->blood_type = 2; // sparks
|
|
else
|
|
self->fogclip |= 2; // custom bloodtype flag
|
|
|
|
if (self->powerarmor)
|
|
{
|
|
if (self->powerarmortype == 1)
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
|
|
else
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
|
|
self->monsterinfo.power_armor_power = self->powerarmor;
|
|
}
|
|
if (!self->monsterinfo.flies)
|
|
self->monsterinfo.flies = 0.10;
|
|
|
|
self->common_name = "Sentien";
|
|
self->class_id = ENTITY_MONSTER_SENTIEN;
|
|
// end Lazarus
|
|
|
|
gi.linkentity (self);
|
|
|
|
self->flash = NULL;
|
|
gi.linkentity(self);
|
|
|
|
create_sentien_laser (self);
|
|
|
|
if (skill->value == 2)
|
|
{
|
|
self->flash->dmg *= 1.5;
|
|
self->yaw_speed *= 1.5;
|
|
}
|
|
else if (skill->value >= 3)
|
|
{
|
|
self->flash->dmg *= 2.5;
|
|
self->yaw_speed *= 2;
|
|
}
|
|
|
|
self->monsterinfo.currentmove = &sentien_move_stand1;
|
|
self->monsterinfo.scale = MODEL_SCALE;
|
|
|
|
walkmonster_start(self);
|
|
}
|