mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
- creatures availability tests no longer check for built buildings.
Fixes #1650 - do not crash if town has 0 creatures on some dwelling level - do not crash if dwelling for some level is not present in town at all
This commit is contained in:
parent
bc1e726be4
commit
fb5c9fc972
@ -1467,7 +1467,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
buildingID = BuildingID::SPECIAL_3;
|
buildingID = BuildingID::SPECIAL_3;
|
||||||
recAreas.push_back(new RecruitArea(positions[i].x, positions[i].y, town, buildingID, i));
|
recAreas.push_back(new RecruitArea(positions[i].x, positions[i].y, town, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
resdatabar = new CMinorResDataBar;
|
resdatabar = new CMinorResDataBar;
|
||||||
@ -1529,7 +1529,36 @@ void LabeledValue::hover(bool on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *Town, BuildingID buildingID, int Level):
|
const CCreature * CFortScreen::RecruitArea::getMyCreature()
|
||||||
|
{
|
||||||
|
if (!town->creatures.at(level).second.empty()) // built
|
||||||
|
return VLC->creh->creatures[town->creatures.at(level).second.back()];
|
||||||
|
if (!town->town->creatures.at(level).empty()) // there are creatures on this level
|
||||||
|
return VLC->creh->creatures[town->town->creatures.at(level).front()];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CBuilding * CFortScreen::RecruitArea::getMyBuilding()
|
||||||
|
{
|
||||||
|
BuildingID myID = BuildingID(BuildingID::DWELL_FIRST).advance(level);
|
||||||
|
|
||||||
|
if (level == GameConstants::CREATURES_PER_TOWN)
|
||||||
|
return town->town->buildings.at(BuildingID::PORTAL_OF_SUMMON);
|
||||||
|
|
||||||
|
if (!town->town->buildings.count(myID))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const CBuilding * build = town->town->buildings.at(myID);
|
||||||
|
while (town->town->buildings.count(myID))
|
||||||
|
{
|
||||||
|
if (town->hasBuilt(myID))
|
||||||
|
build = town->town->buildings.at(myID);
|
||||||
|
myID.advance(GameConstants::CREATURES_PER_TOWN);
|
||||||
|
}
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *Town, int Level):
|
||||||
town(Town),
|
town(Town),
|
||||||
level(Level),
|
level(Level),
|
||||||
availableCount(nullptr)
|
availableCount(nullptr)
|
||||||
@ -1544,39 +1573,37 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
|
|||||||
addUsedEvents(LCLICK | RCLICK | HOVER);//Activate only if dwelling is present
|
addUsedEvents(LCLICK | RCLICK | HOVER);//Activate only if dwelling is present
|
||||||
|
|
||||||
icons = new CPicture("TPCAINFO", 261, 3);
|
icons = new CPicture("TPCAINFO", 261, 3);
|
||||||
buildingPic = new CAnimImage(town->town->clientInfo.buildingsIcons, buildingID, 0, 4, 21);
|
if (getMyBuilding() != nullptr)
|
||||||
|
|
||||||
const CCreature* creature = nullptr;
|
|
||||||
|
|
||||||
if (!town->creatures[level].second.empty())
|
|
||||||
creature = CGI->creh->creatures[town->creatures[level].second.back()];
|
|
||||||
else
|
|
||||||
creature = CGI->creh->creatures[town->town->creatures[level][0]];
|
|
||||||
|
|
||||||
hoverText = boost::str(boost::format(CGI->generaltexth->tcommands[21]) % creature->namePl);
|
|
||||||
creatureAnim = new CCreaturePic(159, 4, creature, false);
|
|
||||||
|
|
||||||
Rect sizes(287, 4, 96, 18);
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[190], CGI->generaltexth->fcommands[0], creature->Attack()));
|
|
||||||
sizes.y+=20;
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[191], CGI->generaltexth->fcommands[1], creature->Defense()));
|
|
||||||
sizes.y+=21;
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[199], CGI->generaltexth->fcommands[2], creature->getMinDamage(), creature->getMaxDamage()));
|
|
||||||
sizes.y+=20;
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[388], CGI->generaltexth->fcommands[3], creature->MaxHealth()));
|
|
||||||
sizes.y+=21;
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[193], CGI->generaltexth->fcommands[4], creature->valOfBonuses(Bonus::STACKS_SPEED)));
|
|
||||||
sizes.y+=20;
|
|
||||||
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
|
|
||||||
|
|
||||||
creatureName = new CLabel(78, 11, FONT_SMALL, CENTER, Colors::WHITE, creature->namePl);
|
|
||||||
dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::WHITE, town->town->buildings.at(buildingID)->Name());
|
|
||||||
|
|
||||||
if (vstd::contains(town->builtBuildings, buildingID))
|
|
||||||
{
|
{
|
||||||
ui32 available = town->creatures[level].first;
|
buildingPic = new CAnimImage(town->town->clientInfo.buildingsIcons, getMyBuilding()->bid, 0, 4, 21);
|
||||||
std::string availableText = CGI->generaltexth->allTexts[217]+ boost::lexical_cast<std::string>(available);
|
dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::WHITE, getMyBuilding()->Name());
|
||||||
availableCount = new CLabel(78, 119, FONT_SMALL, CENTER, Colors::WHITE, availableText);
|
|
||||||
|
if (vstd::contains(town->builtBuildings, getMyBuilding()->bid))
|
||||||
|
{
|
||||||
|
ui32 available = town->creatures[level].first;
|
||||||
|
std::string availableText = CGI->generaltexth->allTexts[217]+ boost::lexical_cast<std::string>(available);
|
||||||
|
availableCount = new CLabel(78, 119, FONT_SMALL, CENTER, Colors::WHITE, availableText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getMyCreature() != nullptr)
|
||||||
|
{
|
||||||
|
hoverText = boost::str(boost::format(CGI->generaltexth->tcommands[21]) % getMyCreature()->namePl);
|
||||||
|
creatureAnim = new CCreaturePic(159, 4, getMyCreature(), false);
|
||||||
|
creatureName = new CLabel(78, 11, FONT_SMALL, CENTER, Colors::WHITE, getMyCreature()->namePl);
|
||||||
|
|
||||||
|
Rect sizes(287, 4, 96, 18);
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[190], CGI->generaltexth->fcommands[0], getMyCreature()->Attack()));
|
||||||
|
sizes.y+=20;
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[191], CGI->generaltexth->fcommands[1], getMyCreature()->Defense()));
|
||||||
|
sizes.y+=21;
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[199], CGI->generaltexth->fcommands[2], getMyCreature()->getMinDamage(), getMyCreature()->getMaxDamage()));
|
||||||
|
sizes.y+=20;
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[388], CGI->generaltexth->fcommands[3], getMyCreature()->MaxHealth()));
|
||||||
|
sizes.y+=21;
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[193], CGI->generaltexth->fcommands[4], getMyCreature()->valOfBonuses(Bonus::STACKS_SPEED)));
|
||||||
|
sizes.y+=20;
|
||||||
|
values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +315,10 @@ class CFortScreen : public CWindowObject
|
|||||||
CAnimImage * buildingPic;
|
CAnimImage * buildingPic;
|
||||||
CCreaturePic *creatureAnim;
|
CCreaturePic *creatureAnim;
|
||||||
|
|
||||||
|
const CCreature * getMyCreature();
|
||||||
|
const CBuilding * getMyBuilding();
|
||||||
public:
|
public:
|
||||||
RecruitArea(int posX, int posY, const CGTownInstance *town, BuildingID buildingID, int level);
|
RecruitArea(int posX, int posY, const CGTownInstance *town, int level);
|
||||||
|
|
||||||
void creaturesChanged();
|
void creaturesChanged();
|
||||||
void hover(bool on);
|
void hover(bool on);
|
||||||
|
@ -2862,7 +2862,10 @@ void OptionsTab::CPregameTooltipBox::genTownWindow()
|
|||||||
const CTown * town = CGI->townh->factions[settings.castle]->town;
|
const CTown * town = CGI->townh->factions[settings.castle]->town;
|
||||||
|
|
||||||
for (auto & elem : town->creatures)
|
for (auto & elem : town->creatures)
|
||||||
components.push_back(new CComponent(CComponent::creature, elem.front(), 0, CComponent::tiny));
|
{
|
||||||
|
if (!elem.empty())
|
||||||
|
components.push_back(new CComponent(CComponent::creature, elem.front(), 0, CComponent::tiny));
|
||||||
|
}
|
||||||
|
|
||||||
new CComponentBox(components, Rect(10, 140, pos.w - 20, 140));
|
new CComponentBox(components, Rect(10, 140, pos.w - 20, 140));
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
|||||||
{
|
{
|
||||||
for(int h=0; h<getHeight(); ++h)
|
for(int h=0; h<getHeight(); ++h)
|
||||||
{
|
{
|
||||||
if (appearance.isBlockedAt(-w, -h))
|
if (appearance.isBlockedAt(w, h))
|
||||||
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
|
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2050,20 +2050,11 @@ int CGTownInstance::mageGuildLevel() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::creatureDwellingLevel(int dwelling) const
|
|
||||||
{
|
|
||||||
if ( dwelling<0 || dwelling >= GameConstants::CREATURES_PER_TOWN )
|
|
||||||
return -1;
|
|
||||||
for (int i=0; ; i++)
|
|
||||||
{
|
|
||||||
if (!hasBuilt(BuildingID(BuildingID::DWELL_FIRST+dwelling+i*GameConstants::CREATURES_PER_TOWN)))
|
|
||||||
return i-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
||||||
{
|
{
|
||||||
return town->hordeLvl.at(HID);
|
return town->hordeLvl.at(HID);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::creatureGrowth(const int & level) const
|
int CGTownInstance::creatureGrowth(const int & level) const
|
||||||
{
|
{
|
||||||
return getGrowthInfo(level).totalGrowth();
|
return getGrowthInfo(level).totalGrowth();
|
||||||
@ -2243,12 +2234,16 @@ void CGTownInstance::initObj()
|
|||||||
creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon
|
creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon
|
||||||
else
|
else
|
||||||
creatures.resize(GameConstants::CREATURES_PER_TOWN);
|
creatures.resize(GameConstants::CREATURES_PER_TOWN);
|
||||||
for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; i++)
|
for (int level = 0; level < GameConstants::CREATURES_PER_TOWN; level++)
|
||||||
{
|
{
|
||||||
int dwellingLevel = creatureDwellingLevel(i);
|
BuildingID buildID = BuildingID(BuildingID::DWELL_FIRST).advance(level);
|
||||||
int creaturesTotal = town->creatures[i].size();
|
int upgradeNum = 0;
|
||||||
for (int j=0; j< std::min(dwellingLevel + 1, creaturesTotal); j++)
|
|
||||||
creatures[i].second.push_back(town->creatures[i][j]);
|
for (; town->buildings.count(buildID); upgradeNum++, buildID.advance(GameConstants::CREATURES_PER_TOWN))
|
||||||
|
{
|
||||||
|
if (hasBuilt(buildID) && town->creatures.at(level).size() > upgradeNum)
|
||||||
|
creatures[level].second.push_back(town->creatures[level][upgradeNum]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (subID)
|
switch (subID)
|
||||||
@ -2321,23 +2316,26 @@ void CGTownInstance::newTurn() const
|
|||||||
}
|
}
|
||||||
if ((stacksCount() < GameConstants::ARMY_SIZE && rand()%100 < 25) || Slots().empty()) //add new stack
|
if ((stacksCount() < GameConstants::ARMY_SIZE && rand()%100 < 25) || Slots().empty()) //add new stack
|
||||||
{
|
{
|
||||||
int i = rand() % std::min (GameConstants::ARMY_SIZE, cb->getDate(Date::MONTH)<<1);
|
int i = rand() % std::min (GameConstants::CREATURES_PER_TOWN, cb->getDate(Date::MONTH)<<1);
|
||||||
CreatureID c = town->creatures[i][0];
|
if (!town->creatures[i].empty())
|
||||||
SlotID n;
|
{
|
||||||
|
CreatureID c = town->creatures[i][0];
|
||||||
|
SlotID n;
|
||||||
|
|
||||||
TQuantity count = creatureGrowth(i);
|
TQuantity count = creatureGrowth(i);
|
||||||
if (!count) // no dwelling
|
if (!count) // no dwelling
|
||||||
count = VLC->creh->creatures[c]->growth;
|
count = VLC->creh->creatures[c]->growth;
|
||||||
|
|
||||||
{//no lower tiers or above current month
|
{//no lower tiers or above current month
|
||||||
|
|
||||||
if ((n = getSlotFor(c)).validSlot())
|
if ((n = getSlotFor(c)).validSlot())
|
||||||
{
|
{
|
||||||
StackLocation sl(this, n);
|
StackLocation sl(this, n);
|
||||||
if (slotEmpty(n))
|
if (slotEmpty(n))
|
||||||
cb->insertNewStack(sl, VLC->creh->creatures[c], count);
|
cb->insertNewStack(sl, VLC->creh->creatures[c], count);
|
||||||
else //add to existing
|
else //add to existing
|
||||||
cb->changeStackCount(sl, count);
|
cb->changeStackCount(sl, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -694,7 +694,6 @@ public:
|
|||||||
CGTownInstance::EFortLevel fortLevel() const;
|
CGTownInstance::EFortLevel fortLevel() const;
|
||||||
int hallLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
|
int hallLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
|
||||||
int mageGuildLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
|
int mageGuildLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
|
||||||
int creatureDwellingLevel(int dwelling) const;
|
|
||||||
int getHordeLevel(const int & HID) const; //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
int getHordeLevel(const int & HID) const; //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
||||||
int creatureGrowth(const int & level) const;
|
int creatureGrowth(const int & level) const;
|
||||||
GrowthInfo getGrowthInfo(int level) const;
|
GrowthInfo getGrowthInfo(int level) const;
|
||||||
|
@ -1290,7 +1290,7 @@ void CGameHandler::newTurn()
|
|||||||
|
|
||||||
for (int k=0; k < GameConstants::CREATURES_PER_TOWN; k++) //creature growths
|
for (int k=0; k < GameConstants::CREATURES_PER_TOWN; k++) //creature growths
|
||||||
{
|
{
|
||||||
if(t->creatureDwellingLevel(k) >= 0)//there is dwelling (k-level)
|
if (!t->creatures.at(k).second.empty()) // there are creatures at this level
|
||||||
{
|
{
|
||||||
ui32 &availableCount = sac.creatures.at(k).first;
|
ui32 &availableCount = sac.creatures.at(k).first;
|
||||||
const CCreature *cre = VLC->creh->creatures.at(t->creatures.at(k).second.back());
|
const CCreature *cre = VLC->creh->creatures.at(t->creatures.at(k).second.back());
|
||||||
@ -4853,7 +4853,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
|||||||
|
|
||||||
for(si32 i=0;i<ev.creatures.size();i++) //creature growths
|
for(si32 i=0;i<ev.creatures.size();i++) //creature growths
|
||||||
{
|
{
|
||||||
if(town->creatureDwellingLevel(i) >= 0 && ev.creatures.at(i))//there is dwelling
|
if(!town->creatures.at(i).second.empty() && ev.creatures.at(i) > 0)//there is dwelling
|
||||||
{
|
{
|
||||||
sac.creatures[i].first += ev.creatures.at(i);
|
sac.creatures[i].first += ev.creatures.at(i);
|
||||||
iw.components.push_back(Component(Component::CREATURE,
|
iw.components.push_back(Component(Component::CREATURE,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user