From bf841969a7b25506058effec4757c36dc3706607 Mon Sep 17 00:00:00 2001 From: Andrettin <andre.ng@live.com> Date: Wed, 25 Nov 2015 13:13:17 +0100 Subject: [PATCH] Units can now (optionally) have a RangedAttack animation specified --- doc/scripts/unittype.html | 1 + src/action/action_attack.cpp | 12 ++++++++---- src/animation/animation.cpp | 3 +++ src/include/animation.h | 4 +++- src/include/unit.h | 2 ++ src/missile/missile.cpp | 5 ++++- src/sound/unitsound.cpp | 1 + src/unit/unit.cpp | 31 +++++++++++++++++++++++++++++++ 8 files changed, 53 insertions(+), 6 deletions(-) diff --git a/doc/scripts/unittype.html b/doc/scripts/unittype.html index 20191efc3..e20c05199 100644 --- a/doc/scripts/unittype.html +++ b/doc/scripts/unittype.html @@ -74,6 +74,7 @@ animation.</dd> <li>Still</li> <li>Move</li> <li>Attack</li> + <li>RangedAttack</li> <li>Repair</li> <li>Train</li> <li>Research</li> diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index 0c1b8eb0d..84c1b5216 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -83,11 +83,15 @@ void AnimateActionAttack(CUnit &unit, COrder &order) // No animation. // So direct fire missile. // FIXME : wait a little. - if (!unit.Type->Animations || !unit.Type->Animations->Attack) { - order.OnAnimationAttack(unit); - return; + if (unit.Type->Animations && unit.Type->Animations->RangedAttack && unit.IsAttackRanged(order.GetGoal(), order.GetGoalPos())) { + UnitShowAnimation(unit, unit.Type->Animations->RangedAttack); + } else { + if (!unit.Type->Animations || !unit.Type->Animations->Attack) { + order.OnAnimationAttack(unit); + return; + } + UnitShowAnimation(unit, unit.Type->Animations->Attack); } - UnitShowAnimation(unit, unit.Type->Animations->Attack); } /* static */ COrder *COrder::NewActionAttack(const CUnit &attacker, CUnit &target) diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp index 3da5c59b0..a3c68a7fa 100644 --- a/src/animation/animation.cpp +++ b/src/animation/animation.cpp @@ -703,6 +703,8 @@ static int CclDefineAnimations(lua_State *l) } } else if (!strcmp(value, "Attack")) { anims->Attack = ParseAnimation(l, -1); + } else if (!strcmp(value, "RangedAttack")) { + anims->RangedAttack = ParseAnimation(l, -1); } else if (!strcmp(value, "SpellCast")) { anims->SpellCast = ParseAnimation(l, -1); } else if (!strcmp(value, "Move")) { @@ -732,6 +734,7 @@ static int CclDefineAnimations(lua_State *l) AddAnimationToArray(anims->Death[i]); } AddAnimationToArray(anims->Attack); + AddAnimationToArray(anims->RangedAttack); AddAnimationToArray(anims->SpellCast); AddAnimationToArray(anims->Move); AddAnimationToArray(anims->Repair); diff --git a/src/include/animation.h b/src/include/animation.h index 7518fe19c..aa064a0c7 100644 --- a/src/include/animation.h +++ b/src/include/animation.h @@ -107,7 +107,7 @@ public: class CAnimations { public: - CAnimations() : Attack(NULL), Build(NULL), Move(NULL), Repair(NULL), + CAnimations() : Attack(NULL), RangedAttack(NULL), Build(NULL), Move(NULL), Repair(NULL), Research(NULL), SpellCast(NULL), Start(NULL), Still(NULL), Train(NULL), Upgrade(NULL) { @@ -118,6 +118,7 @@ public: ~CAnimations() { delete Attack; + delete RangedAttack; delete Build; for (int i = 0; i < ANIMATIONS_DEATHTYPES + 1; ++i) { delete Death[i]; @@ -141,6 +142,7 @@ public: public: CAnimation *Attack; + CAnimation *RangedAttack; CAnimation *Build; CAnimation *Death[ANIMATIONS_DEATHTYPES + 1]; CAnimation *Harvest[MaxCosts]; diff --git a/src/include/unit.h b/src/include/unit.h index 7d2d1cdcf..bffdb768d 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -286,6 +286,8 @@ public: int GetDrawLevel() const; + bool IsAttackRanged(CUnit *goal, const Vec2i &goalPos); + PixelPos GetMapPixelPosTopLeft() const; PixelPos GetMapPixelPosCenter() const; diff --git a/src/missile/missile.cpp b/src/missile/missile.cpp index a95979d8c..2f71cc377 100644 --- a/src/missile/missile.cpp +++ b/src/missile/missile.cpp @@ -367,7 +367,10 @@ void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos) } // No missile hits immediately! - if (unit.Type->Missile.Missile->Class == MissileClassNone) { + if ( + unit.Type->Missile.Missile->Class == MissileClassNone + || (unit.Type->Animations && unit.Type->Animations->Attack && unit.Type->Animations->RangedAttack && !unit.IsAttackRanged(goal, goalPos)) // treat melee attacks from units that have both attack and ranged attack animations as having missile class none + ) { // No goal, take target coordinates if (!goal) { if (Map.WallOnMap(goalPos)) { diff --git a/src/sound/unitsound.cpp b/src/sound/unitsound.cpp index 7820c32df..637d3dcf3 100644 --- a/src/sound/unitsound.cpp +++ b/src/sound/unitsound.cpp @@ -120,6 +120,7 @@ static void MapAnimSounds(CUnitType &type) MapAnimSounds2(type.Animations->Still); MapAnimSounds2(type.Animations->Move); MapAnimSounds2(type.Animations->Attack); + MapAnimSounds2(type.Animations->RangedAttack); MapAnimSounds2(type.Animations->SpellCast); for (int i = 0; i <= ANIMATIONS_DEATHTYPES; ++i) { MapAnimSounds2(type.Animations->Death[i]); diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index d4bd4d020..bc6743c9a 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -3121,6 +3121,37 @@ bool CUnit::IsUnusable(bool ignore_built_state) const return (!IsAliveOnMap() || (!ignore_built_state && CurrentAction() == UnitActionBuilt)); } +/** +** Check if the unit attacking its goal will result in a ranged attack +*/ +bool CUnit::IsAttackRanged(CUnit *goal, const Vec2i &goalPos) +{ + if (this->Variable[ATTACKRANGE_INDEX].Value <= 1) { //always return false if the units attack range is 1 or lower + return false; + } + + if (this->Container) { //if the unit is inside a container, the attack will always be ranged + return true; + } + + if ( + goal + && goal->IsAliveOnMap() + && ( + this->MapDistanceTo(*goal) > 1 + || (this->Type->UnitType != UnitTypeFly && goal->Type->UnitType == UnitTypeFly) + || (this->Type->UnitType == UnitTypeFly && goal->Type->UnitType != UnitTypeFly) + ) + ) { + return true; + } + + if (!goal && Map.Info.IsPointOnMap(goalPos) && this->MapDistanceTo(goalPos) > 1) { + return true; + } + + return false; +} /*---------------------------------------------------------------------------- -- Initialize/Cleanup