void FindAndGatherResource(CUnit* unit, int resourceType) { CUnit* dest; int x, y, result; switch (resourceType) { case GoldCost: dest = UnitFindResource(unit, unit->X, unit->Y, FIND_RESOURCE_RANGE, resourceType); if (dest != NoUnitP) { SendCommandResource(unit, dest, 1); // TODO: don't know what StopResourceFlag corresponds to in 2.2.4 code // unit->StopResourceFlag = 1; } else { SendResponseMessage("Unable to find gold within range.\n", 3); return; } break; case WoodCost: result = FindTerrainType(unit->Type->MovementMask, MapFieldForest, 0, FIND_RESOURCE_RANGE, unit->Player, unit->X, unit->Y, &x, &y); if (result) { SendCommandResourceLoc(unit, x, y, 1); // TODO: don't know what StopResourceFlag corresponds to in 2.2.4 code //unit->StopResourceFlag = 1; } else { SendResponseMessage("Unable to find wood within range.\n", 3); return; } break; default: SendResponseMessage("Unknown resource type\n", 3); } SendResponseMessage("OK\n", 3); }
/** ** Get a suitable depot for better resource harvesting. ** ** @param worker Worker itself. ** @param oldDepot Old assigned depot. ** @param resUnit Resource to harvest from, if succeed ** ** @return new depot if found, NULL otherwise. */ CUnit *AiGetSuitableDepot(const CUnit &worker, const CUnit &oldDepot, CUnit **resUnit) { Assert(worker.CurrentAction() == UnitActionResource); COrder_Resource &order = *static_cast<COrder_Resource *>(worker.CurrentOrder()); const int resource = order.GetCurrentResource(); std::vector<CUnit *> depots; const Vec2i offset(MaxMapWidth, MaxMapHeight); for (std::vector<CUnit *>::iterator it = worker.Player->UnitBegin(); it != worker.Player->UnitEnd(); ++it) { CUnit &unit = **it; if (unit.Type->CanStore[resource] && !unit.IsUnusable()) { depots.push_back(&unit); } } // If there aren't any alternatives, exit if (depots.size() < 2) { return NULL; } std::sort(depots.begin(), depots.end(), CompareDepotsByDistance(worker)); for (std::vector<CUnit *>::iterator it = depots.begin(); it != depots.end(); ++it) { CUnit &unit = **it; const unsigned int tooManyWorkers = 15; const int range = 15; if (&oldDepot == &unit) { continue; } if (unit.Refs > tooManyWorkers) { continue; } //Wyrmgus start // if (AiEnemyUnitsInDistance(worker, range)) { if (AiEnemyUnitsInDistance(worker, range, worker.MapLayer)) { //Wyrmgus end continue; } CUnit *res = UnitFindResource(worker, unit, range, resource, unit.Player->AiEnabled); if (res) { *resUnit = res; return &unit; } } return NULL; }
void HarvestResAtLoc(int resourceType, int x, int y) { CUnit *unit; CUnit *dest; if (resourceType == GoldCost || resourceType == OilCost) { dest = UnitFindResource(unit, x, y, FIND_RESOURCE_RANGE, resourceType); if (dest != NoUnitP) { SendCommandResource(unit, dest, 1); } else { SendResponseMessage("Unable to find resource in range.\n", 3); return; } } else if (resourceType == WoodCost) { SendCommandResourceLoc(unit, x, y, 1); } else { SendResponseMessage("Unknown resource type\n", 3); return; } SendResponseMessage("OK\n", 3); }
bool COrder_Resource::FindAnotherResource(CUnit &unit) { if (this->CurrentResource) { const ResourceInfo *resinfo = unit.Type->ResInfo[this->CurrentResource]; if (resinfo) { //Wyrmgus start // if (!resinfo.TerrainHarvester) { if (!Map.Info.IsPointOnMap(this->goalPos)) { //Wyrmgus end CUnit *newGoal = UnitFindResource(unit, this->Resource.Mine ? *this->Resource.Mine : unit, 8, this->CurrentResource, 1); if (newGoal) { CUnit *mine = this->Resource.Mine; if (mine) { unit.DeAssignWorkerFromMine(*mine); } unit.AssignWorkerToMine(*newGoal); this->Resource.Mine = newGoal; this->goalPos.x = -1; this->goalPos.y = -1; this->State = SUB_MOVE_TO_RESOURCE; this->SetGoal(newGoal); return true; } } else { Vec2i resPos; //Wyrmgus start // if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 8, *unit.Player, unit.tilePos, &resPos)) { if ((this->CurrentResource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, 8, *unit.Player, unit.tilePos, &resPos)) || (this->CurrentResource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 8, *unit.Player, unit.tilePos, &resPos))) { //Wyrmgus end this->goalPos = resPos; this->State = SUB_MOVE_TO_RESOURCE; DebugPrint("Found a better place to harvest %d,%d\n" _C_ resPos.x _C_ resPos.y); return true; } } } } return false; }
/** ** Assign worker to gather a certain resource from Unit. ** ** @param unit pointer to the unit. ** @param resource resource identification. ** ** @return 1 if the worker was assigned, 0 otherwise. */ static int AiAssignHarvesterFromUnit(CUnit &unit, int resource) { // Try to find the nearest depot first. CUnit *depot = FindDeposit(unit, 1000, resource); // Find a resource to harvest from. CUnit *mine = UnitFindResource(unit, depot ? *depot : unit, 1000, resource, true); if (mine) { CommandResource(unit, *mine, FlushCommands); return 1; } int exploremask = 0; for (size_t i = 0; i != UnitTypes.size(); ++i) { const CUnitType *type = UnitTypes[i]; if (type && type->GivesResource == resource) { switch (type->UnitType) { case UnitTypeLand: exploremask |= MapFieldLandUnit; break; case UnitTypeFly: exploremask |= MapFieldAirUnit; break; case UnitTypeNaval: exploremask |= MapFieldSeaUnit; break; default: Assert(0); } } } // Ask the AI to explore AiExplore(unit.tilePos, exploremask); // Failed. return 0; }
/** ** Assign worker to gather a certain resource. ** ** @param unit pointer to the unit. ** @param resource resource identification. ** ** @return 1 if the worker was assigned, 0 otherwise. */ static int AiAssignHarvester(CUnit &unit, int resource) { ResourceInfo *resinfo; // It can't. if (unit.Removed) { return 0; } resinfo = unit.Type->ResInfo[resource]; Assert(resinfo); if (resinfo->TerrainHarvester) { Vec2i forestPos; // // Code for terrain harvesters. Search for piece of terrain to mine. // if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 1000, unit.Player, unit.tilePos, &forestPos)) { CommandResourceLoc(unit, forestPos, FlushCommands); return 1; } // Ask the AI to explore... AiExplore(unit.tilePos, MapFieldLandUnit); } else { int exploremask = 0; // // Find a resource to harvest from. // CUnit *dest = UnitFindResource(unit, unit.tilePos.x, unit.tilePos.y, 1000, resource, true); if (dest) { //FIXME: rb - when workers can speedup building then such assign may be ok. //if(dest->CurrentAction() == UnitActionBuilt) //CommandBuildBuilding(unit, dest->tilePos, dest->Type, FlushCommands); //else CommandResource(unit, *dest, FlushCommands); return 1; } #if 0 //may this code touch needmask which will be reseted before next cycle if (resinfo->RefineryHarvester && (dest = UnitFindMiningArea(unit, unit.X, unit.Y, 1000, resource))) { int needmask; //int counter[UnitTypeMax]; // // Count the already made build requests. // //AiGetBuildRequestsCount(counter); int n = AiHelpers.Refinery[resource - 1].size(); for (int i = 0; i < n; ++i) { CUnitType *type = AiHelpers.Refinery[resource - 1][i]; //if (counter[type->Slot]) { // Already ordered. // return 0; //} if (!AiRequestedTypeAllowed(AiPlayer->Player, type)) { continue; } // // Check if resources available. // needmask = AiCheckUnitTypeCosts(type); if(!needmask && AiMakeUnit(type)) { AiBuildQueue newqueue; newqueue.Type = type; newqueue.Want = 1; newqueue.Made = 1; newqueue.X = dest->X; newqueue.Y = dest->Y; AiPlayer->UnitTypeBuilt.insert( AiPlayer->UnitTypeBuilt.begin(), newqueue); return 0; } } return 0; } #endif for (std::vector<CUnitType *>::iterator i = UnitTypes.begin(); i != UnitTypes.end(); i++) { if (*i && (*i)->GivesResource == resource) { switch ((*i)->UnitType) { case UnitTypeLand: exploremask |= MapFieldLandUnit; break; case UnitTypeFly: exploremask |= MapFieldAirUnit; break; case UnitTypeNaval: exploremask |= MapFieldSeaUnit; break; default: Assert(0); } } } // Ask the AI to explore AiExplore(unit.tilePos, exploremask); } // Failed. return 0; }
/** ** Find something else to do when the resource is exhausted. ** This is called from GatherResource when the resource is empty. ** ** @param unit pointer to harvester unit. ** @param source pointer to resource unit. */ void COrder_Resource::LoseResource(CUnit &unit, CUnit &source) { CUnit *depot; const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource]; //Wyrmgus start const CUnitType &source_type = *source.Type; // Assert((unit.Container == &source && !resinfo.HarvestFromOutside) // || (!unit.Container && resinfo.HarvestFromOutside)); Assert((unit.Container == &source && !source_type.BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) || (!unit.Container && source_type.BoolFlag[HARVESTFROMOUTSIDE_INDEX].value)); //Wyrmgus end //Wyrmgus start // if (resinfo.HarvestFromOutside) { if (source_type.BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) { //Wyrmgus end this->ClearGoal(); --source.Resource.Active; } // Continue to harvest if we aren't fully loaded //Wyrmgus start // if (resinfo.HarvestFromOutside && unit.ResourcesHeld < resinfo.ResourceCapacity) { if (source_type.BoolFlag[HARVESTFROMOUTSIDE_INDEX].value && unit.ResourcesHeld < resinfo.ResourceCapacity) { //Wyrmgus end CUnit *goal = UnitFindResource(unit, unit, 15, this->CurrentResource, 1); if (goal) { this->goalPos.x = -1; this->goalPos.y = -1; this->State = SUB_START_RESOURCE; this->SetGoal(goal); return; } } // If we are fully loaded first search for a depot. if (unit.ResourcesHeld && (depot = FindDeposit(unit, 1000, unit.CurrentResource))) { if (unit.Container) { DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), &source); } // Remember where it mined, so it can look around for another resource. // //FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //unit.CurrentOrder()->Arg1.ResourcePos = (unit.X << 16) | unit.Y; this->DoneHarvesting = true; UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT); DebugPrint("%d: Worker %d report: Resource is exhausted, Going to depot\n" _C_ unit.Player->Index _C_ UnitNumber(unit)); return; } // No depot found, or harvester empty // Dump the unit outside and look for something to do. if (unit.Container) { //Wyrmgus start // Assert(!resinfo.HarvestFromOutside); Assert(!source_type.BoolFlag[HARVESTFROMOUTSIDE_INDEX].value); //Wyrmgus end DropOutOnSide(unit, LookingW, &source); } this->goalPos.x = -1; this->goalPos.y = -1; //use depot as goal depot = UnitFindResource(unit, unit, 15, this->CurrentResource, unit.Player->AiEnabled); if (depot) { DebugPrint("%d: Worker %d report: Resource is exhausted, Found another resource.\n" _C_ unit.Player->Index _C_ UnitNumber(unit)); this->State = SUB_START_RESOURCE; this->SetGoal(depot); } else { DebugPrint("%d: Worker %d report: Resource is exhausted, Just sits around confused.\n" _C_ unit.Player->Index _C_ UnitNumber(unit)); this->Finished = true; } }
/** ** Start harvesting the resource. ** ** @param unit Pointer to unit. ** ** @return TRUE if ready, otherwise FALSE. */ int COrder_Resource::StartGathering(CUnit &unit) { CUnit *goal; const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource]; Assert(!unit.IX); Assert(!unit.IY); //Wyrmgus start // if (resinfo.TerrainHarvester) { if (Map.Info.IsPointOnMap(this->goalPos)) { //Wyrmgus end // This shouldn't happened? #if 0 if (!Map.IsTerrainResourceOnMap(unit.Orders->goalPos, this->CurrentResource)) { DebugPrint("Wood gone, just like that?\n"); return 0; } #endif UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos); if (resinfo.WaitAtResource) { this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]); } else { this->TimeToHarvest = 1; } this->DoneHarvesting = 0; if (this->CurrentResource != unit.CurrentResource) { DropResource(unit); unit.CurrentResource = this->CurrentResource; } return 1; } goal = this->GetGoal(); // Target is dead, stop getting resources. if (!goal || goal->IsVisibleAsGoal(*unit.Player) == false) { // Find an alternative, but don't look too far. this->goalPos.x = -1; this->goalPos.y = -1; if ((goal = UnitFindResource(unit, unit, 15, this->CurrentResource, unit.Player->AiEnabled))) { this->State = SUB_START_RESOURCE; this->SetGoal(goal); } else { this->ClearGoal(); this->Finished = true; } return 0; } // FIXME: 0 can happen, if to near placed by map designer. Assert(unit.MapDistanceTo(*goal) <= 1); // Update the heading of a harvesting unit to looks straight at the resource. //Wyrmgus start // UnitHeadingFromDeltaXY(unit, goal->tilePos - unit.tilePos + goal->Type->GetHalfTileSize()); UnitHeadingFromDeltaXY(unit, Vec2i(goal->tilePos.x * PixelTileSize.x, goal->tilePos.y * PixelTileSize.y) - Vec2i(unit.tilePos.x * PixelTileSize.x, unit.tilePos.y * PixelTileSize.y) + goal->Type->GetHalfTilePixelSize() - unit.Type->GetHalfTilePixelSize()); //Wyrmgus end // If resource is still under construction, wait! if ((goal->Type->MaxOnBoard && goal->Resource.Active >= goal->Type->MaxOnBoard) || goal->CurrentAction() == UnitActionBuilt) { // FIXME: Determine somehow when the resource will be free to use // FIXME: Could we somehow find another resource? Think minerals // FIXME: We should add a flag for that, and a limited range. // However the CPU usage is really low (no pathfinding stuff). unit.Wait = 10; return 0; } // Place unit inside the resource //Wyrmgus start // if (!resinfo.HarvestFromOutside) { if (!goal->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) { //Wyrmgus end if (goal->Variable[MAXHARVESTERS_INDEX].Value == 0 || goal->Variable[MAXHARVESTERS_INDEX].Value > goal->InsideCount) { this->ClearGoal(); int selected = unit.Selected; unit.Remove(goal); if (selected && !Preference.DeselectInMine) { unit.Removed = 0; SelectUnit(unit); SelectionChanged(); unit.Removed = 1; } } else if (goal->Variable[MAXHARVESTERS_INDEX].Value <= goal->InsideCount) { //Resource is full, wait unit.Wait = 10; return 0; } } if (this->CurrentResource != unit.CurrentResource) { DropResource(unit); unit.CurrentResource = this->CurrentResource; } // Activate the resource goal->Resource.Active++; if (resinfo.WaitAtResource) { //Wyrmgus start // this->TimeToHarvest = std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]); int wait_at_resource = resinfo.WaitAtResource; if (!goal->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value) { wait_at_resource = resinfo.WaitAtResource * 100 / resinfo.ResourceStep; } this->TimeToHarvest = std::max<int>(1, wait_at_resource * SPEEDUP_FACTOR / (unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] + goal->Variable[TIMEEFFICIENCYBONUS_INDEX].Value)); //Wyrmgus end } else { this->TimeToHarvest = 1; } this->DoneHarvesting = 0; return 1; }
/** ** Wait in depot, for the resources stored. ** ** @param unit Pointer to unit. ** ** @return TRUE if ready, otherwise FALSE. */ bool COrder_Resource::WaitInDepot(CUnit &unit) { const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource]; const CUnit *depot = ResourceDepositOnMap(unit.tilePos, resinfo.ResourceId); //Assert(depot); // Range hardcoded. don't stray too far though //Wyrmgus start // if (resinfo.TerrainHarvester) { if (!this->Resource.Mine) { //Wyrmgus end Vec2i pos = this->Resource.Pos; //Wyrmgus start // if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 10, *unit.Player, pos, &pos)) { if ((this->CurrentResource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, 10, *unit.Player, pos, &pos)) || (this->CurrentResource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 10, *unit.Player, pos, &pos))) { //Wyrmgus end if (depot) { DropOutNearest(unit, pos, depot); } this->goalPos = pos; //Wyrmgus start if (this->CurrentResource == WoodCost) { //tree tiles can regrow, so we need to check if any have regrown closer to the worker Vec2i forestPos; int max_forest_range = std::max<int>(abs(unit.tilePos.x - this->goalPos.x), abs(unit.tilePos.y - this->goalPos.y)); if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, max_forest_range, *unit.Player, unit.tilePos, &forestPos)) { if (PlaceReachable(unit, forestPos, 1, 1, 0, 1, max_forest_range * 4)) { this->goalPos = forestPos; } } } //Wyrmgus end } else { if (depot) { DropOutOnSide(unit, LookingW, depot); } this->Finished = true; return false; } } else { const unsigned int tooManyWorkers = 15; CUnit *mine = this->Resource.Mine; const int range = 15; CUnit *newdepot = NULL; CUnit *goal = NULL; const bool longWay = unit.pathFinderData->output.Cycles > 500; //Wyrmgus start // if (unit.Player->AiEnabled && AiPlayer && AiPlayer->BuildDepots) { if (depot && unit.Player->AiEnabled && AiPlayer && AiPlayer->BuildDepots) { //check if the depot is valid //Wyrmgus end // If the depot is overused, we need first to try to switch into another depot // Use depot's ref counter for that if (longWay || !mine || (depot->Refs > tooManyWorkers)) { newdepot = AiGetSuitableDepot(unit, *depot, &goal); if (newdepot == NULL && longWay) { // We need a new depot AiNewDepotRequest(unit); } } } // If goal is not NULL, then we got it in AiGetSuitableDepot if (!goal) { goal = UnitFindResource(unit, newdepot ? *newdepot : (mine ? *mine : unit), mine ? range : 1000, this->CurrentResource, unit.Player->AiEnabled, newdepot ? newdepot : depot); } if (goal) { if (depot) { DropOutNearest(unit, goal->tilePos + goal->Type->GetHalfTileSize(), depot); } if (goal != mine) { if (mine) { unit.DeAssignWorkerFromMine(*mine); } unit.AssignWorkerToMine(*goal); this->Resource.Mine = goal; } this->SetGoal(goal); this->goalPos.x = this->goalPos.y = -1; } else { #ifdef DEBUG const Vec2i &pos = mine ? mine->tilePos : unit.tilePos; DebugPrint("%d: Worker %d report: [%d,%d] Resource gone near [%d,%d] in range %d. Sit and play dumb.\n" _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.tilePos.x _C_ unit.tilePos.y _C_ pos.x _C_ pos.y _C_ range); #endif // DEBUG if (depot) { DropOutOnSide(unit, LookingW, depot); } if (mine) { unit.DeAssignWorkerFromMine(*mine); this->Resource.Mine = NULL; } this->Finished = true; return false; } } return true; }
//Wyrmgus start //static int AiAssignHarvesterFromUnit(CUnit &unit, int resource) static int AiAssignHarvesterFromUnit(CUnit &unit, int resource, int resource_range) //Wyrmgus end { // Try to find the nearest depot first. CUnit *depot = FindDeposit(unit, 1000, resource); // Find a resource to harvest from. //Wyrmgus start // CUnit *mine = UnitFindResource(unit, depot ? *depot : unit, 1000, resource, true); CUnit *mine = UnitFindResource(unit, depot ? *depot : unit, resource_range, resource, true, NULL, false); //Wyrmgus end if (mine) { //Wyrmgus start // CommandResource(unit, *mine, FlushCommands); // return 1; if (mine->Type->BoolFlag[CANHARVEST_INDEX].value) { CommandResource(unit, *mine, FlushCommands); return 1; } else { // if the resource isn't readily harvestable (but is a deposit), build a mine there const int n = AiHelpers.Refinery[resource - 1].size(); for (int i = 0; i < n; ++i) { CUnitType &type = *AiHelpers.Refinery[resource - 1][i]; if (CanBuildUnitType(&unit, type, mine->tilePos, 1, true, mine->MapLayer)) { CommandBuildBuilding(unit, mine->tilePos, type, FlushCommands, mine->MapLayer); return 1; } } } //Wyrmgus end } //Wyrmgus start /* int exploremask = 0; for (size_t i = 0; i != UnitTypes.size(); ++i) { const CUnitType *type = UnitTypes[i]; if (type && type->GivesResource == resource) { switch (type->UnitType) { case UnitTypeLand: exploremask |= MapFieldLandUnit; break; case UnitTypeFly: exploremask |= MapFieldAirUnit; break; //Wyrmgus start case UnitTypeFlyLow: exploremask |= MapFieldLandUnit; break; //Wyrmgus end case UnitTypeNaval: exploremask |= MapFieldSeaUnit; break; default: Assert(0); } } } // Ask the AI to explore AiExplore(unit.tilePos, exploremask); */ //Wyrmgus end // Failed. return 0; }