gAIPlayer Class Reference

#include <gAIBase.h>

Inheritance diagram for gAIPlayer:

Inheritance graph
[legend]
Collaboration diagram for gAIPlayer:

Collaboration graph
[legend]

List of all members.

Public Member Functions

gAICharacter * Character () const
 gAIPlayer ()
 ~gAIPlayer ()
void ClearTarget ()
virtual void ControlObject (eNetGameObject *c)
virtual void ClearObject ()
virtual REAL Think ()
bool Alive ()
virtual bool IsHuman () const
gCycle * Object ()
void Timestep (REAL time)
virtual void NewObject ()
virtual void RightBeforeDeath (int triesLeft)
virtual void Color (REAL &r, REAL &g, REAL &b) const
virtual nDescriptor & CreatorDescriptor () const
 gAIPlayer (nMessage &m)

Static Public Member Functions

static void ClearAll ()
 remove all AI players
static void CycleBlocksWay (const gCycleMovement *a, const gCycleMovement *b, int aDir, int bDir, REAL bDist, int winding)
static void CycleBlocksRim (const gCycleMovement *a, int aDir)
static void BreakWall (const gCycleMovement *a, REAL aDist)
static void ConfigureAIs ()
static void SetNumberOfAIs (int num, int minPlayers, int iq, int tries=3)

Protected Member Functions

void SetTraceSide (int side)
void SwitchToState (gAI_STATE nextState, REAL minTime=10)
virtual void ThinkSurvive (ThinkData &data)
virtual void ThinkTrace (ThinkData &data)
virtual void ThinkPath (ThinkData &data)
virtual void ThinkCloseCombat (ThinkData &data)
virtual bool EmergencySurvive (ThinkData &data, int enemyEvade=-1, int preferedSide=0)
virtual void EmergencyTrace (ThinkData &data)
virtual void EmergencyPath (ThinkData &data)
virtual void EmergencyCloseCombat (ThinkData &data)
virtual void ActOnData (ThinkData &data)
virtual void ActOnData (ThinkDataBase &data)

Protected Attributes

gSimpleAI * simpleAI_
gAICharacter * character
nObserverPtr< gCycle > target
ePath path
REAL lastPath
int traceSide
REAL lastChangeAttempt
REAL lazySideChange
gAI_STATE state
REAL nextStateChange
bool emergency
int triesLeft
REAL freeSide
REAL lastTime
REAL nextTime
REAL concentration
gAILog * log

Private Attributes

tReproducibleRandomizer randomizer_

Friends

class gAITeam

Classes

struct  ThinkData
struct  ThinkDataBase


Detailed Description

Definition at line 90 of file gAIBase.h.


Constructor & Destructor Documentation

gAIPlayer::gAIPlayer (  ) 

Definition at line 1098 of file gAIBase.cpp.

References ePlayerNetID::b, character, ClearTarget(), exp(), freeSide, ePlayerNetID::g, G, GrowingArrayBase::Len(), log, MAXAI_COLOR, NewObject(), NULL, ePlayerNetID::ping, ePlayerNetID::pingCharity, ePlayerNetID::r, REAL, ePlayerNetID::score, se_FloorColor(), se_PlayerNetIDs, and traceSide.

01098                     :
01099         simpleAI_(NULL),
01100         character(NULL),
01101         //      target(NULL),
01102         lastPath(se_GameTime()-100),
01103         lastTime(se_GameTime()),
01104         nextTime(0),
01105         concentration(1),
01106         log(NULL)
01107 {
01108     character = NULL;
01109     ClearTarget();
01110     traceSide = 1;
01111     freeSide  = 0;
01112     log       = NULL;
01113 
01114     // find a good color
01115 
01116     current_ai=(current_ai+1) % MAXAI_COLOR;
01117     int take_ai=current_ai;
01118     int try_ai=current_ai;
01119 
01120     REAL maxmindist=-10000;
01121 
01122     for(int i=MAXAI_COLOR-1;i>=0;i--){
01123         REAL mindist=4;
01124         REAL score=0;
01125         for (int j=se_PlayerNetIDs.Len()-1;j>=-1;j--){
01126             REAL R, G, B; // the color we want to avoid
01127 
01128             if (j >= 0)
01129             {
01130                 ePlayerNetID *p=se_PlayerNetIDs(j);
01131                 if (p && p != this)
01132                 {
01133                     R = p->r/15.0;
01134                     G = p->g/15.0;
01135                     B = p->b/15.0;
01136                 }
01137                 else
01138                     continue;
01139             }
01140             else // last case: j = -1. Test against floor color
01141             {
01142                 se_FloorColor(R, G, B);
01143             }
01144             REAL dist=
01145                 fabs(R - rgb_ai[try_ai][0])+
01146                 fabs(G - rgb_ai[try_ai][1])+
01147                 fabs(B - rgb_ai[try_ai][2]);
01148 
01149             score+=exp(-dist*dist*4);
01150 
01151             if (dist<mindist){
01152                 mindist=dist;
01153                 /*         con << c->r << ":" << rgb_ai[try_ai][0] << '\t'
01154                            << c->g << ":" << rgb_ai[try_ai][1] << '\t'
01155                            << c->b << ":" << rgb_ai[try_ai][2] << '\t' << dist << '\n'; */
01156             }
01157         }
01158         //con << "md=" << mindist << "\n\n";
01159         if (mindist>2)
01160             mindist=2;
01161 
01162         mindist=-score;
01163 
01164         if (mindist>maxmindist){
01165             maxmindist=mindist;
01166             take_ai=try_ai;
01167         }
01168 
01169 
01170 
01171         try_ai = ((try_ai+1) % MAXAI_COLOR);
01172     }
01173 
01174 
01175     r = static_cast<int>(rgb_ai[take_ai][0] * 15);
01176     g = static_cast<int>(rgb_ai[take_ai][1] * 15);
01177     b = static_cast<int>(rgb_ai[take_ai][2] * 15);
01178 
01179 
01180     ping = 0;
01181     pingCharity = 300;
01182 
01183     NewObject();
01184 }

Here is the call graph for this function:

gAIPlayer::~gAIPlayer (  ) 

Definition at line 2985 of file gAIBase.cpp.

References ClearObject(), log, NULL, target, and tCHECK_DEST.

02986 {
02987     target=NULL;
02988     ClearObject();
02989     tCHECK_DEST;
02990 
02991     delete log;
02992     log = NULL;
02993 }

Here is the call graph for this function:

gAIPlayer::gAIPlayer ( nMessage &  m  ) 

Definition at line 1085 of file gAIBase.cpp.

01085                                 :
01086         ePlayerNetID(m),
01087         character(NULL),
01088         //      target(NULL),
01089         lastPath(se_GameTime()-100),
01090         lastTime(se_GameTime()),
01091         nextTime(0),
01092         concentration(1),
01093         log(NULL)
01094 {
01095 }


Member Function Documentation

void gAIPlayer::SetTraceSide ( int  side  )  [protected]

Definition at line 1349 of file gAIBase.cpp.

References lastChangeAttempt, lazySideChange, REAL, se_GameTime(), traceSide, and ts.

Referenced by CycleBlocksWay(), EmergencySurvive(), ThinkCloseCombat(), and ThinkTrace().

01350 {
01351     REAL time = se_GameTime();
01352     REAL ts   = time - lastChangeAttempt + 1;
01353     lastChangeAttempt = time;
01354 
01355     lazySideChange += ts * side;
01356     if (lazySideChange * traceSide <= 0)
01357     {
01358         // state change!
01359         traceSide = lazySideChange > 0 ? 1 : -1;
01360         lazySideChange = 10 * traceSide;
01361     }
01362 
01363     if (lazySideChange > 10)
01364         lazySideChange = 10;
01365     if (lazySideChange < -10)
01366         lazySideChange = -10;
01367 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::SwitchToState ( gAI_STATE  nextState,
REAL  minTime = 10 
) [protected]

Definition at line 1370 of file gAIBase.cpp.

References AI_CLOSECOMBAT, AI_PATH, AI_STATE_CLOSECOMBAT, AI_STATE_PATH, AI_STATE_TRACE, AI_SURVIVE, AI_TRACE, character, con, nextStateChange, gAICharacter::properties, Random(), se_GameTime(), and state.

Referenced by CycleBlocksWay(), EmergencySurvive(), RightBeforeDeath(), Think(), ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), and ThinkTrace().

