diff --git a/data/glest_game b/data/glest_game index 4f05a017..b1fc026f 160000 --- a/data/glest_game +++ b/data/glest_game @@ -1 +1 @@ -Subproject commit 4f05a0177385ce47eb4cfcf5ce6676f59b290d37 +Subproject commit b1fc026f227d6947c0bf685d1c705561f2d3909f 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 $@ 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); 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); 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"; diff --git a/source/glest_game/types/skill_type.cpp b/source/glest_game/types/skill_type.cpp index 006b707f..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" @@ -61,34 +62,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 +80,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 +90,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 +111,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 +176,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 +225,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 +263,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 +370,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 +389,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..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" @@ -601,18 +602,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 +783,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 +813,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.