1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Converted Component class to use VariantIdentifier instead of int

This commit is contained in:
Ivan Savenko 2023-10-31 11:09:56 +02:00
parent 0376873cb3
commit 10e50548e7
36 changed files with 435 additions and 363 deletions

View File

@ -664,7 +664,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
// TODO: Find better way to understand it is Chest of Treasures
if(hero.validAndSet()
&& components.size() == 2
&& components.front().id == Component::EComponentType::RESOURCE
&& components.front().type == ComponentType::RESOURCE
&& (nullkiller->heroManager->getHeroRole(hero) != HeroRole::MAIN
|| nullkiller->buildAnalyzer->getGoldPreasure() > MAX_GOLD_PEASURE))
{

View File

@ -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<std::shared_ptr<CComponent>> cmp;
cmp.push_back(std::make_shared<CComponent>(CComponent::flag, playerID.getNum(), 0));
cmp.push_back(std::make_shared<CComponent>(ComponentType::FLAG, playerID));
showInfoDialog(msg, cmp);
}
else
@ -326,7 +326,7 @@ void CPlayerInterface::acceptTurn(QueryID queryID)
auto playerColor = *cb->getPlayerID();
std::vector<Component> 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>(CComponent::artifact, assembledArtifact->getIndex(), 0);
auto sc = std::make_shared<CComponent>(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<std::shared_ptr<CComponent>> cmp;
cmp.push_back(std::make_shared<CComponent>(CComponent::flag, playerID.getNum(), 0));
cmp.push_back(std::make_shared<CComponent>(ComponentType::FLAG, playerID));
makingTurn = true; //workaround for stiff showInfoDialog implementation
showInfoDialog(msg, cmp);
makingTurn = false;

View File

@ -376,47 +376,51 @@ void CInfoBar::pushComponents(const std::vector<Component> & components, std::st
std::array<std::pair<std::vector<Component>, 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;

View File

@ -571,7 +571,7 @@ void OptionsTab::CPlayerOptionTooltipBox::genTownWindow()
for(auto & elem : town->creatures)
{
if(!elem.empty())
components.push_back(std::make_shared<CComponent>(CComponent::creature, elem.front(), 0, CComponent::tiny));
components.push_back(std::make_shared<CComponent>(ComponentType::CREATURE, elem.front(), 0, CComponent::tiny));
}
boxAssociatedCreatures = std::make_shared<CComponentBox>(components, Rect(10, 140, pos.w - 20, 140));
}

View File

@ -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();
}

View File

@ -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<int32_t> 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<int32_t> 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<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(max, pos.w), font);
@ -115,151 +109,207 @@ void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize, EFonts
std::vector<AnimationPath> 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<std::string, 4> primSkillsArr = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"};
static const std::array<std::string, 4> secSkillsArr = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"};
static const std::array<std::string, 4> resourceArr = {"SMALRES", "RESOURCE", "RESOURCE", "RESOUR82"};
static const std::array<std::string, 4> creatureArr = {"CPRSMALL", "CPRSMALL", "CPRSMALL", "TWCRPORT"};
static const std::array<std::string, 4> artifactArr = {"Artifact", "Artifact", "Artifact", "Artifact"};
static const std::array<std::string, 4> spellsArr = {"SpellInt", "SpellInt", "SpellInt", "SPELLSCR"};
static const std::array<std::string, 4> moraleArr = {"IMRL22", "IMRL30", "IMRL42", "imrl82"};
static const std::array<std::string, 4> luckArr = {"ILCK22", "ILCK30", "ILCK42", "ilck82"};
static const std::array<std::string, 4> heroArr = {"PortraitsSmall", "PortraitsSmall", "PortraitsSmall", "PortraitsLarge"};
static const std::array<std::string, 4> flagArr = {"CREST58", "CREST58", "CREST58", "CREST58"};
auto gen = [](const std::string * arr) -> std::vector<AnimationPath>
auto gen = [](const std::array<std::string, 4> & arr) -> std::vector<AnimationPath>
{
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<AnimationPath>(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<AnimationPath>(4, (*CGI->townh)[data.subType.as<BuildingTypeUniqueID>().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<CreatureID>())->getIconIndex();
case ComponentType::ARTIFACT:
return CGI->artifacts()->getById(data.subType.as<ArtifactID>())->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<BuildingTypeUniqueID>().getBuilding();
case ComponentType::HERO_PORTRAIT:
return CGI->heroTypes()->getById(data.subType.as<HeroTypeID>())->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<ArtifactID>())->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<SpellID>());
return description;
}
return description;
case ComponentType::SPELL:
return VLC->spells()->getById(data.subType.as<SpellID>())->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<BuildingTypeUniqueID>();
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<SecondarySkill>())->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<CreatureID>());
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<ArtifactID>())->getNameTranslated();
case ComponentType::SPELL_SCROLL:
case ComponentType::SPELL:
return CGI->spells()->getById(data.subType.as<SpellID>())->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<BuildingTypeUniqueID>();
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<PlayerColor>().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<voi
init();
}
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
CSelectableComponent::CSelectableComponent(ComponentType Type, ComponentSubType Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
{
setRedrawParent(true);

View File

@ -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<AnimationPath> 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<int32_t> Val, ESize imageSize, EFonts font = FONT_SMALL, std::string ValText="");
public:
std::shared_ptr<CAnimImage> 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<int32_t> 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<void()> OnSelect = nullptr);
CSelectableComponent(ComponentType Type, ComponentSubType Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr);
CSelectableComponent(const Component & c, std::function<void()> OnSelect = nullptr);
};

