From 3165e4101420b316f281bd3cf3de24c7f380e3bd Mon Sep 17 00:00:00 2001 From: Mike Hoffert Date: Sat, 19 Jul 2014 22:01:34 -0600 Subject: [PATCH 01/10] Attack speed is now upgradable Syntax is the same as all other upgrade stats. This also allows attack boosts to upgrade the attack speed (since they use the same code). --- source/glest_game/type_instances/unit.cpp | 10 ++- source/glest_game/types/command_type.cpp | 6 ++ source/glest_game/types/skill_type.cpp | 10 +++ source/glest_game/types/skill_type.h | 2 + source/glest_game/types/upgrade_type.cpp | 93 +++++++++++++++++++++++ source/glest_game/types/upgrade_type.h | 9 +++ 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 7042c4ee..3166cf5d 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -2615,7 +2615,15 @@ bool Unit::update() { int64 heightFactor = getHeightFactor(ANIMATION_SPEED_MULTIPLIER); int64 speedDenominator = speedDivider * game->getWorld()->getUpdateFps(this->getFactionIndex()); - int64 progressIncrease = (currSkill->getAnimSpeed() * heightFactor) / speedDenominator; + + // Override the animation speed for attacks that have upgraded the attack speed + int animSpeed = currSkill->getAnimSpeed(); + if(currSkill->getClass() == scAttack) { + int animSpeedBoost = ((AttackSkillType *) currSkill)->getAnimSpeedBoost(&totalUpgrade); + animSpeed += animSpeedBoost; + } + + int64 progressIncrease = (animSpeed * heightFactor) / speedDenominator; // Ensure we increment at least a value of 1 of the action will be stuck infinitely if(currSkill->getAnimSpeed() > 0 && heightFactor > 0 && progressIncrease == 0) { progressIncrease = 1; diff --git a/source/glest_game/types/command_type.cpp b/source/glest_game/types/command_type.cpp index 6e775622..7c3e2b6a 100644 --- a/source/glest_game/types/command_type.cpp +++ b/source/glest_game/types/command_type.cpp @@ -288,7 +288,13 @@ string AttackCommandType::getDesc(const TotalUpgrade *totalUpgrade, bool transla } str+="\n"; + //attack speed str+= lang.getString("AttackSpeed",(translatedValue == true ? "" : "english"))+": "+ intToStr(attackSkillType->getSpeed()) +"\n"; + if(totalUpgrade->getAttackSpeed(attackSkillType) != 0) { + str+= "+"+intToStr(totalUpgrade->getAttackSpeed(attackSkillType)); + } + str+="\n"; + str+=attackSkillType->getBoostDesc(translatedValue); return str; } diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 7a72c5ce..9aabec79 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -935,6 +935,16 @@ void AttackSkillType::load(const XmlNode *sn, const XmlNode *attackBoostsNode, } } +int AttackSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{ + int result = speed + totalUpgrade->getAttackSpeed(this); + result = max(0,result); + return result; +} + +int AttackSkillType::getAnimSpeedBoost(const TotalUpgrade *totalUpgrade) const{ + return totalUpgrade->getAttackSpeed(this); +} + string AttackSkillType::toString(bool translatedValue) const{ if(translatedValue == false) { return "Attack"; diff --git a/source/glest_game/types/skill_type.h b/source/glest_game/types/skill_type.h index 75db79b7..ead459bc 100644 --- a/source/glest_game/types/skill_type.h +++ b/source/glest_game/types/skill_type.h @@ -309,6 +309,8 @@ public: //misc int getTotalAttackStrength(const TotalUpgrade *totalUpgrade) const; int getTotalAttackRange(const TotalUpgrade *totalUpgrade) const; + virtual int getTotalSpeed(const TotalUpgrade *totalUpgrade) const; + virtual int getAnimSpeedBoost(const TotalUpgrade *totalUpgrade) const; virtual void saveGame(XmlNode *rootNode); }; diff --git a/source/glest_game/types/upgrade_type.cpp b/source/glest_game/types/upgrade_type.cpp index 812f247d..b47a97ce 100644 --- a/source/glest_game/types/upgrade_type.cpp +++ b/source/glest_game/types/upgrade_type.cpp @@ -169,6 +169,19 @@ void UpgradeTypeBase::load(const XmlNode *upgradeNode, string upgradename) { else { prodSpeed = 0; } + + attackSpeedIsMultiplier = false; + if(upgradeNode->hasChild("attack-speed") == true) { + attackSpeed= upgradeNode->getChild("attack-speed")->getAttribute("value")->getIntValue(); + if(upgradeNode->getChild("attack-speed")->getAttribute(VALUE_PERCENT_MULTIPLIER_KEY_NAME,false) != NULL) { + attackSpeedIsMultiplier = upgradeNode->getChild("attack-speed")->getAttribute(VALUE_PERCENT_MULTIPLIER_KEY_NAME)->getBoolValue(); + + //printf("Found prodSpeedIsMultiplier = %d\n",prodSpeedIsMultiplier); + } + } + else { + attackSpeed = 0; + } } int UpgradeTypeBase::getAttackStrength(const AttackSkillType *st) const { @@ -212,6 +225,20 @@ int UpgradeTypeBase::getMoveSpeed(const MoveSkillType *st) const { } } +int UpgradeTypeBase::getAttackSpeed(const AttackSkillType *st) const { + if(attackSpeedIsMultiplier == false || st == NULL) { + return attackSpeed; + } + else { + int result = 0; + if(attackSpeedIsMultiplierValueList.find(st->getName()) != attackSpeedIsMultiplierValueList.end()) { + result = attackSpeedIsMultiplierValueList.find(st->getName())->second; + } + + return result; + } +} + int UpgradeTypeBase::getProdSpeed(const SkillType *st) const { if(prodSpeedIsMultiplier == false || st == NULL) { return prodSpeed; @@ -347,6 +374,18 @@ string UpgradeTypeBase::getDesc(bool translatedValue) const{ str+= indent+lang.getString("ProductionSpeed",(translatedValue == true ? "" : "english")) + " +" + intToStr(prodSpeed); } } + if(attackSpeed != 0) { + if(str != "") { + str += "\n"; + } + + if(attackSpeedIsMultiplier) { + str+= indent+lang.getString("AttackSpeed",(translatedValue == true ? "" : "english")) + " *" + intToStr(moveSpeed); + } + else { + str+= indent+lang.getString("AttackSpeed",(translatedValue == true ? "" : "english")) + " +" + intToStr(moveSpeed); + } + } if(str != "") { str += "\n"; } @@ -821,6 +860,9 @@ void TotalUpgrade::reset() { prodSpeed=0; prodSpeedIsMultiplier=false; + + attackSpeed=0; + attackSpeedIsMultiplier=false; } void TotalUpgrade::sum(const UpgradeTypeBase *ut, const Unit *unit) { @@ -832,6 +874,7 @@ void TotalUpgrade::sum(const UpgradeTypeBase *ut, const Unit *unit) { attackRangeIsMultiplier = ut->getAttackRangeIsMultiplier(); moveSpeedIsMultiplier = ut->getMoveSpeedIsMultiplier(); prodSpeedIsMultiplier = ut->getProdSpeedIsMultiplier(); + attackSpeedIsMultiplier = ut->getAttackSpeedIsMultiplier(); if(ut->getMaxHpIsMultiplier() == true) { //printf("#1 Maxhp maxHp = %d, unit->getHp() = %d ut->getMaxHp() = %d\n",maxHp,unit->getHp(),ut->getMaxHp()); @@ -941,6 +984,19 @@ void TotalUpgrade::sum(const UpgradeTypeBase *ut, const Unit *unit) { else { prodSpeed += ut->getProdSpeed(NULL); } + + if(ut->getAttackSpeedIsMultiplier() == true) { + for(unsigned int i = 0; i < (unsigned int)unit->getType()->getSkillTypeCount(); ++i) { + const SkillType *skillType = unit->getType()->getSkillType(i); + const AttackSkillType *ast = dynamic_cast(skillType); + if(ast != NULL) { + attackSpeedIsMultiplierValueList[ast->getName()] += ((double)ast->getSpeed() * ((double)ut->getAttackSpeed(NULL) / (double)100)); + } + } + } + else { + attackSpeed += ut->getAttackSpeed(NULL); + } } void TotalUpgrade::apply(const UpgradeTypeBase *ut, const Unit *unit) { @@ -1080,6 +1136,23 @@ void TotalUpgrade::deapply(const UpgradeTypeBase *ut,const Unit *unit) { prodSpeed -= ut->getProdSpeed(NULL); enforceMinimumValue(0,prodSpeed); } + + if(ut->getAttackSpeedIsMultiplier() == true) { + for(unsigned int i = 0; i < (unsigned int)unit->getType()->getSkillTypeCount(); ++i) { + const SkillType *skillType = unit->getType()->getSkillType(i); + const AttackSkillType *ast = dynamic_cast(skillType); + if(ast != NULL) { + attackSpeedIsMultiplierValueList[ast->getName()] -= ((double)ast->getSpeed() * ((double)ut->getAttackSpeed(NULL) / (double)100)); + enforceMinimumValue(0, attackSpeedIsMultiplierValueList[ast->getName()]); + } + } + + //printf("AFTER Applying moveSpeedIsMultiplier, moveSpeed = %d\n",moveSpeed); + } + else { + attackSpeed -= ut->getAttackSpeed(NULL); + enforceMinimumValue(0, attackSpeed); + } } void TotalUpgrade::incLevel(const UnitType *ut) { @@ -1184,6 +1257,16 @@ void TotalUpgrade::saveGame(XmlNode *rootNode) const { prodSpeedMorphIsMultiplierValueListNode->addAttribute("key",iterMap->first, mapTagReplacements); prodSpeedMorphIsMultiplierValueListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements); } + + upgradeTypeBaseNode->addAttribute("attackSpeed",intToStr(attackSpeed), mapTagReplacements); + upgradeTypeBaseNode->addAttribute("attackSpeedIsMultiplier",intToStr(attackSpeedIsMultiplier), mapTagReplacements); + for(std::map::const_iterator iterMap = attackSpeedIsMultiplierValueList.begin(); + iterMap != attackSpeedIsMultiplierValueList.end(); ++iterMap) { + XmlNode *attackSpeedIsMultiplierValueListNode = upgradeTypeBaseNode->addChild("attackSpeedIsMultiplierValueList"); + + attackSpeedIsMultiplierValueListNode->addAttribute("key",iterMap->first, mapTagReplacements); + attackSpeedIsMultiplierValueListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements); + } } void TotalUpgrade::loadGame(const XmlNode *rootNode) { @@ -1282,6 +1365,16 @@ void TotalUpgrade::loadGame(const XmlNode *rootNode) { prodSpeedMorphIsMultiplierValueList[node->getAttribute("key")->getValue()] = node->getAttribute("value")->getIntValue(); } + + attackSpeed = upgradeTypeBaseNode->getAttribute("attackSpeed")->getIntValue(); + attackSpeedIsMultiplier = upgradeTypeBaseNode->getAttribute("attackSpeedIsMultiplier")->getIntValue() != 0; + vector attackSpeedIsMultiplierValueNodeList = upgradeTypeBaseNode->getChildList("attackSpeedIsMultiplierValueList"); + for(unsigned int i = 0; i < attackSpeedIsMultiplierValueNodeList.size(); ++i) { + XmlNode *node = attackSpeedIsMultiplierValueNodeList[i]; + + attackSpeedIsMultiplierValueList[node->getAttribute("key")->getValue()] = + node->getAttribute("value")->getIntValue(); + } } diff --git a/source/glest_game/types/upgrade_type.h b/source/glest_game/types/upgrade_type.h index 23a77121..c25b5e07 100644 --- a/source/glest_game/types/upgrade_type.h +++ b/source/glest_game/types/upgrade_type.h @@ -80,6 +80,10 @@ protected: std::map prodSpeedUpgradeIsMultiplierValueList; std::map prodSpeedMorphIsMultiplierValueList; + int attackSpeed; + bool attackSpeedIsMultiplier; + std::map attackSpeedIsMultiplierValueList; + public: UpgradeTypeBase() { maxHp = 0;; @@ -127,6 +131,8 @@ public: bool getMoveSpeedIsMultiplier() const {return moveSpeedIsMultiplier;} int getProdSpeed(const SkillType *st) const; bool getProdSpeedIsMultiplier() const {return prodSpeedIsMultiplier;} + int getAttackSpeed(const AttackSkillType *st) const; + bool getAttackSpeedIsMultiplier() const {return attackSpeedIsMultiplier;} void load(const XmlNode *upgradeNode, string upgradename); @@ -207,6 +213,9 @@ public: crcForUpgradeType.addInt64((int64)prodSpeedUpgradeIsMultiplierValueList.size()); //std::map prodSpeedMorphIsMultiplierValueList; crcForUpgradeType.addInt64((int64)prodSpeedMorphIsMultiplierValueList.size()); + + crcForUpgradeType.addInt(attackSpeed); + crcForUpgradeType.addInt(attackSpeedIsMultiplier); return crcForUpgradeType; } From a829fe580a145e486922e25bdca28ae695747414 Mon Sep 17 00:00:00 2001 From: Mike Hoffert Date: Sat, 19 Jul 2014 22:24:23 -0600 Subject: [PATCH 02/10] Animation speed now properly scales That is, the increase in attack speed is the same as the increase in animation speed. Previously, this was only the case for absolute increases. Now percentage increases do so, as well. --- source/glest_game/types/skill_type.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 9aabec79..b6aa6318 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -941,8 +941,16 @@ int AttackSkillType::getTotalSpeed(const TotalUpgrade *totalUpgrade) const{ return result; } +// Get the amount to boost the attack animation speed by (based on attack-speed upgrades) int AttackSkillType::getAnimSpeedBoost(const TotalUpgrade *totalUpgrade) const{ - return totalUpgrade->getAttackSpeed(this); + // Same calculation as in TotalUpgrade::sum, but bypassing the use of the value + // list (which is for the attack speed, not animation speed) + if(totalUpgrade->getAttackRangeIsMultiplier()) { + return animSpeed * (totalUpgrade->getAttackSpeed(NULL) / (double)100); + } + else { + return totalUpgrade->getAttackSpeed(NULL); + } } string AttackSkillType::toString(bool translatedValue) const{ From ea2b4bcc7f803076116f3b937baae57fd943e17c Mon Sep 17 00:00:00 2001 From: titiger Date: Thu, 25 Sep 2014 23:50:37 +0200 Subject: [PATCH 03/10] Headless servers should not precalculate CRCs. This creates too much load when more than one server is running on the same machine. --- source/glest_game/main/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index e885a58f..f30be482 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -5359,7 +5359,8 @@ int glestMain(int argc, char** argv) { bool startCRCPrecacheThread = config.getBool("PreCacheCRCThread","true"); //printf("### In [%s::%s Line: %d] precache thread enabled = %d SystemFlags::VERBOSE_MODE_ENABLED = %d\n",__FILE__,__FUNCTION__,__LINE__,startCRCPrecacheThread,SystemFlags::VERBOSE_MODE_ENABLED); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] precache thread enabled = %d\n",__FILE__,__FUNCTION__,__LINE__,startCRCPrecacheThread); - if(startCRCPrecacheThread == true) { + if (startCRCPrecacheThread == true + && GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) { static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__); vector techDataPaths = config.getPathListForType(ptTechs); From 50cb5f232649074479035f2b25f7acfd670942ce Mon Sep 17 00:00:00 2001 From: titiger Date: Mon, 29 Sep 2014 00:56:05 +0200 Subject: [PATCH 04/10] translation for ChatModeDisabledToAvoidCheating --- data/glest_game | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/glest_game b/data/glest_game index cfb41238..b1fc026f 160000 --- a/data/glest_game +++ b/data/glest_game @@ -1 +1 @@ -Subproject commit cfb41238ad446318b6dda34adba700194a5037c6 +Subproject commit b1fc026f227d6947c0bf685d1c705561f2d3909f From 6ebe0a197c1f6e10e0cbde68916dbc0d1a921842 Mon Sep 17 00:00:00 2001 From: titiger Date: Mon, 29 Sep 2014 01:47:00 +0200 Subject: [PATCH 05/10] whatever caused this code duplication .... --- source/glest_game/types/upgrade_type.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/glest_game/types/upgrade_type.h b/source/glest_game/types/upgrade_type.h index 1269f306..5d8fa483 100644 --- a/source/glest_game/types/upgrade_type.h +++ b/source/glest_game/types/upgrade_type.h @@ -96,10 +96,6 @@ protected: bool attackSpeedIsMultiplier; std::map attackSpeedIsMultiplierValueList; - int attackSpeed; - bool attackSpeedIsMultiplier; - std::map attackSpeedIsMultiplierValueList; - public: /** * Creates an UpgradeTypeBase with values such that there are no stat changes. From feb31e27d98737f0414137aa8d5d531f41c92ec1 Mon Sep 17 00:00:00 2001 From: titiger Date: Mon, 29 Sep 2014 02:23:36 +0200 Subject: [PATCH 06/10] tags feature Tags feature ( manually merged ) from Omegas pullrequest 25 https://github.com/MegaGlest/megaglest-source/pull/25/ see forum discussion: https://forum.megaglest.org/index.php?topic=9543.0 --- source/glest_game/types/skill_type.cpp | 170 ++++++++++++----------- source/glest_game/types/skill_type.h | 15 +- source/glest_game/types/unit_type.cpp | 13 +- source/glest_game/types/unit_type.h | 13 ++ source/glest_game/types/upgrade_type.cpp | 70 +++++++--- source/glest_game/types/upgrade_type.h | 20 +-- 6 files changed, 185 insertions(+), 116 deletions(-) diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 006b707f..14f218b4 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -61,34 +61,16 @@ bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const { else { // All units are affected (including enemies) if(targetType == abtAll) { - destUnitMightApply = (boostUnitList.empty() == true); - - // Specify which units are affected - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; - if(dest->getType()->getId() == ut->getId()) { - destUnitMightApply = true; - break; - } - } - + destUnitMightApply = (boostUnitList.empty() && tags.empty()); + destUnitMightApply = isInUnitListOrTags(dest->getType()); } // Only same faction units are affected else if(targetType == abtFaction) { //if(boostUnitList.empty() == true) { if(source->getFactionIndex() == dest->getFactionIndex()) { //destUnitMightApply = true; - destUnitMightApply = (boostUnitList.empty() == true); - - // Specify which units are affected - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; - if(dest->getType()->getId() == ut->getId()) { - destUnitMightApply = true; - break; - } - } - + destUnitMightApply = (boostUnitList.empty() && tags.empty()); + destUnitMightApply = isInUnitListOrTags(dest->getType()); } //} } @@ -97,16 +79,8 @@ bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const { //if(boostUnitList.empty() == true) { if(source->isAlly(dest) == true) { //destUnitMightApply = true; - destUnitMightApply = (boostUnitList.empty() == true); - - // Specify which units are affected - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; - if(dest->getType()->getId() == ut->getId()) { - destUnitMightApply = true; - break; - } - } + destUnitMightApply = (boostUnitList.empty() && tags.empty()); + destUnitMightApply = isInUnitListOrTags(dest->getType()); } //} } @@ -115,28 +89,13 @@ bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const { //if(boostUnitList.empty() == true) { if(source->isAlly(dest) == false) { //destUnitMightApply = true; - destUnitMightApply = (boostUnitList.empty() == true); - - // Specify which units are affected - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; - if(dest->getType()->getId() == ut->getId()) { - destUnitMightApply = true; - break; - } - } + destUnitMightApply = (boostUnitList.empty() && tags.empty()); + destUnitMightApply = isInUnitListOrTags(dest->getType()); } //} } else if(targetType == abtUnitTypes) { - // Specify which units are affected - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; - if(dest->getType()->getId() == ut->getId()) { - destUnitMightApply = true; - break; - } - } + destUnitMightApply = isInUnitListOrTags(dest->getType()); } } @@ -151,6 +110,32 @@ bool AttackBoost::isAffected(const Unit *source, const Unit *dest) const { return result; } +bool AttackBoost::isInUnitListOrTags(const UnitType *unitType) const { + // Specify which units are affected + std::set::iterator it; + for (it = boostUnitList.begin(); it != boostUnitList.end(); ++it) { + const UnitType *boostUnit = *it; + if(unitType->getId() == boostUnit->getId()) { + return true; + } + } + set unitTags = unitType->getTags(); + set intersect; + set_intersection(tags.begin(),tags.end(),unitTags.begin(),unitTags.end(), + std::inserter(intersect,intersect.begin())); + if(!intersect.empty()) return true; + + // Otherwise no match + return false; +} + +string AttackBoost::getTagName(string tag, bool translatedValue) const { + if(translatedValue == false) return tag; + + Lang &lang = Lang::getInstance(); + return lang.getTechTreeString("TagName_" + tag, tag.c_str()); +} + string AttackBoost::getDesc(bool translatedValue) const{ Lang &lang= Lang::getInstance(); string str= ""; @@ -190,14 +175,31 @@ string AttackBoost::getDesc(bool translatedValue) const{ str+= lang.getString("AffectedUnitsFromAll") +":\n"; } - if(boostUnitList.empty() == false) { - for(int i=0; i < (int)boostUnitList.size(); ++i){ - str+= " "+boostUnitList[i]->getName(translatedValue)+"\n"; - } + if(boostUnitList.empty() && tags.empty()) { + str+= lang.getString("All")+"\n"; } else { - str+= lang.getString("All")+"\n"; + // We want the output to be sorted, so convert the set to a vector and sort that + std::vector outputUnits(boostUnitList.begin(), boostUnitList.end()); + std::sort(outputUnits.begin(), outputUnits.end(), UnitTypeSorter()); + + vector::iterator unitIter; + for (unitIter = outputUnits.begin(); unitIter != outputUnits.end(); ++unitIter) { + const UnitType *unit = *unitIter; + str+= indent+unit->getName(translatedValue)+"\n"; + } + + // Do the same for tags + std::vector outputTags(tags.begin(), tags.end()); + std::sort(outputTags.begin(), outputTags.end()); + + vector::iterator tagIter; + for (tagIter = outputTags.begin(); tagIter != outputTags.end(); ++tagIter) { + string tag = *tagIter; + str+= indent + lang.getString("TagDesc", (translatedValue == true ? "" : "english")) + + " " + getTagName(tag,translatedValue) + "\n"; + } } return str; @@ -222,10 +224,18 @@ void AttackBoost::loadGame(const XmlNode *rootNode, Faction *faction, const Skil string unitTypeName = node->getAttribute("name")->getValue(); const UnitType *unitType = faction->getType()->getUnitType(unitTypeName); if(unitType != NULL) { - boostUnitList.push_back(unitType); + boostUnitList.insert(unitType); } } } + if(attackBoostNode->hasChild("tag")) { + vector tagNodeList = attackBoostNode->getChildList("tag"); + for(unsigned int i = 0; i < tagNodeList.size(); ++i) { + XmlNode *node = tagNodeList[i]; + string tagName = node->getAttribute("name")->getValue(); + tags.insert(tagName); + } + } //boostUpgrade.loadGame(attackBoostNode,faction); boostUpgrade = skillType->getAttackBoost()->boostUpgrade; @@ -252,10 +262,17 @@ void AttackBoost::saveGame(XmlNode *rootNode) const { // AttackBoostTargetType targetType; attackBoostNode->addAttribute("targetType",intToStr(targetType), mapTagReplacements); // vector boostUnitList; - for(unsigned int i = 0; i < boostUnitList.size(); ++i) { - const UnitType *ut = boostUnitList[i]; + std::set::iterator unitIter; + for (unitIter = boostUnitList.begin(); unitIter != boostUnitList.end(); ++unitIter) { + const UnitType *unit = *unitIter; XmlNode *unitTypeNode = attackBoostNode->addChild("UnitType"); - unitTypeNode->addAttribute("name",ut->getName(false), mapTagReplacements); + unitTypeNode->addAttribute("name",unit->getName(false), mapTagReplacements); + } + std::set::iterator tagIter; + for (tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) { + string tag = *tagIter; + XmlNode *unitTypeNode = attackBoostNode->addChild("tag"); + unitTypeNode->addAttribute("name", tag, mapTagReplacements); } // UpgradeTypeBase boostUpgrade; boostUpgrade.saveGame(attackBoostNode); @@ -352,38 +369,18 @@ void SkillType::loadAttackBoost(const XmlNode *attackBoostsNode, const XmlNode * if(targetType == "ally") { attackBoost.targetType = abtAlly; - for(int i = 0;i < (int)attackBoostNode->getChild("target")->getChildCount();++i) { - const XmlNode *boostUnitNode = attackBoostNode->getChild("target")->getChild("unit-type", i); - attackBoost.boostUnitList.push_back(ft->getUnitType(boostUnitNode->getAttribute("name")->getRestrictedValue())); - } } else if(targetType == "foe") { attackBoost.targetType = abtFoe; - for(int i = 0;i < (int)attackBoostNode->getChild("target")->getChildCount();++i) { - const XmlNode *boostUnitNode = attackBoostNode->getChild("target")->getChild("unit-type", i); - attackBoost.boostUnitList.push_back(ft->getUnitType(boostUnitNode->getAttribute("name")->getRestrictedValue())); - } } else if(targetType == "faction") { attackBoost.targetType = abtFaction; - for(int i = 0;i < (int)attackBoostNode->getChild("target")->getChildCount();++i) { - const XmlNode *boostUnitNode = attackBoostNode->getChild("target")->getChild("unit-type", i); - attackBoost.boostUnitList.push_back(ft->getUnitType(boostUnitNode->getAttribute("name")->getRestrictedValue())); - } } else if(targetType == "unit-types") { attackBoost.targetType = abtUnitTypes; - for(int i = 0;i < (int)attackBoostNode->getChild("target")->getChildCount();++i) { - const XmlNode *boostUnitNode = attackBoostNode->getChild("target")->getChild("unit-type", i); - attackBoost.boostUnitList.push_back(ft->getUnitType(boostUnitNode->getAttribute("name")->getRestrictedValue())); - } } else if(targetType == "all") { attackBoost.targetType = abtAll; - for(int i = 0;i < (int)attackBoostNode->getChild("target")->getChildCount();++i) { - const XmlNode *boostUnitNode = attackBoostNode->getChild("target")->getChild("unit-type", i); - attackBoost.boostUnitList.push_back(ft->getUnitType(boostUnitNode->getAttribute("name")->getRestrictedValue())); - } } else { char szBuf[8096] = ""; @@ -391,6 +388,21 @@ void SkillType::loadAttackBoost(const XmlNode *attackBoostsNode, const XmlNode * throw megaglest_runtime_error(szBuf); } + // Load the regular targets + const XmlNode *targetNode = attackBoostNode->getChild("target"); + vector targetNodes = targetNode->getChildList("unit-type"); + for(size_t i = 0;i < targetNodes.size(); ++i) { + string unitName = targetNodes.at(i)->getAttribute("name")->getRestrictedValue(); + attackBoost.boostUnitList.insert(ft->getUnitType(unitName)); + } + + // Load tags + vector tagNodes = targetNode->getChildList("tag"); + for(size_t i = 0;i < tagNodes.size(); ++i) { + string unitName = tagNodes.at(i)->getAttribute("name")->getRestrictedValue(); + attackBoost.tags.insert(unitName); + } + attackBoost.boostUpgrade.load(attackBoostNode,attackBoost.name); if(attackBoostNode->hasChild("particles") == true) { const XmlNode *particleNode = attackBoostNode->getChild("particles"); diff --git a/source/glest_game/types/skill_type.h b/source/glest_game/types/skill_type.h index 15f32360..cad0f652 100644 --- a/source/glest_game/types/skill_type.h +++ b/source/glest_game/types/skill_type.h @@ -30,6 +30,7 @@ #include "projectile_type.h" #include "upgrade_type.h" #include "leak_dumper.h" +#include using Shared::Sound::StaticSound; using Shared::Xml::XmlNode; @@ -98,7 +99,8 @@ public: bool allowMultipleBoosts; int radius; AttackBoostTargetType targetType; - vector boostUnitList; + std::set boostUnitList; + std::set tags; UpgradeTypeBase boostUpgrade; UnitParticleSystemType *unitParticleSystemTypeForSourceUnit; @@ -109,9 +111,20 @@ public: bool isAffected(const Unit *source, const Unit *dest) const; virtual string getDesc(bool translatedValue) const; + string getTagName(string tag, bool translatedValue=false) const; virtual void saveGame(XmlNode *rootNode) const; virtual void loadGame(const XmlNode *rootNode, Faction *faction, const SkillType *skillType); + +private: + /** + * Checks if a unit is affected by the attack boost by checking if either the UnitType is in + * the #boostUnitList or shares a tag with #tags. + * @param unitType The unit type to check. + * @return True if the unit *might* be affected by the attack boost (still have to check if it's + * in range), false otherwise. + */ + bool isInUnitListOrTags(const UnitType *unitType) const; }; class AnimationAttributes { diff --git a/source/glest_game/types/unit_type.cpp b/source/glest_game/types/unit_type.cpp index 7fbdccf8..82129a6a 100644 --- a/source/glest_game/types/unit_type.cpp +++ b/source/glest_game/types/unit_type.cpp @@ -602,7 +602,7 @@ void UnitType::loaddd(int id,const string &dir, const TechTree *techTree, if(parametersNode->hasChild("resources-death")) { const XmlNode *deathResourcesNode= parametersNode->getChild("resources-death"); - for(int i=0; i < deathResourcesNode->getChildCount(); ++i){ + for(size_t i=0; i < deathResourcesNode->getChildCount(); ++i){ const XmlNode *resourceNode= deathResourcesNode->getChild("resource", i); string name= resourceNode->getAttribute("name")->getRestrictedValue(); @@ -656,6 +656,17 @@ void UnitType::loaddd(int id,const string &dir, const TechTree *techTree, } } + // Tags + if(parametersNode->hasChild("tags")) { + const XmlNode *tagsNode= parametersNode->getChild("tags"); + + for(size_t i=0; i < tagsNode->getChildCount(); ++i){ + const XmlNode *resourceNode= tagsNode->getChild("tag", i); + string tag= resourceNode->getAttribute("value")->getRestrictedValue(); + tags.insert(tag); + } + } + //image const XmlNode *imageNode= parametersNode->getChild("image"); image= Renderer::getInstance().newTexture2D(rsGame); diff --git a/source/glest_game/types/unit_type.h b/source/glest_game/types/unit_type.h index fee7f903..2bc37fb0 100644 --- a/source/glest_game/types/unit_type.h +++ b/source/glest_game/types/unit_type.h @@ -193,6 +193,7 @@ private: StoredResources storedResources; Levels levels; LootableResources lootableResources; + std::set tags; //meeting point bool meetingPoint; @@ -265,6 +266,7 @@ public: inline const Resource *getStoredResource(int i) const {return &storedResources[i];} int getLootableResourceCount() const {return lootableResources.size();} inline const LootableResource getLootableResource(int i) const {return lootableResources.at(i);} + const set &getTags() const {return tags;} bool getCellMapCell(int x, int y, CardinalDir facing) const; inline bool getMeetingPoint() const {return meetingPoint;} inline bool getCountUnitDeathInStats() const {return countUnitDeathInStats;} @@ -329,6 +331,17 @@ private: void computeFirstCtOfClass(); }; +/** + * Used to sort UnitType. Sorts by *translated* unit name. Sorting is case sensitive and done in + * lexical order. + */ +struct UnitTypeSorter +{ + bool operator()( const UnitType *left, const UnitType *right ) const { + return left->getName(true) < right->getName(true); + } +}; + }}//end namespace diff --git a/source/glest_game/types/upgrade_type.cpp b/source/glest_game/types/upgrade_type.cpp index b47a97ce..2c5a6e2f 100644 --- a/source/glest_game/types/upgrade_type.cpp +++ b/source/glest_game/types/upgrade_type.cpp @@ -601,18 +601,43 @@ string UpgradeType::getName(bool translatedValue) const { return lang.getTechTreeString("UpgradeTypeName_" + name,name.c_str()); } +string UpgradeType::getTagName(string tag, bool translatedValue) const { + if(translatedValue == false) return tag; + + Lang &lang = Lang::getInstance(); + return lang.getTechTreeString("TagName_" + tag, tag.c_str()); +} + string UpgradeType::getReqDesc(bool translatedValue) const{ Lang &lang= Lang::getInstance(); string str= ProducibleType::getReqDesc(translatedValue); string indent=" "; - if(getEffectCount()>0){ + if(!effects.empty() || !tags.empty()){ str+= "\n"+ lang.getString("Upgrades",(translatedValue == true ? "" : "english"))+"\n"; } str+=UpgradeTypeBase::getDesc(translatedValue); - if(getEffectCount()>0){ + if(!effects.empty() || !tags.empty()){ str+= lang.getString("AffectedUnits",(translatedValue == true ? "" : "english"))+"\n"; - for(int i=0; igetName(translatedValue)+"\n"; + + // We want the output to be sorted, so convert the set to a vector and sort that + std::vector outputUnits(effects.begin(), effects.end()); + std::sort(outputUnits.begin(), outputUnits.end(), UnitTypeSorter()); + + vector::iterator unitIter; + for (unitIter = outputUnits.begin(); unitIter != outputUnits.end(); ++unitIter) { + const UnitType *unit = *unitIter; + str+= indent+unit->getName(translatedValue)+"\n"; + } + + // Do the same for tags + std::vector outputTags(tags.begin(), tags.end()); + std::sort(outputTags.begin(), outputTags.end()); + + vector::iterator tagIter; + for (tagIter = outputTags.begin(); tagIter != outputTags.end(); ++tagIter) { + string tag = *tagIter; + str+= indent + lang.getString("TagDesc", (translatedValue == true ? "" : "english")) + + " " + getTagName(tag,translatedValue) + "\n"; } } return str; @@ -757,29 +782,24 @@ void UpgradeType::load(const string &dir, const TechTree *techTree, sortedItems.clear(); hasDup = false; - //effects + //effects -- get list of affected units const XmlNode *effectsNode= upgradeNode->getChild("effects"); - for(int i = 0; i < (int)effectsNode->getChildCount(); ++i) { - const XmlNode *unitNode= effectsNode->getChild("unit", i); + vector unitNodes= effectsNode->getChildList("unit"); + for(size_t i = 0; i < unitNodes.size(); ++i) { + const XmlNode *unitNode= unitNodes.at(i); string name= unitNode->getAttribute("name")->getRestrictedValue(); - if(sortedItems.find(name) != sortedItems.end()) { - hasDup = true; - } - - sortedItems[name] = 0; + effects.insert(factionType->getUnitType(name)); } - if(hasDup) { - printf("WARNING, upgrade type [%s] has one or more duplicate effects\n",this->getName().c_str()); + //effects -- convert tags into units + vector tagNodes= effectsNode->getChildList("tag"); + for(size_t i = 0; i < tagNodes.size(); ++i) { + const XmlNode *tagNode= tagNodes.at(i); + string name= tagNode->getAttribute("name")->getRestrictedValue(); + tags.insert(name); } - for(std::map::iterator iterMap = sortedItems.begin(); - iterMap != sortedItems.end(); ++iterMap) { - effects.push_back(factionType->getUnitType(iterMap->first)); - } - sortedItems.clear(); - //values UpgradeTypeBase::load(upgradeNode,name); } @@ -792,7 +812,15 @@ void UpgradeType::load(const string &dir, const TechTree *techTree, } bool UpgradeType::isAffected(const UnitType *unitType) const{ - return find(effects.begin(), effects.end(), unitType)!=effects.end(); + if(std::find(effects.begin(), effects.end(), unitType)!=effects.end()) return true; + + const set unitTags = unitType->getTags(); + set intersect; + set_intersection(tags.begin(),tags.end(),unitTags.begin(),unitTags.end(), + std::inserter(intersect,intersect.begin())); + if(!intersect.empty()) return true; + + return false; } //void UpgradeType::saveGame(XmlNode *rootNode) const { diff --git a/source/glest_game/types/upgrade_type.h b/source/glest_game/types/upgrade_type.h index 5d8fa483..5db3218d 100644 --- a/source/glest_game/types/upgrade_type.h +++ b/source/glest_game/types/upgrade_type.h @@ -30,6 +30,7 @@ #include "conversion.h" #include "xml_parser.h" #include "leak_dumper.h" +#include using Shared::Util::Checksum; using namespace Shared::Util; @@ -266,9 +267,10 @@ public: class UpgradeType: public UpgradeTypeBase, public ProducibleType { private: /** - * List of unit types (the "classes" of units, eg, swordman) that are affected by this upgrade. - */ - vector effects; + * Set of unit types (the "classes" of units, eg, swordman) that are affected by this upgrade. + */ + std::set effects; + std::set tags; public: /** @@ -301,17 +303,7 @@ public: * appears in the XMLs. */ virtual string getName(bool translatedValue=false) const; - - /** - * Returns the number of UnitTypes affected by this upgrade. - */ - int getEffectCount() const {return (int)effects.size();} - - /** - * Returns a particular unit type affected by this upgrade. - * @param i Index of the unit type in the #effects list. - */ - const UnitType * getEffect(int i) const {return effects[i];} + string getTagName(string tag, bool translatedValue=false) const; /** * Determines if a unit is affected by this upgrade. From e39fb8e8e48be963006c7e808965ad635cf398bd Mon Sep 17 00:00:00 2001 From: titiger Date: Mon, 29 Sep 2014 02:55:15 +0200 Subject: [PATCH 07/10] trying to fix windows build --- source/glest_game/types/skill_type.cpp | 1 + source/glest_game/types/upgrade_type.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 14f218b4..90d3f782 100644 --- a/source/glest_game/types/skill_type.cpp +++ b/source/glest_game/types/skill_type.cpp @@ -12,6 +12,7 @@ #include "skill_type.h" #include +#include #include "sound.h" #include "util.h" diff --git a/source/glest_game/types/upgrade_type.cpp b/source/glest_game/types/upgrade_type.cpp index 2c5a6e2f..78ad754a 100644 --- a/source/glest_game/types/upgrade_type.cpp +++ b/source/glest_game/types/upgrade_type.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "unit_type.h" #include "util.h" From ea1be622428a9608bd38a0de32b7938c3084533d Mon Sep 17 00:00:00 2001 From: titiger Date: Wed, 1 Oct 2014 00:33:47 +0200 Subject: [PATCH 08/10] fix for a VERY old bug related to wrong display of attack range see https://forum.megaglest.org/index.php?topic=9567.0 this is a bug found in glest 2.0 !!! --- source/glest_game/types/command_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/glest_game/types/command_type.cpp b/source/glest_game/types/command_type.cpp index 7c3e2b6a..7e966dc0 100644 --- a/source/glest_game/types/command_type.cpp +++ b/source/glest_game/types/command_type.cpp @@ -266,7 +266,7 @@ string AttackCommandType::getDesc(const TotalUpgrade *totalUpgrade, bool transla //attack distance str+= lang.getString("AttackDistance",(translatedValue == true ? "" : "english"))+": "+intToStr(attackSkillType->getAttackRange()); if(totalUpgrade->getAttackRange(attackSkillType) != 0) { - str+= "+"+intToStr(totalUpgrade->getAttackRange(attackSkillType) != 0); + str+= "+"+intToStr(totalUpgrade->getAttackRange(attackSkillType)); } str+="\n"; From 626775664679f09b96de58957c4ddbe95c79459b Mon Sep 17 00:00:00 2001 From: titiger Date: Thu, 2 Oct 2014 00:42:45 +0200 Subject: [PATCH 09/10] trying to fix the ubuntu libtasn1.so.3 problem --- mk/linux/start_megaglest | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mk/linux/start_megaglest b/mk/linux/start_megaglest index 29a6cfe1..80cc5e94 100755 --- a/mk/linux/start_megaglest +++ b/mk/linux/start_megaglest @@ -202,6 +202,10 @@ GCRYPT_LINKEDLIBNAME='libgcrypt.so.11' GCRYPT_LIBLOOKUP1=${GCRYPT_LINKEDLIBNAME} GCRYPT_LIBLOOKUP2='libgcrypt.so.' +TASN_LINKEDLIBNAME='libtasn1.so.3' +TASN_LIBLOOKUP1=${TASN_LINKEDLIBNAME} +TASN_LIBLOOKUP2='libtasn1.so.' + if [ "$OS_TYPE"'_' = 'x86_64_' ]; then DIRECTFB_LINKEDLIBNAME='libdirectfb-1.2.so.0' DIRECTFB_LIBLOOKUP1=${DIRECTFB_LINKEDLIBNAME} @@ -279,6 +283,7 @@ findMissingSO "$LDCONFIG" "$GAMEDIR/$LIBDIR/${DL_LINKEDLIBNAME}" "$DL_LIBLOOKUP1 findMissingSO "$LDCONFIG" "$GAMEDIR/$LIBDIR/${VLCCORE_LINKEDLIBNAME}" "$VLCCORE_LIBLOOKUP1" "$VLCCORE_LIBLOOKUP2" findMissingSO "$LDCONFIG" "$GAMEDIR/$LIBDIR/${VLC_LINKEDLIBNAME}" "$VLC_LIBLOOKUP1" "$VLC_LIBLOOKUP2" findMissingSO "$LDCONFIG" "$GAMEDIR/$LIBDIR/${GCRYPT_LINKEDLIBNAME}" "$GCRYPT_LIBLOOKUP1" "$GCRYPT_LIBLOOKUP2" +findMissingSO "$LDCONFIG" "$GAMEDIR/$LIBDIR/${TASN_LINKEDLIBNAME}" "$TASN_LIBLOOKUP1" "$TASN_LIBLOOKUP2" ./megaglest $@ From 8892a2533c40c71bca6c28591b42ae354fc6a2d0 Mon Sep 17 00:00:00 2001 From: titiger Date: Sun, 5 Oct 2014 01:38:18 +0200 Subject: [PATCH 10/10] no more trouble when switching maps in headless mode. If a button was pressed in the last 4 seconds we ignore settings distributed by the headless server. --- source/glest_game/menu/menu_state_connected_game.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/glest_game/menu/menu_state_connected_game.cpp b/source/glest_game/menu/menu_state_connected_game.cpp index 3440e1c6..620a94f0 100644 --- a/source/glest_game/menu/menu_state_connected_game.cpp +++ b/source/glest_game/menu/menu_state_connected_game.cpp @@ -3341,8 +3341,9 @@ void MenuStateConnectedGame::update() { GameSettings *gameSettings = clientInterface->getGameSettingsPtr(); //printf("Menu got new settings thisfactionindex = %d startlocation: %d control = %d\n",gameSettings->getThisFactionIndex(),clientInterface->getGameSettings()->getStartLocationIndex(clientInterface->getGameSettings()->getThisFactionIndex()),gameSettings->getFactionControl(clientInterface->getGameSettings()->getThisFactionIndex())); - - setupUIFromGameSettings(gameSettings, errorOnMissingData); + if ( difftime((long int)time(NULL),broadcastServerSettingsDelayTimer) >= HEADLESSSERVER_BROADCAST_SETTINGS_SECONDS){ + setupUIFromGameSettings(gameSettings, errorOnMissingData); + } } // check if we are joining an in progress game @@ -4604,6 +4605,7 @@ void MenuStateConnectedGame::setupUIFromGameSettings(GameSettings *gameSettings, if(getMissingMapFromFTPServerInProgress == false && gameSettings->getMap() != "") { // map + bool missingMap=false; string mapFile = gameSettings->getMap(); mapFile = formatString(mapFile); @@ -4647,11 +4649,16 @@ void MenuStateConnectedGame::setupUIFromGameSettings(GameSettings *gameSettings, } maps.push_back(Lang::getInstance().getString("DataMissing","",true)); mapFile = Lang::getInstance().getString("DataMissing","",true); + missingMap=true; } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] listBoxMap.getSelectedItemIndex() = %d, mapFiles.size() = " MG_SIZE_T_SPECIFIER ", maps.size() = " MG_SIZE_T_SPECIFIER ", getCurrentMapFile() [%s] mapFile [%s]\n", extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,listBoxMap.getSelectedItemIndex(),mapFiles.size(),maps.size(),getCurrentMapFile().c_str(),mapFile.c_str()); + if(!missingMap && mapFile!=listBoxMap.getSelectedItem()){ + console.addLine("Headless server does not have map, switching to next one"); + printf("Headless server doesn't have map '%s'. Setting map '%s' instead.\n",listBoxMap.getSelectedItem().c_str(),mapFile.c_str()); + } listBoxMap.setItems(maps); listBoxMap.setSelectedItem(mapFile);