/** ** Send unit to harvest resources ** ** @param unit pointer to unit. ** @param dest destination unit. ** @param flush if true, flush command queue. */ void CommandResource(CUnit &unit, CUnit &dest, int flush) { if (IsUnitValidForNetwork(unit) == false) { return ; } if (dest.Destroyed) { return ; } if (!unit.Type->Building && !unit.Type->Harvester) { ClearSavedAction(unit); return ; } COrderPtr *order; if (unit.Type->Building) { ClearNewAction(unit); order = &unit.NewOrder; } else { order = GetNextOrder(unit, flush); if (order == NULL) { return; } } *order = COrder::NewActionResource(unit, dest); ClearSavedAction(unit); }
/** ** Send unit to harvest resources ** ** @param unit pointer to unit. ** @param dest destination unit. ** @param flush if true, flush command queue. */ void CommandResource(CUnit *unit, CUnit *dest, int flush) { COrder *order; // // Check if unit is still valid and Goal still alive? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie && !dest->Destroyed) { // FIXME: more races, could happen with many orders in queue. if (!unit->Type->Building && !unit->Type->Harvester) { ClearSavedAction(unit); return; } // FIXME: if low-level supports searching, pass NoUnitP down. 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; order->Goal = dest; dest->RefsIncrease(); order->Range = 1; } ClearSavedAction(unit); }
/** ** Let unit returning goods. ** ** @param unit pointer to unit. ** @param goal bring goods to this depot. ** @param flush if true, flush command queue. */ void CommandReturnGoods(CUnit *unit, CUnit *goal, int flush) { COrder *order; // // Check if unit is still valid and Goal still alive? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // FIXME: more races, could happen with many orders in queue. if (!unit->Type->Building && !unit->Type->Harvester && !unit->ResourcesHeld) { ClearSavedAction(unit); return; } 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 = UnitActionReturnGoods; // // Destination could be killed. NETWORK! // if (goal && !goal->Destroyed) { order->Goal = goal; goal->RefsIncrease(); } order->Range = 1; } ClearSavedAction(unit); }
/** ** Send unit harvest a location ** ** @param unit pointer to unit. ** @param pos map position for harvest. ** @param flush if true, flush command queue. */ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush) { if (IsUnitValidForNetwork(unit) == false) { return ; } if (!unit.Type->Building && !unit.Type->BoolFlag[HARVESTER_INDEX].value) { ClearSavedAction(unit); return ; } //Wyrmgus start CMapField &mf = *Map.Field(unit.tilePos); if ((mf.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()) { CommandStopUnit(*table[i]); //always stop the raft if a new command is issued } } } //Wyrmgus end COrderPtr *order; if (unit.Type->Building) { ClearNewAction(unit); order = &unit.NewOrder; } else { order = GetNextOrder(unit, flush); if (order == NULL) { return; } } *order = COrder::NewActionResource(unit, pos); ClearSavedAction(unit); }
/** ** Cast a spell at position or unit. ** ** @param unit Pointer to unit. ** @param pos map position to spell cast on. ** @param dest Spell cast on unit (if exist). ** @param spell Spell type pointer. ** @param flush If true, flush command queue. */ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, const SpellType &spell, int flush, bool isAutocast) { DebugPrint(": %d casts %s at %d %d on %d\n" _C_ UnitNumber(unit) _C_ spell.Ident.c_str() _C_ pos.x _C_ pos.y _C_ dest ? UnitNumber(*dest) : 0); Assert(unit.Type->CanCastSpell[spell.Slot]); Assert(Map.Info.IsPointOnMap(pos)); if (IsUnitValidForNetwork(unit) == false) { return ; } //Wyrmgus start CMapField &mf = *Map.Field(unit.tilePos); if ((mf.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()) { CommandStopUnit(*table[i]); //always stop the raft if a new command is issued } } } //Wyrmgus end COrderPtr *order = GetNextOrder(unit, flush); if (order == NULL) { return; } *order = COrder::NewActionSpellCast(spell, pos, dest, true); ClearSavedAction(unit); }
/** ** Building starts training an unit. ** ** @param unit pointer to unit. ** @param type unit type to train. ** @param flush if true, flush command queue. */ void CommandTrainUnit(CUnit &unit, CUnitType &type, int) { if (IsUnitValidForNetwork(unit) == false) { return ; } // Check if enough resources remains? (NETWORK!) // FIXME: wrong if append to message queue!!! if (unit.Player->CheckLimits(type) < 0 || unit.Player->CheckUnitType(type)) { return; } // Not already training? if (!EnableTrainingQueue && unit.CurrentAction() == UnitActionTrain) { DebugPrint("Unit queue disabled!\n"); return; } const int noFlushCommands = 0; COrderPtr *order = GetNextOrder(unit, noFlushCommands); if (order == NULL) { return; } *order = COrder::NewActionTrain(unit, type); ClearSavedAction(unit); }
/** ** Cancel Building researching. ** ** @param unit Pointer to unit. */ void CommandCancelResearch(CUnit *unit) { ReleaseOrders(unit); // empty command queue // // Check if unit is still researching? (NETWORK!) // if (unit->Orders[0]->Action == UnitActionResearch) { const CUpgrade *upgrade; upgrade = unit->Data.Research.Upgrade; unit->Player->UpgradeTimers.Upgrades[upgrade->ID] = 0; unit->Player->AddCostsFactor(upgrade->Costs, CancelResearchCostsFactor); unit->Orders[0]->Init(); unit->Orders[0]->Action = UnitActionStill; unit->SubAction = 0; // // Update interface. // if (unit->Player == ThisPlayer && unit->Selected) { SelectedUnitChanged(); } } ClearSavedAction(unit); }
/** ** Building starts upgrading to. ** ** @param unit pointer to unit. ** @param type upgrade to type ** @param flush if true, flush command queue. */ void CommandUpgradeTo(CUnit *unit, CUnitType *type, int flush) { COrder *order; // // Check if unit is still valid and Goal still alive? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // // Check if enough resources remains? (NETWORK!) // if (unit->Player->CheckUnitType(type)) { return; } if (!flush) { DebugPrint("FIXME: must support order queing!!"); } if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); // FIXME: if you give quick an other order, the resources are lost! unit->Player->SubUnitType(type); order->Action = UnitActionUpgradeTo; order->Type = type; } ClearSavedAction(unit); }
/** ** Let an unit patrol from current to new position ** ** FIXME: want to support patroling between units. ** ** @param unit pointer to unit. ** @param x X map position to patrol between. ** @param y Y map position to patrol between. ** @param flush if true, flush command queue. */ void CommandPatrolUnit(CUnit *unit, int x, int y, int flush) { COrder *order; Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight); // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { if (!CanMove(unit)) { // 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 = UnitActionPatrol; order->X = x; order->Y = y; Assert(!(unit->X & ~0xFFFF) && !(unit->Y & ~0xFFFF)); order->Arg1.Patrol.X = unit->X; order->Arg1.Patrol.Y = unit->Y; } ClearSavedAction(unit); }
/** ** Cancel building upgrading to. ** ** @param unit pointer to unit. */ void CommandCancelUpgradeTo(CUnit *unit) { ReleaseOrders(unit); // empty command queue // // Check if unit is still upgrading? (NETWORK!) // if (unit->Orders[0]->Action == UnitActionUpgradeTo) { unit->Player->AddCostsFactor( unit->Orders[0]->Type->Stats[unit->Player->Index].Costs, CancelUpgradeCostsFactor); unit->Orders[0]->Init(); unit->Orders[0]->Action = UnitActionStill; unit->SubAction = 0; // // Update interface. // if (unit->Player == ThisPlayer && unit->Selected) { SelectedUnitChanged(); } } ClearSavedAction(unit); }
/** ** Attack ground with unit. ** ** @param unit pointer to unit. ** @param x X map position to fire on. ** @param y Y map position to fire on. ** @param flush if true, flush command queue. */ void CommandAttackGround(CUnit *unit, int x, int y, int flush) { COrder *order; Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight); // // 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 = UnitActionAttackGround; order->X = x; order->Y = y; order->Range = unit->Stats->Variables[ATTACKRANGE_INDEX].Max; order->MinRange = unit->Type->MinAttackRange; DebugPrint("FIXME this next\n"); } ClearSavedAction(unit); }
/** ** Unload a transporter. ** ** @param unit pointer to unit. ** @param x X map position to unload. ** @param y Y map position to unload. ** @param what unit to be unloaded, NoUnitP all. ** @param flush if true, flush command queue. */ void CommandUnload(CUnit *unit, int x, int y, CUnit *what, int flush) { COrder *order; // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); order->Action = UnitActionUnload; order->X = x; order->Y = y; // // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. // if (what && !what->Destroyed) { order->Goal = what; what->RefsIncrease(); } } ClearSavedAction(unit); }
/** ** Board a transporter with unit. ** ** @param unit pointer to unit. ** @param dest unit to be boarded. ** @param flush if true, flush command queue. */ void CommandBoard(CUnit *unit, CUnit *dest, int flush) { COrder *order; // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. // if (dest->Destroyed) { return; } 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 = UnitActionBoard; order->Goal = dest; dest->RefsIncrease(); order->Range = 1; } ClearSavedAction(unit); }
/** ** Attack with unit at new position ** ** @param unit pointer to unit. ** @param pos map position to attack. ** @param target or unit to be attacked. ** @param flush if true, flush command queue. */ void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *target, int flush) { Assert(Map.Info.IsPointOnMap(pos)); if (IsUnitValidForNetwork(unit) == false) { return ; } COrderPtr *order; if (!unit.Type->CanAttack) { ClearNewAction(unit); order = &unit.NewOrder; } else { order = GetNextOrder(unit, flush); if (order == NULL) { return; } } if (target && target->IsAlive()) { *order = COrder::NewActionAttack(unit, *target); } else { *order = COrder::NewActionAttack(unit, pos); } ClearSavedAction(unit); }
/** ** Cancel the training of an unit. ** ** @param unit pointer to unit. ** @param slot slot number to cancel. ** @param type Unit-type to cancel. */ void CommandCancelTraining(CUnit *unit, int slot, const CUnitType *type) { DebugPrint("Cancel %d type: %s\n" _C_ slot _C_ type ? type->Ident.c_str() : "-any-"); ClearSavedAction(unit); // // Check if unit is still training 'slot'? (NETWORK!) // if (slot == -1) { // Cancel All training while (unit->Orders[0]->Action == UnitActionTrain) { unit->Player->AddCostsFactor( unit->Orders[0]->Type->Stats[unit->Player->Index].Costs, CancelTrainingCostsFactor); RemoveOrder(unit, 0); } unit->Data.Train.Ticks = 0; if (unit->Player == ThisPlayer && unit->Selected) { SelectedUnitChanged(); } } else if (unit->OrderCount <= slot) { // Order has moved return; } else if (unit->Orders[slot]->Action != UnitActionTrain) { // Order has moved, we are not training return; } else if (unit->Orders[slot]->Action == UnitActionTrain) { // Still training this order, same unit? if (type && unit->Orders[slot]->Type != type) { // Different unit being trained return; } DebugPrint("Cancel training\n"); unit->Player->AddCostsFactor( unit->Orders[slot]->Type->Stats[unit->Player->Index].Costs, CancelTrainingCostsFactor); if (!slot) { // Canceled in work slot unit->Data.Train.Ticks = 0; } RemoveOrder(unit, slot); // // Update interface. // if (unit->Player == ThisPlayer && unit->Selected) { SelectedUnitChanged(); } } }
/** ** Stop unit. ** ** @param unit pointer to unit. */ void CommandStopUnit(CUnit &unit) { // Ignore that the unit could be removed. COrderPtr *order = GetNextOrder(unit, FlushCommands); // Flush them. Assert(order); Assert(*order == NULL); *order = COrder::NewActionStill(); ClearSavedAction(unit); ClearNewAction(unit); }
/** ** Cancel the building construction, or kill a unit. ** ** @param unit pointer to unit. */ void CommandDismiss(CUnit &unit) { // Check if building is still under construction? (NETWORK!) if (unit.CurrentAction() == UnitActionBuilt) { unit.CurrentOrder()->Cancel(unit); } else { DebugPrint("Suicide unit ... \n"); LetUnitDie(unit, true); } ClearSavedAction(unit); }
/** ** Cancel Building researching. ** ** @param unit Pointer to unit. */ void CommandCancelResearch(CUnit &unit) { // Check if unit is still researching? (NETWORK!) if (unit.CurrentAction() == UnitActionResearch) { unit.CurrentOrder()->Cancel(unit); RemoveOrder(unit, 0); if (!Selected.empty()) { SelectedUnitChanged(); } } ClearSavedAction(unit); }
/** ** Cancel building upgrading to. ** ** @param unit pointer to unit. */ void CommandCancelUpgradeTo(CUnit &unit) { // Check if unit is still upgrading? (NETWORK!) if (unit.CurrentAction() == UnitActionUpgradeTo) { unit.CurrentOrder()->Cancel(unit); RemoveOrder(unit, 0); if (Selected) { SelectedUnitChanged(); } } ClearSavedAction(unit); }
/** ** Unload a transporter. ** ** @param unit pointer to unit. ** @param pos map position to unload. ** @param what unit to be unloaded, NULL for all. ** @param flush if true, flush command queue. */ void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush) { if (IsUnitValidForNetwork(unit) == false) { return ; } COrderPtr *order = GetNextOrder(unit, flush); if (order == NULL) { return; } *order = COrder::NewActionUnload(pos, what); ClearSavedAction(unit); }
/** ** Cancel the building construction, or kill an unit. ** ** @param unit pointer to unit. */ void CommandDismiss(CUnit *unit) { // // Check if building is still under construction? (NETWORK!) // if (unit->Orders[0]->Action == UnitActionBuilt) { unit->Data.Built.Cancel = 1; } else { DebugPrint("Suicide unit ... \n"); LetUnitDie(unit); } ClearSavedAction(unit); }
/** ** Order an already formed Order structure ** ** @param unit pointer to unit ** @param cpyorder pointer to valid order ** @param flush if true, flush command queue. */ void CommandAnyOrder(CUnit *unit, COrder *cpyorder, int flush) { COrder *order; if (!(order = GetNextOrder(unit, flush))) { return; } *order = *cpyorder; if (order->Goal) { order->Goal->RefsIncrease(); } ClearSavedAction(unit); }
/** ** Attack with unit at new position ** ** @param unit pointer to unit. ** @param x X map position to attack. ** @param y Y map position to attack. ** @param attack or unit to be attacked. ** @param flush if true, flush command queue. */ void CommandAttack(CUnit *unit, int x, int y, CUnit *attack, int flush) { COrder *order; Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight); // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { if (!unit->Type->CanAttack) { // 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 = UnitActionAttack; if (attack) { // // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. // if (attack->Destroyed) { order->X = attack->X + attack->Type->TileWidth / 2; order->Y = attack->Y + attack->Type->TileHeight / 2; } else { // Removed, Dying handled by action routine. order->Goal = attack; attack->RefsIncrease(); order->Range = unit->Stats->Variables[ATTACKRANGE_INDEX].Max; order->MinRange = unit->Type->MinAttackRange; } } else if (Map.WallOnMap(x,y)) { // FIXME: look into action_attack.c about this ugly problem order->X = x; order->Y = y; order->Range = unit->Stats->Variables[ATTACKRANGE_INDEX].Max; order->MinRange = unit->Type->MinAttackRange; } else { order->X = x; order->Y = y; } } ClearSavedAction(unit); }
/** ** Let unit returning goods. ** ** @param unit pointer to unit. ** @param depot bring goods to this depot. ** @param flush if true, flush command queue. */ void CommandReturnGoods(CUnit &unit, CUnit *depot, int flush) { if (IsUnitValidForNetwork(unit) == false) { return ; } if ((unit.Type->BoolFlag[HARVESTER_INDEX].value && unit.ResourcesHeld == 0) || (!unit.Type->Building && !unit.Type->BoolFlag[HARVESTER_INDEX].value)) { ClearSavedAction(unit); return ; } COrderPtr *order; if (unit.Type->Building) { ClearNewAction(unit); order = &unit.NewOrder; } else { order = GetNextOrder(unit, flush); if (order == NULL) { return; } } *order = COrder::NewActionReturnGoods(unit, depot); ClearSavedAction(unit); }
/** ** Cast a spell at position or unit. ** ** @param unit Pointer to unit. ** @param x X map position to spell cast on. ** @param y Y map position to spell cast on. ** @param dest Spell cast on unit (if exist). ** @param spell Spell type pointer. ** @param flush If true, flush command queue. */ void CommandSpellCast(CUnit *unit, int x, int y, CUnit *dest, SpellType *spell, int flush) { COrder *order; Assert(x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight); DebugPrint(": %d casts %s at %d %d on %d\n" _C_ UnitNumber(unit) _C_ spell->Ident.c_str() _C_ x _C_ y _C_ dest ? UnitNumber(dest) : 0); Assert(unit->Type->CanCastSpell[spell->Slot]); // // Check if unit is still valid? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // FIXME: should I check here, if there is still enough mana? if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); order->Action = UnitActionSpellCast; order->Range = spell->Range; if (dest) { // // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. // if (dest->Destroyed) { // FIXME: where check if spell needs an unit as destination? // FIXME: dest->Type is now set to 0. maybe we shouldn't bother. order->X = dest->X /*+ dest->Type->TileWidth / 2*/ - order->Range; order->Y = dest->Y /*+ dest->Type->TileHeight / 2*/ - order->Range; order->Range <<= 1; } else { order->Goal = dest; dest->RefsIncrease(); } } else { order->X = x; order->Y = y; } order->Arg1.Spell = spell; } ClearSavedAction(unit); }
/** ** Stand ground. ** ** @param unit pointer to unit. ** @param flush if true, flush command queue. */ void CommandStandGround(CUnit &unit, int flush) { COrderPtr *order; if (unit.Type->Building) { ClearNewAction(unit); order = &unit.NewOrder; } else { order = GetNextOrder(unit, flush); if (order == NULL) { return; } } *order = COrder::NewActionStandGround(); ClearSavedAction(unit); }
/** ** Building starts researching. ** ** @param unit pointer to unit. ** @param what what to research. ** @param flush if true, flush command queue. */ void CommandResearch(CUnit &unit, CUpgrade &what, int flush) { if (IsUnitValidForNetwork(unit) == false) { return ; } // Check if enough resources remains? (NETWORK!) if (unit.Player->CheckCosts(what.Costs)) { return; } COrderPtr *order = GetNextOrder(unit, flush); if (order == NULL) { return; } *order = COrder::NewActionResearch(unit, what); ClearSavedAction(unit); }
/** ** Stand ground. ** ** @param unit pointer to unit. ** @param flush if true, flush command queue. */ void CommandStandGround(CUnit *unit, int flush) { COrder *order; // Ignore that the unit could be removed. 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 = UnitActionStandGround; ClearSavedAction(unit); }
/** ** 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); }
/** ** Building starts researching. ** ** @param unit pointer to unit. ** @param what what to research. ** @param flush if true, flush command queue. */ void CommandResearch(CUnit *unit, CUpgrade *what, int flush) { COrder *order; // // Check if unit is still valid and Goal still alive? (NETWORK!) // if (!unit->Removed && unit->Orders[0]->Action != UnitActionDie) { // // Check if enough resources remains? (NETWORK!) // if (unit->Player->CheckCosts(what->Costs)) { return; } if (!flush) { DebugPrint("FIXME: must support order queing!!"); } else { if (unit->Orders[0]->Action == UnitActionResearch) { const CUpgrade *upgrade; // Cancel current research upgrade = unit->Data.Research.Upgrade; unit->Player->UpgradeTimers.Upgrades[upgrade->ID] = 0; unit->Player->AddCostsFactor(upgrade->Costs, CancelResearchCostsFactor); unit->SubAction = 0; } } if (!(order = GetNextOrder(unit, flush))) { return; } order->Init(); // FIXME: if you give quick an other order, the resources are lost! unit->Player->SubCosts(what->Costs); order->Action = UnitActionResearch; order->X = order->Y = -1; order->Arg1.Upgrade = what; } ClearSavedAction(unit); }