From 5d4ddd2508665e089997a620c1b1f399fb891da0 Mon Sep 17 00:00:00 2001 From: joris <joris.dauphin@gmail.com> Date: Fri, 17 Feb 2012 09:05:42 +0100 Subject: [PATCH] Create specific "construtor" for each order. --- src/action/action_attack.cpp | 8 +- src/action/action_patrol.cpp | 7 +- src/action/action_still.cpp | 12 +- src/action/actions.cpp | 339 ++++++++++++++ src/action/command.cpp | 871 ++++++++++++----------------------- src/ai/ai.cpp | 6 +- src/include/actions.h | 36 +- src/include/unit.h | 2 - src/stratagus/groups.cpp | 6 +- src/unit/script_unit.cpp | 9 +- src/unit/unit.cpp | 34 +- 11 files changed, 681 insertions(+), 649 deletions(-) diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index d3ecf310c..97e76fb67 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -147,13 +147,7 @@ static int CheckForTargetInRange(CUnit &unit) CUnit *goal = AttackUnitsInReactRange(unit); if (goal) { - COrder *savedOrder = new COrder(); - - savedOrder->Action = order->Action; - - savedOrder->MinRange = 0;//order->MinRange; - savedOrder->Range = 0;//order->Range; - savedOrder->goalPos = order->goalPos; + COrder *savedOrder = COrder::NewActionAttack(unit, order->goalPos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/action/action_patrol.cpp b/src/action/action_patrol.cpp index 2218d0ca0..3124199ec 100644 --- a/src/action/action_patrol.cpp +++ b/src/action/action_patrol.cpp @@ -131,15 +131,14 @@ void HandleActionPatrol(COrder& order, CUnit &unit) // Save current command to come back. COrder *savedOrder = new COrder(order); + DebugPrint("Patrol attack %d\n" _C_ UnitNumber(*goal)); + CommandAttack(unit, goal->tilePos, NULL, FlushCommands); + if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } unit.ClearAction(); - unit.CurrentOrder()->ClearGoal(); - - DebugPrint("Patrol attack %d\n" _C_ UnitNumber(*goal)); - CommandAttack(unit, goal->tilePos, NULL, FlushCommands); return; } } diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp index a342b3535..67110c70f 100644 --- a/src/action/action_still.cpp +++ b/src/action/action_still.cpp @@ -272,11 +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); - COrder *savedOrder = new COrder; - - savedOrder->Action = UnitActionAttack; - savedOrder->Range = 0; - savedOrder->goalPos = unit.tilePos; + COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; @@ -316,11 +312,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); - COrder *savedOrder = new COrder; - - savedOrder->Action = UnitActionAttack; - savedOrder->Range = 0; - savedOrder->goalPos = unit.tilePos; + COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/action/actions.cpp b/src/action/actions.cpp index 44c2cdc8e..13c0d7155 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -82,6 +82,345 @@ COrder::COrder(const COrder &rhs): Goal(rhs.Goal), Range(rhs.Range), } } + + +/* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target) +{ + COrder *order = new COrder; + + order->Action = UnitActionAttack; + + if (target.Destroyed) { + order->goalPos = target.tilePos + target.Type->GetHalfTileSize(); + } else { + // Removed, Dying handled by action routine. + order->SetGoal(&target); + order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max; + order->MinRange = attacker.Type->MinAttackRange; + } + return order; +} + +/* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, const Vec2i &dest) +{ + Assert(Map.Info.IsPointOnMap(dest)); + + COrder *order = new COrder; + + order->Action = UnitActionAttack; + + if (Map.WallOnMap(dest) && Map.IsFieldExplored(*attacker.Player, dest)) { + // FIXME: look into action_attack.cpp about this ugly problem + order->goalPos = dest; + order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max; + order->MinRange = attacker.Type->MinAttackRange; + } else { + order->goalPos = dest; + } + return order; +} + +/* static */ COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest) +{ + COrder *order = new COrder; + + order->Action = UnitActionAttackGround; + order->goalPos = dest; + order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max; + order->MinRange = attacker.Type->MinAttackRange; + + return order; +} + + +/* static */ COrder* COrder::NewActionBoard(CUnit &unit) +{ + COrder *order = new COrder; + + order->Action = UnitActionBoard; + order->SetGoal(&unit); + order->Range = 1; + + return order; +} + + +/* static */ COrder* COrder::NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building) +{ + COrder *order = new COrder; + + order->Action = UnitActionBuild; + + order->goalPos = pos; + order->Width = building.TileWidth; + order->Height = building.TileHeight; + if (building.BuilderOutside) { + order->Range = builder.Type->RepairRange; + } else { + // If building inside, but be next to stop + if (building.ShoreBuilding && builder.Type->UnitType == UnitTypeLand) { + // Peon won't dive :-) + order->Range = 1; + } + } + order->Arg1.Type = &building; + if (building.BuilderOutside) { + order->MinRange = 1; + } + return order; +} + +/* static */ COrder* COrder::NewActionBuilt() +{ + COrder *order = new COrder; + + order->Action = UnitActionBuilt; + return order; +} + +/* static */ COrder* COrder::NewActionDie() +{ + COrder *order = new COrder; + + order->Action = UnitActionDie; + return order; +} + +/* static */ COrder* COrder::NewActionFollow(CUnit &dest) +{ + COrder *order = new COrder; + + order->Action = UnitActionFollow; + // Destination could be killed. + // Should be handled in action, but is not possible! + // Unit::Refs is used as timeout counter. + if (dest.Destroyed) { + order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize(); + } else { + order->SetGoal(&dest); + order->Range = 1; + } + + return order; +} + + +/* static */ COrder* COrder::NewActionMove(const Vec2i &pos) +{ + COrder *order = new COrder; + + order->Action = UnitActionMove; + order->goalPos = pos; + + return order; +} + + +/* static */ COrder* COrder::NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest) +{ + Assert(Map.Info.IsPointOnMap(currentPos)); + Assert(Map.Info.IsPointOnMap(dest)); + + COrder *order = new COrder; + + order->Action = UnitActionPatrol; + order->goalPos = dest; + order->Arg1.Patrol = currentPos; + + return order; +} + +/* static */ COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target) +{ + COrder *order = new COrder; + + order->Action = UnitActionRepair; + if (target.Destroyed) { + order->goalPos = target.tilePos + target.Type->GetHalfTileSize(); + } else { + order->SetGoal(&target); + order->Range = unit.Type->RepairRange; + } + return order; +} + +/* static */ COrder* COrder::NewActionRepair(const Vec2i &pos) +{ + Assert(Map.Info.IsPointOnMap(pos)); + + COrder *order = new COrder; + + order->Action = UnitActionRepair; + order->goalPos = pos; + return order; +} + + + +/* static */ COrder* COrder::NewActionResearch(CUnit &unit, CUpgrade &upgrade) +{ + COrder *order = new COrder; + + order->Action = UnitActionResearch; + + // FIXME: if you give quick an other order, the resources are lost! + unit.Player->SubCosts(upgrade.Costs); + + order->Arg1.Upgrade = &upgrade; + + return order; +} + +/* static */ COrder* COrder::NewActionResource(CUnit &harvester, const Vec2i &pos) +{ + COrder *order = new COrder; + Vec2i ressourceLoc; + + order->Action = UnitActionResource; + + // Find the closest piece of wood next to a tile where the unit can move + if (!FindTerrainType(0, (harvester.Type->MovementMask), 1, 20, harvester.Player, pos, &ressourceLoc)) { + DebugPrint("FIXME: Give up???\n"); + } + // Max Value > 1 + if ((MyAbs(ressourceLoc.x - pos.x) | MyAbs(ressourceLoc.y - pos.y)) > 1) { + if (!FindTerrainType(0, MapFieldForest, 0, 20, harvester.Player, ressourceLoc, &ressourceLoc)) { + DebugPrint("FIXME: Give up???\n"); + } + } else { + // The destination is next to a reachable tile. + ressourceLoc = pos; + } + order->goalPos = ressourceLoc; + order->Range = 1; + + return order; +} + +/* static */ COrder* COrder::NewActionResource(CUnit &mine) +{ + COrder *order = new COrder; + + order->Action = UnitActionResource; + order->SetGoal(&mine); + order->Range = 1; + + return order; +} + + + +/* static */ COrder* COrder::NewActionReturnGoods(CUnit *depot) +{ + COrder *order = new COrder; + + order->Action = UnitActionReturnGoods; + // Destination could be killed. NETWORK! + if (depot && !depot->Destroyed) { + order->SetGoal(depot); + } + order->Range = 1; + + return order; +} + +/* static */ COrder* COrder::NewActionSpellCast(SpellType &spell, const Vec2i &pos, CUnit *target) +{ + COrder *order = new COrder; + + order->Action = UnitActionSpellCast; + + order->Range = spell.Range; + if (target) { + // Destination could be killed. + // Should be handled in action, but is not possible! + // Unit::Refs is used as timeout counter. + if (target->Destroyed) { + // FIXME: where check if spell needs a unit as destination? + // FIXME: target->Type is now set to 0. maybe we shouldn't bother. + const Vec2i diag = {order->Range, order->Range}; + order->goalPos = target->tilePos /* + target->Type->GetHalfTileSize() */ - diag; + order->Range <<= 1; + } else { + order->SetGoal(target); + } + } else { + order->goalPos = pos; + } + order->Arg1.Spell = &spell; + + return order; +} + +/* static */ COrder* COrder::NewActionStandGround() +{ + COrder *order = new COrder; + + order->Action = UnitActionStandGround; + return order; +} + + +/* static */ COrder* COrder::NewActionStill() +{ + COrder *order = new COrder; + + order->Action = UnitActionStill; + return order; +} + + + + +/* static */ COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type) +{ + COrder *order = new COrder; + + order->Action = UnitActionTrain; + order->Arg1.Type = &type; + // FIXME: if you give quick an other order, the resources are lost! + trainer.Player->SubUnitType(type); + + return order; +} + +/* static */ COrder* COrder::NewActionTransformInto(CUnitType &type) +{ + COrder *order = new COrder; + + order->Action = UnitActionTransformInto; + + order->Arg1.Type = &type; + + return order; +} + +/* static */ COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what) +{ + COrder *order = new COrder; + + order->Action = UnitActionUnload; + order->goalPos = pos; + if (what && !what->Destroyed) { + order->SetGoal(what); + } + + return order; +} + +/* static */ COrder* COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type) +{ + COrder *order = new COrder; + + order->Action = UnitActionUpgradeTo; + + // FIXME: if you give quick an other order, the resources are lost! + unit.Player->SubUnitType(type); + order->Arg1.Type = &type; + + return order; +} + COrder& COrder::operator=(const COrder &rhs) { if (this != &rhs) { Action = rhs.Action; diff --git a/src/action/command.cpp b/src/action/command.cpp index 5f4b9d1b6..69c92ffae 100644 --- a/src/action/command.cpp +++ b/src/action/command.cpp @@ -61,15 +61,14 @@ */ static void ReleaseOrders(CUnit &unit) { - int n = unit.OrderCount; + Assert(static_cast<size_t>(unit.OrderCount) == unit.Orders.size()); + Assert(unit.Orders.size() >= 1); - if (n > 1) { - while (--n) { - delete unit.Orders[n]; - unit.Orders.pop_back(); - } - unit.OrderCount = 1; + for (size_t i = 1; i != unit.Orders.size(); ++i) { + delete unit.Orders[i]; } + unit.Orders.resize(1); + unit.OrderCount = 1; unit.OrderFlush = 1; // Order 0 must be stopped in the action loop. } @@ -82,7 +81,7 @@ static void ReleaseOrders(CUnit &unit) ** ** @return Pointer to next free order slot. */ -static COrderPtr GetNextOrder(CUnit &unit, int flush) +static COrderPtr *GetNextOrder(CUnit &unit, int flush) { if (flush) { // empty command queue @@ -91,7 +90,9 @@ static COrderPtr GetNextOrder(CUnit &unit, int flush) if (unit.OrderCount == 0x7F) { return NULL; } - return unit.CreateOrder(); + unit.Orders.push_back(NULL); + unit.OrderCount++; + return &unit.Orders.back(); } /** @@ -104,24 +105,23 @@ static void RemoveOrder(CUnit &unit, int order) { Assert(0 <= order && order < unit.OrderCount); - if (order != 0) { - delete unit.Orders[order]; + delete unit.Orders[order]; + unit.Orders.erase(unit.Orders.begin() + order); + --unit.OrderCount; + if (order == 0) { + unit.SubAction = 0; } - for (int i = order; i < unit.OrderCount - 1; ++i) { - unit.Orders[i] = unit.Orders[i + 1]; - } - if (unit.OrderCount > 1) { - unit.Orders.pop_back(); - --unit.OrderCount; - if (order == 0) { - unit.SubAction = 0; - } - } else { - unit.CurrentOrder()->Init(); - unit.ClearAction(); + if (unit.Orders.empty()) { + unit.Orders.push_back(COrder::NewActionStill()); } } +static void ClearNewAction(CUnit &unit) +{ + delete unit.NewOrder; + unit.NewOrder = NULL; +} + /** ** Clear the saved action. ** @@ -136,6 +136,12 @@ static void ClearSavedAction(CUnit &unit) unit.SavedOrder = NULL; } +static bool IsUnitValidForNetwork(const CUnit &unit) +{ + return !unit.Removed && unit.CurrentAction() != UnitActionDie; +} + + /*---------------------------------------------------------------------------- -- Commands ----------------------------------------------------------------------------*/ @@ -148,65 +154,13 @@ static void ClearSavedAction(CUnit &unit) void CommandStopUnit(CUnit &unit) { // Ignore that the unit could be removed. - COrderPtr order = GetNextOrder(unit, FlushCommands); // Flush them. + COrderPtr *order = GetNextOrder(unit, FlushCommands); // Flush them. Assert(order); - order->Init(); + Assert(*order == NULL); + *order = COrder::NewActionStill(); - order->Action = UnitActionStill; ClearSavedAction(unit); - delete unit.NewOrder; - unit.NewOrder = NULL; -} - -/** -** 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, COrderPtr cpyorder, int flush) -{ - COrderPtr order; - - if (!(order = GetNextOrder(unit, flush))) { - return; - } - - *order = *cpyorder; - ClearSavedAction(unit); -} - -/** -** Move an order in the order queue. -** ( Cannot move the order 0 ! ) -** -** @param unit pointer to unit -** @param src the order to move -** @param dst the new position of the order -*/ -void CommandMoveOrder(CUnit &unit, int src, int dst) -{ - Assert(src != 0 && dst != 0 && src < unit.OrderCount && dst < unit.OrderCount); - - if (src == dst) { - return; - } - if (src < dst) { - COrderPtr tmp = unit.Orders[src]; - - for (int i = src; i < dst; ++i) { - unit.Orders[i] = unit.Orders[i+1]; - } - unit.Orders[dst] = tmp; - } else { // dst < src - COrderPtr tmp = unit.Orders[src]; - - for (int i = src - 1 ; i >= dst; --i) { - unit.Orders[i + 1] = unit.Orders[i]; - } - unit.Orders[dst] = tmp; - } + ClearNewAction(unit); } /** @@ -217,20 +171,18 @@ void CommandMoveOrder(CUnit &unit, int src, int dst) */ void CommandStandGround(CUnit &unit, int flush) { - COrderPtr order; - - // Ignore that the unit could be removed. + COrderPtr* order; if (unit.Type->Building) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { - return; + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { + return; + } } - order->Init(); - order->Action = UnitActionStandGround; + *order = COrder::NewActionStandGround(); ClearSavedAction(unit); } @@ -243,35 +195,21 @@ void CommandStandGround(CUnit &unit, int flush) */ void CommandFollow(CUnit &unit, CUnit &dest, int flush) { - COrderPtr order; + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + COrderPtr *order; - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (!unit.CanMove()) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (!unit.CanMove()) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { return; } - order->Init(); - - order->Action = UnitActionFollow; - // - // Destination could be killed. - // Should be handled in action, but is not possible! - // Unit::Refs is used as timeout counter. - // - if (dest.Destroyed) { - order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize(); - } else { - order->SetGoal(&dest); - order->Range = 1; - } } + *order = COrder::NewActionFollow(dest); ClearSavedAction(unit); } @@ -284,26 +222,23 @@ void CommandFollow(CUnit &unit, CUnit &dest, int flush) */ void CommandMove(CUnit &unit, const Vec2i &pos, int flush) { - COrderPtr order; - Assert(Map.Info.IsPointOnMap(pos)); - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (!unit.CanMove()) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + COrderPtr *order; + + if (!unit.CanMove()) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { return; } - order->Init(); - order->Action = UnitActionMove; - order->goalPos = pos; } + *order = COrder::NewActionMove(pos); ClearSavedAction(unit); } @@ -317,38 +252,24 @@ void CommandMove(CUnit &unit, const Vec2i &pos, int flush) */ void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush) { - COrderPtr order; + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + COrderPtr *order; - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (unit.Type->Building) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (unit.Type->Building) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { return; } - order->Init(); - - order->Action = UnitActionRepair; - // - // Destination could be killed. - // Should be handled in action, but is not possible! - // Unit::Refs is used as timeout counter. - // - if (dest) { - if (dest->Destroyed) { - order->goalPos = dest->tilePos + dest->Type->GetHalfTileSize(); - } else { - order->SetGoal(dest); - order->Range = unit.Type->RepairRange; - } - } else { - order->goalPos = pos; - } + } + if (dest) { + *order = COrder::NewActionRepair(unit, *dest); + } else { + *order = COrder::NewActionRepair(pos); } ClearSavedAction(unit); } @@ -361,12 +282,10 @@ void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush) */ void CommandAutoRepair(CUnit &unit, int on) { - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - unit.AutoRepair = on; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + unit.AutoRepair = on; } /** @@ -374,52 +293,31 @@ void CommandAutoRepair(CUnit &unit, int on) ** ** @param unit pointer to unit. ** @param pos map position to attack. -** @param attack or unit to be attacked. +** @param target or unit to be attacked. ** @param flush if true, flush command queue. */ -void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush) +void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *target, int flush) { - COrderPtr order; - Assert(Map.Info.IsPointOnMap(pos)); + if (IsUnitValidForNetwork(unit) == false) { + return ; + } - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (!unit.Type->CanAttack) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + COrderPtr *order; + + if (!unit.Type->CanAttack) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { 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->goalPos = attack->tilePos + attack->Type->GetHalfTileSize(); - } else { - // Removed, Dying handled by action routine. - order->SetGoal(attack); - order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; - order->MinRange = unit.Type->MinAttackRange; - } - } else if (Map.WallOnMap(pos)) { - // FIXME: look into action_attack.c about this ugly problem - order->goalPos = pos; - order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; - order->MinRange = unit.Type->MinAttackRange; - } else { - order->goalPos = pos; - } + } + if (target) { + *order = COrder::NewActionAttack(unit, *target); + } else { + *order = COrder::NewActionAttack(unit, pos); } ClearSavedAction(unit); } @@ -433,31 +331,23 @@ void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush) */ void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush) { - COrderPtr order; - Assert(Map.Info.IsPointOnMap(pos)); - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (unit.Type->Building) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + 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; } - order->Init(); - - order->Action = UnitActionAttackGround; - order->goalPos = pos; - order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; - order->MinRange = unit.Type->MinAttackRange; - - DebugPrint("FIXME this next\n"); } + *order = COrder::NewActionAttackGround(unit, pos); ClearSavedAction(unit); } @@ -472,29 +362,24 @@ void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush) */ void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush) { - COrderPtr order; - Assert(Map.Info.IsPointOnMap(pos)); - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (!unit.CanMove()) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + COrderPtr *order; + + if (!unit.CanMove()) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { return; } - order->Init(); - - order->Action = UnitActionPatrol; - order->goalPos = pos; - Assert(!(unit.tilePos.x & ~0xFFFF) && !(unit.tilePos.y & ~0xFFFF)); - order->Arg1.Patrol = unit.tilePos; } + *order = COrder::NewActionPatrol(unit.tilePos, pos); + ClearSavedAction(unit); } @@ -507,35 +392,24 @@ void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush) */ void CommandBoard(CUnit &unit, CUnit &dest, int flush) { - COrderPtr order; - - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { - return; - } - order->Init(); - - order->Action = UnitActionBoard; - order->SetGoal(&dest); - order->Range = 1; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + if (dest.Destroyed) { + return ; + } + COrderPtr *order; + + if (unit.Type->Building) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { + return; + } + } + *order = COrder::NewActionBoard(dest); ClearSavedAction(unit); } @@ -549,28 +423,15 @@ void CommandBoard(CUnit &unit, CUnit &dest, int flush) */ void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush) { - COrderPtr order; - - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (!(order = GetNextOrder(unit, flush))) { - return; - } - order->Init(); - - order->Action = UnitActionUnload; - order->goalPos = pos; - // - // 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->SetGoal(what); - } + if (IsUnitValidForNetwork(unit) == false) { + return ; } + COrderPtr *order = GetNextOrder(unit, flush); + + if (order == NULL) { + return; + } + *order = COrder::NewActionUnload(pos, what); ClearSavedAction(unit); } @@ -584,40 +445,21 @@ void CommandUnload(CUnit &unit, const Vec2i &pos, CUnit *what, int flush) */ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int flush) { - COrderPtr order; + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + COrderPtr *order; - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (unit.Type->Building) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (unit.Type->Building) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { return; } - order->Init(); - - order->Action = UnitActionBuild; - order->goalPos = pos; - order->Width = what.TileWidth; - order->Height = what.TileHeight; - if (what.BuilderOutside) { - order->Range = unit.Type->RepairRange; - } else { - // If building inside, but be next to stop - if (what.ShoreBuilding && unit.Type->UnitType == UnitTypeLand) { - // Peon won't dive :-) - order->Range = 1; - } - } - order->Arg1.Type = &what; - if (what.BuilderOutside) { - order->MinRange = 1; - } } + *order = COrder::NewActionBuild(unit, pos, what); ClearSavedAction(unit); } @@ -628,9 +470,7 @@ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int fl */ void CommandDismiss(CUnit &unit) { - // // Check if building is still under construction? (NETWORK!) - // if (unit.CurrentAction() == UnitActionBuilt) { unit.CurrentOrder()->Data.Built.Cancel = 1; } else { @@ -649,42 +489,25 @@ void CommandDismiss(CUnit &unit) */ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush) { - COrderPtr order; - Vec2i ressourceLoc; + if (IsUnitValidForNetwork(unit) == false) { + return ; + } + if (!unit.Type->Building && !unit.Type->Harvester) { + ClearSavedAction(unit); + return ; + } + COrderPtr *order; - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - if (unit.Type->Building) { - // FIXME: should find a better way for pending orders. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { + if (unit.Type->Building) { + ClearNewAction(unit); + order = &unit.NewOrder; + } else { + order = GetNextOrder(unit, flush); + if (order == NULL) { 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, pos, &ressourceLoc)) { - DebugPrint("FIXME: Give up???\n"); - } - - // Max Value > 1 - if ((MyAbs(ressourceLoc.x - pos.x) | MyAbs(ressourceLoc.y - pos.y)) > 1) { - if (!FindTerrainType(0, MapFieldForest, 0, 20, unit.Player, ressourceLoc, &ressourceLoc)) { - DebugPrint("FIXME: Give up???\n"); - } - } else { - // The destination is next to a reachable tile. - ressourceLoc = pos; - } - order->goalPos = ressourceLoc; - order->Range = 1; } + *order = COrder::NewActionResource(unit, pos); ClearSavedAction(unit); } @@ -697,33 +520,28 @@ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush) */ void CommandResource(CUnit &unit, CUnit &dest, int flush) { - COrderPtr order; - - // - // Check if unit is still valid and Goal still alive? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { - return; - } - order->Init(); - order->Action = UnitActionResource; - order->SetGoal(&dest); - order->Range = 1; + 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(dest); ClearSavedAction(unit); } @@ -736,37 +554,26 @@ void CommandResource(CUnit &unit, CUnit &dest, int flush) */ void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush) { - COrderPtr order; - - // - // Check if unit is still valid and Goal still alive? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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. - delete unit.NewOrder; - unit.NewOrder = new COrder; - order = unit.NewOrder; - } else if (!(order = GetNextOrder(unit, flush))) { - return; - } - order->Init(); - - order->Action = UnitActionReturnGoods; - // - // Destination could be killed. NETWORK! - // - if (goal && !goal->Destroyed) { - order->SetGoal(goal); - } - order->Range = 1; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + if ((unit.Type->Harvester && unit.ResourcesHeld == 0) + || (!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::NewActionReturnGoods(goal); ClearSavedAction(unit); } @@ -779,38 +586,28 @@ void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush) */ void CommandTrainUnit(CUnit &unit, CUnitType &type, int) { - COrderPtr order; - - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - // - // 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 full!\n"); - return; - } - if (!(order = GetNextOrder(unit, 0))) { - return; - } - order->Init(); - - order->Action = UnitActionTrain; - order->Arg1.Type = &type; - // FIXME: if you give quick an other order, the resources are lost! - unit.Player->SubUnitType(type); + 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); } @@ -828,10 +625,7 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type) ClearSavedAction(unit); - // // Check if unit is still training 'slot'? (NETWORK!) - // - if (slot == -1) { // Cancel All training while (unit.CurrentAction() == UnitActionTrain) { @@ -840,7 +634,6 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type) CancelTrainingCostsFactor); RemoveOrder(unit, 0); } - unit.CurrentOrder()->Data.Train.Ticks = 0; if (unit.Player == ThisPlayer && unit.Selected) { SelectedUnitChanged(); } @@ -856,22 +649,14 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type) // Different unit being trained return; } - DebugPrint("Cancel training\n"); unit.Player->AddCostsFactor( unit.Orders[slot]->Arg1.Type->Stats[unit.Player->Index].Costs, CancelTrainingCostsFactor); - - - if (!slot) { // Canceled in work slot - unit.CurrentOrder()->Data.Train.Ticks = 0; - } RemoveOrder(unit, slot); - // // Update interface. - // if (unit.Player == ThisPlayer && unit.Selected) { SelectedUnitChanged(); } @@ -887,33 +672,21 @@ void CommandCancelTraining(CUnit &unit, int slot, const CUnitType *type) */ void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush) { - COrderPtr order; - - // - // Check if unit is still valid and Goal still alive? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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->Arg1.Type = &type; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + + // Check if enough resources remains? (NETWORK!) + if (unit.Player->CheckUnitType(type)) { + return; + } + + COrderPtr *order = GetNextOrder(unit, flush); + + if (order == NULL) { + return; + } + *order = COrder::NewActionUpgradeTo(unit, type); ClearSavedAction(unit); } @@ -925,13 +698,9 @@ void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush) */ void CommandTransformIntoType(CUnit &unit, CUnitType &type) { - COrderPtr order = new COrder; - Assert(unit.CriticalOrder == NULL); - order->Action = UnitActionTransformInto; - order->Arg1.Type = &type; - unit.CriticalOrder = order; + unit.CriticalOrder = COrder::NewActionTransformInto(type); } /** @@ -941,19 +710,16 @@ void CommandTransformIntoType(CUnit &unit, CUnitType &type) */ void CommandCancelUpgradeTo(CUnit &unit) { - ReleaseOrders(unit); // empty command queue - - // // Check if unit is still upgrading? (NETWORK!) - // if (unit.CurrentAction() == UnitActionUpgradeTo) { - unit.Player->AddCostsFactor( unit.CurrentOrder()->Arg1.Type->Stats[unit.Player->Index].Costs, CancelUpgradeCostsFactor); - unit.CurrentOrder()->Init(); - unit.ClearAction(); + RemoveOrder(unit, 0); + if (Selected) { + SelectedUnitChanged(); + } } ClearSavedAction(unit); } @@ -967,46 +733,18 @@ void CommandCancelUpgradeTo(CUnit &unit) */ void CommandResearch(CUnit &unit, CUpgrade *what, int flush) { - COrderPtr order; - - // - // Check if unit is still valid and Goal still alive? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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.CurrentAction() == UnitActionResearch) { - const CUpgrade *upgrade; - - // Cancel current research - upgrade = unit.CurrentOrder()->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->goalPos.x = order->goalPos.y = -1; - order->Arg1.Upgrade = what; + 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); } @@ -1017,21 +755,16 @@ void CommandResearch(CUnit &unit, CUpgrade *what, int flush) */ void CommandCancelResearch(CUnit &unit) { - ReleaseOrders(unit); // empty command queue - - // // Check if unit is still researching? (NETWORK!) - // if (unit.CurrentAction() == UnitActionResearch) { - const CUpgrade *upgrade; + const CUpgrade &upgrade = *unit.CurrentOrder()->Data.Research.Upgrade; + unit.Player->UpgradeTimers.Upgrades[upgrade.ID] = 0; - upgrade = unit.CurrentOrder()->Data.Research.Upgrade; - unit.Player->UpgradeTimers.Upgrades[upgrade->ID] = 0; - - unit.Player->AddCostsFactor(upgrade->Costs, - CancelResearchCostsFactor); - unit.CurrentOrder()->Init(); - unit.ClearAction(); + unit.Player->AddCostsFactor(upgrade.Costs, CancelResearchCostsFactor); + RemoveOrder(unit, 0); + if (Selected) { + SelectedUnitChanged(); + } } ClearSavedAction(unit); } @@ -1047,47 +780,21 @@ void CommandCancelResearch(CUnit &unit) */ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, SpellType *spell, int flush) { - COrderPtr order; - - Assert(Map.Info.IsPointOnMap(pos)); - 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)); - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != 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 a unit as destination? - // FIXME: dest->Type is now set to 0. maybe we shouldn't bother. - const Vec2i diag = {order->Range, order->Range}; - order->goalPos = dest->tilePos /* + dest->Type->GetHalfTileSize() */ - diag; - order->Range <<= 1; - } else { - order->SetGoal(dest); - } - } else { - order->goalPos = pos; - } - order->Arg1.Spell = spell; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + COrderPtr *order = GetNextOrder(unit, flush); + + if (order == NULL) { + return; + } + + *order = COrder::NewActionSpellCast(*spell, pos, dest); ClearSavedAction(unit); } @@ -1100,12 +807,10 @@ void CommandSpellCast(CUnit &unit, const Vec2i &pos, CUnit *dest, SpellType *spe */ void CommandAutoSpellCast(CUnit &unit, int spellid, int on) { - // - // Check if unit is still valid? (NETWORK!) - // - if (!unit.Removed && unit.CurrentAction() != UnitActionDie) { - unit.AutoCastSpell[spellid] = on; + if (IsUnitValidForNetwork(unit) == false) { + return ; } + unit.AutoCastSpell[spellid] = on; } /** diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index f51556c1e..1a08d3c22 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -714,11 +714,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) { - COrder *savedOrder = new COrder; - - savedOrder->Action = UnitActionAttack; - savedOrder->Range = 0; - savedOrder->goalPos = aiunit.tilePos; + COrder *savedOrder = COrder::NewActionAttack(aiunit, aiunit.tilePos); if (aiunit.StoreOrder(savedOrder) == false) { delete savedOrder; diff --git a/src/include/actions.h b/src/include/actions.h index e7b3e9dec..058135249 100644 --- a/src/include/actions.h +++ b/src/include/actions.h @@ -10,7 +10,7 @@ // /**@name actions.h - The actions headerfile. */ // -// (c) Copyright 1998-2006 by Lutz Sammer and Jimmy Salmon +// (c) Copyright 1998-2012 by Lutz Sammer and Jimmy Salmon // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -150,6 +150,31 @@ public: void AiUnitKilled(CUnit &unit); void OnAnimationAttack(CUnit &unit); + + static COrder* NewActionAttack(const CUnit &attacker, CUnit &target); + static COrder* NewActionAttack(const CUnit &attacker, const Vec2i &dest); + static COrder* NewActionAttackGround(const CUnit &attacker, const Vec2i &dest); + static COrder* NewActionBoard(CUnit &unit); + static COrder* NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building); + static COrder* NewActionBuilt(); + static COrder* NewActionDie(); + static COrder* NewActionFollow(CUnit &dest); + static COrder* NewActionMove(const Vec2i &pos); + static COrder* NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest); + static COrder* NewActionRepair(CUnit &unit, CUnit &target); + static COrder* NewActionRepair(const Vec2i &pos); + static COrder* NewActionResearch(CUnit &unit, CUpgrade &upgrade); + static COrder* NewActionResource(CUnit &harvester, const Vec2i &pos); + static COrder* NewActionResource(CUnit &mine); + static COrder* NewActionReturnGoods(CUnit *depot); + static COrder* NewActionSpellCast(SpellType &spell, const Vec2i &pos, CUnit *target); + static COrder* NewActionStandGround(); + static COrder* NewActionStill(); + static COrder* NewActionTrain(CUnit &trainer, CUnitType &type); + static COrder* NewActionTransformInto(CUnitType &type); + static COrder* NewActionUnload(const Vec2i &pos, CUnit *what); + static COrder* NewActionUpgradeTo(CUnit &unit, CUnitType &type); + private: friend void CclParseOrder(lua_State *l, const CUnit &unit, COrder* order); @@ -160,8 +185,7 @@ public: 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 + unsigned char CurrentResource; ///used in UnitActionResource and UnitActionReturnGoods Vec2i goalPos; /// or tile coordinate of destination @@ -292,10 +316,6 @@ extern void CommandDiplomacy(int player, int state, int opponent); extern void CommandSetResource(int player, int resource, int value); /// Prepare shared vision command extern void CommandSharedVision(int player, bool state, int opponent); - /// Send any command -//extern void CommandAnyOrder(CUnit &unit, COrder *order, int flush); - /// Move an order in command queue -extern void CommandMoveOrder(CUnit &unit, int src, int dst); /*---------------------------------------------------------------------------- -- Actions: in action_<name>.c @@ -328,7 +348,7 @@ extern HandleActionFunc HandleActionPatrol; /// Show attack animation extern void AnimateActionAttack(CUnit &unit); /// Handle command attack -extern HandleActionFunc HandleActionAttack; +extern HandleActionFunc HandleActionAttack; /// Handle command board extern HandleActionFunc HandleActionBoard; /// Handle command unload diff --git a/src/include/unit.h b/src/include/unit.h index 4862936c7..55a8b3167 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -597,8 +597,6 @@ public: CUnit *Goal; /// Generic/Teleporter goal pointer - COrder *CreateOrder(); - COrder *CurrentOrder() const { return Orders[0]; } unsigned int CurrentAction() const; diff --git a/src/stratagus/groups.cpp b/src/stratagus/groups.cpp index 30da49b5c..18c3f7c30 100644 --- a/src/stratagus/groups.cpp +++ b/src/stratagus/groups.cpp @@ -307,13 +307,11 @@ void GroupHelpMe(CUnit *attacker, CUnit &defender) && CanTarget(gunit.Type, attacker->Type)) { CommandAttack(gunit, attacker->tilePos, attacker, FlushCommands); if (gunit.SavedOrder == NULL) { - COrder *savedOrder = new COrder; - - savedOrder->Action = UnitActionAttack; - savedOrder->goalPos = gunit.tilePos; + COrder *savedOrder = COrder::NewActionAttack(gunit, gunit.tilePos); if (gunit.StoreOrder(savedOrder) == false) { delete savedOrder; + savedOrder = NULL; } } } diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 12f5d80bc..7d256db29 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -589,9 +589,12 @@ static void CclParseOrders(lua_State *l, CUnit &unit) unit.OrderCount = 0; for (int j = 0; j < n; ++j) { lua_rawgeti(l, -1, j + 1); - COrderPtr order = unit.CreateOrder(); - Assert(order == unit.Orders[j]); - CclParseOrder(l, unit, order); + + unit.Orders.push_back(new COrder); + COrderPtr* order = &unit.Orders[(int)unit.OrderCount++]; + + Assert(order == &unit.Orders[j]); + CclParseOrder(l, unit, *order); lua_pop(l, 1); } } diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index d6c022e43..90f6d5fa8 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -260,13 +260,6 @@ 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); @@ -1059,8 +1052,8 @@ void UnitClearOrders(CUnit &unit) delete unit.Orders[i]; } unit.Orders.clear(); - unit.OrderCount = 0; - CommandStopUnit(unit); + unit.OrderCount = 1; + unit.Orders.push_back(COrder::NewActionStill()); unit.SubAction = unit.State = 0; } @@ -2720,14 +2713,15 @@ void LetUnitDie(CUnit &unit) UnitLost(unit); UnitClearOrders(unit); - // + + // Unit has death animation. - // // Not good: UnitUpdateHeading(unit); unit.SubAction = 0; unit.State = 0; - unit.CurrentOrder()->Action = UnitActionDie; + delete unit.Orders[0]; + unit.Orders[0] = COrder::NewActionDie(); if (type->CorpseType) { #ifdef DYNAMIC_LOAD if (!type->Sprite) { @@ -2977,19 +2971,13 @@ void HitUnit(CUnit *attacker, CUnit &target, int damage) } } if (goal) { - if (target.SavedOrder == NULL) { - COrder* savedOrder = new COrder; + COrder *savedOrder = new COrder(*target.CurrentOrder()); - savedOrder->Action = UnitActionAttack; - savedOrder->goalPos = target.tilePos; - savedOrder->Range = target.Stats->Variables[ATTACKRANGE_INDEX].Max; - savedOrder->MinRange = target.Type->MinAttackRange; - - if (target.StoreOrder(savedOrder) == false) { - delete savedOrder; - } - } CommandAttack(target, goal->tilePos, NoUnitP, FlushCommands); + if (target.StoreOrder(savedOrder) == false) { + delete savedOrder; + savedOrder = NULL; + } return; } }