/** ** Unit stands still or stand ground. ** ** @param unit Unit pointer for action. ** @param stand_ground true if unit is standing ground. */ void ActionStillGeneric(CUnit *unit, bool stand_ground) { // If unit is not bunkered and removed, wait if (unit->Removed && (!unit->Container || !unit->Container->Type->CanTransport || !unit->Container->Type->AttackFromTransporter || unit->Type->Missile.Missile->Class == MissileClassNone)) { // If unit is in building or transporter it is removed. return; } // Animations if (unit->SubAction) { // attacking unit in attack range. AnimateActionAttack(unit); } else { UnitShowAnimation(unit, unit->Type->Animations->Still); } if (unit->Anim.Unbreakable) { // animation can't be aborted here return; } if (AutoCast(unit) || AutoRepair(unit)) { return; } AutoAttack(unit, stand_ground); }
/** ** Handle AI of all players each game cycle. */ void PlayersEachCycle() { for (int player = 0; player < NumPlayers; ++player) { CPlayer *p = &Players[player]; if (p->AutoAttackTargets.size() > 0) { CUnitCache &autoatacktargets = p->AutoAttackTargets; /* both loops can not be connected !!!! */ for (unsigned int i = 0; i < autoatacktargets.size();) { CUnit *aatarget = autoatacktargets[i]; if (!aatarget->IsAliveOnMap() || Map.Field(aatarget->Offset)->Guard[player] == 0) { autoatacktargets.Units.erase(autoatacktargets.Units.begin() + i); aatarget->RefsDecrease(); continue; } ++i; } if (autoatacktargets.size() > 0) { for (int j = 0; j < p->TotalNumUnits; ++j) { CUnit &guard = *p->Units[j]; bool stand_ground = guard.CurrentAction() == UnitActionStandGround; if (guard.Type->CanAttack && (stand_ground || guard.IsIdle()) && !guard.IsUnusable()) { AutoAttack(guard, autoatacktargets, stand_ground); } } } } if (p->AiEnabled) { AiEachCycle(p); } } }
/* virtual */ void COrder_Still::Execute(CUnit &unit) { // If unit is not bunkered and removed, wait if (unit.Removed //Wyrmgus start // && (unit.Container == nullptr || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { && (unit.Container == nullptr || !unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value || !unit.Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value)) { // make both the unit and the transporter have the tag be necessary for the attack to be possible if (unit.Container != nullptr) { LeaveShelter(unit); // leave shelter if surrounded } //Wyrmgus end return ; } this->Finished = false; switch (this->State) { case SUB_STILL_STANDBY: //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); if (unit.Variable[STUN_INDEX].Value == 0) { //only show the idle animation when still if the unit is not stunned UnitShowAnimation(unit, unit.GetAnimations()->Still); } if (SyncRand(100000) == 0) { PlayUnitSound(unit, VoiceIdle); } unit.StepCount = 0; //Wyrmgus end break; case SUB_STILL_ATTACK: // attacking unit in attack range. AnimateActionAttack(unit, *this); break; } if (unit.Anim.Unbreakable) { // animation can't be aborted here return; } //Wyrmgus start if (unit.Variable[STUN_INDEX].Value > 0) { //if unit is stunned, remain still return; } //Wyrmgus end this->State = SUB_STILL_STANDBY; this->Finished = (this->Action == UnitActionStill); if (this->Action == UnitActionStandGround || unit.Removed || unit.CanMove() == false) { if (unit.AutoCastSpell) { this->AutoCastStand(unit); } if (unit.IsAgressive()) { this->AutoAttackStand(unit); } } else { if (AutoCast(unit) || (unit.IsAgressive() && AutoAttack(unit)) || AutoRepair(unit) //Wyrmgus start // || MoveRandomly(unit)) { || MoveRandomly(unit) || PickUpItem(unit)) { //Wyrmgus end } } }
/* virtual */ void COrder_Still::Execute(CUnit &unit) { // If unit is not bunkered and removed, wait if (unit.Removed && (unit.Container == NULL || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { return ; } this->Finished = false; switch (this->State) { case SUB_STILL_STANDBY: UnitShowAnimation(unit, unit.Type->Animations->Still); break; case SUB_STILL_ATTACK: // attacking unit in attack range. AnimateActionAttack(unit, *this); break; } if (unit.Anim.Unbreakable) { // animation can't be aborted here return; } this->State = SUB_STILL_STANDBY; this->Finished = (this->Action == UnitActionStill); if (this->Action == UnitActionStandGround || unit.Removed || unit.CanMove() == false) { if (unit.AutoCastSpell) { this->AutoCastStand(unit); } if (unit.IsAgressive()) { this->AutoAttackStand(unit); } } else { if (AutoCast(unit) || (unit.IsAgressive() && AutoAttack(unit)) || AutoRepair(unit) || MoveRandomly(unit)) { } } }
/* virtual */ void COrder_Defend::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); UnitShowAnimation(unit, unit.GetAnimations()->Still); //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } CUnit *goal = this->GetGoal(); if (this->State == State_Init) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } this->State = State_MovingToTarget; } else if (this->State == State_Defending) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } } if (!unit.Anim.Unbreakable) { if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) { return; } } switch (DoActionMove(unit)) { case PF_UNREACHABLE: //Wyrmgus start //if is unreachable and is on a raft, see if the raft can move closer to the enemy if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) { std::vector<CUnit *> table; Select(unit.tilePos, unit.tilePos, table); for (size_t i = 0; i != table.size(); ++i) { if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) { if (table[i]->CurrentAction() == UnitActionStill) { CommandStopUnit(*table[i]); CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands); } return; } } } //Wyrmgus end // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died this->Finished = true; return; } // Now defend the goal this->goalPos = goal->tilePos; this->State = State_Defending; } default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); this->ClearGoal(); goal = NULL; if (this->State == State_Defending) { this->Finished = true; return; } } }
/* virtual */ void COrder_Defend::Execute(CUnit &unit) { if (unit.Wait) { if (!unit.Waiting) { unit.Waiting = 1; unit.WaitBackup = unit.Anim; } //Wyrmgus start // UnitShowAnimation(unit, unit.Type->Animations->Still); VariationInfo *varinfo = unit.Type->VarInfo[unit.Variation]; if (varinfo && varinfo->Animations && varinfo->Animations->Still) { UnitShowAnimation(unit, varinfo->Animations->Still); } else { UnitShowAnimation(unit, unit.Type->Animations->Still); } //Wyrmgus end unit.Wait--; return; } if (unit.Waiting) { unit.Anim = unit.WaitBackup; unit.Waiting = 0; } CUnit *goal = this->GetGoal(); if (this->State == State_Init) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } this->State = State_MovingToTarget; } else if (this->State == State_Defending) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { this->Finished = true; return; } } if (!unit.Anim.Unbreakable) { if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) { return; } } switch (DoActionMove(unit)) { case PF_UNREACHABLE: // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died this->Finished = true; return; } // Now defend the goal this->goalPos = goal->tilePos; this->State = State_Defending; } default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); this->ClearGoal(); goal = NULL; if (this->State == State_Defending) { this->Finished = true; return; } } }