mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
0d4e872ce9
Added plasma guards (monster_soldier_plasma_re and monster_soldier_plasma_sp) from LM Escape to missionpack DLL. Added Zaero items/weapons to missionpack DLL. Added support for Zaero doors to missionpack DLL. Fixed crash caused by killtargeting sentien (laser edict not freed) in missionpack DLL. Fixed bug with broken Rogue turrets in missionpack DLL. Fixed crash in g_combat.c->M_ReactToDamage() caused by attacker with NULL classname in missionpack DLL.
1309 lines
32 KiB
C
1309 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
|
|
|
|
// gib code to go here
|
|
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", damage, GIB_ORGANIC);
|
|
for (n= 0; n < 12; n++)
|
|
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
|
|
for (n= 0; n < 6; n++)
|
|
ThrowGib (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
|
|
ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
|
|
ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
|
|
self->deadflag = DEAD_DEAD;
|
|
return;
|
|
}
|
|
|
|
if (self->deadflag == DEAD_DEAD)
|
|
return;
|
|
|
|
self->deadflag = DEAD_DEAD;
|
|
self->takedamage = DAMAGE_YES;
|
|
self->s.skinnum |= 1;
|
|
|
|
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";
|
|
// 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);
|
|
}
|