static bool IsReadyToRepair(const CUnit &unit) { if (unit.IsIdle()) { return true; } else if (unit.Orders.size() == 1 && unit.CurrentAction() == UnitActionResource) { COrder_Resource &order = *static_cast<COrder_Resource *>(unit.CurrentOrder()); if (order.IsGatheringStarted() == false) { return true; } } return false; }
/** ** Check if we can upgrade to unit-type. ** ** @param type Unit that can upgrade to unit-type ** @param what To what should be upgraded. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static int AiUpgradeTo(const CUnitType &type, CUnitType &what) { CUnit *table[UnitMax]; int num = 0; // Remove all units already doing something. const int nunits = FindPlayerUnitsByType(AiPlayer->Player, type, table); for (int i = 0; i < nunits; ++i) { CUnit *unit = table[i]; if (unit->IsIdle()) { table[num++] = unit; } } for (int i = 0; i < num; ++i) { CUnit &unit = *table[i]; CommandUpgradeTo(unit, what, FlushCommands); return 1; } return 0; }
/* virtual */ void COrder_Follow::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(); // Reached target if (this->State == State_TargetReached) { if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->Finished = true; return ; } // Don't follow after immobile units if (goal && goal->CanMove() == false) { this->Finished = true; return; } //Wyrmgus start // if (goal->tilePos == this->goalPos) { if (goal->tilePos == this->goalPos && goal->MapLayer == this->MapLayer) { //Wyrmgus end // Move to the next order if (unit.Orders.size() > 1) { this->Finished = true; return ; } unit.Wait = 10; if (this->Range > 1) { this->Range = 1; this->State = State_Init; } return ; } this->State = State_Init; } if (this->State == State_Init) { // first entry this->State = State_Initialized; } switch (DoActionMove(unit)) { // reached end-point? case PF_UNREACHABLE: //Wyrmgus start if ((Map.Field(unit.tilePos, unit.MapLayer)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) { std::vector<CUnit *> table; Select(unit.tilePos, unit.tilePos, table, unit.MapLayer); 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, this->HasGoal() ? this->GetGoal()->MapLayer : this->MapLayer); } return; } } } //Wyrmgus end // Some tries to reach the goal this->Range++; break; case PF_REACHED: { if (!goal) { // goal has died this->Finished = true; return ; } // Handle Teleporter Units // FIXME: BAD HACK // goal shouldn't be busy and portal should be alive if (goal->Type->BoolFlag[TELEPORTER_INDEX].value && goal->Goal && goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) { if (!goal->IsIdle()) { // wait unit.Wait = 10; return; } // Check if we have enough mana if (goal->Goal->Type->TeleportCost > goal->Variable[MANA_INDEX].Value) { this->Finished = true; return; } else { goal->Variable[MANA_INDEX].Value -= goal->Goal->Type->TeleportCost; } // Everything is OK, now teleport the unit unit.Remove(NULL); if (goal->Type->TeleportEffectIn) { goal->Type->TeleportEffectIn->pushPreamble(); goal->Type->TeleportEffectIn->pushInteger(UnitNumber(unit)); goal->Type->TeleportEffectIn->pushInteger(UnitNumber(*goal)); goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().x); goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().y); goal->Type->TeleportEffectIn->run(); } unit.tilePos = goal->Goal->tilePos; //Wyrmgus start unit.MapLayer = goal->Goal->MapLayer; //Wyrmgus end DropOutOnSide(unit, unit.Direction, NULL); // FIXME: we must check if the units supports the new order. CUnit &dest = *goal->Goal; if (dest.Type->TeleportEffectOut) { dest.Type->TeleportEffectOut->pushPreamble(); dest.Type->TeleportEffectOut->pushInteger(UnitNumber(unit)); dest.Type->TeleportEffectOut->pushInteger(UnitNumber(dest)); dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().x); dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().y); dest.Type->TeleportEffectOut->run(); } if (dest.NewOrder == NULL || (dest.NewOrder->Action == UnitActionResource && !unit.Type->BoolFlag[HARVESTER_INDEX].value) //Wyrmgus start // || (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack) || (dest.NewOrder->Action == UnitActionAttack && !unit.CanAttack(true)) //Wyrmgus end || (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) { this->Finished = true; return ; } else { if (dest.NewOrder->HasGoal()) { if (dest.NewOrder->GetGoal()->Destroyed) { delete dest.NewOrder; dest.NewOrder = NULL; this->Finished = true; return ; } unit.Orders.insert(unit.Orders.begin() + 1, dest.NewOrder->Clone()); this->Finished = true; return ; } } } this->goalPos = goal->tilePos; //Wyrmgus start this->MapLayer = goal->MapLayer; //Wyrmgus end this->State = State_TargetReached; } // FALL THROUGH default: break; } // Target destroyed? if (goal && !goal->IsVisibleAsGoal(*unit.Player)) { DebugPrint("Goal gone\n"); this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize(); //Wyrmgus start this->MapLayer = goal->MapLayer; //Wyrmgus end this->ClearGoal(); goal = NULL; } if (unit.Anim.Unbreakable) { return ; } // If our leader is dead or stops or attacks: // Attack any enemy in reaction range. // If don't set the goal, the unit can than choose a // better goal if moving nearer to enemy. //Wyrmgus start // if (unit.Type->CanAttack if (unit.CanAttack() //Wyrmgus end && (!goal || goal->CurrentAction() == UnitActionAttack || goal->CurrentAction() == UnitActionStill)) { CUnit *target = AttackUnitsInReactRange(unit); if (target) { // Save current command to come back. COrder *savedOrder = NULL; if (unit.CanStoreOrder(unit.CurrentOrder())) { savedOrder = this->Clone(); } this->Finished = true; //Wyrmgus start // unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos)); unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos, target->MapLayer)); //Wyrmgus end if (savedOrder != NULL) { unit.SavedOrder = savedOrder; } } } }
/** ** Try to move a unit that's in the way */ static void AiMoveUnitInTheWay(CUnit *unit) { static int dirs[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}}; int ux0; int uy0; int ux1; int uy1; int bx0; int by0; int bx1; int by1; int x; int y; int trycount,i; CUnit *blocker; CUnitType *unittype; CUnitType *blockertype; CUnit *movableunits[16]; int movablepos[16][2]; int movablenb; AiPlayer = unit->Player->Ai; unittype = unit->Type; ux0 = unit->X; uy0 = unit->Y; ux1 = ux0 + unittype->TileWidth - 1; uy1 = uy0 + unittype->TileHeight - 1; movablenb = 0; // Try to make some unit moves around it for (i = 0; i < NumUnits; ++i) { blocker = Units[i]; if (blocker->IsUnusable()) { continue; } if (!blocker->IsIdle()) { continue; } if (blocker->Player != unit->Player) { // Not allied if (!(blocker->Player->Allied & (1 << unit->Player->Index))) { continue; } } blockertype = blocker->Type; if (blockertype->UnitType != unittype->UnitType) { continue; } if (!CanMove(blocker)) { continue; } bx0 = blocker->X; by0 = blocker->Y; bx1 = bx0 + blocker->Type->TileWidth - 1; by1 = by0 + blocker->Type->TileHeight - 1;; // Check for collision if (!((ux0 == bx1 + 1 || ux1 == bx0 - 1) && (std::max(by0, uy0) <= std::min(by1, uy1))) && !((uy0 == by1 + 1 || uy1 == by0 - 1) && (std::max(bx0, ux0) <= std::min(bx1, ux1)))) { continue; } if (unit == blocker) { continue; } // Move blocker in a rand dir i = SyncRand() & 7; trycount = 8; while (trycount > 0) { i = (i + 1) & 7; --trycount; x = blocker->X + dirs[i][0]; y = blocker->Y + dirs[i][1]; // Out of the map => no ! if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) { continue; } // move to blocker ? => no ! if (x == ux0 && y == uy0) { continue; } movableunits[movablenb] = blocker; movablepos[movablenb][0] = x; movablepos[movablenb][1] = y; ++movablenb; trycount = 0; } if (movablenb >= 16) { break; } } // Don't move more than 1 unit. if (movablenb) { i = SyncRand() % movablenb; CommandMove(movableunits[i], movablepos[i][0], movablepos[i][1], FlushCommands); } }
/** ** Get the value of the unit variable. ** ** @param l Lua state. ** ** @return The value of the variable of the unit. */ static int CclGetUnitVariable(lua_State *l) { const int nargs = lua_gettop(l); Assert(nargs == 2 || nargs == 3); lua_pushvalue(l, 1); CUnit *unit = CclGetUnit(l); if (unit == NULL) { return 1; } UpdateUnitVariables(*unit); lua_pop(l, 1); const char *const value = LuaToString(l, 2); if (!strcmp(value, "RegenerationRate")) { lua_pushnumber(l, unit->Variable[HP_INDEX].Increase); } else if (!strcmp(value, "Ident")) { lua_pushstring(l, unit->Type->Ident.c_str()); } else if (!strcmp(value, "ResourcesHeld")) { lua_pushnumber(l, unit->ResourcesHeld); } else if (!strcmp(value, "GiveResourceType")) { lua_pushnumber(l, unit->Type->GivesResource); } else if (!strcmp(value, "CurrentResource")) { lua_pushnumber(l, unit->CurrentResource); } else if (!strcmp(value, "Name")) { lua_pushstring(l, unit->Type->Name.c_str()); } else if (!strcmp(value, "PlayerType")) { lua_pushinteger(l, unit->Player->Type); } else if (!strcmp(value, "IndividualUpgrade")) { LuaCheckArgs(l, 3); std::string upgrade_ident = LuaToString(l, 3); if (CUpgrade::Get(upgrade_ident)) { lua_pushboolean(l, unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID]); } else { LuaError(l, "Individual upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str()); } return 1; } else if (!strcmp(value, "Active")) { lua_pushboolean(l, unit->Active); return 1; } else if (!strcmp(value, "Idle")) { lua_pushboolean(l, unit->IsIdle()); return 1; } else { int index = UnitTypeVar.VariableNameLookup[value];// User variables if (index == -1) { LuaError(l, "Bad variable name '%s'\n" _C_ value); } if (nargs == 2) { lua_pushnumber(l, unit->Variable[index].Value); } else { const char *const type = LuaToString(l, 3); if (!strcmp(type, "Value")) { lua_pushnumber(l, unit->Variable[index].Value); } else if (!strcmp(type, "Max")) { lua_pushnumber(l, unit->Variable[index].Max); } else if (!strcmp(type, "Increase")) { lua_pushnumber(l, unit->Variable[index].Increase); } else if (!strcmp(type, "Enable")) { lua_pushnumber(l, unit->Variable[index].Enable); } else { LuaError(l, "Bad variable type '%s'\n" _C_ type); } } } return 1; }