void CAirCAI::BuggerOff(float3 pos, float radius) { AAirMoveType* myPlane = dynamic_cast<AAirMoveType*>(owner->moveType); if(myPlane) { myPlane->Takeoff(); } else { CMobileCAI::BuggerOff(pos, radius); } }
void CUnitScript::SetUnitVal(int val, int param) { // may happen in case one uses Spring.SetUnitCOBValue (Lua) on a unit with CNullUnitScript if (!unit) { ShowScriptError("Error: no unit (in SetUnitVal)"); return; } #ifndef _CONSOLE switch (val) { case ACTIVATION: { if(unit->unitDef->onoffable) { Command c(CMD_ONOFF, 0, (param == 0) ? 0 : 1); unit->commandAI->GiveCommand(c); } else { if(param == 0) { unit->Deactivate(); } else { unit->Activate(); } } break; } case STANDINGMOVEORDERS: { if (param >= 0 && param <= 2) { Command c(CMD_MOVE_STATE, 0, param); unit->commandAI->GiveCommand(c); } break; } case STANDINGFIREORDERS: { if (param >= 0 && param <= 2) { Command c(CMD_FIRE_STATE, 0, param); unit->commandAI->GiveCommand(c); } break; } case HEALTH: { break; } case INBUILDSTANCE: { unit->inBuildStance = (param != 0); break; } case BUSY: { busy = (param != 0); break; } case PIECE_XZ: { break; } case PIECE_Y: { break; } case UNIT_XZ: { break; } case UNIT_Y: { break; } case UNIT_HEIGHT: { break; } case XZ_ATAN: { break; } case XZ_HYPOT: { break; } case ATAN: { break; } case HYPOT: { break; } case GROUND_HEIGHT: { break; } case GROUND_WATER_HEIGHT: { break; } case BUILD_PERCENT_LEFT: { break; } case YARD_OPEN: { if (unit->blockMap != NULL) { // note: if this unit is a factory, engine-controlled // OpenYard() and CloseYard() calls can interfere with // the yardOpen state (they probably should be removed // at some point) if (param == 0) { if (groundBlockingObjectMap->CanCloseYard(unit)) { groundBlockingObjectMap->CloseBlockingYard(unit); yardOpen = false; } } else { if (groundBlockingObjectMap->CanOpenYard(unit)) { groundBlockingObjectMap->OpenBlockingYard(unit); yardOpen = true; } } } break; } case BUGGER_OFF: { if (param != 0) { helper->BuggerOff(unit->pos + unit->frontdir * unit->radius, unit->radius * 1.5f, true, false, unit->team, NULL); } break; } case ARMORED: { if (param) { unit->curArmorMultiple = unit->armoredMultiple; } else { unit->curArmorMultiple = 1; } unit->armoredState = (param != 0); break; } case VETERAN_LEVEL: { unit->experience = param * 0.01f; break; } case MAX_SPEED: { // interpret negative values as non-persistent changes unit->commandAI->SetScriptMaxSpeed(std::max(param, -param) / float(COBSCALE), (param >= 0)); break; } case CLOAKED: { unit->wantCloak = !!param; break; } case WANT_CLOAK: { unit->wantCloak = !!param; break; } case UPRIGHT: { unit->upright = !!param; break; } case HEADING: { unit->heading = param % COBSCALE; unit->UpdateDirVectors(!unit->upright && unit->moveType->GetMaxSpeed() > 0.0f); unit->UpdateMidAndAimPos(); } break; case LOS_RADIUS: { unit->ChangeLos(param, unit->realAirLosRadius); unit->realLosRadius = param; break; } case AIR_LOS_RADIUS: { unit->ChangeLos(unit->realLosRadius, param); unit->realAirLosRadius = param; break; } case RADAR_RADIUS: { unit->ChangeSensorRadius(&unit->radarRadius, param); break; } case JAMMER_RADIUS: { unit->ChangeSensorRadius(&unit->jammerRadius, param); break; } case SONAR_RADIUS: { unit->ChangeSensorRadius(&unit->sonarRadius, param); break; } case SONAR_JAM_RADIUS: { unit->ChangeSensorRadius(&unit->sonarJamRadius, param); break; } case SEISMIC_RADIUS: { unit->ChangeSensorRadius(&unit->seismicRadius, param); break; } case CURRENT_FUEL: { unit->currentFuel = param / (float) COBSCALE; break; } case SHIELD_POWER: { if (unit->shieldWeapon != NULL) { CPlasmaRepulser* shield = (CPlasmaRepulser*)unit->shieldWeapon; shield->curPower = std::max(0.0f, float(param) / float(COBSCALE)); } break; } case STEALTH: { unit->stealth = !!param; break; } case SONAR_STEALTH: { unit->sonarStealth = !!param; break; } case CRASHING: { AAirMoveType* amt = dynamic_cast<AAirMoveType*>(unit->moveType); if (amt != NULL) { if (!!param) { amt->SetState(AAirMoveType::AIRCRAFT_CRASHING); } else { amt->SetState(AAirMoveType::AIRCRAFT_FLYING); } } break; } case CHANGE_TARGET: { if (param < 0) { return; } if (param >= unit->weapons.size()) { return; } unit->weapons[param]->avoidTarget = true; break; } case ALPHA_THRESHOLD: { unit->alphaThreshold = param / 255.0f; break; } case CEG_DAMAGE: { unit->cegDamage = param; break; } case FLANK_B_MODE: unit->flankingBonusMode = param; break; case FLANK_B_MOBILITY_ADD: unit->flankingBonusMobilityAdd = (param / (float)COBSCALE); break; case FLANK_B_MAX_DAMAGE: { float mindamage = unit->flankingBonusAvgDamage - unit->flankingBonusDifDamage; unit->flankingBonusAvgDamage = (param / (float)COBSCALE + mindamage)*0.5f; unit->flankingBonusDifDamage = (param / (float)COBSCALE - mindamage)*0.5f; break; } case FLANK_B_MIN_DAMAGE: { float maxdamage = unit->flankingBonusAvgDamage + unit->flankingBonusDifDamage; unit->flankingBonusAvgDamage = (maxdamage + param / (float)COBSCALE)*0.5f; unit->flankingBonusDifDamage = (maxdamage - param / (float)COBSCALE)*0.5f; break; } default: { if ((val >= GLOBAL_VAR_START) && (val <= GLOBAL_VAR_END)) { globalVars[val - GLOBAL_VAR_START] = param; } else if ((val >= TEAM_VAR_START) && (val <= TEAM_VAR_END)) { teamVars[unit->team][val - TEAM_VAR_START] = param; } else if ((val >= ALLY_VAR_START) && (val <= ALLY_VAR_END)) { allyVars[unit->allyteam][val - ALLY_VAR_START] = param; } else if ((val >= UNIT_VAR_START) && (val <= UNIT_VAR_END)) { unitVars[val - UNIT_VAR_START] = param; } else { LOG_L(L_ERROR, "CobError: Unknown set constant %d", val); } } } #endif }
void CMobileCAI::GiveCommandReal(const Command &c, bool fromSynced) { if (!AllowedCommand(c, fromSynced)) return; if (owner->unitDef->canfly && c.id == CMD_AUTOREPAIRLEVEL) { if (c.params.empty()) { return; } AAirMoveType* airMT = GetAirMoveType<AAirMoveType>(owner); if (!airMT) return; switch ((int) c.params[0]) { case 0: { airMT->repairBelowHealth = 0.0f; break; } case 1: { airMT->repairBelowHealth = 0.3f; break; } case 2: { airMT->repairBelowHealth = 0.5f; break; } case 3: { airMT->repairBelowHealth = 0.8f; break; } } for (vector<CommandDescription>::iterator cdi = possibleCommands.begin(); cdi != possibleCommands.end(); ++cdi) { if (cdi->id == CMD_AUTOREPAIRLEVEL) { char t[10]; SNPRINTF(t, 10, "%d", (int) c.params[0]); cdi->params[0] = t; break; } } selectedUnits.PossibleCommandChange(owner); return; } if (owner->unitDef->canfly && c.id == CMD_IDLEMODE) { if (c.params.empty()) { return; } AAirMoveType* airMT = GetAirMoveType<AAirMoveType>(owner); if (!airMT) return; switch ((int) c.params[0]) { case 0: { airMT->autoLand = false; airMT->Takeoff(); break; } case 1: { airMT->autoLand = true; break; } } for (vector<CommandDescription>::iterator cdi = possibleCommands.begin(); cdi != possibleCommands.end(); ++cdi) { if (cdi->id == CMD_IDLEMODE) { char t[10]; SNPRINTF(t, 10, "%d", (int) c.params[0]); cdi->params[0] = t; break; } } selectedUnits.PossibleCommandChange(owner); return; } if (!(c.options & SHIFT_KEY) && nonQueingCommands.find(c.id) == nonQueingCommands.end()) { tempOrder = false; StopSlowGuard(); } CCommandAI::GiveAllowedCommand(c); }
void CAirCAI::ExecuteFight(Command &c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); AAirMoveType* myPlane = (AAirMoveType*) owner->moveType; if(tempOrder){ tempOrder=false; inCommand=true; } if(c.params.size()<3){ //this shouldnt happen but anyway ... logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI", owner->unitDef->humanName.c_str()); return; } if(c.params.size() >= 6){ if(!inCommand){ commandPos1 = float3(c.params[3],c.params[4],c.params[5]); } } else { // Some hackery to make sure the line (commandPos1,commandPos2) is NOT // rotated (only shortened) if we reach this because the previous return // fight command finished by the 'if((curPos-pos).SqLength2D()<(127*127)){' // condition, but is actually updated correctly if you click somewhere // outside the area close to the line (for a new command). commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); if ((owner->pos - commandPos1).SqLength2D() > (150 * 150)) { commandPos1 = owner->pos; } } goalPos = float3(c.params[0], c.params[1], c.params[2]); if(!inCommand){ inCommand = true; commandPos2=goalPos; } if(c.params.size() >= 6){ goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } // CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway... if (owner->unitDef->canAttack && owner->fireState >= 2 && owner->moveState != 0 && owner->maxRange > 0) { float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed*10); float testRad = 1000 * owner->moveState; CUnit* enemy = NULL; if(myPlane->IsFighter()) { enemy = helper->GetClosestEnemyAircraft(curPosOnLine, testRad, owner->allyteam); } if(IsValidTarget(enemy) && (owner->moveState!=1 || LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000)) { Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options|INTERNAL_ORDER; commandQue.push_front(nc); tempOrder=true; inCommand=false; if(lastPC1!=gs->frameNum){ //avoid infinite loops lastPC1=gs->frameNum; SlowUpdate(); } return; } else { float3 curPosOnLine = ClosestPointOnLine( commandPos1, commandPos2, owner->pos + owner->speed * 20); float testRad = 500 * owner->moveState; enemy = helper->GetClosestEnemyUnit(curPosOnLine, testRad, owner->allyteam); if(IsValidTarget(enemy)) { Command nc; nc.id = CMD_ATTACK; nc.params.push_back(enemy->id); nc.options = c.options | INTERNAL_ORDER; PushOrUpdateReturnFight(); commandQue.push_front(nc); tempOrder = true; inCommand = false; if(lastPC2 != gs->frameNum){ //avoid infinite loops lastPC2 = gs->frameNum; SlowUpdate(); } return; } } } myPlane->goalPos = goalPos; if((owner->pos - goalPos).SqLength2D() < (127 * 127) || (owner->pos + owner->speed*8 - goalPos).SqLength2D() < (127 * 127)) { FinishCommand(); } return; }
void CAirCAI::SlowUpdate() { // Commands issued may invoke SlowUpdate when paused if (gs->paused) return; if (!commandQue.empty() && (commandQue.front().timeOut < gs->frameNum)) { FinishCommand(); return; } // avoid the invalid (CStrafeAirMoveType*) cast if (owner->UsingScriptMoveType()) return; const bool wantToRefuel = (LandRepairIfNeeded() || RefuelIfNeeded()); #if (AUTO_GENERATE_ATTACK_ORDERS == 1) if (commandQue.empty()) { if (!AirAutoGenerateTarget(GetStrafeAirMoveType(owner))) { // if no target found, queue is still empty so bail now return; } } #endif // FIXME: check owner->UsingScriptMoveType() and skip rest if true? AAirMoveType* myPlane = GetStrafeAirMoveType(owner); Command& c = commandQue.front(); if (c.GetID() == CMD_WAIT) { if ((myPlane->aircraftState == AAirMoveType::AIRCRAFT_FLYING) && !owner->unitDef->DontLand() && myPlane->autoLand) { StopMove(); } return; } if (c.GetID() != CMD_STOP && c.GetID() != CMD_AUTOREPAIRLEVEL && c.GetID() != CMD_IDLEMODE && c.GetID() != CMD_SET_WANTED_MAX_SPEED) { myPlane->Takeoff(); } if (wantToRefuel) { switch (c.GetID()) { case CMD_AREA_ATTACK: case CMD_ATTACK: case CMD_FIGHT: return; } } switch (c.GetID()) { case CMD_AREA_ATTACK: { ExecuteAreaAttack(c); return; } default: { CMobileCAI::Execute(); return; } } }