diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index 96336cffb..9e3af4533 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -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; } //@} diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp index 795cabeb3..be89811e2 100644 --- a/src/action/action_still.cpp +++ b/src/action/action_still.cpp @@ -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; } diff --git a/src/action/command.cpp b/src/action/command.cpp index 4c79989bb..96ab89a05 100644 --- a/src/action/command.cpp +++ b/src/action/command.cpp @@ -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 } //@} diff --git a/src/include/actions.h b/src/include/actions.h index f1bfc62a2..9b356c72c 100644 --- a/src/include/actions.h +++ b/src/include/actions.h @@ -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 diff --git a/src/include/unit.h b/src/include/unit.h index fd37178b1..8eea68e38 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -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