View File

@ -95,7 +95,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
if(artPlace.getArt()->getTypeId() == ArtifactID::CATAPULT)
{
// The Catapult must be equipped
std::vector<std::shared_ptr<CComponent>> catapult(1, std::make_shared<CComponent>(CComponent::artifact, 3, 0));
std::vector<std::shared_ptr<CComponent>> catapult(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, ArtifactID(ArtifactID::CATAPULT)));
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[312], catapult);
return false;
}

View File

@ -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<CComponent> LRClickableAreaWTextComp::createComponent() const
{
if(baseType >= 0)
return std::make_shared<CComponent>(CComponent::Etype(baseType), type, bonusValue);
if(component.type != ComponentType::NONE)
return std::make_shared<CComponent>(component);
else
return std::shared_ptr<CComponent>();
}
@ -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<const BonusList>();
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<CAnimImage>(AnimationPath::builtin(imageName), bonusValue + 3);
image = std::make_shared<CAnimImage>(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;
}

View File

@ -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<CComponent> createComponent() const;
};
@ -263,4 +263,4 @@ class SimpleLine : public CIntObject
public:
SimpleLine(Point pos1, Point pos2, ColorRGBA color);
void showAll(Canvas & to) override;
};
};

View File

@ -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>(CComponent::building, bld->town->faction->getIndex(), bld->bid));
std::make_shared<CComponent>(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<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building, town->subID, building));
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(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<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->getFaction(),building));
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(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<void()> onYes = [this](){ openMagesGuild(); };
CFunctionList<void()> onNo = onYes;
onYes += [hero](){ LOCPLINT->cb->buyArtifact(hero, ArtifactID::SPELLBOOK); };
std::vector<std::shared_ptr<CComponent>> components(1, std::make_shared<CComponent>(CComponent::artifact,ArtifactID::SPELLBOOK,0));
std::vector<std::shared_ptr<CComponent>> components(1, std::make_shared<CComponent>(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<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
else
CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(CComponent::creature, creature->getId()));
CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(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>(CComponent::building, building->town->faction->getIndex(), building->bid);
auto c = std::make_shared<CComponent>(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<std::shared_ptr<CComponent>> components;
for(int i = 0; i<GameConstants::RESOURCE_QUANTITY; i++)
for(GameResID i : GameResID::ALL_RESOURCES())
{
if(building->resources[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>(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<CComponent>(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>(CComponent::spell, spell->id));
LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(ComponentType::SPELL, spell->id));
}
void CMageGuildScreen::Scroll::showPopupWindow(const Point & cursorPosition)
{
CRClickPopup::createAndPush(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
CRClickPopup::createAndPush(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(ComponentType::SPELL, spell->id));
}
void CMageGuildScreen::Scroll::hover(bool on)

View File

@ -325,7 +325,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
std::vector<std::shared_ptr<CComponent>> resComps;
for(TResources::nziterator i(totalCost); i.valid(); i++)
{
resComps.push_back(std::make_shared<CComponent>(CComponent::resource, i->resType, (int)i->resVal));
resComps.push_back(std::make_shared<CComponent>(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<CAnimImage>(AnimationPath::builtin("PSKIL42"), 4, 0, pos.x, pos.y);
auto area = std::make_shared<LRClickableAreaWTextComp>(Rect(pos.x, pos.y, 44, 44), CComponent::experience);
auto area = std::make_shared<LRClickableAreaWTextComp>(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<CAnimImage>(AnimationPath::builtin("ARTIFACT"), art->artType->getIconIndex(), 0, pos.x, pos.y);
parent->stackArtifactHelp = std::make_shared<LRClickableAreaWTextComp>(Rect(pos, Point(44, 44)), CComponent::artifact);
parent->stackArtifactHelp->type = art->artType->getId();
parent->stackArtifactHelp = std::make_shared<LRClickableAreaWTextComp>(Rect(pos, Point(44, 44)), ComponentType::ARTIFACT);
parent->stackArtifactHelp->component.subType = art->artType->getId();
if(parent->info->owner)
{

View File

@ -119,9 +119,9 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
for(int v = 0; v < GameConstants::PRIMARY_SKILLS; ++v)
{
auto area = std::make_shared<LRClickableAreaWTextComp>(Rect(30 + 70 * v, 109, 42, 64), CComponent::primskill);
auto area = std::make_shared<LRClickableAreaWTextComp>(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<size_t>(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<LRClickableAreaWTextComp>(r, CComponent::secskill));
secSkillAreas.push_back(std::make_shared<LRClickableAreaWTextComp>(r, ComponentType::SEC_SKILL));
secSkillImages.push_back(std::make_shared<CAnimImage>(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; g<primSkillAreas.size(); ++g)
{
primSkillAreas[g]->bonusValue = curHero->getPrimSkillLevel(static_cast<PrimarySkill>(g));
primSkillValues[g]->setText(std::to_string(primSkillAreas[g]->bonusValue));
int value = curHero->getPrimSkillLevel(static_cast<PrimarySkill>(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);

View File

@ -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>(CComponent::primskill, getSubID(), (int)getValue());
comp = std::make_shared<CComponent>(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>(CComponent::secskill, subID, (int)value);
comp = std::make_shared<CComponent>(ComponentType::SEC_SKILL, SecondarySkill(subID), (int)value);
}
break;
}

View File

@ -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<std::shared_ptr<CComponent>> hlp(1, std::make_shared<CComponent>(CComponent::spell, mySpell->id, 0));
std::vector<std::shared_ptr<CComponent>> hlp(1, std::make_shared<CComponent>(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>(CComponent::spell, mySpell->id));
CRClickPopup::createAndPush(mySpell->getDescriptionTranslated(schoolLevel) + dmgInfo, std::make_shared<CComponent>(ComponentType::SPELL, mySpell->id));
}
}

View File

@ -401,7 +401,7 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill pskill, std
std::vector<std::shared_ptr<CSelectableComponent>> comps;
for(auto & skill : skills)
{
auto comp = std::make_shared<CSelectableComponent>(CComponent::secskill, skill, hero->getSecSkillLevel(SecondarySkill(skill))+1, CComponent::medium);
auto comp = std::make_shared<CSelectableComponent>(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; g<hero->secSkills.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<LRClickableAreaWTextComp>());
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>(CComponent::secskill, ID, 1));
CRClickPopup::createAndPush(CGI->skillh->getByIndex(ID)->getDescriptionTranslated(1), std::make_shared<CComponent>(ComponentType::SEC_SKILL, ID, 1));
}
void CUniversityWindow::CItem::hover(bool on)

View File

@ -375,7 +375,7 @@ class CUniversityWindow : public CStatusbarWindow
std::shared_ptr<CLabel> name;
std::shared_ptr<CLabel> level;
public:
int ID;//id of selected skill
SecondarySkill ID;//id of selected skill
CUniversityWindow * parent;
void showAll(Canvas & to) override;

View File

@ -1017,6 +1017,11 @@ const Creature * CStackBasicDescriptor::getType() const
return type;
}
CreatureID CStackBasicDescriptor::getId() const
{
return type->getId();
}
TQuantity CStackBasicDescriptor::getCount() const
{
return count;

View File

@ -39,6 +39,7 @@ public:
virtual ~CStackBasicDescriptor() = default;
const Creature * getType() const;
CreatureID getId() const;
TQuantity getCount() const;
virtual void setType(const CCreature * c);

View File

@ -458,6 +458,21 @@ std::string GameResID::entityType()
return "resource";
}
const std::array<GameResID, 7> & 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";

View File

@ -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<GameResID, 7> & ALL_RESOURCES();
};
class BuildingTypeUniqueID : public Identifier<BuildingTypeUniqueID>
class DLL_LINKAGE BuildingTypeUniqueID : public Identifier<BuildingTypeUniqueID>
{
public:
BuildingTypeUniqueID(FactionID faction, BuildingID building );

View File

@ -79,11 +79,7 @@ std::vector<Component> 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<EGameResID>(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);
}

View File

@ -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())

View File

@ -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)
{

View File

@ -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<int>(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:

View File

@ -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);
}
}

View File

@ -204,13 +204,13 @@ void CQuest::addTextReplacements(MetaString & text, std::vector<Component> & 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);
}

View File

@ -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

View File

@ -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<PrimarySkill, SecondarySkill, GameResID, CreatureID, ArtifactID, SpellID, BuildingTypeUniqueID, HeroTypeID, PlayerColor>;
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<int32_t> value; // + give; - take
template <typename Handler> 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<typename Numeric, std::enable_if_t<std::is_arithmetic_v<Numeric>, bool> = true>
Component(ComponentType type, Numeric value)
: type(type)
, value(value)
{
}
template<typename IdentifierType, std::enable_if_t<std::is_base_of_v<IdentifierBase, IdentifierType>, 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)
{
}
};

View File

@ -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)

View File

@ -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;
}

View File

@ -187,49 +187,45 @@ void Rewardable::Limiter::loadComponents(std::vector<Component> & comps,
const CGHeroInstance * h) const
{
if (heroExperience)
comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast<si32>(h->calculateXp(heroExperience)), 0);
comps.emplace_back(ComponentType::EXPERIENCE, static_cast<si32>(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<primary.size(); i++)
{
if (primary[i] != 0)
comps.emplace_back(Component::EComponentType::PRIM_SKILL, static_cast<ui16>(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<resources.size(); i++)
{
if (resources[i] !=0)
comps.emplace_back(Component::EComponentType::RESOURCE, static_cast<ui16>(i), resources[i], 0);
comps.emplace_back(ComponentType::RESOURCE, GameResID(i), resources[i]);
}
}

View File

@ -74,42 +74,42 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & 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<si32>(h ? h->calculateXp(heroExperience) : heroExperience), 0);
comps.emplace_back(ComponentType::EXPERIENCE, static_cast<si32>(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<primary.size(); i++)
{
if (primary[i] != 0)
comps.emplace_back(Component::EComponentType::PRIM_SKILL, static_cast<ui16>(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<resources.size(); i++)
{
if (resources[i] !=0)
comps.emplace_back(Component::EComponentType::RESOURCE, static_cast<ui16>(i), resources[i], 0);
comps.emplace_back(ComponentType::RESOURCE, GameResID(i), resources[i]);
}
}

View File

@ -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);

View File

@ -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<int>(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<int>(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; i<ev.resources.size(); i++)
for (GameResID i : GameResID::ALL_RESOURCES())
{
if (ev.resources[i]) //if resource is changed, we add it to the dialog
iw.components.emplace_back(Component::EComponentType::RESOURCE,i,ev.resources[i],0);
iw.components.emplace_back(ComponentType::RESOURCE, i, ev.resources[i]);
}
sendAndApply(&iw); //show dialog
@ -3273,10 +3274,9 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
n.res[player] += ev.resources;
n.res[player].amax(0);
for (int i=0; i<ev.resources.size(); i++)
for (GameResID i : GameResID::ALL_RESOURCES())
if (ev.resources[i] && pinfo->resources[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<const CObjectVisitQuery>(query);
if (visit && visit->visitedObject == obj)

View File

@ -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);