hexen2-data1-hc/rider.hc

708 lines
15 KiB
C++

/*QUAKED rider_path (0.5 0.3 0) (-8 -8 -8) (8 8 8)
Specifies a path point for a rider. You can specify
up to 4 other places that the rider can go after this
point.
-------------------------FIELDS-------------------------
path_id: number (id) of this path point
next_path_1: number (id) of a possible next point
next_path_2: number (id) of a possible next point
next_path_3: number (id) of a possible next point
next_path_4: number (id) of a possible next point
--------------------------------------------------------
*/
void rider_path(void)
{
}
void riderpath_init(void)
{
entity search,found;
found = world;
search = find(world, classname, "rider_path");
while(search != world && found == world)
{
if (search.path_id == 1)
found = search;
else
search = find(search, classname, "rider_path");
}
if (found==world)
{
dprint("No starting point for rider\n");
remove(self);
return;
}
self.path_current=self.path_last = found;
}
void riderpath_findnext(void)
{
entity search,found;
float next,num_points,position;
num_points = 0;
if (self.path_current.next_path_1)
num_points += 1;
if (self.path_current.next_path_2)
num_points += 1;
if (self.path_current.next_path_3)
num_points += 1;
if (self.path_current.next_path_4)
num_points += 1;
if (!num_points)
{
dprintf("rider path %s has no next points\n",self.path_id);
remove(self);
return;
}
position = random(num_points);
// dprintf("Num_points is %s ",num_points);
// dprintf("position is %s\n",position);
num_points = next = 0;
if (self.path_current.next_path_1)
{
num_points += 1;
if (position <= num_points && !next)
next = self.path_current.next_path_1;
}
if (self.path_current.next_path_2)
{
num_points += 1;
if (position <= num_points && !next)
next = self.path_current.next_path_2;
}
if (self.path_current.next_path_3)
{
num_points += 1;
if (position <= num_points && !next)
next = self.path_current.next_path_3;
}
if (self.path_current.next_path_4)
{
num_points += 1;
if (position <= num_points && !next)
next = self.path_current.next_path_4;
}
if (!next)
{
dprint("Internal error for rider path\n");
dprintf(" Next is %s\n",next);
dprintf(" Num_points is %s\n",num_points);
dprintf(" position is %s\n",position);
return;
}
found = world;
search = find(world, classname, "rider_path");
while(search != world && found == world)
{
if (search.path_id == next)
found = search;
else
search = find(search, classname, "rider_path");
}
if (!found)
{
dprintf("Could not find rider path %s\n",next);
remove(self);
return;
}
else
self.path_current = found;
}
void rider_die(void);
void riderpath_move(float move_speed)
{
float distance, altitude, temp;
vector displace;
entity save_ent;
if(self.velocity!='0 0 0')
self.velocity='0 0 0';
self.ideal_yaw = vectoyaw(self.path_current.origin - self.origin);
self.rider_last_y_change = self.rider_y_change;
self.rider_y_change = ChangeYaw();
//rj rider_die();
if (self.movetype == MOVETYPE_FLY)
{
distance = vhlen(self.origin - self.path_current.origin);
altitude = self.path_current.origin_z - self.origin_z;
if (distance < 400)
{
// altitude *= 0.06;
temp = (distance - self.rider_path_distance) / (400-self.rider_path_distance);
temp = 1-temp;
temp = temp / 6;
if (altitude > 30)
{
self.angles_x = temp * 200;
self.rider_move_adjustment -= 0.1;
}
else if (altitude < -30)
{
self.angles_x = 0 - (temp * 200);
self.rider_move_adjustment += 0.15;
}
if (altitude > 60)
{
self.rider_move_adjustment -= 0.1;
}
else if (altitude < -60)
{
self.rider_move_adjustment += 0.15;
}
altitude *= temp;
}
else
{
altitude = 0;
self.angles_x -= self.angles_x / 10;
self.rider_move_adjustment -= self.rider_move_adjustment / 15;
}
// dprintf("Move adjustment %s\n",self.rider_move_adjustment);
self.origin_z += altitude;
// altitude = self.path_current.origin_z - self.origin_z;
// dprintf("Flying: distance %s",distance);
// dprintf(" Alt is %s\n",altitude);
}
move_speed += self.rider_move_adjustment;
if(!walkmove(self.angles_y, move_speed, TRUE))
{
save_ent=self.goalentity;
self.goalentity=self.path_current;
movetogoal(move_speed);
self.goalentity=save_ent;
}
if (self.classname != "rider_famine") // Famine doesn't do radius pain
{
if (trace_ent)//!=world&&trace_ent.classname!="ghost")
{
displace = normalize(trace_ent.origin - self.origin);
if (infront(trace_ent))
{
trace_ent.velocity += displace*random(1000,1600);
T_Damage (trace_ent, self, self, random(25,35));
if(trace_ent.flags&FL_CLIENT)
{
trace_ent.punchangle_x = random(-9,-1);
trace_ent.punchangle_y = random(-10,10);
trace_ent.punchangle_z = random(-10,10);
}
}
else
{
trace_ent.velocity += displace*random(700,900);
T_Damage (trace_ent, self, self, random(15,20));
if(trace_ent.flags&FL_CLIENT)
{
trace_ent.punchangle_x = random(-3,2);
trace_ent.punchangle_y = random(-5,5);
trace_ent.punchangle_z = random(-5,5);
}
}
}
}
distance = vhlen(self.origin - self.path_current.origin);
if (distance < self.rider_path_distance)
riderpath_findnext();
}
void rider_multi_wait(void)
{
if (self.max_health)
{
self.health = self.max_health;
self.takedamage = DAMAGE_NO_GRENADE;
self.solid = SOLID_BBOX;
}
}
void rider_multi_trigger(void)
{
if (self.nextthink > time)
{
return; // allready been triggered
}
if (self.enemy.classname != "rider_war")
{
return;
}
if (random() <= self.rt_chance)
{
if (self.noise) sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
// don't trigger again until reset
self.takedamage = DAMAGE_NO;
activator = self.enemy;
SUB_UseTargets();
}
if (self.wait > 0)
{
self.think = rider_multi_wait;
thinktime self : self.wait;
}
else
{ // we can't just remove (self) here, because this is a touch function
// called while C code is looping through area links...
self.touch = SUB_Null;
thinktime self : 0.1;
self.think = SUB_Remove;
}
}
void rider_multi_use(void)
{
if (time < self.attack_finished)
return;
self.enemy = activator;
rider_multi_trigger();
}
void rider_multi_touch(void)
{
if (time < self.attack_finished)
return;
// if the trigger has an angles field, check player's facing direction
if (self.movedir != '0 0 0')
{
makevectors (other.angles);
if (v_forward * self.movedir < 0)
return; // not facing the right way
}
self.enemy = other;
rider_multi_trigger ();
}
/*QUAKED rider_trigger_multiple (0.5 0.15 0) ?
-------------------------FIELDS-------------------------
rt_chance: chance (0-1) that the trigger will be run
--------------------------------------------------------
*/
void rider_trigger_multiple(void)
{
if (!self.wait)
self.wait = 0.2;
self.use = rider_multi_use;
InitTrigger ();
if (self.health)
{
self.max_health = self.health;
self.th_die = multi_killed;
self.takedamage = DAMAGE_NO_GRENADE;
self.solid = SOLID_BBOX;
setorigin (self, self.origin); // make sure it links into the world
}
else
{
self.touch = rider_multi_touch;
}
}
/*QUAKED rider_trigger_once (0.5 0.15 0) ?
-------------------------FIELDS-------------------------
rt_chance: chance (0-1) that the trigger will be run
--------------------------------------------------------
*/
void rider_trigger_once(void)
{
self.wait = -1;
rider_trigger_multiple();
}
void beam_move(void)
{
thinktime self : HX_FRAME_TIME;
if (self.scale < self.beam_max_scale)
self.scale += 0.6;
else
self.scale = self.beam_max_scale;
if (self.beam_direction)
{
self.beam_angle_a += self.beam_speed;
if (self.beam_angle_a >= 360) self.beam_angle_a -= 360;
}
else
{
self.beam_angle_a -= self.beam_speed;
if (self.beam_angle_a < 0) self.beam_angle_a += 360;
}
self.angles_x = cos(self.beam_angle_a) * self.beam_angle_b;
self.angles_z = sin(self.beam_angle_a) * self.beam_angle_b;
}
void star_think(void)
{
thinktime self : HX_FRAME_TIME;
self.velocity = self.velocity * 1.05;
if (self.scale < 2)
self.scale *= 1.08;
}
void rider_star(void)
{
entity star;
float angle;
if (random() < 0.5)
return;
star = spawn();
setmodel(star,"models/boss/star.mdl");
setorigin(star,self.origin);
setsize (star, '0 0 0', '0 0 0');
star.owner = self.owner;
star.movetype = MOVETYPE_FLYMISSILE;
star.solid = SOLID_BBOX;
star.avelocity = randomv('40 40 40', '100 100 100');
star.scale = 0.1;
angle = random(360);
star.velocity_x = cos(angle)*300;
star.velocity_y = sin(angle)*300;
star.classname = "rider_temp";
star.think = star_think;
star.touch = SUB_Remove;
thinktime star : HX_FRAME_TIME;
}
void circle_think(void)
{
thinktime self : HX_FRAME_TIME;
rider_star();
if (self.monster_stage == 0)
{
self.scale *= 1.0275;
if (self.scale >= 2.5)
{
self.monster_stage = 1;
self.scale = 2.5;
}
}
else if (self.monster_stage == 1)
{
self.scale -= random(.1);
if (self.scale < 1.5 || random() < 0.1)
self.monster_stage = 2;
}
else if (self.monster_stage == 2)
{
self.scale += random(.1);
if (self.scale >= 2.5)
{
self.monster_stage = 1;
self.scale = 2.5;
}
else if (random() < 0.1)
self.monster_stage = 1;
}
}
void rider_eol(void)
{
entity search;
if (self.count == 0)
{
self.count = 1;
self.effects (-) EF_BRIGHTLIGHT;
self.effects (+) EF_NODRAW;
if(self.movechain!=world)
self.movechain.effects (+) EF_NODRAW;
thinktime self : 5;
search = find(world, classname, "rider_temp");
while (search != world)
{
remove(search);
search = find(search, classname, "rider_temp");
}
return;
}
// return;
nextmap = self.map;
nextstartspot = self.target;
//rj nextmap = "rick1";
intermission_running = 1;
if (deathmatch)
intermission_exittime = time + 5;
else if (self.classname == "monster_eidolon")
intermission_exittime = time + 99999;
else
intermission_exittime = time + 2;
//Remove cross-level trigger server flags for next hub
serverflags(-)(SFL_CROSS_TRIGGER_1|
SFL_CROSS_TRIGGER_2|
SFL_CROSS_TRIGGER_3|
SFL_CROSS_TRIGGER_4|
SFL_CROSS_TRIGGER_5|
SFL_CROSS_TRIGGER_6|
SFL_CROSS_TRIGGER_7|
SFL_CROSS_TRIGGER_8);
search=find(world,classname,"player");
while(search)
{//Take away all their goodies
search.puzzle_inv1 = string_null;
search.puzzle_inv2 = string_null;
search.puzzle_inv3 = string_null;
search.puzzle_inv4 = string_null;
search.puzzle_inv5 = string_null;
search.puzzle_inv6 = string_null;
search.puzzle_inv7 = string_null;
search.puzzle_inv8 = string_null;
search=find(search,classname,"player");
}
WriteByte (MSG_ALL, SVC_INTERMISSION);
if (!cvar("registered") && cvar("oem"))
{
WriteByte (MSG_ALL, 9);
intermission_exittime = time + 99999;
}
else if (self.classname == "rider_famine")
WriteByte (MSG_ALL, 1);
else if (self.classname == "rider_death")
WriteByte (MSG_ALL, 2);
else if (self.classname == "rider_pestilence")
WriteByte (MSG_ALL, 3);
else if (self.classname == "rider_war")
WriteByte (MSG_ALL, 4);
else if (self.classname == "monster_eidolon")
WriteByte (MSG_ALL, 6);
else
dprint("Invalid boss creature\n");
FreezeAllEntities();
}
void rider_die(void)
{
entity beam;
entity save;
entity found;
vector new_origin;
if (self.think != rider_die)
{
SUB_UseTargets();
self.think = rider_die;
self.count = 0;
thinktime self : HX_FRAME_TIME;
self.rider_death_speed = 0.2;
// self.effects = EF_NODRAW;
return;
}
if (self.count == 0)
{
sound (self, CHAN_AUTO, "famine/flashdie.wav", 1, ATTN_NONE); // Start of the death flash
found=find(world,classname,"player");
while(found)
{//Give them all the exp
AwardExperience(found,self,self.experience_value);
found=find(found,classname,"player");
}
self.experience_value=FALSE;
self.drawflags = self.drawflags | MLS_ABSLIGHT;
self.abslight = 3;
if(self.noise)
sound(self,CHAN_VOICE,self.noise,1,ATTN_NONE);
self.movetype=MOVETYPE_NONE;
self.velocity='0 0 0';
}
thinktime self : self.rider_death_speed;
self.rider_death_speed += 0.1;
if (self.count >= 10)
{
if (self.count == 3)
{
beam = spawn();
new_origin = self.origin + '0 0 50';
setmodel(beam,"models/boss/circle.mdl");
setorigin(beam,new_origin);
setsize (beam, '0 0 0', '0 0 0');
beam.owner = self;
beam.movetype = MOVETYPE_FLYMISSILE;
beam.solid = SOLID_NOT;
beam.drawflags = SCALE_TYPE_UNIFORM;
beam.scale = .1;
beam.skin = 0;
beam.avelocity = '0 0 300';
beam.think = circle_think;
thinktime beam : HX_FRAME_TIME;
self.count = 13;
}
self.count = 0;
self.think = rider_eol;
thinktime self : .5;
return;
}
else
{
self.effects = EF_BRIGHTLIGHT;
// self.effects = EF_NODRAW;
if (self.count == 3)
{
beam = spawn();
new_origin = self.origin + '0 0 50';
setmodel(beam,"models/boss/circle.mdl");
setorigin(beam,new_origin);
setsize (beam, '0 0 0', '0 0 0');
beam.owner = self;
beam.movetype = MOVETYPE_FLYMISSILE;
beam.solid = SOLID_NOT;
beam.drawflags = SCALE_TYPE_UNIFORM;
beam.scale = .1;
beam.skin = 0;
beam.avelocity = '0 0 300';
beam.classname = "rider_temp";
beam.think = circle_think;
thinktime beam : HX_FRAME_TIME;
}
else if (self.count == 0)
{
starteffect(18, self.origin + '0 0 40');
}
}
self.count += 1;
beam = spawn();
makevectors(self.angles);
// new_origin = v_factorrange('-3 -25 45', '3 25 50') + self.origin;
new_origin = self.origin + '0 0 50';
setmodel(beam,"models/boss/shaft.mdl");
setorigin(beam,new_origin);
setsize (beam, '0 0 0', '0 0 0');
beam.owner = self;
beam.drawflags = SCALE_ORIGIN_BOTTOM | SCALE_TYPE_XYONLY;
beam.movetype = MOVETYPE_FLYMISSILE;
beam.solid = SOLID_NOT;
beam.think = beam_move;
beam.angles = '0 0 0';
beam.angles_x = random(-50,50);
beam.angles_z = random(-50,50);
beam.beam_angle_a = random(360);
beam.beam_angle_b = random(20,130);
beam.scale = .1;
beam.beam_max_scale = random(.5,1.5);
beam.classname = "rider_temp";
if (random() > 0.5)
beam.beam_direction = 1;
beam.beam_speed = random(2,4.5);
save = self;
self = beam;
beam_move();
self = save;
}
void rider_use(void)
{
thinktime self : 0.2; // wait for path points to spawn
}
void rider_init(void)
{
precache_model3 ("models/boss/shaft.mdl");
precache_model3 ("models/boss/circle.mdl");
precache_model3 ("models/boss/star.mdl");
precache_sound3 ("famine/flashdie.wav");
total_monsters += 1;
self.takedamage = DAMAGE_YES;
self.flags(+)FL_MONSTER;
self.flags2(+)FL_ALIVE;
self.thingtype=THINGTYPE_FLESH;
if(self.classname!="monster_eidolon")
self.monsterclass=CLASS_BOSS;
self.th_die = rider_die;
self.use = rider_use;
if (!(self.spawnflags & 1))
thinktime self : 0.2; // wait for path points to spawn
}