void cCombatManager::UnitIdle(const int& unit, UnitInfo *U) { //*l<<"(cui) -eID="<<U->enemyID; if( ValidateEnemy(unit,U) && CanAttack(U,U->E,GetEnemyPosition(U->enemyID,U->E)) == 0 ) U->enemyID=-1; float3 fPos=cb->GetUnitPos(unit); if( U->enemyID == -1 ) while( (U->enemyID=GetClosestEnemy(fPos,U)) > 0 && !ValidateEnemy(unit,U) ) {} float distance = -1; if( U->enemyID >= 0 ) { distance = fPos.distance(GetEnemyPosition(U->enemyID,U->E)); if( distance == 0 ) distance = 1; } if( U->enemyID == -1 || (U->udrBL->task != TASK_ASSAULT && distance > 2.5*8*U->ud->losRadius) ) { U->inCombat=false; G->UpdateEventAdd(1,0,unit,U); return; } else if( CommandDGun(unit,U) ) return; else if( U->enemyEff == 0 || (U->udrBL->task != TASK_ASSAULT && distance > 1.75*U->enemyEff->BestRange ) || (U->ud->isCommander && cb->GetUnitHealth(unit)/U->ud->health <= 0.66 ) ) // || G->Enemies.find(U->enemyID)->second.ud->kamikazeDist > distance { float3 EPos = GetEnemyPosition(U->enemyID,U->E); CommandRun(unit,U,EPos); return; } else if( CommandCapture(unit,U,distance) || CommandManeuver(unit,U,distance) ) return; else { float3 EPos = GetEnemyPosition(U->enemyID,U->E); Command c; if( U->ud->canAttack && (U->E->inLOS || U->E->inRadar) ) { c.id = CMD_ATTACK; c.params.push_back(U->enemyID); } else if( U->ud->canAttack && (U->udr->IsBomber && U->E->posLocked) ) { c.id = CMD_ATTACK; c.params.push_back(EPos.x); c.params.push_back(EPos.y); c.params.push_back(EPos.z); } else // cant see enemy or Mod Workaround: Combat Lords - cant be given attack orders { c.id = CMD_MOVE; c.params.push_back(EPos.x -100.0 +rand()%201 ); c.params.push_back(EPos.y); c.params.push_back(EPos.z -100.0 +rand()%201 ); } cb->GiveOrder(unit, &c); G->UpdateEventAdd(1,int(GetNextUpdate(distance,U)),unit,U); } }
void cCombatManager::UnitDamaged(const int& unitID, UnitInfo* U, const int& attackerID, EnemyInfo* A, float3& dir) { ValidateEnemy(unitID,U,false); if( attackerID >= 0 && attackerID != U->enemyID ) { float3 Pos = cb->GetUnitPos(unitID); float3 APos = GetEnemyPosition(attackerID,A); if( U->enemyID == -1 || Pos.distance(APos) < Pos.distance(GetEnemyPosition(U->enemyID,U->E)) ) if( CanAttack(U, A, APos) != 0 && (U->group == 0 || U->group->Enemies.find(attackerID) != U->group->Enemies.end()) ) { U->enemyID=attackerID; U->E = A; U->enemyEff = CanAttack(U, A, APos); } } if( U->inCombat ) { if( U->ud->isCommander ) { if( int(cb->GetCurrentUnitCommands(unitID)->size()) == 0 ) UnitIdle(unitID,U); else if( cb->GetCurrentUnitCommands(unitID)->front().id != CMD_MOVE ) { if( cb->GetUnitHealth(unitID)/U->ud->health <= 0.66 || (cb->GetUnitHealth(unitID)/U->ud->health <= 0.9 && cb->GetCurrentUnitCommands(unitID)->front().id == CMD_CAPTURE) ) UnitIdle(unitID,U); } } return; } if( U->BuildQ != 0 && U->BuildQ->RS != 0 ) U->BuildQ->tryCount = 4; // If the project is destroyed too many times, give up on it U->inCombat=true; if( U->enemyID == -1 ) { if( attackerID >= 0 ) { float3 APos = GetEnemyPosition(attackerID,A); CommandRun(unitID,U,APos); } else { float3 EPos = cb->GetUnitPos(unitID); EPos.x += dir.x*700; EPos.z += dir.z*700; EPos.y = cb->GetElevation(EPos.x,EPos.z); CommandRun(unitID,U,EPos); } } else UnitIdle(unitID,U); }
int cCombatManager::GetClosestEnemy(float3 Pos, UnitInfo* U) { U->enemyID=-1; // these two function need improvement, for now I'll just use a short cut if( !G->UM->ActiveAttackOrders() && U->udrBL->task != TASK_SUICIDE ) return GetClosestThreat(Pos, U); sWeaponEfficiency* weTemp; float distance,fTemp; float3 fE; for( map<int,EnemyInfo>::iterator E=G->Enemies.begin(); E!=G->Enemies.end(); E++ ) { fE=GetEnemyPosition(E->first,&E->second); if( (weTemp = CanAttack(U,&E->second,fE)) != 0 ) { fTemp=Pos.distance(fE); if( U->enemyID == -1 || fTemp < distance ) { U->enemyID=E->first; U->E = &E->second; U->enemyEff = weTemp; distance=fTemp; } } } if( U->enemyID != -1 && U->group != 0 ) G->UM->GroupAddEnemy(U->enemyID,U->E,U->group); return U->enemyID; }
bool cCombatManager::CommandDGun(const int& unitID, UnitInfo *U) { if( U->udr->DGun == 0 || cb->GetEnergy() < U->udr->DGun->energycost ) return false; float3 EPos = GetEnemyPosition(U->enemyID,U->E); float EDis = EPos.distance(cb->GetUnitPos(unitID)); if( EDis > 1.05*U->udr->DGun->range ) return false; if( U->ud->isCommander ) { if( U->E->ud != 0 && U->E->ud->isCommander ) { CommandRun(unitID,U,EPos); return true; } } Command c; c.id=CMD_DGUN; c.params.push_back(EPos.x); c.params.push_back(EPos.y); c.params.push_back(EPos.z); cb->GiveOrder(unitID, &c); G->UpdateEventAdd(1,cb->GetCurrentFrame()+5,unitID,U); return true; }
/* bool cCombatManager::CommandTrap(const int& unitID, UnitInfo* U, const float& EDis) { if( !U->E->inLOS || U->ud->transportMass < U->E->ud->mass ) return false; if( U->ud->transportCapacity == 0 ) return false; Command c; c.id = CMD_LOAD_UNITS; c.params.push_back(U->enemyID); cb->GiveOrder(unitID, &c); return true; } */ bool cCombatManager::CommandManeuver(const int& unitID, UnitInfo *U, const float& EDis) { if( U->ud->canfly || U->E->ud == 0 || !U->E->inLOS || U->enemyEff->BestRange <= 1.15*cb->GetUnitMaxRange(U->enemyID) || EDis > 3500.0 || int(G->UMobile.size()) > 60 ) return false; float3 Pos=cb->GetUnitPos(unitID); float3 EPos=GetEnemyPosition(U->enemyID,U->E); if( U->ud->minWaterDepth < 0 && Pos.y <= 0 && U->udr->WeaponSeaEff.BestRange == 0 ) { int iS=G->TM->GetSectorIndex(EPos); if( G->TM->IsSectorValid(iS) ) { Pos = G->TM->GetClosestSector(G->TM->landSectorType,iS)->position; Pos.x+=128-rand()%256; Pos.z+=128-rand()%256; G->CorrectPosition(Pos); Command c; c.id = CMD_MOVE; c.params.push_back(Pos.x); c.params.push_back(Pos.y); c.params.push_back(Pos.z); cb->GiveOrder(unitID, &c); G->UpdateEventAdd(1,int(GetNextUpdate(EDis,U)),unitID,U); return true; } } if( EDis < 0.70*U->enemyEff->BestRange || EDis > U->enemyEff->BestRange ) { float distanceAway=(0.87*U->enemyEff->BestRange-EDis); Pos.x+=(Pos.x-EPos.x)*(distanceAway/EDis); Pos.z+=(Pos.z-EPos.z)*(distanceAway/EDis); G->CorrectPosition(Pos); if( !G->TM->CanMoveToPos(U->area,Pos) ) return false; Command c; c.id = CMD_MOVE; c.params.push_back(Pos.x); c.params.push_back(cb->GetElevation(Pos.x,Pos.z)); c.params.push_back(Pos.z); cb->GiveOrder(unitID, &c); G->UpdateEventAdd(1,int(GetNextUpdate(EDis,U)),unitID,U); return true; } return false; }
int cCombatManager::GetClosestThreat(float3 Pos, UnitInfo* U) { sWeaponEfficiency* weTemp; float distance,fTemp; distance=0.0f; float3 fE; set<int> deletion; for( map<int,EnemyInfo*>::iterator E=G->EThreat.begin(); E!=G->EThreat.end(); ++E ) { fE=GetEnemyPosition(E->first,E->second); if( E->second->baseThreatFrame > cb->GetCurrentFrame()+3600 || (E->second->baseThreatFrame > cb->GetCurrentFrame()+1200 && G->UImmobile.find(E->second->baseThreatID) == G->UImmobile.end() ) || (E->second->ud != 0 && G->UImmobile.find(E->second->baseThreatID) != G->UImmobile.end() && 1.3*E->second->ud->maxWeaponRange < fE.distance(cb->GetUnitPos(E->second->baseThreatID)) ) ) { E->second->baseThreatID = -1; E->second->baseThreatFrame = -1; deletion.insert(E->first); } else if( (weTemp = CanAttack(U,E->second,fE)) != 0 ) { fTemp=Pos.distance(fE); if( U->enemyID == -1 || fTemp < distance ) { U->enemyID=E->first; U->E = E->second; U->enemyEff = weTemp; distance=fTemp; } } } while( int(deletion.size()) > 0 ) { if( !G->UM->ActiveAttackOrders() ) { EnemyInfo* E = G->EThreat.find(*deletion.begin())->second; while( int(E->attackGroups.size()) > 0 ) G->UM->GroupRemoveEnemy(*deletion.begin(),E,*E->attackGroups.begin()); } G->EThreat.erase(*deletion.begin()); deletion.erase(*deletion.begin()); } if( U->enemyID != -1 && U->group != 0 ) G->UM->GroupAddEnemy(U->enemyID,U->E,U->group); return U->enemyID; }
void ParseSayText (edict_t * ent, char *text) { static unsigned char buf[10240], infobuf[10240]; char *p, *pbuf; p = text; pbuf = buf; *pbuf = 0; while (*p != 0) { if (((ptrdiff_t) pbuf - (ptrdiff_t) buf) > 225) { break; } if (*p == '%') { switch (*(p + 1)) { case 'H': GetHealth (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'A': GetAmmo (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'W': GetWeaponName (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'I': GetItemName (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'T': GetNearbyTeammates (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'M': GetViewedTeammateName (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'E': GetViewedEnemyName (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'F': GetViewedEnemyWeapon (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'G': GetEnemyPosition (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'K': GetLastKilledTarget (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; //AQ2:TNG Slicer - New Location Code /* case 'L': GetOwnPosition (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'S': GetViewedPosition (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; */ case 'S': GetSightedLocation (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; case 'L': GetPlayerLocation (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; //AQ2:TNG Slicer Last Damage Location case 'D': GetLastDamagedPart (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; //AQ2:TNG END //AQ2:TNG Freud Last Player Damaged case 'P': GetLastDamagedPlayers (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; continue; //AQ2:TNG END } } *pbuf++ = *p++; } *pbuf = 0; strncpy (text, buf, 225); text[225] = 0; // in case it's 225 }
void ParseSayText (edict_t * ent, char *text, size_t size) { char buf[PARSE_BUFSIZE + 256] = "\0"; //Parsebuf + chatpuf size char *p, *pbuf; p = text; pbuf = buf; while (*p != 0) { if (*p == '%') { switch (*(p + 1)) { case 'H': GetHealth (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'A': GetAmmo (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'W': GetWeaponName (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'I': GetItemName (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'T': GetNearbyTeammates (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'M': GetViewedTeammateName (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'E': GetViewedEnemyName (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'F': GetViewedEnemyWeapon (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'G': GetEnemyPosition (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'K': GetLastKilledTarget (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; //AQ2:TNG Slicer - New Location Code /* case 'L': GetOwnPosition (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'S': GetViewedPosition (ent, infobuf); strcpy (pbuf, infobuf); pbuf = SeekBufEnd (pbuf); p += 2; break; */ case 'S': GetSightedLocation (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; case 'L': GetPlayerLocation (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; //AQ2:TNG Slicer Last Damage Location case 'D': GetLastDamagedPart (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; //AQ2:TNG END //AQ2:TNG Freud Last Player Damaged case 'P': GetLastDamagedPlayers (ent, pbuf); pbuf = SeekBufEnd (pbuf); p += 2; break; //AQ2:TNG END default: *pbuf++ = *p++; break; } } else { *pbuf++ = *p++; } if (buf[size-1]) { buf[size-1] = 0; break; } } *pbuf = 0; strcpy(text, buf); }