From 09f642805e4d0b63eff89a397bebe2ac057cbf4b Mon Sep 17 00:00:00 2001 From: joris <joris.dauphin@gmail.com> Date: Mon, 23 Jan 2012 11:59:13 +0100 Subject: [PATCH] Fix ActionRessource and DeassignWorkerFromMine --- src/action/action_resource.cpp | 314 +++++++++++++++++------------- src/action/action_returngoods.cpp | 2 +- src/action/actions.cpp | 13 +- src/ai/ai_resource.cpp | 128 +++++++----- src/include/unit.h | 2 +- src/unit/script_unit.cpp | 16 +- src/unit/unit.cpp | 51 +++-- src/unit/unit_save.cpp | 17 +- 8 files changed, 318 insertions(+), 225 deletions(-) diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp index d58ba87b5..c0d7ac58f 100644 --- a/src/action/action_resource.cpp +++ b/src/action/action_resource.cpp @@ -66,67 +66,87 @@ -- Functions ----------------------------------------------------------------------------*/ +/** +** Move unit to terrain. +** +** @return 1 if reached, -1 if unreacheable, 0 if on the way. +*/ +static int MoveToResource_Terrain(CUnit &unit) +{ + Vec2i pos = unit.CurrentOrder()->goalPos; + + // Wood gone, look somewhere else. + if ((!Map.ForestOnMap(pos)) && (!unit.IX) && (!unit.IY)) { + if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 16, + unit.Player, unit.CurrentOrder()->goalPos, &pos)) { + // no wood in range + return -1; + } else { + unit.CurrentOrder()->goalPos = pos; + NewResetPath(unit); + } + } + switch (DoActionMove(unit)) { + case PF_UNREACHABLE: + unit.Wait = 10; + if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 9999, + unit.Player, unit.tilePos, &pos)) { + unit.CurrentOrder()->goalPos = pos; + NewResetPath(unit); + 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; + default: + return 0; + } +} + +/** +** Move unit to unit resource. +** +** @return 1 if reached, -1 if unreacheable, 0 if on the way. +*/ +static int MoveToResource_Unit(CUnit &unit) +{ + const CUnit *goal = unit.CurrentOrder()->GetGoal(); + Assert(goal); + + switch (DoActionMove(unit)) { // reached end-point? + case PF_UNREACHABLE: + return -1; + case PF_REACHED: + break; + default: + // Goal gone or something. + if (unit.Anim.Unbreakable || goal->IsVisibleAsGoal(*unit.Player)) { + return 0; + } + break; + } + return 1; +} + /** ** Move unit to resource. ** ** @param unit Pointer to unit. ** -** @return TRUE if reached, otherwise FALSE. +** @return 1 if reached, -1 if unreacheable, 0 if on the way. */ static int MoveToResource(CUnit &unit) { const ResourceInfo &resinfo = *unit.Type->ResInfo[unit.CurrentResource]; if (resinfo.TerrainHarvester) { - Vec2i pos = unit.CurrentOrder()->goalPos; - - // Wood gone, look somewhere else. - if ((!Map.ForestOnMap(pos)) && (!unit.IX) && (!unit.IY)) { - if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 16, - unit.Player, unit.CurrentOrder()->goalPos, &pos)) { - // no wood in range - return -1; - } else { - unit.CurrentOrder()->goalPos = pos; - NewResetPath(unit); - } - } - switch (DoActionMove(unit)) { - case PF_UNREACHABLE: - unit.Wait = 10; - if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 9999, - unit.Player, unit.tilePos, &pos)) { - unit.CurrentOrder()->goalPos = pos; - NewResetPath(unit); - 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; - default: - return 0; - } + return MoveToResource_Terrain(unit); } else { - CUnit *goal = unit.CurrentOrder()->GetGoal(); - Assert(goal); - switch (DoActionMove(unit)) { // reached end-point? - case PF_UNREACHABLE: - return -1; - case PF_REACHED: - break; - default: - // Goal gone or something. - if (unit.Anim.Unbreakable || - goal->IsVisibleAsGoal(*unit.Player)) { - return 0; - } - break; - } - return 1; + return MoveToResource_Unit(unit); } } @@ -324,6 +344,8 @@ static void LoseResource(CUnit &unit, const CUnit &source) } } + + /** ** Gather the resource ** @@ -441,7 +463,6 @@ static int GatherResource(CUnit &unit) LoseResource(*uins, *source); } } - if (source->Data.Resource.Workers) { CUnit *next, *worker = source->Data.Resource.Workers; for (; NULL != worker; worker = next) @@ -462,7 +483,6 @@ static int GatherResource(CUnit &unit) //Assert(source->Data.Resource.Assigned == 0); source->Data.Resource.Workers = NULL; } - // Don't destroy the resource twice. // This only happens when it's empty. if (!dead) { @@ -517,7 +537,6 @@ int GetNumWaitingWorkers(const CUnit &mine) */ static int StopGathering(CUnit &unit) { - CUnit *depot; CUnit *source = 0; const ResourceInfo &resinfo = *unit.Type->ResInfo[unit.CurrentResource]; @@ -531,12 +550,15 @@ static int StopGathering(CUnit &unit) source->Data.Resource.Active--; Assert(source->Data.Resource.Active >= 0); - if (!resinfo.HarvestFromOutside && source->Data.Resource.Active == 0) + if (!resinfo.HarvestFromOutside && source->Data.Resource.Active == 0) { source->SubAction = 1; - + } //Store resource position. - //source->RefsIncrease(); - //unit.Orders[0]->Arg1.Resource.Mine = source; + if (unit.Orders[0]->Arg1.Resource.Mine) { + unit.Orders[0]->Arg1.Resource.Mine->RefsDecrease(); + } + source->RefsIncrease(); + unit.Orders[0]->Arg1.Resource.Mine = source; if (source->Type->MaxOnBoard) { int count = 0; @@ -544,8 +566,7 @@ static int StopGathering(CUnit &unit) CUnit *next = NULL; for(; NULL != worker; worker = worker->NextWorker) { - if (worker != &unit && - worker->SubAction == SUB_START_GATHERING && worker->Wait) { + if (worker != &unit && worker->SubAction == SUB_START_GATHERING && worker->Wait) { count++; if (next) { if (next->Wait > worker->Wait) @@ -572,6 +593,7 @@ static int StopGathering(CUnit &unit) } else { // Store resource position. unit.CurrentOrder()->Arg1.Resource.Pos = unit.tilePos; + Assert(unit.CurrentOrder()->Arg1.Resource.Mine == NULL); } #ifdef DEBUG @@ -581,17 +603,24 @@ static int StopGathering(CUnit &unit) #endif // Find and send to resource deposit. - if (!(depot = FindDeposit(unit, 1000, unit.CurrentResource)) - || !unit.ResourcesHeld) { + CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource); + if (!depot || !unit.ResourcesHeld) { if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) { Assert(unit.Container); DropOutOnSide(unit, LookingW, source); } + CUnit *mine = unit.Orders[0]->Arg1.Resource.Mine; + + if (mine) { + unit.DeAssignWorkerFromMine(*mine); + mine->RefsDecrease(); + unit.Orders[0]->Arg1.Resource.Mine = NULL; + } + DebugPrint("%d: Worker %d report: Can't find a resource [%d] deposit.\n" _C_ unit.Player->Index _C_ unit.Slot _C_ unit.CurrentResource); unit.CurrentOrder()->ClearGoal(); unit.ClearAction(); - // should return 0, done below! return 0; } else { if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) { @@ -638,8 +667,7 @@ static int MoveToDepot(CUnit &unit) // Target is dead, stop getting resources. // if (!goal->IsVisibleAsGoal(*unit.Player)) { - DebugPrint("%d: Worker %d report: Destroyed depot\n" - _C_ unit.Player->Index _C_ unit.Slot); + DebugPrint("%d: Worker %d report: Destroyed depot\n" _C_ unit.Player->Index _C_ unit.Slot); unit.CurrentOrder()->ClearGoal(); @@ -647,8 +675,7 @@ static int MoveToDepot(CUnit &unit) if (depot) { UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT); - DebugPrint("%d: Worker %d report: Going to new deposit.\n" - _C_ unit.Player->Index _C_ unit.Slot); + DebugPrint("%d: Worker %d report: Going to new deposit.\n" _C_ unit.Player->Index _C_ unit.Slot); } else { DebugPrint("%d: Worker %d report: Can't find a new resource deposit.\n" _C_ unit.Player->Index _C_ unit.Slot); @@ -666,7 +693,6 @@ static int MoveToDepot(CUnit &unit) } // If resource depot is still under construction, wait! - // if (goal->CurrentOrder()->Action == UnitActionBuilt) { unit.Wait = 10; return 0; @@ -675,17 +701,13 @@ static int MoveToDepot(CUnit &unit) unit.CurrentOrder()->ClearGoal(); unit.Wait = resinfo.WaitAtDepot; - // // Place unit inside the depot - // if (unit.Wait) { unit.Remove(goal); unit.Anim.CurrAnim = NULL; } - // // Update resource. - // unit.Player->Resources[resinfo.FinalResource] += (unit.ResourcesHeld * unit.Player->Incomes[resinfo.FinalResource]) / 100; unit.Player->TotalResources[resinfo.FinalResource] += (unit.ResourcesHeld * unit.Player->Incomes[resinfo.FinalResource]) / 100; unit.ResourcesHeld = 0; @@ -708,7 +730,6 @@ static int MoveToDepot(CUnit &unit) */ static int WaitInDepot(CUnit &unit) { - Vec2i pos; const ResourceInfo &resinfo = *unit.Type->ResInfo[unit.CurrentResource]; const CUnit *depot = ResourceDepositOnMap(unit.tilePos, resinfo.ResourceId); @@ -716,7 +737,7 @@ static int WaitInDepot(CUnit &unit) // Range hardcoded. don't stray too far though if (resinfo.TerrainHarvester) { - pos = unit.CurrentOrder()->Arg1.Resource.Pos; + Vec2i pos = unit.CurrentOrder()->Arg1.Resource.Pos; if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 10, unit.Player, pos, &pos)) { if (depot) { @@ -730,12 +751,11 @@ static int WaitInDepot(CUnit &unit) unit.ClearAction(); } } else { - CUnit *goal; CUnit *mine = unit.CurrentOrder()->Arg1.Resource.Mine; const int range = (mine ? 15 : 1000); - pos = mine ? mine->tilePos : unit.tilePos; + const Vec2i pos = mine ? mine->tilePos : unit.tilePos; + CUnit *goal = UnitFindResource(unit, pos, range, unit.CurrentResource, unit.Player->AiEnabled, depot); - goal = UnitFindResource(unit, pos, range, unit.CurrentResource, unit.Player->AiEnabled, depot); if (goal) { if (depot) { DropOutNearest(unit, goal->tilePos + goal->Type->GetHalfTileSize(), depot); @@ -750,7 +770,6 @@ static int WaitInDepot(CUnit &unit) goal->RefsIncrease(); unit.CurrentOrder()->Arg1.Resource.Mine = goal; } - unit.CurrentOrder()->SetGoal(goal); unit.CurrentOrder()->Range = 1; unit.CurrentOrder()->goalPos.x = unit.CurrentOrder()->goalPos.y = -1; @@ -812,6 +831,53 @@ void ResourceGiveUp(CUnit &unit) unit.ClearAction(); } +/** +** Initialize +** +** return false if action is canceled, true otherwise. +*/ +static bool ActionResourceInit(CUnit &unit) +{ + Assert(unit.SubAction == SUB_START_RESOURCE); + + CUnit *const goal = unit.CurrentOrder()->GetGoal(); + int newres; + + if (goal) { + newres = goal->Type->GivesResource; + } else { + //FIXME: hardcoded wood + newres = WoodCost; + } + if (newres != unit.CurrentResource) { + DropResource(unit); + } + unit.CurrentResource = newres; + if (newres == 0) { + unit.ResourcesHeld = 0; + ResourceGiveUp(unit); + return false; + } + COrderPtr order = unit.CurrentOrder(); + order->CurrentResource = newres; + if (goal && order->Arg1.Resource.Mine != goal) { + CUnit *mine = order->Arg1.Resource.Mine; + + if (mine) { + unit.DeAssignWorkerFromMine(*mine); + mine->RefsDecrease(); + order->Arg1.Resource.Mine = NULL; + } + if (goal->CurrentAction() != UnitActionBuilt) { + unit.AssignWorkerToMine(*goal); + goal->RefsIncrease(); + order->Arg1.Resource.Mine = goal; + } + } + UnitGotoGoal(unit, goal, SUB_MOVE_TO_RESOURCE); + return true; +} + /** ** Control the unit action: getting a resource. ** @@ -821,9 +887,6 @@ void ResourceGiveUp(CUnit &unit) */ void HandleActionResource(CUnit &unit) { - int ret; - int newres; - if (unit.Wait) { // FIXME: show idle animation while we wait? unit.Wait--; @@ -832,61 +895,35 @@ void HandleActionResource(CUnit &unit) // Let's start mining. if (unit.SubAction == SUB_START_RESOURCE) { - CUnit *const goal = unit.CurrentOrder()->GetGoal(); - if (goal) { - newres = goal->Type->GivesResource; - } else { - //FIXME: hardcoded wood - newres = WoodCost; - } - if (newres != unit.CurrentResource) { - DropResource(unit); - } - if ((unit.CurrentResource = newres)) - { - COrderPtr order = unit.CurrentOrder(); - order->CurrentResource = newres; - if (goal && order->Arg1.Resource.Mine != goal) { - CUnit *mine = order->Arg1.Resource.Mine; - if (mine) { - unit.DeAssignWorkerFromMine(*mine); - mine->RefsDecrease(); - order->Arg1.Resource.Mine = NULL; - } - if (goal->CurrentAction() != UnitActionBuilt) { - unit.AssignWorkerToMine(*goal); - goal->RefsIncrease(); - order->Arg1.Resource.Mine = goal; - } - } - UnitGotoGoal(unit, goal, SUB_MOVE_TO_RESOURCE); - //NewResetPath(unit); - //unit.SubAction = SUB_MOVE_TO_RESOURCE; - //unit.Data.Move.Cycles = 0; - } else { - unit.ResourcesHeld = 0; - ResourceGiveUp(unit); + if (ActionResourceInit(unit) == false) { return; } } // Move to the resource location. - if (unit.SubAction >= SUB_MOVE_TO_RESOURCE - && unit.SubAction < SUB_UNREACHABLE_RESOURCE) { - // -1 failure, 0 not yet reached, 1 reached - if ((ret = MoveToResource(unit))) { - if (ret == -1) { - // Can't Reach + if (SUB_MOVE_TO_RESOURCE <= unit.SubAction && unit.SubAction < SUB_UNREACHABLE_RESOURCE) { + const int ret = MoveToResource(unit); + + switch (ret) + { + case -1: // Can't Reach + { unit.SubAction++; unit.Wait = 5; return; - } else { - // Reached - unit.SubAction = SUB_START_GATHERING; } - } else { - // Move along. - return; + case 1: // Reached + { + unit.SubAction = SUB_START_GATHERING; + break; + } + case 0: // Move along. + return; + default: + { + Assert(0); + break; + } } } @@ -924,19 +961,30 @@ void HandleActionResource(CUnit &unit) } // Move back home. - if (unit.SubAction >= SUB_MOVE_TO_DEPOT - && unit.SubAction < SUB_UNREACHABLE_DEPOT) { - // -1 failure, 0 not yet reached, 1 reached - if ((ret = MoveToDepot(unit))) { - if (ret == -1) { - // Can't Reach + if (SUB_MOVE_TO_DEPOT <= unit.SubAction && unit.SubAction < SUB_UNREACHABLE_DEPOT) { + const int ret = MoveToDepot(unit); + + switch (ret) + { + case -1: // Can't Reach + { unit.SubAction++; unit.Wait = 5; - } else { + return; + } + case 1: // Reached + { unit.SubAction = SUB_RETURN_RESOURCE; + return; + } + case 0: // Move along. + return; + default: + { + Assert(0); + return; } } - return; } // Depot seems to be unreachable diff --git a/src/action/action_returngoods.cpp b/src/action/action_returngoods.cpp index 5e85ec33d..cffcb3050 100644 --- a/src/action/action_returngoods.cpp +++ b/src/action/action_returngoods.cpp @@ -88,7 +88,7 @@ void HandleActionReturnGoods(CUnit &unit) //unit.CurrentOrder()->Arg1.ResourcePos = -1; NewResetPath(unit); - unit.SubAction = 70; // FIXME : Define value. + unit.SubAction = /* SUB_MOVE_TO_DEPOT */ 70; // FIXME : Define value. } //@} diff --git a/src/action/actions.cpp b/src/action/actions.cpp index cf6b1cac0..8083e43d9 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -503,12 +503,21 @@ static void HandleUnitAction(CUnit &unit) // // Release pending references. // + if (order->Action == UnitActionResource) { + CUnit *mine = order->Arg1.Resource.Mine; + + if (mine) { + unit.DeAssignWorkerFromMine(*mine); + mine->RefsDecrease(); + order->Arg1.Resource.Mine = NULL; + + } + } if (order->HasGoal()) { CUnit *goal = order->GetGoal(); // If mining decrease the active count on the resource. if (order->Action == UnitActionResource) { - if(unit.SubAction == 60) { - // FIXME: SUB_GATHER_RESOURCE ? + if (unit.SubAction == 60 /* SUB_GATHER_RESOURCE */ ) { goal->Data.Resource.Active--; Assert(goal->Data.Resource.Active >= 0); } diff --git a/src/ai/ai_resource.cpp b/src/ai/ai_resource.cpp index d69b1e303..ad8ccf57a 100644 --- a/src/ai/ai_resource.cpp +++ b/src/ai/ai_resource.cpp @@ -844,6 +844,75 @@ static void AiCheckingWork() -- WORKERS/RESOURCES ----------------------------------------------------------------------------*/ +/** +** 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, 0, 1000, unit.Player, unit.tilePos, &forestPos)) { + CommandResourceLoc(unit, forestPos, FlushCommands); + return 1; + } + // Ask the AI to explore... + AiExplore(unit.tilePos, MapFieldLandUnit); + + // Failed. + return 0; +} + +/** +** 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) +{ + // Find a resource to harvest from. + CUnit *mine = UnitFindResource(unit, unit.tilePos, 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. ** @@ -854,68 +923,19 @@ static void AiCheckingWork() */ 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; + const ResourceInfo &resinfo = *unit.Type->ResInfo[resource]; + Assert(&resinfo); - // - // 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); + if (resinfo.TerrainHarvester) { + return AiAssignHarvesterFromTerrain(unit, resource); } else { - int exploremask = 0; - // - // Find a resource to harvest from. - // - CUnit *dest = UnitFindResource(unit, unit.tilePos, 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; - } - - 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); + return AiAssignHarvesterFromUnit(unit, resource); } - - // Failed. - return 0; } static int CmpWorkers(const void *w0,const void *w1) { diff --git a/src/include/unit.h b/src/include/unit.h index 088e3ab1a..b6dd61a70 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -566,7 +566,7 @@ public: union { Vec2i Patrol; /// position for patroling. - union { + struct { Vec2i Pos; /// position for terrain resource. CUnit *Mine; } Resource; diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 82a8dfb7b..a2fe22954 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -276,19 +276,19 @@ void CclParseOrder(lua_State *l, COrderPtr order) } else if (!strcmp(value, "resource-pos")) { ++j; lua_rawgeti(l, -1, j + 1); - CclGetPos(l, &order->Arg1.Resource.Pos.x , - &order->Arg1.Resource.Pos.y); + order->Arg1.Resource.Mine = NULL; + CclGetPos(l, &order->Arg1.Resource.Pos.x , &order->Arg1.Resource.Pos.y); lua_pop(l, 1); - //FIXME: hardcoded wood - Assert(order->CurrentResource && order->CurrentResource == WoodCost); + Assert(order->CurrentResource); } else if (!strcmp(value, "resource-mine")) { ++j; lua_rawgeti(l, -1, j + 1); + Vec2i invalidPos = {-1, -1}; + order->Arg1.Resource.Pos = invalidPos; order->Arg1.Resource.Mine = CclGetUnitFromRef(l); lua_pop(l, 1); - } else if (!strcmp(value, "mine")) { - /* old save format */ + } else if (!strcmp(value, "mine")) { /* old save format */ int pos; ++j; lua_rawgeti(l, -1, j + 1); @@ -303,11 +303,15 @@ void CclParseOrder(lua_State *l, COrderPtr order) mine = ResourceOnMap(mpos, pos, true); } while (!mine && pos < MaxCosts); if (mine) { + Vec2i invalidPos = {-1, -1}; + order->Arg1.Resource.Pos = invalidPos; + mine->RefsIncrease(); order->Arg1.Resource.Mine = mine; order->CurrentResource = pos; } else { order->CurrentResource = WoodCost; + order->Arg1.Resource.Mine = NULL; order->Arg1.Resource.Pos = mpos; } } else { diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index cb80a6dfb..267b3139b 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -126,9 +126,7 @@ void CUnit::COrder::Release() { Goal->RefsDecrease(); Goal = NoUnitP; } - //FIXME: Hardcoded wood - if (Action == UnitActionResource && CurrentResource != WoodCost && - Arg1.Resource.Mine ) { + if (Action == UnitActionResource && Arg1.Resource.Mine) { Arg1.Resource.Mine->RefsDecrease(); Arg1.Resource.Mine = NoUnitP; } @@ -145,22 +143,13 @@ CUnit::COrder::COrder(const CUnit::COrder &ths): Goal(ths.Goal), Range(ths.Range memcpy(&Arg1, &ths.Arg1, sizeof(Arg1)); - //FIXME: Hardcoded wood - if (Action == UnitActionResource && - CurrentResource != WoodCost && Arg1.Resource.Mine) { - Arg1.Resource.Mine->RefsIncrease(); + if (Action == UnitActionResource && Arg1.Resource.Mine) { + Arg1.Resource.Mine->RefsIncrease(); } } CUnit::COrder& CUnit::COrder::operator=(const CUnit::COrder &rhs) { if (this != &rhs) { - - //FIXME: Hardcoded wood - if (Action == UnitActionResource && - CurrentResource != WoodCost && Arg1.Resource.Mine) { - Arg1.Resource.Mine->RefsDecrease(); - } - Action = rhs.Action; Range = rhs.Range; MinRange = rhs.MinRange; @@ -172,8 +161,7 @@ CUnit::COrder& CUnit::COrder::operator=(const CUnit::COrder &rhs) { memcpy(&Arg1, &rhs.Arg1, sizeof(Arg1)); //FIXME: Hardcoded wood - if (Action == UnitActionResource && - CurrentResource != WoodCost && Arg1.Resource.Mine) { + if (Action == UnitActionResource && Arg1.Resource.Mine) { Arg1.Resource.Mine->RefsIncrease(); } } @@ -1555,8 +1543,26 @@ void CUnit::ChangeOwner(CPlayer &newplayer) UpdateForNewUnit(*this, 1); } +#ifdef DEBUG + +static bool IsMineAssignedBy(const CUnit &mine, const CUnit &worker) +{ + for (CUnit* it = mine.Data.Resource.Workers; it; it = it->NextWorker) { + if (it == &worker) { + return true; + } + } + return false; +} + +#endif + + void CUnit::AssignWorkerToMine(CUnit &mine) { + Assert(this->NextWorker == NULL); + Assert(IsMineAssignedBy(mine, *this) == false); + CUnit *head = mine.Data.Resource.Workers; /* DebugPrint("%d: Worker [%d] is adding into %s [%d] on %d pos\n" @@ -1573,6 +1579,7 @@ void CUnit::AssignWorkerToMine(CUnit &mine) void CUnit::DeAssignWorkerFromMine(CUnit &mine) { + Assert(IsMineAssignedBy(mine, *this) == true); CUnit *prev = NULL, *worker = mine.Data.Resource.Workers; /* DebugPrint("%d: Worker [%d] is removing from %s [%d] left %d units assigned\n" @@ -1581,10 +1588,11 @@ void CUnit::DeAssignWorkerFromMine(CUnit &mine) _C_ mine.Slot _C_ mine.Data.Resource.Assigned); */ - for(int i = 0; NULL != worker; worker = worker->NextWorker,++i) + for (int i = 0; NULL != worker; worker = worker->NextWorker, ++i) { if (worker == this) { CUnit *next = worker->NextWorker; + worker->NextWorker = NULL; if (prev) { prev->NextWorker = next; } @@ -3357,9 +3365,12 @@ void CleanUnits() int count = NumUnits; do { CUnit *unit = Units[count - 1]; + + if (unit == NULL) { + continue; + } if (!unit->Destroyed) { - if (//unit->Type->Harvester && - unit->CurrentAction() == UnitActionResource) { + if (unit->CurrentAction() == UnitActionResource) { ResourceInfo *resinfo = unit->Type->ResInfo[unit->CurrentResource]; if (resinfo && !resinfo->TerrainHarvester) { CUnit *mine = unit->CurrentOrder()->Arg1.Resource.Mine; @@ -3371,7 +3382,7 @@ void CleanUnits() } } unit->CurrentOrder()->ClearGoal(); - if(!unit->Removed) { + if (!unit->Removed) { unit->Remove(NULL); } UnitClearOrders(*unit); diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp index 285afbacb..ba9cfc208 100644 --- a/src/unit/unit_save.cpp +++ b/src/unit/unit_save.cpp @@ -183,19 +183,20 @@ void SaveOrder(const COrderPtr order, CFile *file) case UnitActionResource : case UnitActionReturnGoods : if (order->CurrentResource) { - file->printf(", \"current-resource\", \"%s\",", - DefaultResourceNames[order->CurrentResource].c_str()); - if(order->CurrentResource == WoodCost) { - file->printf(" \"resource-pos\", {%d, %d}", - order->Arg1.Resource.Pos.x, order->Arg1.Resource.Pos.y); + file->printf(", \"current-resource\", \"%s\",", DefaultResourceNames[order->CurrentResource].c_str()); + const CUnit *mine = order->Arg1.Resource.Mine; + + if (mine == NULL) { + const Vec2i &pos = order->Arg1.Resource.Pos; + + file->printf(" \"resource-pos\", {%d, %d}", pos.x, pos.y); } else { - if (order->Arg1.Resource.Mine->Destroyed) { + if (mine->Destroyed) { /* this unit is destroyed so it's not in the global unit * array - this means it won't be saved!!! */ printf ("FIXME: storing destroyed Mine - loading will fail.\n"); } - file->printf(" \"resource-mine\", \"%s\"", - UnitReference(*order->Arg1.Resource.Mine).c_str()); + file->printf(" \"resource-mine\", \"%s\"", UnitReference(*mine).c_str()); } } break;