Replace some COrder in CUnit by pointer.

Begin to have order and action more linked.
This commit is contained in:
joris 2012-02-07 14:15:16 +01:00
parent 0bd9d6ad4c
commit 12e8eb6846
28 changed files with 289 additions and 392 deletions

View file

@ -135,31 +135,21 @@ static int CheckForDeadGoal(CUnit &unit)
*/
static int CheckForTargetInRange(CUnit &unit)
{
//
// Target is dead?
//
if (CheckForDeadGoal(unit)) {
return 1;
}
COrderPtr order = unit.CurrentOrder();
//
// No goal: if meeting enemy attack it.
//
if (!order->HasGoal() &&
order->Action != UnitActionAttackGround &&
!Map.WallOnMap(order->goalPos)) {
CUnit *goal = AttackUnitsInReactRange(unit);
if (goal) {
#ifdef DEBUG
if (unit.StoreOrder()) {
Assert(!order->HasGoal());
}
#else
unit.StoreOrder();
#endif
order->SetGoal(goal);
order->MinRange = unit.Type->MinAttackRange;
order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
@ -167,13 +157,11 @@ static int CheckForTargetInRange(CUnit &unit)
unit.SubAction |= WEAK_TARGET; // weak target
NewResetPath(*order);
}
//
// Have a weak target, try a better target.
//
} else if (order->HasGoal() && (unit.SubAction & WEAK_TARGET)) {
CUnit *goal = order->GetGoal();
CUnit *temp = AttackUnitsInReactRange(unit);
if (temp && temp->Type->Priority > goal->Type->Priority) {
unit.StoreOrder();
order->SetGoal(temp);
@ -183,8 +171,7 @@ static int CheckForTargetInRange(CUnit &unit)
}
Assert(!unit.Type->Vanishes && !unit.Destroyed && !unit.Removed);
Assert(order->Action == UnitActionAttack ||
order->Action == UnitActionAttackGround);
Assert(order->Action == UnitActionAttack || order->Action == UnitActionAttackGround);
return 0;
}
@ -406,13 +393,10 @@ static void AttackTarget(CUnit &unit)
**
** @param unit Unit, for that the attack is handled.
*/
void HandleActionAttack(CUnit &unit)
void HandleActionAttack(CUnit::COrder& order, CUnit &unit)
{
Assert(unit.CurrentAction() == UnitActionAttackGround ||
unit.CurrentAction() == UnitActionAttack);
Assert(unit.CurrentOrder()->HasGoal() ||
(unit.CurrentOrder()->goalPos.x != -1 && unit.CurrentOrder()->goalPos.y != -1));
Assert(order.Action == UnitActionAttackGround || order.Action == UnitActionAttack);
Assert(order.HasGoal() || (order.goalPos.x != -1 && order.goalPos.y != -1));
if (unit.Wait) {
unit.Wait--;
@ -429,8 +413,8 @@ void HandleActionAttack(CUnit &unit)
return;
}
// Can we already attack ?
if (unit.CurrentOrder()->HasGoal()) {
CUnit *goal = unit.CurrentOrder()->GetGoal();
if (order.HasGoal()) {
CUnit *goal = order.GetGoal();
// dist between unit and unit.CurrentOrder()->Goal.
int dist = goal->MapDistanceTo(unit);
if (unit.Type->MinAttackRange < dist &&
@ -444,7 +428,7 @@ void HandleActionAttack(CUnit &unit)
}
}
unit.SubAction = MOVE_TO_TARGET;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
//
// FIXME: should use a reachable place to reduce pathfinder time.
//

View file

@ -175,12 +175,10 @@ static void EnterTransporter(CUnit &unit)
**
** @param unit Pointer to unit.
*/
void HandleActionBoard(CUnit &unit)
void HandleActionBoard(CUnit::COrder& order, CUnit &unit)
{
switch (unit.SubAction) {
//
// Wait for transporter
//
case 201:
if (WaitForTransporter(unit)) {
unit.SubAction = 202;
@ -188,21 +186,17 @@ void HandleActionBoard(CUnit &unit)
UnitShowAnimation(unit, unit.Type->Animations->Still[GetAnimationDamagedState(unit,1)]);
}
break;
//
// Enter transporter
//
case 202:
EnterTransporter(unit);
break;
//
// Move to transporter
//
case 0:
if (unit.Wait) {
unit.Wait--;
return;
}
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
unit.SubAction = 1;
// FALL THROUGH
default:
@ -213,13 +207,13 @@ void HandleActionBoard(CUnit &unit)
if (i == PF_UNREACHABLE) {
if (++unit.SubAction == 200) {
unit.ClearAction();
unit.CurrentOrder()->ClearGoal();
order.ClearGoal();
} else {
//
// Try with a bigger range.
//
if (unit.CurrentOrder()->CheckRange()) {
unit.CurrentOrder()->Range++;
if (order.CheckRange()) {
order.Range++;
unit.SubAction--;
}
}

View file

@ -408,7 +408,7 @@ static void BuildBuilding(CUnit &unit)
**
** @param unit Unit that builds a building
*/
void HandleActionBuild(CUnit &unit)
void HandleActionBuild(CUnit::COrder& /*order*/, CUnit &unit)
{
CUnit *ontop;
@ -430,7 +430,7 @@ void HandleActionBuild(CUnit &unit)
**
** @param unit Unit that is being built
*/
void HandleActionBuilt(CUnit &unit)
void HandleActionBuilt(CUnit::COrder& order, CUnit &unit)
{
CUnit *worker;
CUnitType *type;
@ -446,8 +446,8 @@ void HandleActionBuilt(CUnit &unit)
smod = (unit.Stats->Costs[TimeCost] * 600) - unit.Variable[SHIELD_INDEX].Value;
// n is the current damage taken by the unit.
n = (unit.CurrentOrder()->Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - 1)) / mod;
sn = (unit.CurrentOrder()->Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (smod - 1)) / smod;
n = (order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - 1)) / mod;
sn = (order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (smod - 1)) / smod;
// This below is most often 0
if (type->BuilderOutside) {
@ -459,14 +459,14 @@ void HandleActionBuilt(CUnit &unit)
}
// Building speeds increase or decrease.
progress *= SpeedBuild;
oldprogress = unit.CurrentOrder()->Data.Built.Progress;
unit.CurrentOrder()->Data.Built.Progress += progress;
oldprogress = order.Data.Built.Progress;
order.Data.Built.Progress += progress;
// mod is use for round to upper and use it as cache
mod = type->Stats[unit.Player->Index].Costs[TimeCost] * 600;
// Keep the same level of damage while increasing HP.
unit.Variable[HP_INDEX].Value +=
(unit.CurrentOrder()->Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n) -
(order.Data.Built.Progress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n) -
(oldprogress * unit.Variable[HP_INDEX].Max + (mod - n - 1)) / (mod - n);
if (unit.Variable[HP_INDEX].Value > unit.Stats->Variables[HP_INDEX].Max) {
unit.Variable[HP_INDEX].Value = unit.Stats->Variables[HP_INDEX].Max;
@ -474,21 +474,18 @@ void HandleActionBuilt(CUnit &unit)
if (unit.Variable[SHIELD_INDEX].Max > 0)
{
unit.Variable[SHIELD_INDEX].Value +=
(unit.CurrentOrder()->Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn) -
(order.Data.Built.Progress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn) -
(oldprogress * unit.Variable[SHIELD_INDEX].Max + (mod - sn - 1)) / (mod - sn);
if (unit.Variable[SHIELD_INDEX].Value > unit.Stats->Variables[SHIELD_INDEX].Max) {
unit.Variable[SHIELD_INDEX].Value = unit.Stats->Variables[SHIELD_INDEX].Max;
}
}
//
// Check if construction should be canceled...
//
if (unit.CurrentOrder()->Data.Built.Cancel || unit.CurrentOrder()->Data.Built.Progress < 0) {
DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index
_C_ unit.Type->Name.c_str());
if (order.Data.Built.Cancel || order.Data.Built.Progress < 0) {
DebugPrint("%d: %s canceled.\n" _C_ unit.Player->Index _C_ unit.Type->Name.c_str());
// Drop out unit
if ((worker = unit.CurrentOrder()->Data.Built.Worker)) {
if ((worker = order.Data.Built.Worker)) {
worker->CurrentOrder()->ClearGoal();
worker->ClearAction();
@ -512,7 +509,7 @@ void HandleActionBuilt(CUnit &unit)
// Check if building ready. Note we can both build and repair.
//
//if (unit.CurrentOrder()->Data.Built.Progress >= unit.Stats->Costs[TimeCost] * 600 ||
if (!unit.CurrentOrder()->Data.Built.Worker->Anim.Unbreakable && (unit.CurrentOrder()->Data.Built.Progress >= mod ||
if (!order.Data.Built.Worker->Anim.Unbreakable && (order.Data.Built.Progress >= mod ||
unit.Variable[HP_INDEX].Value >= unit.Stats->Variables[HP_INDEX].Max)) {
DebugPrint("%d: Building %s(%s) ready.\n" _C_ unit.Player->Index
_C_ unit.Type->Ident.c_str() _C_ unit.Type->Name.c_str() );

View file

@ -53,8 +53,10 @@
**
** @param unit The unit which dies.
*/
void HandleActionDie(CUnit &unit)
void HandleActionDie(CUnit::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]);
@ -92,10 +94,6 @@ void HandleActionDie(CUnit &unit)
unit.Stats = &unit.Type->Stats[unit.Player->Index];
unit.Place(unit.tilePos);
// We must be dead to get here, it we aren't we need to know why
// This assert replaces and old DEBUG message "Reset to die is really needed"
Assert(unit.CurrentAction() == UnitActionDie);
unit.SubAction = 0;
unit.Frame = 0;
UnitUpdateHeading(unit);

View file

@ -58,34 +58,28 @@
**
** @param unit Pointer to unit.
*/
void HandleActionFollow(CUnit &unit)
void HandleActionFollow(CUnit::COrder& order, CUnit &unit)
{
CUnit *goal;
if (unit.Wait) {
unit.Wait--;
return;
}
CUnit *goal = order.GetGoal();
//
// Reached target
//
if (unit.SubAction == 128) {
COrderPtr order = unit.CurrentOrder();
goal = order->GetGoal();
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("Goal gone\n");
order->ClearGoal();
order.ClearGoal();
unit.ClearAction();
return;
}
if (goal->tilePos == order->goalPos) {
if (goal->tilePos == order.goalPos) {
// Move to the next order
if (unit.OrderCount > 1) {
order->ClearGoal();
order.ClearGoal();
unit.ClearAction();
return;
}
@ -95,40 +89,36 @@ void HandleActionFollow(CUnit &unit)
unit.Frame = unit.Type->StillFrame;
UnitUpdateHeading(unit);
unit.Wait = 10;
if (order->Range > 1) {
order->Range = 1;
if (order.Range > 1) {
order.Range = 1;
unit.SubAction = 0;
}
return;
}
unit.SubAction = 0;
}
if (!unit.SubAction) { // first entry
unit.SubAction = 1;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
Assert(unit.State == 0);
}
switch (DoActionMove(unit)) { // reached end-point?
case PF_UNREACHABLE:
//
// Some tries to reach the goal
//
if (unit.CurrentOrder()->CheckRange()) {
unit.CurrentOrder()->Range++;
if (order.CheckRange()) {
order.Range++;
break;
}
// FALL THROUGH
case PF_REACHED:
{
if (!goal) { // goal has died
unit.ClearAction();
return;
}
// Handle Teleporter Units
// FIXME: BAD HACK
if ((goal = unit.CurrentOrder()->GetGoal()) &&
goal->Type->Teleporter && goal->Goal &&
unit.MapDistanceTo(*goal) <= 1) {
CUnit *dest;
if (goal->Type->Teleporter && goal->Goal && unit.MapDistanceTo(*goal) <= 1) {
// Teleport the unit
unit.Remove(NULL);
unit.tilePos = goal->Goal->tilePos;
@ -145,83 +135,63 @@ void HandleActionFollow(CUnit &unit)
#endif
unit.ClearAction();
//
// FIXME: we must check if the units supports the new order.
//
dest = goal->Goal;
CUnit &dest = *goal->Goal;
if (dest) {
if ((dest->NewOrder.Action == UnitActionResource &&
!unit.Type->Harvester) ||
(dest->NewOrder.Action == UnitActionAttack &&
!unit.Type->CanAttack) ||
(dest->NewOrder.Action == UnitActionBoard &&
unit.Type->UnitType != UnitTypeLand)) {
DebugPrint("Wrong order for unit\n");
unit.ClearAction();
unit.CurrentOrder()->ClearGoal();
} else {
if (dest->NewOrder.HasGoal()) {
if (dest->NewOrder.GetGoal()->Destroyed) {
// FIXME: perhaps we should use another dest?
DebugPrint("Destroyed unit in teleport unit\n");
dest->RefsDecrease();///???????
dest->NewOrder.ClearGoal();
dest->NewOrder.Action = UnitActionStill;
}
if (dest.NewOrder == NULL
|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->Harvester)
|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
unit.ClearAction();
unit.CurrentOrder()->ClearGoal();
} else {
if (dest.NewOrder->HasGoal()) {
if (dest.NewOrder->GetGoal()->Destroyed) {
// FIXME: perhaps we should use another dest?
DebugPrint("Destroyed unit in teleport unit\n");
dest.NewOrder->ClearGoal();
dest.NewOrder->Action = UnitActionStill;
}
*(unit.CurrentOrder()) = dest->NewOrder;
unit.CurrentResource = dest->CurrentResource;
}
*(unit.CurrentOrder()) = *dest.NewOrder;
unit.CurrentResource = dest.CurrentResource;
}
return;
}
goal = unit.CurrentOrder()->GetGoal();
if (!goal) { // goal has died
unit.ClearAction();
return;
}
unit.CurrentOrder()->goalPos = goal->tilePos;
order.goalPos = goal->tilePos;
unit.SubAction = 128;
}
// FALL THROUGH
default:
break;
}
//
// Target destroyed?
//
goal = unit.CurrentOrder()->GetGoal();
if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("Goal gone\n");
unit.CurrentOrder()->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
unit.CurrentOrder()->ClearGoal();
order.goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
order.ClearGoal();
goal = NoUnitP;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
}
if (!unit.Anim.Unbreakable) {
//
// If our leader is dead or stops or attacks:
// Attack any enemy in reaction range.
// If don't set the goal, the unit can than choose a
// better goal if moving nearer to enemy.
//
if (unit.Type->CanAttack &&
(!goal || goal->CurrentAction() == UnitActionAttack ||
goal->CurrentAction() == UnitActionStill)) {
if (unit.Type->CanAttack
&& (!goal || goal->CurrentAction() == UnitActionAttack || goal->CurrentAction() == UnitActionStill)) {
goal = AttackUnitsInReactRange(unit);
if (goal) {
CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
// Save current command to come back.
unit.SavedOrder = *(unit.CurrentOrder());
unit.SavedOrder = order;
// This stops the follow command and the attack is executed
order.ClearGoal();
unit.ClearAction();
unit.CurrentOrder()->ClearGoal();
}
}
}

View file

@ -172,7 +172,7 @@ int DoActionMove(CUnit &unit)
**
** @param unit Pointer to unit.
*/
void HandleActionMove(CUnit &unit)
void HandleActionMove(CUnit::COrder& order, CUnit &unit)
{
CUnit *goal;
@ -186,7 +186,7 @@ void HandleActionMove(CUnit &unit)
if (!unit.SubAction) { // first entry
unit.SubAction = 1;
NewResetPath(*unit.CurrentOrder());
unit.CurrentOrder()->Data.Move.Cycles = 0;
order.Data.Move.Cycles = 0;
Assert(unit.State == 0);
}
@ -197,14 +197,14 @@ void HandleActionMove(CUnit &unit)
//
// Some tries to reach the goal
//
if (unit.CurrentOrder()->CheckRange()) {
unit.CurrentOrder()->Range++;
if (order.CheckRange()) {
order.Range++;
break;
}
// FALL THROUGH
case PF_REACHED:
// Release target, if any.
unit.CurrentOrder()->ClearGoal();
order.ClearGoal();
unit.ClearAction();
return;
@ -215,12 +215,12 @@ void HandleActionMove(CUnit &unit)
//
// Target destroyed?
//
goal = unit.CurrentOrder()->GetGoal();
goal = order.GetGoal();
if (goal && goal->Destroyed) {
DebugPrint("Goal dead\n");
unit.CurrentOrder()->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
unit.CurrentOrder()->ClearGoal();
NewResetPath(*unit.CurrentOrder());
order.goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
order.ClearGoal();
NewResetPath(order);
}
}

View file

@ -75,7 +75,7 @@ static void SwapPatrolPoints(CUnit &unit)
**
** @param unit Patroling unit pointer.
*/
void HandleActionPatrol(CUnit &unit)
void HandleActionPatrol(CUnit::COrder& order, CUnit &unit)
{
if (unit.Wait) {
unit.Wait--;
@ -83,8 +83,8 @@ void HandleActionPatrol(CUnit &unit)
}
if (!unit.SubAction) { // first entry.
unit.CurrentOrder()->Data.Move.Cycles = 0; //moving counter
NewResetPath(*unit.CurrentOrder());
order.Data.Move.Cycles = 0; //moving counter
NewResetPath(order);
unit.SubAction = 1;
}
@ -95,14 +95,14 @@ void HandleActionPatrol(CUnit &unit)
case PF_UNREACHABLE:
// Increase range and try again
unit.SubAction = 1;
if (unit.CurrentOrder()->CheckRange()) {
unit.CurrentOrder()->Range++;
if (order.CheckRange()) {
order.Range++;
break;
}
// FALL THROUGH
case PF_REACHED:
unit.SubAction = 1;
unit.CurrentOrder()->Range = 0;
order.Range = 0;
SwapPatrolPoints(unit);
break;
case PF_WAIT:
@ -110,7 +110,7 @@ void HandleActionPatrol(CUnit &unit)
unit.SubAction++;
if (unit.SubAction == 5) {
unit.SubAction = 1;
unit.CurrentOrder()->Range = 0;
order.Range = 0;
SwapPatrolPoints(unit);
}
break;

View file

@ -144,59 +144,51 @@ static int AnimateActionRepair(CUnit &unit)
**
** @param unit Unit, for that the attack is handled.
*/
void HandleActionRepair(CUnit &unit)
void HandleActionRepair(CUnit::COrder& order, CUnit &unit)
{
CUnit *goal;
int err;
switch (unit.SubAction) {
case 0:
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
unit.SubAction = 1;
// FALL THROUGH
//
// Move near to target.
//
case 1:
case 1:// Move near to target.
// FIXME: RESET FIRST!! Why? We move first and than check if
// something is in sight.
err = DoActionMove(unit);
if (!unit.Anim.Unbreakable) {
//
// No goal: if meeting damaged building repair it.
//
goal = unit.CurrentOrder()->GetGoal();
goal = order.GetGoal();
//
// Target is dead, choose new one.
//
// Check if goal is correct unit.
if (goal) {
if (!goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("repair target gone.\n");
unit.CurrentOrder()->goalPos = goal->tilePos;
order.goalPos = goal->tilePos;
// FIXME: should I clear this here?
unit.CurrentOrder()->ClearGoal();
order.ClearGoal();
goal = NULL;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
}
} else if (unit.Player->AiEnabled) {
// Ai players workers should stop if target is killed
err = -1;
}
//
// Have reached target? FIXME: could use return value
//
if (goal && unit.MapDistanceTo(*goal) <= unit.Type->RepairRange &&
goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
unit.State = 0;
unit.SubAction = 2;
unit.CurrentOrder()->Data.Repair.Cycles = 0;
order.Data.Repair.Cycles = 0;
const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
UnitHeadingFromDeltaXY(unit, dir);
} else if (err < 0) {
unit.CurrentOrder()->ClearGoal();
order.ClearGoal();
if (!unit.RestoreOrder()) {
unit.ClearAction();
unit.State = 0;
@ -209,16 +201,12 @@ void HandleActionRepair(CUnit &unit)
}
break;
//
// Repair the target.
//
case 2:
case 2:// Repair the target.
AnimateActionRepair(unit);
unit.CurrentOrder()->Data.Repair.Cycles++;
order.Data.Repair.Cycles++;
if (!unit.Anim.Unbreakable) {
goal = unit.CurrentOrder()->GetGoal();
//
// Target is dead, choose new one.
//
// Check if goal is correct unit.
@ -226,16 +214,16 @@ void HandleActionRepair(CUnit &unit)
if (goal) {
if (!goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("repair goal is gone\n");
unit.CurrentOrder()->goalPos = goal->tilePos;
order.goalPos = goal->tilePos;
// FIXME: should I clear this here?
unit.CurrentOrder()->ClearGoal();
order.ClearGoal();
goal = NULL;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
} else {
int dist = unit.MapDistanceTo(*goal);
if (dist <= unit.Type->RepairRange) {
RepairUnit(unit, *goal);
goal = unit.CurrentOrder()->GetGoal();
goal = order.GetGoal();
} else if (dist > unit.Type->RepairRange) {
// If goal has move, chase after it
unit.State = 0;
@ -244,20 +232,15 @@ void HandleActionRepair(CUnit &unit)
}
}
//
// Target is fine, choose new one.
//
if (!goal || goal->Variable[HP_INDEX].Value >=
goal->Variable[HP_INDEX].Max) {
unit.CurrentOrder()->ClearGoal();
if (!goal || goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
order.ClearGoal();
if (!unit.RestoreOrder()) {
unit.ClearAction();
unit.State = 0;
}
return;
}
// FIXME: automatic repair
}
break;

View file

@ -37,7 +37,6 @@
#include <stdlib.h>
#include "stratagus.h"
#include "video.h"
#include "sound.h"
#include "unitsound.h"
#include "unittype.h"
@ -47,7 +46,6 @@
#include "actions.h"
#include "upgrade_structs.h"
#include "upgrade.h"
#include "interface.h"
#include "ai.h"
/*----------------------------------------------------------------------------
@ -59,19 +57,17 @@
**
** @param unit Pointer of researching unit.
*/
void HandleActionResearch(CUnit &unit)
void HandleActionResearch(CUnit::COrder& order, CUnit &unit)
{
const CUpgrade *upgrade;
if (!unit.SubAction) { // first entry
upgrade = unit.CurrentOrder()->Data.Research.Upgrade = unit.CurrentOrder()->Arg1.Upgrade;
upgrade = order.Data.Research.Upgrade = order.Arg1.Upgrade;
#if 0
// FIXME: I want to support both, but with network we need this check
// but if want combined upgrades this is worse
//
// Check if an other building has already started?
//
if (unit.Player->UpgradeTimers.Upgrades[upgrade - Upgrades]) {
DebugPrint("Two researches running\n");
PlayerAddCosts(unit.Player, upgrade->Costs);
@ -82,7 +78,7 @@ void HandleActionResearch(CUnit &unit)
#endif
unit.SubAction = 1;
} else {
upgrade = unit.CurrentOrder()->Data.Research.Upgrade;
upgrade = order.Data.Research.Upgrade;
}
unit.Type->Animations->Research ?
@ -94,8 +90,7 @@ void HandleActionResearch(CUnit &unit)
}
unit.Player->UpgradeTimers.Upgrades[upgrade->ID] += SpeedResearch;
if (unit.Player->UpgradeTimers.Upgrades[upgrade->ID] >=
upgrade->Costs[TimeCost]) {
if (unit.Player->UpgradeTimers.Upgrades[upgrade->ID] >= upgrade->Costs[TimeCost]) {
unit.Player->Notify(NotifyGreen, unit.tilePos.x, unit.tilePos.y,
_("%s: research complete"), unit.Type->Name.c_str());
@ -108,12 +103,9 @@ void HandleActionResearch(CUnit &unit)
AiResearchComplete(unit, upgrade);
}
UpgradeAcquire(*unit.Player, upgrade);
unit.ClearAction();
return;
}
unit.Wait = CYCLES_PER_SECOND / 6;
}

View file

@ -885,7 +885,7 @@ static bool ActionResourceInit(CUnit &unit)
**
** @param unit Pointer to unit.
*/
void HandleActionResource(CUnit &unit)
void HandleActionResource(CUnit::COrder& order, CUnit &unit)
{
if (unit.Wait) {
// FIXME: show idle animation while we wait?
@ -997,15 +997,14 @@ void HandleActionResource(CUnit &unit)
if (unit.SubAction == SUB_RETURN_RESOURCE) {
if (WaitInDepot(unit)) {
unit.SubAction = SUB_START_RESOURCE;
//
// It's posible, though very rare that the unit's goal blows up
// this cycle, but after this unit. Thus, next frame the unit
// will start mining a destroyed site. If, on the otherhand we
// are already in SUB_MOVE_TO_RESOURCE then we can handle it.
// So, we pass through SUB_START_RESOURCE the very instant it
// goes out of the depot.
//
HandleActionResource(unit);
HandleActionResource(order, unit);
}
return;
}

View file

@ -55,7 +55,7 @@
**
** @todo FIXME: move this into action_resource?
*/
void HandleActionReturnGoods(CUnit &unit)
void HandleActionReturnGoods(CUnit::COrder& order, CUnit &unit)
{
Assert(unit.Type->Harvester);
@ -71,23 +71,23 @@ void HandleActionReturnGoods(CUnit &unit)
}
// If depot was destroyed search for another one.
if (!unit.CurrentOrder()->HasGoal()) {
if (!order.HasGoal()) {
CUnit *destu;
if (!(destu = FindDeposit(unit, 1000, unit.CurrentResource))) {
ResourceGiveUp(unit);
return;
}
unit.CurrentOrder()->SetGoal(destu);
order.SetGoal(destu);
}
unit.CurrentOrder()->Action = UnitActionResource;
order.Action = UnitActionResource;
// Somewhere on the way the loaded worker could have change Arg1
// Bummer, go get the closest resource to the depot
//FIXME!!!!!!!!!!!!!!!!!!!!
//unit.CurrentOrder()->Arg1.ResourcePos = -1;
NewResetPath(*unit.CurrentOrder());
NewResetPath(order);
unit.SubAction = /* SUB_MOVE_TO_DEPOT */ 70; // FIXME : Define value.
}

View file

@ -135,24 +135,18 @@ static void SpellMoveToTarget(CUnit &unit)
**
** @param unit Unit, for that the spell cast is handled.
*/
void HandleActionSpellCast(CUnit &unit)
void HandleActionSpellCast(CUnit::COrder& order, CUnit &unit)
{
if (unit.Wait) {
unit.Wait--;
return;
}
COrderPtr order = unit.CurrentOrder();
const SpellType *spell = order->Arg1.Spell;
const SpellType *spell = order.Arg1.Spell;
switch (unit.SubAction) {
case 0:
//
// Check if we can cast the spell.
//
if (!CanCastSpell(unit, spell, order->GetGoal(), order->goalPos.x, order->goalPos.y)) {
//
if (!CanCastSpell(unit, spell, order.GetGoal(), order.goalPos.x, order.goalPos.y)) {
// Notify player about this problem
//
if (unit.Variable[MANA_INDEX].Value < spell->ManaCost) {
unit.Player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y,
_("%s: not enough mana for spell: %s"),
@ -166,8 +160,8 @@ void HandleActionSpellCast(CUnit &unit)
if (unit.Player->AiEnabled) {
DebugPrint("FIXME: do we need an AI callback?\n");
}
order.ClearGoal(); // Release references
unit.ClearAction();
order->ClearGoal(); // Release references
return;
}
// FIXME FIXME FIXME: Check if already in range and skip straight to 2(casting)
@ -194,16 +188,16 @@ void HandleActionSpellCast(CUnit &unit)
}
} else {
// FIXME: what todo, if unit/goal is removed?
CUnit *goal = order->GetGoal();
CUnit *goal = order.GetGoal();
if (goal && goal != &unit && !goal->IsVisibleAsGoal(*unit.Player)) {
unit.ReCast = 0;
} else {
unit.ReCast = SpellCast(unit, spell, goal, order->goalPos.x, order->goalPos.y);
unit.ReCast = SpellCast(unit, spell, goal, order.goalPos.x, order.goalPos.y);
}
}
if (!unit.ReCast && unit.CurrentAction() != UnitActionDie) {
order.ClearGoal(); // Release references
unit.ClearAction();
order->ClearGoal(); // Release references
}
break;

View file

@ -48,7 +48,7 @@
**
** @param unit Action handled for this unit pointer.
*/
void HandleActionStandGround(CUnit &unit)
void HandleActionStandGround(CUnit::COrder& /*order*/, CUnit &unit)
{
ActionStillGeneric(unit, true);
}

View file

@ -40,8 +40,8 @@
#include "missile.h"
#include "unittype.h"
#include "animation.h"
#include "actions.h"
#include "unit.h"
#include "actions.h"
#include "tileset.h"
#include "map.h"
#include "pathfinder.h"
@ -387,7 +387,7 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground)
**
** @param unit Unit pointer for still action.
*/
void HandleActionStill(CUnit &unit)
void HandleActionStill(CUnit::COrder& /*order*/, CUnit &unit)
{
ActionStillGeneric(unit, false);
}

View file

@ -61,29 +61,32 @@
** @param unit Newly trained unit.
** @param order New order for the unit.
**
** @return 1 if the the unit can do it, 0 otherwise.
** @return true if the the unit can do it, false otherwise.
*/
static int CanHandleOrder(CUnit &unit, COrderPtr order)
static bool CanHandleOrder(CUnit &unit, COrderPtr order)
{
if (order == NULL) {
return false;
}
if (order->Action == UnitActionResource) {
// Check if new unit can harvest.
if (!unit.Type->Harvester) {
return 0;
return false;
}
// Also check if new unit can harvest this specific resource.
CUnit *goal = order->GetGoal();
if (goal && !unit.Type->ResInfo[goal->Type->GivesResource]) {
return 0;
return false;
}
return 1;
return true;
}
if (order->Action == UnitActionAttack && !unit.Type->CanAttack) {
return 0;
return false;
}
if (order->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand) {
return 0;
return false;
}
return 1;
return true;
}
/**
@ -91,11 +94,11 @@ static int CanHandleOrder(CUnit &unit, COrderPtr order)
**
** @param unit Unit that trains.
*/
void HandleActionTrain(CUnit &unit)
void HandleActionTrain(CUnit::COrder& order, CUnit &unit)
{
// First entry
if (!unit.SubAction) {
unit.CurrentOrder()->Data.Train.Ticks = 0;
order.Data.Train.Ticks = 0;
unit.SubAction = 1;
}
@ -109,32 +112,27 @@ void HandleActionTrain(CUnit &unit)
}
CPlayer *player = unit.Player;
CUnitType &ntype = *unit.CurrentOrder()->Arg1.Type;
CUnitType &ntype = *order.Arg1.Type;
const int cost = ntype.Stats[player->Index].Costs[TimeCost];
unit.CurrentOrder()->Data.Train.Ticks += SpeedTrain;
order.Data.Train.Ticks += SpeedTrain;
// FIXME: Should count down
if (unit.CurrentOrder()->Data.Train.Ticks >= cost) {
if (order.Data.Train.Ticks >= cost) {
order.Data.Train.Ticks = cost;
unit.CurrentOrder()->Data.Train.Ticks = cost;
//
// Check if there are still unit slots.
//
if (NumUnits >= UnitMax) {
unit.Wait = CYCLES_PER_SECOND / 6;
return;
}
//
// Check if enough supply available.
//
const int food = player->CheckLimits(ntype);
if (food < 0) {
if (food == -3 && unit.Player->AiEnabled) {
AiNeedMoreSupply(*unit.Player);
}
unit.CurrentOrder()->Data.Train.Ticks = cost;
order.Data.Train.Ticks = cost;
unit.Wait = CYCLES_PER_SECOND / 6;
return;
}
@ -184,23 +182,24 @@ void HandleActionTrain(CUnit &unit)
unit.SubAction = 0;
}
if (!CanHandleOrder(*nunit, &unit.NewOrder)) {
DebugPrint("Wrong order for unit\n");
if (unit.NewOrder && unit.NewOrder->HasGoal()
&& unit.NewOrder->GetGoal()->Destroyed) {
// FIXME: perhaps we should use another goal?
DebugPrint("Destroyed unit in train unit\n");
delete unit.NewOrder;
unit.NewOrder = NULL;
}
if (CanHandleOrder(*nunit, unit.NewOrder) == true) {
*(nunit->CurrentOrder()) = *unit.NewOrder;
#if 0
} else {
// Tell the unit to move instead of trying any funny stuff.
*(nunit->CurrentOrder()) = unit.NewOrder;
nunit->CurrentOrder()->Action = UnitActionMove;
nunit->CurrentOrder()->ClearGoal();
} else {
if (unit.NewOrder.HasGoal()) {
if (unit.NewOrder.GetGoal()->Destroyed) {
// FIXME: perhaps we should use another goal?
DebugPrint("Destroyed unit in train unit\n");
unit.NewOrder.ClearGoal();
unit.NewOrder.Action = UnitActionStill;
}
}
*(nunit->CurrentOrder()) = unit.NewOrder;
#endif
}
if (IsOnlySelected(unit)) {
UI.ButtonPanel.Update();

View file

@ -323,7 +323,7 @@ static void LeaveTransporter(CUnit &transporter)
**
** @param unit Pointer to unit.
*/
void HandleActionUnload(CUnit &unit)
void HandleActionUnload(CUnit::COrder& order, CUnit &unit)
{
const int maxSearchRange = 20;
@ -332,15 +332,15 @@ void HandleActionUnload(CUnit &unit)
}
switch (unit.SubAction) {
case 0: // Choose destination
if (!unit.CurrentOrder()->HasGoal()) {
if (!order.HasGoal()) {
Vec2i pos;
if (!ClosestFreeDropZone(unit, unit.CurrentOrder()->goalPos, maxSearchRange, &pos)) {
if (!ClosestFreeDropZone(unit, order.goalPos, maxSearchRange, &pos)) {
// Sorry... I give up.
unit.ClearAction();
return;
}
unit.CurrentOrder()->goalPos = pos;
order.goalPos = pos;
}
NewResetPath(*unit.CurrentOrder());
@ -367,7 +367,7 @@ void HandleActionUnload(CUnit &unit)
// FIXME: show still animations ?
LeaveTransporter(unit);
if (unit.CanMove() && unit.CurrentAction() != UnitActionStill) {
HandleActionUnload(unit);
HandleActionUnload(*unit.CurrentOrder() , unit);
}
break;
}

View file

@ -134,11 +134,10 @@ static int TransformUnitIntoType(CUnit &unit, CUnitType &newtype)
**
** @param unit Pointer to unit.
*/
void HandleActionTransformInto(CUnit &unit)
void HandleActionTransformInto(CUnit::COrder& order, CUnit &unit)
{
// What to do if an error occurs ?
TransformUnitIntoType(unit, *unit.CriticalOrder.Arg1.Type);
unit.CriticalOrder.Action = UnitActionStill;
TransformUnitIntoType(unit, *order.Arg1.Type);
}
/**
@ -146,10 +145,10 @@ void HandleActionTransformInto(CUnit &unit)
**
** @param unit Pointer to unit.
*/
void HandleActionUpgradeTo(CUnit &unit)
void HandleActionUpgradeTo(CUnit::COrder& order, CUnit &unit)
{
if (!unit.SubAction) { // first entry
unit.CurrentOrder()->Data.UpgradeTo.Ticks = 0;
order.Data.UpgradeTo.Ticks = 0;
unit.SubAction = 1;
}
unit.Type->Animations->Upgrade ?
@ -160,12 +159,12 @@ void HandleActionUpgradeTo(CUnit &unit)
return;
}
CPlayer *player = unit.Player;
CUnitType &newtype = *unit.CurrentOrder()->Arg1.Type;
CUnitType &newtype = *order.Arg1.Type;
const CUnitStats *newstats = &newtype.Stats[player->Index];
// FIXME: Should count down here
unit.CurrentOrder()->Data.UpgradeTo.Ticks += SpeedUpgrade;
if (unit.CurrentOrder()->Data.UpgradeTo.Ticks < newstats->Costs[TimeCost]) {
order.Data.UpgradeTo.Ticks += SpeedUpgrade;
if (order.Data.UpgradeTo.Ticks < newstats->Costs[TimeCost]) {
unit.Wait = CYCLES_PER_SECOND / 6;
return;
}

View file

@ -255,7 +255,7 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale)
**
** @param unit Unit pointer for none action.
*/
static void HandleActionNone(CUnit &unit)
static void HandleActionNone(CUnit::COrder&, CUnit &unit)
{
DebugPrint("FIXME: Should not happen!\n");
DebugPrint("FIXME: Unit (%d) %s has action none.!\n" _C_
@ -267,7 +267,7 @@ static void HandleActionNone(CUnit &unit)
**
** @param unit Unit pointer for not written action.
*/
static void HandleActionNotWritten(CUnit &unit)
static void HandleActionNotWritten(CUnit::COrder&, CUnit &unit)
{
DebugPrint("FIXME: Not written!\n");
DebugPrint("FIXME: Unit (%d) %s has action %d.!\n" _C_
@ -279,7 +279,7 @@ static void HandleActionNotWritten(CUnit &unit)
**
** @note can move function into unit structure.
*/
static void (*HandleActionTable[256])(CUnit &) = {
static void (*HandleActionTable[256])(CUnit::COrder&, CUnit &) = {
HandleActionNone,
HandleActionStill,
HandleActionStandGround,
@ -465,9 +465,9 @@ static void HandleBuffs(CUnit &unit, int amount)
}
}
static void RunAction(unsigned char action, CUnit &unit)
static void RunAction(CUnit::COrder &order, CUnit &unit)
{
HandleActionTable[action](unit);
HandleActionTable[order.Action](order, unit);
}
@ -478,19 +478,16 @@ static void RunAction(unsigned char action, CUnit &unit)
*/
static void HandleUnitAction(CUnit &unit)
{
//
// If current action is breakable proceed with next one.
//
if (!unit.Anim.Unbreakable) {
if (unit.CriticalOrder.Action != UnitActionStill) {
HandleActionTable[unit.CriticalOrder.Action](unit);
unit.CriticalOrder.Action = UnitActionStill;
if (unit.CriticalOrder != NULL) {
RunAction(*unit.CriticalOrder, unit);
delete unit.CriticalOrder;
unit.CriticalOrder = NULL;
}
//
// o Look if we have a new order and old finished.
// o Or the order queue should be flushed.
//
if (unit.OrderCount > 1 &&
(unit.CurrentAction() == UnitActionStill || unit.OrderFlush)) {
@ -524,10 +521,8 @@ static void HandleUnitAction(CUnit &unit)
}
}
//
// Select action.
//
RunAction(unit.CurrentAction(), unit);
RunAction(*unit.CurrentOrder(), unit);
}
/**
@ -544,8 +539,7 @@ void UnitActions()
int i;
int tabsize;
buffsthiscycle = regenthiscycle = blinkthiscycle =
!(GameCycle % CYCLES_PER_SECOND);
buffsthiscycle = regenthiscycle = blinkthiscycle = !(GameCycle % CYCLES_PER_SECOND);
memcpy(table, Units, NumUnits * sizeof(CUnit *));
tabsize = NumUnits;

View file

@ -148,18 +148,16 @@ static void ClearSavedAction(CUnit &unit)
*/
void CommandStopUnit(CUnit &unit)
{
COrderPtr order;
// Ignore that the unit could be removed.
order = GetNextOrder(unit, FlushCommands); // Flush them.
COrderPtr order = GetNextOrder(unit, FlushCommands); // Flush them.
Assert(order);
order->Init();
order->Action = UnitActionStill;
unit.SavedOrder.Release();
unit.NewOrder.Release();
unit.SavedOrder = unit.NewOrder = *order;
unit.SavedOrder = *order;
delete unit.NewOrder;
unit.NewOrder = NULL;
}
/**
@ -227,8 +225,9 @@ void CommandStandGround(CUnit &unit, int flush)
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -254,8 +253,9 @@ void CommandFollow(CUnit &unit, CUnit &dest, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (!unit.CanMove()) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -296,8 +296,9 @@ void CommandMove(CUnit &unit, const Vec2i &pos, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (!unit.CanMove()) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -326,8 +327,9 @@ void CommandRepair(CUnit &unit, const Vec2i &pos, CUnit *dest, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -389,8 +391,9 @@ void CommandAttack(CUnit &unit, const Vec2i &pos, CUnit *attack, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (!unit.Type->CanAttack) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -442,8 +445,9 @@ void CommandAttackGround(CUnit &unit, const Vec2i &pos, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -480,8 +484,9 @@ void CommandPatrolUnit(CUnit &unit, const Vec2i &pos, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (!unit.CanMove()) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -521,8 +526,9 @@ void CommandBoard(CUnit &unit, CUnit &dest, int flush)
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -588,8 +594,9 @@ void CommandBuildBuilding(CUnit &unit, const Vec2i &pos, CUnitType &what, int fl
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -653,8 +660,9 @@ void CommandResourceLoc(CUnit &unit, const Vec2i &pos, int flush)
if (!unit.Removed && unit.CurrentAction() != UnitActionDie) {
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -707,8 +715,9 @@ void CommandResource(CUnit &unit, CUnit &dest, int flush)
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -743,8 +752,9 @@ void CommandReturnGoods(CUnit &unit, CUnit *goal, int flush)
if (unit.Type->Building) {
// FIXME: should find a better way for pending orders.
order = &unit.NewOrder;
order->Release();
delete unit.NewOrder;
unit.NewOrder = new CUnit::COrder;
order = unit.NewOrder;
} else if (!(order = GetNextOrder(unit, flush))) {
return;
}
@ -917,14 +927,13 @@ void CommandUpgradeTo(CUnit &unit, CUnitType &type, int flush)
*/
void CommandTransformIntoType(CUnit &unit, CUnitType &type)
{
COrderPtr order;
COrderPtr order = new CUnit::COrder;
Assert(unit.CriticalOrder.Action == UnitActionStill);
order = &unit.CriticalOrder;
order->Init();
Assert(unit.CriticalOrder == NULL);
order->Action = UnitActionTransformInto;
order->Arg1.Type = &type;
unit.CriticalOrder = order;
}
/**

View file

@ -41,6 +41,7 @@
#include "unittype.h"
#include "map.h"
#include "pathfinder.h"
#include "unit.h"
#include "actions.h"
#include "ai_local.h"

View file

@ -151,52 +151,54 @@ extern int GetNumWaitingWorkers(const CUnit &mine);
extern void AutoAttack(CUnit &unit, CUnitCache &targets, bool stand_ground);
extern void UnHideUnit(CUnit &unit);
typedef void HandleActionFunc(CUnit::COrder& order, CUnit &unit);
/// Generic still action
extern void ActionStillGeneric(CUnit &unit, bool stand_ground);
/// Handle command still
extern void HandleActionStill(CUnit &unit);
extern HandleActionFunc HandleActionStill;
/// Handle command stand ground
extern void HandleActionStandGround(CUnit &unit);
extern HandleActionFunc HandleActionStandGround;
/// Handle command follow
extern void HandleActionFollow(CUnit &unit);
extern HandleActionFunc HandleActionFollow;
/// Generic move action
extern int DoActionMove(CUnit &unit);
/// Handle command move
extern void HandleActionMove(CUnit &unit);
extern HandleActionFunc HandleActionMove;
/// Handle command repair
extern void HandleActionRepair(CUnit &unit);
extern HandleActionFunc HandleActionRepair;
/// Handle command patrol
extern void HandleActionPatrol(CUnit &unit);
extern HandleActionFunc HandleActionPatrol;
/// Show attack animation
extern void AnimateActionAttack(CUnit &unit);
/// Handle command attack
extern void HandleActionAttack(CUnit &unit);
extern HandleActionFunc HandleActionAttack;
/// Handle command board
extern void HandleActionBoard(CUnit &unit);
extern HandleActionFunc HandleActionBoard;
/// Handle command unload
extern void HandleActionUnload(CUnit &unit);
extern HandleActionFunc HandleActionUnload;
/// Handle command resource
extern void HandleActionResource(CUnit &unit);
extern HandleActionFunc HandleActionResource;
/// Handle command return
extern void HandleActionReturnGoods(CUnit &unit);
extern HandleActionFunc HandleActionReturnGoods;
/// Handle command die
extern void HandleActionDie(CUnit &unit);
extern HandleActionFunc HandleActionDie;
/// Handle command build
extern void HandleActionBuild(CUnit &unit);
extern HandleActionFunc HandleActionBuild;
/// Handle command built
extern void HandleActionBuilt(CUnit &unit);
extern HandleActionFunc HandleActionBuilt;
/// Handle command train
extern void HandleActionTrain(CUnit &unit);
extern HandleActionFunc HandleActionTrain;
/// Handle command upgrade to
extern void HandleActionUpgradeTo(CUnit &unit);
extern HandleActionFunc HandleActionUpgradeTo;
/// Handle command transform into
extern void HandleActionTransformInto(CUnit &unit);
extern HandleActionFunc HandleActionTransformInto;
/// Handle command upgrade
extern void HandleActionUpgrade(CUnit &unit);
extern HandleActionFunc HandleActionUpgrade;
/// Handle command research
extern void HandleActionResearch(CUnit &unit);
extern HandleActionFunc HandleActionResearch;
/// Handle command spellcast
extern void HandleActionSpellCast(CUnit &unit);
extern HandleActionFunc HandleActionSpellCast;
/*----------------------------------------------------------------------------
-- Actions: actions.c

View file

@ -537,7 +537,7 @@ public:
void Release();
void ReleaseRefs(CUnit &owner);
COrder& operator=(const COrder &rhs);
bool CheckRange();
bool CheckRange() const;
void Init() {
Assert(Action != UnitActionResource
@ -645,7 +645,7 @@ public:
} Data; /// Storage room for different commands
};
CUnit() { Init(); }
CUnit() : NewOrder(NULL), CriticalOrder(NULL) { Init(); }
void Init() {
Refs = 0;
@ -704,8 +704,10 @@ public:
OrderFlush = 0;
Orders.clear();
SavedOrder.Init();
NewOrder.Init();
CriticalOrder.Init();
delete NewOrder;
NewOrder = NULL;
delete CriticalOrder;
CriticalOrder = NULL;
AutoCastSpell = NULL;
AutoRepair = 0;
Goal = NULL;
@ -812,34 +814,23 @@ public:
char OrderCount; /// how many orders in queue
char OrderFlush; /// cancel current order, take next
std::vector<COrder *> Orders; /// orders to process
COrder SavedOrder; /// order to continue after current
COrder NewOrder; /// order for new trained units
COrder CriticalOrder; /// order to do as possible in breakable animation.
COrder SavedOrder; /// order to continue after current
COrder *NewOrder; /// order for new trained units
COrder *CriticalOrder; /// order to do as possible in breakable animation.
char *AutoCastSpell; /// spells to auto cast
CUnit *Goal; /// Generic/Teleporter goal pointer
inline COrder * CreateOrder() {
COrder * CreateOrder() {
Orders.push_back(new COrder);
return Orders[(int)OrderCount++];
}
inline COrder *CurrentOrder() const
{
#if __GNUC__ < 4
return Orders[0];
#else
return *(Orders.data());
#endif
}
inline UnitAction CurrentAction() const
{
return (UnitAction)(CurrentOrder()->Action);
}
COrder *CurrentOrder() const { return Orders[0]; }
inline bool IsIdle() const {
return OrderCount == 1 && CurrentAction() == UnitActionStill;
}
UnitAction CurrentAction() const { return (UnitAction)(CurrentOrder()->Action); }
bool IsIdle() const { return OrderCount == 1 && CurrentAction() == UnitActionStill; }
inline void ClearAction() {
CurrentOrder()->Action = UnitActionStill;

View file

@ -292,7 +292,6 @@ static int CclShowMapLocation(lua_State *l)
}
CUnit *target = MakeUnit(*unitType, ThisPlayer);
if (target != NoUnitP) {
target->CurrentOrder()->Action = UnitActionStill;
target->Variable[HP_INDEX].Value = 0;
target->tilePos.x = LuaToNumber(l, 1);
target->tilePos.y = LuaToNumber(l, 2);

View file

@ -42,6 +42,7 @@
#include "player.h"
#include "script.h"
#include "ai.h"
#include "unit.h"
#include "actions.h"
#include "commands.h"
#include "map.h"

View file

@ -883,7 +883,8 @@ static int CclUnit(lua_State *l)
}
} else if (!strcmp(value, "critical-order")) {
lua_pushvalue(l, j + 1);
CclParseOrder(l, *unit , &unit->CriticalOrder);
unit->CriticalOrder = new CUnit::COrder;
CclParseOrder(l, *unit , unit->CriticalOrder);
lua_pop(l, 1);
} else if (!strcmp(value, "saved-order")) {
lua_pushvalue(l, j + 1);
@ -891,7 +892,8 @@ static int CclUnit(lua_State *l)
lua_pop(l, 1);
} else if (!strcmp(value, "new-order")) {
lua_pushvalue(l, j + 1);
CclParseOrder(l, *unit, &unit->NewOrder);
unit->NewOrder = new CUnit::COrder;
CclParseOrder(l, *unit, unit->NewOrder);
lua_pop(l, 1);
} else if (!strcmp(value, "goal")) {
unit->Goal = UnitSlots[(int)LuaToNumber(l, j + 1)];

View file

@ -209,7 +209,7 @@ CUnit::COrder& CUnit::COrder::operator=(const CUnit::COrder &rhs) {
return *this;
}
bool CUnit::COrder::CheckRange()
bool CUnit::COrder::CheckRange() const
{
return (Range <= Map.Info.MapWidth || Range <= Map.Info.MapHeight);
}
@ -290,15 +290,11 @@ void CUnit::Init(CUnitType &type)
// Set refs to 1. This is the "I am alive ref", lost in ReleaseUnit.
Refs = 1;
//
// Build all unit table
//
UnitSlot = &Units[NumUnits]; // back pointer
Units[NumUnits++] = this;
//
// Initialise unit structure (must be zero filled!)
//
Type = &type;
Seen.Frame = UnitNotSeen; // Unit isn't yet seen
@ -343,15 +339,13 @@ void CUnit::Init(CUnitType &type)
CurrentOrder()->Action = UnitActionStill;
CurrentOrder()->goalPos.x = CurrentOrder()->goalPos.y = -1;
Assert(!CurrentOrder()->HasGoal());
NewOrder.Action = UnitActionStill;
NewOrder.goalPos.x = NewOrder.goalPos.y = -1;
Assert(!NewOrder.HasGoal());
Assert(NewOrder == NULL);
NewOrder = NULL;
SavedOrder.Action = UnitActionStill;
SavedOrder.goalPos.x = SavedOrder.goalPos.y = -1;
Assert(!SavedOrder.HasGoal());
CriticalOrder.Action = UnitActionStill;
CriticalOrder.goalPos.x = CriticalOrder.goalPos.y = -1;
Assert(!CriticalOrder.HasGoal());
Assert(CriticalOrder == NULL);
CriticalOrder = NULL;
}
/**
@ -1048,22 +1042,13 @@ void UnitLost(CUnit &unit)
*/
void UnitClearOrders(CUnit &unit)
{
int i;
//
// Release all references of the unit.
//
for (i = unit.OrderCount; i-- > 0;) {
if (i != 0) {
COrderPtr order = unit.Orders.back();
delete order;
unit.Orders.pop_back();
} else unit.Orders[0]->Release();
for (int i = 0; i != unit.OrderCount; ++i)
{
delete unit.Orders[i];
}
unit.OrderCount = 1;
unit.NewOrder.Release();
unit.SavedOrder.Release();
unit.CurrentOrder()->Action = UnitActionStill;
unit.Orders.clear();
unit.OrderCount = 0;
CommandStopUnit(unit);
unit.SubAction = unit.State = 0;
}
@ -3413,7 +3398,7 @@ void CleanUnits()
ResourceInfo *resinfo = unit->Type->ResInfo[unit->CurrentResource];
if (resinfo && !resinfo->TerrainHarvester) {
CUnit *mine = unit->CurrentOrder()->Arg1.Resource.Mine;
if (mine) {
if (mine && !mine->Destroyed) {
unit->DeAssignWorkerFromMine(*mine);
mine->RefsDecrease();
unit->CurrentOrder()->Arg1.Resource.Mine = NULL;

View file

@ -878,8 +878,8 @@ void ShowOrder(const CUnit &unit)
}
// Show order for new trained units
if (!unit.CanMove()) {
ShowSingleOrder(unit, x1, y1, (COrderPtr)(&unit.NewOrder));
if (!unit.CanMove() && unit.NewOrder) {
ShowSingleOrder(unit, x1, y1, unit.NewOrder);
}
}

View file

@ -477,10 +477,14 @@ void SaveUnit(const CUnit &unit, CFile *file)
}
file->printf("},\n \"saved-order\", ");
SaveOrder(unit.SavedOrder, unit, file);
file->printf(",\n \"critical-order\", ");
SaveOrder(unit.CriticalOrder, unit, file);
file->printf(",\n \"new-order\", ");
SaveOrder(unit.NewOrder, unit, file);
if (unit.CriticalOrder) {
file->printf(",\n \"critical-order\", ");
SaveOrder(*unit.CriticalOrder, unit, file);
}
if (unit.NewOrder) {
file->printf(",\n \"new-order\", ");
SaveOrder(*unit.NewOrder, unit, file);
}
if (unit.Goal) {
file->printf(",\n \"goal\", %d", UnitNumber(*unit.Goal));