hexen2-hw-hc/hydra.hc

843 lines
16 KiB
C++

/*
* $Header: /HexenWorld/HCode/hydra.hc 2 4/20/98 2:03p Rjohnson $
*/
/*
==============================================================================
Q:\art\models\monsters\hydra\final\hydra.hc
==============================================================================
*/
// For building the model
$cd Q:\art\models\monsters\hydra\final
$origin 0 0 0
$base base 450 200
$skin skin1
$flags 0
//
$frame hadie1 hadie2 hadie3 hadie4 hadie5
$frame hadie6 hadie7 hadie8 hadie9 hadie10
$frame hadie11 hadie12 hadie13 hadie14 hadie15
$frame hadie16 hadie17 hadie18 hadie19 hadie20
$frame hadie21 hadie22 hadie23 hadie24 hadie25
$frame hadie26 hadie27 hadie28 hadie29 hadie30
$frame hadie31 hadie32 hadie33 hadie34 hadie35
$frame hadie36
//
$frame hapan1 hapan2 hapan3 hapan4 hapan5
$frame hapan6 hapan7 hapan8 hapan9 hapan10
//
$frame hlft1 hlft2 hlft3 hlft4 hlft5
$frame hlft6 hlft7 hlft8 hlft9 hlft10
$frame hlft11 hlft12 hlft13 hlft14 hlft15
$frame hlft16 hlft17 hlft18 hlft19 hlft20
$frame hlft21 hlft22 hlft23 hlft24 hlft25
$frame hlft26 hlft27 hlft28 hlft29 hlft30
//
$frame hopen1 hopen2 hopen3 hopen4 hopen5
$frame hopen6 hopen7 hopen8
//
$frame hrit1 hrit2 hrit3 hrit4 hrit5
$frame hrit6 hrit7 hrit8 hrit9 hrit10
$frame hrit11 hrit12 hrit13 hrit14 hrit15
$frame hrit16 hrit17 hrit18 hrit19 hrit20
$frame hrit21 hrit22 hrit23 hrit24 hrit25
$frame hrit26 hrit27 hrit28 hrit29 hrit30
//
$frame hsdie1 hsdie2 hsdie3 hsdie4 hsdie5
$frame hsdie6 hsdie7 hsdie8 hsdie9 hsdie10
$frame hsdie11 hsdie12 hsdie13 hsdie14 hsdie15
$frame hsdie16 hsdie17 hsdie18 hsdie19 hsdie20
$frame hsdie21 hsdie22 hsdie23 hsdie24 hsdie25
$frame hsdie26 hsdie27 hsdie28 hsdie29 hsdie30
$frame hsdie31 hsdie32 hsdie33 hsdie34 hsdie35
$frame hsdie36
//
$frame hspan1 hspan2 hspan3 hspan4 hspan5
$frame hspan6 hspan7 hspan8 hspan9 hspan10
//
$frame hspit1 hspit2 hspit3 hspit4 hspit5
$frame hspit6 hspit7 hspit8 hspit9 hspit10
$frame hspit11 hspit12
//
$frame hswim1 hswim2 hswim3 hswim4 hswim5
$frame hswim6 hswim7 hswim8 hswim9 hswim10
$frame hswim11 hswim12 hswim13 hswim14 hswim15
$frame hswim16 hswim17 hswim18 hswim19 hswim20
//
$frame htent1 htent2 htent3 htent4 htent5
$frame htent6 htent7 htent8 htent9 htent10
$frame htent11 htent12 htent13 htent14 htent15
$frame htent16 htent17 htent18 htent19 htent20
$frame htent21 htent22 htent23 htent24
// Monster Stages
float HYDRA_STAGE_WAIT = 0;
float HYDRA_STAGE_SWIM = 1;
float HYDRA_STAGE_FLOAT = 2;
float HYDRA_STAGE_STRAIGHT = 3;
float HYDRA_STAGE_REVERSE = 4;
float HYDRA_STAGE_CHARGE = 5;
float HYDRA_STAGE_ATTACK = 10;
void hydra_attack(void);
void hydra_CloseFrames(void);
void hydra_move(float thrust);
void hydra_bob(void);
void hydra_init(void)
{ // Set the hydra ready for swim
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
self.think = self.th_run;
thinktime self : random(.1,.6);
self.count = 0;
self.monster_stage = HYDRA_STAGE_SWIM;
self.hydra_FloatTo = 0;
self.goalentity = self.enemy;
self.monster_awake = TRUE;
}
void hydra_wait(void)
{
if (LocateTarget())
{ // We found a target
hydra_init();
}
}
// Starting frames for making a large turn
//void hydra_BigLeft(void);
//void hydra_BigRight(void);
// Starting frames for making a short turn
//void hydra_ShortLeft(void);
//void hydra_ShortRight(void);
void hydra_OpenFrames(void);
void hydra_TentFrames(void);
void hydra_SpitFrames(void);
float hydra_check_blind_melee();
void hydra_charge_finish()
{
self.yaw_speed = 5;
self.cnt = time + random(5,10);
if (CheckMonsterAttack(MA_MELEE, 3.0))
{
self.monster_stage += HYDRA_STAGE_ATTACK;
self.monster_check = 0;
self.think = hydra_attack;
thinktime self : 0.05;
return;
}
self.monster_stage = HYDRA_STAGE_SWIM;
self.think = self.th_run;
thinktime self : 0.1;
}
void hydra_charge()
{
float dist;
self.yaw_speed = 8;
check_pos_enemy();
ai_face();
dist = vlen(self.enemy.origin - self.origin);
movetogoal(dist / 8);
if (range(self.enemy) == RANGE_MELEE)
{
self.monster_check = 0;
hydra_charge_finish();
return;
}
if (self.hydra_chargeTime < time)
{
self.monster_check = 0;
hydra_charge_finish();
return;
}
self.think = hydra_charge;
thinktime self : 0.05;
}
float hydra_check_blind_melee(void)
{
float dist, c1;//, c2;
if (self.enemy.watertype != CONTENT_WATER) return 0;
if (self.cnt > time) return 0;
dist = vhlen(self.enemy.origin - self.origin);
traceline(self.origin, self.enemy.origin, FALSE, self);
c1 = fov(self, self.enemy, 80);
if ((dist < 256) && c1 && trace_ent == self.enemy)
{
if (random() < 0.2)
return 1;
}
return 0;
}
void hydra_blind(void)
{
stuffcmd (self.enemy, "df\n");
self.hydra_chargeTime = time + 1;
self.think = hydra_charge;
thinktime self : 0.05;
}
void hydra_checkForBlind(void)
{
float r;
r = pointcontents(self.enemy.origin);
if (r != CONTENT_WATER)
{
self.think = self.th_run;
thinktime self : 0.1;
return;
}
r = vhlen(self.enemy.origin - self.origin);
if ((r < 256) && (fov(self, self.enemy, 80)) && (fov(self.enemy, self, 80)))
{
thinktime self : 0.1;
self.think = hydra_blind;
}
else
{
self.think = self.th_run;
thinktime self : 0.1;
}
}
void hydra_swim(float thrust)
{
float dist;
float temp;
if (self.velocity) self.velocity = self.velocity * 0.7;
if (!self.enemy.flags2 & FL_ALIVE)
{
self.goalentity = self.enemy = world;
self.monster_stage = HYDRA_STAGE_WAIT;
return;
}
dist = (4.0 + thrust*6); // Movement distance this turn
movetogoal(dist);
if (self.hydra_FloatTo == 0)
{
dist = self.enemy.origin_z - self.origin_z;
if (dist < -50) self.hydra_FloatTo = dist - random(60);
else if (dist > 50) self.hydra_FloatTo = dist + random(60);
}
if (self.hydra_FloatTo < -10)
{
temp = random(-3.5,-2.5);
// movestep(0,0,temp, FALSE);
self.hydra_FloatTo -= temp;
}
else if (self.hydra_FloatTo > 10)
{
temp = random(2.5,3.5);
// movestep(0,0,temp, FALSE);
self.hydra_FloatTo -= temp;
}
else self.hydra_FloatTo = 0;
self.th_save = self.think;
//checkenemy();
enemy_range = range (self.enemy);
if (hydra_check_blind_melee())
{
self.monster_check = 2;
hydra_attack();
}
dist = vlen(self.enemy.origin - self.origin);
if (dist > 350)
{
if (CheckMonsterAttack(MA_MISSILE,8.0))
return;
}
else
CheckMonsterAttack(MA_MELEE,3.0);
}
void hydra_float(void)
{
float Length;
if (self.velocity) self.velocity = self.velocity * 0.7;
Length = vhlen(self.origin - self.enemy.origin);
if (Length < 300.0)
{
self.monster_stage = HYDRA_STAGE_SWIM;
self.hydra_FloatTo = 0;
return;
}
/*self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
ChangeYaw();*/
ai_face();
self.th_save = self.think;
enemy_range = range (self.enemy);
if (hydra_check_blind_melee())
{
self.monster_check = 2;
hydra_attack();
}
CheckMonsterAttack(MA_MISSILE,8.0);
}
void hydra_reverse(void)
{
float retval;
float dist;
self.monster_duration -= 1;
dist = 4.0; // Movement distance this turn
retval = walkmove(self.angles_y + 180, dist, FALSE);
/*if (!retval)
{
self.ideal_yaw = FindDir();
self.monster_duration = 0;//random(40,70);
self.monster_stage = HYDRA_STAGE_STRAIGHT;
ChangeYaw();//hydra_turn(200);
return;
}*/
//self.monster_stage = HYDRA_STAGE_FLOAT;
}
void hydra_move(float thrust)
{
check_pos_enemy();
if (self.monster_stage == HYDRA_STAGE_SWIM)
{
hydra_swim(thrust);
return;
}
else if (self.monster_stage == HYDRA_STAGE_FLOAT)
{
hydra_float();
return;
}
else if (self.monster_stage == HYDRA_STAGE_WAIT)
{
hydra_wait();
return;
}
else if (self.monster_stage == HYDRA_STAGE_REVERSE)
{
// hydra_reverse();
return;
}
}
void hydra_attack(void)
{
if (self.monster_check > 0)
{
hydra_SpitFrames();
}
else
{
hydra_TentFrames();
}
}
void hydra_fire(void)
{
sound (self, CHAN_WEAPON, "hydra/spit.wav", 1, ATTN_NORM);
do_spit('0 0 0');
do_spit('0 0 0');
do_spit('0 0 0');
}
void hydra_tent(float TryHit)
{
ai_face();
check_pos_enemy();
if (TryHit)
{
makevectors(self.angles);
traceline(self.origin,self.origin+v_forward*128,FALSE,self);
if (trace_ent.takedamage)
{
sound (self, CHAN_WEAPON, "hydra/tent.wav", 1, ATTN_NORM);
T_Damage (trace_ent, self, self, random(1,2));
}
else
movetogoal(15);
}
}
void hydra_open(void)
{
ai_face();
}
void hydra_bob(void)
{
local float rnd1, rnd2, rnd3;
// local vector vtmp1, modi;
rnd1 = self.velocity_x + random(-10,10);
rnd2 = self.velocity_y + random(-10,10);
rnd3 = self.velocity_z + random(10);
if (rnd1 > 10)
rnd1 = 10;
if (rnd1 < -10)
rnd1 = -10;
if (rnd2 > 10)
rnd2 = 10;
if (rnd2 < -10)
rnd2 = -10;
/* if (rnd3 < 10)
rnd3 = 15;*/
if (rnd3 > 55)
rnd3 = 50;
self.velocity_x = rnd1;
self.velocity_y = rnd2;
self.velocity_z = rnd3;
}
// Swimming
float hydra_Swim[20] =
{
-0.2,
-0.1,
0.0,
0.1, // Top going down
0.2,
0.3,
0.4,
0.5, // middle
0.4,
0.3,
0.2,
0.1, // bottom
0.0,
-0.1,
-0.2,
-0.3,
-0.4,
-0.5, // middle
-0.4,
-0.3
};
// Top = 1, tr = 2, br = 3, tl = 4, bl = 5
float hydra_TentAttacks[24] =
{
0,
0,
0,
0,
1,
0,
3,
0,
4,
0,
0,
5,
0,
0,
0,
2,
0,
0,
0,
4,
3,
1,
0,
0
};
// Attacking others
void hydra_AttackDieFrames(void)
{
self.think = hydra_AttackDieFrames;
thinktime self : HX_FRAME_TIME;
if (self.frame != $hadie36)
AdvanceFrame($hadie1,$hadie36);
if (self.frame == $hadie35)
{
self.solid = SOLID_NOT;
MakeSolidCorpse();
}
if (self.frame >= $hadie13)
hydra_bob();
if(self.health<-30)
chunk_death();
}
void hydra_AttackPainFrames(void)
{
self.think = hydra_AttackPainFrames;
thinktime self : HX_FRAME_TIME;
AdvanceFrame($hapan1,$hapan10);
}
// Swimming others
void hydra_SwimDieFrames(void)
{
self.think = hydra_SwimDieFrames;
thinktime self : HX_FRAME_TIME;
if (self.frame != $hsdie36)
AdvanceFrame($hsdie1,$hsdie36);
if (self.frame == $hsdie35)
{
self.solid = SOLID_NOT;
MakeSolidCorpse();
}
if (self.frame >= $hsdie8)
hydra_bob();
if(self.health<-30)
chunk_death();
}
void hydra_SwimPainFrames(void)
{
self.think = hydra_SwimPainFrames;
thinktime self : HX_FRAME_TIME;
AdvanceFrame($hspan1,$hspan10);
}
// Attacking
void hydra_OpenFrames(void)
{
self.think = hydra_OpenFrames;
thinktime self : HX_FRAME_TIME;
if (self.enemy.watertype != CONTENT_WATER)
{
self.monster_stage = HYDRA_STAGE_FLOAT;
self.think = self.th_run;
thinktime self : 0.1;
return;
}
hydra_open();
if (AdvanceFrame($hopen1,$hopen8) == AF_END)
{
hydra_attack();
}
}
void hydra_CloseFrames(void)
{
self.think = hydra_CloseFrames;
thinktime self : HX_FRAME_TIME;
if (RewindFrame($hopen8,$hopen1) == AF_END)
{
self.monster_stage -= HYDRA_STAGE_ATTACK;
self.think = self.th_save;
}
}
void hydra_SpitFrames(void)
{
vector vecA,vecB;
self.think = hydra_SpitFrames;
thinktime self : HX_FRAME_TIME;
self.angles_y = vectoyaw(self.enemy.origin - self.origin);
if (AdvanceFrame($hspit1,$hspit12) == AF_END)
{
self.think = hydra_CloseFrames;
self.monster_check = -1;
}
else if (self.frame == $hspit7 && self.monster_check == 2)
{
sound (self, CHAN_WEAPON, "hydra/spit.wav", 1, ATTN_NORM);
vecA = self.enemy.origin - self.origin + self.enemy.proj_ofs;
vecA = vectoangles(vecA);
makevectors(vecA);
v_forward_z = 0 - v_forward_z;
vecA = v_factor('-40 400 -40');
vecB = v_factor('40 500 40');
particle2(self.origin+v_forward*40,vecA,vecB,256,12,400);
self.think = hydra_checkForBlind;
thinktime self : 0.1;
}
else if (self.frame == $hspit8 && self.monster_check == 1)
{
hydra_fire();
}
}
void hydra_TentFrames(void)
{
float r;
if (!self.enemy.flags2 & FL_ALIVE)
{
self.goalentity = self.enemy = world;
self.monster_stage = HYDRA_STAGE_WAIT;
self.think = self.th_stand;
thinktime self : 0.1;
return;
}
self.think = hydra_TentFrames;
thinktime self : 0.025;
if (AdvanceFrame($htent1,$htent24) == AF_END)
{
r = range(self.enemy);
if ((r == RANGE_MELEE) && (random(0, 1) < 0.3))
{
self.frame = $htent1;
hydra_tent(hydra_TentAttacks[self.frame - $htent1]);
}
else
self.think = hydra_CloseFrames;
}
else
{
hydra_tent(hydra_TentAttacks[self.frame - $htent1]);
}
}
// Regular swimming / movement
void hydra_SwimFrames(void)
{
self.think = hydra_SwimFrames;
thinktime self : HX_FRAME_TIME;
AdvanceFrame($hswim1,$hswim20);
if (self.frame == $hswim1)
sound (self, CHAN_WEAPON, "hydra/swim.wav", 1, ATTN_NORM);
hydra_move((hydra_Swim[self.frame - $hswim1]) + 0.3);
}
/*QUAKED misc_fountain (0 1 0.8) (0 0 0) (32 32 32)
New item for QuakeEd
-------------------------FIELDS-------------------------
angles 0 0 0 the direction it should move the particles
movedir 1 1 1 the force it should move them
color 256 the color
cnt 2 the number of particles each time
--------------------------------------------------------
*/
void misc_fountain(void)
{
starteffect(CE_FOUNTAIN, self.origin, self.angles,self.movedir,self.color,self.cnt);
}
void do_hydra_spit(void)
{
self.monster_check = 1;
self.monster_stage += HYDRA_STAGE_ATTACK;
sound (self, CHAN_WEAPON, "hydra/open.wav", 1, ATTN_NORM);
hydra_OpenFrames();
}
void do_hydra_tent(void)
{
self.monster_check = 0;
self.monster_stage += HYDRA_STAGE_ATTACK;
sound (self, CHAN_WEAPON, "hydra/open.wav", 1, ATTN_NORM);
hydra_OpenFrames();
}
void do_hydra_die(void)
{
self.flags (+) FL_SWIM;
sound (self, CHAN_WEAPON, "hydra/die.wav", 1, ATTN_NORM);
if (self.monster_stage >= HYDRA_STAGE_ATTACK)
hydra_AttackDieFrames();
else
hydra_SwimDieFrames();
}
void hydra_retreat()
{
self.monster_stage = HYDRA_STAGE_REVERSE;
self.think = self.th_run;
thinktime self : 0.1;
}
void hydra_pain(entity attacker, float damage)
{
sound (self, CHAN_WEAPON, "hydra/pain.wav", 1, ATTN_NORM);
}
void init_hydra(void)
{
if (deathmatch)
{
remove(self);
return;
}
self.monster_stage = HYDRA_STAGE_WAIT;
precache_model ("models/hydra.mdl");
precache_model ("models/spit.mdl");
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_SWIM;
self.thingtype=THINGTYPE_FLESH;
self.classname="monster_hydra";
self.mass = 7;
setmodel (self, "models/hydra.mdl");
self.skin = 0;
setsize (self, '-30 -30 -24', '30 30 24');
self.hull = HULL_SCORPION;
//self.hull = HULL_HYDRA;
self.health = 125;
self.experience_value = 50;
self.mintel = 4;
self.th_stand = hydra_SwimFrames;
self.th_walk = hydra_SwimFrames;
self.th_run = hydra_SwimFrames;
self.th_pain = hydra_pain;
self.th_die = do_hydra_die;
self.th_missile = do_hydra_spit;
self.th_melee = do_hydra_tent;
self.takedamage = DAMAGE_YES;
self.flags2 (+) FL_ALIVE;
self.ideal_yaw = self.angles * '0 1 0';
if (!self.yaw_speed)
self.yaw_speed = 5;
self.view_ofs = '0 0 0';
self.use = monster_use;
self.flags (+) FL_SWIM | FL_MONSTER;
self.pausetime = 99999999;
total_monsters += 1;
thinktime self : random(0.5);
self.think = self.th_stand;
}
/*QUAKED monster_hydra (1 0.3 0) (-40 -40 -42) (40 40 42) STAND HOVER JUMP PLAY_DEAD DORMANT
New item for QuakeEd
-------------------------FIELDS-------------------------
NOTE: Normal QuakEd monster spawnflags don't apply here (no_jump, play_dead, no_drop)
--------------------------------------------------------
*/
void monster_hydra(void)
{
init_hydra();
precache_sound("hydra/pain.wav");
precache_sound("hydra/die.wav");
precache_sound("hydra/open.wav");
precache_sound5("hydra/turn-s.wav");
precache_sound("hydra/turn-b.wav");
precache_sound("hydra/swim.wav");
precache_sound("hydra/tent.wav");
precache_sound("hydra/spit.wav");
}