diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 9dde74d18..a4613db1b 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -664,7 +664,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vectorheroManager->getHeroRole(hero) != HeroRole::MAIN || nullkiller->buildAnalyzer->getGoldPreasure() > MAX_GOLD_PEASURE)) { diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 491380f3b..409b0f30e 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -293,7 +293,7 @@ void CPlayerInterface::yourTurn(QueryID queryID) std::string msg = CGI->generaltexth->allTexts[13]; boost::replace_first(msg, "%s", cb->getStartInfo()->playerInfos.find(playerID)->second.name); std::vector> cmp; - cmp.push_back(std::make_shared(CComponent::flag, playerID.getNum(), 0)); + cmp.push_back(std::make_shared(ComponentType::FLAG, playerID)); showInfoDialog(msg, cmp); } else @@ -326,7 +326,7 @@ void CPlayerInterface::acceptTurn(QueryID queryID) auto playerColor = *cb->getPlayerID(); std::vector components; - components.emplace_back(Component::EComponentType::FLAG, playerColor.getNum(), 0, 0); + components.emplace_back(ComponentType::FLAG, playerColor); MetaString text; const auto & optDaysWithoutCastle = cb->getPlayerState(playerColor)->daysWithoutCastle; @@ -1228,7 +1228,7 @@ void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, con text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact->getNameTranslated()); // Picture of assembled artifact at bottom. - auto sc = std::make_shared(CComponent::artifact, assembledArtifact->getIndex(), 0); + auto sc = std::make_shared(ComponentType::ARTIFACT, assembledArtifact->getId()); scs.push_back(sc); } else @@ -1441,7 +1441,7 @@ void CPlayerInterface::playerBlocked(int reason, bool start) std::string msg = CGI->generaltexth->translate("vcmi.adventureMap.playerAttacked"); boost::replace_first(msg, "%s", cb->getStartInfo()->playerInfos.find(playerID)->second.name); std::vector> cmp; - cmp.push_back(std::make_shared(CComponent::flag, playerID.getNum(), 0)); + cmp.push_back(std::make_shared(ComponentType::FLAG, playerID)); makingTurn = true; //workaround for stiff showInfoDialog implementation showInfoDialog(msg, cmp); makingTurn = false; diff --git a/client/adventureMap/CInfoBar.cpp b/client/adventureMap/CInfoBar.cpp index 360dd4946..c583f461f 100644 --- a/client/adventureMap/CInfoBar.cpp +++ b/client/adventureMap/CInfoBar.cpp @@ -376,47 +376,51 @@ void CInfoBar::pushComponents(const std::vector & components, std::st std::array, int>, 10> reward_map; for(const auto & c : components) { - switch(c.id) + switch(c.type) { - case Component::EComponentType::PRIM_SKILL: - case Component::EComponentType::EXPERIENCE: + case ComponentType::PRIM_SKILL: + case ComponentType::EXPERIENCE: + case ComponentType::LEVEL: + case ComponentType::MANA: reward_map.at(0).first.push_back(c); reward_map.at(0).second = 8; //At most 8, cannot be more break; - case Component::EComponentType::SEC_SKILL: + case ComponentType::SEC_SKILL: reward_map.at(1).first.push_back(c); reward_map.at(1).second = 4; //At most 4 break; - case Component::EComponentType::SPELL: + case ComponentType::SPELL: reward_map.at(2).first.push_back(c); reward_map.at(2).second = 4; //At most 4 break; - case Component::EComponentType::ARTIFACT: + case ComponentType::ARTIFACT: + case ComponentType::SPELL_SCROLL: reward_map.at(3).first.push_back(c); reward_map.at(3).second = 4; //At most 4, too long names break; - case Component::EComponentType::CREATURE: + case ComponentType::CREATURE: reward_map.at(4).first.push_back(c); reward_map.at(4).second = 4; //At most 4, too long names break; - case Component::EComponentType::RESOURCE: + case ComponentType::RESOURCE: + case ComponentType::RESOURCE_PER_DAY: reward_map.at(5).first.push_back(c); reward_map.at(5).second = 7; //At most 7 break; - case Component::EComponentType::MORALE: - case Component::EComponentType::LUCK: + case ComponentType::MORALE: + case ComponentType::LUCK: reward_map.at(6).first.push_back(c); reward_map.at(6).second = 2; //At most 2 - 1 for morale + 1 for luck break; - case Component::EComponentType::BUILDING: + case ComponentType::BUILDING: reward_map.at(7).first.push_back(c); reward_map.at(7).second = 1; //At most 1 - only large icons available AFAIK break; - case Component::EComponentType::HERO_PORTRAIT: + case ComponentType::HERO_PORTRAIT: reward_map.at(8).first.push_back(c); reward_map.at(8).second = 1; //I do not think than we even can get more than 1 hero break; - case Component::EComponentType::FLAG: + case ComponentType::FLAG: reward_map.at(9).first.push_back(c); reward_map.at(9).second = 1; //I do not think than we even can get more than 1 player in notification break; diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index 72e3817f3..e62bf26c4 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -571,7 +571,7 @@ void OptionsTab::CPlayerOptionTooltipBox::genTownWindow() for(auto & elem : town->creatures) { if(!elem.empty()) - components.push_back(std::make_shared(CComponent::creature, elem.front(), 0, CComponent::tiny)); + components.push_back(std::make_shared(ComponentType::CREATURE, elem.front(), 0, CComponent::tiny)); } boxAssociatedCreatures = std::make_shared(components, Rect(10, 140, pos.w - 20, 140)); } diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index bbe3e07be..c4440aaef 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -49,7 +49,7 @@ void CArtPlace::setInternals(const CArtifactInstance * artInst) if(settings["general"]["enableUiEnhancements"].Bool()) { imageIndex = spellID.num; - if(baseType != CComponent::spell) + if(component.type != ComponentType::SPELL_SCROLL) { image->setScale(Point(pos.w, 34)); image->setAnimationPath(AnimationPath::builtin("spellscr"), imageIndex); @@ -57,21 +57,20 @@ void CArtPlace::setInternals(const CArtifactInstance * artInst) } } // Add spell component info (used to provide a pic in r-click popup) - baseType = CComponent::spell; - type = spellID; + component.type = ComponentType::SPELL_SCROLL; + component.subType = spellID; } else { - if(settings["general"]["enableUiEnhancements"].Bool() && baseType != CComponent::artifact) + if(settings["general"]["enableUiEnhancements"].Bool() && component.type != ComponentType::ARTIFACT) { image->setScale(Point()); image->setAnimationPath(AnimationPath::builtin("artifact"), imageIndex); image->moveTo(Point(pos.x, pos.y)); } - baseType = CComponent::artifact; - type = artInst->getTypeId(); + component.type = ComponentType::ARTIFACT; + component.subType = artInst->getTypeId(); } - bonusValue = 0; image->enable(); text = artInst->getDescription(); } diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index 12844ceb3..2a77b46da 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -39,41 +39,35 @@ #include "../../lib/CArtHandler.h" #include "../../lib/CArtifactInstance.h" -CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize, EFonts font): - perDay(false) +CComponent::CComponent(ComponentType Type, ComponentSubType Subtype, std::optional Val, ESize imageSize, EFonts font) { init(Type, Subtype, Val, imageSize, font, ""); } -CComponent::CComponent(Etype Type, int Subtype, std::string Val, ESize imageSize, EFonts font): - perDay(false) +CComponent::CComponent(ComponentType Type, ComponentSubType Subtype, std::string Val, ESize imageSize, EFonts font) { - init(Type, Subtype, 0, imageSize, font, Val); + init(Type, Subtype, std::nullopt, imageSize, font, Val); } CComponent::CComponent(const Component & c, ESize imageSize, EFonts font) - : perDay(false) { - if(c.id == Component::EComponentType::RESOURCE && c.when==-1) - perDay = true; - - init((Etype)c.id, c.subtype, c.val, imageSize, font); + init(c.type, c.subType, c.value, imageSize, font); } -void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts fnt, std::string ValText) +void CComponent::init(ComponentType Type, ComponentSubType Subtype, std::optional Val, ESize imageSize, EFonts fnt, std::string ValText) { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); addUsedEvents(SHOW_POPUP); - compType = Type; - subtype = Subtype; - val = Val; - valText = ValText; + data.type = Type; + data.subType = Subtype; + data.value = Val; + + customSubtitle = ValText; size = imageSize; font = fnt; - assert(compType < typeInvalid); assert(size < sizeInvalid); setSurface(getFileName()[size], (int)getIndex()); @@ -94,7 +88,7 @@ void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts if (size < small) max = 30; - if(Type == Etype::resource && !valText.empty()) + if(Type == ComponentType::RESOURCE && !ValText.empty()) max = 80; std::vector textLines = CMessage::breakText(getSubtitle(), std::max(max, pos.w), font); @@ -115,151 +109,207 @@ void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts std::vector CComponent::getFileName() { - static const std::string primSkillsArr [] = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"}; - static const std::string secSkillsArr [] = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"}; - static const std::string resourceArr [] = {"SMALRES", "RESOURCE", "RESOURCE", "RESOUR82"}; - static const std::string creatureArr [] = {"CPRSMALL", "CPRSMALL", "CPRSMALL", "TWCRPORT"}; - static const std::string artifactArr[] = {"Artifact", "Artifact", "Artifact", "Artifact"}; - static const std::string spellsArr [] = {"SpellInt", "SpellInt", "SpellInt", "SPELLSCR"}; - static const std::string moraleArr [] = {"IMRL22", "IMRL30", "IMRL42", "imrl82"}; - static const std::string luckArr [] = {"ILCK22", "ILCK30", "ILCK42", "ilck82"}; - static const std::string heroArr [] = {"PortraitsSmall", "PortraitsSmall", "PortraitsSmall", "PortraitsLarge"}; - static const std::string flagArr [] = {"CREST58", "CREST58", "CREST58", "CREST58"}; + static const std::array primSkillsArr = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"}; + static const std::array secSkillsArr = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"}; + static const std::array resourceArr = {"SMALRES", "RESOURCE", "RESOURCE", "RESOUR82"}; + static const std::array creatureArr = {"CPRSMALL", "CPRSMALL", "CPRSMALL", "TWCRPORT"}; + static const std::array artifactArr = {"Artifact", "Artifact", "Artifact", "Artifact"}; + static const std::array spellsArr = {"SpellInt", "SpellInt", "SpellInt", "SPELLSCR"}; + static const std::array moraleArr = {"IMRL22", "IMRL30", "IMRL42", "imrl82"}; + static const std::array luckArr = {"ILCK22", "ILCK30", "ILCK42", "ilck82"}; + static const std::array heroArr = {"PortraitsSmall", "PortraitsSmall", "PortraitsSmall", "PortraitsLarge"}; + static const std::array flagArr = {"CREST58", "CREST58", "CREST58", "CREST58"}; - auto gen = [](const std::string * arr) -> std::vector + auto gen = [](const std::array & arr) -> std::vector { return { AnimationPath::builtin(arr[0]), AnimationPath::builtin(arr[1]), AnimationPath::builtin(arr[2]), AnimationPath::builtin(arr[3]) }; }; - switch(compType) + switch(data.type) { - case primskill: return gen(primSkillsArr); - case secskill: return gen(secSkillsArr); - case resource: return gen(resourceArr); - case creature: return gen(creatureArr); - case artifact: return gen(artifactArr); - case experience: return gen(primSkillsArr); - case spell: return gen(spellsArr); - case morale: return gen(moraleArr); - case luck: return gen(luckArr); - case building: return std::vector(4, (*CGI->townh)[subtype]->town->clientInfo.buildingsIcons); - case hero: return gen(heroArr); - case flag: return gen(flagArr); + case ComponentType::PRIM_SKILL: + case ComponentType::EXPERIENCE: + case ComponentType::MANA: + case ComponentType::LEVEL: + return gen(primSkillsArr); + case ComponentType::SEC_SKILL: + return gen(secSkillsArr); + case ComponentType::RESOURCE: + case ComponentType::RESOURCE_PER_DAY: + return gen(resourceArr); + case ComponentType::CREATURE: + return gen(creatureArr); + case ComponentType::ARTIFACT: + return gen(artifactArr); + case ComponentType::SPELL_SCROLL: + case ComponentType::SPELL: + return gen(spellsArr); + case ComponentType::MORALE: + return gen(moraleArr); + case ComponentType::LUCK: + return gen(luckArr); + case ComponentType::BUILDING: + return std::vector(4, (*CGI->townh)[data.subType.as().getFaction()]->town->clientInfo.buildingsIcons); + case ComponentType::HERO_PORTRAIT: + return gen(heroArr); + case ComponentType::FLAG: + return gen(flagArr); + default: + assert(0); + return {}; } - assert(0); - return {}; } size_t CComponent::getIndex() { - switch(compType) + switch(data.type) { - case primskill: return subtype; - case secskill: return subtype*3 + 3 + val - 1; - case resource: return subtype; - case creature: return CGI->creatures()->getByIndex(subtype)->getIconIndex(); - case artifact: return CGI->artifacts()->getByIndex(subtype)->getIconIndex(); - case experience: return 4; - case spell: return (size < large) ? subtype + 1 : subtype; - case morale: return val+3; - case luck: return val+3; - case building: return val; - case hero: return CGI->heroTypes()->getByIndex(subtype)->getIconIndex(); - case flag: return subtype; + case ComponentType::PRIM_SKILL: + return data.subType.getNum(); + case ComponentType::EXPERIENCE: + case ComponentType::LEVEL: + return 4; // for whatever reason, in H3 experience icon is located in primary skills icons + case ComponentType::MANA: + return 5; // for whatever reason, in H3 mana points icon is located in primary skills icons + case ComponentType::SEC_SKILL: + return data.subType.getNum() * 3 + 3 + data.value.value_or(0) - 1; + case ComponentType::RESOURCE: + case ComponentType::RESOURCE_PER_DAY: + return data.subType.getNum(); + case ComponentType::CREATURE: + return CGI->creatures()->getById(data.subType.as())->getIconIndex(); + case ComponentType::ARTIFACT: + return CGI->artifacts()->getById(data.subType.as())->getIconIndex(); + case ComponentType::SPELL_SCROLL: + case ComponentType::SPELL: + return (size < large) ? data.subType.getNum() + 1 : data.subType.getNum(); + case ComponentType::MORALE: + return data.value.value_or(0) + 3; + case ComponentType::LUCK: + return data.value.value_or(0) + 3; + case ComponentType::BUILDING: + return data.subType.as().getBuilding(); + case ComponentType::HERO_PORTRAIT: + return CGI->heroTypes()->getById(data.subType.as())->getIconIndex(); + case ComponentType::FLAG: + return data.subType.getNum(); + default: + assert(0); + return 0; } - assert(0); - return 0; } std::string CComponent::getDescription() { - switch(compType) + switch(data.type) { - case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill - : CGI->generaltexth->allTexts[149]; //mana - case secskill: return CGI->skillh->getByIndex(subtype)->getDescriptionTranslated(val); - case resource: return CGI->generaltexth->allTexts[242]; - case creature: return ""; - case artifact: - { - auto artID = ArtifactID(subtype); - auto description = VLC->arth->objects[artID]->getDescriptionTranslated(); - if(artID == ArtifactID::SPELL_SCROLL) + case ComponentType::PRIM_SKILL: + return CGI->generaltexth->arraytxt[2+data.subType.getNum()]; + case ComponentType::EXPERIENCE: + case ComponentType::LEVEL: + return CGI->generaltexth->allTexts[241]; + case ComponentType::MANA: + return CGI->generaltexth->allTexts[149]; + case ComponentType::SEC_SKILL: + return CGI->skillh->getByIndex(data.subType.getNum())->getDescriptionTranslated(data.value.value_or(0)); + case ComponentType::RESOURCE: + case ComponentType::RESOURCE_PER_DAY: + return CGI->generaltexth->allTexts[242]; + case ComponentType::CREATURE: + return ""; + case ComponentType::ARTIFACT: + return VLC->artifacts()->getById(data.subType.as())->getDescriptionTranslated(); + case ComponentType::SPELL_SCROLL: { - ArtifactUtils::insertScrrollSpellName(description, SpellID(val)); + auto description = VLC->arth->objects[ArtifactID::SPELL_SCROLL]->getDescriptionTranslated(); + ArtifactUtils::insertScrrollSpellName(description, data.subType.as()); + return description; } - return description; + case ComponentType::SPELL: + return VLC->spells()->getById(data.subType.as())->getDescriptionTranslated(data.value.value_or(0)); + case ComponentType::MORALE: + return CGI->generaltexth->heroscrn[ 4 - (data.value.value_or(0)>0) + (data.value.value_or(0)<0)]; + case ComponentType::LUCK: + return CGI->generaltexth->heroscrn[ 7 - (data.value.value_or(0)>0) + (data.value.value_or(0)<0)]; + case ComponentType::BUILDING: + { + auto index = data.subType.as(); + return (*CGI->townh)[index.getFaction()]->town->buildings[index.getBuilding()]->getDescriptionTranslated(); + } + case ComponentType::HERO_PORTRAIT: + return ""; + case ComponentType::FLAG: + return ""; + default: + assert(0); + return 0; } - case experience: return CGI->generaltexth->allTexts[241]; - case spell: return (*CGI->spellh)[subtype]->getDescriptionTranslated(val); - case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)]; - case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)]; - case building: return (*CGI->townh)[subtype]->town->buildings[BuildingID(val)]->getDescriptionTranslated(); - case hero: return ""; - case flag: return ""; - } - assert(0); - return ""; } std::string CComponent::getSubtitle() { - if(!perDay) - return getSubtitleInternal(); + if (!customSubtitle.empty()) + return customSubtitle; - std::string ret = CGI->generaltexth->allTexts[3]; - boost::replace_first(ret, "%d", getSubtitleInternal()); - return ret; -} - -std::string CComponent::getSubtitleInternal() -{ - //FIXME: some of these are horrible (e.g creature) - switch(compType) + switch(data.type) { - case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387])); - case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->skillh->getByIndex(subtype)->getNameTranslated(); - case resource: return valText.empty() ? std::to_string(val) : valText; - case creature: - { - auto creature = CGI->creh->getByIndex(subtype); - if ( val ) - return std::to_string(val) + " " + (val > 1 ? creature->getNamePluralTranslated() : creature->getNameSingularTranslated()); + case ComponentType::PRIM_SKILL: + if (data.value) + return boost::str(boost::format("%+d %s") % data.value.value_or(0) % CGI->generaltexth->primarySkillNames[data.subType.getNum()]); else - return val > 1 ? creature->getNamePluralTranslated() : creature->getNameSingularTranslated(); - } - case artifact: return CGI->artifacts()->getByIndex(subtype)->getNameTranslated(); - case experience: + return CGI->generaltexth->primarySkillNames[data.subType.getNum()]; + case ComponentType::EXPERIENCE: + return std::to_string(data.value.value_or(0)); + case ComponentType::LEVEL: { - if(subtype == 1) //+1 level - tree of knowledge - { - std::string level = CGI->generaltexth->allTexts[442]; - boost::replace_first(level, "1", std::to_string(val)); - return level; - } + std::string level = CGI->generaltexth->allTexts[442]; + boost::replace_first(level, "1", std::to_string(data.value.value_or(0))); + return level; + } + case ComponentType::MANA: + return boost::str(boost::format("%+d %s") % data.value.value_or(0) % CGI->generaltexth->allTexts[387]); + case ComponentType::SEC_SKILL: + return CGI->generaltexth->levels[data.value.value_or(0)-1] + "\n" + CGI->skillh->getById(data.subType.as())->getNameTranslated(); + case ComponentType::RESOURCE: + return std::to_string(data.value.value_or(0)); + case ComponentType::RESOURCE_PER_DAY: + return boost::str(boost::format(CGI->generaltexth->allTexts[387]) % data.value.value_or(0)); + case ComponentType::CREATURE: + { + auto creature = CGI->creh->getById(data.subType.as()); + if ( data.value.value_or(0) ) + return std::to_string(data.value.value_or(0)) + " " + (data.value.value_or(0) > 1 ? creature->getNamePluralTranslated() : creature->getNameSingularTranslated()); else - { - return std::to_string(val); //amount of experience OR level required for seer hut; - } + return data.value.value_or(0) > 1 ? creature->getNamePluralTranslated() : creature->getNameSingularTranslated(); } - case spell: return CGI->spells()->getByIndex(subtype)->getNameTranslated(); - case morale: return ""; - case luck: return ""; - case building: - { - auto building = (*CGI->townh)[subtype]->town->buildings[BuildingID(val)]; - if(!building) + case ComponentType::ARTIFACT: + return CGI->artifacts()->getById(data.subType.as())->getNameTranslated(); + case ComponentType::SPELL_SCROLL: + case ComponentType::SPELL: + return CGI->spells()->getById(data.subType.as())->getNameTranslated(); + case ComponentType::MORALE: + return ""; + case ComponentType::LUCK: + return ""; + case ComponentType::BUILDING: { - logGlobal->error("Town of faction %s has no building #%d", (*CGI->townh)[subtype]->town->faction->getNameTranslated(), val); - return (boost::format("Missing building #%d") % val).str(); + auto index = data.subType.as(); + auto building = (*CGI->townh)[index.getFaction()]->town->buildings[index.getBuilding()]; + if(!building) + { + logGlobal->error("Town of faction %s has no building #%d", (*CGI->townh)[index.getFaction()]->town->faction->getNameTranslated(), index.getBuilding().getNum()); + return (boost::format("Missing building #%d") % index.getBuilding().getNum()).str(); + } + return building->getNameTranslated(); } - return building->getNameTranslated(); - } - case hero: return ""; - case flag: return CGI->generaltexth->capColors[subtype]; + case ComponentType::HERO_PORTRAIT: + return ""; + case ComponentType::FLAG: + return CGI->generaltexth->capColors[data.subType.as().getNum()]; + default: + assert(0); + return ""; } - logGlobal->error("Invalid CComponent type: %d", (int)compType); - return ""; } void CComponent::setSurface(const AnimationPath & defName, int imgPos) @@ -299,7 +349,7 @@ CSelectableComponent::CSelectableComponent(const Component &c, std::function OnSelect): +CSelectableComponent::CSelectableComponent(ComponentType Type, ComponentSubType Sub, int Val, ESize imageSize, std::function OnSelect): CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect) { setRedrawParent(true); diff --git a/client/widgets/CComponent.h b/client/widgets/CComponent.h index 3f94137ff..813ca5667 100644 --- a/client/widgets/CComponent.h +++ b/client/widgets/CComponent.h @@ -12,6 +12,7 @@ #include "../gui/CIntObject.h" #include "../render/EFont.h" #include "../../lib/filesystem/ResourcePath.h" +#include "../../lib/networkPacks/Component.h" VCMI_LIB_NAMESPACE_BEGIN @@ -26,11 +27,6 @@ class CLabel; class CComponent : public virtual CIntObject { public: - enum Etype - { - primskill, secskill, resource, creature, artifact, experience, spell, morale, luck, building, hero, flag, typeInvalid - }; - //NOTE: not all types have exact these sizes or have less than 4 of them. In such cases closest one will be used enum ESize { @@ -47,26 +43,21 @@ private: size_t getIndex(); std::vector getFileName(); void setSurface(const AnimationPath & defName, int imgPos); - std::string getSubtitleInternal(); - void init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts font = FONT_SMALL, std::string ValText=""); + void init(ComponentType Type, ComponentSubType Subtype, std::optional Val, ESize imageSize, EFonts font = FONT_SMALL, std::string ValText=""); public: std::shared_ptr image; - - Etype compType; //component type + Component data; + std::string customSubtitle; ESize size; //component size. EFonts font; //Font size of label - int subtype; //type-dependant subtype. See getSomething methods for details - int val; // value \ strength \ amount of component. See getSomething methods for details - std::string valText; // value instead of amount; currently only for resource - bool perDay; // add "per day" text to subtitle std::string getDescription(); std::string getSubtitle(); - CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large, EFonts font = FONT_SMALL); - CComponent(Etype Type, int Subtype, std::string Val, ESize imageSize=large, EFonts font = FONT_SMALL); + CComponent(ComponentType Type, ComponentSubType Subtype, std::optional Val = std::nullopt, ESize imageSize=large, EFonts font = FONT_SMALL); + CComponent(ComponentType Type, ComponentSubType Subtype, std::string Val, ESize imageSize=large, EFonts font = FONT_SMALL); CComponent(const Component &c, ESize imageSize=large, EFonts font = FONT_SMALL); void showPopupWindow(const Point & cursorPosition) override; //call-in @@ -86,7 +77,7 @@ public: void clickPressed(const Point & cursorPosition) override; //call-in void clickDouble(const Point & cursorPosition) override; //call-in - CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function OnSelect = nullptr); + CSelectableComponent(ComponentType Type, ComponentSubType Sub, int Val, ESize imageSize=large, std::function OnSelect = nullptr); CSelectableComponent(const Component & c, std::function OnSelect = nullptr); }; diff --git a/client/widgets/CWindowWithArtifacts.cpp b/client/widgets/CWindowWithArtifacts.cpp index 2b6d4d18d..bf5ca043e 100644 --- a/client/widgets/CWindowWithArtifacts.cpp +++ b/client/widgets/CWindowWithArtifacts.cpp @@ -95,7 +95,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst if(artPlace.getArt()->getTypeId() == ArtifactID::CATAPULT) { // The Catapult must be equipped - std::vector> catapult(1, std::make_shared(CComponent::artifact, 3, 0)); + std::vector> catapult(1, std::make_shared(ComponentType::ARTIFACT, ArtifactID(ArtifactID::CATAPULT))); LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[312], catapult); return false; } diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index 4d5eff1d5..0e8d8c353 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -95,16 +95,16 @@ void LRClickableAreaWTextComp::clickPressed(const Point & cursorPosition) LOCPLINT->showInfoDialog(text, comp); } -LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType) - : LRClickableAreaWText(Pos), baseType(BaseType), bonusValue(-1) +LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, ComponentType BaseType) + : LRClickableAreaWText(Pos) { - type = -1; + component.type = BaseType; } std::shared_ptr LRClickableAreaWTextComp::createComponent() const { - if(baseType >= 0) - return std::make_shared(CComponent::Etype(baseType), type, bonusValue); + if(component.type != ComponentType::NONE) + return std::make_shared(component); else return std::shared_ptr(); } @@ -164,17 +164,11 @@ void CHeroArea::hover(bool on) void LRClickableAreaOpenTown::clickPressed(const Point & cursorPosition) { if(town) - { LOCPLINT->openTownWindow(town); - if ( type == 2 ) - LOCPLINT->castleInt->builds->buildingClicked(BuildingID::VILLAGE_HALL); - else if ( type == 3 && town->fortLevel() ) - LOCPLINT->castleInt->builds->buildingClicked(BuildingID::FORT); - } } LRClickableAreaOpenTown::LRClickableAreaOpenTown(const Rect & Pos, const CGTownInstance * Town) - : LRClickableAreaWTextComp(Pos, -1), town(Town) + : LRClickableAreaWTextComp(Pos), town(Town) { } @@ -542,20 +536,21 @@ void MoraleLuckBox::set(const AFactionMember * node) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:} + const std::array textId = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:} const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck - const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat. - const int componentType[] = {CComponent::luck, CComponent::morale}; - const int hoverTextBase[] = {7, 4}; + const std::array neutralDescr = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat. + const std::array componentType = {ComponentType::LUCK, ComponentType::MORALE}; + const std::array hoverTextBase = {7, 4}; TConstBonusListPtr modifierList = std::make_shared(); - bonusValue = 0; + + component.value = 0; if(node) - bonusValue = morale ? node->moraleValAndBonusList(modifierList) : node->luckValAndBonusList(modifierList); + component.value = morale ? node->moraleValAndBonusList(modifierList) : node->luckValAndBonusList(modifierList); - int mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good + int mrlt = (component.value>0)-(component.value<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt]; - baseType = componentType[morale]; + component.type = componentType[morale]; text = CGI->generaltexth->arraytxt[textId[morale]]; boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]); @@ -563,19 +558,19 @@ void MoraleLuckBox::set(const AFactionMember * node) || node->getBonusBearer()->hasBonusOfType(BonusType::NON_LIVING))) { text += CGI->generaltexth->arraytxt[113]; //unaffected by morale - bonusValue = 0; + component.value = 0; } else if(morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_MORALE)) { auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_MORALE)); text += "\n" + noMorale->Description(); - bonusValue = 0; + component.value = 0; } else if (!morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK)) { auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_LUCK)); text += "\n" + noLuck->Description(); - bonusValue = 0; + component.value = 0; } else { @@ -595,7 +590,7 @@ void MoraleLuckBox::set(const AFactionMember * node) else imageName = morale ? "IMRL42" : "ILCK42"; - image = std::make_shared(AnimationPath::builtin(imageName), bonusValue + 3); + image = std::make_shared(AnimationPath::builtin(imageName), *component.value + 3); image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon } @@ -603,7 +598,6 @@ MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r, bool Small) : morale(Morale), small(Small) { - bonusValue = 0; pos = r + pos.topLeft(); defActions = 255-DISPOSE; } diff --git a/client/widgets/MiscWidgets.h b/client/widgets/MiscWidgets.h index 021193e9a..28e306614 100644 --- a/client/widgets/MiscWidgets.h +++ b/client/widgets/MiscWidgets.h @@ -10,6 +10,7 @@ #pragma once #include "../gui/CIntObject.h" +#include "../../lib/networkPacks/Component.h" VCMI_LIB_NAMESPACE_BEGIN @@ -202,13 +203,12 @@ private: class LRClickableAreaWTextComp: public LRClickableAreaWText { public: - int type; - int baseType; - int bonusValue; + Component component; + void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; - LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1); + LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), ComponentType baseType = ComponentType::NONE); std::shared_ptr createComponent() const; }; @@ -263,4 +263,4 @@ class SimpleLine : public CIntObject public: SimpleLine(Point pos1, Point pos2, ColorRGBA color); void showAll(Canvas & to) override; -}; \ No newline at end of file +}; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 8751dcf1e..f1ff6dfee 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -157,7 +157,7 @@ void CBuildingRect::showPopupWindow(const Point & cursorPosition) if (bid < BuildingID::DWELL_FIRST) { CRClickPopup::createAndPush(CInfoWindow::genText(bld->getNameTranslated(), bld->getDescriptionTranslated()), - std::make_shared(CComponent::building, bld->town->faction->getIndex(), bld->bid)); + std::make_shared(ComponentType::BUILDING, BuildingTypeUniqueID(bld->town->faction->getId(), bld->bid))); } else { @@ -860,7 +860,7 @@ void CCastleBuildings::enterBlacksmith(ArtifactID artifactID) void CCastleBuildings::enterBuilding(BuildingID building) { - std::vector> comps(1, std::make_shared(CComponent::building, town->subID, building)); + std::vector> comps(1, std::make_shared(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), building))); LOCPLINT->showInfoDialog( town->town->buildings.find(building)->second->getDescriptionTranslated(), comps); } @@ -920,7 +920,7 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow() void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID upgrades) { - std::vector> comps(1, std::make_shared(CComponent::building,town->getFaction(),building)); + std::vector> comps(1, std::make_shared(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), building))); std::string descr = town->town->buildings.find(building)->second->getDescriptionTranslated(); std::string hasNotProduced; std::string hasProduced; @@ -986,7 +986,7 @@ void CCastleBuildings::enterMagesGuild() CFunctionList onYes = [this](){ openMagesGuild(); }; CFunctionList onNo = onYes; onYes += [hero](){ LOCPLINT->cb->buyArtifact(hero, ArtifactID::SPELLBOOK); }; - std::vector> components(1, std::make_shared(CComponent::artifact,ArtifactID::SPELLBOOK,0)); + std::vector> components(1, std::make_shared(ComponentType::ARTIFACT, ArtifactID(ArtifactID::SPELLBOOK))); LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[214], onYes, onNo, components); } @@ -1129,7 +1129,7 @@ void CCreaInfo::showPopupWindow(const Point & cursorPosition) if (showAvailable) GH.windows().createAndPushWindow(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level); else - CRClickPopup::createAndPush(genGrowthText(), std::make_shared(CComponent::creature, creature->getId())); + CRClickPopup::createAndPush(genGrowthText(), std::make_shared(ComponentType::CREATURE, creature->getId())); } bool CCreaInfo::getShowAvailable() @@ -1180,7 +1180,7 @@ void CTownInfo::showPopupWindow(const Point & cursorPosition) { if(building) { - auto c = std::make_shared(CComponent::building, building->town->faction->getIndex(), building->bid); + auto c = std::make_shared(ComponentType::BUILDING, BuildingTypeUniqueID(building->town->faction->getId(), building->bid)); CRClickPopup::createAndPush(CInfoWindow::genText(building->getNameTranslated(), building->getDescriptionTranslated()), c); } } @@ -1526,15 +1526,22 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin //Create components for all required resources std::vector> components; - for(int i = 0; iresources[i]) { - std::string text = std::to_string(building->resources[i]); - int resAfterBuy = LOCPLINT->cb->getResourceAmount(GameResID(i)) - building->resources[i]; - if(resAfterBuy < 0 && state != EBuildingState::ALREADY_PRESENT && settings["general"]["enableUiEnhancements"].Bool()) - text = "{H3Red|" + std::to_string(LOCPLINT->cb->getResourceAmount(GameResID(i))) + "}" + " / " + text; - components.push_back(std::make_shared(CComponent::resource, i, text, CComponent::small)); + MetaString message; + int resourceAmount = LOCPLINT->cb->getResourceAmount(i); + bool canAfford = resourceAmount >= building->resources[i]; + + if(!canAfford && state != EBuildingState::ALREADY_PRESENT && settings["general"]["enableUiEnhancements"].Bool()) + message.appendRawString("{H3Red|%d}/%d"); + else + message.appendRawString("%d"); + + message.replaceNumber(resourceAmount); + message.replaceNumber(building->resources[i]); + components.push_back(std::make_shared(ComponentType::RESOURCE, i, message.toString(), CComponent::small)); } } @@ -1889,12 +1896,12 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell) void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition) { - LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared(CComponent::spell, spell->id)); + LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared(ComponentType::SPELL, spell->id)); } void CMageGuildScreen::Scroll::showPopupWindow(const Point & cursorPosition) { - CRClickPopup::createAndPush(spell->getDescriptionTranslated(0), std::make_shared(CComponent::spell, spell->id)); + CRClickPopup::createAndPush(spell->getDescriptionTranslated(0), std::make_shared(ComponentType::SPELL, spell->id)); } void CMageGuildScreen::Scroll::hover(bool on) diff --git a/client/windows/CCreatureWindow.cpp b/client/windows/CCreatureWindow.cpp index 0db3a97e1..f6e073f2c 100644 --- a/client/windows/CCreatureWindow.cpp +++ b/client/windows/CCreatureWindow.cpp @@ -325,7 +325,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset) std::vector> resComps; for(TResources::nziterator i(totalCost); i.valid(); i++) { - resComps.push_back(std::make_shared(CComponent::resource, i->resType, (int)i->resVal)); + resComps.push_back(std::make_shared(ComponentType::RESOURCE, i->resType, i->resVal)); } if(LOCPLINT->cb->getResourceAmount().canAfford(totalCost)) @@ -582,10 +582,10 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s const CCommanderInstance * commander = parent->info->commander; expRankIcon = std::make_shared(AnimationPath::builtin("PSKIL42"), 4, 0, pos.x, pos.y); - auto area = std::make_shared(Rect(pos.x, pos.y, 44, 44), CComponent::experience); + auto area = std::make_shared(Rect(pos.x, pos.y, 44, 44), ComponentType::EXPERIENCE); expArea = area; area->text = CGI->generaltexth->allTexts[2]; - area->bonusValue = commander->getExpRank(); + area->component.value = commander->getExpRank(); boost::replace_first(area->text, "%d", std::to_string(commander->getExpRank())); boost::replace_first(area->text, "%d", std::to_string(CGI->heroh->reqExp(commander->getExpRank() + 1))); boost::replace_first(area->text, "%d", std::to_string(commander->experience)); @@ -611,8 +611,8 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s if(art) { parent->stackArtifactIcon = std::make_shared(AnimationPath::builtin("ARTIFACT"), art->artType->getIconIndex(), 0, pos.x, pos.y); - parent->stackArtifactHelp = std::make_shared(Rect(pos, Point(44, 44)), CComponent::artifact); - parent->stackArtifactHelp->type = art->artType->getId(); + parent->stackArtifactHelp = std::make_shared(Rect(pos, Point(44, 44)), ComponentType::ARTIFACT); + parent->stackArtifactHelp->component.subType = art->artType->getId(); if(parent->info->owner) { diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index 6acc90b27..e4e93337d 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -119,9 +119,9 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero) for(int v = 0; v < GameConstants::PRIMARY_SKILLS; ++v) { - auto area = std::make_shared(Rect(30 + 70 * v, 109, 42, 64), CComponent::primskill); + auto area = std::make_shared(Rect(30 + 70 * v, 109, 42, 64), ComponentType::PRIM_SKILL); area->text = CGI->generaltexth->arraytxt[2+v]; - area->type = v; + area->component.subType = PrimarySkill(v); area->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % CGI->generaltexth->primarySkillNames[v]); primSkillAreas.push_back(area); @@ -154,7 +154,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero) for(int i = 0; i < std::min(hero->secSkills.size(), 8u); ++i) { Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), 136, 42); - secSkillAreas.push_back(std::make_shared(r, CComponent::secskill)); + secSkillAreas.push_back(std::make_shared(r, ComponentType::SEC_SKILL)); secSkillImages.push_back(std::make_shared(secSkills, 0, 0, r.x, r.y)); int x = (i % 2) ? 212 : 68; @@ -232,20 +232,21 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) //primary skills support for(size_t g=0; gbonusValue = curHero->getPrimSkillLevel(static_cast(g)); - primSkillValues[g]->setText(std::to_string(primSkillAreas[g]->bonusValue)); + int value = curHero->getPrimSkillLevel(static_cast(g)); + primSkillAreas[g]->component.value = value; + primSkillValues[g]->setText(std::to_string(value)); } //secondary skills support for(size_t g=0; g< secSkillAreas.size(); ++g) { - int skill = curHero->secSkills[g].first; - int level = curHero->getSecSkillLevel(SecondarySkill(curHero->secSkills[g].first)); + SecondarySkill skill = curHero->secSkills[g].first; + int level = curHero->getSecSkillLevel(skill); std::string skillName = CGI->skillh->getByIndex(skill)->getNameTranslated(); std::string skillValue = CGI->generaltexth->levels[level-1]; - secSkillAreas[g]->type = skill; - secSkillAreas[g]->bonusValue = level; + secSkillAreas[g]->component.subType = skill; + secSkillAreas[g]->component.value = level; secSkillAreas[g]->text = CGI->skillh->getByIndex(skill)->getDescriptionTranslated(level); secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % skillValue % skillName); secSkillImages[g]->setFrame(skill*3 + level + 2); diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index 85d157bbe..4be0b5569 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -256,7 +256,7 @@ void InfoBoxAbstractHeroData::prepareMessage(std::string & text, std::shared_ptr break; case HERO_PRIMARY_SKILL: text = CGI->generaltexth->arraytxt[2+getSubID()]; - comp = std::make_shared(CComponent::primskill, getSubID(), (int)getValue()); + comp = std::make_shared(ComponentType::PRIM_SKILL, PrimarySkill(getSubID()), getValue()); break; case HERO_MANA: text = CGI->generaltexth->allTexts[149]; @@ -271,7 +271,7 @@ void InfoBoxAbstractHeroData::prepareMessage(std::string & text, std::shared_ptr if(value) { text = CGI->skillh->getByIndex(subID)->getDescriptionTranslated((int)value); - comp = std::make_shared(CComponent::secskill, subID, (int)value); + comp = std::make_shared(ComponentType::SEC_SKILL, SecondarySkill(subID), (int)value); } break; } diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index bc43ea654..5fb2f1a8d 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -558,7 +558,7 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition) //battle spell on adv map or adventure map spell during combat => display infowindow, not cast if((combatSpell ^ inCombat) || inCastle) { - std::vector> hlp(1, std::make_shared(CComponent::spell, mySpell->id, 0)); + std::vector> hlp(1, std::make_shared(ComponentType::SPELL, mySpell->id)); LOCPLINT->showInfoDialog(mySpell->getDescriptionTranslated(schoolLevel), hlp); } else if(combatSpell) @@ -614,7 +614,7 @@ void CSpellWindow::SpellArea::showPopupWindow(const Point & cursorPosition) boost::algorithm::replace_first(dmgInfo, "%d", std::to_string(causedDmg)); } - CRClickPopup::createAndPush(mySpell->getDescriptionTranslated(schoolLevel) + dmgInfo, std::make_shared(CComponent::spell, mySpell->id)); + CRClickPopup::createAndPush(mySpell->getDescriptionTranslated(schoolLevel) + dmgInfo, std::make_shared(ComponentType::SPELL, mySpell->id)); } } diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index dd06d2dab..34824e619 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -401,7 +401,7 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill pskill, std std::vector> comps; for(auto & skill : skills) { - auto comp = std::make_shared(CComponent::secskill, skill, hero->getSecSkillLevel(SecondarySkill(skill))+1, CComponent::medium); + auto comp = std::make_shared(ComponentType::SEC_SKILL, skill, hero->getSecSkillLevel(SecondarySkill(skill))+1, CComponent::medium); comp->onChoose = std::bind(&CLevelWindow::close, this); comps.push_back(comp); } @@ -693,9 +693,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, else primSkillAreas[g]->pos = Rect(Point(pos.x + 329, pos.y + 19 + 36 * g), Point(140, 32)); primSkillAreas[g]->text = CGI->generaltexth->arraytxt[2+g]; - primSkillAreas[g]->type = g; - primSkillAreas[g]->bonusValue = 0; - primSkillAreas[g]->baseType = 0; + primSkillAreas[g]->component = Component( ComponentType::PRIM_SKILL, PrimarySkill(g)); primSkillAreas[g]->hoverText = CGI->generaltexth->heroscrn[1]; boost::replace_first(primSkillAreas[g]->hoverText, "%s", CGI->generaltexth->primarySkillNames[g]); } @@ -708,14 +706,11 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, //secondary skill's clickable areas for(int g=0; gsecSkills.size(); ++g) { - int skill = hero->secSkills[g].first, - level = hero->secSkills[g].second; // <1, 3> + SecondarySkill skill = hero->secSkills[g].first; + int level = hero->secSkills[g].second; // <1, 3> secSkillAreas[b].push_back(std::make_shared()); secSkillAreas[b][g]->pos = Rect(Point(pos.x + 32 + g * 36 + b * 454 , pos.y + (qeLayout ? 83 : 88)), Point(32, 32) ); - secSkillAreas[b][g]->baseType = 1; - - secSkillAreas[b][g]->type = skill; - secSkillAreas[b][g]->bonusValue = level; + secSkillAreas[b][g]->component = Component(ComponentType::SEC_SKILL, skill, level); secSkillAreas[b][g]->text = CGI->skillh->getByIndex(skill)->getDescriptionTranslated(level); secSkillAreas[b][g]->hoverText = CGI->generaltexth->heroscrn[21]; @@ -1082,7 +1077,7 @@ void CUniversityWindow::CItem::clickPressed(const Point & cursorPosition) void CUniversityWindow::CItem::showPopupWindow(const Point & cursorPosition) { - CRClickPopup::createAndPush(CGI->skillh->getByIndex(ID)->getDescriptionTranslated(1), std::make_shared(CComponent::secskill, ID, 1)); + CRClickPopup::createAndPush(CGI->skillh->getByIndex(ID)->getDescriptionTranslated(1), std::make_shared(ComponentType::SEC_SKILL, ID, 1)); } void CUniversityWindow::CItem::hover(bool on) diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index 5580c5a36..07b47b8eb 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -375,7 +375,7 @@ class CUniversityWindow : public CStatusbarWindow std::shared_ptr name; std::shared_ptr level; public: - int ID;//id of selected skill + SecondarySkill ID;//id of selected skill CUniversityWindow * parent; void showAll(Canvas & to) override; diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index b72f16521..1a75578cc 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -1017,6 +1017,11 @@ const Creature * CStackBasicDescriptor::getType() const return type; } +CreatureID CStackBasicDescriptor::getId() const +{ + return type->getId(); +} + TQuantity CStackBasicDescriptor::getCount() const { return count; diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index 752eb203f..9b3cad26c 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -39,6 +39,7 @@ public: virtual ~CStackBasicDescriptor() = default; const Creature * getType() const; + CreatureID getId() const; TQuantity getCount() const; virtual void setType(const CCreature * c); diff --git a/lib/constants/EntityIdentifiers.cpp b/lib/constants/EntityIdentifiers.cpp index 95d56a267..722033f51 100644 --- a/lib/constants/EntityIdentifiers.cpp +++ b/lib/constants/EntityIdentifiers.cpp @@ -458,6 +458,21 @@ std::string GameResID::entityType() return "resource"; } +const std::array & GameResID::ALL_RESOURCES() +{ + static const std::array allResources = { + GameResID(WOOD), + GameResID(MERCURY), + GameResID(ORE), + GameResID(SULFUR), + GameResID(CRYSTAL), + GameResID(GEMS), + GameResID(GOLD) + }; + + return allResources; +} + std::string SecondarySkill::entityType() { return "secondarySkill"; diff --git a/lib/constants/EntityIdentifiers.h b/lib/constants/EntityIdentifiers.h index 1ff20c597..2a0aaf2ca 100644 --- a/lib/constants/EntityIdentifiers.h +++ b/lib/constants/EntityIdentifiers.h @@ -960,9 +960,11 @@ public: static si32 decode(const std::string & identifier); static std::string encode(const si32 index); static std::string entityType(); + + static const std::array & ALL_RESOURCES(); }; -class BuildingTypeUniqueID : public Identifier +class DLL_LINKAGE BuildingTypeUniqueID : public Identifier { public: BuildingTypeUniqueID(FactionID faction, BuildingID building ); diff --git a/lib/mapObjects/CBank.cpp b/lib/mapObjects/CBank.cpp index 849d171c6..7a6634326 100644 --- a/lib/mapObjects/CBank.cpp +++ b/lib/mapObjects/CBank.cpp @@ -79,11 +79,7 @@ std::vector CBank::getPopupComponents(PlayerColor player) const for (auto const & guard : guardsAmounts) { - Component comp; - comp.id = Component::EComponentType::CREATURE; - comp.subtype = guard.first.getNum(); - comp.val = guard.second; - + Component comp(ComponentType::CREATURE, guard.first, guard.second); result.push_back(comp); } return result; @@ -236,7 +232,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const break; } cb->giveHeroBonus(&gbonus); - iw.components.emplace_back(Component::EComponentType::MORALE, 0, -1, 0); + iw.components.emplace_back(ComponentType::MORALE, -1); iw.soundID = soundBase::GRAVEYARD; break; } @@ -247,7 +243,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const gb.id = hero->id.getNum(); cb->giveHeroBonus(&gb); textID = 107; - iw.components.emplace_back(Component::EComponentType::LUCK, 0, -2, 0); + iw.components.emplace_back(ComponentType::LUCK, -2); break; } case Obj::CREATURE_BANK: @@ -267,21 +263,21 @@ void CBank::doVisit(const CGHeroInstance * hero) const //grant resources if (bc) { - for (int it = 0; it < bc->resources.size(); it++) + for (GameResID it : GameResID::ALL_RESOURCES()) { if (bc->resources[it] != 0) { - iw.components.emplace_back(Component::EComponentType::RESOURCE, it, bc->resources[it], 0); + iw.components.emplace_back(ComponentType::RESOURCE, it, bc->resources[it]); loot.appendRawString("%d %s"); - loot.replaceNumber(iw.components.back().val); - loot.replaceLocalString(EMetaText::RES_NAMES, iw.components.back().subtype); + loot.replaceNumber(bc->resources[it]); + loot.replaceLocalString(EMetaText::RES_NAMES, it); cb->giveResource(hero->getOwner(), static_cast(it), bc->resources[it]); } } //grant artifacts for (auto & elem : bc->artifacts) { - iw.components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0); + iw.components.emplace_back(ComponentType::ARTIFACT, elem); loot.appendRawString("%s"); loot.replaceLocalString(EMetaText::ART_NAMES, elem); cb->giveHeroNewArtifact(hero, VLC->arth->objects[elem], ArtifactPosition::FIRST_AVAILABLE); @@ -325,7 +321,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const if(hero->canLearnSpell(spell)) { spells.insert(spellId); - iw.components.emplace_back(Component::EComponentType::SPELL, spellId, 0, 0); + iw.components.emplace_back(ComponentType::SPELL, spellId); } } else @@ -356,7 +352,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const for(const auto & elem : ourArmy.Slots()) { - iw.components.emplace_back(*elem.second); + iw.components.emplace_back(ComponentType::CREATURE, elem.second->getId(), elem.second->getCount()); loot.appendRawString("%s"); loot.replaceCreatureName(*elem.second); } diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index 2aa2563d2..7fbaaabba 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -563,17 +563,17 @@ void CGCreature::giveReward(const CGHeroInstance * h) const if(!resources.empty()) { cb->giveResources(h->tempOwner, resources); - for(int i = 0; i < resources.size(); i++) + for(auto const & res : GameResID::ALL_RESOURCES()) { - if(resources[i] > 0) - iw.components.emplace_back(Component::EComponentType::RESOURCE, i, resources[i], 0); + if(resources[res] > 0) + iw.components.emplace_back(ComponentType::RESOURCE, res, resources[res]); } } if(gainedArtifact != ArtifactID::NONE) { cb->giveHeroNewArtifact(h, VLC->arth->objects[gainedArtifact], ArtifactPosition::FIRST_AVAILABLE); - iw.components.emplace_back(Component::EComponentType::ARTIFACT, gainedArtifact, 0, 0); + iw.components.emplace_back(ComponentType::ARTIFACT, gainedArtifact); } if(!iw.components.empty()) diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 870e10c8f..d9cd4b6c6 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -944,7 +944,7 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta iw.type = EInfoWindowMode::AUTO; iw.soundID = soundBase::pickup01 + rand.nextInt(6); iw.player = tempOwner; - iw.components.emplace_back(raisedStack); + iw.components.emplace_back(ComponentType::CREATURE, raisedStack.getId(), raisedStack.count); if (raisedStack.count > 1) // Practicing the dark arts of necromancy, ... (plural) { diff --git a/lib/mapObjects/CGTownBuilding.cpp b/lib/mapObjects/CGTownBuilding.cpp index b449dc0e0..1406786f9 100644 --- a/lib/mapObjects/CGTownBuilding.cpp +++ b/lib/mapObjects/CGTownBuilding.cpp @@ -207,31 +207,31 @@ void CTownBonus::onHeroVisit (const CGHeroInstance * h) const case BuildingSubID::KNOWLEDGE_VISITING_BONUS: //wall of knowledge what = PrimarySkill::KNOWLEDGE; val = 1; - iw.components.emplace_back(Component::EComponentType::PRIM_SKILL, 3, 1, 0); + iw.components.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill::KNOWLEDGE, 1); break; case BuildingSubID::SPELL_POWER_VISITING_BONUS: //order of fire what = PrimarySkill::SPELL_POWER; val = 1; - iw.components.emplace_back(Component::EComponentType::PRIM_SKILL, 2, 1, 0); + iw.components.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill::SPELL_POWER, 1); break; case BuildingSubID::ATTACK_VISITING_BONUS: //hall of Valhalla what = PrimarySkill::ATTACK; val = 1; - iw.components.emplace_back(Component::EComponentType::PRIM_SKILL, 0, 1, 0); + iw.components.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill::ATTACK, 1); break; case BuildingSubID::EXPERIENCE_VISITING_BONUS: //academy of battle scholars what = PrimarySkill::EXPERIENCE; val = static_cast(h->calculateXp(1000)); - iw.components.emplace_back(Component::EComponentType::EXPERIENCE, 0, val, 0); + iw.components.emplace_back(ComponentType::EXPERIENCE, val); break; case BuildingSubID::DEFENSE_VISITING_BONUS: //cage of warlords what = PrimarySkill::DEFENSE; val = 1; - iw.components.emplace_back(Component::EComponentType::PRIM_SKILL, 1, 1, 0); + iw.components.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill::DEFENSE, 1); break; case BuildingSubID::CUSTOM_VISITING_BONUS: diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index f0243e86a..0f41e30e8 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -325,7 +325,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const InfoWindow iw; iw.player = h->tempOwner; iw.text.appendRawString(h->commander->getName()); - iw.components.emplace_back(*h->commander); + iw.components.emplace_back(ComponentType::CREATURE, h->commander->getId(), h->commander->getCount()); cb->showInfoDialog(&iw); } } diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index a489b5171..640641685 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -204,13 +204,13 @@ void CQuest::addTextReplacements(MetaString & text, std::vector & com if(killTarget != ObjectInstanceID::NONE && !heroName.empty()) { - components.emplace_back(Component::EComponentType::HERO_PORTRAIT, heroPortrait, 0, 0); + components.emplace_back(ComponentType::HERO_PORTRAIT, heroPortrait); addKillTargetReplacements(text); } if(killTarget != ObjectInstanceID::NONE && stackToKill.type) { - components.emplace_back(stackToKill); + components.emplace_back(ComponentType::CREATURE, stackToKill.getId(), stackToKill.getCount()); addKillTargetReplacements(text); } diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 19193d39f..39506c80a 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -169,7 +169,7 @@ void CGMine::flagMine(const PlayerColor & player) const iw.soundID = soundBase::FLAGMINE; iw.text.appendLocalString(EMetaText::MINE_EVNTS, producedResource); //not use subID, abandoned mines uses default mine texts iw.player = player; - iw.components.emplace_back(Component::EComponentType::RESOURCE, producedResource, producedQuantity, -1); + iw.components.emplace_back(ComponentType::RESOURCE_PER_DAY, producedResource, producedQuantity); cb->showInfoDialog(&iw); } @@ -324,7 +324,7 @@ void CGResource::collectRes(const PlayerColor & player) const sii.text.appendLocalString(EMetaText::ADVOB_TXT,113); sii.text.replaceLocalString(EMetaText::RES_NAMES, resourceID()); } - sii.components.emplace_back(Component::EComponentType::RESOURCE, resourceID(), amount, 0); + sii.components.emplace_back(ComponentType::RESOURCE, resourceID(), amount); sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6); cb->showInfoDialog(&sii); cb->removeObject(this, player); @@ -666,7 +666,7 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const iw.type = EInfoWindowMode::AUTO; iw.player = h->tempOwner; iw.text.appendLocalString(EMetaText::ADVOB_TXT, 168); - iw.components.emplace_back(CStackBasicDescriptor(h->getCreature(targetstack), -countToTake)); + iw.components.emplace_back(ComponentType::CREATURE, h->getCreature(targetstack)->getId(), -countToTake); cb->showInfoDialog(&iw); cb->changeStackCount(StackLocation(h, targetstack), -countToTake); } @@ -790,7 +790,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const { case Obj::ARTIFACT: { - iw.components.emplace_back(Component::EComponentType::ARTIFACT, getArtifact(), 0, 0); + iw.components.emplace_back(ComponentType::ARTIFACT, getArtifact()); if(!message.empty()) iw.text = message; else @@ -800,7 +800,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const case Obj::SPELL_SCROLL: { int spellID = storedArtifact->getScrollSpellID(); - iw.components.emplace_back(Component::EComponentType::SPELL, spellID, 0, 0); + iw.components.emplace_back(ComponentType::SPELL, spellID); if(!message.empty()) iw.text = message; else diff --git a/lib/networkPacks/Component.h b/lib/networkPacks/Component.h index fa764e085..43ec61277 100644 --- a/lib/networkPacks/Component.h +++ b/lib/networkPacks/Component.h @@ -9,44 +9,67 @@ */ #pragma once +#include "../constants/VariantIdentifier.h" +#include "../constants/EntityIdentifiers.h" + VCMI_LIB_NAMESPACE_BEGIN -class CStackBasicDescriptor; +enum class ComponentType : int8_t +{ + NONE = -1, + PRIM_SKILL, + SEC_SKILL, + RESOURCE, + RESOURCE_PER_DAY, + CREATURE, + ARTIFACT, + SPELL_SCROLL, + MANA, + EXPERIENCE, + LEVEL, + SPELL, + MORALE, + LUCK, + BUILDING, + HERO_PORTRAIT, + FLAG +}; + +using ComponentSubType = VariantIdentifier; struct Component { - enum class EComponentType : uint8_t - { - PRIM_SKILL, - SEC_SKILL, - RESOURCE, - CREATURE, - ARTIFACT, - EXPERIENCE, - SPELL, - MORALE, - LUCK, - BUILDING, - HERO_PORTRAIT, - FLAG, - INVALID //should be last - }; - EComponentType id = EComponentType::INVALID; - ui16 subtype = 0; //id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels - si32 val = 0; // + give; - take - si16 when = 0; // 0 - now; +x - within x days; -x - per x days + ComponentType type = ComponentType::NONE; + ComponentSubType subType; + std::optional value; // + give; - take template void serialize(Handler &h, const int version) { - h & id; - h & subtype; - h & val; - h & when; + h & type; + h & subType; + h & value; } + Component() = default; - DLL_LINKAGE explicit Component(const CStackBasicDescriptor &stack); - Component(Component::EComponentType Type, ui16 Subtype, si32 Val, si16 When) - :id(Type),subtype(Subtype),val(Val),when(When) + + template, bool> = true> + Component(ComponentType type, Numeric value) + : type(type) + , value(value) + { + } + + template, bool> = true> + Component(ComponentType type, IdentifierType subType) + : type(type) + , subType(subType) + { + } + + Component(ComponentType type, ComponentSubType subType, int32_t value) + : type(type) + , subType(subType) + , value(value) { } }; diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 147e99f81..da35e7298 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -2522,13 +2522,6 @@ void TurnTimeUpdate::applyGs(CGameState *gs) const playerState.turnTimer = turnTimer; } -Component::Component(const CStackBasicDescriptor & stack) - : id(EComponentType::CREATURE) - , subtype(stack.type->getId()) - , val(stack.count) -{ -} - void EntitiesChanged::applyGs(CGameState * gs) { for(const auto & change : changes) diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index aadf30285..8cfb9e81e 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -201,7 +201,7 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand CreatureID from(VLC->identifiers()->getIdentifier(node.second.meta, "creature", node.first).value()); CreatureID dest(VLC->identifiers()->getIdentifier(node.second.meta, "creature", node.second.String()).value()); - reward.extraComponents.emplace_back(Component::EComponentType::CREATURE, dest.getNum(), 0, 0); + reward.extraComponents.emplace_back(ComponentType::CREATURE, dest.getNum()); reward.creaturesChange[from] = dest; } diff --git a/lib/rewardable/Limiter.cpp b/lib/rewardable/Limiter.cpp index ae6602231..6f78d4868 100644 --- a/lib/rewardable/Limiter.cpp +++ b/lib/rewardable/Limiter.cpp @@ -187,49 +187,45 @@ void Rewardable::Limiter::loadComponents(std::vector & comps, const CGHeroInstance * h) const { if (heroExperience) - comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast(h->calculateXp(heroExperience)), 0); + comps.emplace_back(ComponentType::EXPERIENCE, static_cast(h->calculateXp(heroExperience))); if (heroLevel > 0) - comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0); + comps.emplace_back(ComponentType::EXPERIENCE, heroLevel); if (manaPoints || manaPercentage > 0) { int absoluteMana = h->manaLimit() ? (manaPercentage * h->mana / h->manaLimit() / 100) : 0; - comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, absoluteMana + manaPoints, 0); + comps.emplace_back(ComponentType::MANA, absoluteMana + manaPoints); } for (size_t i=0; i(i), primary[i], 0); + comps.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill(i), primary[i]); } for(const auto & entry : secondary) - comps.emplace_back(Component::EComponentType::SEC_SKILL, entry.first, entry.second, 0); + comps.emplace_back(ComponentType::SEC_SKILL, entry.first, entry.second); for(const auto & entry : artifacts) - comps.emplace_back(Component::EComponentType::ARTIFACT, entry, 1, 0); + comps.emplace_back(ComponentType::ARTIFACT, entry); for(const auto & entry : spells) - comps.emplace_back(Component::EComponentType::SPELL, entry, 1, 0); + comps.emplace_back(ComponentType::SPELL, entry); for(const auto & entry : creatures) - comps.emplace_back(Component::EComponentType::CREATURE, entry.type->getId(), entry.count, 0); + comps.emplace_back(ComponentType::CREATURE, entry.type->getId(), entry.count); for(const auto & entry : players) - comps.emplace_back(Component::EComponentType::FLAG, entry, 0, 0); + comps.emplace_back(ComponentType::FLAG, entry); - //FIXME: portrait may not match hero, if custom portrait was set in map editor for(const auto & entry : heroes) - comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroTypes()->getById(entry)->getIconIndex(), 0, 0); + comps.emplace_back(ComponentType::HERO_PORTRAIT, entry); - for(const auto & entry : heroClasses) - comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroClasses()->getById(entry)->getIconIndex(), 0, 0); - for (size_t i=0; i(i), resources[i], 0); + comps.emplace_back(ComponentType::RESOURCE, GameResID(i), resources[i]); } } diff --git a/lib/rewardable/Reward.cpp b/lib/rewardable/Reward.cpp index cb080adca..135206d90 100644 --- a/lib/rewardable/Reward.cpp +++ b/lib/rewardable/Reward.cpp @@ -74,42 +74,42 @@ void Rewardable::Reward::loadComponents(std::vector & comps, const CG for (auto & bonus : bonuses) { if (bonus.type == BonusType::MORALE) - comps.emplace_back(Component::EComponentType::MORALE, 0, bonus.val, 0); + comps.emplace_back(ComponentType::MORALE, bonus.val); if (bonus.type == BonusType::LUCK) - comps.emplace_back(Component::EComponentType::LUCK, 0, bonus.val, 0); + comps.emplace_back(ComponentType::LUCK, bonus.val); } if (heroExperience) - comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast(h ? h->calculateXp(heroExperience) : heroExperience), 0); + comps.emplace_back(ComponentType::EXPERIENCE, static_cast(h ? h->calculateXp(heroExperience) : heroExperience)); if (heroLevel) - comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0); + comps.emplace_back(ComponentType::LEVEL, heroLevel); if (manaDiff || manaPercentage >= 0) - comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, h ? (calculateManaPoints(h) - h->mana) : manaDiff, 0); + comps.emplace_back(ComponentType::MANA, h ? (calculateManaPoints(h) - h->mana) : manaDiff); for (size_t i=0; i(i), primary[i], 0); + comps.emplace_back(ComponentType::PRIM_SKILL, PrimarySkill(i), primary[i]); } for(const auto & entry : secondary) - comps.emplace_back(Component::EComponentType::SEC_SKILL, entry.first, entry.second, 0); + comps.emplace_back(ComponentType::SEC_SKILL, entry.first, entry.second); for(const auto & entry : artifacts) - comps.emplace_back(Component::EComponentType::ARTIFACT, entry, 1, 0); + comps.emplace_back(ComponentType::ARTIFACT, entry); for(const auto & entry : spells) - comps.emplace_back(Component::EComponentType::SPELL, entry, 1, 0); + comps.emplace_back(ComponentType::SPELL, entry); for(const auto & entry : creatures) - comps.emplace_back(Component::EComponentType::CREATURE, entry.type->getId(), entry.count, 0); + comps.emplace_back(ComponentType::CREATURE, entry.type->getId(), entry.count); for (size_t i=0; i(i), resources[i], 0); + comps.emplace_back(ComponentType::RESOURCE, GameResID(i), resources[i]); } } diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index 7e1e3c19e..2f8b056b3 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -528,8 +528,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons request.player = parameters.caster->getCasterOwner(); request.title.appendLocalString(EMetaText::JK_TXT, 40); request.description.appendLocalString(EMetaText::JK_TXT, 41); - request.icon.id = Component::EComponentType::SPELL; - request.icon.subtype = owner->id.toEnum(); + request.icon = Component(ComponentType::SPELL, owner->id); env->genericQuery(&request, request.player, queryCallback); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index c702f35ee..a8134dfe4 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1571,11 +1571,12 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t if (!cs1.spells.empty() || !cs2.spells.empty())//create a message { - int ScholarSkillLevel = std::max(h1->getSecSkillLevel(SecondarySkill::SCHOLAR), - h2->getSecSkillLevel(SecondarySkill::SCHOLAR)); + SecondarySkill scholarSkill = SecondarySkill::SCHOLAR; + + int scholarSkillLevel = std::max(h1->getSecSkillLevel(scholarSkill), h2->getSecSkillLevel(scholarSkill)); InfoWindow iw; iw.player = h1->tempOwner; - iw.components.emplace_back(Component::EComponentType::SEC_SKILL, 18, ScholarSkillLevel, 0); + iw.components.emplace_back(ComponentType::SEC_SKILL, scholarSkill, scholarSkillLevel); iw.text.appendLocalString(EMetaText::GENERAL_TXT, 139);//"%s, who has studied magic extensively, iw.text.replaceRawString(h1->getNameTranslated()); @@ -1586,7 +1587,7 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t int size = static_cast(cs2.spells.size()); for (auto it : cs2.spells) { - iw.components.emplace_back(Component::EComponentType::SPELL, it, 1, 0); + iw.components.emplace_back(ComponentType::SPELL, it); iw.text.appendLocalString(EMetaText::SPELL_NAME, it.toEnum()); switch (size--) { @@ -1614,7 +1615,7 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t int size = static_cast(cs1.spells.size()); for (auto it : cs1.spells) { - iw.components.emplace_back(Component::EComponentType::SPELL, it, 1, 0); + iw.components.emplace_back(ComponentType::SPELL, it); iw.text.appendLocalString(EMetaText::SPELL_NAME, it.toEnum()); switch (size--) { @@ -3216,10 +3217,10 @@ void CGameHandler::handleTimeEvents() iw.player = color; iw.text = ev.message; - for (int i=0; iresources[i] != n.res.at(player)[i]) //if resource had changed, we add it to the dialog - iw.components.emplace_back(Component::EComponentType::RESOURCE,i,n.res.at(player)[i]-was[i],0); - + iw.components.emplace_back(ComponentType::RESOURCE, i, n.res.at(player)[i] - was[i]); } for (auto & i : ev.buildings) @@ -3284,7 +3284,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n) if (!town->hasBuilt(i)) { buildStructure(town->id, i, true); - iw.components.emplace_back(Component::EComponentType::BUILDING, town->getFaction(), i, 0); + iw.components.emplace_back(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), i)); } } @@ -3300,8 +3300,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n) if (!town->creatures.at(i).second.empty() && ev.creatures.at(i) > 0)//there is dwelling { sac.creatures[i].first += ev.creatures.at(i); - iw.components.emplace_back(Component::EComponentType::CREATURE, - town->creatures.at(i).second.back(), ev.creatures.at(i), 0); + iw.components.emplace_back(ComponentType::CREATURE, town->creatures.at(i).second.back(), ev.creatures.at(i)); } } sendAndApply(&iw); //show dialog @@ -3641,7 +3640,7 @@ void CGameHandler::getVictoryLossMessage(PlayerColor player, const EVictoryLossC out.player = player; out.text = victoryLossCheckResult.messageToSelf; out.text.replaceLocalString(EMetaText::COLOR, player.getNum()); - out.components.emplace_back(Component::EComponentType::FLAG, player.getNum(), 0, 0); + out.components.emplace_back(ComponentType::FLAG, player); } bool CGameHandler::dig(const CGHeroInstance *h) @@ -3669,7 +3668,7 @@ bool CGameHandler::dig(const CGHeroInstance *h) sendAndApply(&iw); iw.soundID = soundBase::invalid; - iw.components.emplace_back(Component::EComponentType::ARTIFACT, ArtifactID::GRAIL, 0, 0); + iw.components.emplace_back(ComponentType::ARTIFACT, ArtifactID(ArtifactID::GRAIL)); iw.text.clear(); iw.text.appendLocalString(EMetaText::ART_DESCR, ArtifactID::GRAIL); sendAndApply(&iw); @@ -4144,7 +4143,7 @@ const CGHeroInstance * CGameHandler::getVisitingHero(const CGObjectInstance *obj { assert(obj); - for (auto const & query : queries->allQueries()) + for(const auto & query : queries->allQueries()) { auto visit = std::dynamic_pointer_cast(query); if (visit && visit->visitedObject == obj) diff --git a/server/battles/BattleResultProcessor.cpp b/server/battles/BattleResultProcessor.cpp index 4b3f60491..99e50d389 100644 --- a/server/battles/BattleResultProcessor.cpp +++ b/server/battles/BattleResultProcessor.cpp @@ -419,9 +419,11 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle) for (auto art : arts) //TODO; separate function to display loot for various ojects? { - iw.components.emplace_back( - Component::EComponentType::ARTIFACT, art->artType->getId(), - art->artType->getId() == ArtifactID::SPELL_SCROLL? art->getScrollSpellID() : SpellID(0), 0); + if (art->artType->getId() == ArtifactID::SPELL_SCROLL) + iw.components.emplace_back(ComponentType::SPELL_SCROLL, art->getScrollSpellID()); + else + iw.components.emplace_back(ComponentType::ARTIFACT, art->artType->getId()); + if (iw.components.size() >= 14) { gameHandler->sendAndApply(&iw); @@ -463,7 +465,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle) iw.text.replaceLocalString(EMetaText::SPELL_NAME, it->toEnum()); if (i == cs.spells.size() - 2) //we just added pre-last name iw.text.replaceLocalString(EMetaText::GENERAL_TXT, 141); // " and " - iw.components.emplace_back(Component::EComponentType::SPELL, *it, 0, 0); + iw.components.emplace_back(ComponentType::SPELL, *it); } gameHandler->sendAndApply(&iw); gameHandler->sendAndApply(&cs);