//Wyrmgus start //static int AiAssignHarvesterFromTerrain(CUnit &unit, int resource) static int AiAssignHarvesterFromTerrain(CUnit &unit, int resource, int resource_range) //Wyrmgus end { // TODO : hardcoded forest Vec2i forestPos; //Wyrmgus start Vec2i rockPos; //Wyrmgus end // Code for terrain harvesters. Search for piece of terrain to mine. //Wyrmgus start // if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 1000, *unit.Player, unit.tilePos, &forestPos)) { if (resource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, resource_range, *unit.Player, unit.tilePos, &forestPos, unit.MapLayer)) { //Wyrmgus end //Wyrmgus start // CommandResourceLoc(unit, forestPos, FlushCommands); CommandResourceLoc(unit, forestPos, FlushCommands, unit.MapLayer); //Wyrmgus end return 1; } //Wyrmgus start if (resource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, resource_range, *unit.Player, unit.tilePos, &rockPos, unit.MapLayer)) { CommandResourceLoc(unit, rockPos, FlushCommands, unit.MapLayer); return 1; } //Wyrmgus end // Ask the AI to explore... //Wyrmgus start // AiExplore(unit.tilePos, MapFieldLandUnit); //Wyrmgus end // Failed. return 0; }
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); }
/** ** Send unit harvest a location ** ** @param unit pointer to unit. ** @param x X map position for harvest. ** @param y Y map position for harvest. ** @param flush if true, flush command queue. */ void CommandResourceLoc(CUnit *unit, int x, int y, int flush) { COrder *order; int nx; int ny; // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { if (unit->Type->Building) { // FIXME: should find a better way for pending orders. order = &unit->NewOrder; ReleaseOrder(order); } else if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); order->Action = UnitActionResource; // Find the closest piece of wood next to a tile where the unit can move if (!FindTerrainType(0, (unit->Type->MovementMask), 1, 20, unit->Player, x, y, &nx, &ny)) { DebugPrint("FIXME: Give up???\n"); } // Max Value > 1 if ((abs(nx - x) | abs(ny - y)) > 1) { if (!FindTerrainType(0, MapFieldForest, 0, 20, unit->Player, nx, ny, &nx, &ny)) { DebugPrint("FIXME: Give up???\n"); } } else { // The destination is next to a reacahble tile. nx = x; ny = y; } order->X = nx; order->Y = ny; order->Range = 1; } ClearSavedAction(unit); }
/** ** Assign worker to gather a certain resource from terrain. ** ** @param unit pointer to the unit. ** @param resource resource identification. ** ** @return 1 if the worker was assigned, 0 otherwise. */ static int AiAssignHarvesterFromTerrain(CUnit &unit, int resource) { // TODO : hardcoded forest Vec2i forestPos; // Code for terrain harvesters. Search for piece of terrain to mine. if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 1000, *unit.Player, unit.tilePos, &forestPos)) { CommandResourceLoc(unit, forestPos, FlushCommands); return 1; } // Ask the AI to explore... AiExplore(unit.tilePos, MapFieldLandUnit); // Failed. return 0; }
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. ** ** @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; }
/** ** Move unit to terrain. ** ** @return 1 if reached, -1 if unreacheable, 0 if on the way. */ int COrder_Resource::MoveToResource_Terrain(CUnit &unit) { Vec2i pos = this->goalPos; // Wood gone, look somewhere else. if ((Map.Info.IsPointOnMap(pos) == false || Map.Field(pos)->IsTerrainResourceOnMap(CurrentResource) == false) && (!unit.IX) && (!unit.IY)) { //Wyrmgus start // if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 16, *unit.Player, this->goalPos, &pos)) { if ((this->CurrentResource == WoodCost && !FindTerrainType(unit.Type->MovementMask, MapFieldForest, 16, *unit.Player, this->goalPos, &pos)) || (this->CurrentResource == StoneCost && !FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 16, *unit.Player, this->goalPos, &pos))) { //Wyrmgus end // no wood in range return -1; } else { this->goalPos = pos; } } switch (DoActionMove(unit)) { case PF_UNREACHABLE: //Wyrmgus start //if is unreachable and is on a raft, see if the raft can move closer 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 0; } } } //Wyrmgus end unit.Wait = 10; if (unit.Player->AiEnabled) { this->Range++; if (this->Range >= 5) { this->Range = 0; AiCanNotMove(unit); } } //Wyrmgus start // if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 9999, *unit.Player, unit.tilePos, &pos)) { if ((this->CurrentResource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, 9999, *unit.Player, unit.tilePos, &pos)) || (this->CurrentResource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 9999, *unit.Player, unit.tilePos, &pos))) { //Wyrmgus end this->goalPos = pos; DebugPrint("Found a better place to harvest %d,%d\n" _C_ pos.x _C_ pos.y); // FIXME: can't this overflow? It really shouldn't, since // x and y are really supossed to be reachable, checked thorugh a flood fill. // I don't know, sometimes stuff happens. return 0; } return -1; case PF_REACHED: return 1; case PF_WAIT: if (unit.Player->AiEnabled) { this->Range++; if (this->Range >= 5) { this->Range = 0; AiCanNotMove(unit); } } default: return 0; } }
/** ** 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; }