350 lines
8.2 KiB
C++
350 lines
8.2 KiB
C++
|
/*
|
||
|
* $Header: /H2 Mission Pack/HCode/ravenai.hc 2 2/12/98 5:55p Jmonroe $
|
||
|
*/
|
||
|
|
||
|
float() LocateTarget =
|
||
|
{
|
||
|
return FindTarget(TRUE);
|
||
|
};
|
||
|
|
||
|
float MA_SUCCESSFUL = 0;
|
||
|
float MA_BLOCKED = -1;
|
||
|
float MA_CROSSED = -2;
|
||
|
float MA_NOWEAPON = -3;
|
||
|
float MA_TOOSOON = -4;
|
||
|
float MA_TOOFAR = -5;
|
||
|
float MA_NOATTACK = -6;
|
||
|
|
||
|
float MA_MELEE = 1;
|
||
|
float MA_MISSILE = 2;
|
||
|
float MA_BOTH = 3;
|
||
|
float MA_FAR_MELEE = 4;
|
||
|
float MA_SHORT_MISSILE = 8;
|
||
|
|
||
|
// You must perform the following call sometime before calling this function:
|
||
|
// enemy_range = range (self.enemy);
|
||
|
float(float AttackType, float ChanceModifier) CheckMonsterAttack =
|
||
|
{
|
||
|
local vector spot1, spot2;
|
||
|
local entity targ;
|
||
|
local float chance;
|
||
|
|
||
|
targ = self.enemy;
|
||
|
|
||
|
if (self.classname == "monster_hydra")
|
||
|
if (self.enemy.watertype != CONTENT_WATER)
|
||
|
{
|
||
|
if (self.search_time < time)
|
||
|
{
|
||
|
self.monster_stage = 0;
|
||
|
self.enemy = world;
|
||
|
return 0;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
else self.search_time = time + 5;
|
||
|
|
||
|
// see if any entities are in the way of the shot
|
||
|
spot1 = self.origin + self.view_ofs;
|
||
|
spot2 = targ.origin + targ.view_ofs;
|
||
|
|
||
|
traceline (spot1, spot2, FALSE, self);
|
||
|
|
||
|
if(trace_ent.thingtype>=THINGTYPE_WEBS)
|
||
|
traceline (trace_endpos, spot2, FALSE, trace_ent);
|
||
|
|
||
|
if (trace_ent != targ)
|
||
|
if(trace_ent.health>25||!trace_ent.takedamage||(trace_ent.flags&FL_MONSTER&&trace_ent.classname!="player_sheep"))
|
||
|
return MA_BLOCKED; // don't have a clear shot
|
||
|
|
||
|
if (trace_inopen && trace_inwater)
|
||
|
return MA_CROSSED; // sight line crossed contents
|
||
|
|
||
|
if (enemy_range == RANGE_MELEE)
|
||
|
{ // melee attack
|
||
|
if (AttackType & MA_SHORT_MISSILE)
|
||
|
{
|
||
|
if (random() < 0.5)
|
||
|
{
|
||
|
self.th_missile ();
|
||
|
return MA_SUCCESSFUL;
|
||
|
}
|
||
|
}
|
||
|
if (self.th_melee)
|
||
|
{
|
||
|
if (AttackType & MA_MELEE)
|
||
|
{
|
||
|
self.th_melee ();
|
||
|
return MA_SUCCESSFUL;
|
||
|
}
|
||
|
else
|
||
|
return MA_NOWEAPON;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// missile attack
|
||
|
if (!self.th_missile || !(AttackType & (MA_MISSILE | MA_FAR_MELEE)))
|
||
|
{
|
||
|
return MA_NOWEAPON;
|
||
|
}
|
||
|
|
||
|
if (time < self.attack_finished)
|
||
|
return MA_TOOSOON;
|
||
|
|
||
|
if (enemy_range == RANGE_FAR)
|
||
|
return MA_TOOFAR;
|
||
|
|
||
|
if (enemy_range == RANGE_MELEE)
|
||
|
{
|
||
|
chance = 0.9;
|
||
|
self.attack_finished = 0;
|
||
|
}
|
||
|
else if (enemy_range == RANGE_NEAR)
|
||
|
{
|
||
|
if (self.th_melee)
|
||
|
chance = 0.2;
|
||
|
else
|
||
|
chance = 0.4;
|
||
|
}
|
||
|
else if (enemy_range == RANGE_MID)
|
||
|
{
|
||
|
if (self.th_melee)
|
||
|
chance = 0.05;
|
||
|
else
|
||
|
chance = 0.1;
|
||
|
}
|
||
|
else
|
||
|
chance = 0;
|
||
|
|
||
|
chance = chance * ChanceModifier;
|
||
|
if (chance > 0.95) chance = 0.95;
|
||
|
|
||
|
if (random () < chance)
|
||
|
{
|
||
|
if (self.th_melee)
|
||
|
{ // quake c wouldn't allow me to put this in on if!!!
|
||
|
if (AttackType & MA_FAR_MELEE)
|
||
|
{
|
||
|
self.th_melee ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.th_missile ();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.th_missile ();
|
||
|
}
|
||
|
// SUB_AttackFinished (random(2,0));
|
||
|
SUB_AttackFinished (random(8,0));
|
||
|
return MA_SUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
return MA_NOATTACK;
|
||
|
};
|
||
|
|
||
|
float (vector offset, vector to_where)monster_checkpos =
|
||
|
{
|
||
|
// This function will trace 2 lines - the first line will go from the origin to the offset from the origin.
|
||
|
// If this could be done atleast half way, then a 2nd trace is done from the end point of the first trace
|
||
|
// to the final destination. If this was mostly successful, then the function will return true, otherwise
|
||
|
// false. You would use this function in a situation where you want to see if the enemy is visibile from
|
||
|
// your right side, so you first see if you can go do the right side, then go forward from there to the enemy.
|
||
|
local vector start;
|
||
|
local float length;
|
||
|
|
||
|
start = self.origin + offset;
|
||
|
traceline (self.origin, start, FALSE, self);
|
||
|
if (trace_fraction < 0.5)
|
||
|
{ // Couldn't get to the offset
|
||
|
return FALSE;
|
||
|
}
|
||
|
length = vlen(self.origin-start) * trace_fraction;
|
||
|
start = trace_endpos;
|
||
|
traceline (start,to_where, FALSE, self);
|
||
|
if (trace_ent == self.enemy || trace_fraction > 0.98)
|
||
|
{ // We found the enemy!
|
||
|
length = length + vlen(start-self.enemy.origin) * trace_fraction;
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
};
|
||
|
|
||
|
|
||
|
void (float l, float r, float u, float d, float last_move, vector where) find_path =
|
||
|
{
|
||
|
// This function will check to see if an enemy can be located from the top, bottom, left, and right sides.
|
||
|
// The l, r, u, d parameters specify the order for which the search should be done. If it couldn't find
|
||
|
// the enemy, then it will try the last seen position of the enemy. last_move indicates that the previous
|
||
|
// move was successful (i.e. the monster could move forward). where is the position to check for.
|
||
|
local float length;
|
||
|
local float newyaw;
|
||
|
local float newz;
|
||
|
local float c;
|
||
|
local float retval;
|
||
|
// local vector a, b;
|
||
|
|
||
|
makevectors (self.angles);
|
||
|
length = 99999;
|
||
|
newyaw = self.ideal_yaw;
|
||
|
newz = self.velocity_z;
|
||
|
|
||
|
c = 0;
|
||
|
while(c<=4)
|
||
|
{ // We have 5 checks to do
|
||
|
if (c == 0 && last_move)
|
||
|
{ // Try checking forward
|
||
|
retval = monster_checkpos(v_forward*300,where);
|
||
|
if (retval && retval < length)
|
||
|
{
|
||
|
//dprint("found you to the forward\n");
|
||
|
self.monster_duration = 18 + 5;
|
||
|
length = retval;
|
||
|
}
|
||
|
}
|
||
|
if (c == l)
|
||
|
{ // Try checking to the left
|
||
|
retval = monster_checkpos(v_right*-200,where);
|
||
|
if (retval && retval < length)
|
||
|
{
|
||
|
//dprint("found you to the left\n");
|
||
|
newyaw = self.angles_y + 90;
|
||
|
self.monster_duration = 18 + 5;
|
||
|
length = retval;
|
||
|
}
|
||
|
}
|
||
|
else if (c == r)
|
||
|
{ // Try checking to the right
|
||
|
retval = monster_checkpos(v_right*200,where);
|
||
|
if (retval && retval < length)
|
||
|
{
|
||
|
//dprint("found you to the right\n");
|
||
|
newyaw = self.angles_y - 90;
|
||
|
self.monster_duration = 18 + 5;
|
||
|
length = retval;
|
||
|
}
|
||
|
}
|
||
|
else if (c == u)
|
||
|
{ // Try checking to the top
|
||
|
retval = monster_checkpos(v_up*200,where);
|
||
|
if (retval && retval < length)
|
||
|
{
|
||
|
//dprint("found you to the up\n");
|
||
|
newz = 30;
|
||
|
self.monster_duration = 18 + 5;
|
||
|
length = retval;
|
||
|
}
|
||
|
}
|
||
|
else if (c == d)
|
||
|
{ // Try checking to the bottom
|
||
|
retval = monster_checkpos(v_up*-200,where);
|
||
|
if (retval && retval < length)
|
||
|
{
|
||
|
//dprint("found you to the down\n");
|
||
|
newz = -30;
|
||
|
self.monster_duration = 18 + 5;
|
||
|
length = retval;
|
||
|
}
|
||
|
}
|
||
|
c = c + 1;
|
||
|
}
|
||
|
|
||
|
if (length == 99999 && self.monster_last_seen != where)
|
||
|
{ // If we didn't find a direction, and we haven't done this, try looking where the enemy
|
||
|
// was last seen
|
||
|
find_path(l,r,u,d,0,self.monster_last_seen);
|
||
|
//dprint("Using last seen\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.ideal_yaw = newyaw;
|
||
|
self.velocity_z = newz;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
float () FindDir =
|
||
|
{ // Monster couldn't go in the direction it is pointed to, so find one it can go to
|
||
|
local vector a,b,c;
|
||
|
local float inc,step;
|
||
|
|
||
|
if (random() < 0.5) inc = 45;
|
||
|
else inc = -45;
|
||
|
|
||
|
c = '0 0 0';
|
||
|
c_y = c_y + inc;
|
||
|
|
||
|
step = 0;
|
||
|
while(step < 6)
|
||
|
{ // 7 directions to check (45 degrees each)
|
||
|
makevectors (self.angles + c);
|
||
|
a = self.origin + self.view_ofs;
|
||
|
b = a + v_forward*100;
|
||
|
|
||
|
traceline (a, b, FALSE, self);
|
||
|
|
||
|
if (trace_fraction > 0.9)
|
||
|
{ // We can mostly go this direction
|
||
|
return self.angles_y + c_y;
|
||
|
//dprint(" found\n");
|
||
|
}
|
||
|
c_y = c_y + inc;
|
||
|
step = step + 1;
|
||
|
}
|
||
|
|
||
|
return self.angles_y;
|
||
|
};
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* $Log: /H2 Mission Pack/HCode/ravenai.hc $
|
||
|
*
|
||
|
* 2 2/12/98 5:55p Jmonroe
|
||
|
* remove unreferenced funcs
|
||
|
*
|
||
|
* 18 10/28/97 1:01p Mgummelt
|
||
|
* Massive replacement, rewrote entire code... just kidding. Added
|
||
|
* support for 5th class.
|
||
|
*
|
||
|
* 16 9/03/97 9:14p Mgummelt
|
||
|
* Fixing targetting AI
|
||
|
*
|
||
|
* 15 8/26/97 2:26a Mgummelt
|
||
|
*
|
||
|
* 14 8/14/97 10:28p Bgokey
|
||
|
*
|
||
|
* 13 8/14/97 7:32p Bgokey
|
||
|
*
|
||
|
* 12 8/14/97 7:05p Bgokey
|
||
|
*
|
||
|
* 11 8/12/97 6:10p Mgummelt
|
||
|
*
|
||
|
* 10 7/21/97 4:04p Mgummelt
|
||
|
*
|
||
|
* 9 7/21/97 4:02p Mgummelt
|
||
|
*
|
||
|
* 8 6/18/97 5:40p Mgummelt
|
||
|
*
|
||
|
* 7 6/16/97 12:03p Rjohnson
|
||
|
* Removed imp stuff
|
||
|
*
|
||
|
* 6 5/31/97 4:00p Mgummelt
|
||
|
*
|
||
|
* 5 5/30/97 10:04p Mgummelt
|
||
|
*
|
||
|
* 4 2/26/97 3:14p Rlove
|
||
|
* Changes to basic monster ai
|
||
|
*
|
||
|
* 3 1/09/97 1:48p Rjohnson
|
||
|
* Made FindDir() return a direction instead of just setting it
|
||
|
*
|
||
|
* 2 1/02/97 11:20a Rjohnson
|
||
|
* Christmas Changes
|
||
|
*
|
||
|
* 1 12/17/96 10:38a Rjohnson
|
||
|
* Initial Version
|
||
|
*/
|