1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +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

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