#include <gAIBase.h>
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 |
Definition at line 90 of file gAIBase.h.
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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;}
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 }
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 }
void gAIPlayer::CycleBlocksRim | ( | const gCycleMovement * | a, | |
int | aDir | |||
) | [static] |
Definition at line 1041 of file gAIBase.cpp.
Referenced by blocks().
void gAIPlayer::BreakWall | ( | const gCycleMovement * | a, | |
REAL | aDist | |||
) | [static] |
void gAIPlayer::ConfigureAIs | ( | ) | [static] |
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 }
void gAIPlayer::ClearTarget | ( | ) | [inline] |
Definition at line 206 of file gAIBase.h.
Referenced by gAIPlayer(), and NewObject().
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_.
00208 { ePlayerNetID::ControlObject( c ); simpleAI_ = NULL; }
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().
00209 { ePlayerNetID::ClearObject(); simpleAI_ = NULL; }
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 }
bool gAIPlayer::Alive | ( | ) | [inline] |
Definition at line 214 of file gAIBase.h.
References gCycleMovement::Alive(), and Object().
Referenced by RightBeforeDeath(), and Think().
virtual bool gAIPlayer::IsHuman | ( | ) | const [inline, virtual] |
Reimplemented from ePlayerNetID.
Definition at line 218 of file gAIBase.h.
Referenced by gAITeam::BalanceWithAIs().
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 }
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 }
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 }
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 }
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 }
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 }
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] |
REAL gAIPlayer::lastPath [protected] |
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] |
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] |
REAL gAIPlayer::freeSide [protected] |
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] |
gAILog* gAIPlayer::log [protected] |
Definition at line 126 of file gAIBase.h.
Referenced by EmergencySurvive(), gAIPlayer(), NewObject(), RightBeforeDeath(), Think(), and ~gAIPlayer().