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

gAICharacterCharacter () const
 gAIPlayer ()
 ~gAIPlayer ()
void ClearTarget ()
virtual void ControlObject (eNetGameObject *c)
virtual void ClearObject ()
virtual REAL Think ()
bool Alive ()
virtual bool IsHuman () const
gCycleObject ()
void Timestep (REAL time)
virtual void NewObject ()
virtual void RightBeforeDeath (int triesLeft)
virtual void Color (REAL &r, REAL &g, REAL &b) const
virtual nDescriptorCreatorDescriptor () 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

gSimpleAIsimpleAI_
gAICharactercharacter
nObserverPtr< gCycletarget
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
gAILoglog

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