Units returns after attacking to its old goal.

This commit is contained in:
johns 2000-04-24 20:40:02 +00:00
parent 572668946e
commit 1b216ed611
5 changed files with 337 additions and 163 deletions

View file

@ -72,7 +72,7 @@ local void DoActionAttackGeneric(Unit* unit,const Animation* attack)
}
);
if( (flags&AnimationSound) ) {
if( (flags&AnimationSound) ) {
PlayUnitSound(unit,VoiceAttacking);
}
@ -96,6 +96,257 @@ global int AnimateActionAttack(Unit* unit)
return 0;
}
/**
** Handle moving to the target.
**
** @param unit Unit, for that the attack is handled.
*/
local void MoveToTarget(Unit* unit)
{
Unit* goal;
int wall;
int err;
err=HandleActionMove(unit);
// FIXME: Should handle new return codes here (for Fabrice)
if( unit->Reset ) {
//
// Target is dead, choose new one.
//
#ifdef NEW_UNIT
if( (goal=unit->Command.Data.Move.Goal) ) {
if( goal->Destroyed ) {
DebugLevel0(__FUNCTION__": destroyed unit\n");
if( !--goal->Refs ) {
ReleaseUnit(goal);
}
unit->Command.Data.Move.Goal=goal=NoUnitP;
} else if( !goal->HP || goal->Command.Action==UnitActionDie ) {
unit->Command.Data.Move.Goal=goal=NoUnitP;
}
}
#else
goal=unit->Command.Data.Move.Goal;
if( goal && (!goal->HP || goal->Command.Action==UnitActionDie) ) {
unit->Command.Data.Move.Goal=goal=NoUnitP;
}
#endif
//
// No goal: if meeting enemy attack it.
//
wall=0;
if( !goal && !(wall=WallOnMap(unit->Command.Data.Move.DX
,unit->Command.Data.Move.DY)) ) {
goal=AttackUnitsInReactRange(unit);
if( goal ) {
#ifdef NEW_UNIT
goal->Refs++;
#endif
if( unit->SavedCommand.Action==UnitActionStill ) {
// Save current command to come back.
unit->SavedCommand=unit->Command;
}
unit->Command.Data.Move.Goal=goal;
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
unit->SubAction|=2; // weak target
DebugLevel3(__FUNCTION__": %Zd in react range %Zd\n"
,UnitNumber(unit),UnitNumber(goal));
}
//
// Have a weak target, try a better target.
//
} else if( goal && (unit->SubAction&2) ) {
Unit* temp;
temp=AttackUnitsInReactRange(unit);
if( temp && temp->Type->Priority>goal->Type->Priority ) {
#ifdef NEW_UNIT
goal->Refs--;
temp->Refs++;
#endif
if( unit->SavedCommand.Action==UnitActionStill ) {
// Save current command to come back.
unit->SavedCommand=unit->Command;
}
unit->Command.Data.Move.Goal=goal=temp;
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
}
}
//
// Have reached target?
//
if( goal && MapDistanceToUnit(unit->X,unit->Y,goal)
<=unit->Stats->AttackRange ) {
unit->State=0;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit,goal->X-unit->X,goal->Y-unit->Y);
}
unit->SubAction++;
} else if( wall && MapDistance(unit->X,unit->Y
,unit->Command.Data.Move.DX,unit->Command.Data.Move.DY)
<=unit->Stats->AttackRange ) {
DebugLevel3("Attacking wall\n");
unit->State=0;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit,unit->Command.Data.Move.DX-unit->X
,unit->Command.Data.Move.DY-unit->Y);
}
unit->SubAction=1;
} else if( err ) {
unit->SubAction=0;
// Return to old task!
if( unit->Command.Action==UnitActionStill ) {
unit->Command=unit->SavedCommand;
// Must finish if saved command finishes
unit->SavedCommand.Action=UnitActionStill;
}
return;
}
DebugCheck( unit->Type->Vanishes || unit->Destroyed );
unit->Command.Action=UnitActionAttack;
}
}
/**
** Handle attacking the target.
**
** @param unit Unit, for that the attack is handled.
*/
local void AttackTarget(Unit* unit)
{
Unit* goal;
AnimateActionAttack(unit);
if( unit->Reset ) {
goal=unit->Command.Data.Move.Goal;
//
// Goal is "weak" or a wall.
//
if( !goal && WallOnMap(unit->Command.Data.Move.DX
,unit->Command.Data.Move.DY) ) {
DebugLevel3("attack a wall!!!!\n");
return;
}
//
// Target is dead, choose new one.
//
#ifdef NEW_UNIT
if( goal ) {
if( goal->Destroyed ) {
DebugLevel0(__FUNCTION__": destroyed unit\n");
if( !--goal->Refs ) {
ReleaseUnit(goal);
}
unit->Command.Data.Move.Goal=goal=NoUnitP;
} else if( !goal->HP || goal->Command.Action==UnitActionDie ) {
unit->Command.Data.Move.Goal=goal=NoUnitP;
}
}
//
// No target choose one.
//
if( !goal ) {
unit->State=0;
goal=AttackUnitsInReactRange(unit);
if( !goal ) {
unit->SubAction=0;
// Return to old task!
unit->Command=unit->SavedCommand;
// Must finish if saved command finishes
unit->SavedCommand.Action=UnitActionStill;
return;
}
if( unit->SavedCommand.Action==UnitActionStill ) {
// Save current command to come back.
unit->SavedCommand=unit->Command;
}
#ifdef NEW_UNIT
goal->Refs++;
#endif
DebugLevel3(__FUNCTION__": %Zd Unit in react range %Zd\n"
,UnitNumber(unit),UnitNumber(goal));
unit->Command.Data.Move.Goal=goal;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
unit->SubAction|=2;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit,goal->X-unit->X,goal->Y-unit->Y);
}
} else
#else
if( !goal || !goal->HP || goal->Command.Action==UnitActionDie ) {
unit->State=0;
goal=AttackUnitsInReactRange(unit);
unit->Command.Data.Move.Goal=goal;
if( !goal ) {
unit->SubAction=0;
unit->Command.Action=UnitActionStill; // cade?
return;
}
unit->SubAction|=2;
DebugLevel3("Unit in react range %Zd\n",UnitNumber(goal));
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit
,goal->X-unit->X,goal->Y-unit->Y);
}
} else
#endif
//
// Have a weak target, try a better target.
//
if( goal && (unit->SubAction&2) ) {
Unit* temp;
temp=AttackUnitsInReactRange(unit);
if( temp && temp->Type->Priority>goal->Type->Priority ) {
#ifdef NEW_UNIT
goal->Refs--;
temp->Refs++;
#endif
if( unit->SavedCommand.Action==UnitActionStill ) {
// Save current command to come back.
unit->SavedCommand=unit->Command;
}
unit->Command.Data.Move.Goal=goal=temp;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit,goal->X-unit->X,goal->Y-unit->Y);
}
}
}
//
// Still near to target, if not goto target.
//
if( MapDistanceToUnit(unit->X,unit->Y,goal)
>unit->Stats->AttackRange ) {
if( unit->SavedCommand.Action==UnitActionStill ) {
// Save current command to come back.
unit->SavedCommand=unit->Command;
}
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
unit->Frame=0;
unit->State=0;
unit->SubAction--;
}
}
}
/**
** Unit attacks!
**
@ -104,95 +355,17 @@ global int AnimateActionAttack(Unit* unit)
**
** @param unit Unit, for that the attack is handled.
*/
global int HandleActionAttack(Unit* unit)
global void HandleActionAttack(Unit* unit)
{
Unit* goal;
int wall;
int err;
DebugLevel3(__FUNCTION__": Attack %Zd\n",UnitNumber(unit));
switch( unit->SubAction ) {
//
// Move near to target.
// Move near to the target.
//
case 0:
case 2:
// FIXME: RESET FIRST!!
err=HandleActionMove(unit);
if( unit->Reset ) {
//
// Target is dead, choose new one.
//
goal=unit->Command.Data.Move.Goal;
if( goal && (!goal->HP
|| goal->Command.Action==UnitActionDie) ) {
unit->Command.Data.Move.Goal=goal=NoUnitP;
}
//
// No goal: if meeting enemy attack it.
//
wall=0;
if( !goal
&& !(wall=WallOnMap(unit->Command.Data.Move.DX
,unit->Command.Data.Move.DY)) ) {
goal=AttackUnitsInReactRange(unit);
if( goal ) {
unit->Command.Data.Move.Goal=goal;
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
unit->SubAction|=2;
DebugLevel3("Unit in react range %Zd\n",UnitNumber(goal));
}
} else
//
// Have a weak target, try a better target.
//
if( goal && (unit->SubAction&2) ) {
Unit* temp;
temp=AttackUnitsInReactRange(unit);
if( temp && temp->Type->Priority>goal->Type->Priority ) {
unit->Command.Data.Move.Goal=goal=temp;
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=temp->X;
unit->Command.Data.Move.DY=temp->Y;
}
}
//
// Have reached target?
//
if( goal && MapDistanceToUnit(unit->X,unit->Y,goal)
<=unit->Stats->AttackRange ) {
unit->State=0;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit
,goal->X-unit->X,goal->Y-unit->Y);
}
unit->SubAction++;
} else if( wall && MapDistance(unit->X,unit->Y
,unit->Command.Data.Move.DX
,unit->Command.Data.Move.DY)
<=unit->Stats->AttackRange ) {
DebugLevel3("Attacking wall\n");
unit->State=0;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit
,unit->Command.Data.Move.DX-unit->X
,unit->Command.Data.Move.DY-unit->Y);
}
unit->SubAction=1;
} else if( err ) {
unit->SubAction=0;
return 1;
}
DebugCheck( unit->Type->Vanishes );
unit->Command.Action=UnitActionAttack;
}
MoveToTarget(unit);
break;
//
@ -200,77 +373,9 @@ global int HandleActionAttack(Unit* unit)
//
case 1:
case 3:
AnimateActionAttack(unit);
if( unit->Reset ) {
goal=unit->Command.Data.Move.Goal;
//
// Goal is "weak" or a wall.
//
if( !goal && WallOnMap(unit->Command.Data.Move.DX
,unit->Command.Data.Move.DY) ) {
DebugLevel3("attack a wall!!!!\n");
break;
}
//
// Target is dead, choose new one.
//
if( !goal || !goal->HP
|| goal->Command.Action==UnitActionDie ) {
unit->State=0;
goal=AttackUnitsInReactRange(unit);
unit->Command.Data.Move.Goal=goal;
if( !goal ) {
unit->SubAction=0;
unit->Command.Action=UnitActionStill; // cade?
return 1;
}
unit->SubAction|=2;
DebugLevel3("Unit in react range %Zd\n",UnitNumber(goal));
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit
,goal->X-unit->X,goal->Y-unit->Y);
}
} else
//
// Have a weak target, try a better target.
//
if( goal && (unit->SubAction&2) ) {
Unit* temp;
temp=AttackUnitsInReactRange(unit);
if( temp && temp->Type->Priority>goal->Type->Priority ) {
unit->Command.Data.Move.Goal=goal=temp;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
if( !unit->Type->Tower ) {
UnitNewHeadingFromXY(unit
,goal->X-unit->X,goal->Y-unit->Y);
}
}
}
//
// Still near to target, if not goto target.
//
if( MapDistanceToUnit(unit->X,unit->Y,goal)
>unit->Stats->AttackRange ) {
unit->Command.Data.Move.Fast=1;
unit->Command.Data.Move.DX=goal->X;
unit->Command.Data.Move.DY=goal->Y;
unit->Frame=0;
unit->State=0;
unit->SubAction--;
break;
}
}
AttackTarget(unit);
break;
}
return 0;
}
//@}

