COrder_Attack

COrder is now abstract
This commit is contained in:
joris 2012-02-25 12:41:53 +01:00
parent 13d9646a7c
commit d3c2041d27
6 changed files with 212 additions and 430 deletions

View file

@ -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);

View file

@ -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.
**

View file

@ -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
----------------------------------------------------------------------------*/

View file

@ -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);
}

View file

@ -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;

View file

@ -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\", {");