COrder_{Move, Follow}

Fix typo with Unload.
This commit is contained in:
joris 2012-02-23 16:12:12 +01:00
parent 1ef5a6d8bc
commit 77334d3533
7 changed files with 182 additions and 142 deletions

View file

@ -41,46 +41,72 @@
#include "unit.h"
#include "unittype.h"
#include "pathfinder.h"
#include "map.h"
#include "actions.h"
#include "iolib.h"
#include "script.h"
/*----------------------------------------------------------------------------
-- Variables
-- Functions
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
-- Function
----------------------------------------------------------------------------*/
/**
** Unit follow action:
**
** @param unit Pointer to unit.
*/
void HandleActionFollow(COrder& order, CUnit &unit)
/* virtual */ void COrder_Follow::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-follow\",");
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(" \"state\", %d,", this->State);
SaveDataMove(file);
file.printf("}");
}
/* virtual */ bool COrder_Follow::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (ParseMoveData(l, j, value)) {
return true;
} else if (!strcmp(value, "state")) {
++j;
lua_rawgeti(l, -1, j + 1);
this->State = LuaToNumber(l, -1);
lua_pop(l, 1);
} else {
return false;
}
return true;
}
/* virtual */ bool COrder_Follow::Execute(CUnit &unit)
{
if (unit.Wait) {
unit.Wait--;
return;
return false;
}
CUnit *goal = order.GetGoal();
CUnit *goal = this->GetGoal();
// Reached target
if (order.SubAction.Follow == 128) {
if (this->State == 128) {
if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("Goal gone\n");
order.ClearGoal();
unit.ClearAction();
return;
return true;
}
if (goal->tilePos == order.goalPos) {
if (goal->tilePos == this->goalPos) {
// Move to the next order
if (unit.Orders.size() > 1) {
order.ClearGoal();
unit.ClearAction();
return;
return true;
}
// Reset frame to still frame while we wait
@ -88,32 +114,30 @@ void HandleActionFollow(COrder& order, CUnit &unit)
unit.Frame = unit.Type->StillFrame;
UnitUpdateHeading(unit);
unit.Wait = 10;
if (order.Range > 1) {
order.Range = 1;
order.SubAction.Follow = 0;
if (this->Range > 1) {
this->Range = 1;
this->State = 0;
}
return;
return false;
}
order.SubAction.Follow = 0;
this->State = 0;
}
if (!order.SubAction.Follow) { // first entry
order.SubAction .Follow= 1;
order.NewResetPath();
Assert(unit.State == 0);
if (!this->State) { // first entry
this->State = 1;
this->NewResetPath();
}
switch (DoActionMove(unit)) { // reached end-point?
case PF_UNREACHABLE:
// Some tries to reach the goal
if (order.CheckRange()) {
order.Range++;
if (this->CheckRange()) {
this->Range++;
break;
}
// FALL THROUGH
case PF_REACHED:
{
if (!goal) { // goal has died
unit.ClearAction();
return;
return true;
}
// Handle Teleporter Units
// FIXME: BAD HACK
@ -132,8 +156,6 @@ void HandleActionFollow(COrder& order, CUnit &unit)
unit.tilePos.x * PixelTileSize.x + PixelTileSize.x / 2,
unit.tilePos.y * PixelTileSize.y + PixelTileSize.y / 2);
#endif
unit.ClearAction();
// FIXME: we must check if the units supports the new order.
CUnit &dest = *goal->Goal;
@ -141,26 +163,24 @@ void HandleActionFollow(COrder& order, CUnit &unit)
|| (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();
return true;
} 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;
delete dest.NewOrder;
dest.NewOrder = NULL;
return true;
}
}
delete unit.CurrentOrder();
unit.Orders[0] = dest.NewOrder->Clone();
unit.CurrentResource = dest.CurrentResource;
return false;
}
return;
}
order.goalPos = goal->tilePos;
order.SubAction.Follow = 128;
this->goalPos = goal->tilePos;
this->State = 128;
}
// FALL THROUGH
default:
@ -170,36 +190,43 @@ void HandleActionFollow(COrder& order, CUnit &unit)
// Target destroyed?
if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
DebugPrint("Goal gone\n");
order.goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
order.ClearGoal();
this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
this->ClearGoal();
goal = NoUnitP;
order.NewResetPath();
this->NewResetPath();
}
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)) {
goal = AttackUnitsInReactRange(unit);
if (goal) {
// Save current command to come back.
COrder *savedOrder = order.Clone();
if (unit.Anim.Unbreakable) {
return false;
}
// 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)) {
CUnit *target = AttackUnitsInReactRange(unit);
if (target) {
// Save current command to come back.
COrder *savedOrder = this->Clone();
CommandAttack(unit, goal->tilePos, NULL, FlushCommands);
CommandAttack(unit, target->tilePos, NULL, FlushCommands);
if (unit.StoreOrder(savedOrder) == false) {
delete savedOrder;
savedOrder = NULL;
}
// This stops the follow command and the attack is executed
unit.CurrentOrder()->ClearGoal();
unit.ClearAction();
if (unit.StoreOrder(savedOrder) == false) {
delete savedOrder;
savedOrder = NULL;
}
return true;
}
}
return false;
}
void HandleActionFollow(COrder& order, CUnit &unit)
{
if (order.Execute(unit)) {
unit.ClearAction();
}
}
//@}

