sof-sdk/Source/Game/gamecpp/m_heliactions.cpp
2000-06-15 00:00:00 +00:00

722 lines
18 KiB
C++

// m_heliactions.cpp
#include "g_local.h"
#include "ai_private.h"
#include "m_heliai.h"
//#include "m_heli.h"
//#include <windows.h> // for OutputDebugString() only, do not leave in!
/**********************************************************************************
**********************************************************************************/
heli_action::heli_action(decision_c *od, action_c *oa, mmove_t *newanim,
int nCommand, vec3_t vPos, edict_t* target, float fArg)
:action_c(od, oa, newanim, vPos, vPos, NULL, 999999, true)
{
m_nCommand = nCommand;
action_target = target;
m_fArg = fArg;
m_think = NULL;
m_nextthink = NULL;
m_nID = -1;
}
qboolean heli_action::Think(ai_c &which_ai, edict_t &monster)
{
float fHealthPercentage = 1.0f;
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)&which_ai;
body_heli* body = NULL;
if (ai)
{
body = ai->GetHeliBody();
}
if (!body)
{
return false;
}
qboolean bRet = true;
if (m_think)
{
// set our script params in the body's member variables
body->m_fArg = m_fArg;
VectorCopy(dest, body->m_vPos);
body->m_target = action_target;
// this past think may have updated our next think
if (m_nextthink && m_nextthink != m_think)
{
m_think = m_nextthink;
m_nextthink = NULL;
}
m_think(&monster);
fHealthPercentage = (float)monster.health/(float)monster.max_health;
body->UpdateSmoke(&monster, fHealthPercentage);
// kef -- dunno if I like this. probly a cleaner way...
bRet = ((generic_ghoul_heli_ai*)&which_ai)->IsActionDone();
}
// check our need for creating a pseudo-action if our current action
//completed or if we just reached zer0 health
if (bRet ||
((body->m_flags & HELIFLAG_ISDEAD) && !(body->m_flags & HELIFLAG_ISDEADACKNOWLEDGED)))
{
// going to emulate Ste's CobraThink_Think here so we can "insert"
//pseudo-actions into the action queue
// if it's on the pad, explode
if (((body->m_flags & HELIFLAG_ISDEAD) && !(body->m_flags & HELIFLAG_ISDEADACKNOWLEDGED)) &&
fabs(monster.s.origin[0]) - fabs(body->m_v3HeliPadRestPos[0]) < 0.1f &&
fabs(monster.s.origin[1]) - fabs(body->m_v3HeliPadRestPos[1]) < 0.1f &&
fabs(monster.s.origin[2]) - fabs(body->m_v3HeliPadRestPos[2]) < 0.1f )
{
ai->TimeToDie(true);
ResolveAction(which_ai, monster, 1.0, 1.0);
}
else if(InsertPseudoAction(body, &monster))
{
// inserted a pseudo-action, so we want the heli ai to believe
//we're still executing the same action
bRet = false;
}
else
{
ResolveAction(which_ai, monster, 1.0, 1.0);
}
// just finished an action so reset our variable
((generic_ghoul_heli_ai*)&which_ai)->ActionIsDone(false);
}
return bRet;
}
// overriding this fn is a quick way of keeping action_c from screwing with
//our heli's sequence
qboolean heli_action::SetAnimation(ai_c &which_ai, edict_t &monster)
{
//just bein safe
if (!which_ai.GetBody())
{
gi.dprintf("heli_action::SetAnimation--ai has no body!\n");
return false;
}
return true;
}
// overriding this fn is a quick way of keeping action_c from screwing with
//our heli's sequence
qboolean heli_action::ForceAnimation(ai_c &which_ai, edict_t &monster)
{
//just bein safe
if (!which_ai.GetBody())
{
gi.dprintf("heli_action::ForceAnimation--ai has no body!\n");
return false;
}
return true;
}
qboolean heli_action::InsertPseudoAction(body_heli* body, edict_t* self)
{
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)self->ai;
// if we've been given the script command to turn ai on, check here
//to see if we should turn it off and start executing more script cmds
body->m_flags &= ~HELIFLAG_SCRIPTEDAIJUSTFINISHED; // regardless
if (body->m_flags & HELIFLAG_DOINGSCRIPTEDAI &&
((ai && level.time > body->m_fHeliAITimer && ai->GetActionSize()) ||
(body->m_flags & HELIFLAG_ISDEAD)) )
{
body->m_flags &= ~( HELIFLAG_DOINGSCRIPTEDAI |
HELIFLAG_DOINGSMARTGOTO |
HELIFLAG_DOINGSCRIPTEDFIREAT);
body->m_flags |= HELIFLAG_SCRIPTEDAIJUSTFINISHED; // so hover code can pick it up
}
if ((body->m_flags & HELIFLAG_ISDEAD) && !(body->m_flags & HELIFLAG_ISDEADACKNOWLEDGED))
{
body->m_flags |= HELIFLAG_ISDEADACKNOWLEDGED;
if (self->spawnflags & ONDIE_HEAD2SPAWN)
{
Cobra2_LegaliseVector(self, body->m_v3HeliDeathDest, body->m_v3HeliDeathDest, true); // qboolean qbUseWorldClip
VectorCopy(body->m_v3HeliDeathDest, dest);
m_think = Cobra2GotoCoordsHelper;
}
else
{
// store the current forward vector in body->m_v3HeliDeathDest
vec3_t vF, vR, vU;
AngleVectors(self->s.angles, vF, vR, vU);
VectorNegate(vR, body->m_v3HeliDeathDest);
body->m_v3HeliDeathDest[2] = 0;
body->m_fHeliHoverTimer = level.time + 2.0f;
m_think = m_nextthink = Cobra2_OutOfControl;
}
return true;
}
if (body->m_flags & HELIFLAG_DOINGSMARTGOTO) // this one MUST be before the 'HELIFLAG_DOINGSCRIPTEDLANDING' check
{
m_think = Cobra2Think_SmartHeadToDest;
return true;
}
if (body->m_flags & HELIFLAG_DOINGSCRIPTEDLANDING)
{
m_nextthink = m_think = Cobra2Think_Land;
body->m_flags &= ~HELIFLAG_DOINGSCRIPTEDLANDING;
return true;
}
if (body->m_flags & HELIFLAG_DOINGSCRIPTEDFIREAT)
{
m_think = Cobra2Think_GotoFireAt;
return true;
}
if (body->m_flags & HELIFLAG_DOINGSCRIPTEDHOVER)
{
m_think = Cobra2Think_Hover;
return true;
}
if (body->m_flags & HELIFLAG_DOINGSCRIPTEDAI)
{
Cobra2Think_AI(self);
return true;
}
return false;
}
heli_action::heli_action(heli_action *orig)
: action_c(orig)
{
m_nID = orig->m_nID;
m_nCommand = orig->m_nCommand;
m_fArg = orig->m_fArg;
*(int *)&m_think = GetThinkNum(orig->m_think);
*(int *)&m_nextthink = GetThinkNum(orig->m_nextthink);
}
void heli_action::Evaluate(heli_action *orig)
{
m_nID = orig->m_nID;
m_nCommand = orig->m_nCommand;
m_fArg = orig->m_fArg;
m_think = (void (*)(edict_t *self))GetThinkPtr((int)orig->m_think);
m_nextthink = (void (*)(edict_t *self))GetThinkPtr((int)orig->m_nextthink);
action_c::Evaluate(orig);
}
void heli_action::Read()
{
char loaded[sizeof(heli_action)];;
gi.ReadFromSavegame('AIHE', loaded, sizeof(heli_action));
Evaluate((heli_action *)loaded);
}
void heli_action::Write()
{
heli_action *savable;
savable = new heli_action(this);
gi.AppendToSavegame('AIHE', savable, sizeof(*this));
delete savable;
}
/**********************************************************************************
**********************************************************************************/
helimove_action::helimove_action(decision_c *od, action_c *oa, ai_c* which_ai,
mmove_t *newanim, int nCommand, vec3_t vPos,
edict_t* target, float fArg, int nID)
:heli_action(od, oa, newanim, nCommand, vPos, target, fArg)
{
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)which_ai;
body_heli* body = NULL;
if (ai)
{
body = ai->GetHeliBody();
}
if (!body)
{
return;
}
// save our id (uniquely determined by the ai)
m_nID = nID;
// save our script params
m_fArg = fArg;
VectorCopy(vPos, dest);
action_target = target;
switch(m_nCommand)
{
case generic_ghoul_heli_ai::hse_TAKEOFF:
{
m_think = Cobra2Think_TakeOff;
break;
}
case generic_ghoul_heli_ai::hse_LAND:
{
VectorCopy(body->m_v3HeliPadRestPos,dest);
m_think = Cobra2LandHelper;
break;
}
case generic_ghoul_heli_ai::hse_GOTO_COORDS:
{
m_think = Cobra2GotoCoordsHelper;
break;
}
case generic_ghoul_heli_ai::hse_GOTOREL_ENTITY:
{
if (target)
{
body->m_target = target;
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2GotoRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_GOTOREL_ENT_X:
{
if (target)
{
body->m_target = target;
VectorSet(dest, fArg, 0, 0);
m_think = Cobra2GotoRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_GOTOREL_ENT_Y:
{
if (target)
{
body->m_target = target;
VectorSet(dest, 0, fArg, 0);
m_think = Cobra2GotoRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_GOTOREL_ENT_Z:
{
if (target)
{
body->m_target = target;
VectorSet(dest, 0, 0, fArg);
m_think = Cobra2GotoRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_MOVEREL:
{
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2GotoRelHelper;
break;
}
case generic_ghoul_heli_ai::hse_STRAFE_RT:
{
m_fArg = fabs(fArg);
m_think = Cobra2StrafeHelper;
break;
}
case generic_ghoul_heli_ai::hse_STRAFE_LT:
{
m_fArg = -fabs(fArg);
m_think = Cobra2StrafeHelper;
break;
}
case generic_ghoul_heli_ai::hse_HOVER_PASSIVE:
{
m_fArg = fArg;
dest[0] = 0;
m_think = Cobra2HoverHelper;
break;
}
case generic_ghoul_heli_ai::hse_HOVER_AGGRESSIVE:
{
body->m_fArg = fArg;
dest[0] = 1;
m_think = Cobra2HoverHelper;
break;
}
case generic_ghoul_heli_ai::hse_REPAIR:
{
m_think = Cobra2Think_Repair;
break;
}
case generic_ghoul_heli_ai::hse_REARM:
{
m_think = Cobra2RearmHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_WORLDMINS:
{
m_fArg = body->m_fArg = 0; // 0 == mins
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2WorldHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_WORLDMAXS:
{
m_fArg = body->m_fArg = 1; // 1 == maxs
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2WorldHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_DEATHDEST:
{
m_think = Cobra2DeathDestHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_TRACEDIMS:
{
m_think = Cobra2TraceDimsHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_HEALTH:
{
dest[0] = 0; // 0 == health
m_think = Cobra2HealthHelper;
break;
}
case generic_ghoul_heli_ai::hse_SET_MAXHEALTH:
{
dest[0] = 1; // 1 == maxhealth
m_think = Cobra2HealthHelper;
break;
}
case generic_ghoul_heli_ai::hse_CHANGE_SKIN:
{
// set the skin
if (1 == m_fArg)
{
SetSkin(target, "enemy/chopper", "cobrass", "cobra","m_x_chopper_black", true);
}
else if (2 == m_fArg)
{
SetSkin(target, "enemy/chopper", "cobrass", "cobra","m_x_chopper_green", true);
}
else
{
SetSkin(target, "enemy/chopper", "cobrass", "cobra","m_x_chopper_white", true);
}
break;
}
case generic_ghoul_heli_ai::hse_CHANGE_BODY:
{
// set the body
if (1 == m_fArg)
{
ai->ChangeBody(target, "enemy/hind", "hind");
}
break;
}
case generic_ghoul_heli_ai::hse_OUT_OF_CONTROL:
{
// body->m_v3HeliDeathDest contains a base velocity for crashing
VectorClear(body->m_v3HeliDeathDest);
body->m_fHeliHoverTimer = level.time + 2.0f;
m_think = Cobra2_OutOfControl;
break;
}
case generic_ghoul_heli_ai::hse_AI:
{
m_think = Cobra2AIHelper;
break;
}
case generic_ghoul_heli_ai::hse_WAYPOINT:
{
ai->AddWaypoint(vPos);
break;
}
case generic_ghoul_heli_ai::hse_VOLUME:
{
ai->SetWaypointPtVolume(ai->GetNumWaypointPts()-1,vPos);
break;
}
case generic_ghoul_heli_ai::hse_VOLUMEMINS:
{
// vPos is in world coords, change to rel-to-waypt-origin
heliWaypoint* pt = ai->GetWaypointPt(ai->GetNumWaypointPts()-1);
if (pt)
{
VectorCopy(vPos, pt->m_volMins);
}
break;
}
case generic_ghoul_heli_ai::hse_VOLUMEMAXS:
{
// vPos is in world coords, change to rel-to-waypt-origin
vec3_t vTemp;
heliWaypoint* pt = ai->GetWaypointPt(ai->GetNumWaypointPts()-1);
if (pt)
{
VectorCopy(vPos, pt->m_volMaxs);
VectorAdd(pt->m_volMins, pt->m_volMins, vTemp);
VectorScale(vTemp, 0.5f, pt->m_v);
VectorSubtract(pt->m_volMins, pt->m_v, pt->m_volMins);
VectorSubtract(pt->m_volMaxs, pt->m_v, pt->m_volMaxs);
ai->SetWaypointPtVolume(ai->GetNumWaypointPts()-1,pt->m_volMaxs);
}
break;
}
case generic_ghoul_heli_ai::hse_DEBUG:
{
// sets the proper spawnflag in ds.cpp, nothing to do here
break;
}
default:
break;
}
}
/**********************************************************************************
**********************************************************************************/
heliface_action::heliface_action(decision_c *od, action_c *oa, ai_c* which_ai,
mmove_t *newanim, int nCommand, vec3_t vPos,
edict_t* target, float fArg, int nID)
:heli_action(od, oa, newanim, nCommand, vPos, target, fArg)
{
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)which_ai;
body_heli* body = NULL;
if (ai)
{
body = ai->GetHeliBody();
}
if (!body)
{
return;
}
// save our id (uniquely determined by the ai)
m_nID = nID;
// save our script params
m_fArg = fArg;
VectorCopy(vPos, dest);
action_target = target;
switch(m_nCommand)
{
case generic_ghoul_heli_ai::hse_FACE_RELENT:
{
if (target)
{
body->m_target = target;
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2FaceRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_FACE_ABSCOORDS:
{
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2FaceAbsHelper;
break;
}
case generic_ghoul_heli_ai::hse_FACE_ABSDIR:
{
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2FaceAbsDirHelper;
break;
}
case generic_ghoul_heli_ai::hse_FACE_RELCOORDS:
{
VectorCopy(vPos, body->m_vPos);
m_think = Cobra2FaceRelCoordsHelper;
break;
}
case generic_ghoul_heli_ai::hse_PILOT_FACERELENT:
case generic_ghoul_heli_ai::hse_GUNNER_FACERELENT:
{
if (target)
{
body->m_target = target;
VectorCopy(vPos, body->m_vPos);
if (m_nCommand == generic_ghoul_heli_ai::hse_GUNNER_FACERELENT)
{
m_fArg = 0; // 0 == gunner
}
else
{
m_fArg = 1; // 1 == pilot
}
m_think = Cobra2HeadFaceRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_PILOT_FACERELCOORDS:
case generic_ghoul_heli_ai::hse_GUNNER_FACERELCOORDS:
{
VectorCopy(vPos, body->m_vPos);
if (m_nCommand == generic_ghoul_heli_ai::hse_GUNNER_FACERELCOORDS)
{
m_fArg = 0; // 0 == gunner
}
else
{
m_fArg = 1; // 1 == pilot
}
m_think = Cobra2HeadFaceRelCoordsHelper;
break;
}
case generic_ghoul_heli_ai::hse_PILOT_FACEABSCOORDS:
case generic_ghoul_heli_ai::hse_GUNNER_FACEABSCOORDS:
{
VectorCopy(vPos, body->m_vPos);
if (m_nCommand == generic_ghoul_heli_ai::hse_GUNNER_FACEABSCOORDS)
{
m_fArg = 0; // 0 == gunner
}
else
{
m_fArg = 1; // 1 == pilot
}
m_think = Cobra2HeadFaceAbsCoordsHelper;
break;
}
default:
break;
}
}
/**********************************************************************************
**********************************************************************************/
heliattack_action::heliattack_action(decision_c *od, action_c *oa, ai_c* which_ai,
mmove_t *newanim, int nCommand, vec3_t vPos,
edict_t* target, float fArg, int nID)
:heli_action(od, oa, newanim, nCommand, vPos, target, fArg)
{
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)which_ai;
body_heli* body = NULL;
if (ai)
{
body = ai->GetHeliBody();
}
if (!body)
{
return;
}
// save our id (uniquely determined by the ai)
m_nID = nID;
// save our script params
m_fArg = fArg;
VectorCopy(vPos, dest);
action_target = target;
switch(m_nCommand)
{
case generic_ghoul_heli_ai::hse_ROCKETS_ENABLE:
{
m_fArg = 1;
m_think = Cobra2RocketsEnableHelper;
break;
}
case generic_ghoul_heli_ai::hse_ROCKETS_DISABLE:
{
m_fArg = 0;
m_think = Cobra2RocketsEnableHelper;
break;
}
case generic_ghoul_heli_ai::hse_CHAINGUN_ENABLE:
{
m_fArg = 1;
m_think = Cobra2ChainGunEnableHelper;
break;
}
case generic_ghoul_heli_ai::hse_CHAINGUN_DISABLE:
{
m_fArg = 0;
m_think = Cobra2ChainGunEnableHelper;
Cobra2_Fire_OFF(body->GetHeliEdict());
body->m_fArg = 0;
ai->ActionIsDone(true);
break;
}
case generic_ghoul_heli_ai::hse_AUTOFIRE_ON:
{
m_fArg = 1;
m_think = Cobra2AutoFireHelper;
break;
}
case generic_ghoul_heli_ai::hse_AUTOFIRE_OFF:
{
m_fArg = 0;
m_think = Cobra2AutoFireHelper;
break;
}
case generic_ghoul_heli_ai::hse_FIREAT_RELENT:
{
if (target)
{
body->m_target = target;
VectorCopy(vPos, body->m_vPos);
body->m_fArg = fArg;
m_think = Cobra2FireAtRelEntHelper;
}
break;
}
case generic_ghoul_heli_ai::hse_FIREAT_ABSCOORDS:
{
VectorCopy(vPos, body->m_vPos);
body->m_fArg = fArg;
m_think = Cobra2FireAtAbsHelper;
break;
}
case generic_ghoul_heli_ai::hse_FIREAT_RELCOORDS:
{
VectorCopy(vPos, body->m_vPos);
body->m_fArg = fArg;
m_think = Cobra2FireAtRelHelper;
break;
}
default:
break;
}
}
/**********************************************************************************
**********************************************************************************/
helideath_action::helideath_action(decision_c *od, action_c *oa, ai_c* which_ai,
mmove_t *newanim, int nCommand, vec3_t vPos,
edict_t* target, float fArg, int nID)
:heli_action(od, oa, newanim, nCommand, vPos, target, fArg)
{
generic_ghoul_heli_ai* ai = (generic_ghoul_heli_ai*)(ai_public_c*)which_ai;
body_heli* body = NULL;
if (ai)
{
body = ai->GetHeliBody();
}
if (!body)
{
return;
}
m_think = Cobra2GotoCoordsHelper;
// save our id (uniquely determined by the ai)
m_nID = nID;
// save our script params
m_fArg = fArg;
VectorCopy(vPos, dest);
action_target = target;
}