diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 9f45266b..6ffb334e 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -278,6 +278,8 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType //starting skill this->lastModelIndexForCurrSkillType = -1; this->currSkill = getType()->getFirstStOfClass(scStop); + this->currentAttackBoostUnits.first = this->currSkill; + livingUnits.insert(id); livingUnitsp.insert(this); @@ -1231,6 +1233,40 @@ bool Unit::update() { } } + //if(currSkill != currentAttackBoostUnits.first) { + // First remove any units that were previosuly in range + if(currentAttackBoostUnits.second.size() > 0) { + for(unsigned int i = 0; i < currentAttackBoostUnits.second.size(); ++i) { + // Remove attack boost upgrades from unit + Unit *affectedUnit = currentAttackBoostUnits.second[i]; + affectedUnit->deapplyAttackBoost(currentAttackBoostUnits.first->getAttackBoost(), this); + + //printf("!!!! DE-APPLY ATTACK BOOST from unit [%s - %d]\n",affectedUnit->getType()->getName().c_str(),affectedUnit->getId()); + } + currentAttackBoostUnits.second.clear(); + } + //} + currentAttackBoostUnits.first = currSkill; + + if(currSkill->isAttackBoostEnabled() == true) { + // Search for units in range of this unit which apply to the + // attack-boost and temporarily upgrade them + UnitUpdater *unitUpdater = this->game->getWorld()->getUnitUpdater(); + + const AttackBoost *attackBoost = currSkill->getAttackBoost(); + vector candidates = unitUpdater->findUnitsInRange(this, attackBoost->radius); + for(unsigned int i = 0; i < candidates.size(); ++i) { + Unit *affectedUnit = candidates[i]; + if(attackBoost->isAffected(this,affectedUnit) == true) { + affectedUnit->applyAttackBoost(attackBoost, this); + + currentAttackBoostUnits.second.push_back(affectedUnit); + + //printf("@@@@ APPLY ATTACK BOOST to unit [%s - %d]\n",affectedUnit->getType()->getName().c_str(),affectedUnit->getId()); + } + } + } + return return_value; } @@ -1516,6 +1552,38 @@ string Unit::getDesc() const { return str; } +void Unit::applyAttackBoost(const AttackBoost *boost, const Unit *source) { + if(boost == NULL) { + char szBuf[4096]=""; + sprintf(szBuf,"In [%s::%s Line: %d] ERROR: boost == NULL, Unit = [%s]\n",__FILE__,__FUNCTION__,__LINE__,this->toString().c_str()); + throw runtime_error(szBuf); + } + + if(boost->isAffected(source, this)) { + totalUpgrade.apply(&boost->boostUpgrade); + + checkItemInVault(&this->hp,this->hp); + hp += boost->boostUpgrade.getMaxHp(); + addItemToVault(&this->hp,this->hp); + } +} + +void Unit::deapplyAttackBoost(const AttackBoost *boost, const Unit *source) { + if(boost == NULL) { + char szBuf[4096]=""; + sprintf(szBuf,"In [%s::%s Line: %d] ERROR: boost == NULL, Unit = [%s]\n",__FILE__,__FUNCTION__,__LINE__,this->toString().c_str()); + throw runtime_error(szBuf); + } + + if(boost->isAffected(source, this)) { + totalUpgrade.deapply(&boost->boostUpgrade); + + checkItemInVault(&this->hp,this->hp); + hp -= boost->boostUpgrade.getMaxHp(); + addItemToVault(&this->hp,this->hp); + } +} + void Unit::applyUpgrade(const UpgradeType *upgradeType){ if(upgradeType == NULL) { char szBuf[4096]=""; diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index 7799aac7..ec75a213 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -19,6 +19,7 @@ #include "game_constants.h" #include #include "platform_common.h" +#include #include "leak_dumper.h" namespace Glest { namespace Game { @@ -49,6 +50,7 @@ class UpgradeType; class Level; class MorphCommandType; class Game; +class Unit; enum CommandResult{ crSuccess, @@ -342,6 +344,8 @@ private: bool usePathfinderExtendedMaxNodes; int maxQueuedCommandDisplayCount; + std::pair > currentAttackBoostUnits; + public: Unit(int id, UnitPathInterface *path, const Vec2i &pos, const UnitType *type, Faction *faction, Map *map, CardinalDir placeFacing); ~Unit(); @@ -463,6 +467,10 @@ public: int update2(); bool update(); void tick(); + + void applyAttackBoost(const AttackBoost *boost, const Unit *source); + void deapplyAttackBoost(const AttackBoost *boost, const Unit *source); + void applyUpgrade(const UpgradeType *upgradeType); void computeTotalUpgrade(); void incKills(int team); diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 48b7e1b4..2ea3a42b 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -28,6 +28,55 @@ using namespace Shared::Graphics; namespace Glest{ namespace Game{ + +AttackBoost::AttackBoost() { + enabled = false; + radius = 0; + boostAllUnits = false; +} +bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const { + bool result = false; + if(enabled == true && source != NULL && dest != NULL && + source != dest) { + // All units are affected (including enemies) + if(boostAllUnits == true) { + float distance = source->getCenteredPos().dist(dest->getCenteredPos()); + if(distance <= radius) { + result = true; + } + } + else { + // Only same faction units are affected + if(boostUnitList.size() == 0) { + //if(source->isAlly(dest) == true) { + //} + if(source->getFactionIndex() == dest->getFactionIndex()) { + float distance = source->getCenteredPos().dist(dest->getCenteredPos()); + if(distance <= radius) { + result = true; + } + } + } + // Specify which units are affected + else { + for(unsigned int i = 0; i < boostUnitList.size(); ++i) { + const UnitType *ut = boostUnitList[i]; + if(dest->getType()->getId() == ut->getId()) { + float distance = source->getCenteredPos().dist(dest->getCenteredPos()); + if(distance <= radius) { + result = true; + break; + } + } + } + } + } + } + + return result; +} + + // ===================================================== // class SkillType // ===================================================== diff --git a/source/glest_game/types/skill_type.h b/source/glest_game/types/skill_type.h index 70e5c99f..670fb22d 100644 --- a/source/glest_game/types/skill_type.h +++ b/source/glest_game/types/skill_type.h @@ -41,6 +41,7 @@ class FactionType; class TechTree; class Lang; class TotalUpgrade; +class Unit; enum Field{ @@ -75,16 +76,14 @@ typedef list UnitParticleSystemTypes; class AttackBoost { public: - AttackBoost() { - enabled = false; - radius = 0; - boostAllUnits = false; - } + AttackBoost(); bool enabled; int radius; bool boostAllUnits; vector boostUnitList; UpgradeTypeBase boostUpgrade; + + bool isAffected(const Unit *source, const Unit *dest) const; }; class SkillType { @@ -123,6 +122,9 @@ public: StaticSound *getSound() const {return sounds.getRandSound();} float getSoundStartTime() const {return soundStartTime;} + bool isAttackBoostEnabled() const { return attackBoost.enabled; } + const AttackBoost * getAttackBoost() const { return &attackBoost; } + //other virtual string toString() const= 0; virtual int getTotalSpeed(const TotalUpgrade *) const {return speed;} diff --git a/source/glest_game/types/upgrade_type.cpp b/source/glest_game/types/upgrade_type.cpp index 69357313..f8bedb90 100644 --- a/source/glest_game/types/upgrade_type.cpp +++ b/source/glest_game/types/upgrade_type.cpp @@ -232,11 +232,11 @@ string UpgradeType::getReqDesc() const{ // class TotalUpgrade // =============================== -TotalUpgrade::TotalUpgrade(){ +TotalUpgrade::TotalUpgrade() { reset(); } -void TotalUpgrade::reset(){ +void TotalUpgrade::reset() { maxHp= 0; maxEp= 0; sight=0; @@ -247,7 +247,7 @@ void TotalUpgrade::reset(){ prodSpeed=0; } -void TotalUpgrade::sum(const UpgradeType *ut){ +void TotalUpgrade::sum(const UpgradeTypeBase *ut) { maxHp+= ut->getMaxHp(); maxEp+= ut->getMaxEp(); sight+= ut->getSight(); @@ -258,11 +258,26 @@ void TotalUpgrade::sum(const UpgradeType *ut){ prodSpeed+= ut->getProdSpeed(); } -void TotalUpgrade::incLevel(const UnitType *ut){ +void TotalUpgrade::incLevel(const UnitType *ut) { maxHp+= ut->getMaxHp()*50/100; maxEp+= ut->getMaxEp()*50/100; sight+= ut->getSight()*20/100; armor+= ut->getArmor()*50/100; } +void TotalUpgrade::apply(const UpgradeTypeBase *ut) { + sum(ut); +} + +void TotalUpgrade::deapply(const UpgradeTypeBase *ut) { + maxHp-= ut->getMaxHp(); + maxEp-= ut->getMaxEp(); + sight-= ut->getSight(); + armor-= ut->getArmor(); + attackStrength-= ut->getAttackStrength(); + attackRange-= ut->getAttackRange(); + moveSpeed-= ut->getMoveSpeed(); + prodSpeed-= ut->getProdSpeed(); +} + }}//end namespace diff --git a/source/glest_game/types/upgrade_type.h b/source/glest_game/types/upgrade_type.h index 696976d6..664c218d 100644 --- a/source/glest_game/types/upgrade_type.h +++ b/source/glest_game/types/upgrade_type.h @@ -22,7 +22,7 @@ using Shared::Util::Checksum; using namespace Shared::Util; using namespace Shared::Xml; -namespace Glest{ namespace Game{ +namespace Glest { namespace Game { class TechTree; class FactionType; @@ -75,7 +75,7 @@ public: // class UpgradeType // =============================== -class UpgradeType: public UpgradeTypeBase, public ProducibleType{ +class UpgradeType: public UpgradeTypeBase, public ProducibleType { private: vector effects; @@ -98,13 +98,16 @@ public: // class TotalUpgrade // =============================== -class TotalUpgrade: public UpgradeTypeBase{ +class TotalUpgrade: public UpgradeTypeBase { public: TotalUpgrade(); void reset(); - void sum(const UpgradeType *ut); + void sum(const UpgradeTypeBase *ut); void incLevel(const UnitType *ut); + + void apply(const UpgradeTypeBase *ut); + void deapply(const UpgradeTypeBase *ut); }; }}//end namespace diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index f3683f66..ce98f167 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -2330,6 +2330,49 @@ vector UnitUpdater::enemyUnitsOnRange(const Unit *unit,const AttackSkillT return enemies; } + +void UnitUpdater::findUnitsForCell(Cell *cell, const Unit *unit,vector &units) { + //all fields + for(int k = 0; k < fieldCount; k++) { + Field f= static_cast(k); + + //check field + Unit *cellUnit = cell->getUnit(f); + + if(cellUnit != NULL && cellUnit->isAlive()) { + units.push_back(cellUnit); + } + } +} + +vector UnitUpdater::findUnitsInRange(const Unit *unit, int radius) { + int range = radius; + vector units; + + //aux vars + int size = unit->getType()->getSize(); + Vec2i center = unit->getPos(); + Vec2f floatCenter = unit->getFloatCenteredPos(); + + //nearby cells + UnitRangeCellsLookupItem cacheItem; + for(int i = center.x - range; i < center.x + range + size; ++i) { + for(int j = center.y - range; j < center.y + range + size; ++j) { + //cells inside map and in range +#ifdef USE_STREFLOP + if(map->isInside(i, j) && streflop::floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){ +#else + if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){ +#endif + Cell *cell = map->getCell(i,j); + findUnitsForCell(cell,unit,units); + } + } + } + + return units; +} + // ===================================================== // class ParticleDamager // ===================================================== diff --git a/source/glest_game/world/unit_updater.h b/source/glest_game/world/unit_updater.h index f1ad66f2..e752fc72 100644 --- a/source/glest_game/world/unit_updater.h +++ b/source/glest_game/world/unit_updater.h @@ -121,6 +121,9 @@ public: vector enemyUnitsOnRange(const Unit *unit,const AttackSkillType *ast); void findEnemiesForCell(const Vec2i pos, int size, int sightRange, const Faction *faction, vector &enemies, bool attackersOnly) const; + void findUnitsForCell(Cell *cell, const Unit *unit,vector &units); + vector findUnitsInRange(const Unit *unit, int radius); + private: //attack void hit(Unit *attacker);