From c3dea78611482eca2cd31c7652c4cb8ee6613df9 Mon Sep 17 00:00:00 2001 From: joris <joris.dauphin@gmail.com> Date: Wed, 22 Feb 2012 08:45:58 +0100 Subject: [PATCH] Some more COrder_ (Die, Patrol, StandGroung, Still) --- src/action/action_build.cpp | 4 - src/action/action_die.cpp | 114 ++++++++++------- src/action/action_patrol.cpp | 165 ++++++++++++------------ src/action/action_research.cpp | 5 - src/action/action_spellcast.cpp | 9 +- src/action/action_stand.cpp | 38 +++++- src/action/action_still.cpp | 161 ++++++++++++++--------- src/action/actions.cpp | 219 ++++---------------------------- src/include/actions.h | 117 +++++++++++++---- src/include/script.h | 23 +++- src/unit/script_unit.cpp | 142 ++++++++------------- src/unit/unit_draw.cpp | 7 +- src/unit/unit_save.cpp | 15 --- 13 files changed, 492 insertions(+), 527 deletions(-) diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp index 29ad1d712..b739b2e24 100644 --- a/src/action/action_build.cpp +++ b/src/action/action_build.cpp @@ -350,10 +350,6 @@ void HandleActionBuild(COrder& /*order*/, CUnit &unit) // Action_built ////////////////////////// -/* virtual */ COrder_Built *COrder_Built::Clone() const -{ - return new COrder_Built(*this); -} /* virtual */ void COrder_Built::Save(CFile &file, const CUnit &unit) const { file.printf("{\"action-built\", "); diff --git a/src/action/action_die.cpp b/src/action/action_die.cpp index 44b712f8d..3646c1cca 100644 --- a/src/action/action_die.cpp +++ b/src/action/action_die.cpp @@ -39,15 +39,81 @@ #include "stratagus.h" #include "unittype.h" #include "animation.h" -#include "player.h" #include "unit.h" #include "actions.h" -#include "map.h" +#include "iolib.h" /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ +/* virtual */ void COrder_Die::Save(CFile &file, const CUnit &unit) const +{ + file.printf("{\"action-die\"}"); +} + +/* virtual */ bool COrder_Die::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) +{ + return false; +} + +static bool AnimateActionDie(CUnit &unit) +{ + const CAnimations *animations = unit.Type->Animations; + + if (animations == NULL) { + return false; + } + if (animations->Death[unit.DamagedType]) { + UnitShowAnimation(unit, animations->Death[unit.DamagedType]); + return true; + } else if (animations->Death[ANIMATIONS_DEATHTYPES]) { + UnitShowAnimation(unit, animations->Death[ANIMATIONS_DEATHTYPES]); + return true; + } + return false; +} + + +/* virtual */ bool COrder_Die::Execute(CUnit &unit) +{ + // Show death animation + if (AnimateActionDie(unit) == false) { + // some units has no death animation + unit.Anim.Unbreakable = 0; + } + if (unit.Anim.Unbreakable) { + return false; + } + CUnitType &type = *unit.Type; + + // Die sequence terminated, generate corpse. + if (type.CorpseType == NULL) { + unit.Remove(NULL); + unit.Release(); + return false; + } + + CUnitType &corpseType = *type.CorpseType; + Assert(type.TileWidth >= corpseType.TileWidth && type.TileHeight >= corpseType.TileHeight); + + // Update sight for new corpse + // We have to unmark BEFORE changing the type. + // Always do that, since types can have different vision properties. + + unit.Remove(NULL); + unit.Type = &corpseType; + unit.Stats = &type.Stats[unit.Player->Index]; + unit.Place(unit.tilePos); + + unit.SubAction = 0; + unit.Frame = 0; + UnitUpdateHeading(unit); + AnimateActionDie(unit); // with new corpse. + return false; +} + + /** ** Unit dies! ** @@ -57,48 +123,8 @@ void HandleActionDie(COrder& order, CUnit &unit) { Assert(order.Action == UnitActionDie); - // Show death animation - if (unit.Type->Animations && unit.Type->Animations->Death[unit.DamagedType]) { - UnitShowAnimation(unit, unit.Type->Animations->Death[unit.DamagedType]); - } - else if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) { - UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]); - } else { - // some units has no death animation - unit.Anim.Unbreakable = 0; - } - - if (unit.Anim.Unbreakable) { - return; - } - // Die sequence terminated, generate corpse. - if (!unit.Type->CorpseType) { - // We may be in the cache if we just finished out death animation - // even though there is no corpse. - // (unit.Type->Animations && unit.Type->Animations->Death) - // Remove us from the map to be safe - unit.Remove(NULL); - unit.Release(); - return; - } - - Assert(unit.Type->TileWidth >= unit.Type->CorpseType->TileWidth && - unit.Type->TileHeight >= unit.Type->CorpseType->TileHeight); - - // Update sight for new corpse - // We have to unmark BEFORE changing the type. - // Always do that, since types can have different vision properties. - - unit.Remove(NULL); - unit.Type = unit.Type->CorpseType; - unit.Stats = &unit.Type->Stats[unit.Player->Index]; - unit.Place(unit.tilePos); - - unit.SubAction = 0; - unit.Frame = 0; - UnitUpdateHeading(unit); - if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) { - UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]); + if (order.Execute(unit)) { + unit.ClearAction(); } } diff --git a/src/action/action_patrol.cpp b/src/action/action_patrol.cpp index 7e5cceafa..9b4b1cfc2 100644 --- a/src/action/action_patrol.cpp +++ b/src/action/action_patrol.cpp @@ -42,26 +42,97 @@ #include "actions.h" #include "pathfinder.h" #include "map.h" +#include "iolib.h" +#include "script.h" /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ -extern bool AutoRepair(CUnit &unit); -extern bool AutoCast(CUnit &unit); -/** -** Swap the patrol points. -*/ -static void SwapPatrolPoints(CUnit &unit) +/* virtual */ void COrder_Patrol::Save(CFile &file, const CUnit &unit) const { - COrderPtr order = unit.CurrentOrder(); + file.printf("{\"action-patrol\","); - std::swap(order->Arg1.Patrol.x, order->goalPos.x); - std::swap(order->Arg1.Patrol.y, order->goalPos.y); + file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y); + file.printf(" \"range\", %d,", this->Range); - unit.CurrentOrder()->Data.Move.Cycles = 0; //moving counter - unit.CurrentOrder()->NewResetPath(); + file.printf(" \"patrol\", {%d, %d},\n ", this->WayPoint.x, this->WayPoint.y); + SaveDataMove(file); + file.printf("}"); +} + +/* virtual */ bool COrder_Patrol::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) +{ + if (ParseMoveData(l, j, value)) { + return true; + } else if (!strcmp(value, "patrol")) { + ++j; + lua_rawgeti(l, -1, j + 1); + CclGetPos(l, &this->WayPoint.x , &this->WayPoint.y); + lua_pop(l, 1); + } else { + return false; + } + return true; +} + +/* virtual */ bool COrder_Patrol::Execute(CUnit &unit) +{ + if (unit.Wait) { + unit.Wait--; + return false; + } + + if (!unit.SubAction) { // first entry. + this->Data.Move.Cycles = 0; //moving counter + this->NewResetPath(); + unit.SubAction = 1; + } + + switch (DoActionMove(unit)) { + case PF_FAILED: + unit.SubAction = 1; + break; + case PF_UNREACHABLE: + // Increase range and try again + unit.SubAction = 1; + if (this->CheckRange()) { + this->Range++; + break; + } + // FALL THROUGH + case PF_REACHED: + unit.SubAction = 1; + this->Range = 0; + std::swap(this->WayPoint, this->goalPos); + + this->Data.Move.Cycles = 0; //moving counter + this->NewResetPath(); + break; + case PF_WAIT: + // Wait for a while then give up + unit.SubAction++; + if (unit.SubAction == 5) { + unit.SubAction = 1; + this->Range = 0; + std::swap(this->WayPoint, this->goalPos); + + this->Data.Move.Cycles = 0; //moving counter + this->NewResetPath(); + } + break; + default: // moving + unit.SubAction = 1; + break; + } + + if (!unit.Anim.Unbreakable) { + if (AutoAttack(unit, false) || AutoRepair(unit) || AutoCast(unit)) { + return true; + } + } + return false; } /** @@ -77,76 +148,10 @@ static void SwapPatrolPoints(CUnit &unit) */ void HandleActionPatrol(COrder& order, CUnit &unit) { - if (unit.Wait) { - unit.Wait--; - return; - } + Assert(order.Action == UnitActionPatrol); - if (!unit.SubAction) { // first entry. - order.Data.Move.Cycles = 0; //moving counter - order.NewResetPath(); - unit.SubAction = 1; - } - - switch (DoActionMove(unit)) { - case PF_FAILED: - unit.SubAction = 1; - break; - case PF_UNREACHABLE: - // Increase range and try again - unit.SubAction = 1; - if (order.CheckRange()) { - order.Range++; - break; - } - // FALL THROUGH - case PF_REACHED: - unit.SubAction = 1; - order.Range = 0; - SwapPatrolPoints(unit); - break; - case PF_WAIT: - // Wait for a while then give up - unit.SubAction++; - if (unit.SubAction == 5) { - unit.SubAction = 1; - order.Range = 0; - SwapPatrolPoints(unit); - } - break; - default: // moving - unit.SubAction = 1; - break; - } - - if (!unit.Anim.Unbreakable) { - // - // Attack any enemy in reaction range. - // If don't set the goal, the unit can then choose a - // better goal if moving nearer to enemy. - // - if (unit.Type->CanAttack) { - const CUnit *goal = AttackUnitsInReactRange(unit); - if (goal) { - // Save current command to come back. - COrder *savedOrder = order.Clone(); - - 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(); - return; - } - } - - // Look for something to auto repair or auto cast - if (AutoRepair(unit) || AutoCast(unit)) { - return; - } + if (order.Execute(unit)) { + unit.ClearAction(); } } diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp index 700c59e59..4fa71899b 100644 --- a/src/action/action_research.cpp +++ b/src/action/action_research.cpp @@ -54,11 +54,6 @@ -- Functions ----------------------------------------------------------------------------*/ -/* virtual */ COrder_Research *COrder_Research::Clone() const -{ - return new COrder_Research(*this); -} - /* virtual */ void COrder_Research::Save(CFile &file, const CUnit &unit) const { file.printf("{\"action-research\""); diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp index 22fbd2c5a..6276a4da2 100644 --- a/src/action/action_spellcast.cpp +++ b/src/action/action_spellcast.cpp @@ -62,11 +62,6 @@ -- Functions ----------------------------------------------------------------------------*/ -/* virtual */ COrder_SpellCast *COrder_SpellCast::Clone() const -{ - return new COrder_SpellCast(*this); -} - /* virtual */ void COrder_SpellCast::Save(CFile &file, const CUnit &unit) const { file.printf("{\"action-spell-cast\","); @@ -94,7 +89,9 @@ /* virtual */ bool COrder_SpellCast::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { - if (!strcmp(value, "spell")) { + if (ParseMoveData(l, j, value)) { + return true; + } else if (!strcmp(value, "spell")) { ++j; lua_rawgeti(l, -1, j + 1); this->Spell = SpellTypeByIdent(LuaToString(l, -1)); diff --git a/src/action/action_stand.cpp b/src/action/action_stand.cpp index 30a4136f8..22c830f95 100644 --- a/src/action/action_stand.cpp +++ b/src/action/action_stand.cpp @@ -38,19 +38,53 @@ #include "stratagus.h" #include "unit.h" #include "actions.h" +#include "iolib.h" /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ + +/* virtual */ void COrder_StandGround::Save(CFile &file, const CUnit &unit) const +{ + file.printf("{\"action-stand-ground\""); + if (this->HasGoal()) { + CUnit &goal = *this->GetGoal(); + if (goal.Destroyed) { + /* this unit is destroyed so it's not in the global unit + * array - this means it won't be saved!!! */ + printf ("FIXME: storing destroyed Goal - loading will fail.\n"); + } + file.printf(", \"goal\", \"%s\"", UnitReference(goal).c_str()); + } + file.printf("}"); +} + +/* virtual */ bool COrder_StandGround::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) +{ + return false; +} + +/* virtual */ bool COrder_StandGround::Execute(CUnit &unit) +{ + ActionStillGeneric(unit, true); + + return false; +} + + /** ** Unit stands ground! ** ** @param unit Action handled for this unit pointer. */ -void HandleActionStandGround(COrder& /*order*/, CUnit &unit) +void HandleActionStandGround(COrder& order, CUnit &unit) { - ActionStillGeneric(unit, true); + Assert(order.Action == UnitActionStandGround); + + if (order.Execute(unit)) { + unit.ClearAction(); + } } //@} diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp index ead9d330d..8f8614154 100644 --- a/src/action/action_still.cpp +++ b/src/action/action_still.cpp @@ -47,11 +47,35 @@ #include "pathfinder.h" #include "spells.h" #include "player.h" +#include "iolib.h" #define SUB_STILL_INIT 0 #define SUB_STILL_STANDBY 1 #define SUB_STILL_ATTACK 2 + + +/* virtual */ void COrder_Still::Save(CFile &file, const CUnit &unit) const +{ + file.printf("{\"action-still\""); + if (this->HasGoal()) { + CUnit &goal = *this->GetGoal(); + if (goal.Destroyed) { + /* this unit is destroyed so it's not in the global unit + * array - this means it won't be saved!!! */ + printf ("FIXME: storing destroyed Goal - loading will fail.\n"); + } + file.printf(", \"goal\", \"%s\"", UnitReference(goal).c_str()); + } + file.printf("}"); +} + +/* virtual */ bool COrder_Still::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) +{ + return false; +} + + /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ @@ -239,66 +263,81 @@ bool AutoRepair(CUnit &unit) { const int repairRange = unit.Type->Variable[AUTOREPAIRRANGE_INDEX].Value; - if (unit.AutoRepair && repairRange) { - CUnit *repairedUnit = UnitToRepairInRange(unit, repairRange); - - if (repairedUnit != NoUnitP) { - const Vec2i invalidPos = {-1, -1}; - COrder *savedOrder = unit.CurrentOrder()->Clone(); - - //Command* will clear unit.SavedOrder - CommandRepair(unit, invalidPos, repairedUnit, FlushCommands); - if (unit.StoreOrder(savedOrder) == false) { - delete savedOrder; - savedOrder = NULL; - } - return true; - } + if (unit.AutoRepair == false || repairRange == 0) { + return false; } - return false; + CUnit *repairedUnit = UnitToRepairInRange(unit, repairRange); + + if (repairedUnit == NoUnitP) { + return false; + } + const Vec2i invalidPos = {-1, -1}; + COrder *savedOrder = unit.CurrentOrder()->Clone(); + + //Command* will clear unit.SavedOrder + CommandRepair(unit, invalidPos, repairedUnit, FlushCommands); + if (unit.StoreOrder(savedOrder) == false) { + delete savedOrder; + savedOrder = NULL; + } + return true; } /** ** Auto attack nearby units if possible */ -static bool AutoAttack(CUnit &unit, bool stand_ground) +bool AutoAttack(CUnit &unit, bool stand_ground) { - CUnit *goal; - - // Cowards and invisible units don't attack unless ordered. - if (unit.IsAgressive()) { - // Normal units react in reaction range. - if (!stand_ground && !unit.Removed && unit.CanMove()) { - if ((goal = AttackUnitsInReactRange(unit))) { - // Weak goal, can choose other unit, come back after attack - CommandAttack(unit, goal->tilePos, NULL, FlushCommands); - COrder *savedOrder = COrder::NewActionAttack(unit, unit.tilePos); - - if (unit.StoreOrder(savedOrder) == false) { - delete savedOrder; - } - return true; - } - // Removed units can only attack in AttackRange, from bunker - } else { - if ((goal = AttackUnitsInRange(unit))) { - CUnit *temp = unit.CurrentOrder()->GetGoal(); - if (temp && temp->CurrentAction() == UnitActionDie) { - unit.CurrentOrder()->ClearGoal(); - temp = NoUnitP; - } - if (unit.SubAction < SUB_STILL_ATTACK || temp != goal) { - // New target. - unit.CurrentOrder()->SetGoal(goal); - unit.State = 0; - unit.SubAction = SUB_STILL_ATTACK; // Mark attacking. - UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos); - } - return true; - } - } + if (unit.Type->CanAttack == false) { + return false; } - return false; + + if (stand_ground || unit.Removed || unit.CanMove() == false) { + // Removed units can only attack in AttackRange, from bunker + CUnit *goal = AttackUnitsInRange(unit); + + if (goal == NULL) { + return false; + } + + CUnit *temp = unit.CurrentOrder()->GetGoal(); + if (temp && temp->CurrentAction() == UnitActionDie) { + unit.CurrentOrder()->ClearGoal(); + temp = NoUnitP; + } + if (unit.SubAction < SUB_STILL_ATTACK || temp != goal) { + // New target. + unit.CurrentOrder()->SetGoal(goal); + unit.State = 0; + unit.SubAction = SUB_STILL_ATTACK; // Mark attacking. + UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos); + } + return true; + } + // Normal units react in reaction range. + CUnit *goal = AttackUnitsInReactRange(unit); + + if (goal == NULL) { + return false; + } + + COrder *savedOrder; + + if (unit.SavedOrder != NULL) { + savedOrder = unit.SavedOrder->Clone(); + } else if (unit.CurrentAction() == UnitActionStill) { + savedOrder = COrder::NewActionAttack(unit, unit.tilePos); + } else { + savedOrder = unit.CurrentOrder()->Clone(); + } + + // Weak goal, can choose other unit, come back after attack + CommandAttack(unit, goal->tilePos, NULL, FlushCommands); + + if (unit.StoreOrder(savedOrder) == false) { + delete savedOrder; + } + return true; } void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground) @@ -360,8 +399,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground) return; } - switch (unit.SubAction) - { + switch (unit.SubAction) { case SUB_STILL_INIT: //first entry MapMarkUnitGuard(unit); unit.SubAction = SUB_STILL_STANDBY; @@ -378,7 +416,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground) return; } - if (AutoAttack(unit, stand_ground) + if ((unit.IsAgressive() && AutoAttack(unit, stand_ground)) || AutoCast(unit) || AutoRepair(unit) || MoveRandomly(unit)) { @@ -391,9 +429,18 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground) ** ** @param unit Unit pointer for still action. */ -void HandleActionStill(COrder& /*order*/, CUnit &unit) +void HandleActionStill(COrder& order, CUnit &unit) { - ActionStillGeneric(unit, false); + Assert(order.Action == UnitActionStill); + + order.Execute(unit); } +/* virtual */ bool COrder_Still::Execute(CUnit &unit) +{ + ActionStillGeneric(unit, false); + return false; +} + + //@} diff --git a/src/action/actions.cpp b/src/action/actions.cpp index 9cf0349db..c38ed5f68 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -92,9 +92,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target) { - COrder *order = new COrder; - - order->Action = UnitActionAttack; + COrder *order = new COrder(UnitActionAttack); if (target.Destroyed) { order->goalPos = target.tilePos + target.Type->GetHalfTileSize(); @@ -111,9 +109,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); { Assert(Map.Info.IsPointOnMap(dest)); - COrder *order = new COrder; - - order->Action = UnitActionAttack; + COrder *order = new COrder(UnitActionAttack); if (Map.WallOnMap(dest) && Map.IsFieldExplored(*attacker.Player, dest)) { // FIXME: look into action_attack.cpp about this ugly problem @@ -128,9 +124,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionAttackGround); - order->Action = UnitActionAttackGround; order->goalPos = dest; order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max; order->MinRange = attacker.Type->MinAttackRange; @@ -141,9 +136,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionBoard(CUnit &unit) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionBoard); - order->Action = UnitActionBoard; order->SetGoal(&unit); order->Range = 1; @@ -153,9 +147,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building) { - COrder *order = new COrder; - - order->Action = UnitActionBuild; + COrder *order = new COrder(UnitActionBuild); order->goalPos = pos; order->Width = building.TileWidth; @@ -200,17 +192,13 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionDie() { - COrder *order = new COrder; - - order->Action = UnitActionDie; - return order; + return new COrder_Die; } /* static */ COrder* COrder::NewActionFollow(CUnit &dest) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionFollow); - order->Action = UnitActionFollow; // Destination could be killed. // Should be handled in action, but is not possible! // Unit::Refs is used as timeout counter. @@ -227,9 +215,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionMove(const Vec2i &pos) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionMove); - order->Action = UnitActionMove; order->goalPos = pos; return order; @@ -241,20 +228,18 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); Assert(Map.Info.IsPointOnMap(currentPos)); Assert(Map.Info.IsPointOnMap(dest)); - COrder *order = new COrder; + COrder_Patrol *order = new COrder_Patrol(); - order->Action = UnitActionPatrol; order->goalPos = dest; - order->Arg1.Patrol = currentPos; + order->WayPoint = currentPos; return order; } /* static */ COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionRepair); - order->Action = UnitActionRepair; if (target.Destroyed) { order->goalPos = target.tilePos + target.Type->GetHalfTileSize(); } else { @@ -268,9 +253,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); { Assert(Map.Info.IsPointOnMap(pos)); - COrder *order = new COrder; + COrder *order = new COrder(UnitActionRepair); - order->Action = UnitActionRepair; order->goalPos = pos; return order; } @@ -293,11 +277,9 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionResource(CUnit &harvester, const Vec2i &pos) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionResource); 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"); @@ -319,9 +301,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionResource(CUnit &mine) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionResource); - order->Action = UnitActionResource; order->SetGoal(&mine); order->Range = 1; @@ -332,9 +313,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionReturnGoods(CUnit *depot) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionReturnGoods); - order->Action = UnitActionReturnGoods; // Destination could be killed. NETWORK! if (depot && !depot->Destroyed) { order->SetGoal(depot); @@ -374,19 +354,12 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionStandGround() { - COrder *order = new COrder; - - order->Action = UnitActionStandGround; - return order; + return new COrder_StandGround; } - /* static */ COrder* COrder::NewActionStill() { - COrder *order = new COrder; - - order->Action = UnitActionStill; - return order; + return new COrder_Still; } @@ -394,9 +367,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionTrain); - order->Action = UnitActionTrain; order->Arg1.Type = &type; // FIXME: if you give quick an other order, the resources are lost! trainer.Player->SubUnitType(type); @@ -406,9 +378,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionTransformInto(CUnitType &type) { - COrder *order = new COrder; - - order->Action = UnitActionTransformInto; + COrder *order = new COrder(UnitActionTransformInto); order->Arg1.Type = &type; @@ -417,9 +387,8 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what) { - COrder *order = new COrder; + COrder *order = new COrder(UnitActionUnload); - order->Action = UnitActionUnload; order->goalPos = pos; if (what && !what->Destroyed) { order->SetGoal(what); @@ -430,9 +399,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); /* static */ COrder* COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type) { - COrder *order = new COrder; - - order->Action = UnitActionUpgradeTo; + COrder *order = new COrder(UnitActionUpgradeTo); // FIXME: if you give quick an other order, the resources are lost! unit.Player->SubUnitType(type); @@ -441,152 +408,10 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type); return order; } -#if 1 // currently needed for parsing -/* static */ COrder* COrder::NewActionAttack() -{ - COrder *order = new COrder; - - order->Action = UnitActionAttack; - return order; -} - -/* static */ COrder* COrder::NewActionAttackGround() -{ - COrder *order = new COrder; - - order->Action = UnitActionAttackGround; - return order; -} - -/* static */ COrder* COrder::NewActionBoard() -{ - COrder *order = new COrder; - - order->Action = UnitActionBoard; - return order; -} - -/* static */ COrder* COrder::NewActionBuild() -{ - COrder *order = new COrder; - - order->Action = UnitActionBuild; - return order; -} - -/* static */ COrder* COrder::NewActionBuilt() -{ - COrder *order = new COrder_Built; - - order->Action = UnitActionBuilt; - return order; -} - -/* static */ COrder* COrder::NewActionFollow() -{ - COrder *order = new COrder; - - order->Action = UnitActionFollow; - return order; -} - -/* static */ COrder* COrder::NewActionMove() -{ - COrder *order = new COrder; - - order->Action = UnitActionMove; - return order; -} - -/* static */ COrder* COrder::NewActionPatrol() -{ - COrder *order = new COrder; - - order->Action = UnitActionPatrol; - return order; -} - -/* static */ COrder* COrder::NewActionRepair() -{ - COrder *order = new COrder; - - order->Action = UnitActionRepair; - return order; -} - -/* static */ COrder* COrder::NewActionResearch() -{ - COrder_Research *order = new COrder_Research; - - order->Action = UnitActionResearch; - return order; -} - -/* static */ COrder* COrder::NewActionResource() -{ - COrder *order = new COrder; - - order->Action = UnitActionResource; - return order; -} - -/* static */ COrder* COrder::NewActionReturnGoods() -{ - COrder *order = new COrder; - - order->Action = UnitActionReturnGoods; - return order; -} - -/* static */ COrder* COrder::NewActionSpellCast() -{ - COrder *order = new COrder_SpellCast; - - order->Action = UnitActionSpellCast; - return order; -} - -/* static */ COrder* COrder::NewActionTrain() -{ - COrder *order = new COrder; - - order->Action = UnitActionTrain; - return order; -} - -/* static */ COrder* COrder::NewActionTransformInto() -{ - COrder *order = new COrder; - - order->Action = UnitActionTransformInto; - return order; -} - -/* static */ COrder* COrder::NewActionUnload() -{ - COrder *order = new COrder; - - order->Action = UnitActionUnload; - return order; -} - -/* static */ COrder* COrder::NewActionUpgradeTo() -{ - COrder *order = new COrder; - - order->Action = UnitActionUpgradeTo; - return order; -} - -#endif - - - COrder* COrder::Clone() const { - COrder *clone = new COrder(); + COrder *clone = new COrder(this->Action); - clone->Action = this->Action; clone->Range = this->Range; clone->MinRange = this->MinRange; clone->Width = this->Width; diff --git a/src/include/actions.h b/src/include/actions.h index 93c4e87f4..4f9440723 100644 --- a/src/include/actions.h +++ b/src/include/actions.h @@ -102,8 +102,8 @@ struct lua_State; class COrder { public: - COrder() : Goal(NULL), Range(0), MinRange(0), Width(0), - Height(0), Action(UnitActionNone), CurrentResource(0) + COrder(int action) : Goal(NULL), Range(0), MinRange(0), Width(0), + Height(0), Action(action), CurrentResource(0) { goalPos.x = -1; goalPos.y = -1; @@ -154,7 +154,7 @@ public: */ void NewResetPath() { Data.Move.Fast = 1; Data.Move.Length = 0; } void SaveDataMove(CFile &file) const; - + bool ParseMoveData(lua_State *l, int &j, const char *value); bool OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/); void AiUnitKilled(CUnit &unit); @@ -165,7 +165,6 @@ public: 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* NewActionBuilt(CUnit &builder, CUnit &unit); static COrder* NewActionDie(); static COrder* NewActionFollow(CUnit &dest); @@ -186,22 +185,19 @@ public: static COrder* NewActionUpgradeTo(CUnit &unit, CUnitType &type); #if 1 // currently needed for parsing - static COrder* NewActionAttack(); - static COrder* NewActionAttackGround(); - static COrder* NewActionBoard(); - static COrder* NewActionBuild(); - static COrder* NewActionFollow(); - static COrder* NewActionMove(); - static COrder* NewActionPatrol(); - static COrder* NewActionRepair(); - static COrder* NewActionResearch(); - static COrder* NewActionResource(); - static COrder* NewActionReturnGoods(); - static COrder* NewActionSpellCast(); - static COrder* NewActionTrain(); - static COrder* NewActionTransformInto(); - static COrder* NewActionUnload(); - static COrder* NewActionUpgradeTo(); + static COrder* NewActionAttack() { return new COrder(UnitActionAttack); } + static COrder* NewActionAttackGround() { return new COrder(UnitActionAttackGround); } + static COrder* NewActionBoard() { return new COrder(UnitActionBoard); } + static COrder* NewActionBuild() { return new COrder(UnitActionBuild); } + static COrder* NewActionFollow() { return new COrder(UnitActionFollow); } + static COrder* NewActionMove() { return new COrder(UnitActionMove); } + static COrder* NewActionRepair() { return new COrder(UnitActionRepair); } + static COrder* NewActionResource() { return new COrder(UnitActionResource); } + static COrder* NewActionReturnGoods() { return new COrder(UnitActionReturnGoods); } + static COrder* NewActionTrain() { return new COrder(UnitActionTrain); } + static COrder* NewActionTransformInto() { return new COrder(UnitActionTransformInto); } + static COrder* NewActionUnload() { return new COrder(UnitActionUnload); } + static COrder* NewActionUpgradeTo() { return new COrder(UnitActionUpgradeTo); } #endif private: @@ -218,7 +214,6 @@ public: Vec2i goalPos; /// or tile coordinate of destination union { - Vec2i Patrol; /// position for patroling. struct { Vec2i Pos; /// position for terrain resource. CUnit *Mine; @@ -257,7 +252,9 @@ class COrder_Built : public COrder { friend COrder* COrder::NewActionBuilt(CUnit &builder, CUnit &unit); public: - virtual COrder_Built *Clone() const; + COrder_Built() : COrder(UnitActionBuilt) {} + + virtual COrder_Built *Clone() const { return new COrder_Built(*this); } virtual void Save(CFile &file, const CUnit &unit) const; virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); @@ -289,11 +286,45 @@ private: }; +class COrder_Die : public COrder +{ +public: + COrder_Die() : COrder(UnitActionDie) {} + + virtual COrder_Die *Clone() const { return new COrder_Die(*this); } + + virtual void Save(CFile &file, const CUnit &unit) const; + virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); + + virtual bool Execute(CUnit &unit); +}; + + +class COrder_Patrol : public COrder +{ + friend COrder* COrder::NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest); +public: + COrder_Patrol() : COrder(UnitActionPatrol) {} + + virtual COrder_Patrol *Clone() const { return new COrder_Patrol(*this); } + + virtual void Save(CFile &file, const CUnit &unit) const; + virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); + + virtual bool Execute(CUnit &unit); + + const Vec2i& GetWayPoint() const { return WayPoint; } +private: + Vec2i WayPoint; /// position for patroling. +}; + class COrder_Research : public COrder { public: - virtual COrder_Research *Clone() const; + COrder_Research() : COrder(UnitActionResearch), Upgrade(NULL) {} + + virtual COrder_Research *Clone() const { return new COrder_Research(*this); } virtual void Save(CFile &file, const CUnit &unit) const; virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); @@ -309,10 +340,12 @@ private: CUpgrade *Upgrade; }; -class COrder_SpellCast: public COrder +class COrder_SpellCast : public COrder { public: - virtual COrder_SpellCast *Clone() const; + COrder_SpellCast() : COrder(UnitActionSpellCast), Spell(NULL) {} + + virtual COrder_SpellCast *Clone() const { return new COrder_SpellCast(*this); } virtual void Save(CFile &file, const CUnit &unit) const; virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); @@ -329,6 +362,36 @@ private: + +class COrder_StandGround : public COrder +{ +public: + COrder_StandGround() : COrder(UnitActionStandGround) {} + + virtual COrder_StandGround *Clone() const { return new COrder_StandGround(*this); } + + virtual void Save(CFile &file, const CUnit &unit) const; + virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); + + virtual bool Execute(CUnit &unit); +}; + +class COrder_Still : public COrder +{ +public: + COrder_Still() : COrder(UnitActionStill) {} + + virtual COrder_Still *Clone() const { return new COrder_Still(*this); } + + virtual void Save(CFile &file, const CUnit &unit) const; + virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); + + virtual bool Execute(CUnit &unit); +}; + + + + /*---------------------------------------------------------------------------- -- Variables ----------------------------------------------------------------------------*/ @@ -413,6 +476,10 @@ extern void DropResource(CUnit &unit); extern void ResourceGiveUp(CUnit &unit); extern int GetNumWaitingWorkers(const CUnit &mine); extern void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground); +extern bool AutoAttack(CUnit &unit, bool stand_ground); +extern bool AutoRepair(CUnit &unit); +extern bool AutoCast(CUnit &unit); + extern void UnHideUnit(CUnit &unit); typedef void HandleActionFunc(COrder& order, CUnit &unit); diff --git a/src/include/script.h b/src/include/script.h index d241a44a4..62bb2ce91 100644 --- a/src/include/script.h +++ b/src/include/script.h @@ -287,7 +287,28 @@ extern int CclCommand(const std::string &command, bool exitOnError = true); CUnit *CclGetUnitFromRef(lua_State *l); - +/** +** Get a position from lua state +** +** @param l Lua state. +** param x pointer to output x position. +** @param y pointer to output y position. +** +** @return The unit pointer +*/ +template <typename T> +static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1) +{ + if (!lua_istable(l, offset) || lua_objlen(l, offset) != 2) { + LuaError(l, "incorrect argument"); + } + lua_rawgeti(l, offset, 1); + *x = LuaToNumber(l, -1); + lua_pop(l, 1); + lua_rawgeti(l, offset, 2); + *y = LuaToNumber(l, -1); + lua_pop(l, 1); +} extern NumberDesc *Damage; /// Damage calculation for missile. diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index a913f54bd..504919800 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -132,29 +132,6 @@ CUnit *CclGetUnitFromRef(lua_State *l) return UnitSlots[slot]; } -/** -** Get a position from lua state -** -** @param l Lua state. -** @param x pointer to output x position. -** @param y pointer to output y position. -** -** @return The unit pointer -*/ -template <typename T> -static void CclGetPos(lua_State *l, T *x , T *y, const int offset = -1) -{ - if (!lua_istable(l, offset) || lua_objlen(l, offset) != 2) { - LuaError(l, "incorrect argument"); - } - lua_rawgeti(l, offset, 1); - *x = LuaToNumber(l, -1); - lua_pop(l, 1); - lua_rawgeti(l, offset, 2); - *y = LuaToNumber(l, -1); - lua_pop(l, 1); -} - /** ** Parse res worker data ** @@ -251,55 +228,6 @@ static void CclParseTrain(lua_State *l, COrderPtr order) } } -/** -** Parse stored data for move order -** -** @param l Lua state. -** @param unit Unit pointer which should be filled with the data. -*/ -static void CclParseMove(lua_State *l, COrderPtr order) -{ - const char *value; - int args; - int j; - - if (!lua_istable(l, -1)) { - LuaError(l, "incorrect argument"); - } - args = lua_objlen(l, -1); - for (j = 0; j < args; ++j) { - lua_rawgeti(l, -1, j + 1); - value = LuaToString(l, -1); - lua_pop(l, 1); - ++j; - if (!strcmp(value, "cycles")) { - lua_rawgeti(l, -1, j + 1); - order->Data.Move.Cycles = LuaToNumber(l, -1); - lua_pop(l, 1); - } else if (!strcmp(value, "fast")) { - order->Data.Move.Fast = 1; - --j; - } else if (!strcmp(value, "path")) { - int subargs; - int k; - - lua_rawgeti(l, -1, j + 1); - if (!lua_istable(l, -1)) { - LuaError(l, "incorrect argument"); - } - subargs = lua_objlen(l, -1); - for (k = 0; k < subargs; ++k) { - lua_rawgeti(l, -1, k + 1); - order->Data.Move.Path[k] = LuaToNumber(l, -1); - lua_pop(l, 1); - } - order->Data.Move.Length = subargs; - lua_pop(l, 1); - } else { - LuaError(l, "ParseMove: Unsupported tag: %s" _C_ value); - } - } -} bool COrder::ParseGenericData(lua_State *l, int &j, const char *value) { @@ -339,6 +267,52 @@ bool COrder::ParseGenericData(lua_State *l, int &j, const char *value) return true; } + +bool COrder::ParseMoveData(lua_State *l, int &j, const char *value) +{ + if (strcmp(value, "data-move") != 0) { + return false; + } + ++j; + lua_rawgeti(l, -1, j + 1); + + if (!lua_istable(l, -1)) { + LuaError(l, "incorrect argument"); + } + const int args = 1 + lua_objlen(l, -1); + for (int i = 1; i < args; ++i) { + lua_rawgeti(l, -1, i); + const char *tag = LuaToString(l, -1); + lua_pop(l, 1); + ++i; + if (!strcmp(tag, "cycles")) { + lua_rawgeti(l, -1, i); + this->Data.Move.Cycles = LuaToNumber(l, -1); + lua_pop(l, 1); + } else if (!strcmp(tag, "fast")) { + this->Data.Move.Fast = 1; + --i; + } else if (!strcmp(tag, "path")) { + lua_rawgeti(l, -1, i); + if (!lua_istable(l, -1)) { + LuaError(l, "incorrect argument _"); + } + const int subargs = lua_objlen(l, -1); + for (int k = 0; k < subargs; ++k) { + lua_rawgeti(l, -1, k + 1); + this->Data.Move.Path[k] = LuaToNumber(l, -1); + lua_pop(l, 1); + } + this->Data.Move.Length = subargs; + lua_pop(l, 1); + } else { + LuaError(l, "ParseMove: Unsupported tag: %s" _C_ tag); + } + } + lua_pop(l, 1); + return true; +} + bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) { if (!strcmp(value, "type")) { @@ -347,11 +321,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU this->Arg1.Type = UnitTypeByIdent(LuaToString(l, -1)); lua_pop(l, 1); - } else if (!strcmp(value, "patrol")) { - ++j; - lua_rawgeti(l, -1, j + 1); - CclGetPos(l, &this->Arg1.Patrol.x , &this->Arg1.Patrol.y); - lua_pop(l, 1); } else if (!strcmp(value, "current-resource")) { ++j; lua_rawgeti(l, -1, j + 1); @@ -387,11 +356,6 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU lua_rawgeti(l, -1, j + 1); CclParseTrain(l, this); lua_pop(l, 1); - } else if (!strcmp(value, "data-move")) { - ++j; - lua_rawgeti(l, -1, j + 1); - CclParseMove(l, this); - lua_pop(l, 1); } else if (!strcmp(value, "mine")) { /* old save format */ int pos; ++j; @@ -439,9 +403,9 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr) lua_pop(l, 1); if (!strcmp(actiontype, "action-still")) { - *orderPtr = COrder::NewActionStill(); + *orderPtr = new COrder_Still; } else if (!strcmp(actiontype, "action-stand-ground")) { - *orderPtr = COrder::NewActionStandGround(); + *orderPtr = new COrder_StandGround; } else if (!strcmp(actiontype, "action-follow")) { *orderPtr = COrder::NewActionFollow(); } else if (!strcmp(actiontype, "action-move")) { @@ -451,23 +415,23 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr) } else if (!strcmp(actiontype, "action-attack-ground")) { *orderPtr = COrder::NewActionAttackGround(); } else if (!strcmp(actiontype, "action-die")) { - *orderPtr = COrder::NewActionDie(); + *orderPtr = new COrder_Die; } else if (!strcmp(actiontype, "action-spell-cast")) { - *orderPtr = COrder::NewActionSpellCast(); + *orderPtr = new COrder_SpellCast; } else if (!strcmp(actiontype, "action-train")) { *orderPtr = COrder::NewActionTrain(); } else if (!strcmp(actiontype, "action-upgrade-to")) { *orderPtr = COrder::NewActionUpgradeTo(); } else if (!strcmp(actiontype, "action-research")) { - *orderPtr = COrder::NewActionResearch(); + *orderPtr = new COrder_Research; } else if (!strcmp(actiontype, "action-built")) { - *orderPtr = COrder::NewActionBuilt(); + *orderPtr = new COrder_Built; } else if (!strcmp(actiontype, "action-board")) { *orderPtr = COrder::NewActionBoard(); } else if (!strcmp(actiontype, "action-unload")) { *orderPtr = COrder::NewActionUnload(); } else if (!strcmp(actiontype, "action-patrol")) { - *orderPtr = COrder::NewActionPatrol(); + *orderPtr = new COrder_Patrol; } else if (!strcmp(actiontype, "action-build")) { *orderPtr = COrder::NewActionBuild(); } else if (!strcmp(actiontype, "action-repair")) { diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index 9fdf3e5f2..6a3050c92 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -737,12 +737,15 @@ static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder break; case UnitActionPatrol: + { Video.DrawLineClip(ColorGreen, pos1.x, pos1.y, pos2.x, pos2.y); e_color = color = ColorBlue; - pos1 = CurrentViewport->TilePosToScreen_Center(order.Arg1.Patrol); + const COrder_Patrol &orderPatrol = static_cast<const COrder_Patrol&>(order); + + pos1 = CurrentViewport->TilePosToScreen_Center(orderPatrol.GetWayPoint()); dest = true; break; - + } case UnitActionRepair: e_color = color = ColorGreen; dest = true; diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp index fed0b6265..81e7a4447 100644 --- a/src/unit/unit_save.cpp +++ b/src/unit/unit_save.cpp @@ -96,12 +96,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) case UnitActionNone: file.printf("\"action-none\","); break; - case UnitActionStill: - file.printf("\"action-still\","); - break; - case UnitActionStandGround: - file.printf("\"action-stand-ground\","); - break; case UnitActionFollow: file.printf("\"action-follow\","); break; @@ -114,9 +108,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) case UnitActionAttackGround: file.printf("\"action-attack-ground\","); break; - case UnitActionDie: - file.printf("\"action-die\","); - break; case UnitActionTrain: file.printf("\"action-train\","); break; @@ -129,9 +120,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) case UnitActionUnload: file.printf("\"action-unload\","); break; - case UnitActionPatrol: - file.printf("\"action-patrol\","); - break; case UnitActionBuild: file.printf("\"action-build\","); break; @@ -174,9 +162,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) case UnitActionTransformInto: file.printf(", \"type\", \"%s\"", order.Arg1.Type->Ident.c_str()); break; - case UnitActionPatrol: - file.printf(", \"patrol\", {%d, %d}", order.Arg1.Patrol.x, order.Arg1.Patrol.y); - break; case UnitActionResource : case UnitActionReturnGoods : if (order.CurrentResource) {