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

621 lines
18 KiB
C

/*
==============================================================================
beast
==============================================================================
*/
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame stand10 stand11 stand12 stand13
$frame runa1 runa2 runa3 runa4 runa5 runa6 runa7 runa8 runa9 runa10
$frame runa11 runa12
$frame runb1 runb2 runb3 runb4 runb5 runb6 runb7 runb8 runb9 runb10
$frame runb11 runb12
$frame runc1 runc2 runc3 runc4 runc5 runc6 runc7 runc8 runc9 runc10
$frame runc11 runc12
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10
$frame death11 death12
$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 deata10
$frame deata11 deata12
$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8
$frame atta9 atta10 atta11 atta12
$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8
$frame attb9 attb10 attb11 attb12
$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8
$frame xatta9 xatta10 xatta11 xatta12 xatta13 xatta14 xatta15 xatta16 xatta17 xatta18
void() beast_atta1;
void() beast_atta8;
void() beast_runa1;
/*
================
beast_bite
================
*/
void() beast_bite =
{
local vector delta;
local float ldmg;
local entity plyr;
makevectors(self.v_angle);
if ((plyr = FindSightEnemy(self.origin, v_forward, 60, 40, "all", self)) == world)
return;
delta = plyr.origin - self.origin;
if (vlen(delta) > 60)
return;
ldmg = 9 + random() * 3;
T_Damage (plyr, self, self, ldmg);
if (self.frame >= $attb1 ) {
if (random() < 0.5)
sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM);
else
sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM);
}
else
sound(self, CHAN_WEAPON, "generic/punch1.wav", 1, ATTN_NORM);
};
/*
void() beast_JumpTouch =
{
local float ldmg;
if (self.health <= 0)
return;
if (other.takedamage)
{
if ( vlen(self.velocity) > 300 )
{
ldmg = 15 + 10*random();
T_Damage (other, self, self, ldmg);
}
}
if (!checkbottom(self))
{
if (self.flags & FL_ONGROUND)
{ // jump randomly to not get hung up
//bprint ("popjump\n");
self.touch = SUB_Null;
self.think = beast_atta1;
self.nextthink = time + 0.1;
// self.velocity_x = (random() - 0.5) * 600;
// self.velocity_y = (random() - 0.5) * 600;
// self.velocity_z = 200;
// self.flags = self.flags - FL_ONGROUND;
}
return; // not on ground yet
}
self.touch = SUB_Null;
self.think = beast_atta8;
self.nextthink = time + 0.05;
};
*/
void() beast_stand1 =[ $stand1, beast_stand2 ] {ai_stand();};
void() beast_stand2 =[ $stand2, beast_stand3 ] {ai_stand();};
void() beast_stand3 =[ $stand3, beast_stand4 ] {ai_stand();};
void() beast_stand4 =[ $stand4, beast_stand5 ] {ai_stand();};
void() beast_stand5 =[ $stand5, beast_stand6 ] {ai_stand();};
void() beast_stand6 =[ $stand6, beast_stand7 ] {ai_stand();};
void() beast_stand7 =[ $stand7, beast_stand8 ] {ai_stand();};
void() beast_stand8 =[ $stand8, beast_stand9 ] {ai_stand();};
void() beast_stand9 =[ $stand9, beast_stand10 ] {ai_stand();};
void() beast_stand10 =[ $stand10, beast_stand11 ] {ai_stand();};
void() beast_stand11 =[ $stand11, beast_stand12 ] {ai_stand();};
void() beast_stand12 =[ $stand12, beast_stand13 ] {ai_stand();};
void() beast_stand13 =[ $stand13, beast_stand1 ] {ai_stand();};
/*
void() beast_walk1 =[ $walk1 , beast_walk2 ] {
ai_walk(8);};
void() beast_walk2 =[ $walk2 , beast_walk3 ] {ai_walk(8);};
void() beast_walk3 =[ $walk3 , beast_walk4 ] {ai_walk(8);};
void() beast_walk4 =[ $walk4 , beast_walk5 ] {ai_walk(8);};
void() beast_walk5 =[ $walk5 , beast_walk6 ] {ai_walk(8);};
void() beast_walk6 =[ $walk6 , beast_walk7 ] {ai_walk(8);};
void() beast_walk7 =[ $walk7 , beast_walk8 ] {ai_walk(8);};
void() beast_walk8 =[ $walk8 , beast_walk1 ] {ai_walk(8);};
*/
void() beast_random_run;
void() beast_runa1 =[ $runa1 , beast_runa2 ] {
ai_run(32);};
void() beast_runa2 =[ $runa2 , beast_runa3 ] {ai_run(32);};
void() beast_runa3 =[ $runa3 , beast_runa4 ] {ai_run(32);};
void() beast_runa4 =[ $runa4 , beast_runa5 ] {ai_run(20);};
void() beast_runa5 =[ $runa5 , beast_runa6 ] {ai_run(32);};
void() beast_runa6 =[ $runa6 , beast_runa7 ] {ai_run(32);};
void() beast_runa7 =[ $runa7 , beast_runa8 ] {ai_run(26);};
void() beast_runa8 =[ $runa8 , beast_runa9 ] {ai_run(32);};
void() beast_runa9 =[ $runa9 , beast_runa10 ] {ai_run(32);};
void() beast_runa10 =[ $runa10 , beast_runa11 ] {ai_run(20);};
void() beast_runa11 =[ $runa11 , beast_runa12 ] {ai_run(32);};
void() beast_runa12 =[ $runa12 , beast_runa1 ]
{
ai_run(32);
beast_random_run();
};
void() beast_runb1 =[ $runb1 , beast_runb2 ] {
ai_run(32);};
void() beast_runb2 =[ $runb2 , beast_runb3 ] {ai_run(32);};
void() beast_runb3 =[ $runb3 , beast_runb4 ] {ai_run(32);};
void() beast_runb4 =[ $runb4 , beast_runb5 ] {ai_run(20);};
void() beast_runb5 =[ $runb5 , beast_runb6 ] {ai_run(32);};
void() beast_runb6 =[ $runb6 , beast_runb7 ] {ai_run(32);};
void() beast_runb7 =[ $runb7 , beast_runb8 ] {ai_run(26);};
void() beast_runb8 =[ $runb8 , beast_runb9 ] {ai_run(32);};
void() beast_runb9 =[ $runb9 , beast_runb10 ] {ai_run(32);};
void() beast_runb10 =[ $runb10 , beast_runb11 ] {ai_run(20);};
void() beast_runb11 =[ $runb11 , beast_runb12 ] {ai_run(32);};
void() beast_runb12 =[ $runb12 , beast_runb1 ]
{
ai_run(32);
beast_random_run();
};
void() beast_runc1 =[ $runc1 , beast_runc2 ] {
ai_run(32);};
void() beast_runc2 =[ $runc2 , beast_runc3 ] {ai_run(32);};
void() beast_runc3 =[ $runc3 , beast_runc4 ] {ai_run(32);};
void() beast_runc4 =[ $runc4 , beast_runc5 ] {ai_run(20);};
void() beast_runc5 =[ $runc5 , beast_runc6 ] {ai_run(32);};
void() beast_runc6 =[ $runc6 , beast_runc7 ] {ai_run(32);};
void() beast_runc7 =[ $runc7 , beast_runc8 ] {ai_run(26);};
void() beast_runc8 =[ $runc8 , beast_runc9 ] {ai_run(32);};
void() beast_runc9 =[ $runc9 , beast_runc10 ] {ai_run(32);};
void() beast_runc10 =[ $runc10 , beast_runc11 ] {ai_run(20);};
void() beast_runc11 =[ $runc11 , beast_runc12 ] {ai_run(32);};
void() beast_runc12 =[ $runc12 , beast_runc1 ]
{
ai_run(32);
beast_random_run();
};
void() beast_random_run =
{
local float rnd;
rnd = random() * 3;
if (rnd < 1)
self.think = beast_runa1;
else if (rnd < 2)
self.think = beast_runb1;
else
self.think = beast_runc1;
};
float() CheckbeastMelee;
void() beast_attb1 =[ $attb1, beast_attb2 ] {ai_charge(10);};
void() beast_attb2 =[ $attb2, beast_attb3 ] {ai_charge(10);};
void() beast_attb3 =[ $attb3, beast_attb4 ] {ai_charge(10);};
void() beast_attb4 =[ $attb4, beast_attb5 ] {
beast_bite();};
void() beast_attb5 =[ $attb5, beast_attb6 ] {ai_charge(10);};
void() beast_attb6 =[ $attb6, beast_attb7 ]
{
ai_charge(10);
// check if enemy is still in striking distance
if (!CheckbeastMelee())
beast_runa1();
};
void() beast_attb7 =[ $attb7, beast_attb8 ] {
beast_bite();};
void() beast_attb8 =[ $attb8, beast_attb9 ] {ai_charge(10);};
void() beast_attb9 =[ $attb9, beast_attb10 ] {ai_charge(10);};
void() beast_attb10 =[ $attb10, beast_attb11 ] {
beast_bite();};
void() beast_attb11 =[ $attb11, beast_attb12 ] {ai_charge(10);};
void() beast_attb12 =[ $attb12, beast_runa1 ] {ai_charge(10);};
void() beast_atta1 =[ $atta1, beast_atta2 ] {ai_charge(10);};
void() beast_atta2 =[ $atta2, beast_atta3 ] {ai_charge(10);};
void() beast_atta3 =[ $atta3, beast_atta4 ] {ai_charge(10);};
void() beast_atta4 =[ $atta4, beast_atta5 ] {ai_charge(10);};
void() beast_atta5 =[ $atta5, beast_atta6 ] {ai_charge(10);};
void() beast_atta6 =[ $atta6, beast_atta7 ] {ai_charge(10);};
void() beast_atta7 =[ $atta7, beast_atta8 ] {ai_charge(10);};
void() beast_atta8 =[ $atta8, beast_atta9 ] {ai_charge(10);};
void() beast_atta9 =[ $atta9, beast_atta10 ] {
beast_bite();
beast_bite();
ai_charge(10);};
void() beast_atta10 =[ $atta10, beast_atta11 ] {ai_charge(10);};
void() beast_atta11 =[ $atta11, beast_atta12 ] {ai_charge(10);};
void() beast_atta12 =[ $atta12, beast_runa1 ] {ai_charge(10);};
void() beast_melee =
{
if (random() < 0.5)
beast_atta1();
else
beast_attb1();
};
// special attack
void() BeastPowTouch =
{
local float damg;
if ((other == self.owner) || (other == world))
return;
damg = 25 + random()*10;
if (other.health)
{
T_Damage (other, self, self.owner, damg );
}
other.velocity = other.velocity + self.velocity + '0 0 200';
other.flags = other.flags - (other.flags & FL_ONGROUND);
setorigin(other, other.origin + '0 0 1');
sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0.2, ATTN_NORM);
self.origin = self.origin - 8*normalize(self.velocity);
/*
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);
*/
// BecomeExplosion ();
remove(self);
};
void() BeastPowThink =
{
local entity trav;
local vector vec;
local float dist, ratio;
if ((self.spawn_time < (time - 3)) || (self.origin == self.oldorigin)) {
sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0.2, ATTN_NORM);
remove(self);
return;
}
self.frame = self.frame + 1;
if (self.frame >= 8)
self.frame = 0;
vec = self.velocity;
traceline(self.origin + vec*frametime*2 + '0 0 32', self.origin + vec*frametime*2 - '0 0 48', TRUE, world);
if (trace_fraction == 1) {
sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0, ATTN_NORM);
remove(self);
return;
}
else {
self.velocity = normalize(trace_endpos + '0 0 24' - self.origin) * 750;
self.flags = self.flags - (self.flags & FL_ONGROUND);
traceline(self.origin + '0 0 32', self.origin - '0 0 48', TRUE, world);
setorigin(self, trace_endpos + '0 0 24');
}
// earth-shake
trav = findradius(self.origin, 512);
while (trav != world) {
if (trav.classname == "player") {
// shake view
vec = '12 0 0' * random() + '0 12 0' * random() + '0 0 22' * random() - '6 6 14';
ratio = 1 - (vlen(trav.origin - self.origin) / 512);
if (ratio > 1)
ratio = 1;
vec = vec * ratio;
trav.view_ofs = '0 0 22' + vec;
trav.punchangle = vec * 0.5;
if (trav.view_ofs == '0 0 0')
trav.view_ofs = '0 0 1';
}
trav = trav.chain;
}
self.oldorigin = self.origin;
self.nextthink = time + 0.05;
};
void() BeastSpecialAttack =
{
local entity trav;
local entity missile;
missile = spawn();
missile.classname = "beast_power";
missile.owner = self;
missile.solid = SOLID_TRIGGER;
missile.movetype = MOVETYPE_FLY;
setsize(missile, '0 0 0', '0 0 0');
setmodel(missile, "progs/pow.mdl");
missile.velocity = normalize(self.enemy.origin - self.origin + self.enemy.velocity * 0.5) * 750;
missile.velocity_z = 0;
missile.old_velocity = missile.velocity;
makevectors(self.angles);
setorigin(missile, self.origin + v_forward * 16);
missile.touch = BeastPowTouch;
missile.think = BeastPowThink;
missile.spawn_time = time;
missile.nextthink = time + 0.05;
/*
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, missile.origin_x);
WriteCoord (MSG_BROADCAST, missile.origin_y);
WriteCoord (MSG_BROADCAST, missile.origin_z);
*/
sound (self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM);
sound (self, CHAN_WEAPON, "doors/stndr1.wav", 1, ATTN_NORM);
// send players airbourne
trav = find(world, classname, "player");
while (trav != world) {
if ((trav.flags & FL_ONGROUND) && (vlen(trav.origin - self.origin) < 256))
trav.velocity_z = 225;
trav = find(trav, classname, "player");
}
};
void() beast_xatta1 =[ $xatta1, beast_xatta2 ] {self.last_special = time;};
void() beast_xatta2 =[ $xatta2, beast_xatta3 ] {};
void() beast_xatta3 =[ $xatta3, beast_xatta4 ] {};
void() beast_xatta4 =[ $xatta4, beast_xatta5 ] {};
void() beast_xatta5 =[ $xatta5, beast_xatta6 ] {};
void() beast_xatta6 =[ $xatta6, beast_xatta7 ] {};
void() beast_xatta7 =[ $xatta7, beast_xatta8 ] {};
void() beast_xatta8 =[ $xatta8, beast_xatta9 ] {};
void() beast_xatta9 =[ $xatta9, beast_xatta10 ] {};
void() beast_xatta10 =[ $xatta10, beast_xatta11 ] {};
void() beast_xatta11 =[ $xatta11, beast_xatta12 ] {BeastSpecialAttack();};
void() beast_xatta12 =[ $xatta12, beast_xatta13 ] {};
void() beast_xatta13 =[ $xatta13, beast_xatta14 ] {};
void() beast_xatta14 =[ $xatta14, beast_xatta15 ] {};
void() beast_xatta15 =[ $xatta15, beast_xatta16 ] {};
void() beast_xatta16 =[ $xatta16, beast_xatta17 ] {};
void() beast_xatta17 =[ $xatta17, beast_xatta18 ] {};
void() beast_xatta18 =[ $xatta18, beast_runa1 ] {};
void() beast_pain1 =[ $pain1 , beast_pain2 ] {};
void() beast_pain2 =[ $pain2 , beast_pain3 ] {};
void() beast_pain3 =[ $pain3 , beast_pain4 ] {};
void() beast_pain4 =[ $pain4 , beast_pain5 ] {};
void() beast_pain5 =[ $pain5 , beast_pain6 ] {};
void() beast_pain6 =[ $pain6 , beast_runa1 ] {};
void(entity attacker, float damage) beast_pain =
{
if (self.pain_finished > time)
return;
MalePainSound(1);
if (random()*100 > damage)
return;
self.pain_finished = time + 2;
beast_pain1 ();
};
void() beast_die1 =[ $death1, beast_die2 ] {};
void() beast_die2 =[ $death2, beast_die3 ] {};
void() beast_die3 =[ $death3, beast_die4 ] {};
void() beast_die4 =[ $death4, beast_die5 ] {};
void() beast_die5 =[ $death5, beast_die6 ] {};
void() beast_die6 =[ $death6, beast_die7 ] {};
void() beast_die7 =[ $death7, beast_die8 ] {};
void() beast_die8 =[ $death8, beast_die9 ] {};
void() beast_die9 =[ $death9, beast_die10 ] {};
void() beast_die10 =[ $death10, beast_die11 ] {};
void() beast_die11 =[ $death11, beast_die12 ] {};
void() beast_die12 =[ $death12, beast_die12 ] {};
void() beast_diea1 =[ $deata1, beast_diea2 ] {};
void() beast_diea2 =[ $deata2, beast_diea3 ] {};
void() beast_diea3 =[ $deata3, beast_diea4 ] {};
void() beast_diea4 =[ $deata4, beast_diea5 ] {};
void() beast_diea5 =[ $deata5, beast_diea6 ] {};
void() beast_diea6 =[ $deata6, beast_diea7 ] {};
void() beast_diea7 =[ $deata7, beast_diea8 ] {};
void() beast_diea8 =[ $deata8, beast_diea9 ] {};
void() beast_diea9 =[ $deata9, beast_diea10 ] {};
void() beast_diea10 =[ $deata10, beast_diea11 ] {};
void() beast_diea11 =[ $deata11, beast_diea12 ] {};
void() beast_diea12 =[ $deata12, beast_diea12 ] {};
void() beast_die =
{
// regular death
MaleDeathSound(1);
self.solid = SOLID_NOT;
if (random() > 0.5)
beast_die1 ();
else
beast_diea1 ();
};
//============================================================================
/*
==============
CheckbeastMelee
Returns TRUE if a melee attack would hit right now
==============
*/
float() CheckbeastMelee =
{
if ((enemy_range == RANGE_MELEE) && (vlen(self.origin - self.enemy.origin) < 96))
{ // FIXME: check canreach
self.attack_state = AS_MELEE;
return TRUE;
}
return FALSE;
};
/*
==============
CheckbeastJump
==============
*/
float() CheckbeastJump =
{
local vector dist, p1, p2;
local float d;
if (self.last_special > (time - 4))
return FALSE;
// check for head room
traceline(self.origin, self.origin + '0 0 64', TRUE, self);
if (trace_fraction < 1)
return FALSE;
// check if on same level as enemy
traceline(self.origin, self.origin - '0 0 64', TRUE, self);
p1 = trace_endpos;
traceline(self.enemy.origin, self.enemy.origin - '0 0 64', TRUE, self);
p2 = trace_endpos;
if (p1_z != p2_z)
return FALSE;
// now, check line of sight (between p1 and p2)
p1 = p1 + '0 0 1';
p2 = p2 + '0 0 1';
traceline(p1, p2, TRUE, world);
if (trace_fraction < 1)
return FALSE;
dist = self.enemy.origin - self.origin;
dist_z = 0;
d = vlen(dist);
if (d < 80)
return FALSE;
if (d > 256)
return FALSE;
return TRUE;
};
float() beastCheckAttack =
{
local vector vec;
// if close enough for slashing, go for it
if (CheckbeastMelee ())
{
self.attack_state = AS_MELEE;
return TRUE;
}
if (CheckbeastJump ())
{
self.attack_state = AS_MISSILE;
return TRUE;
}
return FALSE;
};
//===========================================================================
/*QUAKED monster_beast (1 0 0) (-32 -32 -24) (32 32 40) Ambush
*/
void() monster_dog =
{
remove(self);
};
void() xmen_beast =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/beast.mdl");
precache_model ("progs/pow.mdl");
// XMen matched ID sounds
// precache_sound ("zombie/z_hit.wav");
precache_sound ("zombie/z_miss.wav");
precache_sound ("doors/stndr1.wav");
precache_sound ("generic/punch1.wav");
precache_sound ("generic/punch2.wav");
precache_sound ("generic/punch3.wav");
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/beast.mdl");
setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
self.health = 100 + cvar("skill")*10;
self.th_stand = beast_stand1;
self.th_walk = beast_stand1;
self.th_run = beast_runa1;
self.th_pain = beast_pain;
self.th_die = beast_die;
self.th_melee = beast_melee;
self.th_missile = beast_xatta1;
walkmonster_start();
};