xmen/sinister.c
2005-09-22 00:00:00 +00:00

645 lines
No EOL
20 KiB
C

/****************************************************************************
SINISTER (2nd Episode boss)
****************************************************************************/
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 stand10
$frame stand11 stand12 stand13
$frame laugh1 laugh2 laugh3 laugh4 laugh5 laugh6 laugh7 laugh8 laugh9 laugh10
$frame laugh11 laugh12
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10
$frame walk11 walk12
$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8 pain9
$frame guard1 guard2 guard3 guard4 guard5 guard6 guard7 guard8
$frame guard9 guard10 guard11 guard12
$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8
$frame xatta9 xatta10 xatta11 xatta12
$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8
$frame xattb9 xattb10 xattb11 xattb12
$frame diss1 diss2 diss3 diss4 diss5 diss6
$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10
$frame death11 death12 death13 death14 death15 death16 death17 death18 death19 death20
$frame death21 death22 death23 death24 death25 death26 death27 death28 death29 death30
$frame death31 death32 death33 death34
//============================================================================
void() CheckPlayerSight =
{
local entity sin, current;
if (self.spawnflags & SPAWNFLAG_CLONE)
return;
if (self.enemy == world)
self.enemy = self.goalentity = find(world, classname, "player");
if (self.enemy.health <= 0) {
return;
}
if (self.enemy != world) {
traceline(self.origin + '0 0 40', self.enemy.origin + '0 0 40', TRUE, world);
if (trace_fraction == 1) {
self.th_run();
if (self.x_flags & X_SINISTER_FINAL) {
// remove all other sinisters still in the map
sin = find(world, classname, "xmen_sinister");
while (sin != world) {
current = sin;
if (sin != self)
remove(sin);
sin = find(current, classname, "xmen_sinister");
}
self.last_flame = time;
sound(self, CHAN_ITEM, "sinister/mrsin1.wav", 1, ATTN_NONE);
}
}
}
};
void() sin_laugh1;
void() sin_stand1 = [ $stand1, sin_stand2 ] {CheckPlayerSight();};
void() sin_stand2 = [ $stand2, sin_stand3 ] {CheckPlayerSight();};
void() sin_stand3 = [ $stand3, sin_stand4 ] {CheckPlayerSight();};
void() sin_stand4 = [ $stand4, sin_stand5 ] {CheckPlayerSight();};
void() sin_stand5 = [ $stand5, sin_stand6 ] {CheckPlayerSight();};
void() sin_stand6 = [ $stand6, sin_stand7 ] {CheckPlayerSight();};
void() sin_stand7 = [ $stand7, sin_stand8 ] {CheckPlayerSight();};
void() sin_stand8 = [ $stand8, sin_stand9 ] {CheckPlayerSight();};
void() sin_stand9 = [ $stand9, sin_stand10 ] {CheckPlayerSight();};
void() sin_stand10 = [ $stand10, sin_stand11 ] {CheckPlayerSight();};
void() sin_stand11 = [ $stand11, sin_stand12 ] {CheckPlayerSight();};
void() sin_stand12 = [ $stand12, sin_stand13 ] {CheckPlayerSight();};
void() sin_stand13 = [ $stand13, sin_stand1 ]
{
if (!(self.x_flags & X_SINISTER_FINAL)) {
self.count = self.count + 1;
if ((random() < 0.4) || (self.count == 3)) {
self.count = 0;
self.think = sin_laugh1;
}
}
};
void() sin_laugh1 = [ $laugh1, sin_laugh2 ]
{
local float rnd;
if ((self.count == 0) && (self.last_flame < (time - 4))) {
rnd = random() * 8;
if (rnd < 1)
sound(self, CHAN_VOICE, "sinister/laugh1.wav", 1, 2);
else if (rnd < 2)
sound(self, CHAN_VOICE, "sinister/laugh2.wav", 1, 2);
else if (rnd < 2)
sound(self, CHAN_VOICE, "sinister/cackle1.wav", 1, 2);
else if (rnd < 4)
sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 2);
else if (rnd < 5)
sound(self, CHAN_VOICE, "sinister/cackle3.wav", 1, 2);
else if (rnd < 6)
sound(self, CHAN_VOICE, "sinister/threat1.wav", 1, 2);
else if (rnd < 7)
sound(self, CHAN_VOICE, "sinister/threat2.wav", 1, 2);
else
sound(self, CHAN_VOICE, "sinister/threat3.wav", 1, 2);
}
};
void() sin_laugh2 = [ $laugh2, sin_laugh3 ] {CheckPlayerSight();};
void() sin_laugh3 = [ $laugh3, sin_laugh4 ] {CheckPlayerSight();};
void() sin_laugh4 = [ $laugh4, sin_laugh5 ] {CheckPlayerSight();};
void() sin_laugh5 = [ $laugh5, sin_laugh6 ] {CheckPlayerSight();};
void() sin_laugh6 = [ $laugh6, sin_laugh7 ] {CheckPlayerSight();};
void() sin_laugh7 = [ $laugh7, sin_laugh8 ] {CheckPlayerSight();};
void() sin_laugh8 = [ $laugh8, sin_laugh9 ] {CheckPlayerSight();};
void() sin_laugh9 = [ $laugh9, sin_laugh10 ] {CheckPlayerSight();};
void() sin_laugh10 = [ $laugh10, sin_laugh11 ] {CheckPlayerSight();};
void() sin_laugh11 = [ $laugh11, sin_laugh12 ] {CheckPlayerSight();};
void() sin_laugh12 = [ $laugh12, sin_laugh1 ]
{
self.count = self.count + 1;
if (self.count >= 4) {
self.count = 0;
self.think = sin_stand1;
}
};
//============================================================================
void() SinisterMissile;
void() sin_sightlaugh1 = [ $laugh1, sin_sightlaugh2 ]
{
local float rnd;
if (self.count == 0) {
rnd = random() * 8;
if (rnd < 1)
sound(self, CHAN_VOICE, "sinister/laugh1.wav", 1, 2);
else if (rnd < 2)
sound(self, CHAN_VOICE, "sinister/laugh2.wav", 1, 2);
else if (rnd < 2)
sound(self, CHAN_VOICE, "sinister/cackle1.wav", 1, 2);
else if (rnd < 4)
sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 2);
else if (rnd < 5)
sound(self, CHAN_VOICE, "sinister/cackle3.wav", 1, 2);
else if (rnd < 6)
sound(self, CHAN_VOICE, "sinister/threat1.wav", 1, 2);
else if (rnd < 7)
sound(self, CHAN_VOICE, "sinister/threat2.wav", 1, 2);
else
sound(self, CHAN_VOICE, "sinister/threat3.wav", 1, 2);
}
};
void() sin_sightlaugh2 = [ $laugh2, sin_sightlaugh3 ] {};
void() sin_sightlaugh3 = [ $laugh3, sin_sightlaugh4 ] {};
void() sin_sightlaugh4 = [ $laugh4, sin_sightlaugh5 ] {};
void() sin_sightlaugh5 = [ $laugh5, sin_sightlaugh6 ] {};
void() sin_sightlaugh6 = [ $laugh6, sin_sightlaugh7 ] {};
void() sin_sightlaugh7 = [ $laugh7, sin_sightlaugh8 ] {};
void() sin_sightlaugh8 = [ $laugh8, sin_sightlaugh9 ] {};
void() sin_sightlaugh9 = [ $laugh9, sin_sightlaugh10 ] {};
void() sin_sightlaugh10 = [ $laugh10, sin_sightlaugh11 ] {};
void() sin_sightlaugh11 = [ $laugh11, sin_sightlaugh12 ] {};
void() sin_sightlaugh12 = [ $laugh12, sin_sightlaugh1 ]
{
self.count = self.count + 1;
if (self.count >= 4) {
self.count = 0;
self.think = SinisterMissile;
}
};
void() sin_walk1 = [ $walk1, sin_walk2 ] {ai_run(3);};
void() sin_walk2 = [ $walk2, sin_walk3 ] {ai_run(2);};
void() sin_walk3 = [ $walk3, sin_walk4 ] {ai_run(3);};
void() sin_walk4 = [ $walk4, sin_walk5 ] {ai_run(5);};
void() sin_walk5 = [ $walk5, sin_walk6 ] {ai_run(6);};
void() sin_walk6 = [ $walk6, sin_walk7 ] {ai_run(6);};
void() sin_walk7 = [ $walk7, sin_walk8 ] {ai_run(5);};
void() sin_walk8 = [ $walk8, sin_walk9 ] {ai_run(3);};
void() sin_walk9 = [ $walk9, sin_walk10 ] {ai_run(3);};
void() sin_walk10 = [ $walk10, sin_walk11 ] {ai_run(4);};
void() sin_walk11 = [ $walk11, sin_walk12 ] {ai_run(5);};
void() sin_walk12 = [ $walk12, sin_walk1 ] {ai_run(6);};
//============================================================================
void() sin_pain1 = [ $pain1, sin_pain2 ] {};
void() sin_pain2 = [ $pain2, sin_pain3 ] {};
void() sin_pain3 = [ $pain3, sin_pain4 ] {};
void() sin_pain4 = [ $pain4, sin_pain5 ] {};
void() sin_pain5 = [ $pain5, sin_pain6 ] {};
void() sin_pain6 = [ $pain6, sin_pain7 ] {};
void() sin_pain7 = [ $pain7, sin_pain8 ] {};
void() sin_pain8 = [ $pain8, sin_pain9 ] {};
void() sin_pain9 = [ $pain9, sin_walk1 ] {};
void() sin_diss1;
void(entity attacker, float damage) SinisterPain =
{
local float best;
local entity stemp;
if (self.spawnflags & SPAWNFLAG_CLONE) {
self.health = 99999;
return;
}
if (self.x_flags & X_SINISTER_FINAL) {
//self.health =1;
//return;
if (attacker.weapon == IT_SPECIAL_WEAPON) {
if (self.health < 10000) { // special weapon has removed invulnerability
self.health = self.start_health = 500;
self.x_flags = self.x_flags | X_MEGA_HIT;
attacker.currentammo = attacker.ammo_special = 0;
self.th_run();
return;
}
if (self.pain_finished > time)
return;
self.pain_finished = time + 5;
// sin_pain1();
return;
}
if (!(self.x_flags & X_MEGA_HIT)) {
self.health = 99999;
return;
}
if (self.pain_finished > time)
return;
if ((random() * 20) > damage) // don't flinch
return;
self.pain_finished = time + 2;
sin_pain1();
return;
}
else { // move to next spot
sin_diss1();
}
self.health = 99999;
};
//============================================================================
void() sin_guard8;
void() sin_guard1 = [ $guard1, sin_guard2 ] {};
void() sin_guard2 = [ $guard2, sin_guard3 ] {};
void() sin_guard3 = [ $guard3, sin_guard4 ] {};
void() sin_guard4 = [ $guard4, sin_guard5 ] {};
void() sin_guard5 = [ $guard5, sin_guard6 ] {};
void() sin_guard6 = [ $guard6, sin_guard7 ] {self.flags = self.flags | FL_GODMODE;};
void() sin_guard7 = [ $guard7, sin_guard7 ]
{
local entity trav;
trav = world;
while ((trav = find(trav, classname, "guided_rocket")) != world) {
// check that rocket is targetted for self
if (trav.enemy == self) { // uh oh
return;
}
}
// dangerous rocket not found
self.flags = self.flags - (self.flags & FL_GODMODE);
self.think = sin_guard8;
};
void() sin_guard8 = [ $guard8, sin_guard9 ] {};
void() sin_guard9 = [ $guard9, sin_guard10 ] {};
void() sin_guard10 = [ $guard10, sin_guard11 ] {};
void() sin_guard11 = [ $guard11, sin_guard12 ] {};
void() sin_guard12 = [ $guard12, sin_walk1 ] {};
//============================================================================
void() SinisterMissile;
void() SinMissileTouch =
{
if (other == self.owner)
return;
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
if (other.takedamage == DAMAGE_AIM)
{
spawn_touchblood (5);
T_Damage(other, self, self.owner, 5);
}
remove(self);
};
void(vector org) spawn_sinister_missile =
{
local entity missile, mpuff;
local vector vect;
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_FLYMISSILE;
missile.solid = SOLID_BBOX;
missile.classname = "sin_missile";
missile.velocity = ProjectVelocity(750, '0 0 0');
missile.angles = vectoangles(missile.velocity);
missile.old_velocity = missile.velocity;
missile.touch = SinMissileTouch;
missile.last_touch = 0;
missile.oldorigin = missile.origin;
missile.nextthink = time + 10;
missile.think = SUB_Remove;
setmodel (missile, "progs/sinblast.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, org);
};
void() sin_xatta1 = [ $xatta1, sin_xatta2 ] {ai_face();};
void() sin_xatta2 = [ $xatta2, sin_xatta3 ] {ai_face();};
void() sin_xatta3 = [ $xatta3, sin_xatta4 ] {ai_face();};
void() sin_xatta4 = [ $xatta4, sin_xatta5 ] {ai_face();};
void() sin_xatta5 = [ $xatta5, sin_xatta6 ]
{
ai_face();
makevectors(self.angles);
spawn_sinister_missile(self.origin + v_right * 4);
spawn_sinister_missile(self.origin + v_right * -4);
};
void() sin_xatta6 = [ $xatta6, sin_xatta7 ] {ai_face();};
void() sin_xatta7 = [ $xatta7, sin_xatta8 ] {ai_face();};
void() sin_xatta8 = [ $xatta8, sin_xatta9 ] {ai_face();};
void() sin_xatta9 = [ $xatta9, sin_xatta10 ] {ai_face();};
void() sin_xatta10 = [ $xatta10, sin_xatta11 ] {ai_face();};
void() sin_xatta11 = [ $xatta11, sin_xatta12 ] {ai_face();};
void() sin_xatta12 = [ $xatta12, sin_walk1 ]
{
if (!(self.x_flags & X_SINISTER_FINAL))
SinisterMissile();
};
void() sin_xattb1 = [ $xattb1, sin_xattb2 ] {ai_face();};
void() sin_xattb2 = [ $xattb2, sin_xattb3 ] {ai_face();};
void() sin_xattb3 = [ $xattb3, sin_xattb4 ]
{
ai_face();
makevectors(self.angles);
spawn_sinister_missile(self.origin + v_right * 4);
};
void() sin_xattb4 = [ $xattb4, sin_xattb5 ] {ai_face();};
void() sin_xattb5 = [ $xattb5, sin_xattb6 ] {ai_face();};
void() sin_xattb6 = [ $xattb6, sin_xattb7 ]
{
ai_face();
makevectors(self.angles);
spawn_sinister_missile(self.origin + v_right * -4);
};
void() sin_xattb7 = [ $xattb7, sin_xattb8 ] {ai_face();};
void() sin_xattb8 = [ $xattb8, sin_xattb9 ] {ai_face();};
void() sin_xattb9 = [ $xattb9, sin_xattb10 ]
{
ai_face();
makevectors(self.angles);
spawn_sinister_missile(self.origin + v_right * 4);
};
void() sin_xattb10 = [ $xattb10, sin_xattb11 ] {ai_face();};
void() sin_xattb11 = [ $xattb11, sin_xattb12 ] {ai_face();};
void() sin_xattb12 = [ $xattb12, sin_walk1 ]
{
if (!(self.x_flags & X_SINISTER_FINAL))
SinisterMissile();
};
void() SinisterMissile =
{
if ((self.x_flags & X_SINISTER_FINAL) && !(self.x_flags & X_MEGA_HIT) && (random() < 0.9)) {
self.count = 0;
sin_sightlaugh1();
return;
}
if (random() < 0.7)
sin_xatta1();
else
sin_xattb1();
};
//============================================================================
void() SinNextSpot =
{
local entity stemp, trav;
if (!(self.x_flags & X_SINISTER_FINAL)) {
self.state = self.state + 1;
self.enemy = world;
stemp = find(world, classname, "xmen_sinister_spot");
while (stemp != world) {
if (stemp.state == self.state) {
spawn_tfog(stemp.origin);
setorigin(self, stemp.origin);
droptofloor();
self.angles = stemp.angles;
self.velocity = '0 0 0';
self.th_stand();
return;
}
else
stemp = find(stemp, classname, "xmen_sinister_spot");
}
// no spot found, so disappear altogether
remove(self);
}
else { // random teleport
stemp = find(world, classname, "xmen_sinister_teleport");
while (stemp != world) {
if ((random() < 0.1) && (vlen(stemp.origin - self.origin) > 128)) {
self.oldorigin = self.origin;
setorigin(self, stemp.origin);
droptofloor();
if (!walkmove(0,0)) {
setorigin(self, self.oldorigin);
}
else {
spawn_tfog(stemp.origin);
self.angles = stemp.angles;
self.velocity = '0 0 0';
self.th_run();
trav = find(world, classname, "guided_rocket");
while (trav != world) {
if (trav.enemy == self)
trav.enemy = world;
trav = find(trav, classname, "guided_rocket");
}
return;
}
}
else {
stemp = find(stemp, classname, "xmen_sinister_teleport");
if (stemp == world) {
stemp = find(world, classname, "xmen_sinister_teleport");
}
}
}
}
};
void() sin_diss1 = [ $diss1, sin_diss2 ] {};
void() sin_diss2 = [ $diss2, sin_diss3 ] {};
void() sin_diss3 = [ $diss3, sin_diss4 ] {};
void() sin_diss4 = [ $diss4, sin_diss5 ] {};
void() sin_diss5 = [ $diss5, sin_diss6 ] {};
void() sin_diss6 = [ $diss6, SinNextSpot ] {spawn_tfog(self.origin);};
//============================================================================
void() sin_death1 = [ $death1, sin_death2 ] {};
void() sin_death2 = [ $death2, sin_death3 ] {};
void() sin_death3 = [ $death3, sin_death4 ] {};
void() sin_death4 = [ $death4, sin_death5 ] {};
void() sin_death5 = [ $death5, sin_death6 ] {};
void() sin_death6 = [ $death6, sin_death7 ] {};
void() sin_death7 = [ $death7, sin_death8 ] {};
void() sin_death8 = [ $death8, sin_death9 ] {};
void() sin_death9 = [ $death9, sin_death10 ] {};
void() sin_death10 = [ $death10, sin_death11 ] {};
void() sin_death11 = [ $death11, sin_death12 ] {};
void() sin_death12 = [ $death12, sin_death13 ] {};
void() sin_death13 = [ $death13, sin_death14 ] {};
void() sin_death14 = [ $death14, sin_death15 ] {};
void() sin_death15 = [ $death15, sin_death16 ] {};
void() sin_death16 = [ $death16, sin_death17 ] {};
void() sin_death17 = [ $death17, sin_death18 ] {};
void() sin_death18 = [ $death18, sin_death19 ] {};
void() sin_death19 = [ $death19, sin_death20 ] {};
void() sin_death20 = [ $death20, sin_death21 ] {};
void() sin_death21 = [ $death21, sin_death22 ] {};
void() sin_death22 = [ $death22, sin_death23 ] {};
void() sin_death23 = [ $death23, sin_death24 ] {};
void() sin_death24 = [ $death24, sin_death25 ] {};
void() sin_death25 = [ $death25, sin_death26 ] {};
void() sin_death26 = [ $death26, sin_death27 ] {};
void() sin_death27 = [ $death27, sin_death28 ] {};
void() sin_death28 = [ $death28, sin_death29 ] {};
void() sin_death29 = [ $death29, sin_death30 ] {};
void() sin_death30 = [ $death30, sin_death31 ] {sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 0);};
void() sin_death31 = [ $death31, sin_death32 ] {};
void() sin_death32 = [ $death32, sin_death33 ] {};
void() sin_death33 = [ $death33, sin_death34 ] {spawn_tfog(self.origin);};
void() sin_death34 = [ $death34, sin_death34 ]
{
local entity trav;
killed_monsters = killed_monsters + 1;
WriteByte (MSG_ALL, SVC_KILLEDMONSTER); // FIXME: reliable broadcast
trav = find (world, classname, "player");
while (trav != world)
{
trav.view_ofs = '0 0 0';
trav.nextthink = time + 0.5;
trav.takedamage = DAMAGE_NO;
trav.solid = SOLID_NOT;
trav.movetype = MOVETYPE_NONE;
trav.modelindex = 0;
trav = find (trav, classname, "player");
}
WriteByte (MSG_ALL, SVC_INTERMISSION);
nextmap = "start";
intermission_running = 1;
SUB_UseTargets ();
remove (self);
};
//============================================================================
// Sinister teleport destination, use self.state to set sequence
void() xmen_sinister;
void() xmen_sinister_spot =
{
self.classname = "xmen_sinister";
xmen_sinister();
};
//============================================================================
void() xmen_sinister =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/sinister.mdl");
precache_model ("progs/sinblast.mdl");
precache_sound ("sinister/laugh1.wav");
precache_sound ("sinister/laugh2.wav");
precache_sound ("sinister/cackle1.wav");
precache_sound ("sinister/cackle2.wav");
precache_sound ("sinister/cackle3.wav");
precache_sound ("sinister/mrsin1.wav");
precache_sound ("sinister/threat1.wav");
precache_sound ("sinister/threat2.wav");
precache_sound ("sinister/threat3.wav");
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/sinister.mdl");
setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
self.health = 99999;
self.th_stand = sin_stand1;
self.th_walk = sin_stand1;
self.th_run = sin_sightlaugh1;
self.th_pain = SinisterPain;
self.th_die = sin_death1;
self.th_missile = SinisterMissile;
if (!(self.spawnflags & SPAWNFLAG_CLONE))
walkmonster_start();
else {
self.flags = self.flags | FL_GODMODE;
self.think = self.th_stand;
self.nextthink = time + 0.1;
}
self.health = 99999;
};
void() xmen_sinister_final =
{
self.x_flags = self.x_flags | X_SINISTER_FINAL;
self.classname = "xmen_sinister";
xmen_sinister();
self.th_guard = sin_diss5;
self.th_run = sin_walk1;
};
void() xmen_sinister_teleport = {};