bool CAICallback::GetProperty(int unitId, int property, void* data) { verify(); if (CHECK_UNITID(unitId)) { const CUnit* unit = unitHandler->GetUnit(unitId); const int allyTeam = teamHandler->AllyTeam(team); myAllyTeamId = allyTeam; // the unit does not exist or can not be seen if (unit == nullptr || !unit_IsInLos(unit)) return false; switch (property) { case AIVAL_UNITDEF: { if (teamHandler->Ally(unit->allyteam, allyTeam)) { (*(const UnitDef**)data) = unit->unitDef; } else { const UnitDef* unitDef = unit->unitDef; const UnitDef* decoyDef = unitDef->decoyDef; if (decoyDef == NULL) { (*(const UnitDef**)data) = unitDef; } else { (*(const UnitDef**)data) = decoyDef; } } return true; } case AIVAL_CURRENT_FUEL: { //Deprecated (*(float*)data) = 0; return true; } case AIVAL_STOCKPILED: { if (!unit->stockpileWeapon || !teamHandler->Ally(unit->allyteam, allyTeam)) { return false; } (*(int*)data) = unit->stockpileWeapon->numStockpiled; return true; } case AIVAL_STOCKPILE_QUED: { if (!unit->stockpileWeapon || !teamHandler->Ally(unit->allyteam, allyTeam)) { return false; } (*(int*)data) = unit->stockpileWeapon->numStockpileQued; return true; } case AIVAL_UNIT_MAXSPEED: { (*(float*) data) = unit->moveType->GetMaxSpeed(); return true; } default: return false; } } return false; }
/// You have to set myAllyTeamId before calling this function. NOT thread safe! static inline bool unit_IsNeutralAndInLos(const CUnit* unit) { return (unit_IsNeutral(unit) && unit_IsInLos(unit)); }
/// You have to set myAllyTeamId before calling this function. NOT thread safe! static inline bool unit_IsEnemyAndInLosOrRadar(const CUnit* unit) { return (unit_IsEnemy(unit) && (unit_IsInLos(unit) || unit_IsInRadar(unit))); }
/// You have to set myAllyTeamId before calling this function. NOT thread safe! static inline bool unit_IsEnemyAndInLos(const CUnit* unit) { return (unit_IsEnemy(unit) && unit_IsInLos(unit)); }
int CAICallback::HandleCommand(int commandId, void* data) { switch (commandId) { case AIHCQuerySubVersionId: { return 1; // current version of Handle Command interface } break; case AIHCAddMapPointId: { const AIHCAddMapPoint* cmdData = static_cast<AIHCAddMapPoint*>(data); net->Send(CBaseNetProtocol::Get().SendMapDrawPoint(team, (short)cmdData->pos.x, (short)cmdData->pos.z, std::string(cmdData->label), false)); return 1; } break; case AIHCAddMapLineId: { const AIHCAddMapLine* cmdData = static_cast<AIHCAddMapLine*>(data); net->Send(CBaseNetProtocol::Get().SendMapDrawLine(team, (short)cmdData->posfrom.x, (short)cmdData->posfrom.z, (short)cmdData->posto.x, (short)cmdData->posto.z, false)); return 1; } break; case AIHCRemoveMapPointId: { const AIHCRemoveMapPoint* cmdData = static_cast<AIHCRemoveMapPoint*>(data); net->Send(CBaseNetProtocol::Get().SendMapErase(team, (short)cmdData->pos.x, (short)cmdData->pos.z)); return 1; } break; case AIHCSendStartPosId: { const AIHCSendStartPos* cmdData = static_cast<AIHCSendStartPos*>(data); SendStartPos(cmdData->ready, cmdData->pos); return 1; } break; case AIHCGetUnitDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCGetWeaponDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCGetFeatureDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCTraceRayId: { AIHCTraceRay* cmdData = static_cast<AIHCTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->units[cmdData->srcUID]; if (srcUnit != NULL) { CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; //FIXME add COLLISION_NOFEATURE? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitUnit != NULL) { myAllyTeamId = teamHandler->AllyTeam(team); const bool isUnitVisible = unit_IsInLos(hitUnit); if (isUnitVisible) { cmdData->rayLen = realLen; cmdData->hitUID = hitUnit->id; } } } } return 1; } break; case AIHCFeatureTraceRayId: { AIHCFeatureTraceRay* cmdData = static_cast<AIHCFeatureTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->units[cmdData->srcUID]; if (srcUnit != NULL) { CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; //FIXME add COLLISION_NOENEMIES || COLLISION_NOFRIENDLIES || COLLISION_NONEUTRALS? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitFeature != NULL) { const bool isFeatureVisible = hitFeature->IsInLosForAllyTeam(teamHandler->AllyTeam(team)); if (isFeatureVisible) { cmdData->rayLen = realLen; cmdData->hitFID = hitFeature->id; } } } } return 1; } break; case AIHCPauseId: { AIHCPause* cmdData = static_cast<AIHCPause*>(data); net->Send(CBaseNetProtocol::Get().SendPause(gu->myPlayerNum, cmdData->enable)); LOG("Skirmish AI controlling team %i paused the game, reason: %s", team, cmdData->reason != NULL ? cmdData->reason : "UNSPECIFIED"); return 1; } break; case AIHCGetDataDirId: { // do nothing // this event will never end up here, as // it is handled in the C layer directly // see Clb_DataDirs_allocatePath in rts/ExternalAI/Interface/SSkirmishAICallback.h return 0; } break; case AIHCDebugDrawId: { AIHCDebugDraw* cmdData = static_cast<AIHCDebugDraw*>(data); switch (cmdData->cmdMode) { case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_GRAPH_POINT: { debugDrawerAI->AddGraphPoint(this->team, cmdData->lineId, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_GRAPH_POINTS: { debugDrawerAI->DelGraphPoints(this->team, cmdData->lineId, cmdData->numPoints); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_POS: { debugDrawerAI->SetGraphPos(this->team, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_SIZE: { debugDrawerAI->SetGraphSize(this->team, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_COLOR: { debugDrawerAI->SetGraphLineColor(this->team, cmdData->lineId, cmdData->color); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_LABEL: { debugDrawerAI->SetGraphLineLabel(this->team, cmdData->lineId, cmdData->label); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_OVERLAY_TEXTURE: { cmdData->texHandle = debugDrawerAI->AddOverlayTexture( this->team, cmdData->texData, int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_UPDATE_OVERLAY_TEXTURE: { debugDrawerAI->UpdateOverlayTexture( this->team, cmdData->texHandle, cmdData->texData, int(cmdData->x), // interpret as absolute pixel col int(cmdData->y), // interpret as absolute pixel row int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_OVERLAY_TEXTURE: { debugDrawerAI->DelOverlayTexture(this->team, cmdData->texHandle); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_POS: { debugDrawerAI->SetOverlayTexturePos(this->team, cmdData->texHandle, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_SIZE: { debugDrawerAI->SetOverlayTextureSize(this->team, cmdData->texHandle, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_LABEL: { debugDrawerAI->SetOverlayTextureLabel(this->team, cmdData->texHandle, cmdData->label); } break; default: { } break; } return 1; } break; default: { return 0; } } }
int CAICallback::HandleCommand(int commandId, void* data) { switch (commandId) { case AIHCQuerySubVersionId: { return 1; // current version of Handle Command interface } break; case AIHCAddMapPointId: { const AIHCAddMapPoint* cmdData = static_cast<AIHCAddMapPoint*>(data); /* TODO: gu->myPlayerNum makes the command to look like as it comes from the local player, "team" should be used (but needs some major changes in other engine parts) */ clientNet->Send(CBaseNetProtocol::Get().SendMapDrawPoint(gu->myPlayerNum, (short)cmdData->pos.x, (short)cmdData->pos.z, std::string(cmdData->label), false)); return 1; } break; case AIHCAddMapLineId: { const AIHCAddMapLine* cmdData = static_cast<AIHCAddMapLine*>(data); // see TODO above clientNet->Send(CBaseNetProtocol::Get().SendMapDrawLine(gu->myPlayerNum, (short)cmdData->posfrom.x, (short)cmdData->posfrom.z, (short)cmdData->posto.x, (short)cmdData->posto.z, false)); return 1; } break; case AIHCRemoveMapPointId: { const AIHCRemoveMapPoint* cmdData = static_cast<AIHCRemoveMapPoint*>(data); // see TODO above clientNet->Send(CBaseNetProtocol::Get().SendMapErase(gu->myPlayerNum, (short)cmdData->pos.x, (short)cmdData->pos.z)); return 1; } break; case AIHCSendStartPosId: case AIHCGetUnitDefByIdId: case AIHCGetWeaponDefByIdId: case AIHCGetFeatureDefByIdId: case AIHCGetDataDirId: { // NOTE: these commands should never arrive, handled in SSkirmishAICallbackImpl assert(false); return 0; } break; case AIHCTraceRayId: { AIHCTraceRay* cmdData = static_cast<AIHCTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->GetUnit(cmdData->srcUID); if (srcUnit != nullptr) { CUnit* hitUnit = nullptr; CFeature* hitFeature = nullptr; //FIXME add COLLISION_NOFEATURE? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitUnit != nullptr) { myAllyTeamId = teamHandler->AllyTeam(team); if (unit_IsInLos(hitUnit)) { cmdData->rayLen = realLen; cmdData->hitUID = hitUnit->id; } } } } return 1; } break; case AIHCFeatureTraceRayId: { AIHCFeatureTraceRay* cmdData = static_cast<AIHCFeatureTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->GetUnit(cmdData->srcUID); if (srcUnit != nullptr) { CUnit* hitUnit = nullptr; CFeature* hitFeature = nullptr; //FIXME add COLLISION_NOENEMIES || COLLISION_NOFRIENDLIES || COLLISION_NONEUTRALS? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitFeature != nullptr) { if (hitFeature->IsInLosForAllyTeam(teamHandler->AllyTeam(team))) { cmdData->rayLen = realLen; cmdData->hitFID = hitFeature->id; } } } } return 1; } break; case AIHCPauseId: { AIHCPause* cmdData = static_cast<AIHCPause*>(data); clientNet->Send(CBaseNetProtocol::Get().SendPause(gu->myPlayerNum, cmdData->enable)); LOG("Skirmish AI controlling team %i paused the game, reason: %s", team, cmdData->reason != NULL ? cmdData->reason : "UNSPECIFIED"); return 1; } break; case AIHCDebugDrawId: { AIHCDebugDraw* cmdData = static_cast<AIHCDebugDraw*>(data); switch (cmdData->cmdMode) { case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_GRAPH_POINT: { debugDrawerAI->AddGraphPoint(this->team, cmdData->lineId, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_GRAPH_POINTS: { debugDrawerAI->DelGraphPoints(this->team, cmdData->lineId, cmdData->numPoints); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_POS: { debugDrawerAI->SetGraphPos(this->team, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_SIZE: { debugDrawerAI->SetGraphSize(this->team, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_COLOR: { debugDrawerAI->SetGraphLineColor(this->team, cmdData->lineId, cmdData->color); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_LABEL: { debugDrawerAI->SetGraphLineLabel(this->team, cmdData->lineId, cmdData->label); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_OVERLAY_TEXTURE: { cmdData->texHandle = debugDrawerAI->AddOverlayTexture( this->team, cmdData->texData, int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_UPDATE_OVERLAY_TEXTURE: { debugDrawerAI->UpdateOverlayTexture( this->team, cmdData->texHandle, cmdData->texData, int(cmdData->x), // interpret as absolute pixel col int(cmdData->y), // interpret as absolute pixel row int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_OVERLAY_TEXTURE: { debugDrawerAI->DelOverlayTexture(this->team, cmdData->texHandle); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_POS: { debugDrawerAI->SetOverlayTexturePos(this->team, cmdData->texHandle, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_SIZE: { debugDrawerAI->SetOverlayTextureSize(this->team, cmdData->texHandle, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_LABEL: { debugDrawerAI->SetOverlayTextureLabel(this->team, cmdData->texHandle, cmdData->label); } break; default: { } break; } return 1; } break; default: { return 0; } } }