/** ** Move unit to unit resource. ** ** @return 1 if reached, -1 if unreacheable, 0 if on the way. */ int COrder_Resource::MoveToResource_Unit(CUnit &unit) { const CUnit *goal = this->GetGoal(); Assert(goal); switch (DoActionMove(unit)) { // reached end-point? 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 return -1; case PF_REACHED: break; case PF_WAIT: if (unit.Player->AiEnabled) { this->Range++; if (this->Range >= 5) { this->Range = 0; AiCanNotMove(unit); } } default: // Goal gone or something. if (unit.Anim.Unbreakable || goal->IsVisibleAsGoal(*unit.Player)) { return 0; } break; } return 1; }
/** ** Unit moves! Generic function called from other actions. ** ** @param unit Pointer to unit. ** ** @return >0 remaining path length, 0 wait for path, -1 ** reached goal, -2 can't reach the goal. */ int DoActionMove(CUnit &unit) { Vec2i posd; // movement in tile. int d; Assert(unit.CanMove()); if (!unit.Moving && (unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) { Assert(!unit.Anim.Unbreakable); // FIXME: So units flying up and down are not affected. unit.IX = 0; unit.IY = 0; UnmarkUnitFieldFlags(unit); d = NextPathElement(unit, &posd.x, &posd.y); MarkUnitFieldFlags(unit); switch (d) { case PF_UNREACHABLE: // Can't reach, stop if (unit.Player->AiEnabled) { AiCanNotMove(unit); } unit.Moving = 0; return d; case PF_REACHED: // Reached goal, stop unit.Moving = 0; return d; case PF_WAIT: // No path, wait // Reset frame to still frame while we wait // FIXME: Unit doesn't animate. unit.Frame = unit.Type->StillFrame; UnitUpdateHeading(unit); unit.Wait = 10; unit.Moving = 0; return d; default: // On the way moving unit.Moving = 1; break; } if (unit.Type->UnitType == UnitTypeNaval) { // Boat (un)docking? const CMapField &mf_cur = *Map.Field(unit.Offset); const CMapField &mf_next = *Map.Field(unit.tilePos + posd); if (mf_cur.WaterOnMap() && mf_next.CoastOnMap()) { PlayUnitSound(unit, VoiceDocking); } else if (mf_cur.CoastOnMap() && mf_next.WaterOnMap()) { PlayUnitSound(unit, VoiceDocking); // undocking } } Vec2i pos = unit.tilePos + posd; unit.MoveToXY(pos); // Remove unit from the current selection if (unit.Selected && !Map.Field(pos)->playerInfo.IsTeamVisible(*ThisPlayer)) { if (NumSelected == 1) { // Remove building cursor CancelBuildingMode(); } if (!ReplayRevealMap) { UnSelectUnit(unit); SelectionChanged(); } } unit.IX = -posd.x * PixelTileSize.x; unit.IY = -posd.y * PixelTileSize.y; unit.Frame = unit.Type->StillFrame; UnitHeadingFromDeltaXY(unit, posd); } else { posd.x = Heading2X[unit.Direction / NextDirection]; posd.y = Heading2Y[unit.Direction / NextDirection]; d = unit.pathFinderData->output.Length + 1; } unit.pathFinderData->output.Cycles++;//reset have to be manualy controled by caller. int move = UnitShowAnimationScaled(unit, unit.Type->Animations->Move, Map.Field(unit.Offset)->Cost); unit.IX += posd.x * move; unit.IY += posd.y * move; // Finished move animation, set Moving to 0 so we recalculate the path // next frame // FIXME: this is broken for subtile movement if (!unit.Anim.Unbreakable && !unit.IX && !unit.IY) { unit.Moving = 0; } return d; }
/** ** 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; } }
/** ** Move to resource depot ** ** @param unit Pointer to unit. ** ** @return TRUE if reached, otherwise FALSE. */ int COrder_Resource::MoveToDepot(CUnit &unit) { const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource]; CUnit &goal = *this->GetGoal(); CPlayer &player = *unit.Player; Assert(&goal); switch (DoActionMove(unit)) { // reached end-point? 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 return -1; case PF_REACHED: break; case PF_WAIT: if (unit.Player->AiEnabled) { this->Range++; if (this->Range >= 5) { this->Range = 0; AiCanNotMove(unit); } } default: if (unit.Anim.Unbreakable || goal.IsVisibleAsGoal(player)) { return 0; } break; } // // Target is dead, stop getting resources. // if (!goal.IsVisibleAsGoal(player)) { DebugPrint("%d: Worker %d report: Destroyed depot\n" _C_ player.Index _C_ UnitNumber(unit)); unit.CurrentOrder()->ClearGoal(); CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource); if (depot) { UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT); DebugPrint("%d: Worker %d report: Going to new deposit.\n" _C_ player.Index _C_ UnitNumber(unit)); } else { DebugPrint("%d: Worker %d report: Can't find a new resource deposit.\n" _C_ player.Index _C_ UnitNumber(unit)); // FIXME: perhaps we should choose an alternative this->Finished = true; } return 0; } // If resource depot is still under construction, wait! if (goal.CurrentAction() == UnitActionBuilt) { unit.Wait = 10; return 0; } this->ClearGoal(); unit.Wait = resinfo.WaitAtDepot; // Place unit inside the depot if (unit.Wait) { int selected = unit.Selected; unit.Remove(&goal); if (selected && !Preference.DeselectInMine) { unit.Removed = 0; SelectUnit(unit); SelectionChanged(); unit.Removed = 1; } unit.Anim.CurrAnim = NULL; } // Update resource. const int rindex = resinfo.FinalResource; //Wyrmgus start // player.ChangeResource(rindex, (unit.ResourcesHeld * player.Incomes[rindex]) / 100, true); // player.TotalResources[rindex] += (unit.ResourcesHeld * player.Incomes[rindex]) / 100; player.ChangeResource(rindex, (unit.ResourcesHeld * resinfo.FinalResourceConversionRate / 100 * player.Incomes[rindex]) / 100, true); player.TotalResources[rindex] += (unit.ResourcesHeld * resinfo.FinalResourceConversionRate / 100 * player.Incomes[rindex]) / 100; //Wyrmgus end unit.ResourcesHeld = 0; unit.CurrentResource = 0; if (unit.Wait) { //Wyrmgus start // unit.Wait /= std::max(1, unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR); unit.Wait /= std::max(1, (unit.Player->SpeedResourcesReturn[resinfo.ResourceId] + goal.Variable[TIMEEFFICIENCYBONUS_INDEX].Value) / SPEEDUP_FACTOR); //Wyrmgus end if (unit.Wait) { unit.Wait--; } } return 1; }