Add COrder_ {Board, Unload, Repair}
Move CUnit::SubAction into corresponding COrder_ Merge COrder_StandGround into COrder_Still
This commit is contained in:
parent
373616150a
commit
d52a301924
24 changed files with 742 additions and 621 deletions
|
@ -157,11 +157,11 @@ static int CheckForTargetInRange(CUnit &unit)
|
|||
order->MinRange = unit.Type->MinAttackRange;
|
||||
order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
|
||||
order->goalPos.x = order->goalPos.y = -1;
|
||||
unit.SubAction |= WEAK_TARGET; // weak target
|
||||
order->SubAction.Attack |= WEAK_TARGET; // weak target
|
||||
order->NewResetPath();
|
||||
}
|
||||
// Have a weak target, try a better target.
|
||||
} else if (order->HasGoal() && (unit.SubAction & WEAK_TARGET)) {
|
||||
} else if (order->HasGoal() && (order->SubAction.Attack & WEAK_TARGET)) {
|
||||
CUnit *goal = order->GetGoal();
|
||||
CUnit *temp = AttackUnitsInReactRange(unit);
|
||||
|
||||
|
@ -231,7 +231,7 @@ static void MoveToTarget(CUnit &unit)
|
|||
unit.State = 0;
|
||||
const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
|
||||
UnitHeadingFromDeltaXY(unit, dir);
|
||||
unit.SubAction++;
|
||||
order->SubAction.Attack++;
|
||||
return;
|
||||
}
|
||||
//
|
||||
|
@ -244,8 +244,8 @@ static void MoveToTarget(CUnit &unit)
|
|||
// Reached wall or ground, now attacking it
|
||||
unit.State = 0;
|
||||
UnitHeadingFromDeltaXY(unit, order->goalPos - unit.tilePos);
|
||||
unit.SubAction &= WEAK_TARGET;
|
||||
unit.SubAction |= ATTACK_TARGET;
|
||||
order->SubAction.Attack &= WEAK_TARGET;
|
||||
order->SubAction.Attack |= ATTACK_TARGET;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ static void AttackTarget(CUnit &unit)
|
|||
if (unit.RestoreOrder()) {
|
||||
return;
|
||||
}
|
||||
unit.SubAction = MOVE_TO_TARGET;
|
||||
order->SubAction.Attack = MOVE_TO_TARGET;
|
||||
return;
|
||||
}
|
||||
// Save current command to come back.
|
||||
|
@ -335,14 +335,14 @@ static void AttackTarget(CUnit &unit)
|
|||
order->MinRange = unit.Type->MinAttackRange;
|
||||
order->Range = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
|
||||
order->NewResetPath();
|
||||
unit.SubAction |= WEAK_TARGET;
|
||||
order->SubAction.Attack |= WEAK_TARGET;
|
||||
|
||||
//
|
||||
// Have a weak target, try a better target.
|
||||
// FIXME: if out of range also try another target quick
|
||||
//
|
||||
} else {
|
||||
if ((unit.SubAction & WEAK_TARGET)) {
|
||||
if ((order->SubAction.Attack & WEAK_TARGET)) {
|
||||
CUnit *temp = AttackUnitsInReactRange(unit);
|
||||
if (temp && temp->Type->Priority > goal->Type->Priority) {
|
||||
COrder *savedOrder = order->Clone();
|
||||
|
@ -355,7 +355,7 @@ static void AttackTarget(CUnit &unit)
|
|||
order->SetGoal(temp);
|
||||
order->goalPos.x = order->goalPos.y = -1;
|
||||
order->MinRange = unit.Type->MinAttackRange;
|
||||
unit.SubAction = MOVE_TO_TARGET;
|
||||
order->SubAction.Attack = MOVE_TO_TARGET;
|
||||
order->NewResetPath();
|
||||
}
|
||||
}
|
||||
|
@ -375,11 +375,11 @@ static void AttackTarget(CUnit &unit)
|
|||
order->NewResetPath();
|
||||
unit.Frame = 0;
|
||||
unit.State = 0;
|
||||
unit.SubAction &= WEAK_TARGET;
|
||||
unit.SubAction |= MOVE_TO_TARGET;
|
||||
order->SubAction.Attack &= WEAK_TARGET;
|
||||
order->SubAction.Attack |= MOVE_TO_TARGET;
|
||||
}
|
||||
if (dist < unit.Type->MinAttackRange) {
|
||||
unit.SubAction = MOVE_TO_TARGET;
|
||||
order->SubAction.Attack = MOVE_TO_TARGET;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -414,7 +414,7 @@ void HandleActionAttack(COrder& order, CUnit &unit)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (unit.SubAction) {
|
||||
switch (order.SubAction.Attack) {
|
||||
case 0: // First entry
|
||||
{
|
||||
// did Order change ?
|
||||
|
@ -431,12 +431,12 @@ void HandleActionAttack(COrder& order, CUnit &unit)
|
|||
const Vec2i dir = goal.tilePos + goal.Type->GetHalfTileSize() - unit.tilePos;
|
||||
|
||||
UnitHeadingFromDeltaXY(unit, dir);
|
||||
unit.SubAction = ATTACK_TARGET;
|
||||
order.SubAction.Attack = ATTACK_TARGET;
|
||||
AttackTarget(unit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
unit.SubAction = MOVE_TO_TARGET;
|
||||
order.SubAction.Attack = MOVE_TO_TARGET;
|
||||
order.NewResetPath();
|
||||
// FIXME: should use a reachable place to reduce pathfinder time.
|
||||
Assert(unit.State == 0);
|
||||
|
|
|
@ -42,14 +42,51 @@
|
|||
#include "player.h"
|
||||
#include "unit.h"
|
||||
#include "actions.h"
|
||||
#include "interface.h"
|
||||
#include "pathfinder.h"
|
||||
#include "map.h"
|
||||
#include "iolib.h"
|
||||
#include "script.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/* virtual */ void COrder_Board::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-board\",");
|
||||
|
||||
file.printf(" \"range\", %d,", this->Range);
|
||||
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(" \"state\", %d,\n ", this->State);
|
||||
|
||||
SaveDataMove(file);
|
||||
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Board::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
if (this->ParseMoveData(l, j, value)) {
|
||||
return true;
|
||||
} else if (!strcmp("state", value)) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
** Move to transporter.
|
||||
**
|
||||
|
@ -80,49 +117,47 @@ static int MoveToTransporter(CUnit &unit)
|
|||
**
|
||||
** @return True if ship arrived/present, False otherwise.
|
||||
*/
|
||||
static int WaitForTransporter(CUnit &unit)
|
||||
bool COrder_Board::WaitForTransporter(CUnit &unit)
|
||||
{
|
||||
|
||||
if (unit.Wait) {
|
||||
unit.Wait--;
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
CUnit *trans = unit.CurrentOrder()->GetGoal();
|
||||
const CUnit *trans = this->GetGoal();
|
||||
|
||||
if (!trans || !CanTransport(*trans, unit)) {
|
||||
// FIXME: destination destroyed??
|
||||
unit.Wait = 6;
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!trans->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("Transporter Gone\n");
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
this->ClearGoal();
|
||||
unit.Wait = 6;
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unit.MapDistanceTo(*trans) == 1) {
|
||||
// enter transporter
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: any enemies in range attack them, while waiting.
|
||||
//
|
||||
|
||||
// n0b0dy: This means we have to search with a smaller range.
|
||||
// It happens only when you reach the shore,and the transporter
|
||||
// is not there. The unit searches with a big range, so it thinks
|
||||
// it's there. This is why we reset the search. The transporter
|
||||
// should be a lot closer now, so it's not as bad as it seems.
|
||||
unit.SubAction = 0;
|
||||
unit.CurrentOrder()->Range = 1;
|
||||
this->State = 0;
|
||||
this->Range = 1;
|
||||
// Uhh wait a bit.
|
||||
unit.Wait = 10;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,26 +165,19 @@ static int WaitForTransporter(CUnit &unit)
|
|||
**
|
||||
** @param unit Pointer to unit.
|
||||
*/
|
||||
static void EnterTransporter(CUnit &unit)
|
||||
static void EnterTransporter(CUnit &unit, COrder_Board &order)
|
||||
{
|
||||
CUnit *transporter;
|
||||
CUnit *transporter = order.GetGoal();
|
||||
|
||||
unit.ClearAction();
|
||||
Assert(transporter != NULL);
|
||||
|
||||
transporter = unit.CurrentOrder()->GetGoal();
|
||||
if (!transporter->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("Transporter gone\n");
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
return;
|
||||
}
|
||||
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
|
||||
//
|
||||
// Place the unit inside the transporter.
|
||||
//
|
||||
|
||||
if (transporter->BoardCount < transporter->Type->MaxOnBoard) {
|
||||
// Place the unit inside the transporter.
|
||||
unit.Remove(transporter);
|
||||
transporter->BoardCount++;
|
||||
unit.Boarded = 1;
|
||||
|
@ -166,6 +194,56 @@ static void EnterTransporter(CUnit &unit)
|
|||
DebugPrint("No free slot in transporter\n");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Board::Execute(CUnit &unit)
|
||||
{
|
||||
switch (this->State) {
|
||||
// Wait for transporter
|
||||
case 201:
|
||||
if (this->WaitForTransporter(unit)) {
|
||||
this->State = 202;
|
||||
} else {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Still);
|
||||
}
|
||||
break;
|
||||
// Enter transporter
|
||||
case 202:
|
||||
EnterTransporter(unit, *this);
|
||||
return true;
|
||||
break;
|
||||
// Move to transporter
|
||||
case 0:
|
||||
if (unit.Wait) {
|
||||
unit.Wait--;
|
||||
return false;
|
||||
}
|
||||
this->NewResetPath();
|
||||
this->State = 1;
|
||||
// FALL THROUGH
|
||||
default:
|
||||
if (this->State <= 200) {
|
||||
const int pathRet = MoveToTransporter(unit);
|
||||
// FIXME: if near transporter wait for enter
|
||||
if (pathRet) {
|
||||
if (pathRet == PF_UNREACHABLE) {
|
||||
if (++this->State == 200) {
|
||||
return true;
|
||||
} else {
|
||||
// Try with a bigger range.
|
||||
if (this->CheckRange()) {
|
||||
this->Range++;
|
||||
this->State--;
|
||||
}
|
||||
}
|
||||
} else if (pathRet == PF_REACHED) {
|
||||
this->State = 201;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
** The unit boards a transporter.
|
||||
**
|
||||
|
@ -175,52 +253,8 @@ static void EnterTransporter(CUnit &unit)
|
|||
*/
|
||||
void HandleActionBoard(COrder& order, CUnit &unit)
|
||||
{
|
||||
switch (unit.SubAction) {
|
||||
// Wait for transporter
|
||||
case 201:
|
||||
if (WaitForTransporter(unit)) {
|
||||
unit.SubAction = 202;
|
||||
} else {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Still);
|
||||
}
|
||||
break;
|
||||
// Enter transporter
|
||||
case 202:
|
||||
EnterTransporter(unit);
|
||||
break;
|
||||
// Move to transporter
|
||||
case 0:
|
||||
if (unit.Wait) {
|
||||
unit.Wait--;
|
||||
return;
|
||||
}
|
||||
order.NewResetPath();
|
||||
unit.SubAction = 1;
|
||||
// FALL THROUGH
|
||||
default:
|
||||
if (unit.SubAction <= 200) {
|
||||
int i;
|
||||
// FIXME: if near transporter wait for enter
|
||||
if ((i = MoveToTransporter(unit))) {
|
||||
if (i == PF_UNREACHABLE) {
|
||||
if (++unit.SubAction == 200) {
|
||||
unit.ClearAction();
|
||||
order.ClearGoal();
|
||||
} else {
|
||||
//
|
||||
// Try with a bigger range.
|
||||
//
|
||||
if (order.CheckRange()) {
|
||||
order.Range++;
|
||||
unit.SubAction--;
|
||||
}
|
||||
}
|
||||
} else if (i == PF_REACHED) {
|
||||
unit.SubAction = 201;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (order.Execute(unit)) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ extern void AiReduceMadeInBuilt(PlayerAi &pai, const CUnitType &type);
|
|||
|
||||
enum
|
||||
{
|
||||
State_Start = 0,
|
||||
State_MoveToLocationMax = 10, // Range from prev
|
||||
State_NearOfLocation = 11, // Range to next
|
||||
State_StartBuilding_Failed = 20,
|
||||
|
@ -89,8 +90,8 @@ enum
|
|||
}
|
||||
file.printf(" \"building\", \"%s\",", UnitReference(this->BuildingUnit).c_str());
|
||||
}
|
||||
file.printf(" \"type\", \"%s\",\n ", this->Type->Ident.c_str());
|
||||
|
||||
file.printf(" \"type\", \"%s\",", this->Type->Ident.c_str());
|
||||
file.printf(" \"state\", %d,\n ", this->State);
|
||||
SaveDataMove(file);
|
||||
file.printf("}");
|
||||
}
|
||||
|
@ -104,6 +105,11 @@ enum
|
|||
lua_rawgeti(l, -1, j + 1);
|
||||
this->BuildingUnit = CclGetUnitFromRef(l);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "state")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "type")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
|
@ -135,18 +141,18 @@ void COrder_Build::AiUnitKilled(CUnit& unit)
|
|||
**
|
||||
** @param unit Unit to move
|
||||
*/
|
||||
static bool MoveToLocation(CUnit &unit, COrder_Build &order)
|
||||
bool COrder_Build::MoveToLocation(CUnit &unit)
|
||||
{
|
||||
// First entry
|
||||
if (!unit.SubAction) {
|
||||
order.Data.Move.Cycles = 0; //moving counter
|
||||
unit.SubAction = 1;
|
||||
order.NewResetPath();
|
||||
if (this->State == 0) {
|
||||
this->Data.Move.Cycles = 0; //moving counter
|
||||
this->State = 1;
|
||||
this->NewResetPath();
|
||||
}
|
||||
switch (DoActionMove(unit)) { // reached end-point?
|
||||
case PF_UNREACHABLE: {
|
||||
// Some tries to reach the goal
|
||||
if (unit.SubAction++ < 10) {
|
||||
if (this->State++ < 10) {
|
||||
// To keep the load low, retry each 1/4 second.
|
||||
// NOTE: we can already inform the AI about this problem?
|
||||
unit.Wait = CYCLES_PER_SECOND / 4;
|
||||
|
@ -156,12 +162,12 @@ static bool MoveToLocation(CUnit &unit, COrder_Build &order)
|
|||
unit.Player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y,
|
||||
_("You cannot reach building place"));
|
||||
if (unit.Player->AiEnabled) {
|
||||
AiCanNotReach(unit, order.GetUnitType());
|
||||
AiCanNotReach(unit, this->GetUnitType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case PF_REACHED:
|
||||
unit.SubAction = State_NearOfLocation;
|
||||
this->State = State_NearOfLocation;
|
||||
return false;
|
||||
|
||||
default:
|
||||
|
@ -219,10 +225,10 @@ private:
|
|||
**
|
||||
** @param unit Unit to check
|
||||
*/
|
||||
static CUnit *CheckCanBuild(CUnit &unit, COrder_Build &order)
|
||||
CUnit *COrder_Build::CheckCanBuild(CUnit &unit)
|
||||
{
|
||||
const Vec2i pos = order.goalPos;
|
||||
const CUnitType &type = order.GetUnitType();
|
||||
const Vec2i pos = this->goalPos;
|
||||
const CUnitType &type = this->GetUnitType();
|
||||
|
||||
// Check if the building could be built there.
|
||||
|
||||
|
@ -231,28 +237,27 @@ static CUnit *CheckCanBuild(CUnit &unit, COrder_Build &order)
|
|||
if (ontop != NULL) {
|
||||
return ontop;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* FIXME: rb - CheckAlreadyBuilding should be somehow
|
||||
* enabled/disable via game lua scripting
|
||||
*/
|
||||
CUnit *building = AlreadyBuildingFinder(unit, type).Find(Map.Field(pos));
|
||||
if (building != NULL) {
|
||||
if (unit.CurrentOrder() == &order) {
|
||||
if (unit.CurrentOrder() == this) {
|
||||
DebugPrint("%d: Worker [%d] is helping build: %s [%d]\n"
|
||||
_C_ unit.Player->Index _C_ unit.Slot
|
||||
_C_ building->Type->Name.c_str()
|
||||
_C_ building->Slot);
|
||||
|
||||
unit.SubAction = 0;
|
||||
delete ℴ
|
||||
unit.Orders[0] = COrder::NewActionRepair(unit, *building);
|
||||
return NULL;
|
||||
delete this; // Bad
|
||||
unit.Orders[0] = COrder::NewActionRepair(unit, *building);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
// Some tries to build the building.
|
||||
unit.SubAction++;
|
||||
this->State++;
|
||||
// To keep the load low, retry each 10 cycles
|
||||
// NOTE: we can already inform the AI about this problem?
|
||||
unit.Wait = 10;
|
||||
|
@ -311,12 +316,12 @@ bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop)
|
|||
if (!type.BuilderOutside) {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Still);
|
||||
unit.Remove(build);
|
||||
unit.SubAction = State_BuildFromInside;
|
||||
this->State = State_BuildFromInside;
|
||||
if (unit.Selected) {
|
||||
SelectedUnitChanged();
|
||||
}
|
||||
} else {
|
||||
unit.SubAction = State_BuildFromOutside;
|
||||
this->State = State_BuildFromOutside;
|
||||
this->BuildingUnit = build;
|
||||
unit.Direction = DirectionToHeading(build->tilePos - unit.tilePos);
|
||||
UnitUpdateHeading(unit);
|
||||
|
@ -372,24 +377,24 @@ bool COrder_Build::BuildFromOutside(CUnit &unit) const
|
|||
unit.Wait--;
|
||||
return false;
|
||||
}
|
||||
if (unit.SubAction <= State_MoveToLocationMax) {
|
||||
if (MoveToLocation(unit, *this)) {
|
||||
if (this->State <= State_MoveToLocationMax) {
|
||||
if (this->MoveToLocation(unit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const CUnitType &type = this->GetUnitType();
|
||||
|
||||
if (State_NearOfLocation <= unit.SubAction && unit.SubAction < State_StartBuilding_Failed) {
|
||||
if (State_NearOfLocation <= this->State && this->State < State_StartBuilding_Failed) {
|
||||
if (CheckLimit(unit, type) == false) {
|
||||
return true;
|
||||
}
|
||||
CUnit *ontop = CheckCanBuild(unit, *this);
|
||||
CUnit *ontop = this->CheckCanBuild(unit);
|
||||
|
||||
if (ontop != NULL) {
|
||||
this->StartBuilding(unit, *ontop);
|
||||
}
|
||||
}
|
||||
if (unit.SubAction == State_StartBuilding_Failed) {
|
||||
if (this->State == State_StartBuilding_Failed) {
|
||||
unit.Player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y,
|
||||
_("You cannot build %s here"), type.Name.c_str());
|
||||
if (unit.Player->AiEnabled) {
|
||||
|
@ -397,7 +402,7 @@ bool COrder_Build::BuildFromOutside(CUnit &unit) const
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (unit.SubAction == State_BuildFromOutside) {
|
||||
if (this->State == State_BuildFromOutside) {
|
||||
this->BuildFromOutside(unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,6 @@ static bool AnimateActionDie(CUnit &unit)
|
|||
unit.Stats = &type.Stats[unit.Player->Index];
|
||||
unit.Place(unit.tilePos);
|
||||
|
||||
unit.SubAction = 0;
|
||||
unit.Frame = 0;
|
||||
UnitUpdateHeading(unit);
|
||||
AnimateActionDie(unit); // with new corpse.
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "unittype.h"
|
||||
#include "pathfinder.h"
|
||||
#include "map.h"
|
||||
#include "interface.h"
|
||||
#include "actions.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -67,7 +66,7 @@ void HandleActionFollow(COrder& order, CUnit &unit)
|
|||
CUnit *goal = order.GetGoal();
|
||||
|
||||
// Reached target
|
||||
if (unit.SubAction == 128) {
|
||||
if (order.SubAction.Follow == 128) {
|
||||
|
||||
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("Goal gone\n");
|
||||
|
@ -91,14 +90,14 @@ void HandleActionFollow(COrder& order, CUnit &unit)
|
|||
unit.Wait = 10;
|
||||
if (order.Range > 1) {
|
||||
order.Range = 1;
|
||||
unit.SubAction = 0;
|
||||
order.SubAction.Follow = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
unit.SubAction = 0;
|
||||
order.SubAction.Follow = 0;
|
||||
}
|
||||
if (!unit.SubAction) { // first entry
|
||||
unit.SubAction = 1;
|
||||
if (!order.SubAction.Follow) { // first entry
|
||||
order.SubAction .Follow= 1;
|
||||
order.NewResetPath();
|
||||
Assert(unit.State == 0);
|
||||
}
|
||||
|
@ -161,7 +160,7 @@ void HandleActionFollow(COrder& order, CUnit &unit)
|
|||
return;
|
||||
}
|
||||
order.goalPos = goal->tilePos;
|
||||
unit.SubAction = 128;
|
||||
order.SubAction.Follow = 128;
|
||||
}
|
||||
// FALL THROUGH
|
||||
default:
|
||||
|
|
|
@ -182,13 +182,6 @@ void HandleActionMove(COrder& order, CUnit &unit)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!unit.SubAction) { // first entry
|
||||
unit.SubAction = 1;
|
||||
unit.CurrentOrder()->NewResetPath();
|
||||
order.Data.Move.Cycles = 0;
|
||||
Assert(unit.State == 0);
|
||||
}
|
||||
|
||||
// FIXME: (mr-russ) Make a reachable goal here with GoalReachable ...
|
||||
|
||||
switch (DoActionMove(unit)) { // reached end-point?
|
||||
|
|
|
@ -57,6 +57,9 @@
|
|||
file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
|
||||
file.printf(" \"range\", %d,", this->Range);
|
||||
|
||||
if (this->WaitingCycle != 0) {
|
||||
file.printf(" \"waiting-cycle\", %d,", this->WaitingCycle);
|
||||
}
|
||||
file.printf(" \"patrol\", {%d, %d},\n ", this->WayPoint.x, this->WayPoint.y);
|
||||
SaveDataMove(file);
|
||||
file.printf("}");
|
||||
|
@ -71,6 +74,11 @@
|
|||
lua_rawgeti(l, -1, j + 1);
|
||||
CclGetPos(l, &this->WayPoint.x , &this->WayPoint.y);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "waiting-cycle")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->WaitingCycle = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -84,37 +92,30 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!unit.SubAction) { // first entry.
|
||||
this->Data.Move.Cycles = 0; //moving counter
|
||||
this->NewResetPath();
|
||||
unit.SubAction = 1;
|
||||
}
|
||||
|
||||
switch (DoActionMove(unit)) {
|
||||
case PF_FAILED:
|
||||
unit.SubAction = 1;
|
||||
this->WaitingCycle = 0;
|
||||
break;
|
||||
case PF_UNREACHABLE:
|
||||
// Increase range and try again
|
||||
unit.SubAction = 1;
|
||||
this->WaitingCycle = 1;
|
||||
if (this->CheckRange()) {
|
||||
this->Range++;
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
case PF_REACHED:
|
||||
unit.SubAction = 1;
|
||||
this->WaitingCycle = 1;
|
||||
this->Range = 0;
|
||||
std::swap(this->WayPoint, this->goalPos);
|
||||
|
||||
this->Data.Move.Cycles = 0; //moving counter
|
||||
this->NewResetPath();
|
||||
break;
|
||||
case PF_WAIT:
|
||||
// Wait for a while then give up
|
||||
unit.SubAction++;
|
||||
if (unit.SubAction == 5) {
|
||||
unit.SubAction = 1;
|
||||
this->WaitingCycle++;
|
||||
if (this->WaitingCycle == 5) {
|
||||
this->WaitingCycle = 0;
|
||||
this->Range = 0;
|
||||
std::swap(this->WayPoint, this->goalPos);
|
||||
|
||||
|
@ -123,12 +124,12 @@
|
|||
}
|
||||
break;
|
||||
default: // moving
|
||||
unit.SubAction = 1;
|
||||
this->WaitingCycle = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
if (AutoAttack(unit, false) || AutoRepair(unit) || AutoCast(unit)) {
|
||||
if (AutoAttack(unit) || AutoRepair(unit) || AutoCast(unit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,60 +48,103 @@
|
|||
#include "map.h"
|
||||
#include "pathfinder.h"
|
||||
#include "interface.h"
|
||||
#include "iolib.h"
|
||||
#include "script.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/* virtual */ void COrder_Repair::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-repair\",");
|
||||
|
||||
file.printf(" \"range\", %d,", this->Range);
|
||||
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(" \"repaircycle\", %d,", this->RepairCycle);
|
||||
file.printf(" \"state\", %d,\n ", this->State);
|
||||
|
||||
SaveDataMove(file);
|
||||
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Repair::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
if (this->ParseMoveData(l, j, value)) {
|
||||
return true;
|
||||
} else if (!strcmp("repaircycle", value)) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->RepairCycle = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp("state", value)) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** Repair a unit.
|
||||
**
|
||||
** @param unit unit repairing
|
||||
** @param goal unit being repaired
|
||||
**
|
||||
** @return true when action is finished/canceled.
|
||||
*/
|
||||
static void RepairUnit(CUnit &unit, CUnit &goal)
|
||||
bool COrder_Repair::RepairUnit(const CUnit &unit, CUnit &goal)
|
||||
{
|
||||
if (goal.CurrentAction() == UnitActionBuilt) {
|
||||
COrder_Built &order = *static_cast<COrder_Built *>(goal.CurrentOrder());
|
||||
|
||||
order.ProgressHp(goal, 100 * unit.CurrentOrder()->Data.Repair.Cycles);
|
||||
unit.CurrentOrder()->Data.Repair.Cycles = 0;
|
||||
return ;
|
||||
order.ProgressHp(goal, 100 * this->RepairCycle);
|
||||
this->RepairCycle = 0;
|
||||
return false;
|
||||
}
|
||||
CPlayer *player = unit.Player;
|
||||
char buf[100];
|
||||
if (goal.Variable[HP_INDEX].Value >= goal.Variable[HP_INDEX].Max) {
|
||||
return true;
|
||||
}
|
||||
CPlayer &player = *unit.Player;
|
||||
|
||||
// Calculate the repair costs.
|
||||
Assert(goal.Stats->Variables[HP_INDEX].Max);
|
||||
|
||||
// Check if enough resources are available
|
||||
for (int i = 1; i < MaxCosts; ++i) {
|
||||
if (player->Resources[i] < goal.Type->RepairCosts[i]) {
|
||||
snprintf(buf, 100, _("We need more %s for repair!"),
|
||||
DefaultResourceNames[i].c_str());
|
||||
player->Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
|
||||
if (player->AiEnabled) {
|
||||
// FIXME: call back to AI?
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
if (!unit.RestoreOrder()) {
|
||||
unit.ClearAction();
|
||||
unit.State = 0;
|
||||
}
|
||||
}
|
||||
// FIXME: We shouldn't animate if no resources are available.
|
||||
return;
|
||||
if (player.Resources[i] < goal.Type->RepairCosts[i]) {
|
||||
char buf[100];
|
||||
|
||||
snprintf(buf, 100, _("We need more %s for repair!"), DefaultResourceNames[i].c_str());
|
||||
player.Notify(NotifyYellow, unit.tilePos.x, unit.tilePos.y, buf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Subtract the resources
|
||||
//
|
||||
player->SubCosts(goal.Type->RepairCosts);
|
||||
player.SubCosts(goal.Type->RepairCosts);
|
||||
|
||||
goal.Variable[HP_INDEX].Value += goal.Type->RepairHP;
|
||||
if (goal.Variable[HP_INDEX].Value > goal.Variable[HP_INDEX].Max) {
|
||||
if (goal.Variable[HP_INDEX].Value >= goal.Variable[HP_INDEX].Max) {
|
||||
goal.Variable[HP_INDEX].Value = goal.Variable[HP_INDEX].Max;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,46 +152,33 @@ static void RepairUnit(CUnit &unit, CUnit &goal)
|
|||
**
|
||||
** @param unit Unit, for that the repair animation is played.
|
||||
*/
|
||||
static int AnimateActionRepair(CUnit &unit)
|
||||
static void AnimateActionRepair(CUnit &unit)
|
||||
{
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Repair);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
** Unit repairs
|
||||
**
|
||||
** @param unit Unit, for that the attack is handled.
|
||||
*/
|
||||
void HandleActionRepair(COrder& order, CUnit &unit)
|
||||
/* virtual */ bool COrder_Repair::Execute(CUnit &unit)
|
||||
{
|
||||
CUnit *goal;
|
||||
int err;
|
||||
|
||||
switch (unit.SubAction) {
|
||||
switch (this->State) {
|
||||
case 0:
|
||||
order.NewResetPath();
|
||||
unit.SubAction = 1;
|
||||
this->NewResetPath();
|
||||
this->State = 1;
|
||||
// FALL THROUGH
|
||||
case 1:// Move near to target.
|
||||
case 1: { // Move near to target.
|
||||
// FIXME: RESET FIRST!! Why? We move first and than check if
|
||||
// something is in sight.
|
||||
err = DoActionMove(unit);
|
||||
int err = DoActionMove(unit);
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
// No goal: if meeting damaged building repair it.
|
||||
goal = order.GetGoal();
|
||||
CUnit *goal = this->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");
|
||||
order.goalPos = goal->tilePos;
|
||||
// FIXME: should I clear this here?
|
||||
order.ClearGoal();
|
||||
this->goalPos = goal->tilePos;
|
||||
this->ClearGoal();
|
||||
goal = NULL;
|
||||
order.NewResetPath();
|
||||
this->NewResetPath();
|
||||
}
|
||||
} else if (unit.Player->AiEnabled) {
|
||||
// Ai players workers should stop if target is killed
|
||||
|
@ -156,70 +186,65 @@ void HandleActionRepair(COrder& order, CUnit &unit)
|
|||
}
|
||||
|
||||
// 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) {
|
||||
if (goal && unit.MapDistanceTo(*goal) <= unit.Type->RepairRange
|
||||
&& goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
|
||||
unit.State = 0;
|
||||
unit.SubAction = 2;
|
||||
order.Data.Repair.Cycles = 0;
|
||||
this->State = 2;
|
||||
this->RepairCycle = 0;
|
||||
const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
|
||||
UnitHeadingFromDeltaXY(unit, dir);
|
||||
} else if (err < 0) {
|
||||
order.ClearGoal();
|
||||
if (!unit.RestoreOrder()) {
|
||||
unit.ClearAction();
|
||||
unit.State = 0;
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Should be it already?
|
||||
Assert(unit.CurrentAction() == UnitActionRepair);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:// Repair the target.
|
||||
}
|
||||
case 2: {// Repair the target.
|
||||
AnimateActionRepair(unit);
|
||||
order.Data.Repair.Cycles++;
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
goal = unit.CurrentOrder()->GetGoal();
|
||||
|
||||
// Target is dead, choose new one.
|
||||
//
|
||||
// Check if goal is correct unit.
|
||||
// FIXME: should I do a function for this?
|
||||
if (goal) {
|
||||
if (!goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("repair goal is gone\n");
|
||||
order.goalPos = goal->tilePos;
|
||||
// FIXME: should I clear this here?
|
||||
order.ClearGoal();
|
||||
goal = NULL;
|
||||
order.NewResetPath();
|
||||
} else {
|
||||
int dist = unit.MapDistanceTo(*goal);
|
||||
if (dist <= unit.Type->RepairRange) {
|
||||
RepairUnit(unit, *goal);
|
||||
goal = order.GetGoal();
|
||||
} else if (dist > unit.Type->RepairRange) {
|
||||
// If goal has move, chase after it
|
||||
unit.State = 0;
|
||||
unit.SubAction = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Target is fine, choose new one.
|
||||
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
|
||||
this->RepairCycle++;
|
||||
if (unit.Anim.Unbreakable) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
if (goal) {
|
||||
if (!goal->IsVisibleAsGoal(*unit.Player)) {
|
||||
DebugPrint("repair goal is gone\n");
|
||||
this->goalPos = goal->tilePos;
|
||||
// FIXME: should I clear this here?
|
||||
this->ClearGoal();
|
||||
goal = NULL;
|
||||
this->NewResetPath();
|
||||
} else {
|
||||
const int dist = unit.MapDistanceTo(*goal);
|
||||
|
||||
if (dist <= unit.Type->RepairRange) {
|
||||
if (RepairUnit(unit, *goal)) {
|
||||
return true;
|
||||
}
|
||||
} else if (dist > unit.Type->RepairRange) {
|
||||
// If goal has move, chase after it
|
||||
unit.State = 0;
|
||||
this->State = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Target is fine, choose new one.
|
||||
if (!goal || goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
|
||||
return true;
|
||||
}
|
||||
// FIXME: automatic repair
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void HandleActionRepair(COrder& order, CUnit &unit)
|
||||
{
|
||||
if (order.Execute(unit)) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ static void UnitGotoGoal(CUnit &unit, CUnit *const goal, int mode)
|
|||
}
|
||||
}
|
||||
order->Range = 1;
|
||||
unit.SubAction = mode;
|
||||
order->SubAction.Res = mode;
|
||||
unit.State = 0;
|
||||
if (mode == SUB_MOVE_TO_DEPOT || mode == SUB_MOVE_TO_RESOURCE) {
|
||||
unit.CurrentOrder()->Data.Move.Cycles = 0; //moving counter
|
||||
|
@ -209,7 +209,7 @@ static int StartGathering(CUnit &unit)
|
|||
// Find an alternative, but don't look too far.
|
||||
unit.CurrentOrder()->goalPos.x = unit.CurrentOrder()->goalPos.y = -1;
|
||||
if ((goal = UnitFindResource(unit, unit.tilePos, 15, unit.CurrentResource, unit.Player->AiEnabled))) {
|
||||
unit.SubAction = SUB_START_RESOURCE;
|
||||
unit.CurrentOrder()->SubAction.Res = SUB_START_RESOURCE;
|
||||
unit.CurrentOrder()->SetGoal(goal);
|
||||
} else {
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
|
@ -324,7 +324,7 @@ static void LoseResource(CUnit &unit, const CUnit &source)
|
|||
unit.CurrentOrder()->Arg1.Resource.Mine = goal;
|
||||
unit.CurrentOrder()->Range = 1;
|
||||
unit.CurrentOrder()->goalPos = goal->tilePos;
|
||||
unit.SubAction = SUB_MOVE_TO_RESOURCE;
|
||||
unit.CurrentOrder()->SubAction.Res = SUB_MOVE_TO_RESOURCE;
|
||||
unit.State = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ static void LoseResource(CUnit &unit, const CUnit &source)
|
|||
if (depot) {
|
||||
DebugPrint("%d: Worker %d report: Resource is exhausted, Found another resource.\n"
|
||||
_C_ unit.Player->Index _C_ unit.Slot);
|
||||
unit.SubAction = SUB_START_RESOURCE;
|
||||
unit.CurrentOrder()->SubAction.Res = SUB_START_RESOURCE;
|
||||
unit.State = 0;
|
||||
unit.CurrentOrder()->SetGoal(depot);
|
||||
} else {
|
||||
|
@ -391,7 +391,9 @@ static int GatherResource(CUnit &unit)
|
|||
int addload;
|
||||
|
||||
if (!resinfo.HarvestFromOutside && unit.Container != NULL) {
|
||||
unit.Container->SubAction = SUB_GATHER_RESOURCE;
|
||||
#if 0
|
||||
// unit.Container->SubAction = SUB_GATHER_RESOURCE;
|
||||
#endif
|
||||
UnitShowAnimation(*unit.Container, unit.Container->Type->Animations->Harvest[unit.CurrentResource]);
|
||||
}
|
||||
|
||||
|
@ -412,7 +414,7 @@ static int GatherResource(CUnit &unit)
|
|||
if (resinfo.TerrainHarvester && !Map.ForestOnMap(unit.CurrentOrder()->goalPos)) {
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
// Action now breakable, move to resource again.
|
||||
unit.SubAction = SUB_MOVE_TO_RESOURCE;
|
||||
unit.CurrentOrder()->SubAction.Res = SUB_MOVE_TO_RESOURCE;
|
||||
// Give it some reasonable look while searching.
|
||||
// FIXME: which frame?
|
||||
unit.Frame = 0;
|
||||
|
@ -529,7 +531,7 @@ int GetNumWaitingWorkers(const CUnit &mine)
|
|||
|
||||
for (int i = 0; NULL != worker; worker = worker->NextWorker, ++i)
|
||||
{
|
||||
if (worker->SubAction == SUB_START_GATHERING && worker->Wait) {
|
||||
if (worker->CurrentOrder()->SubAction.Res == SUB_START_GATHERING && worker->Wait) {
|
||||
ret++;
|
||||
}
|
||||
Assert(i <= mine.Resource.Assigned);
|
||||
|
@ -558,10 +560,11 @@ static int StopGathering(CUnit &unit)
|
|||
}
|
||||
source->Resource.Active--;
|
||||
Assert(source->Resource.Active >= 0);
|
||||
|
||||
#if 0
|
||||
if (!resinfo.HarvestFromOutside && source->Resource.Active == 0) {
|
||||
source->SubAction = 1;
|
||||
}
|
||||
#endif
|
||||
//Store resource position.
|
||||
if (unit.Orders[0]->Arg1.Resource.Mine) {
|
||||
unit.Orders[0]->Arg1.Resource.Mine->RefsDecrease();
|
||||
|
@ -575,7 +578,7 @@ static int StopGathering(CUnit &unit)
|
|||
CUnit *next = NULL;
|
||||
for(; NULL != worker; worker = worker->NextWorker)
|
||||
{
|
||||
if (worker != &unit && worker->SubAction == SUB_START_GATHERING && worker->Wait) {
|
||||
if (worker != &unit && worker->CurrentOrder()->SubAction.Res == SUB_START_GATHERING && worker->Wait) {
|
||||
count++;
|
||||
if (next) {
|
||||
if (next->Wait > worker->Wait)
|
||||
|
@ -849,7 +852,7 @@ void ResourceGiveUp(CUnit &unit)
|
|||
*/
|
||||
static bool ActionResourceInit(CUnit &unit)
|
||||
{
|
||||
Assert(unit.SubAction == SUB_START_RESOURCE);
|
||||
Assert(unit.CurrentOrder()->SubAction.Res == SUB_START_RESOURCE);
|
||||
|
||||
CUnit *const goal = unit.CurrentOrder()->GetGoal();
|
||||
int newres;
|
||||
|
@ -905,27 +908,27 @@ void HandleActionResource(COrder& order, CUnit &unit)
|
|||
}
|
||||
|
||||
// Let's start mining.
|
||||
if (unit.SubAction == SUB_START_RESOURCE) {
|
||||
if (order.SubAction.Res == SUB_START_RESOURCE) {
|
||||
if (ActionResourceInit(unit) == false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the resource location.
|
||||
if (SUB_MOVE_TO_RESOURCE <= unit.SubAction && unit.SubAction < SUB_UNREACHABLE_RESOURCE) {
|
||||
if (SUB_MOVE_TO_RESOURCE <= order.SubAction.Res && order.SubAction.Res < SUB_UNREACHABLE_RESOURCE) {
|
||||
const int ret = MoveToResource(unit);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case -1: // Can't Reach
|
||||
{
|
||||
unit.SubAction++;
|
||||
order.SubAction.Res++;
|
||||
unit.Wait = 5;
|
||||
return;
|
||||
}
|
||||
case 1: // Reached
|
||||
{
|
||||
unit.SubAction = SUB_START_GATHERING;
|
||||
order.SubAction.Res = SUB_START_GATHERING;
|
||||
break;
|
||||
}
|
||||
case 0: // Move along.
|
||||
|
@ -939,53 +942,53 @@ void HandleActionResource(COrder& order, CUnit &unit)
|
|||
}
|
||||
|
||||
// Resource seems to be unreachable
|
||||
if (unit.SubAction == SUB_UNREACHABLE_RESOURCE) {
|
||||
if (order.SubAction.Res == SUB_UNREACHABLE_RESOURCE) {
|
||||
ResourceGiveUp(unit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start gathering the resource
|
||||
if (unit.SubAction == SUB_START_GATHERING) {
|
||||
if (order.SubAction.Res == SUB_START_GATHERING) {
|
||||
if (StartGathering(unit)) {
|
||||
unit.SubAction = SUB_GATHER_RESOURCE;
|
||||
order.SubAction.Res = SUB_GATHER_RESOURCE;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Gather the resource.
|
||||
if (unit.SubAction == SUB_GATHER_RESOURCE) {
|
||||
if (order.SubAction.Res == SUB_GATHER_RESOURCE) {
|
||||
if (GatherResource(unit)) {
|
||||
unit.SubAction = SUB_STOP_GATHERING;
|
||||
order.SubAction.Res = SUB_STOP_GATHERING;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop gathering the resource.
|
||||
if (unit.SubAction == SUB_STOP_GATHERING) {
|
||||
if (order.SubAction.Res == SUB_STOP_GATHERING) {
|
||||
if (StopGathering(unit)) {
|
||||
unit.SubAction = SUB_MOVE_TO_DEPOT;
|
||||
unit.CurrentOrder()->Data.Move.Cycles = 0; //moving counter
|
||||
order.SubAction.Res = SUB_MOVE_TO_DEPOT;
|
||||
order.Data.Move.Cycles = 0; //moving counter
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
// Move back home.
|
||||
if (SUB_MOVE_TO_DEPOT <= unit.SubAction && unit.SubAction < SUB_UNREACHABLE_DEPOT) {
|
||||
if (SUB_MOVE_TO_DEPOT <= order.SubAction.Res && order.SubAction.Res < SUB_UNREACHABLE_DEPOT) {
|
||||
const int ret = MoveToDepot(unit);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case -1: // Can't Reach
|
||||
{
|
||||
unit.SubAction++;
|
||||
order.SubAction.Res++;
|
||||
unit.Wait = 5;
|
||||
return;
|
||||
}
|
||||
case 1: // Reached
|
||||
{
|
||||
unit.SubAction = SUB_RETURN_RESOURCE;
|
||||
order.SubAction.Res = SUB_RETURN_RESOURCE;
|
||||
return;
|
||||
}
|
||||
case 0: // Move along.
|
||||
|
@ -999,15 +1002,15 @@ void HandleActionResource(COrder& order, CUnit &unit)
|
|||
}
|
||||
|
||||
// Depot seems to be unreachable
|
||||
if (unit.SubAction == SUB_UNREACHABLE_DEPOT) {
|
||||
if (order.SubAction.Res == SUB_UNREACHABLE_DEPOT) {
|
||||
ResourceGiveUp(unit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Unload resources at the depot.
|
||||
if (unit.SubAction == SUB_RETURN_RESOURCE) {
|
||||
if (order.SubAction.Res == SUB_RETURN_RESOURCE) {
|
||||
if (WaitInDepot(unit)) {
|
||||
unit.SubAction = SUB_START_RESOURCE;
|
||||
order.SubAction.Res = 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
|
||||
|
|
|
@ -88,7 +88,7 @@ void HandleActionReturnGoods(COrder& order, CUnit &unit)
|
|||
//unit.CurrentOrder()->Arg1.ResourcePos = -1;
|
||||
|
||||
order.NewResetPath();
|
||||
unit.SubAction = /* SUB_MOVE_TO_DEPOT */ 70; // FIXME : Define value.
|
||||
order.SubAction.Res = /* SUB_MOVE_TO_DEPOT */ 70; // FIXME : Define value.
|
||||
}
|
||||
|
||||
//@}
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
#include "tileset.h"
|
||||
#include "map.h"
|
||||
#include "spells.h"
|
||||
#include "interface.h"
|
||||
#include "iolib.h"
|
||||
#include "script.h"
|
||||
|
||||
|
@ -81,6 +80,7 @@
|
|||
}
|
||||
file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
|
||||
|
||||
file.printf("\"state\", %d", this->State);
|
||||
file.printf(" \"spell\", \"%s\",\n ", this->Spell->Ident.c_str());
|
||||
|
||||
SaveDataMove(file);
|
||||
|
@ -96,6 +96,11 @@
|
|||
lua_rawgeti(l, -1, j + 1);
|
||||
this->Spell = SpellTypeByIdent(LuaToString(l, -1));
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "state")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -145,45 +150,38 @@ static void AnimateActionSpellCast(CUnit &unit, COrder_SpellCast &order)
|
|||
**
|
||||
** @param unit Unit, for that the spell cast is handled.
|
||||
*/
|
||||
static void SpellMoveToTarget(CUnit &unit)
|
||||
bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
|
||||
{
|
||||
CUnit *goal;
|
||||
int err;
|
||||
|
||||
// Unit can't move
|
||||
err = 1;
|
||||
int err = 1;
|
||||
if (unit.CanMove()) {
|
||||
err = DoActionMove(unit);
|
||||
if (unit.Anim.Unbreakable) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// when reached DoActionMove changes unit action
|
||||
// FIXME: use return codes from pathfinder
|
||||
COrderPtr order = unit.CurrentOrder();
|
||||
goal = order->GetGoal();
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
if (goal && unit.MapDistanceTo(*goal) <= order->Range) {
|
||||
if (goal && unit.MapDistanceTo(*goal) <= this->Range) {
|
||||
// there is goal and it is in range
|
||||
unit.State = 0;
|
||||
UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
|
||||
unit.SubAction++; // cast the spell
|
||||
return;
|
||||
} else if (!goal && unit.MapDistanceTo(order->goalPos.x, order->goalPos.y) <= order->Range) {
|
||||
this->State++; // cast the spell
|
||||
return false;
|
||||
} else if (!goal && unit.MapDistanceTo(this->goalPos.x, this->goalPos.y) <= this->Range) {
|
||||
// there is no goal and target spot is in range
|
||||
UnitHeadingFromDeltaXY(unit, order->goalPos - unit.tilePos);
|
||||
unit.SubAction++; // cast the spell
|
||||
return;
|
||||
UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
|
||||
this->State++; // cast the spell
|
||||
return false;
|
||||
} else if (err == PF_UNREACHABLE) {
|
||||
//
|
||||
// goal/spot unreachable and out of range -- give up
|
||||
//
|
||||
unit.ClearAction();
|
||||
unit.State = 0;
|
||||
order->ClearGoal(); // Release references
|
||||
return true;
|
||||
}
|
||||
Assert(!unit.Type->Vanishes && !unit.Destroyed);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,7 +194,7 @@ static void SpellMoveToTarget(CUnit &unit)
|
|||
return false;
|
||||
}
|
||||
const SpellType &spell = order.GetSpell();
|
||||
switch (unit.SubAction) {
|
||||
switch (this->State) {
|
||||
case 0:
|
||||
// Check if we can cast the spell.
|
||||
if (!CanCastSpell(unit, &spell, order.GetGoal(), order.goalPos.x, order.goalPos.y)) {
|
||||
|
@ -221,14 +219,16 @@ static void SpellMoveToTarget(CUnit &unit)
|
|||
unit.CurrentOrder()->NewResetPath();
|
||||
}
|
||||
unit.ReCast = 0; // repeat spell on next pass? (defaults to `no')
|
||||
unit.SubAction = 1;
|
||||
this->State = 1;
|
||||
// FALL THROUGH
|
||||
case 1: // Move to the target.
|
||||
if (spell.Range && spell.Range != INFINITE_RANGE) {
|
||||
SpellMoveToTarget(unit);
|
||||
break;
|
||||
if (SpellMoveToTarget(unit) == true) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
unit.SubAction = 2;
|
||||
this->State = 2;
|
||||
}
|
||||
// FALL THROUGH
|
||||
case 2: // Cast spell on the target.
|
||||
|
@ -252,7 +252,7 @@ static void SpellMoveToTarget(CUnit &unit)
|
|||
break;
|
||||
|
||||
default:
|
||||
unit.SubAction = 0; // Reset path, than move to target
|
||||
this->State = 0; // Reset path, than move to target
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -38,41 +38,11 @@
|
|||
#include "stratagus.h"
|
||||
#include "unit.h"
|
||||
#include "actions.h"
|
||||
#include "iolib.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* virtual */ void COrder_StandGround::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-stand-ground\"");
|
||||
if (this->HasGoal()) {
|
||||
CUnit &goal = *this->GetGoal();
|
||||
if (goal.Destroyed) {
|
||||
/* this unit is destroyed so it's not in the global unit
|
||||
* array - this means it won't be saved!!! */
|
||||
printf ("FIXME: storing destroyed Goal - loading will fail.\n");
|
||||
}
|
||||
file.printf(", \"goal\", \"%s\"", UnitReference(goal).c_str());
|
||||
}
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_StandGround::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_StandGround::Execute(CUnit &unit)
|
||||
{
|
||||
ActionStillGeneric(unit, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Unit stands ground!
|
||||
**
|
||||
|
|
|
@ -48,16 +48,21 @@
|
|||
#include "spells.h"
|
||||
#include "player.h"
|
||||
#include "iolib.h"
|
||||
#include "script.h"
|
||||
|
||||
#define SUB_STILL_INIT 0
|
||||
#define SUB_STILL_STANDBY 1
|
||||
#define SUB_STILL_ATTACK 2
|
||||
|
||||
|
||||
enum {
|
||||
SUB_STILL_INIT = 0,
|
||||
SUB_STILL_STANDBY = 1,
|
||||
SUB_STILL_ATTACK = 2
|
||||
};
|
||||
|
||||
/* virtual */ void COrder_Still::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-still\"");
|
||||
if (this->Action == UnitActionStill) {
|
||||
file.printf("{\"action-still\"");
|
||||
} else {
|
||||
file.printf("{\"action-stand-ground\",");
|
||||
}
|
||||
if (this->HasGoal()) {
|
||||
CUnit &goal = *this->GetGoal();
|
||||
if (goal.Destroyed) {
|
||||
|
@ -65,14 +70,24 @@
|
|||
* 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(" \"goal\", \"%s\",", UnitReference(goal).c_str());
|
||||
}
|
||||
|
||||
file.printf(", \"state\", %d", this->State);
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Still::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
return false;
|
||||
if (!strcmp("state", value)) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,53 +107,47 @@ void UnHideUnit(CUnit &unit)
|
|||
*/
|
||||
static bool MoveRandomly(CUnit &unit)
|
||||
{
|
||||
if (unit.Type->RandomMovementProbability &&
|
||||
((SyncRand() % 100) <= unit.Type->RandomMovementProbability)) {
|
||||
// pick random location
|
||||
Vec2i pos = unit.tilePos;
|
||||
if (unit.Type->RandomMovementProbability == false
|
||||
|| ((SyncRand() % 100) > unit.Type->RandomMovementProbability)) {
|
||||
return false;
|
||||
}
|
||||
// pick random location
|
||||
Vec2i pos = unit.tilePos;
|
||||
|
||||
switch ((SyncRand() >> 12) & 15) {
|
||||
case 0: pos.x++; break;
|
||||
case 1: pos.y++; break;
|
||||
case 2: pos.x--; break;
|
||||
case 3: pos.y--; break;
|
||||
case 4: pos.x++; pos.y++; break;
|
||||
case 5: pos.x--; pos.y++; break;
|
||||
case 6: pos.y--; pos.x++; break;
|
||||
case 7: pos.x--; pos.y--; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch ((SyncRand() >> 12) & 15) {
|
||||
case 0: pos.x++; break;
|
||||
case 1: pos.y++; break;
|
||||
case 2: pos.x--; break;
|
||||
case 3: pos.y--; break;
|
||||
case 4: pos.x++; pos.y++; break;
|
||||
case 5: pos.x--; pos.y++; break;
|
||||
case 6: pos.y--; pos.x++; break;
|
||||
case 7: pos.x--; pos.y--; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// restrict to map
|
||||
if (pos.x < 0) {
|
||||
pos.x = 0;
|
||||
} else if (pos.x >= Map.Info.MapWidth) {
|
||||
pos.x = Map.Info.MapWidth - 1;
|
||||
}
|
||||
if (pos.y < 0) {
|
||||
pos.y = 0;
|
||||
} else if (pos.y >= Map.Info.MapHeight) {
|
||||
pos.y = Map.Info.MapHeight - 1;
|
||||
}
|
||||
// restrict to map
|
||||
if (pos.x < 0) {
|
||||
pos.x = 0;
|
||||
} else if (pos.x >= Map.Info.MapWidth) {
|
||||
pos.x = Map.Info.MapWidth - 1;
|
||||
}
|
||||
if (pos.y < 0) {
|
||||
pos.y = 0;
|
||||
} else if (pos.y >= Map.Info.MapHeight) {
|
||||
pos.y = Map.Info.MapHeight - 1;
|
||||
}
|
||||
|
||||
// move if possible
|
||||
if (pos != unit.tilePos) {
|
||||
UnmarkUnitFieldFlags(unit);
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
COrderPtr order = unit.CurrentOrder();
|
||||
// FIXME: Don't use pathfinder for this, costs too much cpu.
|
||||
order->Action = UnitActionMove;
|
||||
Assert(!order->HasGoal());
|
||||
order->ClearGoal();
|
||||
order->Range = 0;
|
||||
order->goalPos = pos;
|
||||
unit.State = 0;
|
||||
//return true;//TESTME: new localization
|
||||
}
|
||||
// move if possible
|
||||
if (pos != unit.tilePos) {
|
||||
UnmarkUnitFieldFlags(unit);
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
MarkUnitFieldFlags(unit);
|
||||
CommandMove(unit, pos, FlushCommands);
|
||||
return true;
|
||||
}
|
||||
return true;//TESTME: old localization
|
||||
MarkUnitFieldFlags(unit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -152,9 +161,9 @@ bool AutoCast(CUnit &unit)
|
|||
{
|
||||
if (unit.AutoCastSpell && !unit.Removed) { // Removed units can't cast any spells, from bunker)
|
||||
for (unsigned int i = 0; i < SpellTypeTable.size(); ++i) {
|
||||
if (unit.AutoCastSpell[i] &&
|
||||
(SpellTypeTable[i]->AutoCast || SpellTypeTable[i]->AICast) &&
|
||||
AutoCastSpell(unit, SpellTypeTable[i])) {
|
||||
if (unit.AutoCastSpell[i]
|
||||
&& (SpellTypeTable[i]->AutoCast || SpellTypeTable[i]->AICast)
|
||||
&& AutoCastSpell(unit, SpellTypeTable[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +198,7 @@ static CUnit *UnitToRepairInRange(const CUnit &unit, int range)
|
|||
return &candidate;
|
||||
}
|
||||
}
|
||||
return NoUnitP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +215,7 @@ bool AutoRepair(CUnit &unit)
|
|||
}
|
||||
CUnit *repairedUnit = UnitToRepairInRange(unit, repairRange);
|
||||
|
||||
if (repairedUnit == NoUnitP) {
|
||||
if (repairedUnit == NULL) {
|
||||
return false;
|
||||
}
|
||||
const Vec2i invalidPos = {-1, -1};
|
||||
|
@ -221,36 +230,41 @@ bool AutoRepair(CUnit &unit)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
** Auto attack nearby units if possible
|
||||
*/
|
||||
bool AutoAttack(CUnit &unit, bool stand_ground)
|
||||
bool COrder_Still::AutoAttackStand(CUnit &unit)
|
||||
{
|
||||
if (unit.Type->CanAttack == false) {
|
||||
return false;
|
||||
}
|
||||
// Removed units can only attack in AttackRange, from bunker
|
||||
CUnit *goal = AttackUnitsInRange(unit);
|
||||
|
||||
if (stand_ground || unit.Removed || unit.CanMove() == false) {
|
||||
// Removed units can only attack in AttackRange, from bunker
|
||||
CUnit *goal = AttackUnitsInRange(unit);
|
||||
if (goal == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (goal == NULL) {
|
||||
return false;
|
||||
}
|
||||
CUnit *oldGoal =this->GetGoal();
|
||||
if (oldGoal && oldGoal->CurrentAction() == UnitActionDie) {
|
||||
this->ClearGoal();
|
||||
oldGoal = NULL;
|
||||
}
|
||||
if (this->State < SUB_STILL_ATTACK || oldGoal != goal) {
|
||||
// New target.
|
||||
this->SetGoal(goal);
|
||||
unit.State = 0;
|
||||
this->State = SUB_STILL_ATTACK; // Mark attacking.
|
||||
UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CUnit *temp = unit.CurrentOrder()->GetGoal();
|
||||
if (temp && temp->CurrentAction() == UnitActionDie) {
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
temp = NoUnitP;
|
||||
}
|
||||
if (unit.SubAction < SUB_STILL_ATTACK || temp != goal) {
|
||||
// New target.
|
||||
unit.CurrentOrder()->SetGoal(goal);
|
||||
unit.State = 0;
|
||||
unit.SubAction = SUB_STILL_ATTACK; // Mark attacking.
|
||||
UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
|
||||
}
|
||||
return true;
|
||||
|
||||
/**
|
||||
** Auto attack nearby units if possible
|
||||
*/
|
||||
bool AutoAttack(CUnit &unit)
|
||||
{
|
||||
if (unit.Type->CanAttack == false) {
|
||||
return false;
|
||||
}
|
||||
// Normal units react in reaction range.
|
||||
CUnit *goal = AttackUnitsInReactRange(unit);
|
||||
|
@ -258,7 +272,6 @@ bool AutoAttack(CUnit &unit, bool stand_ground)
|
|||
if (goal == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
COrder *savedOrder;
|
||||
|
||||
if (unit.SavedOrder != NULL) {
|
||||
|
@ -268,7 +281,6 @@ bool AutoAttack(CUnit &unit, bool stand_ground)
|
|||
} else {
|
||||
savedOrder = unit.CurrentOrder()->Clone();
|
||||
}
|
||||
|
||||
// Weak goal, can choose other unit, come back after attack
|
||||
CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
|
||||
|
||||
|
@ -279,28 +291,17 @@ bool AutoAttack(CUnit &unit, bool stand_ground)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** Unit stands still or stand ground.
|
||||
**
|
||||
** @param unit Unit pointer for action.
|
||||
** @param stand_ground true if unit is standing ground.
|
||||
*/
|
||||
void ActionStillGeneric(CUnit &unit, bool stand_ground)
|
||||
/* virtual */ bool COrder_Still::Execute(CUnit &unit)
|
||||
{
|
||||
// If unit is not bunkered and removed, wait
|
||||
if (unit.Removed
|
||||
&& (!unit.Container
|
||||
|| !unit.Container->Type->CanTransport()
|
||||
|| !unit.Container->Type->AttackFromTransporter
|
||||
|| unit.Type->Missile.Missile->Class == MissileClassNone)) {
|
||||
// If unit is in building or transporter it is removed.
|
||||
return;
|
||||
&& (unit.Container == NULL || unit.Container->Type->AttackFromTransporter == false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (unit.SubAction) {
|
||||
switch (this->State) {
|
||||
case SUB_STILL_INIT: //first entry
|
||||
unit.SubAction = SUB_STILL_STANDBY;
|
||||
this->State = SUB_STILL_STANDBY;
|
||||
// no break : follow
|
||||
case SUB_STILL_STANDBY:
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Still);
|
||||
|
@ -309,17 +310,23 @@ void ActionStillGeneric(CUnit &unit, bool stand_ground)
|
|||
AnimateActionAttack(unit);
|
||||
break;
|
||||
}
|
||||
|
||||
if (unit.Anim.Unbreakable) { // animation can't be aborted here
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((unit.IsAgressive() && AutoAttack(unit, stand_ground))
|
||||
|| AutoCast(unit)
|
||||
|| AutoRepair(unit)
|
||||
|| MoveRandomly(unit)) {
|
||||
return;
|
||||
if (this->Action == UnitActionStandGround || unit.Removed || unit.CanMove() == false) {
|
||||
if (unit.IsAgressive()) {
|
||||
this->AutoAttackStand(unit);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ((unit.IsAgressive() && AutoAttack(unit))
|
||||
|| AutoCast(unit)
|
||||
|| AutoRepair(unit)
|
||||
|| MoveRandomly(unit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,14 +338,11 @@ void HandleActionStill(COrder& order, CUnit &unit)
|
|||
{
|
||||
Assert(order.Action == UnitActionStill);
|
||||
|
||||
order.Execute(unit);
|
||||
if (order.Execute(unit)) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Still::Execute(CUnit &unit)
|
||||
{
|
||||
ActionStillGeneric(unit, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//@}
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "missile.h"
|
||||
#include "sound.h"
|
||||
#include "ai.h"
|
||||
#include "interface.h"
|
||||
#include "ui.h"
|
||||
#include "iolib.h"
|
||||
|
||||
|
|
|
@ -42,13 +42,50 @@
|
|||
#include "unit.h"
|
||||
#include "actions.h"
|
||||
#include "map.h"
|
||||
#include "interface.h"
|
||||
#include "pathfinder.h"
|
||||
#include "script.h"
|
||||
#include "iolib.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/* virtual */ void COrder_Unload::Save(CFile &file, const CUnit &unit) const
|
||||
{
|
||||
file.printf("{\"action-unload\",");
|
||||
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 ");
|
||||
SaveDataMove(file);
|
||||
file.printf("}");
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Unload::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
if (this->ParseMoveData(l, j, value) == true) {
|
||||
return true;
|
||||
} else if (!strcmp("state", value)) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->State = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** Find a free position close to startPos
|
||||
**
|
||||
|
@ -114,7 +151,7 @@ static bool FindUnloadPosition(const CUnit &transporter, const CUnit &unit, cons
|
|||
**
|
||||
** @param unit Unit to drop out.
|
||||
**
|
||||
** @return True if unit can be unloaded.
|
||||
** @return True if unit is unloaded.
|
||||
**
|
||||
** @bug FIXME: Place unit only on fields reachable from the transporter
|
||||
*/
|
||||
|
@ -125,11 +162,12 @@ static int UnloadUnit(CUnit &transporter, CUnit &unit)
|
|||
|
||||
Assert(unit.Removed);
|
||||
if (!FindUnloadPosition(transporter, unit, transporter.tilePos, maxRange, &pos)) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
unit.Boarded = 0;
|
||||
unit.Place(pos);
|
||||
return 1;
|
||||
transporter.BoardCount--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -265,38 +303,36 @@ static int MoveToDropZone(CUnit &unit)
|
|||
/**
|
||||
** Make one or more unit leave the transporter.
|
||||
**
|
||||
** @param unit Pointer to unit.
|
||||
** @return false if action should continue
|
||||
*/
|
||||
static void LeaveTransporter(CUnit &transporter)
|
||||
bool COrder_Unload::LeaveTransporter(CUnit &transporter)
|
||||
{
|
||||
int stillonboard = 0;
|
||||
CUnit *goal = transporter.CurrentOrder()->GetGoal();
|
||||
//
|
||||
|
||||
// Goal is the specific unit unit that you want to unload.
|
||||
// This can be NULL, in case you want to unload everything.
|
||||
//
|
||||
if (goal) {
|
||||
if (goal->Destroyed) {
|
||||
if (this->HasGoal()) {
|
||||
CUnit &goal = *this->GetGoal();
|
||||
|
||||
if (goal.Destroyed) {
|
||||
DebugPrint("destroyed unit unloading?\n");
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
return;
|
||||
this->ClearGoal();
|
||||
return true;
|
||||
}
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
goal->tilePos = transporter.tilePos;
|
||||
// Try to unload the unit. If it doesn't work there is no problem.
|
||||
if (UnloadUnit(transporter, *goal)) {
|
||||
transporter.BoardCount--;
|
||||
if (UnloadUnit(transporter, goal)) {
|
||||
this->ClearGoal();
|
||||
} else {
|
||||
++stillonboard;
|
||||
}
|
||||
} else {
|
||||
// Unload all units.
|
||||
goal = transporter.UnitInside;
|
||||
CUnit *goal = transporter.UnitInside;
|
||||
for (int i = transporter.InsideCount; i; --i, goal = goal->NextContained) {
|
||||
if (goal->Boarded) {
|
||||
goal->tilePos = transporter.tilePos;
|
||||
if (!UnloadUnit(transporter, *goal)) {
|
||||
++stillonboard;
|
||||
} else {
|
||||
transporter.BoardCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -309,15 +345,64 @@ static void LeaveTransporter(CUnit &transporter)
|
|||
if (stillonboard) {
|
||||
// We tell it to unload at it's current position. This can't be done,
|
||||
// so it will search for a piece of free coast nearby.
|
||||
transporter.CurrentOrder()->Action = UnitActionUnload;
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
transporter.CurrentOrder()->goalPos = transporter.tilePos;
|
||||
transporter.SubAction = 0;
|
||||
this->State = 0;
|
||||
return false;
|
||||
} else {
|
||||
transporter.ClearAction();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ bool COrder_Unload::Execute(CUnit &unit)
|
||||
{
|
||||
const int maxSearchRange = 20;
|
||||
|
||||
if (!unit.CanMove()) {
|
||||
this->State = 2;
|
||||
}
|
||||
switch (this->State) {
|
||||
case 0: // Choose destination
|
||||
if (!this->HasGoal()) {
|
||||
Vec2i pos;
|
||||
|
||||
if (!ClosestFreeDropZone(unit, this->goalPos, maxSearchRange, &pos)) {
|
||||
return true;
|
||||
}
|
||||
this->goalPos = pos;
|
||||
}
|
||||
|
||||
this->NewResetPath();
|
||||
this->State = 1;
|
||||
// follow on next case
|
||||
case 1: // Move unit to destination
|
||||
// The Goal is the unit that we have to unload.
|
||||
if (!this->HasGoal()) {
|
||||
const int moveResult = MoveToDropZone(unit);
|
||||
|
||||
// We have to unload everything
|
||||
if (moveResult) {
|
||||
if (moveResult == PF_REACHED) {
|
||||
if (++this->State == 1) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
this->State = 2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 2: { // Leave the transporter
|
||||
// FIXME: show still animations ?
|
||||
if (LeaveTransporter(unit)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** The transporter unloads a unit.
|
||||
**
|
||||
|
@ -325,52 +410,12 @@ static void LeaveTransporter(CUnit &transporter)
|
|||
*/
|
||||
void HandleActionUnload(COrder& order, CUnit &unit)
|
||||
{
|
||||
const int maxSearchRange = 20;
|
||||
Assert(order.Action == UnitActionUnload);
|
||||
|
||||
if (!unit.CanMove()) {
|
||||
unit.SubAction = 2;
|
||||
}
|
||||
switch (unit.SubAction) {
|
||||
case 0: // Choose destination
|
||||
if (!order.HasGoal()) {
|
||||
Vec2i pos;
|
||||
|
||||
if (!ClosestFreeDropZone(unit, order.goalPos, maxSearchRange, &pos)) {
|
||||
// Sorry... I give up.
|
||||
unit.ClearAction();
|
||||
return;
|
||||
}
|
||||
order.goalPos = pos;
|
||||
}
|
||||
|
||||
unit.CurrentOrder()->NewResetPath();
|
||||
unit.SubAction = 1;
|
||||
// follow on next case
|
||||
case 1: // Move unit to destination
|
||||
// The Goal is the unit that we have to unload.
|
||||
if (!unit.CurrentOrder()->HasGoal()) {
|
||||
const int moveResult = MoveToDropZone(unit);
|
||||
|
||||
// We have to unload everything
|
||||
if (moveResult) {
|
||||
if (moveResult == PF_REACHED) {
|
||||
if (++unit.SubAction == 1) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
} else {
|
||||
unit.SubAction = 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // Leave the transporter
|
||||
// FIXME: show still animations ?
|
||||
LeaveTransporter(unit);
|
||||
if (unit.CanMove() && unit.CurrentAction() != UnitActionStill) {
|
||||
HandleActionUnload(*unit.CurrentOrder() , unit);
|
||||
}
|
||||
break;
|
||||
if (order.Execute(unit)) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//@}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "player.h"
|
||||
#include "unit.h"
|
||||
#include "missile.h"
|
||||
#include "interface.h"
|
||||
#include "map.h"
|
||||
#include "sound.h"
|
||||
#include "spells.h"
|
||||
|
@ -133,7 +132,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures
|
|||
|
||||
/* static */ COrder* COrder::NewActionBoard(CUnit &unit)
|
||||
{
|
||||
COrder *order = new COrder(UnitActionBoard);
|
||||
COrder_Board *order = new COrder_Board;
|
||||
|
||||
order->SetGoal(&unit);
|
||||
order->Range = 1;
|
||||
|
@ -234,7 +233,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures
|
|||
|
||||
/* static */ COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target)
|
||||
{
|
||||
COrder *order = new COrder(UnitActionRepair);
|
||||
COrder_Repair *order = new COrder_Repair();
|
||||
|
||||
if (target.Destroyed) {
|
||||
order->goalPos = target.tilePos + target.Type->GetHalfTileSize();
|
||||
|
@ -249,14 +248,13 @@ unsigned SyncHash; /// Hash calculated to find sync failures
|
|||
{
|
||||
Assert(Map.Info.IsPointOnMap(pos));
|
||||
|
||||
COrder *order = new COrder(UnitActionRepair);
|
||||
COrder_Repair *order = new COrder_Repair;
|
||||
|
||||
order->goalPos = pos;
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* static */ COrder* COrder::NewActionResearch(CUnit &unit, CUpgrade &upgrade)
|
||||
{
|
||||
COrder_Research *order = new COrder_Research();
|
||||
|
@ -350,17 +348,14 @@ unsigned SyncHash; /// Hash calculated to find sync failures
|
|||
|
||||
/* static */ COrder* COrder::NewActionStandGround()
|
||||
{
|
||||
return new COrder_StandGround;
|
||||
return new COrder_Still(true);
|
||||
}
|
||||
|
||||
/* static */ COrder* COrder::NewActionStill()
|
||||
{
|
||||
return new COrder_Still;
|
||||
return new COrder_Still(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* static */ COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type)
|
||||
{
|
||||
COrder_Train *order = new COrder_Train;
|
||||
|
@ -383,7 +378,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures
|
|||
|
||||
/* static */ COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what)
|
||||
{
|
||||
COrder *order = new COrder(UnitActionUnload);
|
||||
COrder *order = new COrder_Unload;
|
||||
|
||||
order->goalPos = pos;
|
||||
if (what && !what->Destroyed) {
|
||||
|
@ -452,7 +447,7 @@ void COrder::ReleaseRefs(CUnit &unit)
|
|||
if (this->HasGoal()) {
|
||||
// If mining decrease the active count on the resource.
|
||||
if (this->Action == UnitActionResource) {
|
||||
if (unit.SubAction == 60 /* SUB_GATHER_RESOURCE */ ) {
|
||||
if (this->SubAction.Res == 60 /* SUB_GATHER_RESOURCE */ ) {
|
||||
CUnit *goal = this->GetGoal();
|
||||
|
||||
goal->Resource.Active--;
|
||||
|
@ -460,7 +455,7 @@ void COrder::ReleaseRefs(CUnit &unit)
|
|||
}
|
||||
}
|
||||
// Still shouldn't have a reference unless attacking
|
||||
Assert(!(this->Action == UnitActionStill && !unit.SubAction));
|
||||
Assert(!(this->Action == UnitActionStill && !SubAction.Attack));
|
||||
this->ClearGoal();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
|
@ -525,11 +520,11 @@ bool COrder::OnAiHitUnit(CUnit &unit, CUnit *attacker, int /*damage*/)
|
|||
// Maybe AI should cancel action and save resources ???
|
||||
return true;
|
||||
case UnitActionResource:
|
||||
if (unit.SubAction >= 65) {
|
||||
if (SubAction.Res >= 65) {
|
||||
//Normal return to depot
|
||||
return true;
|
||||
}
|
||||
if (unit.SubAction > 55 &&
|
||||
if (SubAction.Res > 55 &&
|
||||
unit.ResourcesHeld > 0) {
|
||||
//escape to Depot with this what you have;
|
||||
Data.ResWorker.DoneHarvesting = 1;
|
||||
|
@ -1564,10 +1559,7 @@ static void HandleUnitAction(CUnit &unit)
|
|||
delete unit.Orders[0];
|
||||
unit.Orders.erase(unit.Orders.begin());
|
||||
|
||||
//
|
||||
// Note subaction 0 should reset.
|
||||
//
|
||||
unit.SubAction = unit.State = 0;
|
||||
unit.State = 0;
|
||||
unit.Wait = 0;
|
||||
|
||||
if (IsOnlySelected(unit)) { // update display for new action
|
||||
|
@ -1721,7 +1713,7 @@ void UnitActions()
|
|||
SyncHash = (SyncHash << 5) | (SyncHash >> 27);
|
||||
SyncHash ^= unit.Orders.size() > 0 ? unit.CurrentAction() << 18 : 0;
|
||||
SyncHash ^= unit.State << 12;
|
||||
SyncHash ^= unit.SubAction << 6;
|
||||
// SyncHash ^= unit.SubAction << 6;
|
||||
SyncHash ^= unit.Refs << 3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "upgrade.h"
|
||||
#include "pathfinder.h"
|
||||
#include "spells.h"
|
||||
#include "interface.h"
|
||||
#include "ui.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -107,9 +106,6 @@ static void RemoveOrder(CUnit &unit, unsigned int order)
|
|||
|
||||
delete unit.Orders[order];
|
||||
unit.Orders.erase(unit.Orders.begin() + order);
|
||||
if (order == 0) {
|
||||
unit.SubAction = 0;
|
||||
}
|
||||
if (unit.Orders.empty()) {
|
||||
unit.Orders.push_back(COrder::NewActionStill());
|
||||
}
|
||||
|
|
|
@ -238,10 +238,15 @@ static int AiBuildBuilding(const CUnitType &type, CUnitType &building, int near_
|
|||
int action = unit.Orders[j]->Action;
|
||||
if (action == UnitActionBuild ||
|
||||
action == UnitActionRepair ||
|
||||
action == UnitActionReturnGoods ||
|
||||
(action == UnitActionResource &&
|
||||
unit.SubAction > 55) /* SUB_START_GATHERING */) {
|
||||
break;
|
||||
action == UnitActionReturnGoods) {
|
||||
break;
|
||||
}
|
||||
if (action == UnitActionResource) {
|
||||
const COrder &order = *unit.Orders[j];
|
||||
|
||||
if (order.SubAction.Res > 55 /* SUB_START_GATHERING */) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j == unit.Orders.size()) {
|
||||
|
@ -1093,7 +1098,9 @@ static void AiCollectResources()
|
|||
for (int k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) {
|
||||
unit = units_assigned[src_c][k];
|
||||
|
||||
if (unit->SubAction >= 65 /* SUB_STOP_GATHERING */ ) {
|
||||
COrder &order = *unit->CurrentOrder();
|
||||
|
||||
if (order.SubAction.Res >= 65 /* SUB_STOP_GATHERING */ ) {
|
||||
//worker returning with resource
|
||||
continue;
|
||||
}
|
||||
|
@ -1162,10 +1169,16 @@ static int AiRepairBuilding(const CUnitType &type, CUnit &building)
|
|||
for (int i = 0; i < nunits; ++i) {
|
||||
CUnit &unit = *table[i];
|
||||
|
||||
if (unit.Type->RepairRange && unit.Orders.size() == 1 &&
|
||||
((unit.CurrentAction() == UnitActionResource && unit.SubAction <= 55) /* SUB_START_GATHERING */ ||
|
||||
unit.CurrentAction() == UnitActionStill)) {
|
||||
table[num++] = &unit;
|
||||
if (unit.Type->RepairRange && unit.Orders.size() == 1) {
|
||||
if (unit.CurrentAction() == UnitActionStill) {
|
||||
table[num++] = &unit;
|
||||
} else if (unit.CurrentAction() == UnitActionResource) {
|
||||
COrder &order = *unit.CurrentOrder();
|
||||
|
||||
if (order.SubAction.Res <= 55 /* SUB_START_GATHERING */) {
|
||||
table[num++] = &unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ public:
|
|||
goalPos.x = -1;
|
||||
goalPos.y = -1;
|
||||
memset(&Arg1, 0, sizeof (Arg1));
|
||||
memset(&SubAction, 0, sizeof (SubAction));
|
||||
memset(&Data, 0, sizeof (Data));
|
||||
}
|
||||
virtual ~COrder();
|
||||
|
@ -170,10 +171,8 @@ public:
|
|||
#if 1 // currently needed for parsing
|
||||
static COrder* NewActionAttack() { return new COrder(UnitActionAttack); }
|
||||
static COrder* NewActionAttackGround() { return new COrder(UnitActionAttackGround); }
|
||||
static COrder* NewActionBoard() { return new COrder(UnitActionBoard); }
|
||||
static COrder* NewActionFollow() { return new COrder(UnitActionFollow); }
|
||||
static COrder* NewActionMove() { return new COrder(UnitActionMove); }
|
||||
static COrder* NewActionRepair() { return new COrder(UnitActionRepair); }
|
||||
static COrder* NewActionResource() { return new COrder(UnitActionResource); }
|
||||
static COrder* NewActionReturnGoods() { return new COrder(UnitActionReturnGoods); }
|
||||
static COrder* NewActionUnload() { return new COrder(UnitActionUnload); }
|
||||
|
@ -199,6 +198,13 @@ public:
|
|||
} Resource;
|
||||
} Arg1; /// Extra command argument.
|
||||
|
||||
union {
|
||||
int Attack;
|
||||
int Follow;
|
||||
int Res;
|
||||
} SubAction;
|
||||
|
||||
|
||||
union _order_data_ {
|
||||
struct _order_move_ {
|
||||
unsigned short int Cycles; /// how much Cycles we move.
|
||||
|
@ -211,17 +217,34 @@ public:
|
|||
int TimeToHarvest; /// how much time until we harvest some more.
|
||||
unsigned DoneHarvesting:1; /// Harvesting done, wait for action to break.
|
||||
} ResWorker; /// Worker harvesting
|
||||
struct _order_repair_ {
|
||||
int Cycles; /// Cycles unit has been repairing for
|
||||
} Repair; /// Repairing unit
|
||||
} Data; /// Storage room for different commands
|
||||
};
|
||||
|
||||
class COrder_Board : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionBoard(CUnit &unit);
|
||||
public:
|
||||
COrder_Board() : COrder(UnitActionBoard), State(0) {}
|
||||
|
||||
virtual COrder_Board *Clone() const { return new COrder_Board(*this); }
|
||||
|
||||
virtual void Save(CFile &file, const CUnit &unit) const;
|
||||
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
|
||||
|
||||
virtual bool Execute(CUnit &unit);
|
||||
|
||||
private:
|
||||
bool WaitForTransporter(CUnit &unit);
|
||||
|
||||
private:
|
||||
int State;
|
||||
};
|
||||
|
||||
class COrder_Build : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionBuild(const CUnit &builder, const Vec2i &pos, CUnitType &building);
|
||||
public:
|
||||
COrder_Build() : COrder(UnitActionBuild), Type(NULL) {}
|
||||
COrder_Build() : COrder(UnitActionBuild), Type(NULL), State(0) {}
|
||||
|
||||
virtual COrder_Build *Clone() const { return new COrder_Build(*this); }
|
||||
|
||||
|
@ -235,11 +258,14 @@ public:
|
|||
const CUnitType& GetUnitType() const { return *Type; }
|
||||
|
||||
private:
|
||||
bool MoveToLocation(CUnit &unit);
|
||||
CUnit *CheckCanBuild(CUnit &unit);
|
||||
bool StartBuilding(CUnit &unit, CUnit &ontop);
|
||||
bool BuildFromOutside(CUnit &unit) const;
|
||||
private:
|
||||
CUnitType *Type; /// build a unit of this unit-type
|
||||
CUnitPtr BuildingUnit; /// unit builded.
|
||||
int State;
|
||||
};
|
||||
|
||||
|
||||
|
@ -298,7 +324,7 @@ class COrder_Patrol : public COrder
|
|||
{
|
||||
friend COrder* COrder::NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest);
|
||||
public:
|
||||
COrder_Patrol() : COrder(UnitActionPatrol) {}
|
||||
COrder_Patrol() : COrder(UnitActionPatrol), WaitingCycle(0) {}
|
||||
|
||||
virtual COrder_Patrol *Clone() const { return new COrder_Patrol(*this); }
|
||||
|
||||
|
@ -310,8 +336,30 @@ public:
|
|||
const Vec2i& GetWayPoint() const { return WayPoint; }
|
||||
private:
|
||||
Vec2i WayPoint; /// position for patroling.
|
||||
unsigned int WaitingCycle; /// number of cycle pathfinder wait.
|
||||
};
|
||||
|
||||
class COrder_Repair : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionRepair(CUnit &unit, CUnit &target);
|
||||
friend COrder* COrder::NewActionRepair(const Vec2i &pos);
|
||||
public:
|
||||
COrder_Repair() : COrder(UnitActionRepair), State(0), RepairCycle(0) {}
|
||||
|
||||
virtual COrder_Repair *Clone() const { return new COrder_Repair(*this); }
|
||||
|
||||
virtual void Save(CFile &file, const CUnit &unit) const;
|
||||
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
|
||||
|
||||
virtual bool Execute(CUnit &unit);
|
||||
private:
|
||||
bool RepairUnit(const CUnit &unit, CUnit &goal);
|
||||
private:
|
||||
unsigned int State;
|
||||
unsigned int RepairCycle;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class COrder_Research : public COrder
|
||||
{
|
||||
|
@ -337,7 +385,7 @@ private:
|
|||
class COrder_SpellCast : public COrder
|
||||
{
|
||||
public:
|
||||
COrder_SpellCast() : COrder(UnitActionSpellCast), Spell(NULL) {}
|
||||
COrder_SpellCast() : COrder(UnitActionSpellCast), Spell(NULL), State(0) {}
|
||||
|
||||
virtual COrder_SpellCast *Clone() const { return new COrder_SpellCast(*this); }
|
||||
|
||||
|
@ -350,30 +398,17 @@ public:
|
|||
|
||||
const SpellType& GetSpell() const { return *Spell; }
|
||||
void SetSpell(SpellType &spell) { Spell = &spell; }
|
||||
private:
|
||||
bool SpellMoveToTarget(CUnit &unit);
|
||||
private:
|
||||
SpellType *Spell;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class COrder_StandGround : public COrder
|
||||
{
|
||||
public:
|
||||
COrder_StandGround() : COrder(UnitActionStandGround) {}
|
||||
|
||||
virtual COrder_StandGround *Clone() const { return new COrder_StandGround(*this); }
|
||||
|
||||
virtual void Save(CFile &file, const CUnit &unit) const;
|
||||
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
|
||||
|
||||
virtual bool Execute(CUnit &unit);
|
||||
int State;
|
||||
};
|
||||
|
||||
class COrder_Still : public COrder
|
||||
{
|
||||
public:
|
||||
COrder_Still() : COrder(UnitActionStill) {}
|
||||
COrder_Still(bool stand) : COrder(stand ? UnitActionStandGround : UnitActionStill), State(0) {}
|
||||
|
||||
virtual COrder_Still *Clone() const { return new COrder_Still(*this); }
|
||||
|
||||
|
@ -381,12 +416,13 @@ public:
|
|||
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
|
||||
|
||||
virtual bool Execute(CUnit &unit);
|
||||
private:
|
||||
bool AutoAttackStand(CUnit &unit);
|
||||
private:
|
||||
int State;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class COrder_Train : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionTrain(CUnit &trainer, CUnitType &type);
|
||||
|
@ -429,6 +465,27 @@ private:
|
|||
};
|
||||
|
||||
|
||||
|
||||
class COrder_Unload : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionUnload(const Vec2i &pos, CUnit *what);
|
||||
public:
|
||||
COrder_Unload() : COrder(UnitActionUnload), State(0) {}
|
||||
|
||||
virtual COrder_Unload *Clone() const { return new COrder_Unload(*this); }
|
||||
|
||||
virtual void Save(CFile &file, const CUnit &unit) const;
|
||||
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
|
||||
|
||||
virtual bool Execute(CUnit &unit);
|
||||
|
||||
private:
|
||||
bool LeaveTransporter(CUnit &transporter);
|
||||
private:
|
||||
int State;
|
||||
};
|
||||
|
||||
|
||||
class COrder_UpgradeTo : public COrder
|
||||
{
|
||||
friend COrder* COrder::NewActionUpgradeTo(CUnit &unit, CUnitType &type);
|
||||
|
@ -451,7 +508,6 @@ private:
|
|||
int Ticks; /// Ticks to complete
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
----------------------------------------------------------------------------*/
|
||||
|
@ -535,7 +591,7 @@ extern void CommandSharedVision(int player, bool state, int opponent);
|
|||
extern void DropResource(CUnit &unit);
|
||||
extern void ResourceGiveUp(CUnit &unit);
|
||||
extern int GetNumWaitingWorkers(const CUnit &mine);
|
||||
extern bool AutoAttack(CUnit &unit, bool stand_ground);
|
||||
extern bool AutoAttack(CUnit &unit);
|
||||
extern bool AutoRepair(CUnit &unit);
|
||||
extern bool AutoCast(CUnit &unit);
|
||||
|
||||
|
@ -543,8 +599,6 @@ extern void UnHideUnit(CUnit &unit);
|
|||
|
||||
typedef void HandleActionFunc(COrder& order, CUnit &unit);
|
||||
|
||||
/// Generic still action
|
||||
extern void ActionStillGeneric(CUnit &unit, bool stand_ground);
|
||||
/// Handle command still
|
||||
extern HandleActionFunc HandleActionStill;
|
||||
/// Handle command stand ground
|
||||
|
|
|
@ -269,12 +269,6 @@
|
|||
** in a harvester.
|
||||
** @todo continue documentation
|
||||
**
|
||||
** CUnit::SubAction
|
||||
**
|
||||
** This is an action private variable, it is zero on the first
|
||||
** entry of an action. Must be set to zero, if an action finishes.
|
||||
** It should only be used inside of actions.
|
||||
**
|
||||
** CUnit::Wait
|
||||
**
|
||||
** The unit is forced too wait for that many cycles. Be carefull,
|
||||
|
@ -514,7 +508,6 @@ public:
|
|||
|
||||
unsigned char DamagedType; /// Index of damage type of unit which damaged this unit
|
||||
unsigned long Attacked; /// gamecycle unit was last attacked
|
||||
unsigned SubAction : 8; /// sub-action of unit
|
||||
unsigned State : 8; /// action state
|
||||
unsigned Blink : 3; /// Let selection rectangle blink
|
||||
unsigned Moving : 1; /// The unit is moving
|
||||
|
|
|
@ -252,7 +252,14 @@ bool COrder::ParseMoveData(lua_State *l, int &j, const char *value)
|
|||
|
||||
bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
|
||||
{
|
||||
if (!strcmp(value, "current-resource")) {
|
||||
if (this->ParseMoveData(l, j, value)) {
|
||||
return true;
|
||||
} else if (!strcmp(value, "subaction")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->SubAction.Attack = this->SubAction.Follow = this->SubAction.Res = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "current-resource")) {
|
||||
++j;
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
this->CurrentResource = CclGetResourceByName(l);
|
||||
|
@ -324,9 +331,9 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
|
|||
lua_pop(l, 1);
|
||||
|
||||
if (!strcmp(actiontype, "action-still")) {
|
||||
*orderPtr = new COrder_Still;
|
||||
*orderPtr = new COrder_Still(false);
|
||||
} else if (!strcmp(actiontype, "action-stand-ground")) {
|
||||
*orderPtr = new COrder_StandGround;
|
||||
*orderPtr = new COrder_Still(true);
|
||||
} else if (!strcmp(actiontype, "action-follow")) {
|
||||
*orderPtr = COrder::NewActionFollow();
|
||||
} else if (!strcmp(actiontype, "action-move")) {
|
||||
|
@ -348,7 +355,7 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
|
|||
} else if (!strcmp(actiontype, "action-built")) {
|
||||
*orderPtr = new COrder_Built;
|
||||
} else if (!strcmp(actiontype, "action-board")) {
|
||||
*orderPtr = COrder::NewActionBoard();
|
||||
*orderPtr = new COrder_Board;
|
||||
} else if (!strcmp(actiontype, "action-unload")) {
|
||||
*orderPtr = COrder::NewActionUnload();
|
||||
} else if (!strcmp(actiontype, "action-patrol")) {
|
||||
|
@ -356,13 +363,13 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
|
|||
} else if (!strcmp(actiontype, "action-build")) {
|
||||
*orderPtr = new COrder_Build;
|
||||
} else if (!strcmp(actiontype, "action-repair")) {
|
||||
*orderPtr = COrder::NewActionRepair();
|
||||
*orderPtr = new COrder_Repair;
|
||||
} else if (!strcmp(actiontype, "action-resource")) {
|
||||
*orderPtr = COrder::NewActionResource();
|
||||
} else if (!strcmp(actiontype, "action-return-goods")) {
|
||||
*orderPtr = COrder::NewActionReturnGoods();
|
||||
} else if (!strcmp(actiontype, "action-transform-into")) {
|
||||
*orderPtr = new COrder_TransformInto();
|
||||
*orderPtr = new COrder_TransformInto;
|
||||
} else {
|
||||
LuaError(l, "ParseOrder: Unsupported type: %s" _C_ actiontype);
|
||||
}
|
||||
|
@ -591,8 +598,6 @@ static int CclUnit(lua_State *l)
|
|||
lua_pushvalue(l, j + 1);
|
||||
unit->CurrentResource = CclGetResourceByName(l);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "sub-action")) {
|
||||
unit->SubAction = LuaToNumber(l, j + 1);
|
||||
} else if (!strcmp(value, "wait")) {
|
||||
unit->Wait = LuaToNumber(l, j + 1);
|
||||
} else if (!strcmp(value, "state")) {
|
||||
|
|
|
@ -170,7 +170,6 @@ void CUnit::Init()
|
|||
GroupId = 0;
|
||||
LastGroup = 0;
|
||||
ResourcesHeld = 0;
|
||||
SubAction = 0;
|
||||
Wait = 0;
|
||||
State = 0;
|
||||
Blink = 0;
|
||||
|
@ -268,7 +267,6 @@ void CUnit::ClearAction()
|
|||
delete CurrentOrder();
|
||||
Orders[0] = COrder::NewActionStill();
|
||||
|
||||
SubAction = 0;
|
||||
if (Selected) {
|
||||
SelectedUnitChanged();
|
||||
}
|
||||
|
@ -372,7 +370,6 @@ bool CUnit::RestoreOrder()
|
|||
|
||||
// Restart order state.
|
||||
this->State = 0;
|
||||
this->SubAction = 0;
|
||||
|
||||
// Cannot delete this->Orders[0] since it is generally that order
|
||||
// which call this method.
|
||||
|
@ -1064,7 +1061,7 @@ void UnitClearOrders(CUnit &unit)
|
|||
}
|
||||
unit.Orders.clear();
|
||||
unit.Orders.push_back(COrder::NewActionStill());
|
||||
unit.SubAction = unit.State = 0;
|
||||
unit.State = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2136,7 +2133,6 @@ void DropOutAll(const CUnit &source)
|
|||
DropOutOnSide(*unit, LookingW, &source);
|
||||
Assert(!unit->CurrentOrder()->HasGoal());
|
||||
unit->CurrentOrder()->Action = UnitActionStill;
|
||||
unit->SubAction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2821,7 +2817,6 @@ void LetUnitDie(CUnit &unit)
|
|||
// Unit has death animation.
|
||||
|
||||
// Not good: UnitUpdateHeading(unit);
|
||||
unit.SubAction = 0;
|
||||
unit.State = 0;
|
||||
delete unit.Orders[0];
|
||||
unit.Orders[0] = COrder::NewActionDie();
|
||||
|
|
|
@ -757,7 +757,8 @@ static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder
|
|||
pos2 = CurrentViewport->TilePosToScreen_Center(order.goalPos);
|
||||
// FALL THROUGH
|
||||
case UnitActionAttack:
|
||||
if (unit.SubAction & 2) { // Show weak targets.
|
||||
{
|
||||
if (order.SubAction.Attack & 2) { // Show weak targets.
|
||||
e_color = ColorBlue;
|
||||
} else {
|
||||
e_color = ColorRed;
|
||||
|
@ -765,7 +766,7 @@ static void ShowSingleOrder(const CUnit &unit, const PixelPos &pos, const COrder
|
|||
color = ColorRed;
|
||||
dest = true;
|
||||
break;
|
||||
|
||||
}
|
||||
case UnitActionBoard:
|
||||
e_color = color = ColorGreen;
|
||||
dest = true;
|
||||
|
|
|
@ -108,15 +108,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
|
|||
case UnitActionAttackGround:
|
||||
file.printf("\"action-attack-ground\",");
|
||||
break;
|
||||
case UnitActionBoard:
|
||||
file.printf("\"action-board\",");
|
||||
break;
|
||||
case UnitActionUnload:
|
||||
file.printf("\"action-unload\",");
|
||||
break;
|
||||
case UnitActionRepair:
|
||||
file.printf("\"action-repair\",");
|
||||
break;
|
||||
case UnitActionResource:
|
||||
file.printf("\"action-resource\",");
|
||||
break;
|
||||
|
@ -142,6 +133,21 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
|
|||
}
|
||||
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;
|
||||
case UnitActionFollow:
|
||||
file.printf(", \"subaction\", %d", order.SubAction.Follow);
|
||||
break;
|
||||
case UnitActionResource:
|
||||
case UnitActionReturnGoods:
|
||||
file.printf(", \"subaction\", %d", order.SubAction.Res);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Extra arg.
|
||||
switch (order.Action) {
|
||||
case UnitActionResource :
|
||||
|
@ -330,17 +336,6 @@ void SaveUnit(const CUnit &unit, CFile *file)
|
|||
file->printf("\"current-resource\", \"%s\",\n ",
|
||||
DefaultResourceNames[unit.CurrentResource].c_str());
|
||||
}
|
||||
if (unit.SubAction && unit.IsAgressive() &&
|
||||
(unit.CurrentAction() == UnitActionStill ||
|
||||
unit.CurrentAction() == UnitActionStandGround))
|
||||
{
|
||||
//Force recalculate Guard points
|
||||
//if unit atack from StandGround then attac target is recalculate
|
||||
//When unit first time handle action code.
|
||||
file->printf("\"sub-action\", 0, ");
|
||||
} else {
|
||||
file->printf("\"sub-action\", %d, ", unit.SubAction);
|
||||
}
|
||||
file->printf("\"wait\", %d, ", unit.Wait);
|
||||
file->printf("\"state\", %d,", unit.State);
|
||||
file->printf("\"anim-wait\", %d,", unit.Anim.Wait);
|
||||
|
|
Loading…
Add table
Reference in a new issue