engine/quakec/basemod/fight.qc

366 lines
6.4 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
A monster is in fight mode if it thinks it can effectively attack its
enemy.
When it decides it can't attack, it goes into hunt mode.
*/
float(float v) anglemod;
void() ai_face;
//=============================================================================
/*
===========
CheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
BOOL(float enemy_range) CheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
targ = self.enemy;
// 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 != targ)
return FALSE; // don't have a clear shot
if (trace_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (enemy_range == RANGE_MELEE)
{ // melee attack
if (self.th_melee)
{
self.th_melee ();
return TRUE;
}
}
// missile attack
if (!self.th_missile)
return FALSE;
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_FAR)
return FALSE;
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;
if (random () < chance)
{
self.th_missile ();
SUB_AttackFinished (2*random());
return TRUE;
}
return FALSE;
};
/*
=============
ai_face
Stay facing the enemy
=============
*/
void() ai_face =
{
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
ChangeYaw ();
};
/*
=============
ai_charge
The monster is in a melee attack, so get as close as possible to .enemy
=============
*/
BOOL (entity targ) visible;
BOOL(entity targ) infront;
float(entity targ) range;
void(float d) ai_charge =
{
ai_face ();
movetogoal (d); // done in C code...
};
void() ai_charge_side =
{
local vector dtemp;
local float heading;
// aim to the left of the enemy for a flyby
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
ChangeYaw ();
makevectors (self.angles);
dtemp = self.enemy.origin - 30*v_right;
heading = vectoyaw(dtemp - self.origin);
walkmove(heading, 20);
};
/*
=============
ai_melee
=============
*/
void(INTEGER mod) ai_melee =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return; // removed before stroke
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 60)
return;
ldmg = (random() + random() + random()) * 3;
T_Damage (self.enemy, self, self, ldmg, mod);
};
void(INTEGER mod) ai_melee_side =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return; // removed before stroke
ai_charge_side();
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 60)
return;
if (!CanDamage (self.enemy, self))
return;
ldmg = (random() + random() + random()) * 3;
T_Damage (self.enemy, self, self, ldmg, mod);
};
//=============================================================================
/*
===========
SoldierCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
BOOL(float enemy_range) SoldierCheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
targ = self.enemy;
// 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_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (trace_ent != targ)
return FALSE; // don't have a clear shot
// missile attack
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_FAR)
return FALSE;
if (enemy_range == RANGE_MELEE)
chance = 0.9;
else if (enemy_range == RANGE_NEAR)
chance = 0.4;
else if (enemy_range == RANGE_MID)
chance = 0.05;
else
chance = 0;
if (random() < chance)
{
self.th_missile ();
SUB_AttackFinished (1 + random());
return TRUE;
}
return FALSE;
};
//=============================================================================
/*
===========
ShamCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
BOOL(float enemy_range) ShamCheckAttack =
{
local vector spot1, spot2;
local entity targ;
// local float chance;
// local float enemy_yaw;
if (enemy_range == RANGE_MELEE)
{
if (CanDamage (self.enemy, self))
{
self.attack_state = AS_MELEE;
return TRUE;
}
}
if (time < self.attack_finished)
return FALSE;
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;
if (vlen(spot1 - spot2) > 600)
return FALSE;
traceline (spot1, spot2, FALSE, self);
if (trace_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (trace_ent != targ)
{
return FALSE; // don't have a clear shot
}
// missile attack
if (enemy_range == RANGE_FAR)
return FALSE;
self.attack_state = AS_MISSILE;
SUB_AttackFinished (2 + 2*random());
return TRUE;
};
//============================================================================
/*
===========
OgreCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
BOOL(float enemy_range) OgreCheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
if (enemy_range == RANGE_MELEE)
{
if (CanDamage (self.enemy, self))
{
self.attack_state = AS_MELEE;
return TRUE;
}
}
if (time < self.attack_finished)
return FALSE;
targ = self.enemy;
// 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_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (trace_ent != targ)
{
return FALSE; // don't have a clear shot
}
// missile attack
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_FAR)
return FALSE;
else if (enemy_range == RANGE_NEAR)
chance = 0.10;
else if (enemy_range == RANGE_MID)
chance = 0.05;
else
chance = 0;
self.attack_state = AS_MISSILE;
SUB_AttackFinished (1 + 2*random());
return TRUE;
};