View file

@ -37,27 +37,43 @@
#include <stdlib.h>
#include "stratagus.h"
#include "video.h"
#include "actions.h"
#include "unittype.h"
#include "animation.h"
#include "player.h"
#include "unit.h"
#include "tileset.h"
#include "map.h"
#include "actions.h"
#include "pathfinder.h"
#include "sound.h"
#include "interface.h"
#include "map.h"
#include "ai.h"
#include "iolib.h"
#include "script.h"
/*----------------------------------------------------------------------------
-- Variables
-- Functions
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
-- Function
----------------------------------------------------------------------------*/
/* virtual */ void COrder_Move::Save(CFile &file, const CUnit &unit) const
{
file.printf("{\"action-move\",");
file.printf(" \"range\", %d,", this->Range);
file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
SaveDataMove(file);
file.printf("}");
}
/* virtual */ bool COrder_Move::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
{
if (ParseMoveData(l, j, value)) {
return true;
} else {
return false;
}
}
/**
** Unit moves! Generic function called from other actions.
@ -72,16 +88,17 @@ int DoActionMove(CUnit &unit)
Vec2i posd; // movement in tile.
int d;
Vec2i pos;
int move;
int off;
Assert(unit.CanMove());
if (!unit.Moving &&
(unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) {
COrder& order = *unit.CurrentOrder();
if (!unit.Moving && (unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) {
Assert(!unit.Anim.Unbreakable);
// FIXME: So units flying up and down are not affected.
unit.IX = unit.IY = 0;
unit.IX = 0;
unit.IY = 0;
UnmarkUnitFieldFlags(unit);
d = NextPathElement(unit, &posd.x, &posd.y);
@ -110,14 +127,14 @@ int DoActionMove(CUnit &unit)
break;
}
pos = unit.tilePos;
off = unit.Offset;
int off = unit.Offset;
//
// Transporter (un)docking?
//
// FIXME: This is an ugly hack
if (unit.Type->CanTransport() &&
((Map.WaterOnMap(off) && Map.CoastOnMap(pos + posd)) ||
(Map.CoastOnMap(off) && Map.WaterOnMap(pos + posd)))) {
if (unit.Type->CanTransport()
&& ((Map.WaterOnMap(off) && Map.CoastOnMap(pos + posd))
|| (Map.CoastOnMap(off) && Map.WaterOnMap(pos + posd)))) {
PlayUnitSound(unit, VoiceDocking);
}
@ -142,12 +159,11 @@ int DoActionMove(CUnit &unit)
} else {
posd.x = Heading2X[unit.Direction / NextDirection];
posd.y = Heading2Y[unit.Direction / NextDirection];
d = unit.CurrentOrder()->Data.Move.Length + 1;
d = order.Data.Move.Length + 1;
}
unit.CurrentOrder()->Data.Move.Cycles++;//reset have to be manualy controled by caller.
move = UnitShowAnimationScaled(unit, unit.Type->Animations->Move,
Map.Field(unit.Offset)->Cost);
order.Data.Move.Cycles++;//reset have to be manualy controled by caller.
int move = UnitShowAnimationScaled(unit, unit.Type->Animations->Move, Map.Field(unit.Offset)->Cost);
unit.IX += posd.x * move;
unit.IY += posd.y * move;
@ -161,58 +177,37 @@ int DoActionMove(CUnit &unit)
return d;
}
/**
** Unit move action:
**
** Move to a place or to a unit (can move).
** Tries 10x to reach the target, note this are the complete tries.
** If the target entered another unit, move to it's position.
** If the target unit is destroyed, continue to move to it's last position.
**
** @param unit Pointer to unit.
*/
void HandleActionMove(COrder& order, CUnit &unit)
{
CUnit *goal;
/* virtual */ bool COrder_Move::Execute(CUnit &unit)
{
Assert(unit.CanMove());
if (unit.Wait) {
unit.Wait--;
return;
return false;
}
// FIXME: (mr-russ) Make a reachable goal here with GoalReachable ...
switch (DoActionMove(unit)) { // reached end-point?
case PF_UNREACHABLE:
//
// Some tries to reach the goal
//
if (order.CheckRange()) {
order.Range++;
if (this->CheckRange()) {
this->Range++;
break;
}
// FALL THROUGH
case PF_REACHED:
// Release target, if any.
order.ClearGoal();
unit.ClearAction();
return;
return true;
default:
break;
}
return false;
}
//
// Target destroyed?
//
goal = order.GetGoal();
if (goal && goal->Destroyed) {
DebugPrint("Goal dead\n");
order.goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
order.ClearGoal();
order.NewResetPath();
void HandleActionMove(COrder& order, CUnit &unit)
{
if (order.Execute(unit)) {
unit.ClearAction();
}
}

View file

@ -63,7 +63,7 @@
file.printf(" \"goal\", \"%s\",", UnitReference(goal).c_str());
}
file.printf(" \"tile\", {%d, %d}, ", this->goalPos.x, this->goalPos.y);
file.printf("\"state\", %d,\n ");
file.printf("\"state\", %d,\n ", this->State);
SaveDataMove(file);
file.printf("}");
}

View file

@ -192,7 +192,7 @@ unsigned SyncHash; /// Hash calculated to find sync failures
/* static */ COrder* COrder::NewActionFollow(CUnit &dest)
{
COrder *order = new COrder(UnitActionFollow);
COrder_Follow *order = new COrder_Follow;
// Destination could be killed.
// Should be handled in action, but is not possible!
@ -210,7 +210,9 @@ unsigned SyncHash; /// Hash calculated to find sync failures
/* static */ COrder* COrder::NewActionMove(const Vec2i &pos)
{
COrder *order = new COrder(UnitActionMove);
Assert(Map.Info.IsPointOnMap(pos));
COrder_Move *order = new COrder_Move;
order->goalPos = pos;

View file

@ -171,11 +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* NewActionFollow() { return new COrder(UnitActionFollow); }
static COrder* NewActionMove() { return new COrder(UnitActionMove); }
static COrder* NewActionResource() { return new COrder(UnitActionResource); }
static COrder* NewActionReturnGoods() { return new COrder(UnitActionReturnGoods); }
static COrder* NewActionUnload() { return new COrder(UnitActionUnload); }
#endif
private:
@ -200,7 +197,6 @@ public:
union {
int Attack;
int Follow;
int Res;
} SubAction;
@ -319,6 +315,35 @@ public:
virtual bool Execute(CUnit &unit);
};
class COrder_Follow : public COrder
{
public:
COrder_Follow() : COrder(UnitActionFollow), State(0) {}
virtual COrder_Follow *Clone() const { return new COrder_Follow(*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:
unsigned int State;
};
class COrder_Move : public COrder
{
public:
COrder_Move() : COrder(UnitActionMove) {}
virtual COrder_Move *Clone() const { return new COrder_Move(*this); }
virtual void Save(CFile &file, const CUnit &unit) const;
virtual bool ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit);
virtual bool Execute(CUnit &unit);
};
class COrder_Patrol : public COrder
{

View file

@ -257,7 +257,7 @@ bool COrder::ParseSpecificData(lua_State *l, int &j, const char *value, const CU
} else if (!strcmp(value, "subaction")) {
++j;
lua_rawgeti(l, -1, j + 1);
this->SubAction.Attack = this->SubAction.Follow = this->SubAction.Res = LuaToNumber(l, -1);
this->SubAction.Attack = this->SubAction.Res = LuaToNumber(l, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "current-resource")) {
++j;
@ -335,9 +335,9 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
} else if (!strcmp(actiontype, "action-stand-ground")) {
*orderPtr = new COrder_Still(true);
} else if (!strcmp(actiontype, "action-follow")) {
*orderPtr = COrder::NewActionFollow();
*orderPtr = new COrder_Follow;
} else if (!strcmp(actiontype, "action-move")) {
*orderPtr = COrder::NewActionMove();
*orderPtr = new COrder_Move;
} else if (!strcmp(actiontype, "action-attack")) {
*orderPtr = COrder::NewActionAttack();
} else if (!strcmp(actiontype, "action-attack-ground")) {
@ -357,7 +357,7 @@ void CclParseOrder(lua_State *l, const CUnit &unit, COrderPtr *orderPtr)
} else if (!strcmp(actiontype, "action-board")) {
*orderPtr = new COrder_Board;
} else if (!strcmp(actiontype, "action-unload")) {
*orderPtr = COrder::NewActionUnload();
*orderPtr = new COrder_Unload;
} else if (!strcmp(actiontype, "action-patrol")) {
*orderPtr = new COrder_Patrol;
} else if (!strcmp(actiontype, "action-build")) {

View file

@ -96,12 +96,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
case UnitActionNone:
file.printf("\"action-none\",");
break;
case UnitActionFollow:
file.printf("\"action-follow\",");
break;
case UnitActionMove:
file.printf("\"action-move\",");
break;
case UnitActionAttack:
file.printf("\"action-attack\",");
break;
@ -138,9 +132,6 @@ void SaveOrder(const COrder &order, const CUnit &unit, CFile *file)
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);