01371 {
01372     int thisAbility = 10 - character->properties[AI_STATE_TRACE];
01373     switch (state)
01374     {
01375     case AI_TRACE:
01376         thisAbility = character->properties[AI_STATE_TRACE];
01377         break;
01378     case AI_CLOSECOMBAT:
01379         thisAbility = character->properties[AI_STATE_CLOSECOMBAT];
01380         break;
01381     case AI_PATH:
01382         thisAbility = character->properties[AI_STATE_PATH];
01383         break;
01384     case AI_SURVIVE:
01385         break;
01386     };
01387 
01388     int nextAbility = 10;
01389     switch (nextState)
01390     {
01391     case AI_TRACE:
01392         nextAbility = character->properties[AI_STATE_TRACE];
01393         break;
01394     case AI_CLOSECOMBAT:
01395         nextAbility = character->properties[AI_STATE_CLOSECOMBAT];
01396         break;
01397     case AI_PATH:
01398         nextAbility = character->properties[AI_STATE_PATH];
01399         break;
01400     case AI_SURVIVE:
01401         break;
01402     };
01403 
01404 
01405     if (nextAbility > thisAbility && Random() * 10 > nextAbility)
01406         return;
01407 
01408 #ifdef DEBUG
01409     if (state != nextState)
01410         con << "Switching to state " << nextState << "\n";
01411 #endif
01412 
01413     state           = nextState;
01414     nextStateChange = se_GameTime() + minTime;
01415 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ThinkSurvive ( ThinkData &  data  )  [protected, virtual]

Definition at line 1418 of file gAIBase.cpp.

References AI_CLOSECOMBAT, character, eSensor::detect(), eCoord, EmergencySurvive(), gAISensor::front, eGrid::GameObjects(), eGameObject::Grid(), gSENSOR_RIM, eSensor::hit, IsTrapped(), gAIPlayer::ThinkData::left, GrowingArrayBase::Len(), nextStateChange, NULL, Object(), eGameObject::Position(), Random(), REAL, gAIPlayer::ThinkData::right, se_GameTime(), st_Breakpoint(), SwitchToState(), target, eGameObject::Team(), gAIPlayer::ThinkDataBase::thinkAgain, and gHitData::wallType.

Referenced by Think().

01419 {
01420     if (!character)
01421     {
01422         st_Breakpoint();
01423         return;
01424     }
01425 
01426     REAL random = 0;
01427     // do nothing much. Rely on the emergency program.
01428     /*
01429       random=10*(Random()/float(1));
01430       if (random < .2)
01431       EmergencySurvive(front, left, right, -1, 1);
01432       else if (random > 9.8)
01433       EmergencySurvive(front, left, right, -1, -1);
01434       else
01435       if (front.front.wallType == gSENSOR_RIM && front.distance < 10)
01436       st_Breakpoint();
01437 
01438 
01439     */
01440 
01441     if (data.left.front.wallType == gSENSOR_RIM)
01442         EmergencySurvive( data, 1);
01443     else if (data.right.front.wallType == gSENSOR_RIM)
01444         EmergencySurvive( data, -1);
01445     else
01446         EmergencySurvive( data );
01447 
01448 
01449 
01450     if (nextStateChange > se_GameTime())
01451     {
01452         data.thinkAgain = .5f;
01453         return;
01454     }
01455 
01456     // switch from Survival to close combat if surviving is too boring
01457     random=10*Random();
01458     if (random < 5)
01459     {
01460         // find a new victim:
01461         eCoord enemypos=eCoord(1000,100);
01462 
01463         const tList<eGameObject>& gameObjects = Object()->Grid()->GameObjects();
01464         gCycle *secondbest = NULL;
01465 
01466         // find the closest enemy
01467         for (int i=gameObjects.Len()-1;i>=0;i--){
01468             gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
01469 
01470             if (other && other->Team()!=Object()->Team() &&
01471                     !IsTrapped(other, Object())){
01472                 // then, enemy is realy an enemy
01473                 eCoord otherpos=other->Position()-Object()->Position();
01474                 if (otherpos.NormSquared()<enemypos.NormSquared()){
01475                     // check if the path is clear
01476                     gSensor p(Object(),Object()->Position(),otherpos);
01477                     p.detect(REAL(.98));
01478                     secondbest = dynamic_cast<gCycle *>(other);
01479                     if (p.hit>=.98){
01480                         enemypos = otherpos;
01481                         target = secondbest;
01482                     }
01483                 }
01484             }
01485         }
01486 
01487         if (!target)
01488             target = secondbest;
01489 
01490         if (target)
01491             SwitchToState(AI_CLOSECOMBAT, 1);
01492     }
01493 
01494     data.thinkAgain = 1;
01495 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ThinkTrace ( ThinkData &  data  )  [protected, virtual]

Definition at line 1497 of file gAIBase.cpp.

References a, AI_CLOSECOMBAT, ePlayerNetID::b, Conj, Delay(), eSensor::detect(), gAISensor::distance, eCoord, gHitData::edge, EmergencySurvive(), gAISensor::front, gAIPlayer::ThinkData::front, eGrid::GameObjects(), eGameObject::Grid(), gSENSOR_RIM, eSensor::hit, gAISensor::Hit(), IsTrapped(), gAIPlayer::ThinkData::left, GrowingArrayBase::Len(), nextStateChange, NULL, Object(), eHalfEdge::Other(), eHalfEdge::Point(), eGameObject::Position(), REAL, gAIPlayer::ThinkData::right, se_GameTime(), SetTraceSide(), gCycleMovement::Speed(), SwitchToState(), target, eGameObject::Team(), gAIPlayer::ThinkDataBase::thinkAgain, traceSide, and gHitData::wallType.

Referenced by Think().

01498 {
01499     gAISensor const & front = data.front;
01500     gAISensor const & left = data.left;
01501     gAISensor const & right = data.right;
01502 
01503     bool inverse = front.Hit() && front.distance < Object()->Speed() * Delay();
01504 
01505     if (left.front.wallType == gSENSOR_RIM)
01506         SetTraceSide(1);
01507 
01508     if (right.front.wallType == gSENSOR_RIM)
01509         SetTraceSide(-1);
01510 
01511     bool success = EmergencySurvive(data, 0, traceSide * ( inverse ? -1 : 1));
01512 
01513     REAL & nextTurn = data.thinkAgain;
01514     nextTurn = 100;
01515     if (left.front.edge)
01516     {
01517         REAL a = eCoord::F(Object()->Direction(), *left.front.edge->Point() - Object()->Position());
01518         REAL b = eCoord::F(Object()->Direction(), *left.front.edge->Other()->Point() - Object()->Position());
01519 
01520         if (a < b)
01521             a = b;
01522         if ( a > 0 )
01523             nextTurn = a;
01524     }
01525 
01526     if (right.front.edge)
01527     {
01528         REAL a = eCoord::F(Object()->Direction(), *right.front.edge->Point() - Object()->Position());
01529         REAL b = eCoord::F(Object()->Direction(), *right.front.edge->Other()->Point() - Object()->Position());
01530 
01531         if (a < b)
01532             a = b;
01533         if ( a > 0 && a < nextTurn || !left.front.edge)
01534             nextTurn = a;
01535     }
01536 
01537     nextTurn/= Object()->Speed() * .98f;
01538 
01539     REAL delay = Delay() * 1.5f;
01540     if ((!Object()->CanMakeTurn(1) || !Object()->CanMakeTurn(-1) || success) && nextTurn > delay)
01541         nextTurn = delay;
01542 
01543     if (nextTurn > .3f)
01544         nextTurn = .3f;
01545 
01546     if (nextStateChange > se_GameTime())
01547         return;
01548 
01549     // find a new victim:
01550     eCoord enemypos=eCoord(1000,100);
01551 
01552     const tList<eGameObject>& gameObjects = Object()->Grid()->GameObjects();
01553     gCycle *secondbest = NULL;
01554 
01555     // find the closest enemy
01556     for (int i=gameObjects.Len()-1;i>=0;i--){
01557         gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
01558 
01559         if (other && other->Team()!=Object()->Team() &&
01560                 !IsTrapped(other, Object())){
01561             // then, enemy is realy an enemy
01562             eCoord otherpos=other->Position()-Object()->Position();
01563             if (otherpos.NormSquared()<enemypos.NormSquared()){
01564                 // check if the path is clear
01565                 gSensor p(Object(),Object()->Position(),otherpos);
01566                 p.detect(REAL(.98));
01567                 secondbest = dynamic_cast<gCycle *>(other);
01568 
01569                 if (!target)
01570                     enemypos = otherpos;
01571 
01572                 if (p.hit>=.98){
01573                     enemypos = otherpos;
01574                     target = secondbest;
01575                 }
01576             }
01577         }
01578     }
01579 
01580     eCoord relpos=enemypos.Turn(Object()->Direction().Conj()).Turn(0,1);
01581 
01582 
01583     if (!target)
01584         target = secondbest;
01585     else
01586         SwitchToState(AI_CLOSECOMBAT, 1);
01587 
01588     if (target)
01589         SetTraceSide((relpos.x  > 0 ? 10 : -10) *
01590                      (target->Speed() > Object()->Speed() ? -1 : 1));
01591 
01592     nextStateChange = se_GameTime() + 10;
01593 
01594     //  SwitchToState(AI_SURVIVE, 1);
01595     return;
01596 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ThinkPath ( ThinkData &  data  )  [protected, virtual]

Definition at line 1599 of file gAIBase.cpp.

References AI_CLOSECOMBAT, AI_SURVIVE, con, ePath::CurrentOffset(), ePath::CurrentPosition(), d, eSensor::detect(), gCycle::Direction(), gAISensor::distance, eCoord, EmergencySurvive(), eGameObject::FindCurrentFace(), eHalfEdge::FindPath(), ePath::GoBack(), eSensor::hit, IsTrapped(), lastPath, gAIPlayer::ThinkData::left, ls, nextStateChange, Object(), path, pos, eGameObject::Position(), ePath::Proceed(), REAL, gAIPlayer::ThinkData::right, se_GameTime(), gCycleMovement::Speed(), sqrt(), SwitchToState(), target, gAIPlayer::ThinkDataBase::thinkAgain, ePath::Valid(), and z.

Referenced by Think().

01600 {
01601     int lr = 0;
01602     REAL mindist = 10;
01603 
01604     eCoord dir = Object()->Direction();
01605     // REAL fs=front.distance;
01606     REAL ls=data.left.distance;
01607     REAL rs=data.right.distance;
01608 
01609 
01610     if (!target->CurrentFace() || IsTrapped(target, Object()))
01611     {
01612         SwitchToState(AI_SURVIVE, 1);
01613         EmergencySurvive( data );
01614 
01615         data.thinkAgain = 4;
01616         return;
01617     }
01618 
01619     eCoord tDir = target->Position() - Object()->Position();
01620 
01621     if ( nextStateChange < se_GameTime() )
01622     {
01623         gSensor p(Object(),Object()->Position(), tDir);
01624         p.detect(REAL(.9999999));
01625         if (p.hit >=  .9999999)  // free line of sight to victim. Switch to close combat.
01626         {
01627             SwitchToState(AI_CLOSECOMBAT, 5);
01628             EmergencySurvive( data );
01629 
01630             return;
01631         }
01632     }
01633 
01634 
01635 
01636     // find a new path if the one we got is outdated:
01637     if (lastPath < se_GameTime() - 10)
01638         if (target->CurrentFace())
01639         {
01640             Object()->FindCurrentFace();
01641             eHalfEdge::FindPath(Object()->Position(), Object()->CurrentFace(),
01642                                 target->Position(), target->CurrentFace(),
01643                                 Object(),
01644                                 path);
01645             lastPath = se_GameTime();
01646         }
01647 
01648     if (!path.Valid())
01649     {
01650         data.thinkAgain = 1;
01651         return;
01652     }
01653 
01654     // find the most advanced path point that is in our viewing range:
01655 
01656     for (int z = 10; z>=0; z--)
01657         path.Proceed();
01658 
01659     bool goon   = path.Proceed();
01660     bool nogood = false;
01661 
01662     do
01663     {
01664         if (goon)
01665             goon = path.GoBack();
01666         else
01667             goon = true;
01668 
01669         eCoord pos   = path.CurrentPosition() + path.CurrentOffset() * 0.1f;
01670         eCoord opos  = Object()->Position();
01671         eCoord odir  = pos - opos;
01672 
01673         eCoord intermediate = opos + dir * eCoord::F(odir, dir);
01674 
01675         gSensor p(Object(), opos, intermediate - opos);
01676         p.detect(1.1f);
01677         nogood = (p.hit <= .999999999 || eCoord::F(path.CurrentOffset(), odir) < 0);
01678 
01679         if (!nogood)
01680         {
01681             gSensor p(Object(), intermediate, pos - intermediate);
01682             p.detect(1);
01683             nogood = (p.hit <= .99999999 || eCoord::F(path.CurrentOffset(), odir) < 0);
01684         }
01685 
01686     }
01687     while (goon && nogood);
01688 
01689     if (goon)
01690     {
01691         // now we have found our next goal. Try to get there.
01692         eCoord pos    = Object()->Position();
01693         eCoord target = path.CurrentPosition();
01694 
01695         // look how far ahead the target is:
01696         REAL ahead = eCoord::F(target - pos, dir)
01697                      + eCoord::F(path.CurrentOffset(), dir);
01698 
01699         if ( ahead > 0)
01700         {         // it is still before us. just wait a while.
01701             mindist = ahead;
01702         }
01703         else
01704         { // we have passed it. Make a turn towards it.
01705             REAL side = (target - pos) * dir;
01706 
01707             if ( !((side > 0 && ls < 3) || (side < 0 && rs < 3))
01708                     && (fabs(side) > 3 || ahead < -10) )
01709             {
01710 #ifdef DEBUG
01711                 con << "Following path...\n";
01712 #endif
01713                 lr += (side > 0 ? 1 : -1);
01714             }
01715         }
01716     }
01717     else // nogood
01718     {
01719         lastPath -= 1;
01720         SwitchToState(AI_SURVIVE);
01721     }
01722 
01723     EmergencySurvive( data, 1, -lr );
01724 
01725     REAL d = sqrt(tDir.NormSquared()) * .2f;
01726     if (d < mindist)
01727         mindist = d;
01728 
01729     data.thinkAgain = mindist / Object()->Speed();
01730     if (data.thinkAgain > .4)
01731         data.thinkAgain *= .7;
01732 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ThinkCloseCombat ( ThinkData &  data  )  [protected, virtual]

Definition at line 1735 of file gAIBase.cpp.

References AI_PATH, AI_TRACE, con, gCycle::Direction(), gAISensor::distance, eCoord, EmergencySurvive(), gAIPlayer::ThinkData::front, gAISensor::Hit(), IsTrapped(), gAIPlayer::ThinkData::left, nCLIENT, nextStateChange, Object(), eGameObject::Position(), Random(), REACTION, REAL, gAIPlayer::ThinkData::right, se_GameTime(), SetTraceSide(), sn_GetNetState(), gCycleMovement::Speed(), sr_predictObjects, SwitchToState(), target, and gAIPlayer::ThinkDataBase::thinkAgain.

Referenced by Think().

01736 {
01737     int lr=0;
01738 
01739     REAL nextThought = 0;
01740 
01741     const gAISensor* sides[2];
01742     sides[0] = &data.left;
01743     sides[1] = &data.right;
01744 
01745     eCoord dir = Object()->Direction();
01746     REAL fs=data.front.distance;
01747     //  REAL ls=left.hit;
01748     //  REAL rs=right.hit;
01749 
01750     if ( bool( target ) && !IsTrapped(target, Object()) && nextStateChange < se_GameTime() )
01751     {
01752         gSensor p(Object(),Object()->Position(),target->Position() - Object()->Position());
01753         p.detect(REAL(1));
01754         if (p.hit <=  .999999)  // no free line of sight to victim. Switch to path mode.
01755         {
01756             SwitchToState(AI_PATH, 5);
01757             EmergencySurvive( data );
01758             return;
01759         }
01760     }
01761 
01762     REAL ed = 0;
01763 
01764     const REAL fear=REAL(.01);
01765     const REAL caution=.001;
01766     const REAL evasive=100;
01767     const REAL attack=100;
01768     const REAL seek=REAL(1);
01769     const REAL trap=REAL(.01);
01770     const REAL ffar=20;
01771     //    const REAL close=1000;
01772 
01773     REAL random=10*Random()*Random();
01774 
01775     if ( bool( target ) && target->Alive()){
01776 
01777         eCoord enemypos=target->Position()-Object()->Position();
01778         eCoord enemydir=target->Direction();
01779         REAL enemyspeed=target->Speed();
01780 
01781         ed=REAL(fabs(enemypos.x)+fabs(enemypos.y));
01782         ed/=enemyspeed;
01783 
01784         // transform coordinates relative to us:
01785         enemypos=enemypos.Turn(dir.Conj()).Turn(0,1);
01786         enemydir=enemydir.Turn(dir.Conj()).Turn(0,1);
01787 
01788         // now we are at the center of the coordinate system facing
01789         // in direction (0,1).
01790 
01791         // rules are symmetrical: exploit that.
01792         int side=1;
01793         if (enemypos.x<0){
01794             side*=-1;
01795             enemypos.x*=-1;
01796             enemydir.x*=-1;
01797 
01798             sides[1] = &data.left;
01799             sides[0] = &data.right;
01800             //      Swap(ls,rs);
01801         }
01802         // now we can even assume the enemy is on our right side.
01803 
01804         // consider his ping and our reaction time
01805 #define REACTION .2
01806 
01807 
01808         //REAL enemyspeed=target->speed;
01809         REAL ourspeed=Object()->Speed();
01810 
01811         REAL enemydist=target->Lag()*enemyspeed;
01812 
01813         // redo the prediction
01814 #ifndef DEDICATED
01815         if (sn_GetNetState()==nCLIENT && !sr_predictObjects)
01816 #endif
01817             enemypos=enemypos-enemydir*enemydist;
01818         enemydist+=2*REACTION *enemyspeed;
01819 
01820         REAL ourdist=REACTION*ourspeed;;
01821 
01822 
01823         // now we consider the worst case: we drive straight on,
01824         enemypos.y-=ourdist;
01825         // while the enemy cuts us: he goes in front of us
01826         REAL forward=-enemypos.y+.01;
01827         if (forward<0) // no need to go to much ahead
01828             forward=0;
01829         if (forward>enemydist)
01830             forward=enemydist;
01831 
01832         enemypos.y+=forward;
01833         enemydist-=forward;
01834 
01835         // and then he turns left.
01836         enemypos.x-=enemydist;
01837 
01838         if (enemypos.y*enemyspeed>enemypos.x*ourspeed){ // he is right ahead of us.
01839             if (random<fear){ // evade him
01840 #ifdef DEBUG
01841                 con << "fear!\n";
01842 #endif
01843                 lr+=side;
01844 
01845                 nextThought += 1;
01846             }
01847             if (enemypos.y<=ffar &&
01848                     ((enemydir.x<0 && random<evasive) ||
01849                      (enemydir.y>0 && random<caution) ||
01850                      (enemydir.y<0 && random<attack))){
01851 #ifdef DEBUG
01852                 con << "caution!\n";
01853 #endif
01854                 lr+=side;
01855 
01856                 nextThought += 1;
01857 
01858                 if (enemyspeed > ourspeed)
01859                 {
01860                     SetTraceSide(-side);
01861                     SwitchToState(AI_TRACE, 10);
01862                 }
01863             }
01864         }
01865         else if (enemypos.y*ourspeed<-enemypos.x*enemyspeed){
01866             /*
01867               // good attack position
01868               if (enemypos.x<rs && rs < range*.99){
01869               #ifdef DEBUG
01870               con << "BOX!\n";
01871               #endif
01872               turn+=10;
01873               lr-=side;
01874               }
01875 
01876             */
01877 
01878             REAL canCutIfDriveOn = enemypos.x*ourspeed - fs * (enemyspeed - ourspeed);
01879             canCutIfDriveOn -= enemypos.y*enemyspeed;
01880 
01881             REAL canCutIfAttack  = - sides[1]->distance * enemyspeed
01882                                    - (sides[1]->distance - enemypos.x -enemypos.y*ourspeed) * ourspeed;
01883 
01884             if (random<attack && (!(data.front.Hit() && data.front.distance < 20) || canCutIfAttack > canCutIfDriveOn)){
01885 #ifdef DEBUG
01886                 con << "attack!\n";
01887 #endif
01888                 lr-=side;
01889 
01890                 nextThought += 1;
01891             }
01892         }
01893         else if(enemypos.x>ffar*4){
01894             if(random<seek){
01895 #ifdef DEBUG
01896                 con << "seek!\n";
01897 #endif
01898                 lr-=side;
01899 
01900                 nextThought += 1;
01901             }
01902         }
01903         else if (enemypos.x<ffar*2 && fabs(enemypos.y)<ffar){
01904             if(random<trap){
01905 #ifdef DEBUG
01906                 con << "trap!\n";
01907 #endif
01908                 lr+=side;
01909 
01910                 nextThought += 1;
01911             }
01912         }
01913     }
01914 
01915     if (!EmergencySurvive(data, 1, -lr))
01916         nextThought = 0;
01917 
01918     data.thinkAgain = ed/2 + nextThought;
01919 }

Here is the call graph for this function:

Here is the caller graph for this function:

bool gAIPlayer::EmergencySurvive ( ThinkData &  data,
int  enemyEvade = -1,
int  preferedSide = 0 
) [protected, virtual]

Definition at line 2019 of file gAIBase.cpp.

References AI_EMERGENCY, AI_ENEMY, AI_LOOP, AI_TRACE, gCycleMovement::Alive(), character, ePlayerNetID::Chat(), CheckLoop(), gLoopData::closedIn, COLIDELEVEL, gAILog::current, DANGERLEVELS, Delay(), gAILog::DeleteEntry(), eSensor::detect(), gCycle::Direction(), gAISensor::distance, eDebugLine::Draw(), eCoord, emergency, gAILog::entries, freeSide, gAISensor::front, gAIPlayer::ThinkData::front, gAILogEntry::frontDanger, gAISensor::frontLoop, eGrid::GameObjects(), eGameObject::Grid(), gSENSOR_RIM, eSensor::hit, gAISensor::Hit(), tRecorderBase::IsRunning(), IsTrapped(), gAIPlayer::ThinkData::left, GrowingArrayBase::Len(), log, gLoopData::loop, LOOPLEVEL, gHitData::lr, gAILog::NextEntry(), NULL, Object(), gHitData::otherCycle, eGameObject::Position(), gAILog::Print(), gAICharacter::properties, REAL, gAIPlayer::ThinkData::right, se_GameTime(), eDebugLine::SetColor(), eDebugLine::SetTimeout(), SetTraceSide(), gAILogEntry::sideDanger, gAISensor::sideLoop, gArena::SizeMultiplier(), SPACELEVEL, gCycleMovement::Speed(), sqrt(), st_Breakpoint(), SwitchToState(), target, eGameObject::Team(), TEAMLEVEL, gAILogEntry::time, tNEW, TOL, TRAPLEVEL, gAILogEntry::tries, triesLeft, gAIPlayer::ThinkDataBase::turn, gAILogEntry::turn, gHitData::wallType, gCycle::WindingNumber(), and x.

Referenced by EmergencyCloseCombat(), EmergencyPath(), EmergencyTrace(), RightBeforeDeath(), ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), and ThinkTrace().

02020 {
02021     if (!character)
02022     {
02023         st_Breakpoint();
02024         return false;
02025     }
02026 
02027     gAISensor const & front = data.front;
02028     gAISensor const & left = data.left;
02029     gAISensor const & right = data.right;
02030 
02031     if (!log)
02032         log = tNEW(gAILog);
02033 
02034 #ifdef DEBUG
02035     static int last = 0;
02036     if (log->current >= 4
02037             && log->entries[log->current-2].time > se_GameTime() - .2
02038             && log->entries[log->current-1].turn * last <= 0
02039             && log->entries[log->current-1].turn * log->entries[log->current-2].turn < 0
02040             //      && log->entries[log->current-3].turn * log->entries[log->current-2].turn < 0
02041             //      && log->entries[log->current-3].turn * log->entries[log->current-4].turn < 0
02042        )
02043     {
02044         log->Print();
02045         //      st_Breakpoint();
02046     }
02047     if ( log->current > 0 )
02048         last = log->entries[log->current-1].turn;
02049 #endif
02050 
02051     triesLeft = (triesLeft * character->properties[AI_EMERGENCY])/10;
02052 
02053     freeSide *= .95;
02054 
02055     int i, j;
02056 
02057     // don't do a thing if there may be a better way out of we drive on:
02058     if (triesLeft > 0 &&
02059             front.front.otherCycle &&
02060             front.front.otherCycle != Object() &&
02061             ((front.frontLoop[1].loop && front.front.otherCycle != left .front.otherCycle && left .front.otherCycle)||
02062              (front.frontLoop[0].loop && front.front.otherCycle != right.front.otherCycle && right.front.otherCycle ) )
02063        )
02064         return false;
02065 
02066     // get the delay between two turns
02067     REAL delay = Delay();
02068     REAL range = Object()->Speed() * delay;
02069 
02070     // nothing we can do if we cannot make a turn immediately
02071     if (!Object()->CanMakeTurn(1) || !Object()->CanMakeTurn(-1))
02072         return false;
02073 
02074     //  bool dontCheckForLoop[2] = { false, false };
02075 
02076 
02077     // look out if there is anything bad going on in one of the directions:
02078     // [signifficance: danger level of n: You'll be (as good as) dead in [10/n delay times] if you drive that way
02079     int sideDanger[DANGERLEVELS][2];
02080     int frontDanger[DANGERLEVELS];
02081     for(i = DANGERLEVELS-1; i>=0; i--)
02082     {
02083         sideDanger[i][0] = 0;
02084         sideDanger[i][1] = 0;
02085         frontDanger[i]   = 0;
02086     }
02087 
02088     bool canTrapEnemy = false;
02089 
02090     if (emergency)
02091     {
02092         frontDanger[SPACELEVEL] += 40;
02093     }
02094 
02095     const gAISensor* sides[2];
02096     sides[0] = &left;
02097     sides[1] = &right;
02098 
02099     // avoid loops:
02100 
02101     bool isTrapped = IsTrapped(Object(), NULL);
02102 
02103     /*
02104       if (front.front.wallType == gSENSOR_ENEMY)
02105       sideDanger[LOOPLEVEL][(1-front.front.lr*enemyevade) >> 1] += 5;
02106     */  
02107 
02108     if (!isTrapped)
02109         for (i = 1; i>=0; i--)
02110         {
02111             if (front.frontLoop[i].loop && front.distance < 5*sides[i]->distance)
02112             {
02113                 // if we would close ourself in, make the danger bigger
02114                 if (front.front.otherCycle == Object() && i+i-1 == front.front.lr)
02115                     sideDanger[LOOPLEVEL][i]+=40;
02116 
02117                 sideDanger[LOOPLEVEL][i]+=40;
02118                 for (j = front.frontLoop[i].closedIn.Len()-1; j>=0; j--)
02119                     if (front.frontLoop[i].closedIn(j) == target)
02120                         canTrapEnemy = true;
02121             }
02122 
02123             for (j = 1; j>=0; j--)
02124                 if (front.sideLoop[i][j].loop)
02125                     sideDanger[LOOPLEVEL][j]++;
02126 
02127             // if we would close ourselfs in by a zigzag in direction i,
02128             // but not by a u-turn and there is enough space for a u-turn,
02129             // do it.
02130             if (sides[i]->frontLoop[1-i].loop  &&
02131                     !sides[i]->frontLoop[i].loop)
02132             {
02133                 if (sides[i]->distance > range)
02134                 {
02135                     frontDanger[LOOPLEVEL]     += 20;
02136                     sideDanger[LOOPLEVEL][1-i] += 10;
02137                 }
02138                 else // try to make some room so we can evade:
02139                 {
02140                     frontDanger[LOOPLEVEL]     += 20;
02141 
02142                     sideDanger[LOOPLEVEL][i]   += 10;
02143                 }
02144             }
02145 
02146             // if we would close ourselves in by a U-Turn, don't do it.
02147             //  if (sides[i]->frontLoop[i].loop && sides[i].distance < range * 2)
02148             //    sideDanger[LOOPLEVEL][i] += 40;
02149         }
02150 
02151     // try to trap the enemy
02152     if (character->properties[AI_LOOP] >= 10 && canTrapEnemy && !emergency)
02153         return false;
02154 
02155 
02156     /*
02157       // avoid closing yourself or a teammate in.
02158       if (front.type == gSENSOR_SELF || front.type == gSENSOR_TEAMMATE)
02159       {
02160          if (front.lr > 0)
02161       sideDanger[][1] +=2;
02162          else
02163       sideDanger[][0] +=2;
02164       }
02165     */
02166 
02167 
02168 
02169     {
02170         if (front.Hit() &&
02171                 ( front.distance + range < sides[0]->distance ||
02172                   front.distance + range < sides[1]->distance) )
02173         {
02174             if ( front.front.wallType == gSENSOR_RIM)
02175                 frontDanger[SPACELEVEL] += static_cast<int>(100 * range * gArena::SizeMultiplier() / (front.distance + range * .1));
02176 
02177             frontDanger[SPACELEVEL] += static_cast<int>(5 * range / (front.distance + range *.2));
02178 
02179             if (front.distance < range)
02180                 frontDanger[SPACELEVEL] += static_cast<int>(20 * range / (front.distance + range *.2)) + 1;
02181         }
02182 
02183 
02184         // avoid close corners:
02185         for (i = 1; i>=0; i--)
02186         {
02187             if (sides[i]->Hit() && //sides[i]->distance < range * 3 &&
02188                     sides[i]->distance < front.distance + range)
02189             {
02190                 if ( sides[i]->front.wallType == gSENSOR_RIM)
02191                     sideDanger[SPACELEVEL][i] += static_cast<int>(150 * range * gArena::SizeMultiplier() / (sides[i]->distance + range * .1));
02192 
02193                 sideDanger[SPACELEVEL][i] += static_cast<int>
02194                                              (range * 5 / (sides[i]->distance + range * .1));
02195 
02196                 if (sides[i]->distance < range)
02197                     sideDanger[SPACELEVEL][i] += static_cast<int>
02198                                                  (range * 20 / (sides[i]->distance + range * .1));
02199             }
02200 
02201             // give us a chance to turn around:
02202             if (frontDanger[SPACELEVEL] * 2 < sideDanger[SPACELEVEL][i])
02203                 sideDanger[LOOPLEVEL][i-i] -= sideDanger[SPACELEVEL][i] * 2;
02204         }
02205     }
02206 
02207     // avoid close proximity to other cycles
02208     const gCycle* target = NULL;
02209     const tList<eGameObject>& gameObjects = Object()->Grid()->GameObjects();
02210     gCycle *secondbest = NULL;
02211     REAL closest = 1000000;
02212     eCoord dir     = Object()->Direction();
02213 
02214     // find the closest enemy
02215     for (i=gameObjects.Len()-1;i>=0;i--){
02216         gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
02217 
02218         if (other && other->Alive() && other != Object())
02219         {
02220             eCoord otherpos=other->Position()-Object()->Position();
02221             REAL otherNorm = otherpos.NormSquared();
02222 
02223             bool nothit = false;
02224             if (otherNorm < closest * 4)
02225             {
02226                 gSensor p(other, other->Position(), -otherpos);
02227                 p.detect(REAL(.9999));
02228                 gSensor q(Object(), Object()->Position(), otherpos);
02229                 q.detect(REAL(.9999));
02230 
02231                 nothit = p.hit>=.999 && q.hit >=.999;
02232             }
02233 
02234             if (other->Team() != Object()->Team())
02235             {
02236                 // then, enemy is realy an enemy
02237                 //      REAL s = Object()->Speed() * 50;
02238                 if (/* otherNorm < s*s && */ otherNorm < closest)
02239                 {
02240                     // check if the path is clear
02241                     secondbest = dynamic_cast<gCycle *>(other);
02242                     if (nothit){
02243                         closest = otherNorm;
02244                         target = secondbest;
02245                     }
02246                 }
02247             }
02248             else if (nothit)
02249             {
02250                 // he is a teammate. Avoid him.
02251 
02252                 eCoord friendpos=other->Position() - Object()->Position();
02253 
02254                 // transform coordinates relative to us:
02255                 friendpos=friendpos.Turn(dir.Conj()).Turn(0,1);
02256 
02257                 if (friendpos.y > fabs(friendpos.x) * 1.5f)
02258                     frontDanger[TEAMLEVEL] += 10;
02259                 if (friendpos.x * 2 > -friendpos.y)
02260                     sideDanger[TEAMLEVEL][1] += 10;
02261                 else if (-friendpos.x * 2 > -friendpos.y)
02262                     sideDanger[TEAMLEVEL][0] += 10;
02263             }
02264         }
02265     }
02266 
02267     //  if (!target)
02268     //target = secondbest;
02269 
02270     if (target && character->properties[AI_ENEMY] > 0)
02271     {
02272         bool sdanger = false;
02273         for (i = DANGERLEVELS-1; i>=0; i--)
02274             sdanger |= sideDanger[i][0] > 4 || sideDanger[i][1] > 4;
02275 
02276         eCoord enemypos=target->Position() - Object()->Position();
02277         eCoord enemydir=target->Direction();
02278         REAL enemyspeed=target->Speed();
02279 
02280 
02281         // transform coordinates relative to us:
02282         enemypos=enemypos.Turn(dir.Conj()).Turn(0,1);
02283         enemydir=enemydir.Turn(dir.Conj()).Turn(0,1);
02284 
02285         if (character->properties[AI_ENEMY] > 7)
02286         {
02287             // would he be able to trap us if we drive straight on?
02288             bool trap[2] = {false, false};
02289 
02290             if (!isTrapped)
02291                 for (i = 1; i>=0; i--)
02292                 {
02293                     // if the enemy comes racing towards us, check if he could
02294                     // close us in by touching our own line ON THE OPPOSITE side of i
02295                     tArray<const gCycle*> closedIn;
02296                     int winding = 0;
02297 
02298                     bool loop = CheckLoop(target, Object(),
02299                                           Object()->GetDistance() + 4 * TOL, i, 0,
02300                                           closedIn, winding);
02301 
02302                     winding -= Object()->WindingNumber();
02303                     winding += target->WindingNumber();
02304 
02305 
02306                     // yes! we shoult turn in direction 1-i to get the target
02307                     // to the other side.
02308                     if (loop)
02309                         if (winding * (i+i-1) < 0)
02310                         {
02311                             trap[i] = true;
02312                             REAL x = enemypos.x * (i+i-1);
02313                             REAL y = enemypos.y;
02314 
02315                             bool canAccelerateByTurning =
02316                                 ( sides[1-i]->Hit() &&
02317                                   sides[1-i]->distance < Object()->Speed() * delay * 5 &&
02318                                   sides[i-i]->distance > Object()->Speed() * delay &&
02319                                   !sides[i-i]->frontLoop[i].loop) ;
02320 
02321                             bool ohShit = target->Speed() > Object()->Speed() + sqrt(closest);
02322 
02323                             if (ohShit)
02324                             {
02325                                 SetTraceSide(-(i+i-1));
02326                                 SwitchToState(AI_TRACE, 10);
02327                             }
02328 
02329                             bool turningIsFutile =
02330                                 front.front.otherCycle == Object() &&
02331                                 sides[1-i]->front.otherCycle == Object() &&
02332                                 front.distance < sides[1-1]->distance * 10 ;
02333 
02334                             if (
02335                                 x < 0 &&
02336                                 (
02337                                     x * Object()->Speed() < -y * target->Speed() + 1000 ||
02338                                     canAccelerateByTurning || ohShit
02339                                 )
02340                                 &&
02341                                 !turningIsFutile
02342                             )
02343                             {
02344                                 if (enemydir.y < -.2f && y < 0)
02345                                     SetTraceSide(-(i+i-1));
02346 
02347                                 frontDanger[TRAPLEVEL]    += 10;
02348                             }
02349 
02350                             if ( y > 0 || x < 0 || ohShit
02351                                     //                     ( y * Object()->Speed() > x * target->Speed()*.9 - 200 || enemyspeed.x * (i+i-1)
02352                                )
02353                                 sideDanger[TRAPLEVEL][i] += 20;
02354                             // sideDanger[TRAPLEVEL][i] ++;
02355                         }
02356                 }
02357         }
02358 
02359         if (character->properties[AI_ENEMY] > 0)
02360         {
02361             // imminent collision check
02362             REAL totalspeed = enemyspeed + Object()->Speed();
02363 
02364             if ((fabs(enemypos.y) < totalspeed * .3f && fabs(enemypos.x) < totalspeed * .3f))
02365             {
02366                 REAL diffSpeed  = -enemydir.y * enemyspeed + Object()->Speed();
02367                 if (diffSpeed > 0 && enemydir.y <= .2)
02368                 {
02369                     REAL enemyFront = enemypos.y / diffSpeed;
02370                     REAL enemySide  = fabs(enemypos.x) / diffSpeed;
02371                     if (enemyFront > 0 && enemyFront < .4 + enemySide && fabs(enemypos.y) > fabs(enemypos.x))
02372                     {
02373                         frontDanger[COLIDELEVEL] += 1 + int(4 / (enemyFront + .01));
02374                         //                    SwitchToState( AI_SURVIVE, enemyFront * 4 + 2 );
02375                     }
02376                 }
02377 
02378                 int side = enemypos.x > 0 ? 1 : 0;
02379 
02380                 // can we cut him instead of evade him?
02381                 if (Object()->Team() != target->Team() &&
02382                         ( ( enemydir.y <= -.2 &&
02383                             enemypos.y*target->Speed()*1.1 > fabs(enemypos.x) * Object()->Speed() ) ||
02384                           sideDanger[COLIDELEVEL][side] > 0))
02385                     sideDanger[COLIDELEVEL][1-side]+=5;
02386                 else if ( -(enemypos.y + .3f) * Object()->Speed() < fabs(enemypos.x) * target->Speed()*1.2)
02387                     sideDanger[COLIDELEVEL][side]+=10;
02388             }
02389         }
02390     }
02391 
02392     eDebugLine::SetTimeout(.5);
02393     eDebugLine::SetColor  (1, 0, 1);
02394     eCoord p = Object()->Position();
02395     eDebugLine::Draw(p, .5, p, 8.5);
02396     eDebugLine::SetTimeout(0);
02397 
02398 
02399 
02400     // determine the total danger levels by taking the max of the individual experts:
02401     int fDanger = 0;
02402     int sDanger[2] = { 0, 0 };
02403     for (i = 0; i<DANGERLEVELS; i++)
02404         // for (i = 1; i< 2; i++)
02405     {
02406         if (!fDanger || frontDanger[i] > fDanger + 2)
02407             fDanger = frontDanger[i];
02408 
02409         for (int j=1; j>=0; j--)
02410             if (!sDanger[j] || sideDanger[i][j] > sDanger[j] + 2)
02411                 sDanger[j] = sideDanger[i][j];
02412     }
02413 
02414     // nothing to do if we are not in immediate danger.
02415     if (!fDanger && !preferedSide)
02416         return false;
02417 
02418 
02419     // decide about your direction:
02420     int turn = 0;
02421 
02422     turn += sDanger[0];
02423     turn -= sDanger[1];
02424 
02425     if (!turn)
02426         turn = (int) freeSide;
02427 
02428     if (!turn && front.front.wallType != gSENSOR_RIM)
02429         turn = front.front.lr * enemyevade;
02430 
02431     if (!turn)
02432         turn = (sides[0]->distance > sides[1]->distance ? -1 : 1);
02433 
02434     if (!turn && log->current)
02435         turn = log->entries[log->current-1].turn;
02436 
02437 
02438 
02439     // switch to survival mode if we just trapped an enemy
02440     if (canTrapEnemy)
02441     {
02442 #ifdef DEBUG
02443         if ( !tRecorder::IsRunning() )
02444             Chat(tString( "Hehe! Got you!" ) );
02445 #endif
02446         SwitchToState(AI_TRACE, 10);
02447 
02448         if (turn)
02449             this->SetTraceSide(-turn);
02450     }
02451 
02452     gAILogEntry&e = log->NextEntry();
02453     e.turn = 0;
02454     e.tries = triesLeft;
02455     for (i = DANGERLEVELS-1; i>=0; i--)
02456     {
02457         e.frontDanger[i]   = frontDanger[i];
02458         e.sideDanger[i][0] = sideDanger[i][0];
02459         e.sideDanger[i][1] = sideDanger[i][1];
02460     }
02461 
02462 
02463     int side = 1;
02464     if (preferedSide < 0)
02465     {
02466         for (i = DANGERLEVELS-1; i>=0; i--)
02467         {
02468             int dSwap = sideDanger[i][0];
02469             sideDanger[i][0] = sideDanger[i][1];
02470             sideDanger[i][1] = dSwap;
02471         }
02472 
02473         int dSwap = sDanger[0];
02474         sDanger[0] = sDanger[1];
02475         sDanger[1] = dSwap;
02476 
02477         sides[1] = &left;
02478         sides[0] = &right;
02479         side     = -1;
02480         preferedSide = 1;
02481     }
02482 
02483 
02484     // no problem in the preferred direction. Just take it.
02485     if (preferedSide)
02486     {
02487         if( fDanger  * 3 >= sDanger[1] * 2 - 5 &&
02488                 sDanger[0] * 3 >= sDanger[1] * 2 - 5)
02489         {
02490             freeSide -= side*100;
02491             e.turn = side;
02492             data.turn = side;
02493             return true;
02494         }
02495 
02496         if (fDanger * 2 <= sDanger[0] * 3 + 3)
02497         {
02498             log->DeleteEntry();
02499             return false;
02500         }
02501     }
02502 
02503     // it is safer driving straight on
02504     if (fDanger <= sDanger[0] + 3 && fDanger <= sDanger[1] + 3 && fDanger < 20)
02505     {
02506         log->DeleteEntry();
02507         return false;
02508     }
02509 
02510 
02511     if (turn)
02512     {
02513         freeSide -= side*100;
02514         e.turn = turn;
02515         data.turn = turn;
02516     }
02517     else
02518         log->DeleteEntry();
02519 
02520     return turn;
02521 
02522     eDebugLine::SetTimeout(0);
02523 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::EmergencyTrace ( ThinkData &  data  )  [protected, virtual]

Definition at line 2526 of file gAIBase.cpp.

References EmergencySurvive(), and traceSide.

Referenced by RightBeforeDeath().

02527 {
02528     EmergencySurvive( data, -1, -traceSide );
02529 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::EmergencyPath ( ThinkData &  data  )  [protected, virtual]

Definition at line 2532 of file gAIBase.cpp.

References EmergencySurvive().

Referenced by RightBeforeDeath().

02533 {
02534     EmergencySurvive( data );
02535 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::EmergencyCloseCombat ( ThinkData &  data  )  [protected, virtual]

Definition at line 2537 of file gAIBase.cpp.

References EmergencySurvive().

Referenced by RightBeforeDeath().

02538 {
02539     EmergencySurvive( data );
02540 
02541     /*
02542       int dir = 0;
02543 
02544       if (target)
02545       {
02546          eCoord enemyPos = target->Position() - Object()->Position();
02547          eCoord dirRel   = Object()->Direction();
02548          if (enemyPos * dirRel < 0)
02549       dir --;
02550          else
02551       dir ++;
02552       }
02553 
02554 
02555       EmergencySurvive(front, left, right, 1, dir);
02556     */
02557 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ActOnData ( ThinkData &  data  )  [protected, virtual]

Definition at line 2890 of file gAIBase.cpp.

References eSensor::detect(), eSensor::hit, Object(), REAL, gCycleMovement::Speed(), and gAIPlayer::ThinkDataBase::thinkAgain.

Referenced by RightBeforeDeath(), and Think().

02891 {
02892     // delegate
02893     ThinkDataBase & base = data;
02894     ActOnData( base );
02895 
02896     // sanitize next think time so it will be before we hit the next wall
02897     if ( Object()->Speed() > 0 && data.thinkAgain > 0 )
02898     {
02899         gSensor front( Object(), Object()->Position(), Object()->Direction() );
02900         front.detect( Object()->Speed() * data.thinkAgain * 1.5 );
02901         if ( front.ehit )
02902         {
02903             REAL thinkAgain = ( front.hit / Object()->Speed() ) * .8;
02904             if ( data.thinkAgain > thinkAgain )
02905                 data.thinkAgain = thinkAgain;
02906         }
02907     }
02908 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ActOnData ( ThinkDataBase &  data  )  [protected, virtual]

Definition at line 2910 of file gAIBase.cpp.

References EPS, Object(), tRecorder::Playback(), REAL, tRecorder::Record(), st_Breakpoint(), gAIPlayer::ThinkDataBase::thinkAgain, gCycleMovement::Turn(), and gAIPlayer::ThinkDataBase::turn.

02911 {
02912     // archive decision
02913     ThinkDataBase copy = data;
02914     if ( tRecorder::Playback( section, data ) )
02915     {
02916         if ( copy.turn != data.turn )
02917         {
02918             // AI made a different decision than recorded, better let a programmer have a look at it
02919             std::cout << "AI turn decision changed!\n";
02920             st_Breakpoint();
02921         }
02922 
02923         REAL difference =  fabs( copy.thinkAgain - data.thinkAgain );
02924         static REAL minReport = EPS;
02925         if ( difference > minReport )
02926         {
02927             minReport = difference * 2;
02928             std::cout << "AI timing decision changed by " << difference
02929             << " from " << data.thinkAgain << " to " << copy.thinkAgain <<"!\n";
02930             st_Breakpoint();
02931         }
02932     }
02933     tRecorder::Record( section, data );
02934 
02935     // execute turn
02936     if ( data.turn )
02937         Object()->Turn( data.turn );
02938 }

Here is the call graph for this function:

gAICharacter* gAIPlayer::Character (  )  const [inline]

Definition at line 178 of file gAIBase.h.

References character.

Referenced by gAITeam::BalanceWithAIs(), BestIQ(), CycleBlocksWay(), and gAISensor::gAISensor().

00178 {return character;}

Here is the caller graph for this function:

void gAIPlayer::ClearAll (  )  [static]

remove all AI players

Reimplemented from ePlayerNetID.

Definition at line 2995 of file gAIBase.cpp.

References AITeam(), ClearAITeam(), and tReferenceHolder< T >::ReleaseAll().

02996 {
02997     sg_AIReferences.ReleaseAll();
02998 
02999     // remove empty AI team
03000     if ( 0 == AITeam()->NumPlayers() )
03001     {
03002         ClearAITeam();
03003     }
03004 }

Here is the call graph for this function:

void gAIPlayer::CycleBlocksWay ( const gCycleMovement *  a,
const gCycleMovement *  b,
int  aDir,
int  bDir,
REAL  bDist,
int  winding 
) [static]

Definition at line 981 of file gAIBase.cpp.

References a, ai, AI_DETECTTRACE, AI_TRACE, ePlayerNetID::b, Character(), CycleBlocksWayHelper(), gCycleMovement::GetDistance(), lastChangeAttempt, nextStateChange, eNetGameObject::Player(), gAICharacter::properties, REAL, se_GameTime(), SetTraceSide(), gCycleMovement::Speed(), SwitchToState(), target, tASSERT, and eGameObject::Team().

Referenced by blocks().

00983 {
00984 
00985 
00986     tASSERT(aa && bb);
00987     gCycle * a = dynamic_cast< gCycle * >( const_cast< gCycleMovement * > ( aa ) );
00988     gCycle * b = dynamic_cast< gCycle * >( const_cast< gCycleMovement * > ( bb ) );
00989 
00990     REAL aDist = a->GetDistance();
00991     aDir = (aDir > 0 ? 1 : 0);
00992     bDir = (bDir > 0 ? 1 : 0);
00993 
00994     int w = winding + aDir * 2 + bDir * 2;
00995     while (w < 0)
00996         w+=400;
00997     if (w % 4 != 2)
00998         return;
00999 
01000     CycleBlocksWayHelper(a,b,aDir,bDir,aDist,bDist,  winding);
01001     CycleBlocksWayHelper(b,a,bDir,aDir,bDist,aDist, -winding);
01002 
01003     // what to do if cylce a tries to trace cylce b?
01004     if (a->Team() != b->Team())
01005     {
01006         gAIPlayer* ai = dynamic_cast<gAIPlayer*>(b->Player());
01007         if (ai && ai->Character() && ai->Character()->properties[AI_DETECTTRACE] > 5)
01008             if(aDir != bDir && ai->nextStateChange < se_GameTime() + 5 &&
01009                     ai->lastChangeAttempt < se_GameTime() - 5 )
01010             {
01011                 REAL behind = b->GetDistance() - bDist;
01012                 if (a->Speed() > b->Speed() * 1.2f && behind < (a->Speed() - b->Speed()) * 10)
01013                 { // a is faster. Try to escape.
01014                     ai->SetTraceSide(aDir > 0 ? 1 : -1);
01015                     ai->SwitchToState(AI_TRACE, 10);
01016                     ai->target = const_cast< gCycle * >( a );
01017                 }
01018                 else// if (a->Speed() < b->Speed() * 1.1f)
01019                 { // b is faster. Attack.
01020                     ai->SetTraceSide(aDir > 0 ? -1 : 1);
01021                     ai->SwitchToState(AI_TRACE, 10 + behind / ( a->Speed() + b->Speed() ) );
01022                     ai->target = const_cast< gCycle * >( a );
01023                 }
01024             }
01025 
01026         // what to do if the AI player traces his opponent by accident? Trace On!
01027         ai = dynamic_cast<gAIPlayer*>(a->Player());
01028         if (ai && ai->Character() && ai->Character()->properties[AI_DETECTTRACE] > 0)
01029             if(aDir != bDir && ai->nextStateChange < se_GameTime() + 5 &&
01030                     ai->lastChangeAttempt < se_GameTime() - 5 )
01031             {
01032                 REAL behind = b->GetDistance() - bDist;
01033                 ai->SetTraceSide(aDir > 0 ? 1 : -1);
01034                 ai->SwitchToState(AI_TRACE, 10 + 4 * behind / a->Speed());
01035                 ai->target = const_cast< gCycle * >( b );
01036             }
01037     }
01038 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::CycleBlocksRim ( const gCycleMovement *  a,
int  aDir 
) [static]

Definition at line 1041 of file gAIBase.cpp.

Referenced by blocks().

01042 {
01043 }

Here is the caller graph for this function:

void gAIPlayer::BreakWall ( const gCycleMovement *  a,
REAL  aDist 
) [static]

Definition at line 1046 of file gAIBase.cpp.

01047 {}

void gAIPlayer::ConfigureAIs (  )  [static]

Definition at line 1186 of file gAIBase.cpp.

01187 {
01188 
01189 }

void gAIPlayer::SetNumberOfAIs ( int  num,
int  minPlayers,
int  iq,
int  tries = 3 
) [static]

Definition at line 1193 of file gAIBase.cpp.

References tReferenceHolder< T >::Add(), ai, AITeam(), gAITeam::BalanceWithAIs(), BestIQ(), character, ClearAITeam(), nNetObject::GetRefcount(), gAICharacter::iq, ePlayerNetID::IsSpectating(), GrowingArrayBase::Len(), gAICharacter::name, ePlayerNetID::NextTeam(), NULL, tReferenceHolder< T >::Remove(), ePlayerNetID::RemoveFromGame(), se_PlayerNetIDs, ePlayerNetID::SetName(), ePlayerNetID::SetTeam(), st_Breakpoint(), tNEW, and ePlayerNetID::UpdateTeam().

Referenced by init_game_objects().

01194 {
01195     // balance the human teams with AI players
01196     gAITeam::BalanceWithAIs();
01197 
01198     // remove AI players that got kicked out of their team
01199     for (int i = se_PlayerNetIDs.Len()-1; i>=0; i--)
01200     {
01201         // count the active AIs
01202         ePlayerNetID *p = se_PlayerNetIDs(i);
01203         gAIPlayer  *ai  = dynamic_cast<gAIPlayer*>(p);
01204         if ( ai && !bool( ai->NextTeam() ) )
01205         {
01206             ai->RemoveFromGame();
01207 
01208 #ifdef DEBUG
01209             if ( ai->GetRefcount() > 1 )
01210             {
01211                 st_Breakpoint();
01212             }
01213 #endif
01214 
01215             sg_AIReferences.Remove( ai );
01216         }
01217     }
01218 
01219     int count = 0;
01220 
01221     bool iqperfect = false;
01222 
01223     // repeat until we run out of tries or the total amount of AIs is correct
01224     do
01225     {
01226         count = 0;
01227 
01228         int i;
01229         gAIPlayer* worstIQ = NULL; // worst fitting AI player that is in the game
01230 
01231         //              static tArray<bool> inGame(gAICharacter::s_Characters.Len());
01232         //              for (i = gAICharacter::s_Characters.Len()-1; i>=0; i--)
01233         //                      inGame(i) = false;
01234 
01235         for (i = se_PlayerNetIDs.Len()-1; i>=0; i--)
01236         {
01237             // count the active AIs
01238             ePlayerNetID *p = se_PlayerNetIDs(i);
01239             gAIPlayer  *ai  = dynamic_cast<gAIPlayer*>(p);
01240             if (ai && ai->NextTeam() == sg_AITeam )
01241             {
01242                 //                              int index = ((int)ai->character - (int)&gAICharacter::s_Characters(0))/sizeof(gAICharacter);
01243                 //                              inGame(index) = true;
01244 
01245                 if (!worstIQ || !worstIQ->character || fabs(worstIQ->character->iq - iq) < fabs(ai->character->iq - iq) )
01246                     worstIQ = ai;
01247 
01248                 count++;
01249             }
01250         }
01251 
01252         gAICharacter* bestIQ = BestIQ( iq );
01253 
01254         // count = numberOfAIs to add / remove(numberofAIs - requestedNumAIs)
01255         count -= num;
01256 
01257         // pcount = numberPlayers above minPlayers
01258         int pcount = - minPlayers;
01259         // check if more AIs are required (because there are less than minPlayers players)
01260         for (i = se_PlayerNetIDs.Len()-1; i>=0; i--)
01261         {
01262             ePlayerNetID *p = se_PlayerNetIDs(i);
01263             if ( !p->IsSpectating() )
01264                 ++pcount;
01265         }
01266 
01267         if (pcount < count)
01268             count = pcount;
01269 
01270         iqperfect = true;
01271         if (bestIQ && worstIQ && worstIQ->character )
01272             iqperfect = (fabs(bestIQ->iq - iq) > fabs(worstIQ->character->iq - iq) * .9f);
01273 
01274 
01275         // count complete. Do something!
01276         if (worstIQ && (count > 0 || (count >= 0 && !iqperfect)))
01277         {
01278             // too many AIs. Delete the one with the least fitting intelligence.
01279             worstIQ->RemoveFromGame();
01280             //                  worstIQ->ReleaseOwnership();
01281 
01282 #ifdef DEBUG
01283             if ( worstIQ->GetRefcount() > 1 )
01284             {
01285                 st_Breakpoint();
01286             }
01287 #endif
01288 
01289             sg_AIReferences.Remove( worstIQ );
01290             count--;
01291 
01292             // remove empty AI team
01293             if ( 0 == AITeam()->NumPlayers() )
01294             {
01295                 ClearAITeam();
01296             }
01297         }
01298         if (bestIQ && count < 0)
01299         {
01300             // too litte AIs. Create one.
01301             gAIPlayer *ai = tNEW(gAIPlayer)();
01302             ai->SetName( bestIQ->name );
01303             ai->character = bestIQ;
01304 
01305             sg_AIReferences.Add( ai );
01306 
01307             ai->SetTeam ( AITeam() );
01308             ai->UpdateTeam();
01309 
01310             /*
01311             {
01312                 tOutput mess;
01313                 tColoredString printname;
01314                 printname << *(ePlayerNetID*)ai << tColoredString::ColorString(.5,1,.5);
01315 
01316                 mess.SetTemplateParameter(1, printname);
01317                 mess << "$player_entered_game";
01318 
01319                 sn_ConsoleOut( mess );
01320             }
01321             */
01322 
01323             count++;
01324         }
01325 
01326     }
01327     while ((count != 0 ||
01328             !iqperfect) &&
01329             tries-- != 0);
01330 
01331 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::ClearTarget (  )  [inline]

Definition at line 206 of file gAIBase.h.

References NULL, and target.

Referenced by gAIPlayer(), and NewObject().

00206 {target=NULL;}

Here is the caller graph for this function:

virtual void gAIPlayer::ControlObject ( eNetGameObject *  c  )  [inline, virtual]

Reimplemented from ePlayerNetID.

Definition at line 208 of file gAIBase.h.

References ePlayerNetID::ControlObject(), NULL, and simpleAI_.

Here is the call graph for this function:

virtual void gAIPlayer::ClearObject (  )  [inline, virtual]

Reimplemented from ePlayerNetID.

Definition at line 209 of file gAIBase.h.

References ePlayerNetID::ClearObject(), NULL, and simpleAI_.

Referenced by ~gAIPlayer().

Here is the call graph for this function:

Here is the caller graph for this function:

REAL gAIPlayer::Think (  )  [virtual]

Definition at line 2722 of file gAIBase.cpp.

References ActOnData(), AI_CLOSECOMBAT, AI_PATH, AI_SURVIVE, AI_TRACE, Alive(), gSimpleAIFactory::Create(), Delay(), gCycle::Direction(), eGrid::DirectionWinding(), gAISensor::distance, eDebugLine::Draw(), eCoord, emergency, eGrid::GameObjects(), gSimpleAIFactory::Get(), eGameObject::Grid(), gAISensor::Hit(), GrowingArrayBase::Len(), log, nextStateChange, NULL, Object(), eGameObject::Position(), gAILog::Print(), REAL, se_GameTime(), eDebugLine::SetColor(), eDebugLine::SetTimeout(), sg_GetSensor(), simpleAI_, gCycleMovement::Speed(), sqrt(), st_Breakpoint(), state, SwitchToState(), target, gSimpleAI::Think(), gAIPlayer::ThinkDataBase::thinkAgain, ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), ThinkTrace(), triesLeft, gCycleMovement::Turn(), and x.

Referenced by Timestep().

02722                      {
02723     if ( !simpleAI_ )
02724     {
02725         gSimpleAIFactory * factory = gSimpleAIFactory::Get();
02726         if ( factory )
02727         {
02728             simpleAI_ = factory->Create( Object() );
02729         }
02730     }
02731 
02732     if ( simpleAI_ )
02733     {
02734         return simpleAI_->Think();
02735     }
02736 
02737     // get the delay between two turns
02738     REAL delay = Delay();
02739 
02740 #ifdef DEBUG_X  
02741     if (log && !Object()->Alive())
02742     {
02743         log->Print();
02744         st_Breakpoint();
02745         delete log;
02746         log = NULL;
02747     }
02748 #endif
02749 
02750     if (!Object()->Alive())
02751         return 100;
02752 
02753     emergency = false;
02754     //  return 1;
02755 
02756     // first, find close eWalls and evade them.
02757     REAL speed=Object()->Speed();
02758     REAL range=speed;
02759     eCoord dir=Object()->Direction();
02760     REAL side=speed*delay;
02761 
02762     REAL corridor = range;
02763     if (corridor < side * 2)
02764         corridor = side * 2;
02765 
02766     gAISensor front(Object(),Object()->Position(),dir, side * 2, range, corridor, 0);
02767 
02768 #ifdef DEBUG_X
02769     if (front.Hit())
02770     {
02771         gRandomController noRandom;
02772 
02773         if (front.distance < 1)
02774         {
02775             int x;
02776             x = 1;
02777         }
02778         gAISensor front(Object(),Object()->Position(),dir, side, range, corridor, 0);
02779     }
02780 #endif
02781 
02782     // get the sensors to the left and right with the most free space
02783     int currentDirectionNumber = Object()->Grid()->DirectionWinding( dir );
02784     REAL mindistLeft = 1E+30, mindistRight = 1E+30;
02785     std::auto_ptr< gAISensor > left  ( sg_GetSensor( currentDirectionNumber, *Object(), -1, side, range, corridor, mindistLeft ) );
02786     std::auto_ptr< gAISensor > right ( sg_GetSensor( currentDirectionNumber, *Object(), 1, side, range, corridor, mindistRight ) );
02787 
02788     // count intermediate walls to the left and right as if they were in front
02789     {
02790         REAL mindistFront = mindistLeft > mindistRight ? mindistLeft : mindistRight;
02791         if ( mindistFront < front.distance )
02792         {
02793             front.distance = mindistFront;
02794         }
02795     }
02796 
02797 #ifdef TESTSTATE  
02798     state = TESTSTATE;
02799     nextStateChange = se_GameTime() + 100;
02800 #else
02801     // switch to survival state if our victim died:
02802     if (state != AI_SURVIVE && state != AI_TRACE && (!target || !target->Alive()))
02803         SwitchToState(AI_SURVIVE, 1);
02804 #endif
02805 
02806     {
02807         eDebugLine::SetTimeout(.5);
02808         eDebugLine::SetColor  (0, 1, 0);
02809         eCoord p = Object()->Position();
02810         eDebugLine::Draw(p, .5, p, 5.5);
02811         eDebugLine::SetTimeout(0);
02812     }
02813 
02814     triesLeft = 10;
02815 
02816     REAL ret = 1;
02817 
02818     //not the best solution, but still better than segfault...
02819     if(left.get() != 0 && right.get() != 0) {
02820         ThinkData data( front, *left, *right);
02821         switch (state)
02822         {
02823         case AI_SURVIVE:
02824             ThinkSurvive(data);
02825             break;
02826         case AI_PATH:
02827             ThinkPath(data);
02828             break;
02829         case AI_TRACE:
02830             ThinkTrace(data);
02831             break;
02832         case AI_CLOSECOMBAT:
02833             ThinkCloseCombat(data);
02834             break;
02835         }
02836         ActOnData( data );
02837         ret = data.thinkAgain;
02838     }
02839 
02840 #ifdef DEBUG_X
02841     {
02842         gAISensor front(Object(),Object()->Position(),dir, side, range, range*.3, 0);
02843         gAISensor left(Object(),Object()->Position(),dir.Turn(eCoord(0,1)), side, range, range*.3, -1);
02844         gAISensor right(Object(),Object()->Position(),dir.Turn(eCoord(0,-1)), side, range, range*.3, 1);
02845     }
02846 #endif
02847 
02848     REAL mindist = front.distance * front.distance * 8;
02849 
02850     const tList<eGameObject>& gameObjects = Object()->Grid()->GameObjects();
02851 
02852     // find the closest enemy
02853     for (int i=gameObjects.Len()-1;i>=0;i--){
02854         gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
02855 
02856         if (other && other != Object()){
02857             // then, enemy is realy an enemy
02858             eCoord otherpos=other->Position()-Object()->Position();
02859             REAL dist = otherpos.NormSquared();
02860 
02861             if (dist < mindist)
02862                 mindist = dist;
02863         }
02864     }
02865 
02866     mindist = sqrt(mindist) / (3 * Object()->Speed());
02867 
02868     if (ret > mindist)
02869         ret = mindist;
02870 
02871     return ret;
02872 }

Here is the call graph for this function:

Here is the caller graph for this function:

bool gAIPlayer::Alive (  )  [inline]

Definition at line 214 of file gAIBase.h.

References gCycleMovement::Alive(), and Object().

Referenced by RightBeforeDeath(), and Think().

00214                 {
00215         return bool(Object()) && Object()->Alive();
00216     }

Here is the call graph for this function:

Here is the caller graph for this function:

virtual bool gAIPlayer::IsHuman (  )  const [inline, virtual]

Reimplemented from ePlayerNetID.

Definition at line 218 of file gAIBase.h.

Referenced by gAITeam::BalanceWithAIs().

00218 { return false; }

Here is the caller graph for this function:

gCycle* gAIPlayer::Object (  )  [inline]

Definition at line 220 of file gAIBase.h.

References NULL, ePlayerNetID::Object(), and tASSERT.

Referenced by ActOnData(), Alive(), EmergencySurvive(), RightBeforeDeath(), Think(), ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), ThinkTrace(), and Timestep().

00221     {
00222         eGameObject* go = ePlayerNetID::Object();
00223         if ( !go )
00224         {
00225             return NULL;
00226         }
00227         else
00228         {
00229             tASSERT(dynamic_cast<gCycle*>(go));
00230             return static_cast<gCycle*>(go);
00231         }
00232     }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::Timestep ( REAL  time  ) 

Definition at line 2942 of file gAIBase.cpp.

References AI_REACTION, gCycleMovement::Alive(), character, concentration, EPS, lastTime, nextTime, Object(), gAICharacter::properties, randomizer_, REAL, st_Breakpoint(), Think(), and ts.

Referenced by gGame::GameLoop().

02942                                  {
02943     if (!character)
02944     {
02945         st_Breakpoint();
02946         return;
02947     }
02948 
02949     // don't think if the object is not up to date
02950     if ( Object() && Object()->LastTime() < time - EPS )
02951         return;
02952 
02953     REAL ts=time-lastTime;
02954     lastTime=time;
02955 
02956     if (concentration < 0)
02957         concentration = 0;
02958 
02959     concentration += 4*(character->properties[AI_REACTION]+1) * ts/relax;
02960     concentration=concentration/(1+ts/relax);
02961 
02962     if (bool(Object()) && Object()->Alive() && nextTime<time){
02963         gRandomController random( randomizer_ );
02964 
02965         REAL nextthought=Think();
02966         //    if (nextthought>.9) nextthought=REAL(.9);
02967 
02968         if (nextthought<REAL(.6-concentration)) nextthought=REAL(.6-concentration);
02969 
02970         nextTime=nextTime+nextthought;
02971 
02972         //con << concentration << "\t" << nextthought << '\t' << ts << '\n';
02973 
02974         if(.1+4*nextthought<1)
02975             concentration*=REAL(.1+4*nextthought);
02976     }
02977 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::NewObject (  )  [virtual]

Reimplemented from ePlayerNetID.

Definition at line 2649 of file gAIBase.cpp.

References AI_STARTSTATE, AI_STARTSTRAIGHT, AI_STATECHANGE, AI_TRACE, character, ePath::Clear(), ClearTarget(), lastChangeAttempt, lastPath, lastTime, lazySideChange, log, nextStateChange, nextTime, NULL, path, gAICharacter::properties, gArena::SizeMultiplier(), gCycleMovement::SpeedMultiplier(), and state.

Referenced by gAIPlayer().

02650 {
02651     lastTime = 0;
02652     lastPath = 0;
02653     lastChangeAttempt = 0;
02654     lazySideChange = 0;
02655     path.Clear();
02656 
02657     if (character)
02658     {
02659         nextTime        = character->properties[AI_STARTSTRAIGHT] * gArena::SizeMultiplier()/gCycleMovement::SpeedMultiplier();
02660         nextStateChange = character->properties[AI_STATECHANGE];
02661         state           = (gAI_STATE)character->properties[AI_STARTSTATE];
02662     }
02663     else
02664     {
02665         nextTime        = 10;
02666         nextStateChange = 30;
02667         state           = AI_TRACE;
02668     }
02669 
02670     if (log)
02671         delete log;
02672     log = NULL;
02673 
02674     ClearTarget();
02675 }

Here is the call graph for this function:

Here is the caller graph for this function:

void gAIPlayer::RightBeforeDeath ( int  triesLeft  )  [virtual]

Reimplemented from ePlayerNetID.

Definition at line 2562 of file gAIBase.cpp.

References ActOnData(), AI_CLOSECOMBAT, AI_EMERGENCY, AI_PATH, AI_SURVIVE, AI_TRACE, Alive(), character, Delay(), gCycle::Direction(), eCoord, emergency, EmergencyCloseCombat(), EmergencyPath(), EmergencySurvive(), EmergencyTrace(), lastTime, log, nCLIENT, nextStateChange, nextTime, NULL, Object(), gAILog::Print(), gAICharacter::properties, Random(), randomizer_, REAL, se_GameTime(), simpleAI_, sn_GetNetState(), gCycleMovement::Speed(), st_Breakpoint(), state, SwitchToState(), target, and gCycleMovement::Turn().

02563 {
02564     if ( nCLIENT == sn_GetNetState() )
02565         return;
02566 
02567     if ( simpleAI_ )
02568         return;
02569 
02570     if (!character)
02571     {
02572         st_Breakpoint();
02573         return;
02574     }
02575 
02576     gRandomController random( randomizer_ );
02577 
02578     // think again immediately after this
02579     nextTime = lastTime;
02580 
02581 #ifdef DEBUG_X
02582     if (log && !Object()->Alive())
02583     {
02584         log->Print();
02585         //      st_Breakpoint();
02586         delete log;
02587         log = NULL;
02588     }
02589 #endif
02590 
02591     if (!Object()->Alive() || ( character && Random() * 10 > character->properties[AI_EMERGENCY] ) )
02592         return;
02593 
02594 
02595     // get the delay between two turns
02596     REAL delay = Delay();
02597 
02598     this->triesLeft = triesLeft;
02599     this->emergency = (triesLeft < 2);
02600 
02601     REAL speed=Object()->Speed();
02602     REAL range=speed;
02603     eCoord dir=Object()->Direction();
02604     REAL  side = speed*delay;
02605 
02606     gAISensor front(Object(),Object()->Position(),dir, side, range, range*.3, 0);
02607     gAISensor left(Object(),Object()->Position(),dir.Turn(eCoord(0,1)), side, range, range*.3, -1);
02608     gAISensor right(Object(),Object()->Position(),dir.Turn(eCoord(0,-1)), side, range, range*.3, 1);
02609 
02610 
02611 
02612 
02613 #ifdef TESTSTATE  
02614     state = TESTSTATE;
02615     nextStateChange = se_GameTime() + 100;
02616 #else
02617     // switch to survival state if our victim died:
02618     if ((!target || !target->Alive()) && state != AI_TRACE)
02619         SwitchToState(AI_SURVIVE, 1);
02620 #endif
02621 
02622     ThinkData data( front, left, right);
02623     switch (state)
02624     {
02625     case AI_SURVIVE:
02626         EmergencySurvive(data);
02627         break;
02628     case AI_PATH:
02629         EmergencyPath(data);
02630         break;
02631     case AI_TRACE:
02632         EmergencyTrace(data);
02633         break;
02634     case AI_CLOSECOMBAT:
02635         EmergencyCloseCombat(data);
02636         break;
02637     }
02638     ActOnData( data );
02639 
02640 #ifdef DEBUG_X
02641     {
02642         gAISensor front(Object(),Object()->Position(),dir, side, range, range*.3, 0);
02643         gAISensor left(Object(),Object()->Position(),dir.Turn(eCoord(0,1)), side, range, range*.3, -1);
02644         gAISensor right(Object(),Object()->Position(),dir.Turn(eCoord(0,-1)), side, range, range*.3, 1);
02645     }
02646 #endif
02647 }

Here is the call graph for this function:

void gAIPlayer::Color ( REAL &  r,
REAL &  g,
REAL &  b 
) const [virtual]

Reimplemented from ePlayerNetID.

Definition at line 2980 of file gAIBase.cpp.

References ePlayerNetID::Color().

02981 {
02982     ePlayerNetID::Color( a_r, a_g, a_b );
02983 }

Here is the call graph for this function:

nDescriptor & gAIPlayer::CreatorDescriptor ( void   )  const [virtual]

Reimplemented from ePlayerNetID.

Definition at line 1081 of file gAIBase.cpp.

References gAIPlayer_init.

01081                                                {
01082     return gAIPlayer_init;
01083 }


Friends And Related Function Documentation

friend class gAITeam [friend]

Definition at line 91 of file gAIBase.h.


Member Data Documentation

tReproducibleRandomizer gAIPlayer::randomizer_ [private]

Definition at line 93 of file gAIBase.h.

Referenced by RightBeforeDeath(), and Timestep().

gSimpleAI* gAIPlayer::simpleAI_ [protected]

Definition at line 95 of file gAIBase.h.

Referenced by ClearObject(), ControlObject(), RightBeforeDeath(), and Think().

gAICharacter* gAIPlayer::character [protected]

Definition at line 96 of file gAIBase.h.

Referenced by gAITeam::BalanceWithAIs(), Character(), EmergencySurvive(), gAIPlayer(), NewObject(), RightBeforeDeath(), SetNumberOfAIs(), SwitchToState(), ThinkSurvive(), and Timestep().

nObserverPtr< gCycle > gAIPlayer::target [protected]

Definition at line 99 of file gAIBase.h.

Referenced by ClearTarget(), CycleBlocksWay(), EmergencySurvive(), RightBeforeDeath(), Think(), ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), ThinkTrace(), and ~gAIPlayer().

ePath gAIPlayer::path [protected]

Definition at line 102 of file gAIBase.h.

Referenced by NewObject(), and ThinkPath().

REAL gAIPlayer::lastPath [protected]

Definition at line 103 of file gAIBase.h.

Referenced by NewObject(), and ThinkPath().

int gAIPlayer::traceSide [protected]

Definition at line 106 of file gAIBase.h.

Referenced by EmergencyTrace(), gAIPlayer(), SetTraceSide(), and ThinkTrace().

REAL gAIPlayer::lastChangeAttempt [protected]

Definition at line 107 of file gAIBase.h.

Referenced by CycleBlocksWay(), NewObject(), and SetTraceSide().

REAL gAIPlayer::lazySideChange [protected]

Definition at line 108 of file gAIBase.h.

Referenced by NewObject(), and SetTraceSide().

gAI_STATE gAIPlayer::state [protected]

Definition at line 111 of file gAIBase.h.

Referenced by NewObject(), RightBeforeDeath(), SwitchToState(), and Think().

REAL gAIPlayer::nextStateChange [protected]

Definition at line 112 of file gAIBase.h.

Referenced by CycleBlocksWay(), NewObject(), RightBeforeDeath(), SwitchToState(), Think(), ThinkCloseCombat(), ThinkPath(), ThinkSurvive(), and ThinkTrace().

bool gAIPlayer::emergency [protected]

Definition at line 114 of file gAIBase.h.

Referenced by EmergencySurvive(), RightBeforeDeath(), and Think().

int gAIPlayer::triesLeft [protected]

Definition at line 115 of file gAIBase.h.

Referenced by EmergencySurvive(), and Think().

REAL gAIPlayer::freeSide [protected]

Definition at line 117 of file gAIBase.h.

Referenced by EmergencySurvive(), and gAIPlayer().

REAL gAIPlayer::lastTime [protected]

Definition at line 120 of file gAIBase.h.

Referenced by NewObject(), RightBeforeDeath(), and Timestep().

REAL gAIPlayer::nextTime [protected]

Definition at line 121 of file gAIBase.h.

Referenced by NewObject(), RightBeforeDeath(), and Timestep().

REAL gAIPlayer::concentration [protected]

Definition at line 123 of file gAIBase.h.

Referenced by Timestep().

gAILog* gAIPlayer::log [protected]

Definition at line 126 of file gAIBase.h.

Referenced by EmergencySurvive(), gAIPlayer(), NewObject(), RightBeforeDeath(), Think(), and ~gAIPlayer().


The documentation for this class was generated from the following files:
Generated on Sat Mar 15 23:33:27 2008 for Armagetron Advanced by  doxygen 1.5.4