diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index 50b7e3359..a98f5297e 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -147,7 +147,7 @@ static int CheckForTargetInRange(CUnit &unit) CUnit *goal = AttackUnitsInReactRange(unit); if (goal) { - CUnit::COrder *savedOrder = new CUnit::COrder(); + COrder *savedOrder = new COrder(); savedOrder->Action = order->Action; @@ -172,7 +172,7 @@ static int CheckForTargetInRange(CUnit &unit) CUnit *temp = AttackUnitsInReactRange(unit); if (temp && temp->Type->Priority > goal->Type->Priority) { - CUnit::COrder *savedOrder = new CUnit::COrder(*order); + COrder *savedOrder = new COrder(*order); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; @@ -330,7 +330,7 @@ static void AttackTarget(CUnit &unit) return; } // Save current command to come back. - CUnit::COrder *savedOrder = new CUnit::COrder(*order); + COrder *savedOrder = new COrder(*order); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; @@ -351,7 +351,7 @@ static void AttackTarget(CUnit &unit) if ((unit.SubAction & WEAK_TARGET)) { CUnit *temp = AttackUnitsInReactRange(unit); if (temp && temp->Type->Priority > goal->Type->Priority) { - CUnit::COrder *savedOrder = new CUnit::COrder(*order); + COrder *savedOrder = new COrder(*order); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; @@ -372,7 +372,7 @@ static void AttackTarget(CUnit &unit) // int dist = unit.MapDistanceTo(*goal); if (dist > unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { - CUnit::COrder *savedOrder = new CUnit::COrder(*order); + COrder *savedOrder = new COrder(*order); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; @@ -410,7 +410,7 @@ static void AttackTarget(CUnit &unit) ** ** @param unit Unit, for that the attack is handled. */ -void HandleActionAttack(CUnit::COrder& order, CUnit &unit) +void HandleActionAttack(COrder& order, CUnit &unit) { Assert(order.Action == UnitActionAttackGround || order.Action == UnitActionAttack); Assert(order.HasGoal() || Map.Info.IsPointOnMap(order.goalPos)); diff --git a/src/action/action_board.cpp b/src/action/action_board.cpp index db489465a..fc615ef83 100644 --- a/src/action/action_board.cpp +++ b/src/action/action_board.cpp @@ -175,7 +175,7 @@ static void EnterTransporter(CUnit &unit) ** ** @param unit Pointer to unit. */ -void HandleActionBoard(CUnit::COrder& order, CUnit &unit) +void HandleActionBoard(COrder& order, CUnit &unit) { switch (unit.SubAction) { // Wait for transporter diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp index 914a0bb90..b218d9543 100644 --- a/src/action/action_build.cpp +++ b/src/action/action_build.cpp @@ -408,7 +408,7 @@ static void BuildBuilding(CUnit &unit) ** ** @param unit Unit that builds a building */ -void HandleActionBuild(CUnit::COrder& /*order*/, CUnit &unit) +void HandleActionBuild(COrder& /*order*/, CUnit &unit) { CUnit *ontop; @@ -430,7 +430,7 @@ void HandleActionBuild(CUnit::COrder& /*order*/, CUnit &unit) ** ** @param unit Unit that is being built */ -void HandleActionBuilt(CUnit::COrder& order, CUnit &unit) +void HandleActionBuilt(COrder& order, CUnit &unit) { CUnit *worker; CUnitType *type; diff --git a/src/action/action_die.cpp b/src/action/action_die.cpp index 3ddefd8d3..44b712f8d 100644 --- a/src/action/action_die.cpp +++ b/src/action/action_die.cpp @@ -53,7 +53,7 @@ ** ** @param unit The unit which dies. */ -void HandleActionDie(CUnit::COrder& order, CUnit &unit) +void HandleActionDie(COrder& order, CUnit &unit) { Assert(order.Action == UnitActionDie); diff --git a/src/action/action_follow.cpp b/src/action/action_follow.cpp index 93ae4bdd7..3ac2cec38 100644 --- a/src/action/action_follow.cpp +++ b/src/action/action_follow.cpp @@ -58,7 +58,7 @@ ** ** @param unit Pointer to unit. */ -void HandleActionFollow(CUnit::COrder& order, CUnit &unit) +void HandleActionFollow(COrder& order, CUnit &unit) { if (unit.Wait) { unit.Wait--; @@ -186,7 +186,7 @@ void HandleActionFollow(CUnit::COrder& order, CUnit &unit) goal = AttackUnitsInReactRange(unit); if (goal) { // Save current command to come back. - CUnit::COrder *savedOrder = new CUnit::COrder(order); + COrder *savedOrder = new COrder(order); CommandAttack(unit, goal->tilePos, NULL, FlushCommands); diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 778b658d7..065201d76 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -172,7 +172,7 @@ int DoActionMove(CUnit &unit) ** ** @param unit Pointer to unit. */ -void HandleActionMove(CUnit::COrder& order, CUnit &unit) +void HandleActionMove(COrder& order, CUnit &unit) { CUnit *goal; diff --git a/src/action/action_patrol.cpp b/src/action/action_patrol.cpp index f182152a7..f1bbb4f78 100644 --- a/src/action/action_patrol.cpp +++ b/src/action/action_patrol.cpp @@ -75,7 +75,7 @@ static void SwapPatrolPoints(CUnit &unit) ** ** @param unit Patroling unit pointer. */ -void HandleActionPatrol(CUnit::COrder& order, CUnit &unit) +void HandleActionPatrol(COrder& order, CUnit &unit) { if (unit.Wait) { unit.Wait--; @@ -129,7 +129,7 @@ void HandleActionPatrol(CUnit::COrder& order, CUnit &unit) const CUnit *goal = AttackUnitsInReactRange(unit); if (goal) { // Save current command to come back. - CUnit::COrder *savedOrder = new CUnit::COrder(order); + COrder *savedOrder = new COrder(order); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/action/action_repair.cpp b/src/action/action_repair.cpp index 9b0b33ad7..c36bd7c6b 100644 --- a/src/action/action_repair.cpp +++ b/src/action/action_repair.cpp @@ -144,7 +144,7 @@ static int AnimateActionRepair(CUnit &unit) ** ** @param unit Unit, for that the attack is handled. */ -void HandleActionRepair(CUnit::COrder& order, CUnit &unit) +void HandleActionRepair(COrder& order, CUnit &unit) { CUnit *goal; int err; diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp index 333ecdf2e..a35318bd1 100644 --- a/src/action/action_research.cpp +++ b/src/action/action_research.cpp @@ -57,7 +57,7 @@ ** ** @param unit Pointer of researching unit. */ -void HandleActionResearch(CUnit::COrder& order, CUnit &unit) +void HandleActionResearch(COrder& order, CUnit &unit) { const CUpgrade *upgrade; diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp index f3c0c3817..6d35b96ba 100644 --- a/src/action/action_resource.cpp +++ b/src/action/action_resource.cpp @@ -885,7 +885,7 @@ static bool ActionResourceInit(CUnit &unit) ** ** @param unit Pointer to unit. */ -void HandleActionResource(CUnit::COrder& order, CUnit &unit) +void HandleActionResource(COrder& order, CUnit &unit) { if (unit.Wait) { // FIXME: show idle animation while we wait? diff --git a/src/action/action_returngoods.cpp b/src/action/action_returngoods.cpp index 29fbc1dd1..031422b02 100644 --- a/src/action/action_returngoods.cpp +++ b/src/action/action_returngoods.cpp @@ -55,7 +55,7 @@ ** ** @todo FIXME: move this into action_resource? */ -void HandleActionReturnGoods(CUnit::COrder& order, CUnit &unit) +void HandleActionReturnGoods(COrder& order, CUnit &unit) { Assert(unit.Type->Harvester); diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp index 269aa18ca..28468a363 100644 --- a/src/action/action_spellcast.cpp +++ b/src/action/action_spellcast.cpp @@ -135,7 +135,7 @@ static void SpellMoveToTarget(CUnit &unit) ** ** @param unit Unit, for that the spell cast is handled. */ -void HandleActionSpellCast(CUnit::COrder& order, CUnit &unit) +void HandleActionSpellCast(COrder& order, CUnit &unit) { if (unit.Wait) { unit.Wait--; diff --git a/src/action/action_stand.cpp b/src/action/action_stand.cpp index 270b70594..30a4136f8 100644 --- a/src/action/action_stand.cpp +++ b/src/action/action_stand.cpp @@ -48,7 +48,7 @@ ** ** @param unit Action handled for this unit pointer. */ -void HandleActionStandGround(CUnit::COrder& /*order*/, CUnit &unit) +void HandleActionStandGround(COrder& /*order*/, CUnit &unit) { ActionStillGeneric(unit, true); } diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp index 0d5e91dc2..a342b3535 100644 --- a/src/action/action_still.cpp +++ b/src/action/action_still.cpp @@ -244,7 +244,7 @@ bool AutoRepair(CUnit &unit) if (repairedUnit != NoUnitP) { const Vec2i invalidPos = {-1, -1}; - CUnit::COrder *savedOrder = new CUnit::COrder(*unit.CurrentOrder()); + COrder *savedOrder = new COrder(*unit.CurrentOrder()); //Command* will clear unit.SavedOrder CommandRepair(unit, invalidPos, repairedUnit, FlushCommands); @@ -272,7 +272,7 @@ static bool AutoAttack(CUnit &unit, bool stand_ground) if ((goal = AttackUnitsInReactRange(unit))) { // Weak goal, can choose other unit, come back after attack CommandAttack(unit, goal->tilePos, NULL, FlushCommands); - CUnit::COrder *savedOrder = new CUnit::COrder; + COrder *savedOrder = new COrder; savedOrder->Action = UnitActionAttack; savedOrder->Range = 0; @@ -316,7 +316,7 @@ void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground) if (goal) { // Weak goal, can choose other unit, come back after attack CommandAttack(unit, goal->tilePos, NULL, FlushCommands); - CUnit::COrder *savedOrder = new CUnit::COrder; + COrder *savedOrder = new COrder; savedOrder->Action = UnitActionAttack; savedOrder->Range = 0; @@ -399,7 +399,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground) ** ** @param unit Unit pointer for still action. */ -void HandleActionStill(CUnit::COrder& /*order*/, CUnit &unit) +void HandleActionStill(COrder& /*order*/, CUnit &unit) { ActionStillGeneric(unit, false); } diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp index b23690bb2..abff56de0 100644 --- a/src/action/action_train.cpp +++ b/src/action/action_train.cpp @@ -94,7 +94,7 @@ static bool CanHandleOrder(CUnit &unit, COrderPtr order) ** ** @param unit Unit that trains. */ -void HandleActionTrain(CUnit::COrder& order, CUnit &unit) +void HandleActionTrain(COrder& order, CUnit &unit) { // First entry if (!unit.SubAction) { diff --git a/src/action/action_unload.cpp b/src/action/action_unload.cpp index ce702fb87..f7452096f 100644 --- a/src/action/action_unload.cpp +++ b/src/action/action_unload.cpp @@ -323,7 +323,7 @@ static void LeaveTransporter(CUnit &transporter) ** ** @param unit Pointer to unit. */ -void HandleActionUnload(CUnit::COrder& order, CUnit &unit) +void HandleActionUnload(COrder& order, CUnit &unit) { const int maxSearchRange = 20; diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp index 3cbab84ef..e173b5f00 100644 --- a/src/action/action_upgradeto.cpp +++ b/src/action/action_upgradeto.cpp @@ -134,7 +134,7 @@ static int TransformUnitIntoType(CUnit &unit, CUnitType &newtype) ** ** @param unit Pointer to unit. */ -void HandleActionTransformInto(CUnit::COrder& order, CUnit &unit) +void HandleActionTransformInto(COrder& order, CUnit &unit) { // What to do if an error occurs ? TransformUnitIntoType(unit, *order.Arg1.Type); @@ -145,7 +145,7 @@ void HandleActionTransformInto(CUnit::COrder& order, CUnit &unit) ** ** @param unit Pointer to unit. */ -void HandleActionUpgradeTo(CUnit::COrder& order, CUnit &unit) +void HandleActionUpgradeTo(COrder& order, CUnit &unit) { if (!unit.SubAction) { // first entry order.Data.UpgradeTo.Ticks = 0; diff --git a/src/action/actions.cpp b/src/action/actions.cpp index 93e0d97c5..7825ff60b 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -39,12 +39,13 @@ #include <time.h> #include "stratagus.h" + +#include "actions.h" #include "video.h" #include "unittype.h" #include "animation.h" #include "player.h" #include "unit.h" -#include "actions.h" #include "missile.h" #include "interface.h" #include "map.h" @@ -61,6 +62,120 @@ unsigned SyncHash; /// Hash calculated to find sync failures -- Functions ----------------------------------------------------------------------------*/ +COrder::~COrder() { + if (Goal) { + Goal->RefsDecrease(); + Goal = NoUnitP; + } + if (Action == UnitActionResource && Arg1.Resource.Mine) { + Arg1.Resource.Mine->RefsDecrease(); + Arg1.Resource.Mine = NoUnitP; + } +} + +void COrder::ReleaseRefs(CUnit &unit) +{ + // Release pending references. + if (this->Action == UnitActionResource) { + CUnit *mine = this->Arg1.Resource.Mine; + + if (mine) { + unit.DeAssignWorkerFromMine(*mine); + mine->RefsDecrease(); + this->Arg1.Resource.Mine = NULL; + + } + } + if (this->HasGoal()) { + // If mining decrease the active count on the resource. + if (this->Action == UnitActionResource) { + if (unit.SubAction == 60 /* SUB_GATHER_RESOURCE */ ) { + CUnit *goal = this->GetGoal(); + + goal->CurrentOrder()->Data.Resource.Active--; + Assert(goal->CurrentOrder()->Data.Resource.Active >= 0); + } + } + // Still shouldn't have a reference unless attacking + Assert(!(this->Action == UnitActionStill && !unit.SubAction)); + this->ClearGoal(); + } +#ifdef DEBUG + else { + if (unit.CurrentResource && + !unit.Type->ResInfo[unit.CurrentResource]->TerrainHarvester) { + Assert(this->Action != UnitActionResource); + } + } +#endif +} + + + + + +COrder::COrder(const COrder &rhs): Goal(rhs.Goal), Range(rhs.Range), + MinRange(rhs.MinRange), Width(rhs.Width), Height(rhs.Height), + Action(rhs.Action), CurrentResource(rhs.CurrentResource), + goalPos(rhs.goalPos) + { + if (Goal) { + Goal->RefsIncrease(); + } + + memcpy(&Arg1, &rhs.Arg1, sizeof(Arg1)); + memcpy(&Data, &rhs.Data, sizeof (Data)); + if (Action == UnitActionResource && Arg1.Resource.Mine) { + Arg1.Resource.Mine->RefsIncrease(); + } +} + +COrder& COrder::operator=(const COrder &rhs) { + if (this != &rhs) { + Action = rhs.Action; + Range = rhs.Range; + MinRange = rhs.MinRange; + Width = rhs.Width; + Height = rhs.Height; + CurrentResource = rhs.CurrentResource; + SetGoal(rhs.Goal); + goalPos = rhs.goalPos; + memcpy(&Arg1, &rhs.Arg1, sizeof(Arg1)); + memcpy(&Data, &rhs.Data, sizeof (Data)); + //FIXME: Hardcoded wood + if (Action == UnitActionResource && Arg1.Resource.Mine) { + Arg1.Resource.Mine->RefsIncrease(); + } + } + return *this; +} + +void COrder::SetGoal(CUnit *const new_goal) +{ + if (new_goal) { + new_goal->RefsIncrease(); + } + if (Goal) { + Goal->RefsDecrease(); + } + Goal = new_goal; +} + +void COrder::ClearGoal() +{ + if (Goal) { + Goal->RefsDecrease(); + } + Goal = NULL; +} + + +bool COrder::CheckRange() const +{ + return (Range <= Map.Info.MapWidth || Range <= Map.Info.MapHeight); +} + + /*---------------------------------------------------------------------------- -- Animation @@ -255,7 +370,7 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale) ** ** @param unit Unit pointer for none action. */ -static void HandleActionNone(CUnit::COrder&, CUnit &unit) +static void HandleActionNone(COrder&, CUnit &unit) { DebugPrint("FIXME: Should not happen!\n"); DebugPrint("FIXME: Unit (%d) %s has action none.!\n" _C_ @@ -267,7 +382,7 @@ static void HandleActionNone(CUnit::COrder&, CUnit &unit) ** ** @param unit Unit pointer for not written action. */ -static void HandleActionNotWritten(CUnit::COrder&, CUnit &unit) +static void HandleActionNotWritten(COrder&, CUnit &unit) { DebugPrint("FIXME: Not written!\n"); DebugPrint("FIXME: Unit (%d) %s has action %d.!\n" _C_ @@ -279,7 +394,7 @@ static void HandleActionNotWritten(CUnit::COrder&, CUnit &unit) ** ** @note can move function into unit structure. */ -static void (*HandleActionTable[256])(CUnit::COrder&, CUnit &) = { +static void (*HandleActionTable[256])(COrder&, CUnit &) = { HandleActionNone, HandleActionStill, HandleActionStandGround, @@ -465,7 +580,7 @@ static void HandleBuffs(CUnit &unit, int amount) } } -static void RunAction(CUnit::COrder &order, CUnit &unit) +static void RunAction(COrder &order, CUnit &unit) { HandleActionTable[order.Action](order, unit); } diff --git a/src/action/command.cpp b/src/action/command.cpp index 8ee812ca4..5f4b9d1b6 100644 --- a/src/action/command.cpp +++ b/src/action/command.cpp @@ -224,7 +224,7 @@ void CommandStandGround(CUnit &unit, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -252,7 +252,7 @@ void CommandFollow(CUnit &unit, CUnit &dest, int flush) if (!unit.CanMove()) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -295,7 +295,7 @@ void CommandMove(CUnit &unit, const Vec2i &pos, int flush) if (!unit.CanMove()) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -326,7 +326,7 @@ void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -390,7 +390,7 @@ void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush) if (!unit.Type->CanAttack) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -444,7 +444,7 @@ void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -483,7 +483,7 @@ void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush) if (!unit.CanMove()) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -525,7 +525,7 @@ void CommandBoard(CUnit &unit, CUnit &dest, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -593,7 +593,7 @@ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int fl if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -659,7 +659,7 @@ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -714,7 +714,7 @@ void CommandResource(CUnit &unit, CUnit &dest, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -751,7 +751,7 @@ void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush) if (unit.Type->Building) { // FIXME: should find a better way for pending orders. delete unit.NewOrder; - unit.NewOrder = new CUnit::COrder; + unit.NewOrder = new COrder; order = unit.NewOrder; } else if (!(order = GetNextOrder(unit, flush))) { return; @@ -925,7 +925,7 @@ void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush) */ void CommandTransformIntoType(CUnit &unit, CUnitType &type) { - COrderPtr order = new CUnit::COrder; + COrderPtr order = new COrder; Assert(unit.CriticalOrder == NULL); diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 23527da01..61ebd620e 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -746,7 +746,7 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender) && CanTarget(aiunit->Type, attacker->Type)) { CommandAttack(*aiunit, attacker->tilePos, const_cast<CUnit*>(attacker), FlushCommands); if (aiunit->SavedOrder == NULL) { - CUnit::COrder *savedOrder = new CUnit::COrder; + COrder *savedOrder = new COrder; savedOrder->Action = UnitActionAttack; savedOrder->Range = 0; diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h index 9340a0c6a..5e9d18f02 100644 --- a/src/ai/ai_local.h +++ b/src/ai/ai_local.h @@ -271,7 +271,7 @@ public: public: CUnit *Unit; - CUnit::COrder Order; + COrder Order; }; /** diff --git a/src/include/actions.h b/src/include/actions.h index f5f3532aa..fd831f3a5 100644 --- a/src/include/actions.h +++ b/src/include/actions.h @@ -52,12 +52,161 @@ enum _diplomacy_ { DiplomacyCrazy /// Ally and attack opponent }; /// Diplomacy states for CommandDiplomacy +/** +** All possible unit actions. +** +** @note Always change the table ::HandleActionTable +** +** @see HandleActionTable +*/ +enum UnitAction { + UnitActionNone, /// No valid action + + UnitActionStill, /// unit stand still, does nothing + UnitActionStandGround, /// unit stands ground + UnitActionFollow, /// unit follows units + UnitActionMove, /// unit moves to position/unit + UnitActionAttack, /// unit attacks position/unit + UnitActionAttackGround, /// unit attacks ground + UnitActionDie, /// unit dies + + UnitActionSpellCast, /// unit casts spell + + UnitActionTrain, /// building is training + UnitActionUpgradeTo, /// building is upgrading itself + UnitActionResearch, /// building is researching spell + UnitActionBuilt, /// building is under construction + +// Compound actions + UnitActionBoard, /// unit entering transporter + UnitActionUnload, /// unit leaving transporter + UnitActionPatrol, /// unit paroling area + UnitActionBuild, /// unit builds building + + UnitActionRepair, /// unit repairing + UnitActionResource, /// unit harvesting resources + UnitActionReturnGoods, /// unit returning any resource + UnitActionTransformInto /// unit transform into type. +}; + +class CConstructionFrame; class CUnit; class CUnitType; class CUpgrade; class SpellType; class CAnimation; +/** +** Unit order structure. +*/ +class COrder +{ +public: + COrder() : Goal(NULL), Range(0), MinRange(0), Width(0), + Height(0), Action(UnitActionNone), CurrentResource(0) + { + goalPos.x = -1; + goalPos.y = -1; + memset(&Arg1, 0, sizeof (Arg1)); + memset(&Data, 0, sizeof (Data)); + } + COrder(const COrder &ths); + ~COrder(); + + void ReleaseRefs(CUnit &owner); + COrder& operator=(const COrder &rhs); + bool CheckRange() const; + + void Init() { + Assert(Action != UnitActionResource + || (Action == UnitActionResource && Arg1.Resource.Mine == NULL)); + Action = UnitActionNone; + Range = 0; + MinRange = 0; + Width = 0; + Height = 0; + CurrentResource = 0; + Assert(!Goal); + goalPos.x = -1; + goalPos.y = -1; + memset(&Arg1, 0, sizeof(Arg1)); + memset(&Data, 0, sizeof(Data)); + }; + + bool HasGoal() const { return Goal != NULL; } + CUnit * GetGoal() const { return Goal; }; + void SetGoal(CUnit *const new_goal); + void ClearGoal(); + +private: + friend void CclParseOrder(lua_State *l, const CUnit &unit, COrder* order); + + CUnit *Goal; +public: + int Range; /// How far away + unsigned int MinRange; /// How far away minimum + unsigned char Width; /// Goal Width (used when Goal is not) + unsigned char Height; /// Goal Height (used when Goal is not) + unsigned char Action; /// global action + unsigned char CurrentResource; //used in UnitActionResource and + //UnitActionReturnGoods + + Vec2i goalPos; /// or tile coordinate of destination + + union { + Vec2i Patrol; /// position for patroling. + struct { + Vec2i Pos; /// position for terrain resource. + CUnit *Mine; + } Resource; + SpellType *Spell; /// spell when casting. + CUpgrade *Upgrade; /// upgrade. + CUnitType *Type; /// Unit-type argument used mostly for traning/building, etc. + } Arg1; /// Extra command argument. + + union _order_data_ { + struct _order_move_ { + unsigned short int Cycles; /// how much Cycles we move. + char Fast; /// Flag fast move (one step) + char Length; /// stored path length +#define MAX_PATH_LENGTH 28 /// max length of precalculated path + char Path[MAX_PATH_LENGTH]; /// directions of stored path + } Move; /// ActionMove,... + struct _order_built_ { + CUnit *Worker; /// Worker building this unit + int Progress; /// Progress counter, in 1/100 cycles. + int Cancel; /// Cancel construction + CConstructionFrame *Frame; /// Construction frame + } Built; /// ActionBuilt,... + struct _order_build_ { + int Cycles; /// Cycles unit has been building for + } Build; /// ActionBuild + struct _order_resource_ { + CUnit *Workers; //pointer to first assigned worker to this resource. + int Assigned; /// how many units are assigned to harvesting from the resource. + int Active; /// how many units are harvesting from the resource. + } Resource; /// Resource still + struct _order_resource_worker_ { + int TimeToHarvest; /// how much time until we harvest some more. + unsigned DoneHarvesting:1; /// Harvesting done, wait for action to break. + } ResWorker; /// Worker harvesting + struct _order_repair_ { + int Cycles; /// Cycles unit has been repairing for + } Repair; /// Repairing unit + struct _order_research_ { + CUpgrade *Upgrade; /// Upgrade researched + } Research; /// Research action + struct _order_upgradeto_ { + int Ticks; /// Ticks to complete + } UpgradeTo; /// Upgrade to action + struct _order_train_ { + int Ticks; /// Ticks to complete + } Train; /// Train units action + } Data; /// Storage room for different commands +}; + + + /*---------------------------------------------------------------------------- -- Variables @@ -151,7 +300,7 @@ extern int GetNumWaitingWorkers(const CUnit &mine); extern void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground); extern void UnHideUnit(CUnit &unit); -typedef void HandleActionFunc(CUnit::COrder& order, CUnit &unit); +typedef void HandleActionFunc(COrder& order, CUnit &unit); /// Generic still action extern void ActionStillGeneric(CUnit &unit, bool stand_ground); diff --git a/src/include/unit.h b/src/include/unit.h index ca965f7a5..1b12b8584 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -365,12 +365,15 @@ #include "player.h" #endif +#include "actions.h" + #include "vec2i.h" /*---------------------------------------------------------------------------- -- Declarations ----------------------------------------------------------------------------*/ +class COrder; class CUnit; class CUnitType; class CUnitStats; @@ -432,43 +435,6 @@ extern int MapDistanceBetweenTypes(const CUnitType &src, const Vec2i &pos1, */ typedef unsigned short UnitRef; -/** -** All possible unit actions. -** -** @note Always change the table ::HandleActionTable -** -** @see HandleActionTable -*/ -typedef enum _unit_action_ { - UnitActionNone, /// No valid action - - UnitActionStill, /// unit stand still, does nothing - UnitActionStandGround, /// unit stands ground - UnitActionFollow, /// unit follows units - UnitActionMove, /// unit moves to position/unit - UnitActionAttack, /// unit attacks position/unit - UnitActionAttackGround, /// unit attacks ground - UnitActionDie, /// unit dies - - UnitActionSpellCast, /// unit casts spell - - UnitActionTrain, /// building is training - UnitActionUpgradeTo, /// building is upgrading itself - UnitActionResearch, /// building is researching spell - UnitActionBuilt, /// building is under construction - -// Compound actions - UnitActionBoard, /// unit entering transporter - UnitActionUnload, /// unit leaving transporter - UnitActionPatrol, /// unit paroling area - UnitActionBuild, /// unit builds building - - UnitActionRepair, /// unit repairing - UnitActionResource, /// unit harvesting resources - UnitActionReturnGoods, /// unit returning any resource - UnitActionTransformInto /// unit transform into type. -} UnitAction; - /** ** Voice groups for a unit */ @@ -512,203 +478,9 @@ enum _directions_ { /// The big unit structure class CUnit { public: - - /** - ** Unit order structure. - */ - class COrder - { - public: - COrder() : Goal(NULL), Range(0), MinRange(0), Width(0), - Height(0), Action(UnitActionNone), CurrentResource(0) - { - goalPos.x = -1; - goalPos.y = -1; - memset(&Arg1, 0, sizeof (Arg1)); - memset(&Data, 0, sizeof (Data)); - } - COrder(const COrder &ths); - ~COrder(); - - void ReleaseRefs(CUnit &owner); - COrder& operator=(const COrder &rhs); - bool CheckRange() const; - - void Init() { - Assert(Action != UnitActionResource - || (Action == UnitActionResource && Arg1.Resource.Mine == NULL)); - Action = UnitActionNone; - Range = 0; - MinRange = 0; - Width = 0; - Height = 0; - CurrentResource = 0; - Assert(!Goal); - goalPos.x = -1; - goalPos.y = -1; - memset(&Arg1, 0, sizeof(Arg1)); - memset(&Data, 0, sizeof(Data)); - }; - - bool HasGoal() const { return Goal != NULL; } - - CUnit * GetGoal() const { return Goal; }; - - void SetGoal(CUnit *const new_goal) - { - if (new_goal) { - new_goal->RefsIncrease(); - } - if (Goal) { - Goal->RefsDecrease(); - } - Goal = new_goal; - } - - void ClearGoal() - { - if (Goal) { - Goal->RefsDecrease(); - } - Goal = NULL; - } - - private: - friend void CclParseOrder(lua_State *l, const CUnit &unit, COrder* order); - - CUnit *Goal; - public: - int Range; /// How far away - unsigned int MinRange; /// How far away minimum - unsigned char Width; /// Goal Width (used when Goal is not) - unsigned char Height; /// Goal Height (used when Goal is not) - unsigned char Action; /// global action - unsigned char CurrentResource; //used in UnitActionResource and - //UnitActionReturnGoods - - Vec2i goalPos; /// or tile coordinate of destination - - union { - Vec2i Patrol; /// position for patroling. - struct { - Vec2i Pos; /// position for terrain resource. - CUnit *Mine; - } Resource; - SpellType *Spell; /// spell when casting. - CUpgrade *Upgrade; /// upgrade. - CUnitType *Type; /// Unit-type argument used mostly for traning/building, etc. - } Arg1; /// Extra command argument. - - union _order_data_ { - struct _order_move_ { - unsigned short int Cycles; /// how much Cycles we move. - char Fast; /// Flag fast move (one step) - char Length; /// stored path length - #define MAX_PATH_LENGTH 28 /// max length of precalculated path - char Path[MAX_PATH_LENGTH]; /// directions of stored path - } Move; /// ActionMove,... - struct _order_built_ { - CUnit *Worker; /// Worker building this unit - int Progress; /// Progress counter, in 1/100 cycles. - int Cancel; /// Cancel construction - CConstructionFrame *Frame; /// Construction frame - } Built; /// ActionBuilt,... - struct _order_build_ { - int Cycles; /// Cycles unit has been building for - } Build; /// ActionBuild - struct _order_resource_ { - CUnit *Workers; //pointer to first assigned worker to this resource. - int Assigned; /// how many units are assigned to harvesting from the resource. - int Active; /// how many units are harvesting from the resource. - } Resource; /// Resource still - struct _order_resource_worker_ { - int TimeToHarvest; /// how much time until we harvest some more. - unsigned DoneHarvesting:1; /// Harvesting done, wait for action to break. - } ResWorker; /// Worker harvesting - struct _order_repair_ { - int Cycles; /// Cycles unit has been repairing for - } Repair; /// Repairing unit - struct _order_research_ { - CUpgrade *Upgrade; /// Upgrade researched - } Research; /// Research action - struct _order_upgradeto_ { - int Ticks; /// Ticks to complete - } UpgradeTo; /// Upgrade to action - struct _order_train_ { - int Ticks; /// Ticks to complete - } Train; /// Train units action - } Data; /// Storage room for different commands - }; - CUnit() : SavedOrder(NULL), NewOrder(NULL), CriticalOrder(NULL) { Init(); } - void Init() { - Refs = 0; - Slot = 0; - UnitSlot = NULL; - PlayerSlot = NULL; - Next = NULL; - InsideCount = 0; - BoardCount = 0; - UnitInside = NULL; - Container = NULL; - NextContained = NULL; - PrevContained = NULL; - NextWorker = NULL; - tilePos.x = 0; - tilePos.y = 0; - Offset = 0; - Type = NULL; - Player = NULL; - Stats = NULL; - CurrentSightRange = 0; - Colors = NULL; - IX = 0; - IY = 0; - Frame = 0; - Direction = 0; - DamagedType = ANIMATIONS_DEATHTYPES; - Attacked = 0; - Burning = 0; - Destroyed = 0; - Removed = 0; - Selected = 0; - TeamSelected = 0; - Constructed = 0; - Active = 0; - Boarded = 0; - RescuedFrom = NULL; - memset(VisCount, 0, sizeof(VisCount)); - memset(&Seen, 0, sizeof(Seen)); - Variable = NULL; - TTL = 0; - GroupId = 0; - LastGroup = 0; - ResourcesHeld = 0; - SubAction = 0; - Wait = 0; - State = 0; - Blink = 0; - Moving = 0; - ReCast = 0; - CacheLock = 0; - GuardLock = 0; - memset(&Anim, 0, sizeof(Anim)); - CurrentResource = 0; - OrderCount = 0; - OrderFlush = 0; - Orders.clear(); - delete SavedOrder; - SavedOrder = NULL; - delete NewOrder; - NewOrder = NULL; - delete CriticalOrder; - CriticalOrder = NULL; - AutoCastSpell = NULL; - AutoRepair = 0; - Goal = NULL; - } - + void Init(); // @note int is faster than shorts unsigned int Refs; /// Reference counter int Slot; /// Assigned slot number @@ -817,24 +589,15 @@ public: CUnit *Goal; /// Generic/Teleporter goal pointer - COrder * CreateOrder() { - Orders.push_back(new COrder); - return Orders[(int)OrderCount++]; - } + COrder *CreateOrder(); COrder *CurrentOrder() const { return Orders[0]; } - UnitAction CurrentAction() const { return (UnitAction)(CurrentOrder()->Action); } + unsigned int CurrentAction() const; - bool IsIdle() const { return OrderCount == 1 && CurrentAction() == UnitActionStill; } + bool IsIdle() const; - inline void ClearAction() { - CurrentOrder()->Action = UnitActionStill; - SubAction = 0; - if (Selected) { - SelectedUnitChanged(); - } - } + void ClearAction(); inline int GetReactRange() const { @@ -874,7 +637,7 @@ public: void Release(bool final = false); bool RestoreOrder(); - bool StoreOrder(CUnit::COrder* order); + bool StoreOrder(COrder* order); // Cowards and invisible units don't attack unless ordered. bool IsAgressive() const @@ -898,10 +661,7 @@ public: ** ** @return True if alive, false otherwise. */ - inline bool IsAlive() const - { - return !Destroyed && CurrentAction() != UnitActionDie; - } + bool IsAlive() const; /** ** Returns true if unit is alive and on the map. @@ -1009,22 +769,14 @@ public: ** Test if unit can move. ** For the moment only check for move animation. ** - ** @return 0 if unit cannot move. + ** @return true if unit cann move. */ - bool CanMove() const - { - return Type->CanMove(); - } - - int GetDrawLevel() const - { - return ((Type->CorpseType && CurrentAction() == UnitActionDie) ? - Type->CorpseType->DrawLevel : Type->DrawLevel); - } + bool CanMove() const { return Type->CanMove(); } + int GetDrawLevel() const; }; -typedef CUnit::COrder* COrderPtr; +typedef COrder* COrderPtr; class CUnitPtr { CUnit *unit; @@ -1351,7 +1103,7 @@ extern int CanTransport(const CUnit &transporter, const CUnit &unit); /// Generate a unit reference, a printable unique string for unit extern std::string UnitReference(const CUnit &unit); /// Save an order -extern void SaveOrder(const CUnit::COrder &order, const CUnit &unit, CFile *file); +extern void SaveOrder(const COrder &order, const CUnit &unit, CFile *file); /// save unit-structure extern void SaveUnit(const CUnit &unit, CFile *file); /// save all units diff --git a/src/stratagus/groups.cpp b/src/stratagus/groups.cpp index 1bda07c94..30da49b5c 100644 --- a/src/stratagus/groups.cpp +++ b/src/stratagus/groups.cpp @@ -307,7 +307,7 @@ void GroupHelpMe(CUnit *attacker, CUnit &defender) && CanTarget(gunit.Type, attacker->Type)) { CommandAttack(gunit, attacker->tilePos, attacker, FlushCommands); if (gunit.SavedOrder == NULL) { - CUnit::COrder *savedOrder = new CUnit::COrder; + COrder *savedOrder = new COrder; savedOrder->Action = UnitActionAttack; savedOrder->goalPos = gunit.tilePos; diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 599c162d9..59a29724d 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -883,17 +883,17 @@ static int CclUnit(lua_State *l) } } else if (!strcmp(value, "critical-order")) { lua_pushvalue(l, j + 1); - unit->CriticalOrder = new CUnit::COrder; + unit->CriticalOrder = new COrder; CclParseOrder(l, *unit , unit->CriticalOrder); lua_pop(l, 1); } else if (!strcmp(value, "saved-order")) { lua_pushvalue(l, j + 1); - unit->SavedOrder = new CUnit::COrder; + unit->SavedOrder = new COrder; CclParseOrder(l, *unit, unit->SavedOrder); lua_pop(l, 1); } else if (!strcmp(value, "new-order")) { lua_pushvalue(l, j + 1); - unit->NewOrder = new CUnit::COrder; + unit->NewOrder = new COrder; CclParseOrder(l, *unit, unit->NewOrder); lua_pop(l, 1); } else if (!strcmp(value, "goal")) { diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 0d286762f..f43b7a99c 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -121,97 +121,72 @@ void CUnit::RefsDecrease() } } -CUnit::COrder::~COrder() { - if (Goal) { - Goal->RefsDecrease(); - Goal = NoUnitP; - } - if (Action == UnitActionResource && Arg1.Resource.Mine) { - Arg1.Resource.Mine->RefsDecrease(); - Arg1.Resource.Mine = NoUnitP; - } -} - -void CUnit::COrder::ReleaseRefs(CUnit &unit) +void CUnit::Init() { - // Release pending references. - if (this->Action == UnitActionResource) { - CUnit *mine = this->Arg1.Resource.Mine; - - if (mine) { - unit.DeAssignWorkerFromMine(*mine); - mine->RefsDecrease(); - this->Arg1.Resource.Mine = NULL; - - } - } - if (this->HasGoal()) { - // If mining decrease the active count on the resource. - if (this->Action == UnitActionResource) { - if (unit.SubAction == 60 /* SUB_GATHER_RESOURCE */ ) { - CUnit *goal = this->GetGoal(); - - goal->CurrentOrder()->Data.Resource.Active--; - Assert(goal->CurrentOrder()->Data.Resource.Active >= 0); - } - } - // Still shouldn't have a reference unless attacking - Assert(!(this->Action == UnitActionStill && !unit.SubAction)); - this->ClearGoal(); - } -#ifdef DEBUG - else { - if (unit.CurrentResource && - !unit.Type->ResInfo[unit.CurrentResource]->TerrainHarvester) { - Assert(this->Action != UnitActionResource); - } - } -#endif -} - - - - - -CUnit::COrder::COrder(const CUnit::COrder &rhs): Goal(rhs.Goal), Range(rhs.Range), - MinRange(rhs.MinRange), Width(rhs.Width), Height(rhs.Height), - Action(rhs.Action), CurrentResource(rhs.CurrentResource), - goalPos(rhs.goalPos) - { - if (Goal) { - Goal->RefsIncrease(); - } - - memcpy(&Arg1, &rhs.Arg1, sizeof(Arg1)); - memcpy(&Data, &rhs.Data, sizeof (Data)); - if (Action == UnitActionResource && Arg1.Resource.Mine) { - Arg1.Resource.Mine->RefsIncrease(); - } -} - -CUnit::COrder& CUnit::COrder::operator=(const CUnit::COrder &rhs) { - if (this != &rhs) { - Action = rhs.Action; - Range = rhs.Range; - MinRange = rhs.MinRange; - Width = rhs.Width; - Height = rhs.Height; - CurrentResource = rhs.CurrentResource; - SetGoal(rhs.Goal); - goalPos = rhs.goalPos; - memcpy(&Arg1, &rhs.Arg1, sizeof(Arg1)); - memcpy(&Data, &rhs.Data, sizeof (Data)); - //FIXME: Hardcoded wood - if (Action == UnitActionResource && Arg1.Resource.Mine) { - Arg1.Resource.Mine->RefsIncrease(); - } - } - return *this; -} - -bool CUnit::COrder::CheckRange() const -{ - return (Range <= Map.Info.MapWidth || Range <= Map.Info.MapHeight); + Refs = 0; + Slot = 0; + UnitSlot = NULL; + PlayerSlot = NULL; + Next = NULL; + InsideCount = 0; + BoardCount = 0; + UnitInside = NULL; + Container = NULL; + NextContained = NULL; + PrevContained = NULL; + NextWorker = NULL; + tilePos.x = 0; + tilePos.y = 0; + Offset = 0; + Type = NULL; + Player = NULL; + Stats = NULL; + CurrentSightRange = 0; + Colors = NULL; + IX = 0; + IY = 0; + Frame = 0; + Direction = 0; + DamagedType = ANIMATIONS_DEATHTYPES; + Attacked = 0; + Burning = 0; + Destroyed = 0; + Removed = 0; + Selected = 0; + TeamSelected = 0; + Constructed = 0; + Active = 0; + Boarded = 0; + RescuedFrom = NULL; + memset(VisCount, 0, sizeof(VisCount)); + memset(&Seen, 0, sizeof(Seen)); + Variable = NULL; + TTL = 0; + GroupId = 0; + LastGroup = 0; + ResourcesHeld = 0; + SubAction = 0; + Wait = 0; + State = 0; + Blink = 0; + Moving = 0; + ReCast = 0; + CacheLock = 0; + GuardLock = 0; + memset(&Anim, 0, sizeof(Anim)); + CurrentResource = 0; + OrderCount = 0; + OrderFlush = 0; + Orders.clear(); + delete SavedOrder; + SavedOrder = NULL; + delete NewOrder; + NewOrder = NULL; + delete CriticalOrder; + CriticalOrder = NULL; + AutoCastSpell = NULL; + AutoRepair = 0; + Goal = NULL; } @@ -280,6 +255,46 @@ void CUnit::Release(bool final) UnitManager.ReleaseUnit(this); } + +COrder *CUnit::CreateOrder() +{ + Orders.push_back(new COrder); + return Orders[(int)OrderCount++]; +} + +unsigned int CUnit::CurrentAction() const +{ + return (CurrentOrder()->Action); +} + +void CUnit::ClearAction() +{ + CurrentOrder()->Action = UnitActionStill; + SubAction = 0; + if (Selected) { + SelectedUnitChanged(); + } +} + + +bool CUnit::IsIdle() const +{ + return OrderCount == 1 && CurrentAction() == UnitActionStill; +} + +bool CUnit::IsAlive() const +{ + return !Destroyed && CurrentAction() != UnitActionDie; +} + +int CUnit::GetDrawLevel() const +{ + return ((Type->CorpseType && CurrentAction() == UnitActionDie) ? + Type->CorpseType->DrawLevel : Type->DrawLevel); +} + + + /** ** Initialize the unit slot with default values. ** @@ -380,7 +395,7 @@ bool CUnit::RestoreOrder() ** ** @return True if the current order was saved */ -bool CUnit::StoreOrder(CUnit::COrder* order) +bool CUnit::StoreOrder(COrder* order) { Assert(order); Assert(order->HasGoal() || Map.Info.IsPointOnMap(order->goalPos)); @@ -3002,7 +3017,7 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage) } if (goal) { if (target.SavedOrder == NULL) { - CUnit::COrder* savedOrder = new CUnit::COrder; + COrder* savedOrder = new COrder; savedOrder->Action = UnitActionAttack; savedOrder->goalPos = target.tilePos; diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp index 92d3837bb..8e09f6c72 100644 --- a/src/unit/unit_save.cpp +++ b/src/unit/unit_save.cpp @@ -68,7 +68,7 @@ std::string UnitReference(const CUnit &unit) ** @param unit Order behave to this unit. ** @param file Output file. */ -void SaveOrder(const CUnit::COrder &order, const CUnit &unit, CFile *file) +void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) { file->printf("{"); switch (order.Action) {