From d3c2041d2737ba61c9d52be5112b356250b5a4e5 Mon Sep 17 00:00:00 2001 From: joris <joris.dauphin@gmail.com> Date: Sat, 25 Feb 2012 12:41:53 +0100 Subject: [PATCH] COrder_Attack COrder is now abstract --- src/action/action_attack.cpp | 282 ++++++++++++++++++----------------- src/action/actions.cpp | 162 +------------------- src/include/actions.h | 58 +++---- src/unit/script_unit.cpp | 67 ++++----- src/unit/unit_draw.cpp | 7 +- src/unit/unit_save.cpp | 66 -------- 6 files changed, 212 insertions(+), 430 deletions(-) diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index 28f7617ae..23a623cd7 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -52,6 +52,8 @@ #include "sound.h" #include "map.h" #include "pathfinder.h" +#include "script.h" +#include "iolib.h" /*---------------------------------------------------------------------------- -- Defines @@ -85,6 +87,59 @@ void AnimateActionAttack(CUnit &unit) UnitShowAnimation(unit, unit.Type->Animations->Attack); } + +/* virtual */ void COrder_Attack::Save(CFile &file, const CUnit &unit) const +{ + Assert(Action == UnitActionAttack || Action == UnitActionAttackGround); + + if (Action == UnitActionAttack) { + file.printf("{\"action-attack\","); + } else { + file.printf("{\"action-attack-ground\","); + } + file.printf(" \"range\", %d,", this->Range); + file.printf(" \"min-range\", %d,", this->MinRange); + + if (this->Finished) { + file.printf(" \"finished\", "); + } + 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(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y); + + file.printf(" \"state\", %d,\n ", this->State); + SaveDataMove(file); + file.printf("}"); +} + + +/* virtual */ bool COrder_Attack::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) +{ + if (this->ParseMoveData(l, j, value)) { + return true; + } else if (!strcmp(value, "state")) { + ++j; + lua_rawgeti(l, -1, j + 1); + this->State = LuaToNumber(l, -1); + lua_pop(l, 1); + } else { + return false; + } + return true; +} + +bool COrder_Attack::IsWeakTargetSelected() const +{ + return (this->State & WEAK_TARGET) != 0; +} + /** ** Check for dead goal. ** @@ -95,34 +150,29 @@ void AnimateActionAttack(CUnit &unit) ** ** @param unit Unit using the goal. ** -** @return 1 if order have changed, 0 else. +** @return true if order have changed, false else. */ -static int CheckForDeadGoal(CUnit &unit) +bool COrder_Attack::CheckForDeadGoal(CUnit &unit) { - COrderPtr order = unit.CurrentOrder(); - CUnit *goal = order->GetGoal(); + CUnit *goal = this->GetGoal(); // Position or valid target, it is ok. if (!goal || goal->IsVisibleAsGoal(*unit.Player)) { - return 0; + return false; } // Goal could be destroyed or unseen // So, cannot use type. - order->goalPos = goal->tilePos; - order->MinRange = 0; - order->Range = 0; - order->ClearGoal(); + this->goalPos = goal->tilePos; + this->MinRange = 0; + this->Range = 0; + this->ClearGoal(); - // // If we have a saved order continue this saved order. - // if (unit.RestoreOrder()) { - //unit.ClearAction(); - return 1; + return true; } -// NewResetPath(unit); // Should be useless. - return 0; + return false; } /** @@ -130,58 +180,55 @@ static int CheckForDeadGoal(CUnit &unit) ** ** @param unit Unit to check if goal is in range ** -** @return 1 if order(action) have changed, 0 else (if goal change retrun 0). +** @return true if order(action) have changed, false else (if goal change return false). */ -static int CheckForTargetInRange(CUnit &unit) +bool COrder_Attack::CheckForTargetInRange(CUnit &unit) { // Target is dead? if (CheckForDeadGoal(unit)) { - return 1; + return true; } - COrderPtr order = unit.CurrentOrder(); // No goal: if meeting enemy attack it. - if (!order->HasGoal() && - order->Action != UnitActionAttackGround && - !Map.WallOnMap(order->goalPos)) { + if (!this->HasGoal() + && this->Action != UnitActionAttackGround + && !Map.WallOnMap(this->goalPos)) { CUnit *goal = AttackUnitsInReactRange(unit); if (goal) { - COrder *savedOrder = COrder::NewActionAttack(unit, order->goalPos); + COrder *savedOrder = COrder::NewActionAttack(unit, this->goalPos); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } - order->SetGoal(goal); - order->MinRange = unit.Type->MinAttackRange; - order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; - order->goalPos.x = order->goalPos.y = -1; - order->SubAction.Attack |= WEAK_TARGET; // weak target - order->NewResetPath(); + this->SetGoal(goal); + this->MinRange = unit.Type->MinAttackRange; + this->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; + this->goalPos.x = this->goalPos.y = -1; + this->State |= WEAK_TARGET; // weak target + this->NewResetPath(); } // Have a weak target, try a better target. - } else if (order->HasGoal() && (order->SubAction.Attack & WEAK_TARGET)) { - CUnit *goal = order->GetGoal(); - CUnit *temp = AttackUnitsInReactRange(unit); + } else if (this->HasGoal() && (this->State & WEAK_TARGET)) { + CUnit *goal = this->GetGoal(); + CUnit *newTarget = AttackUnitsInReactRange(unit); - if (temp && temp->Type->Priority > goal->Type->Priority) { - COrder *savedOrder = order->Clone(); + if (newTarget && newTarget->Type->Priority > goal->Type->Priority) { + COrder *savedOrder = this->Clone(); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } - order->SetGoal(temp); - order->goalPos.x = order->goalPos.y = -1; - order->NewResetPath(); + this->SetGoal(newTarget); + this->goalPos.x = this->goalPos.y = -1; + this->NewResetPath(); } } Assert(!unit.Type->Vanishes && !unit.Destroyed && !unit.Removed); - Assert(order->Action == UnitActionAttack || order->Action == UnitActionAttackGround); - - return 0; + return false; } /** @@ -189,13 +236,12 @@ static int CheckForTargetInRange(CUnit &unit) ** ** @param unit Unit that is attacking and moving */ -static void MoveToTarget(CUnit &unit) +void COrder_Attack::MoveToTarget(CUnit &unit) { Assert(!unit.Type->Vanishes && !unit.Destroyed && !unit.Removed); - Assert(unit.CurrentAction() == UnitActionAttack || unit.CurrentAction() == UnitActionAttackGround); + Assert(unit.CurrentOrder() == this); Assert(unit.CanMove()); - Assert(unit.CurrentOrder()->HasGoal() - || (unit.CurrentOrder()->goalPos.x != -1 && unit.CurrentOrder()->goalPos.y != -1)); + Assert(this->HasGoal() || Map.Info.IsPointOnMap(this->goalPos)); int err = DoActionMove(unit); @@ -203,14 +249,10 @@ static void MoveToTarget(CUnit &unit) return; } - // // Look if we have reached the target. - // - COrderPtr order = unit.CurrentOrder(); - if (err == 0 && !order->HasGoal()) { + if (err == 0 && !this->HasGoal()) { // Check if we're in range when attacking a location and we are waiting - if (unit.MapDistanceTo(order->goalPos.x, order->goalPos.y) <= - unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { + if (unit.MapDistanceTo(this->goalPos.x, this->goalPos.y) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { err = PF_REACHED; } } @@ -221,58 +263,48 @@ static void MoveToTarget(CUnit &unit) return; } if (err == PF_REACHED) { - CUnit *goal = order->GetGoal(); - // + CUnit *goal = this->GetGoal(); // Have reached target? FIXME: could use the new return code? - // if (goal && unit.MapDistanceTo(*goal) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { // Reached another unit, now attacking it unit.State = 0; const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos; UnitHeadingFromDeltaXY(unit, dir); - order->SubAction.Attack++; + this->State++; return; } - // // Attacking wall or ground. - // - if (!goal && (Map.WallOnMap(order->goalPos) || - order->Action == UnitActionAttackGround) && - unit.MapDistanceTo(order->goalPos.x, order->goalPos.y) <= - unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { + if (!goal && (Map.WallOnMap(this->goalPos) || this->Action == UnitActionAttackGround) + && unit.MapDistanceTo(this->goalPos.x, this->goalPos.y) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { // Reached wall or ground, now attacking it unit.State = 0; - UnitHeadingFromDeltaXY(unit, order->goalPos - unit.tilePos); - order->SubAction.Attack &= WEAK_TARGET; - order->SubAction.Attack |= ATTACK_TARGET; + UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos); + this->State &= WEAK_TARGET; + this->State |= ATTACK_TARGET; return; } } - // // Unreachable. - // + if (err == PF_UNREACHABLE) { unit.State = 0; - if (!order->HasGoal()) { - // + if (!this->HasGoal()) { // When attack-moving we have to allow a bigger range - // - if (order->CheckRange()) { + if (this->CheckRange()) { // Try again with more range - order->Range++; + this->Range++; unit.Wait = 5; return; } } else { - order->ClearGoal(); + this->ClearGoal(); } } - // + // Return to old task? - // if (!unit.RestoreOrder()) { - unit.ClearAction(); + this->Finished = true; unit.State = 0; } } @@ -282,34 +314,26 @@ static void MoveToTarget(CUnit &unit) ** ** @param unit Unit, for that the attack is handled. */ -static void AttackTarget(CUnit &unit) +void COrder_Attack::AttackTarget(CUnit &unit) { - Assert(unit.CurrentOrder()->HasGoal() || - (unit.CurrentOrder()->goalPos.x != -1 && unit.CurrentOrder()->goalPos.y != -1)); + Assert(this->HasGoal() || Map.Info.IsPointOnMap(this->goalPos)); AnimateActionAttack(unit); if (unit.Anim.Unbreakable) { return; } - // - // Goal is "weak" or a wall. - // - COrderPtr order = unit.CurrentOrder(); - if (!order->HasGoal() && (order->Action == UnitActionAttackGround || Map.WallOnMap(order->goalPos))) { + + if (!this->HasGoal() && (this->Action == UnitActionAttackGround || Map.WallOnMap(this->goalPos))) { return; } - // // Target is dead ? Change order ? - // if (CheckForDeadGoal(unit)) { return; } - CUnit *goal = order->GetGoal(); + CUnit *goal = this->GetGoal(); - // // No target choose one. - // if (!goal) { unit.State = 0; goal = AttackUnitsInReactRange(unit); @@ -320,71 +344,65 @@ static void AttackTarget(CUnit &unit) if (unit.RestoreOrder()) { return; } - order->SubAction.Attack = MOVE_TO_TARGET; + this->State = MOVE_TO_TARGET; return; } // Save current command to come back. - COrder *savedOrder = order->Clone(); + COrder *savedOrder = this->Clone(); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } - order->SetGoal(goal); - order->goalPos.x = order->goalPos.y = -1; - order->MinRange = unit.Type->MinAttackRange; - order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; - order->NewResetPath(); - order->SubAction.Attack |= WEAK_TARGET; + this->SetGoal(goal); + this->goalPos.x = this->goalPos.y = -1; + this->MinRange = unit.Type->MinAttackRange; + this->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max; + this->NewResetPath(); + this->State |= WEAK_TARGET; - // // Have a weak target, try a better target. // FIXME: if out of range also try another target quick - // } else { - if ((order->SubAction.Attack & WEAK_TARGET)) { - CUnit *temp = AttackUnitsInReactRange(unit); - if (temp && temp->Type->Priority > goal->Type->Priority) { - COrder *savedOrder = order->Clone(); + if ((this->State & WEAK_TARGET)) { + CUnit *newTarget = AttackUnitsInReactRange(unit); + if (newTarget && newTarget->Type->Priority > goal->Type->Priority) { + COrder *savedOrder = this->Clone(); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } - goal = temp; - order->SetGoal(temp); - order->goalPos.x = order->goalPos.y = -1; - order->MinRange = unit.Type->MinAttackRange; - order->SubAction.Attack = MOVE_TO_TARGET; - order->NewResetPath(); + goal = newTarget; + this->SetGoal(newTarget); + this->goalPos.x = this->goalPos.y = -1; + this->MinRange = unit.Type->MinAttackRange; + this->State = MOVE_TO_TARGET; + this->NewResetPath(); } } } - // // Still near to target, if not goto target. - // - int dist = unit.MapDistanceTo(*goal); + const int dist = unit.MapDistanceTo(*goal); if (dist > unit.Stats->Variables[ATTACKRANGE_INDEX].Max) { - COrder *savedOrder = order->Clone(); + COrder *savedOrder = this->Clone(); if (unit.StoreOrder(savedOrder) == false) { delete savedOrder; savedOrder = NULL; } - order->NewResetPath(); + this->NewResetPath(); unit.Frame = 0; unit.State = 0; - order->SubAction.Attack &= WEAK_TARGET; - order->SubAction.Attack |= MOVE_TO_TARGET; + this->State &= WEAK_TARGET; + this->State |= MOVE_TO_TARGET; } if (dist < unit.Type->MinAttackRange) { - order->SubAction.Attack = MOVE_TO_TARGET; + this->State = MOVE_TO_TARGET; } - // // Turn always to target - // if (goal) { const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos; UnitHeadingFromDeltaXY(unit, dir); @@ -394,9 +412,8 @@ static void AttackTarget(CUnit &unit) /** ** Unit attacks! ** -** I added a little trick, if SubAction&WEAK_TARGET is true the goal is -** a weak goal. This means the unit AI (little AI) could choose a new -** better goal. +** if (SubAction & WEAK_TARGET) is true the goal is a weak goal. +** This means the unit AI (little AI) could choose a new better goal. ** ** @todo Lets do some tries to reach the target. ** If target place is not reachable, choose better goal to reduce @@ -404,26 +421,24 @@ static void AttackTarget(CUnit &unit) ** ** @param unit Unit, for that the attack is handled. */ -void HandleActionAttack(COrder& order, CUnit &unit) +/* virtual */ void COrder_Attack::Execute(CUnit &unit) { - Assert(order.Action == UnitActionAttackGround || order.Action == UnitActionAttack); - Assert(order.HasGoal() || Map.Info.IsPointOnMap(order.goalPos)); + Assert(this->HasGoal() || Map.Info.IsPointOnMap(this->goalPos)); if (unit.Wait) { unit.Wait--; return; } - switch (order.SubAction.Attack) { - case 0: // First entry - { + switch (this->State) { + case 0: { // First entry // did Order change ? if (CheckForTargetInRange(unit)) { return; } // Can we already attack ? - if (order.HasGoal()) { - CUnit &goal = *order.GetGoal(); + if (this->HasGoal()) { + CUnit &goal = *this->GetGoal(); const int dist = goal.MapDistanceTo(unit); if (unit.Type->MinAttackRange < dist && @@ -431,13 +446,13 @@ void HandleActionAttack(COrder& order, CUnit &unit) const Vec2i dir = goal.tilePos + goal.Type->GetHalfTileSize() - unit.tilePos; UnitHeadingFromDeltaXY(unit, dir); - order.SubAction.Attack = ATTACK_TARGET; + this->State = ATTACK_TARGET; AttackTarget(unit); return; } } - order.SubAction.Attack = MOVE_TO_TARGET; - order.NewResetPath(); + this->State = MOVE_TO_TARGET; + this->NewResetPath(); // FIXME: should use a reachable place to reduce pathfinder time. Assert(unit.State == 0); } @@ -446,7 +461,7 @@ void HandleActionAttack(COrder& order, CUnit &unit) case MOVE_TO_TARGET + WEAK_TARGET: if (!unit.CanMove()) { if (!unit.RestoreOrder()) { - unit.ClearAction(); + this->Finished = true; unit.State = 0; } return; @@ -454,9 +469,6 @@ void HandleActionAttack(COrder& order, CUnit &unit) MoveToTarget(unit); break; - // - // Attack the target. - // case ATTACK_TARGET: case ATTACK_TARGET + WEAK_TARGET: AttackTarget(unit); diff --git a/src/action/actions.cpp b/src/action/actions.cpp index a699e67c4..0384458bb 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -88,7 +88,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures /* static */ COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target) { - COrder *order = new COrder(UnitActionAttack); + COrder_Attack *order = new COrder_Attack(false); if (target.Destroyed) { order->goalPos = target.tilePos + target.Type->GetHalfTileSize(); @@ -105,7 +105,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures { Assert(Map.Info.IsPointOnMap(dest)); - COrder *order = new COrder(UnitActionAttack); + COrder_Attack *order = new COrder_Attack(false); if (Map.WallOnMap(dest) && Map.IsFieldExplored(*attacker.Player, dest)) { // FIXME: look into action_attack.cpp about this ugly problem @@ -120,7 +120,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures /* static */ COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest) { - COrder *order = new COrder(UnitActionAttackGround); + COrder_Attack *order = new COrder_Attack(true); order->goalPos = dest; order->Range = attacker.Stats->Variables[ATTACKRANGE_INDEX].Max; @@ -409,20 +409,6 @@ unsigned SyncHash; /// Hash calculated to find sync failures return order; } -COrder* COrder::Clone() const -{ - COrder *clone = new COrder(this->Action); - - clone->Range = this->Range; - clone->MinRange = this->MinRange; - clone->Width = this->Width; - clone->Height = this->Height; - clone->SetGoal(this->Goal); - clone->goalPos = this->goalPos; - memcpy(&clone->Data, &this->Data, sizeof (clone->Data)); - return clone; -} - COrder::~COrder() { if (Goal) { @@ -1254,140 +1240,6 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale) -- Actions ----------------------------------------------------------------------------*/ -/** -** Unit does nothing! -** -** @param unit Unit pointer for none action. -*/ -static void HandleActionNone(COrder&, CUnit &unit) -{ - DebugPrint("FIXME: Should not happen!\n"); - DebugPrint("FIXME: Unit (%d) %s has action none.!\n" _C_ - UnitNumber(unit) _C_ unit.Type->Ident.c_str()); -} - -/** -** Unit has not written function. -** -** @param unit Unit pointer for not written action. -*/ -static void HandleActionNotWritten(COrder&, CUnit &unit) -{ - DebugPrint("FIXME: Not written!\n"); - DebugPrint("FIXME: Unit (%d) %s has action %d.!\n" _C_ - UnitNumber(unit) _C_ unit.Type->Ident.c_str() _C_ unit.CurrentAction()); -} - -/** -** Jump table for actions. -** -** @note can move function into unit structure. -*/ -static void (*HandleActionTable[256])(COrder&, CUnit &) = { - HandleActionNone, - HandleActionNone, // HandleActionStill, - HandleActionNone, // HandleActionStandGround, - HandleActionNone, // HandleActionFollow, - HandleActionNone, // HandleActionMove, - HandleActionAttack, - HandleActionAttack, // HandleActionAttackGround, - HandleActionNone, // HandleActionDie, - HandleActionNone, // HandleActionSpellCast, - HandleActionNone, // HandleActionTrain, - HandleActionNone, // HandleActionUpgradeTo, - HandleActionNone, // HandleActionResearch, - HandleActionNone, // HandleActionBuilt, - HandleActionNone, // HandleActionBoard, - HandleActionNone, // HandleActionUnload, - HandleActionNone, // HandleActionPatrol, - HandleActionNone, // HandleActionBuild, - HandleActionNone, // HandleActionRepair, - HandleActionNone, // HandleActionResource, - HandleActionNone, // HandleActionReturnGoods, - HandleActionNone, // HandleActionTransformInto, - HandleActionNotWritten, - - // Enough for the future ? - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, - HandleActionNotWritten, HandleActionNotWritten, HandleActionNotWritten, -}; - /** ** Increment a unit's health ** @@ -1469,14 +1321,6 @@ static void HandleBuffs(CUnit &unit, int amount) } - - -void COrder::Execute(CUnit &unit) -{ - HandleActionTable[Action](*this, unit); -} - - /** ** Handle the action of a unit. ** diff --git a/src/include/actions.h b/src/include/actions.h index 77ce35a92..3ce0adc57 100644 --- a/src/include/actions.h +++ b/src/include/actions.h @@ -83,7 +83,6 @@ enum UnitAction { UnitActionRepair, /// unit repairing UnitActionResource, /// unit harvesting resources - UnitActionDummy, // UnitActionReturnGoods, /// unit returning any resource UnitActionTransformInto /// unit transform into type. }; @@ -101,26 +100,24 @@ struct lua_State; */ class COrder { - public: COrder(int action) : Goal(NULL), Range(0), MinRange(0), Width(0), Height(0), Action(action), Finished(false) { goalPos.x = -1; goalPos.y = -1; - memset(&SubAction, 0, sizeof (SubAction)); memset(&Data, 0, sizeof (Data)); } virtual ~COrder(); - virtual COrder *Clone() const; - virtual void Execute(CUnit &unit); + virtual COrder *Clone() const = 0; + virtual void Execute(CUnit &unit) = 0; virtual void Cancel(CUnit &unit) {} virtual void OnAnimationAttack(CUnit &unit); - virtual void Save(CFile &file, const CUnit &unit) const; + virtual void Save(CFile &file, const CUnit &unit) const = 0; bool ParseGenericData(lua_State *l, int &j, const char *value); - virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit); + virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) = 0; virtual void UpdateUnitVariables(CUnit &unit) const {} virtual void FillSeenValues(CUnit &unit) const; @@ -143,7 +140,6 @@ public: bool OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/); - 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); @@ -168,13 +164,7 @@ public: static COrder* NewActionUnload(const Vec2i &pos, CUnit *what); static COrder* NewActionUpgradeTo(CUnit &unit, CUnitType &type); -#if 1 // currently needed for parsing - static COrder* NewActionAttack() { return new COrder(UnitActionAttack); } - static COrder* NewActionAttackGround() { return new COrder(UnitActionAttackGround); } -#endif - private: - CUnit *Goal; public: int Range; /// How far away @@ -186,12 +176,7 @@ public: Vec2i goalPos; /// or tile coordinate of destination - union { - int Attack; - } SubAction; - - - union _order_data_ { + struct _order_data_ { struct _order_move_ { unsigned short int Cycles; /// how much Cycles we move. char Fast; /// Flag fast move (one step) @@ -202,6 +187,33 @@ public: } Data; /// Storage room for different commands }; +class COrder_Attack : public COrder +{ + friend COrder* COrder::NewActionAttack(const CUnit &attacker, CUnit &target); + friend COrder* COrder::NewActionAttack(const CUnit &attacker, const Vec2i &dest); + friend COrder* COrder::NewActionAttackGround(const CUnit &attacker, const Vec2i &dest); +public: + COrder_Attack(bool ground) : COrder(ground ? UnitActionAttackGround : UnitActionAttack), State(0) + {} + + virtual COrder_Attack* Clone() const { return new COrder_Attack(*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 void Execute(CUnit &unit); + + bool IsWeakTargetSelected() const; + +private: + bool CheckForDeadGoal(CUnit &unit); + bool CheckForTargetInRange(CUnit &unit); + void MoveToTarget(CUnit &unit); + void AttackTarget(CUnit &unit); + +private: + int State; +}; class COrder_Board : public COrder { @@ -667,12 +679,6 @@ extern int DoActionMove(CUnit &unit); /// Show attack animation extern void AnimateActionAttack(CUnit &unit); - -typedef void HandleActionFunc(COrder& order, CUnit &unit); - - /// Handle command attack -extern HandleActionFunc HandleActionAttack; - /*---------------------------------------------------------------------------- -- Actions: actions.c ----------------------------------------------------------------------------*/ diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index d45c27b74..1fc72382a 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -221,21 +221,6 @@ bool COrder::ParseMoveData(lua_State *l, int &j, const char *value) return true; } -bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit) -{ - if (this->ParseMoveData(l, j, value)) { - return true; - } else if (!strcmp(value, "subaction")) { - ++j; - lua_rawgeti(l, -1, j + 1); - this->SubAction.Attack = LuaToNumber(l, -1); - lua_pop(l, 1); - } else { - return false; - } - return true; -} - /** ** Parse order ** @@ -250,44 +235,44 @@ void CclParseOrder(lua_State *l, CUnit &unit, COrderPtr *orderPtr) const char *actiontype = LuaToString(l, -1); lua_pop(l, 1); - if (!strcmp(actiontype, "action-still")) { - *orderPtr = new COrder_Still(false); - } else if (!strcmp(actiontype, "action-stand-ground")) { - *orderPtr = new COrder_Still(true); + if (!strcmp(actiontype, "action-attack")) { + *orderPtr = new COrder_Attack(false); + } else if (!strcmp(actiontype, "action-attack-ground")) { + *orderPtr = new COrder_Attack(true); + } else if (!strcmp(actiontype, "action-board")) { + *orderPtr = new COrder_Board; + } else if (!strcmp(actiontype, "action-build")) { + *orderPtr = new COrder_Build; + } else if (!strcmp(actiontype, "action-built")) { + *orderPtr = new COrder_Built; + } else if (!strcmp(actiontype, "action-die")) { + *orderPtr = new COrder_Die; } else if (!strcmp(actiontype, "action-follow")) { *orderPtr = new COrder_Follow; } else if (!strcmp(actiontype, "action-move")) { *orderPtr = new COrder_Move; - } else if (!strcmp(actiontype, "action-attack")) { - *orderPtr = COrder::NewActionAttack(); - } else if (!strcmp(actiontype, "action-attack-ground")) { - *orderPtr = COrder::NewActionAttackGround(); - } else if (!strcmp(actiontype, "action-die")) { - *orderPtr = new COrder_Die; - } else if (!strcmp(actiontype, "action-spell-cast")) { - *orderPtr = new COrder_SpellCast; - } else if (!strcmp(actiontype, "action-train")) { - *orderPtr = new COrder_Train; - } else if (!strcmp(actiontype, "action-upgrade-to")) { - *orderPtr = new COrder_UpgradeTo; - } else if (!strcmp(actiontype, "action-research")) { - *orderPtr = new COrder_Research; - } else if (!strcmp(actiontype, "action-built")) { - *orderPtr = new COrder_Built; - } else if (!strcmp(actiontype, "action-board")) { - *orderPtr = new COrder_Board; - } else if (!strcmp(actiontype, "action-unload")) { - *orderPtr = new COrder_Unload; } else if (!strcmp(actiontype, "action-patrol")) { *orderPtr = new COrder_Patrol; - } else if (!strcmp(actiontype, "action-build")) { - *orderPtr = new COrder_Build; } else if (!strcmp(actiontype, "action-repair")) { *orderPtr = new COrder_Repair; + } else if (!strcmp(actiontype, "action-research")) { + *orderPtr = new COrder_Research; } else if (!strcmp(actiontype, "action-resource")) { *orderPtr = new COrder_Resource(unit); + } else if (!strcmp(actiontype, "action-spell-cast")) { + *orderPtr = new COrder_SpellCast; + } else if (!strcmp(actiontype, "action-stand-ground")) { + *orderPtr = new COrder_Still(true); + } else if (!strcmp(actiontype, "action-still")) { + *orderPtr = new COrder_Still(false); + } else if (!strcmp(actiontype, "action-train")) { + *orderPtr = new COrder_Train; } else if (!strcmp(actiontype, "action-transform-into")) { *orderPtr = new COrder_TransformInto; + } else if (!strcmp(actiontype, "action-upgrade-to")) { + *orderPtr = new COrder_UpgradeTo; + } else if (!strcmp(actiontype, "action-unload")) { + *orderPtr = new COrder_Unload; } else { LuaError(l, "ParseOrder: Unsupported type: %s" _C_ actiontype); } diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index b56876ea1..0639f23c2 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -756,9 +756,10 @@ static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder case UnitActionAttackGround: pos2 = CurrentViewport->TilePosToScreen_Center(order.goalPos); // FALL THROUGH - case UnitActionAttack: - { - if (order.SubAction.Attack & 2) { // Show weak targets. + case UnitActionAttack: { + const COrder_Attack &orderAttack = static_cast<const COrder_Attack&>(order); + + if (orderAttack.IsWeakTargetSelected()) { // Show weak targets. e_color = ColorBlue; } else { e_color = ColorRed; diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp index d1e1db55b..60d0a2222 100644 --- a/src/unit/unit_save.cpp +++ b/src/unit/unit_save.cpp @@ -88,72 +88,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file) order.Save(*file, unit); } -/* virtual */ void COrder::Save(CFile &file, const CUnit &unit) const -{ - const COrder &order = *this; - file.printf("{"); - switch (order.Action) { - case UnitActionNone: - file.printf("\"action-none\","); - break; - case UnitActionAttack: - file.printf("\"action-attack\","); - break; - case UnitActionAttackGround: - file.printf("\"action-attack-ground\","); - break; - default: - DebugPrint("Unknown action in order\n"); - } - - file.printf(" \"range\", %d,", order.Range); - file.printf(" \"width\", %d,", order.Width); - file.printf(" \"height\", %d,", order.Height); - file.printf(" \"min-range\", %d,", order.MinRange); - - if (order.Finished) { - file.printf(" \"finished\", "); - } - - if (order.HasGoal()) { - CUnit &goal = *order.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(" \"tile\", {%d, %d}", order.goalPos.x, order.goalPos.y); - - switch (order.Action) { - case UnitActionAttack: - case UnitActionAttackGround: - file.printf(", \"subaction\", %d", order.SubAction.Attack); - break; - default: - break; - } - - // - // Order data part - // - switch (order.Action) { - case UnitActionStill: - case UnitActionResource: - case UnitActionBuilt: - case UnitActionResearch: - case UnitActionUpgradeTo: - case UnitActionTrain: - break; - default: - file.printf(",\n "); - SaveDataMove(file); - break; - } - file.printf("}"); -} - void COrder::SaveDataMove(CFile &file) const { file.printf("\"data-move\", {");