View file

@ -25,22 +25,21 @@
#include <stdlib.h>
#include "freecraft.h"
#include "video.h"
#include "sound_id.h"
#include "unitsound.h"
#include "missile.h"
#include "unittype.h"
#include "player.h"
#include "unit.h"
#include "actions.h"
#include "unit.h"
#include "tileset.h"
#include "map.h"
#include "sound_server.h"
#include "missile.h"
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
// FIXME: should combine stand ground and still.
/**
** Unit stands still!
*/
@ -191,14 +190,30 @@ global void HandleActionStill(Unit* unit)
//
if( /*unit->Player->Type!=PlayerHuman &&*/ !type->Tower ) {
if( (goal=AttackUnitsInReactRange(unit)) ) {
CommandAttack(unit,goal->X,goal->Y,NULL,0);
// Weak goal, can choose other unit, come back after attack
// FIXME: should rewrite command handling
CommandAttack(unit,unit->X,unit->Y,NULL,FlushCommands);
unit->SavedCommand=unit->NextCommand[0];
CommandAttack(unit,goal->X,goal->Y,NULL,FlushCommands);
DebugLevel3(__FUNCTION__": %Zd Attacking in range %d\n"
,UnitNumber(unit),unit->SubAction);
unit->SubAction|=2;
unit->SavedCommand.Action=UnitActionAttack;
}
} else if( (goal=AttackUnitsInRange(unit)) ) {
// FIXME: johns, looks wired what I have written here
// FIXME: Why have I written such a chaos? (johns)
// FIXME: Johns should rewrite this
// FIXME: Applies now only for towers
if( !unit->SubAction || unit->Command.Data.Move.Goal!=goal ) {
// New target.
#ifdef NEW_UNIT
if( unit->Command.Data.Move.Goal ) {
unit->Command.Data.Move.Goal--;
}
unit->Command.Data.Move.Goal=goal;
goal->Refs++;
#else
unit->Command.Data.Move.Goal=goal;
#endif
unit->State=0;
unit->SubAction=1;
// Turn to target
@ -211,7 +226,12 @@ global void HandleActionStill(Unit* unit)
}
}
if( unit->SubAction ) {
if( unit->SubAction ) { // was attacking.
#ifdef NEW_UNIT
if( unit->Command.Data.Move.Goal ) {
unit->Command.Data.Move.Goal--;
}
#endif
unit->SubAction=unit->State=0;
}

View file

@ -81,6 +81,8 @@ global void CommandStopUnit(Unit* unit)
unit->NextCommand[0].Action=UnitActionStill;
unit->PendCommand=unit->NextCommand[0];
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -98,6 +100,8 @@ global void CommandStandGround(Unit* unit,int flush)
}
command->Action=UnitActionStandGround;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -124,6 +128,8 @@ global void CommandFollow(Unit* unit,Unit* dest,int flush)
command->Data.Move.Range=1;
command->Data.Move.SX=unit->X;
command->Data.Move.SY=unit->Y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -160,6 +166,8 @@ global void CommandMove(Unit* unit,int x,int y,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -205,6 +213,8 @@ global void CommandRepair(Unit* unit,int x,int y,Unit* dest,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -262,6 +272,8 @@ global void CommandAttack(Unit* unit,int x,int y,Unit* attack,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -296,6 +308,8 @@ global void CommandAttackGround(Unit* unit,int x,int y,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -329,6 +343,8 @@ global void CommandPatrolUnit(Unit* unit,int x,int y,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -357,6 +373,8 @@ global void CommandBoard(Unit* unit,Unit* dest,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=dest->X;
command->Data.Move.DY=dest->Y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -394,6 +412,8 @@ global void CommandUnload(Unit* unit,int x,int y,Unit* what,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -434,6 +454,8 @@ global void CommandBuildBuilding(Unit* unit,int x,int y
command->Data.Move.SY=unit->Y;
command->Data.Build.BuildThis=what;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -453,6 +475,8 @@ global void CommandCancelBuilding(Unit* unit,Unit* worker)
unit->Wait=1;
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -493,6 +517,8 @@ global void CommandHarvest(Unit* unit,int x,int y,int flush)
// FIXME: this hack didn't work correct on map border
command->Data.Move.DX=x ? x-1 : x;
command->Data.Move.DY=y ? y-1 : y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -531,6 +557,8 @@ global void CommandMineGold(Unit* unit,Unit* dest,int flush)
command->Data.Move.DX=dest->X;
command->Data.Move.DY=dest->Y;
#endif
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -569,6 +597,8 @@ global void CommandHaulOil(Unit* unit,Unit* dest,int flush)
command->Data.Move.DX=dest->X;
command->Data.Move.DY=dest->Y;
#endif
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -589,6 +619,8 @@ global void CommandReturnGoods(Unit* unit,int flush)
unit->NextCommand[0].Data.Move.Range=1;
unit->NextCommand[0].Data.Move.SX=unit->X;
unit->NextCommand[0].Data.Move.SY=unit->Y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -642,6 +674,8 @@ global void CommandTrainUnit(Unit* unit,UnitType* what,int flush)
unit->Wait=1; // FIXME: correct this
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -667,6 +701,8 @@ global void CommandCancelTraining(Unit* unit,int slot)
unit->Wait=1;
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -687,6 +723,8 @@ global void CommandUpgradeTo(Unit* unit,UnitType* what,int flush)
unit->Wait=1; // FIXME: correct this
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -701,6 +739,8 @@ global void CommandCancelUpgradeTo(Unit* unit)
unit->Wait=1; // FIXME: correct this
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -722,6 +762,8 @@ global void CommandResearch(Unit* unit,Upgrade* what,int flush)
unit->Wait=1; // FIXME: correct this
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -736,6 +778,8 @@ global void CommandCancelResearch(Unit* unit)
unit->Wait=1; // FIXME: correct this
unit->Reset=1;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
/**
@ -786,6 +830,8 @@ global void CommandDemolish(Unit* unit,int x,int y,Unit* dest,int flush)
command->Data.Move.SY=unit->Y;
command->Data.Move.DX=x;
command->Data.Move.DY=y;
unit->SavedCommand.Action=UnitActionStill; // clear saved action
}
//@}

View file

@ -104,7 +104,7 @@ extern int HandleActionRepair(Unit* unit);
/// Handle command patrol
extern void HandleActionPatrol(Unit* unit);
/// Handle command attack
extern int HandleActionAttack(Unit* unit);
extern void HandleActionAttack(Unit* unit);
/// Handle command board
extern void HandleActionBoard(Unit* unit);
/// Handle command unload

View file

@ -263,6 +263,9 @@ struct _unit_ {
#define NoUnitP (Unit*)0 /// return value: for no unit found
#define InfiniteDistance INT_MAX /// the distance is unreachable
#define FlushCommands 1 /// Flush commands in queue
// FIXME: will be removed, we get player limits
#define MAX_UNITS 1800 /// maximal number of units supported