mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-29 22:57:49 +02:00
Merge branch 'develop' into crash_fix4
This commit is contained in:
commit
5645806035
@ -818,11 +818,11 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
|
||||
int oldValue = s->getCreature()->getAIValue();
|
||||
int newValue = upgID.toCreature()->getAIValue();
|
||||
|
||||
if(newValue > oldValue && nullkiller->getFreeResources().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->count))
|
||||
if(newValue > oldValue && nullkiller->getFreeResources().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->getCount()))
|
||||
{
|
||||
myCb->upgradeCreature(obj, SlotID(i), upgID);
|
||||
upgraded = true;
|
||||
logAi->debug("Upgraded %d %s to %s", s->count, upgradeInfo.oldID.toCreature()->getNamePluralTranslated(),
|
||||
logAi->debug("Upgraded %d %s to %s", s->getCount(), upgradeInfo.oldID.toCreature()->getNamePluralTranslated(),
|
||||
upgradeInfo.getUpgrade().toCreature()->getNamePluralTranslated());
|
||||
}
|
||||
else
|
||||
|
@ -98,7 +98,7 @@ std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, c
|
||||
|
||||
slotInfp.creature = cre;
|
||||
slotInfp.power += i.second->getPower();
|
||||
slotInfp.count += i.second->count;
|
||||
slotInfp.count += i.second->getCount();
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,7 +491,7 @@ void ArmyManager::update()
|
||||
{
|
||||
for(const auto & slot : army->Slots())
|
||||
{
|
||||
totalArmy[slot.second->getCreatureID()].count += slot.second->count;
|
||||
totalArmy[slot.second->getCreatureID()].count += slot.second->getCount();
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +511,7 @@ std::vector<SlotInfo> ArmyManager::convertToSlots(const CCreatureSet * army) con
|
||||
SlotInfo slotInfo;
|
||||
|
||||
slotInfo.creature = slot.second->getCreatureID().toCreature();
|
||||
slotInfo.count = slot.second->count;
|
||||
slotInfo.count = slot.second->getCount();
|
||||
slotInfo.power = evaluateStackPower(slotInfo.creature, slotInfo.count);
|
||||
|
||||
result.push_back(slotInfo);
|
||||
@ -537,7 +537,7 @@ std::vector<StackUpgradeInfo> ArmyManager::getHillFortUpgrades(const CCreatureSe
|
||||
return cre.toCreature()->getAIValue();
|
||||
});
|
||||
|
||||
StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->count);
|
||||
StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->getCount());
|
||||
|
||||
if(initial.toCreature()->getLevel() == 1)
|
||||
upgrade.cost = TResources();
|
||||
@ -576,7 +576,7 @@ std::vector<StackUpgradeInfo> ArmyManager::getDwellingUpgrades(const CCreatureSe
|
||||
return cre.toCreature()->getAIValue();
|
||||
});
|
||||
|
||||
StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->count);
|
||||
StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->getCount());
|
||||
|
||||
upgrades.push_back(upgrade);
|
||||
}
|
||||
|
@ -699,7 +699,7 @@ int32_t getArmyCost(const CArmedInstance * army)
|
||||
|
||||
for(const auto & stack : army->Slots())
|
||||
{
|
||||
value += stack.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * stack.second->count;
|
||||
value += stack.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * stack.second->getCount();
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -362,7 +362,7 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
|
||||
{
|
||||
const auto & targetSlot = target->getSlotFor(slot.second->getCreatureID());
|
||||
|
||||
target->addToSlot(targetSlot, slot.second->getCreatureID(), slot.second->count);
|
||||
target->addToSlot(targetSlot, slot.second->getCreatureID(), slot.second->getCount());
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,7 +422,7 @@ DwellingActor::DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bo
|
||||
{
|
||||
for(auto & slot : creatureSet->Slots())
|
||||
{
|
||||
armyCost += slot.second->getCreatureID().toCreature()->getFullRecruitCost() * slot.second->count;
|
||||
armyCost += slot.second->getCreatureID().toCreature()->getFullRecruitCost() * slot.second->getCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, c
|
||||
|
||||
slotInfp.creature = cre;
|
||||
slotInfp.power += i.second->getPower();
|
||||
slotInfp.count += i.second->count;
|
||||
slotInfp.count += i.second->getCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ TGoalVec CompleteQuest::missionArmy() const
|
||||
|
||||
for(auto creature : q.getQuest(cb)->mission.creatures)
|
||||
{
|
||||
solutions.push_back(sptr(GatherTroops(creature.getId().getNum(), creature.count)));
|
||||
solutions.push_back(sptr(GatherTroops(creature.getId().getNum(), creature.getCount())));
|
||||
}
|
||||
|
||||
return solutions;
|
||||
|
@ -33,7 +33,7 @@ int GatherTroops::getCreaturesCount(const CArmedInstance * army)
|
||||
{
|
||||
if(objid == stack.second->getCreatureID().num)
|
||||
{
|
||||
count += stack.second->count;
|
||||
count += stack.second->getCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,10 +791,10 @@ void makePossibleUpgrades(const CArmedInstance * obj)
|
||||
{
|
||||
return id.toCreature()->getAIValue();
|
||||
});
|
||||
if(cb->getResourceAmount().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->count))
|
||||
if(cb->getResourceAmount().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->getCount()))
|
||||
{
|
||||
cb->upgradeCreature(obj, SlotID(i), upgID);
|
||||
logAi->debug("Upgraded %d %s to %s", s->count, upgradeInfo.oldID.toCreature()->getNamePluralTranslated(),
|
||||
logAi->debug("Upgraded %d %s to %s", s->getCount(), upgradeInfo.oldID.toCreature()->getNamePluralTranslated(),
|
||||
upgradeInfo.getUpgrade().toCreature()->getNamePluralTranslated());
|
||||
}
|
||||
else
|
||||
|
@ -131,9 +131,9 @@ int CCallback::bulkSplitStack(ObjectInstanceID armyId, SlotID srcSlot, int howMa
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CCallback::bulkSmartSplitStack(ObjectInstanceID armyId, SlotID srcSlot)
|
||||
int CCallback::bulkSplitAndRebalanceStack(ObjectInstanceID armyId, SlotID srcSlot)
|
||||
{
|
||||
BulkSmartSplitStack pack(armyId, srcSlot);
|
||||
BulkSplitAndRebalanceStack pack(armyId, srcSlot);
|
||||
sendRequest(pack);
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
// To implement high-level army management bulk actions
|
||||
virtual int bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot) = 0;
|
||||
virtual int bulkSplitStack(ObjectInstanceID armyId, SlotID srcSlot, int howMany = 1) = 0;
|
||||
virtual int bulkSmartSplitStack(ObjectInstanceID armyId, SlotID srcSlot) = 0;
|
||||
virtual int bulkSplitAndRebalanceStack(ObjectInstanceID armyId, SlotID srcSlot) = 0;
|
||||
virtual int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) = 0;
|
||||
|
||||
|
||||
@ -181,7 +181,7 @@ public:
|
||||
int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2, int val) override;
|
||||
int bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot) override;
|
||||
int bulkSplitStack(ObjectInstanceID armyId, SlotID srcSlot, int howMany = 1) override;
|
||||
int bulkSmartSplitStack(ObjectInstanceID armyId, SlotID srcSlot) override;
|
||||
int bulkSplitAndRebalanceStack(ObjectInstanceID armyId, SlotID srcSlot) override;
|
||||
int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) override;
|
||||
bool dismissHero(const CGHeroInstance * hero) override;
|
||||
bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override;
|
||||
|
@ -46,7 +46,6 @@ public:
|
||||
void visitInsertNewStack(InsertNewStack & pack) override;
|
||||
void visitRebalanceStacks(RebalanceStacks & pack) override;
|
||||
void visitBulkRebalanceStacks(BulkRebalanceStacks & pack) override;
|
||||
void visitBulkSmartRebalanceStacks(BulkSmartRebalanceStacks & pack) override;
|
||||
void visitPutArtifact(PutArtifact & pack) override;
|
||||
void visitEraseArtifact(BulkEraseArtifacts & pack) override;
|
||||
void visitBulkMoveArtifacts(BulkMoveArtifacts & pack) override;
|
||||
|
@ -263,19 +263,6 @@ void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & p
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyClientNetPackVisitor::visitBulkSmartRebalanceStacks(BulkSmartRebalanceStacks & pack)
|
||||
{
|
||||
if(!pack.moves.empty())
|
||||
{
|
||||
assert(pack.moves[0].srcArmy == pack.moves[0].dstArmy);
|
||||
dispatchGarrisonChange(cl, pack.moves[0].srcArmy, ObjectInstanceID());
|
||||
}
|
||||
else if(!pack.changes.empty())
|
||||
{
|
||||
dispatchGarrisonChange(cl, pack.changes[0].army, ObjectInstanceID());
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyClientNetPackVisitor::visitPutArtifact(PutArtifact & pack)
|
||||
{
|
||||
callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactPut, pack.al);
|
||||
@ -880,7 +867,7 @@ void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied &
|
||||
if(pack.raisedStack.getCreature())
|
||||
callInterfaceIfPresent(cl, pack.victor, &CGameInterface::showInfoDialog, EInfoWindowMode::AUTO,
|
||||
UIHelper::getNecromancyInfoWindowText(pack.raisedStack), std::vector<Component>{Component(ComponentType::CREATURE, pack.raisedStack.getId(),
|
||||
pack.raisedStack.count)}, UIHelper::getNecromancyInfoWindowSound());
|
||||
pack.raisedStack.getCount())}, UIHelper::getNecromancyInfoWindowSound());
|
||||
|
||||
callInterfaceIfPresent(cl, pack.victor, &IGameEventsReceiver::battleResultsApplied);
|
||||
callInterfaceIfPresent(cl, pack.loser, &IGameEventsReceiver::battleResultsApplied);
|
||||
|
@ -50,10 +50,10 @@ soundBase::soundID UIHelper::getNecromancyInfoWindowSound()
|
||||
std::string UIHelper::getNecromancyInfoWindowText(const CStackBasicDescriptor & stack)
|
||||
{
|
||||
MetaString text;
|
||||
if(stack.count > 1) // Practicing the dark arts of necromancy, ... (plural)
|
||||
if(stack.getCount() > 1) // Practicing the dark arts of necromancy, ... (plural)
|
||||
{
|
||||
text.appendLocalString(EMetaText::GENERAL_TXT, 145);
|
||||
text.replaceNumber(stack.count);
|
||||
text.replaceNumber(stack.getCount());
|
||||
}
|
||||
else // Practicing the dark arts of necromancy, ... (singular)
|
||||
{
|
||||
|
@ -51,6 +51,7 @@ BasicMapView::BasicMapView(const Point & offset, const Point & dimensions)
|
||||
: model(createModel(dimensions))
|
||||
, tilesCache(new MapViewCache(model))
|
||||
, controller(new MapViewController(model, tilesCache))
|
||||
, needFullUpdate(false)
|
||||
{
|
||||
OBJECT_CONSTRUCTION;
|
||||
pos += offset;
|
||||
@ -76,7 +77,7 @@ void BasicMapView::tick(uint32_t msPassed)
|
||||
void BasicMapView::show(Canvas & to)
|
||||
{
|
||||
CanvasClipRectGuard guard(to, pos);
|
||||
render(to, false);
|
||||
render(to, needFullUpdate);
|
||||
|
||||
controller->afterRender();
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ protected:
|
||||
void render(Canvas & target, bool fullUpdate);
|
||||
|
||||
public:
|
||||
bool needFullUpdate;
|
||||
|
||||
BasicMapView(const Point & offset, const Point & dimensions);
|
||||
~BasicMapView() override;
|
||||
|
||||
|
@ -255,8 +255,8 @@ bool CGarrisonSlot::split()
|
||||
}
|
||||
}
|
||||
|
||||
int countLeft = selection->myStack ? selection->myStack->count : 0;
|
||||
int countRight = myStack ? myStack->count : 0;
|
||||
int countLeft = selection->myStack ? selection->myStack->getCount() : 0;
|
||||
int countRight = myStack ? myStack->getCount() : 0;
|
||||
|
||||
auto splitFunctor = [this, selection](int amountLeft, int amountRight)
|
||||
{
|
||||
@ -345,7 +345,7 @@ void CGarrisonSlot::clickPressed(const Point & cursorPosition)
|
||||
refr = split();
|
||||
}
|
||||
else if(!creature && lastHeroStackSelected) // split all except last creature
|
||||
GAME->interface()->cb->splitStack(selectedObj, owner->army(upg), selection->ID, ID, selection->myStack->count - 1);
|
||||
GAME->interface()->cb->splitStack(selectedObj, owner->army(upg), selection->ID, ID, selection->myStack->getCount() - 1);
|
||||
else if(creature != selection->creature) // swap
|
||||
GAME->interface()->cb->swapCreatures(owner->army(upg), selectedObj, ID, selection->ID);
|
||||
else if(lastHeroStackSelected) // merge last stack to other hero stack
|
||||
@ -388,7 +388,7 @@ void CGarrisonSlot::gesture(bool on, const Point & initialPosition, const Point
|
||||
{ RadialMenuConfig::ITEM_NW, hasSameUnit, "stackMerge", "vcmi.radialWheel.mergeSameUnit", [this](){owner->bulkMergeStacks(this);} },
|
||||
{ RadialMenuConfig::ITEM_NE, hasOwnEmptySlots, "stackFillOne", "vcmi.radialWheel.fillSingleUnit", [this](){owner->bulkSplitStack(this);} },
|
||||
{ RadialMenuConfig::ITEM_WW, hasOwnEmptySlots, "stackSplitOne", "vcmi.radialWheel.splitSingleUnit", [this](){splitIntoParts(this->getGarrison(), 1); } },
|
||||
{ RadialMenuConfig::ITEM_EE, hasOwnEmptySlots, "stackSplitEqual", "vcmi.radialWheel.splitUnitEqually", [this](){owner->bulkSmartSplitStack(this);} },
|
||||
{ RadialMenuConfig::ITEM_EE, hasOwnEmptySlots, "stackSplitEqual", "vcmi.radialWheel.splitUnitEqually", [this](){owner->bulkSplitAndRebalanceStack(this);} },
|
||||
{ RadialMenuConfig::ITEM_SW, hasOtherEmptySlots, "heroMove", "vcmi.radialWheel.moveUnit", [this](){owner->moveStackToAnotherArmy(this);} },
|
||||
{ RadialMenuConfig::ITEM_SE, hasAnyEmptySlots, "heroSwap", "vcmi.radialWheel.splitUnit", [this](){ owner->selectSlot(this); owner->splitClick();} },
|
||||
};
|
||||
@ -418,7 +418,7 @@ void CGarrisonSlot::update()
|
||||
creatureImage->setFrame(creature->getIconIndex());
|
||||
|
||||
stackCount->enable();
|
||||
stackCount->setText(TextOperations::formatMetric(myStack->count, 4));
|
||||
stackCount->setText(TextOperations::formatMetric(myStack->getCount(), 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -499,7 +499,7 @@ bool CGarrisonSlot::handleSplittingShortcuts()
|
||||
if(!selected)
|
||||
return true; // Some Shortcusts are pressed but there are no appropriate actions
|
||||
|
||||
auto units = selected->myStack->count;
|
||||
auto units = selected->myStack->getCount();
|
||||
if(units < 1)
|
||||
return true;
|
||||
|
||||
@ -529,7 +529,7 @@ bool CGarrisonSlot::handleSplittingShortcuts()
|
||||
if(isLCtrl && isLShift)
|
||||
owner->bulkSplitStack(selected);
|
||||
else if(isLShift)
|
||||
owner->bulkSmartSplitStack(selected);
|
||||
owner->bulkSplitAndRebalanceStack(selected);
|
||||
else
|
||||
splitIntoParts(selected->upg, 1); // LCtrl
|
||||
}
|
||||
@ -603,7 +603,7 @@ void CGarrisonInt::splitStacks(const CGarrisonSlot * from, const CArmedInstance
|
||||
|
||||
bool CGarrisonInt::checkSelected(const CGarrisonSlot * selected, TQuantity min) const
|
||||
{
|
||||
return selected && selected->myStack && selected->myStack->count > min && selected->creature;
|
||||
return selected && selected->myStack && selected->myStack->getCount() > min && selected->creature;
|
||||
}
|
||||
|
||||
void CGarrisonInt::moveStackToAnotherArmy(const CGarrisonSlot * selected)
|
||||
@ -634,7 +634,7 @@ void CGarrisonInt::moveStackToAnotherArmy(const CGarrisonSlot * selected)
|
||||
destSlot = srcSlot; // Same place is more preferable
|
||||
|
||||
const bool isLastStack = srcArmy->stacksCount() == 1 && srcArmy->needsLastStack();
|
||||
auto srcAmount = selected->myStack->count - (isLastStack ? 1 : 0);
|
||||
auto srcAmount = selected->myStack->getCount() - (isLastStack ? 1 : 0);
|
||||
|
||||
if(!srcAmount)
|
||||
return;
|
||||
@ -696,7 +696,7 @@ void CGarrisonInt::bulkSplitStack(const CGarrisonSlot * selected)
|
||||
GAME->interface()->cb->bulkSplitStack(armedObjs[type]->id, selected->ID);
|
||||
}
|
||||
|
||||
void CGarrisonInt::bulkSmartSplitStack(const CGarrisonSlot * selected)
|
||||
void CGarrisonInt::bulkSplitAndRebalanceStack(const CGarrisonSlot * selected)
|
||||
{
|
||||
if(!checkSelected(selected, 1))
|
||||
return;
|
||||
@ -707,7 +707,7 @@ void CGarrisonInt::bulkSmartSplitStack(const CGarrisonSlot * selected)
|
||||
if(!hasEmptySlot(type) && armedObjs[type]->isCreatureBalanced(selected->creature))
|
||||
return;
|
||||
|
||||
GAME->interface()->cb->bulkSmartSplitStack(armedObjs[type]->id, selected->ID);
|
||||
GAME->interface()->cb->bulkSplitAndRebalanceStack(armedObjs[type]->id, selected->ID);
|
||||
}
|
||||
|
||||
CGarrisonInt::CGarrisonInt(const Point & position, int inx, const Point & garsOffset, const CArmedInstance * s1, const CArmedInstance * s2, bool _removableUnits, bool smallImgs, ESlotsLayout _layout)
|
||||
|
@ -134,7 +134,7 @@ public:
|
||||
void bulkMoveArmy(const CGarrisonSlot * selected);
|
||||
void bulkMergeStacks(const CGarrisonSlot * selected); // Gather all creatures of selected type to the selected slot from other hero/garrison slots
|
||||
void bulkSplitStack(const CGarrisonSlot * selected); // Used to separate one-creature troops from main stack
|
||||
void bulkSmartSplitStack(const CGarrisonSlot * selected);
|
||||
void bulkSplitAndRebalanceStack(const CGarrisonSlot * selected);
|
||||
|
||||
/// Constructor
|
||||
/// @param position Relative position to parent element
|
||||
|
@ -286,20 +286,20 @@ void CArmyTooltip::init(const InfoAboutArmy &army)
|
||||
std::string subtitle;
|
||||
if(army.army.isDetailed)
|
||||
{
|
||||
subtitle = TextOperations::formatMetric(slot.second.count, 4);
|
||||
subtitle = TextOperations::formatMetric(slot.second.getCount(), 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if =0 - we have no information about stack size at all
|
||||
if(slot.second.count)
|
||||
if(slot.second.getCount())
|
||||
{
|
||||
if(settings["gameTweaks"]["numericCreaturesQuantities"].Bool())
|
||||
{
|
||||
subtitle = CCreature::getQuantityRangeStringForId((CCreature::CreatureQuantityId)slot.second.count);
|
||||
subtitle = CCreature::getQuantityRangeStringForId((CCreature::CreatureQuantityId)slot.second.getCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitle = LIBRARY->generaltexth->arraytxt[171 + 3*(slot.second.count)];
|
||||
subtitle = LIBRARY->generaltexth->arraytxt[171 + 3*(slot.second.getCount())];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ void CHeroGSlot::gesture(bool on, const Point & initialPosition, const Point & f
|
||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, static_cast<GameResID>(GameResID::GOLD), 0)); // add at least gold, when there are no costs
|
||||
resComps.back()->newLine = true;
|
||||
for(auto & upgradeInfo : upgradableSlots.upgradeInfos)
|
||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::CREATURE, upgradeInfo.second.getUpgrade(), obj->Slots().at(upgradeInfo.first)->count));
|
||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::CREATURE, upgradeInfo.second.getUpgrade(), obj->Slots().at(upgradeInfo.first)->getCount()));
|
||||
|
||||
std::string textID = upgradableSlots.canAffordAll ? "core.genrltxt.207" : "vcmi.townWindow.upgradeAll.notAllUpgradable";
|
||||
|
||||
|
@ -664,7 +664,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
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(LIBRARY->heroh->reqExp(commander->getExpRank() + 1)));
|
||||
boost::replace_first(area->text, "%d", std::to_string(commander->experience));
|
||||
boost::replace_first(area->text, "%d", std::to_string(commander->getAverageExperience()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -674,7 +674,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
}
|
||||
expLabel = std::make_shared<CLabel>(
|
||||
pos.x + 21, pos.y + 55, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE,
|
||||
TextOperations::formatMetric(stack->experience, 6));
|
||||
TextOperations::formatMetric(stack->getAverageExperience(), 6));
|
||||
}
|
||||
|
||||
if(showArt)
|
||||
@ -764,7 +764,7 @@ CStackWindow::CStackWindow(const CStackInstance * stack, bool popup)
|
||||
{
|
||||
info->stackNode = stack;
|
||||
info->creature = stack->getCreature();
|
||||
info->creatureCount = stack->count;
|
||||
info->creatureCount = stack->getCount();
|
||||
info->popupWindow = popup;
|
||||
info->owner = dynamic_cast<const CGHeroInstance *> (stack->getArmy());
|
||||
init();
|
||||
@ -776,7 +776,7 @@ CStackWindow::CStackWindow(const CStackInstance * stack, std::function<void()> d
|
||||
{
|
||||
info->stackNode = stack;
|
||||
info->creature = stack->getCreature();
|
||||
info->creatureCount = stack->count;
|
||||
info->creatureCount = stack->getCount();
|
||||
|
||||
if(upgradeInfo.canUpgrade())
|
||||
{
|
||||
@ -968,8 +968,8 @@ std::string CStackWindow::generateStackExpDescription()
|
||||
boost::replace_first(expText, "%s", creature->getNamePluralTranslated());
|
||||
boost::replace_first(expText, "%s", LIBRARY->generaltexth->translate("vcmi.stackExperience.rank", rank));
|
||||
boost::replace_first(expText, "%i", std::to_string(rank));
|
||||
boost::replace_first(expText, "%i", std::to_string(stack->experience));
|
||||
number = static_cast<int>(LIBRARY->creh->expRanks[tier][rank] - stack->experience);
|
||||
boost::replace_first(expText, "%i", std::to_string(stack->getAverageExperience()));
|
||||
number = static_cast<int>(LIBRARY->creh->expRanks[tier][rank] - stack->getAverageExperience());
|
||||
boost::replace_first(expText, "%i", std::to_string(number));
|
||||
|
||||
number = LIBRARY->creh->maxExpPerBattle[tier]; //percent
|
||||
@ -977,10 +977,10 @@ std::string CStackWindow::generateStackExpDescription()
|
||||
number *= LIBRARY->creh->expRanks[tier].back() / 100; //actual amount
|
||||
boost::replace_first(expText, "%i", std::to_string(number));
|
||||
|
||||
boost::replace_first(expText, "%i", std::to_string(stack->count)); //Number of Creatures in stack
|
||||
boost::replace_first(expText, "%i", std::to_string(stack->getCount())); //Number of Creatures in stack
|
||||
|
||||
int expmin = std::max(LIBRARY->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
|
||||
number = static_cast<int>((stack->count * (stack->experience - expmin)) / expmin); //Maximum New Recruits without losing current Rank
|
||||
number = stack->getTotalExperience() / expmin - stack->getCount(); //Maximum New Recruits without losing current Rank
|
||||
boost::replace_first(expText, "%i", std::to_string(number)); //TODO
|
||||
|
||||
boost::replace_first(expText, "%.2f", std::to_string(1)); //TODO Experience Multiplier
|
||||
@ -991,7 +991,7 @@ std::string CStackWindow::generateStackExpDescription()
|
||||
int expmax = LIBRARY->creh->expRanks[tier][10];
|
||||
number = expmax - expmin;
|
||||
boost::replace_first(expText, "%i", std::to_string(number)); //Experience after Rank 10
|
||||
number = (stack->count * (expmax - expmin)) / expmin;
|
||||
number = (stack->getCount() * (expmax - expmin)) / expmin;
|
||||
boost::replace_first(expText, "%i", std::to_string(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience
|
||||
|
||||
return expText;
|
||||
|
@ -43,6 +43,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
|
||||
quitb->setBorderColor(Colors::METALLIC_GOLD);
|
||||
|
||||
mapView = std::make_shared<PuzzleMapView>(Point(8,9), Point(591, 544), grailPos);
|
||||
mapView->needFullUpdate = true;
|
||||
|
||||
logo = std::make_shared<CPicture>(ImagePath::builtin("PUZZLOGO"), 607, 3);
|
||||
title = std::make_shared<CLabel>(700, 95, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, LIBRARY->generaltexth->allTexts[463]);
|
||||
@ -93,4 +94,7 @@ void CPuzzleWindow::show(Canvas & to)
|
||||
currentAlpha -= animSpeed;
|
||||
}
|
||||
CWindowObject::show(to);
|
||||
|
||||
if(mapView->needFullUpdate && piecesToRemove.empty())
|
||||
mapView->needFullUpdate = false;
|
||||
}
|
||||
|
@ -481,12 +481,12 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="82"/>
|
||||
<source>Config editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>配置编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="89"/>
|
||||
<source>Open editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>打开编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="102"/>
|
||||
@ -588,7 +588,7 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
|
||||
<source>Ignore mute switch</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>忽略静音开关</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="693"/>
|
||||
@ -876,37 +876,37 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>保存</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
|
||||
<source>File:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>文件:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
|
||||
<source>Close</source>
|
||||
<translation type="unfinished">关闭</translation>
|
||||
<translation>关闭</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
|
||||
<source>Config editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>配置编辑器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="68"/>
|
||||
<source>Unsaved changes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>未保存的改动</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="68"/>
|
||||
<source>Do you want to discard changes?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>是否放弃更改?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="122"/>
|
||||
<source>JSON file is not valid!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>JSON文件格式错误!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1168,7 +1168,7 @@ Please select the directory with Heroes III: Complete Edition or Heroes III: Sha
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="369"/>
|
||||
<source>Failed to open file: %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>打开文件失败:%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="438"/>
|
||||
@ -1318,18 +1318,19 @@ Bin (%n字节):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="23"/>
|
||||
<source>Belarusian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>
|
||||
白俄罗斯语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="24"/>
|
||||
<source>Bulgarian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>保加利亚语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="25"/>
|
||||
<source>Czech</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">捷克语</translation>
|
||||
<translation>捷克语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="26"/>
|
||||
@ -1340,111 +1341,100 @@ Bin (%n字节):
|
||||
<location filename="../languages.cpp" line="27"/>
|
||||
<source>English</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">英语</translation>
|
||||
<translation>英语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="28"/>
|
||||
<source>Finnish</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">芬兰语</translation>
|
||||
<translation>芬兰语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="29"/>
|
||||
<source>French</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">法语</translation>
|
||||
<translation>法语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="30"/>
|
||||
<source>German</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">德语</translation>
|
||||
<translation>德语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="31"/>
|
||||
<source>Greek</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>希腊语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="32"/>
|
||||
<source>Hungarian</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">匈牙利语</translation>
|
||||
<translation>匈牙利语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="33"/>
|
||||
<source>Italian</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">意大利语</translation>
|
||||
<translation>意大利语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="34"/>
|
||||
<source>Japanese</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>日本语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="35"/>
|
||||
<source>Korean</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">韩语</translation>
|
||||
<translation>朝鲜语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="36"/>
|
||||
<source>Norwegian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>挪威语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="37"/>
|
||||
<source>Polish</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">波兰语</translation>
|
||||
<translation>波兰语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="38"/>
|
||||
<source>Portuguese</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">葡萄牙语</translation>
|
||||
<translation>葡萄牙语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="39"/>
|
||||
<source>Romanian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>罗马尼亚语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="40"/>
|
||||
<source>Russian</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">俄语</translation>
|
||||
<translation>俄语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="41"/>
|
||||
<source>Spanish</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">西班牙语</translation>
|
||||
<translation>西班牙语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="42"/>
|
||||
<source>Swedish</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">瑞典语</translation>
|
||||
<translation>瑞典语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="43"/>
|
||||
<source>Turkish</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">土耳其语</translation>
|
||||
<translation>土耳其语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="44"/>
|
||||
<source>Ukrainian</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">乌克兰语</translation>
|
||||
<translation>乌克兰语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="45"/>
|
||||
<source>Vietnamese</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">越南语</translation>
|
||||
<translation>越南语</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="67"/>
|
||||
@ -1685,7 +1675,7 @@ Bin (%n字节):
|
||||
<message>
|
||||
<location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
|
||||
<source>Campaigns</source>
|
||||
<translation type="unfinished">战役</translation>
|
||||
<translation>战役</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
|
||||
@ -1979,13 +1969,13 @@ To resolve this problem, please copy missing data files from Heroes III to VCMI
|
||||
<location filename="../startGame/StartGameTab.cpp" line="407"/>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="416"/>
|
||||
<source>Preset import failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>预设导入失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="407"/>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="416"/>
|
||||
<source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>导入预设失败——剪切板中的数据并非模组预设数据!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="432"/>
|
||||
|
@ -307,20 +307,17 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="482"/>
|
||||
<source>Context menu</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">Menu de contexto</translation>
|
||||
<translation>Menu de contexto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="525"/>
|
||||
<source>Open directory</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">Abrir diretório</translation>
|
||||
<translation>Abrir diretório</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="530"/>
|
||||
<source>Open repository</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">Abrir repositório</translation>
|
||||
<translation>Abrir repositório</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="783"/>
|
||||
@ -475,12 +472,12 @@ O download da instalação foi bem-sucedido?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="82"/>
|
||||
<source>Config editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Editor de configuração</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="89"/>
|
||||
<source>Open editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Abrir editor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="102"/>
|
||||
@ -510,8 +507,7 @@ O download da instalação foi bem-sucedido?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="547"/>
|
||||
<source>Allow portrait mode</source>
|
||||
<translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
|
||||
<translation type="unfinished">Permitir modo retrato</translation>
|
||||
<translation>Permitir modo retrato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="825"/>
|
||||
@ -583,7 +579,7 @@ Modo de tela cheia exclusivo - o jogo cobrirá toda a sua tela e usará a resolu
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
|
||||
<source>Ignore mute switch</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ignorar botão de mudo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="693"/>
|
||||
@ -875,37 +871,37 @@ Modo de tela cheia exclusivo - o jogo cobrirá toda a sua tela e usará a resolu
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Salvar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
|
||||
<source>File:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Arquivo:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
|
||||
<source>Close</source>
|
||||
<translation type="unfinished">Fechar</translation>
|
||||
<translation>Fechar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
|
||||
<source>Config editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Editor de configuração</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="68"/>
|
||||
<source>Unsaved changes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Alterações não salvas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="68"/>
|
||||
<source>Do you want to discard changes?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Deseja descartar as alterações?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/configeditordialog_moc.cpp" line="122"/>
|
||||
<source>JSON file is not valid!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>O arquivo JSON não é válido!</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1171,7 +1167,7 @@ Por favor, selecione o diretório com Heroes III: Complete Edition ou Heroes III
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="369"/>
|
||||
<source>Failed to open file: %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Falha ao abrir o arquivo: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="462"/>
|
||||
@ -1322,12 +1318,12 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="23"/>
|
||||
<source>Belarusian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Bielorrusso</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="24"/>
|
||||
<source>Bulgarian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Búlgaro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="25"/>
|
||||
@ -1362,7 +1358,7 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="31"/>
|
||||
<source>Greek</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Grego</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="32"/>
|
||||
@ -1377,7 +1373,7 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="34"/>
|
||||
<source>Japanese</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Japonês</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="35"/>
|
||||
@ -1387,7 +1383,7 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="36"/>
|
||||
<source>Norwegian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Norueguês</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="37"/>
|
||||
@ -1402,7 +1398,7 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="39"/>
|
||||
<source>Romanian</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Romeno</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../languages.cpp" line="40"/>
|
||||
@ -1673,7 +1669,7 @@ Bin (%n bytes):
|
||||
<message>
|
||||
<location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
|
||||
<source>Campaigns</source>
|
||||
<translation type="unfinished">Campanhas</translation>
|
||||
<translation>Campanhas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
|
||||
@ -1969,13 +1965,13 @@ Para resolver esse problema, copie manualmente os arquivos de dados ausentes do
|
||||
<location filename="../startGame/StartGameTab.cpp" line="407"/>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="416"/>
|
||||
<source>Preset import failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Falha na importação da predefinição</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="407"/>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="416"/>
|
||||
<source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Falha ao importar predefinição - os dados na área de transferência não parecem ser uma predefinição de mod!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../startGame/StartGameTab.cpp" line="432"/>
|
||||
|
@ -125,7 +125,7 @@ std::vector<SlotID> CCreatureSet::getCreatureSlots(const CCreature * c, const Sl
|
||||
if(!elem.second || !elem.second->getType() || elem.second->getType() != c)
|
||||
continue;
|
||||
|
||||
if(elem.second->count == ignoreAmount || elem.second->count < 1)
|
||||
if(elem.second->getCount() == ignoreAmount || elem.second->getCount() < 1)
|
||||
continue;
|
||||
|
||||
result.push_back(elem.first);
|
||||
@ -144,7 +144,7 @@ bool CCreatureSet::isCreatureBalanced(const CCreature * c, TQuantity ignoreAmoun
|
||||
if(!elem.second || !elem.second->getType() || elem.second->getType() != c)
|
||||
continue;
|
||||
|
||||
const auto count = elem.second->count;
|
||||
const auto count = elem.second->getCount();
|
||||
|
||||
if(count == ignoreAmount || count < 1)
|
||||
continue;
|
||||
@ -236,20 +236,19 @@ TCreatureQueue CCreatureSet::getCreatureQueue(const SlotID & exclude) const
|
||||
|
||||
TQuantity CCreatureSet::getStackCount(const SlotID & slot) const
|
||||
{
|
||||
auto i = stacks.find(slot);
|
||||
if (i != stacks.end())
|
||||
return i->second->count;
|
||||
else
|
||||
return 0; //TODO? consider issuing a warning
|
||||
if (!hasStackAtSlot(slot))
|
||||
return 0;
|
||||
return stacks.at(slot)->getCount();
|
||||
}
|
||||
|
||||
TExpType CCreatureSet::getStackExperience(const SlotID & slot) const
|
||||
TExpType CCreatureSet::getStackTotalExperience(const SlotID & slot) const
|
||||
{
|
||||
auto i = stacks.find(slot);
|
||||
if (i != stacks.end())
|
||||
return i->second->experience;
|
||||
else
|
||||
return 0; //TODO? consider issuing a warning
|
||||
return stacks.at(slot)->getTotalExperience();
|
||||
}
|
||||
|
||||
TExpType CCreatureSet::getStackAverageExperience(const SlotID & slot) const
|
||||
{
|
||||
return stacks.at(slot)->getAverageExperience();
|
||||
}
|
||||
|
||||
bool CCreatureSet::mergeableStacks(std::pair<SlotID, SlotID> & out, const SlotID & preferable) const /*looks for two same stacks, returns slot positions */
|
||||
@ -284,19 +283,6 @@ bool CCreatureSet::mergeableStacks(std::pair<SlotID, SlotID> & out, const SlotID
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCreatureSet::sweep()
|
||||
{
|
||||
for(auto i=stacks.begin(); i!=stacks.end(); ++i)
|
||||
{
|
||||
if(!i->second->count)
|
||||
{
|
||||
stacks.erase(i);
|
||||
sweep();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCreatureSet::addToSlot(const SlotID & slot, const CreatureID & cre, TQuantity count, bool allowMerging)
|
||||
{
|
||||
const CCreature *c = cre.toCreature();
|
||||
@ -437,23 +423,24 @@ void CCreatureSet::setFormation(EArmyFormation mode)
|
||||
|
||||
void CCreatureSet::setStackCount(const SlotID & slot, TQuantity count)
|
||||
{
|
||||
assert(hasStackAtSlot(slot));
|
||||
assert(stacks[slot]->count + count > 0);
|
||||
if (count > stacks[slot]->count)
|
||||
stacks[slot]->experience = static_cast<TExpType>(stacks[slot]->experience * (count / static_cast<double>(stacks[slot]->count)));
|
||||
stacks[slot]->count = count;
|
||||
stacks.at(slot)->setCount(count);
|
||||
armyChanged();
|
||||
}
|
||||
|
||||
void CCreatureSet::giveStackExp(TExpType exp)
|
||||
void CCreatureSet::giveAverageStackExperience(TExpType exp)
|
||||
{
|
||||
for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); i++)
|
||||
i->second->giveStackExp(exp);
|
||||
for(const auto & stack : stacks)
|
||||
{
|
||||
stack.second->giveAverageStackExperience(exp);
|
||||
stack.second->nodeHasChanged();
|
||||
}
|
||||
}
|
||||
void CCreatureSet::setStackExp(const SlotID & slot, TExpType exp)
|
||||
|
||||
void CCreatureSet::giveTotalStackExperience(const SlotID & slot, TExpType exp)
|
||||
{
|
||||
assert(hasStackAtSlot(slot));
|
||||
stacks[slot]->experience = exp;
|
||||
stacks[slot]->giveTotalStackExperience(exp);
|
||||
stacks[slot]->nodeHasChanged();
|
||||
}
|
||||
|
||||
void CCreatureSet::clearSlots()
|
||||
@ -528,7 +515,23 @@ void CCreatureSet::joinStack(const SlotID & slot, std::unique_ptr<CStackInstance
|
||||
assert(c);
|
||||
|
||||
//TODO move stuff
|
||||
changeStackCount(slot, stack->count);
|
||||
changeStackCount(slot, stack->getCount());
|
||||
giveTotalStackExperience(slot, stack->getTotalExperience());
|
||||
}
|
||||
|
||||
std::unique_ptr<CStackInstance> CCreatureSet::splitStack(const SlotID & slot, TQuantity toSplit)
|
||||
{
|
||||
auto & currentStack = stacks.at(slot);
|
||||
assert(currentStack->getCount() > toSplit);
|
||||
|
||||
TExpType experienceBefore = currentStack->getTotalExperience();
|
||||
currentStack->setCount(currentStack->getCount() - toSplit);
|
||||
TExpType experienceAfter = currentStack->getTotalExperience();
|
||||
|
||||
auto newStack = std::make_unique<CStackInstance>(currentStack->cb, currentStack->getCreatureID(), toSplit);
|
||||
newStack->giveTotalStackExperience(experienceBefore - experienceAfter);
|
||||
|
||||
return newStack;
|
||||
}
|
||||
|
||||
void CCreatureSet::changeStackCount(const SlotID & slot, TQuantity toAdd)
|
||||
@ -674,14 +677,13 @@ void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::strin
|
||||
|
||||
CStackInstance::CStackInstance(IGameCallback *cb, bool isHypothetic)
|
||||
: CBonusSystemNode(isHypothetic)
|
||||
, CStackBasicDescriptor(nullptr, 0)
|
||||
, CArtifactSet(cb)
|
||||
, GameCallbackHolder(cb)
|
||||
, nativeTerrain(this, Selector::type()(BonusType::TERRAIN_NATIVE))
|
||||
, initiative(this, Selector::type()(BonusType::STACKS_SPEED))
|
||||
, totalExperience(0)
|
||||
{
|
||||
experience = 0;
|
||||
count = 0;
|
||||
setType(nullptr);
|
||||
setNodeType(STACK_INSTANCE);
|
||||
}
|
||||
|
||||
@ -689,12 +691,12 @@ CStackInstance::CStackInstance(IGameCallback *cb, const CreatureID & id, TQuanti
|
||||
: CStackInstance(cb, false)
|
||||
{
|
||||
setType(id);
|
||||
count = Count;
|
||||
setCount(Count);
|
||||
}
|
||||
|
||||
CCreature::CreatureQuantityId CStackInstance::getQuantityID() const
|
||||
{
|
||||
return CCreature::getQuantityID(count);
|
||||
return CCreature::getQuantityID(getCount());
|
||||
}
|
||||
|
||||
int CStackInstance::getExpRank() const
|
||||
@ -706,7 +708,7 @@ int CStackInstance::getExpRank() const
|
||||
{
|
||||
for(int i = static_cast<int>(LIBRARY->creh->expRanks[tier].size()) - 2; i > -1; --i) //sic!
|
||||
{ //exp values vary from 1st level to max exp at 11th level
|
||||
if (experience >= LIBRARY->creh->expRanks[tier][i])
|
||||
if (getAverageExperience() >= LIBRARY->creh->expRanks[tier][i])
|
||||
return ++i; //faster, but confusing - 0 index mean 1st level of experience
|
||||
}
|
||||
return 0;
|
||||
@ -715,7 +717,7 @@ int CStackInstance::getExpRank() const
|
||||
{
|
||||
for(int i = static_cast<int>(LIBRARY->creh->expRanks[0].size()) - 2; i > -1; --i)
|
||||
{
|
||||
if (experience >= LIBRARY->creh->expRanks[0][i])
|
||||
if (getAverageExperience() >= LIBRARY->creh->expRanks[0][i])
|
||||
return ++i;
|
||||
}
|
||||
return 0;
|
||||
@ -727,17 +729,47 @@ int CStackInstance::getLevel() const
|
||||
return std::max(1, getType()->getLevel());
|
||||
}
|
||||
|
||||
void CStackInstance::giveStackExp(TExpType exp)
|
||||
void CStackInstance::giveAverageStackExperience(TExpType desiredAmountPerUnit)
|
||||
{
|
||||
int level = getType()->getLevel();
|
||||
if (!vstd::iswithin(level, 1, 7))
|
||||
level = 0;
|
||||
if (!canGainExperience())
|
||||
return;
|
||||
|
||||
ui32 maxExp = LIBRARY->creh->expRanks[level].back();
|
||||
int level = std::clamp(getLevel(), 1, 7);
|
||||
TExpType maxAmountPerUnit = LIBRARY->creh->expRanks[level].back();
|
||||
TExpType actualAmountPerUnit = std::min(desiredAmountPerUnit, maxAmountPerUnit * LIBRARY->creh->maxExpPerBattle[level]/100);
|
||||
TExpType maxExperience = maxAmountPerUnit * getCount();
|
||||
TExpType maxExperienceToGain = maxExperience - totalExperience;
|
||||
TExpType actualGainedExperience = std::min(maxExperienceToGain, actualAmountPerUnit * getCount());
|
||||
|
||||
vstd::amin(exp, static_cast<TExpType>(maxExp)); //prevent exp overflow due to different types
|
||||
vstd::amin(exp, (maxExp * LIBRARY->creh->maxExpPerBattle[level])/100);
|
||||
vstd::amin(experience += exp, maxExp); //can't get more exp than this limit
|
||||
totalExperience += actualGainedExperience;
|
||||
}
|
||||
|
||||
void CStackInstance::giveTotalStackExperience(TExpType experienceToGive)
|
||||
{
|
||||
if (!canGainExperience())
|
||||
return;
|
||||
|
||||
int level = std::clamp(getLevel(), 1, 7);
|
||||
TExpType maxAmountPerUnit = LIBRARY->creh->expRanks[level].back();
|
||||
TExpType maxExperience = maxAmountPerUnit * getCount();
|
||||
TExpType maxExperienceToGain = maxExperience - totalExperience;
|
||||
TExpType actualGainedExperience = std::min(maxExperienceToGain, experienceToGive);
|
||||
totalExperience += actualGainedExperience;
|
||||
}
|
||||
|
||||
TExpType CStackInstance::getTotalExperience() const
|
||||
{
|
||||
return totalExperience;
|
||||
}
|
||||
|
||||
TExpType CStackInstance::getAverageExperience() const
|
||||
{
|
||||
return totalExperience / getCount();
|
||||
}
|
||||
|
||||
bool CStackInstance::canGainExperience() const
|
||||
{
|
||||
return cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE);
|
||||
}
|
||||
|
||||
void CStackInstance::setType(const CreatureID & creID)
|
||||
@ -753,8 +785,8 @@ void CStackInstance::setType(const CCreature *c)
|
||||
if(getCreature())
|
||||
{
|
||||
detachFromSource(*getCreature());
|
||||
if (getCreature()->isMyUpgrade(c) && LIBRARY->engineSettings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
||||
experience = static_cast<TExpType>(experience * LIBRARY->creh->expAfterUpgrade / 100.0);
|
||||
if (LIBRARY->engineSettings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
||||
totalExperience = totalExperience * LIBRARY->creh->expAfterUpgrade / 100;
|
||||
}
|
||||
|
||||
CStackBasicDescriptor::setType(c);
|
||||
@ -762,6 +794,20 @@ void CStackInstance::setType(const CCreature *c)
|
||||
if(getCreature())
|
||||
attachToSource(*getCreature());
|
||||
}
|
||||
|
||||
void CStackInstance::setCount(TQuantity newCount)
|
||||
{
|
||||
assert(newCount >= 0);
|
||||
|
||||
if (newCount < getCount())
|
||||
{
|
||||
TExpType averageExperience = totalExperience / getCount();
|
||||
totalExperience = averageExperience * newCount;
|
||||
}
|
||||
|
||||
CStackBasicDescriptor::setCount(newCount);
|
||||
}
|
||||
|
||||
std::string CStackInstance::bonusToString(const std::shared_ptr<Bonus>& bonus, bool description) const
|
||||
{
|
||||
return LIBRARY->getBth()->bonusToString(bonus, this, description);
|
||||
@ -774,32 +820,28 @@ ImagePath CStackInstance::bonusToGraphics(const std::shared_ptr<Bonus> & bonus)
|
||||
|
||||
CArmedInstance * CStackInstance::getArmy()
|
||||
{
|
||||
if (armyInstanceID.hasValue())
|
||||
return dynamic_cast<CArmedInstance*>(cb->gameState().getObjInstance(armyInstanceID));
|
||||
return nullptr;
|
||||
return armyInstance;
|
||||
}
|
||||
|
||||
const CArmedInstance * CStackInstance::getArmy() const
|
||||
{
|
||||
if (armyInstanceID.hasValue())
|
||||
return dynamic_cast<const CArmedInstance*>(cb->getObjInstance(armyInstanceID));
|
||||
return nullptr;
|
||||
return armyInstance;
|
||||
}
|
||||
|
||||
void CStackInstance::setArmy(const CArmedInstance * ArmyObj)
|
||||
void CStackInstance::setArmy(CArmedInstance * ArmyObj)
|
||||
{
|
||||
auto oldArmy = getArmy();
|
||||
|
||||
if(oldArmy)
|
||||
{
|
||||
detachFrom(*oldArmy);
|
||||
armyInstanceID = {};
|
||||
armyInstance = nullptr;
|
||||
}
|
||||
|
||||
if(ArmyObj)
|
||||
{
|
||||
attachTo(const_cast<CArmedInstance&>(*ArmyObj));
|
||||
armyInstanceID = ArmyObj->id;
|
||||
armyInstance = ArmyObj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,7 +873,7 @@ bool CStackInstance::valid(bool allowUnrandomized) const
|
||||
std::string CStackInstance::nodeName() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Stack of " << count << " of ";
|
||||
oss << "Stack of " << getCount() << " of ";
|
||||
if(getType())
|
||||
oss << getType()->getNamePluralTextID();
|
||||
else
|
||||
@ -861,12 +903,13 @@ TerrainId CStackInstance::getNativeTerrain() const
|
||||
|
||||
return getFactionID().toEntity(LIBRARY)->getNativeTerrain();
|
||||
}
|
||||
|
||||
TerrainId CStackInstance::getCurrentTerrain() const
|
||||
{
|
||||
assert(getArmy() != nullptr);
|
||||
return getArmy()->getCurrentTerrain();
|
||||
}
|
||||
|
||||
|
||||
CreatureID CStackInstance::getCreatureID() const
|
||||
{
|
||||
if(getType())
|
||||
@ -877,19 +920,19 @@ CreatureID CStackInstance::getCreatureID() const
|
||||
|
||||
std::string CStackInstance::getName() const
|
||||
{
|
||||
return (count > 1) ? getType()->getNamePluralTranslated() : getType()->getNameSingularTranslated();
|
||||
return (getCount() > 1) ? getType()->getNamePluralTranslated() : getType()->getNameSingularTranslated();
|
||||
}
|
||||
|
||||
ui64 CStackInstance::getPower() const
|
||||
{
|
||||
assert(getType());
|
||||
return static_cast<ui64>(getType()->getAIValue()) * count;
|
||||
return static_cast<ui64>(getType()->getAIValue()) * getCount();
|
||||
}
|
||||
|
||||
ui64 CStackInstance::getMarketValue() const
|
||||
{
|
||||
assert(getType());
|
||||
return getType()->getFullRecruitCost().marketValue() * count;
|
||||
return getType()->getFullRecruitCost().marketValue() * getCount();
|
||||
}
|
||||
|
||||
ArtBearer::ArtBearer CStackInstance::bearerType() const
|
||||
@ -968,9 +1011,8 @@ CCommanderInstance::CCommanderInstance(IGameCallback *cb, const CreatureID & id)
|
||||
, name("Commando")
|
||||
{
|
||||
alive = true;
|
||||
experience = 0;
|
||||
level = 1;
|
||||
count = 1;
|
||||
setCount(1);
|
||||
setType(nullptr);
|
||||
setNodeType (CBonusSystemNode::COMMANDER);
|
||||
secondarySkills.resize (ECommander::SPELL_POWER + 1);
|
||||
@ -988,15 +1030,14 @@ void CCommanderInstance::setAlive (bool Alive)
|
||||
}
|
||||
}
|
||||
|
||||
void CCommanderInstance::giveStackExp (TExpType exp)
|
||||
bool CCommanderInstance::canGainExperience() const
|
||||
{
|
||||
if (alive)
|
||||
experience += exp;
|
||||
return alive && CStackInstance::canGainExperience();
|
||||
}
|
||||
|
||||
int CCommanderInstance::getExpRank() const
|
||||
{
|
||||
return LIBRARY->heroh->level (experience);
|
||||
return LIBRARY->heroh->level (getTotalExperience());
|
||||
}
|
||||
|
||||
int CCommanderInstance::getLevel() const
|
||||
@ -1020,7 +1061,7 @@ ArtBearer::ArtBearer CCommanderInstance::bearerType() const
|
||||
|
||||
bool CCommanderInstance::gainsLevel() const
|
||||
{
|
||||
return experience >= LIBRARY->heroh->reqExp(level + 1);
|
||||
return getTotalExperience() >= LIBRARY->heroh->reqExp(level + 1);
|
||||
}
|
||||
|
||||
//This constructor should be placed here to avoid side effects
|
||||
@ -1062,6 +1103,12 @@ void CStackBasicDescriptor::setType(const CCreature * c)
|
||||
typeID = c ? c->getId() : CreatureID();
|
||||
}
|
||||
|
||||
void CStackBasicDescriptor::setCount(TQuantity newCount)
|
||||
{
|
||||
assert(newCount >= 0);
|
||||
count = newCount;
|
||||
}
|
||||
|
||||
bool operator== (const CStackBasicDescriptor & l, const CStackBasicDescriptor & r)
|
||||
{
|
||||
return l.typeID == r.typeID && l.count == r.count;
|
||||
|
@ -33,9 +33,9 @@ class JsonSerializeFormat;
|
||||
class DLL_LINKAGE CStackBasicDescriptor
|
||||
{
|
||||
CreatureID typeID;
|
||||
public:
|
||||
TQuantity count = -1; //exact quantity or quantity ID from CCreature::getQuantityID when getting info about enemy army
|
||||
|
||||
public:
|
||||
CStackBasicDescriptor();
|
||||
CStackBasicDescriptor(const CreatureID & id, TQuantity Count);
|
||||
CStackBasicDescriptor(const CCreature *c, TQuantity Count);
|
||||
@ -47,6 +47,7 @@ public:
|
||||
TQuantity getCount() const;
|
||||
|
||||
virtual void setType(const CCreature * c);
|
||||
virtual void setCount(TQuantity amount);
|
||||
|
||||
friend bool operator== (const CStackBasicDescriptor & l, const CStackBasicDescriptor & r);
|
||||
|
||||
@ -75,9 +76,11 @@ class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDe
|
||||
BonusValueCache nativeTerrain;
|
||||
BonusValueCache initiative;
|
||||
|
||||
ObjectInstanceID armyInstanceID; //stack must be part of some army, army must be part of some object
|
||||
CArmedInstance * armyInstance = nullptr; //stack must be part of some army, army must be part of some object
|
||||
|
||||
IGameCallback * getCallback() const final { return cb; }
|
||||
|
||||
TExpType totalExperience;//commander needs same amount of exp as hero
|
||||
public:
|
||||
struct RandomStackInfo
|
||||
{
|
||||
@ -89,9 +92,11 @@ public:
|
||||
|
||||
CArmedInstance * getArmy();
|
||||
const CArmedInstance * getArmy() const; //stack must be part of some army, army must be part of some object
|
||||
void setArmy(const CArmedInstance *ArmyObj);
|
||||
void setArmy(CArmedInstance *ArmyObj);
|
||||
|
||||
TExpType experience;//commander needs same amount of exp as hero
|
||||
TExpType getTotalExperience() const;
|
||||
TExpType getAverageExperience() const;
|
||||
virtual bool canGainExperience() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
@ -99,17 +104,26 @@ public:
|
||||
h & static_cast<CStackBasicDescriptor&>(*this);
|
||||
h & static_cast<CArtifactSet&>(*this);
|
||||
|
||||
if (h.hasFeature(Handler::Version::STACK_INSTANCE_ARMY_FIX))
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
if (h.hasFeature(Handler::Version::NO_RAW_POINTERS_IN_SERIALIZER))
|
||||
{
|
||||
h & armyInstanceID;
|
||||
ObjectInstanceID dummyID;
|
||||
h & dummyID;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::shared_ptr<CGObjectInstance> army;
|
||||
h & army;
|
||||
armyInstanceID = army->id;
|
||||
}
|
||||
h & experience;
|
||||
|
||||
h & totalExperience;
|
||||
if (!h.hasFeature(Handler::Version::STACK_INSTANCE_EXPERIENCE_FIX))
|
||||
{
|
||||
totalExperience *= getCount();
|
||||
}
|
||||
}
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
@ -138,7 +152,12 @@ public:
|
||||
|
||||
void setType(const CreatureID & creID);
|
||||
void setType(const CCreature * c) final;
|
||||
virtual void giveStackExp(TExpType exp);
|
||||
void setCount(TQuantity amount) final;
|
||||
|
||||
/// Gives specified amount of stack experience that will not be scaled by unit size
|
||||
void giveAverageStackExperience(TExpType exp);
|
||||
void giveTotalStackExperience(TExpType exp);
|
||||
|
||||
bool valid(bool allowUnrandomized) const;
|
||||
ArtPlacementMap putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art) override;//from CArtifactSet
|
||||
void removeArtifact(const ArtifactPosition & pos) override;
|
||||
@ -166,9 +185,9 @@ public:
|
||||
CCommanderInstance(IGameCallback *cb);
|
||||
CCommanderInstance(IGameCallback *cb, const CreatureID & id);
|
||||
void setAlive (bool alive);
|
||||
void giveStackExp (TExpType exp) override;
|
||||
void levelUp ();
|
||||
|
||||
bool canGainExperience() const override;
|
||||
bool gainsLevel() const; //true if commander has lower level than should upon his experience
|
||||
ui64 getPower() const override {return 0;};
|
||||
int getExpRank() const override;
|
||||
@ -255,12 +274,26 @@ public:
|
||||
void setStackCount(const SlotID & slot, TQuantity count); //stack must exist!
|
||||
std::unique_ptr<CStackInstance> detachStack(const SlotID & slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted)
|
||||
void setStackType(const SlotID & slot, const CreatureID & type);
|
||||
void giveStackExp(TExpType exp);
|
||||
void setStackExp(const SlotID & slot, TExpType exp);
|
||||
|
||||
//derivative
|
||||
void eraseStack(const SlotID & slot); //slot must be occupied
|
||||
/// Give specified amount of experience to all units in army
|
||||
/// Amount of granted experience is scaled by unit stack size
|
||||
void giveAverageStackExperience(TExpType exp);
|
||||
|
||||
/// Give specified amount of experience to unit in specified slot
|
||||
/// Amount of granted experience is not scaled by unit stack size
|
||||
void giveTotalStackExperience(const SlotID & slot, TExpType exp);
|
||||
|
||||
/// Erased stack from specified slot. Slot must be non-empty
|
||||
void eraseStack(const SlotID & slot);
|
||||
|
||||
/// Joins stack into stack that occupies targeted slot.
|
||||
/// Slot must be non-empty and contain same creature type
|
||||
void joinStack(const SlotID & slot, std::unique_ptr<CStackInstance> stack); //adds new stack to the existing stack of the same type
|
||||
|
||||
/// Splits off some units of specified stack and returns newly created stack
|
||||
/// Slot must be non-empty and contain more units that split quantity
|
||||
std::unique_ptr<CStackInstance> splitStack(const SlotID & slot, TQuantity toSplit);
|
||||
|
||||
void changeStackCount(const SlotID & slot, TQuantity toAdd); //stack must exist!
|
||||
bool setCreature (SlotID slot, CreatureID type, TQuantity quantity) override; //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack
|
||||
void setToArmy(CSimpleArmy &src); //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all.
|
||||
@ -269,7 +302,8 @@ public:
|
||||
CStackInstance * getStackPtr(const SlotID & slot) const; //if stack doesn't exist, returns nullptr
|
||||
const CCreature * getCreature(const SlotID & slot) const; //workaround of map issue;
|
||||
int getStackCount(const SlotID & slot) const;
|
||||
TExpType getStackExperience(const SlotID & slot) const;
|
||||
TExpType getStackTotalExperience(const SlotID & slot) const;
|
||||
TExpType getStackAverageExperience(const SlotID & slot) const;
|
||||
SlotID findStack(const CStackInstance *stack) const; //-1 if none
|
||||
SlotID getSlotFor(const CreatureID & creature, ui32 slotsAmount = GameConstants::ARMY_SIZE) const; //returns -1 if no slot available
|
||||
SlotID getSlotFor(const CCreature *c, ui32 slotsAmount = GameConstants::ARMY_SIZE) const; //returns -1 if no slot available
|
||||
@ -311,7 +345,6 @@ public:
|
||||
{
|
||||
return !stacks.empty();
|
||||
}
|
||||
void sweep();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -360,13 +360,13 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
||||
doBasicDisguise(info);
|
||||
|
||||
for(auto & elem : info.army)
|
||||
elem.second.count = 0;
|
||||
elem.second.setCount(0);
|
||||
};
|
||||
|
||||
auto doExpertDisguise = [this,h](InfoAboutHero & info)
|
||||
{
|
||||
for(auto & elem : info.army)
|
||||
elem.second.count = 0;
|
||||
elem.second.setCount(0);
|
||||
|
||||
const auto factionIndex = getStartInfo()->playerInfos.at(h->tempOwner).castle;
|
||||
|
||||
|
@ -30,7 +30,7 @@ CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, Battle
|
||||
base(Base),
|
||||
ID(I),
|
||||
typeID(Base->getId()),
|
||||
baseAmount(Base->count),
|
||||
baseAmount(Base->getCount()),
|
||||
owner(O),
|
||||
slot(S),
|
||||
side(Side)
|
||||
@ -51,7 +51,7 @@ CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I
|
||||
CBonusSystemNode(STACK_BATTLE),
|
||||
ID(I),
|
||||
typeID(stack->getId()),
|
||||
baseAmount(stack->count),
|
||||
baseAmount(stack->getCount()),
|
||||
owner(O),
|
||||
slot(S),
|
||||
side(Side)
|
||||
|
@ -207,6 +207,8 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b
|
||||
auto possibleSlot = ArtifactUtils::getArtAnyPosition(&fittingSet, art->getId());
|
||||
if(ArtifactUtils::isSlotEquipment(possibleSlot))
|
||||
{
|
||||
if (fittingSet.getSlot(possibleSlot) == nullptr)
|
||||
fittingSet.artifactsWorn.insert(std::make_pair(possibleSlot, ArtSlotInfo(fittingSet.cb)));
|
||||
fittingSet.lockSlot(possibleSlot);
|
||||
}
|
||||
else
|
||||
|
@ -1304,7 +1304,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
|
||||
{
|
||||
for(const auto & elem : ai->Slots()) //iterate through army
|
||||
if(elem.second->getId() == condition.objectType.as<CreatureID>()) //it's searched creature
|
||||
total += elem.second->count;
|
||||
total += elem.second->getCount();
|
||||
}
|
||||
}
|
||||
return total >= condition.value;
|
||||
@ -1766,13 +1766,13 @@ void CGameState::loadGame(CLoadFile & file)
|
||||
logGlobal->info("Loading game state...");
|
||||
|
||||
CMapHeader dummyHeader;
|
||||
auto startInfo = std::make_shared<StartInfo>();
|
||||
StartInfo dummyStartInfo;
|
||||
ActiveModsInSaveList dummyActiveMods;
|
||||
|
||||
file.load(dummyHeader);
|
||||
if (file.hasFeature(ESerializationVersion::NO_RAW_POINTERS_IN_SERIALIZER))
|
||||
{
|
||||
file.load(startInfo);
|
||||
file.load(dummyStartInfo);
|
||||
file.load(dummyActiveMods);
|
||||
file.load(*this);
|
||||
}
|
||||
@ -1781,7 +1781,7 @@ void CGameState::loadGame(CLoadFile & file)
|
||||
bool dummyA = false;
|
||||
uint32_t dummyB = 0;
|
||||
uint16_t dummyC = 0;
|
||||
file.load(startInfo);
|
||||
file.load(dummyStartInfo);
|
||||
file.load(dummyActiveMods);
|
||||
file.load(dummyA);
|
||||
file.load(dummyB);
|
||||
|
@ -43,12 +43,12 @@ int ArmyDescriptor::getStrength() const
|
||||
if(isDetailed)
|
||||
{
|
||||
for(const auto & elem : *this)
|
||||
ret += elem.second.getType()->getAIValue() * elem.second.count;
|
||||
ret += elem.second.getType()->getAIValue() * elem.second.getCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto & elem : *this)
|
||||
ret += elem.second.getType()->getAIValue() * CCreature::estimateCreatureCount(elem.second.count);
|
||||
ret += elem.second.getType()->getAIValue() * CCreature::estimateCreatureCount(elem.second.getCount());
|
||||
}
|
||||
return static_cast<int>(ret);
|
||||
}
|
||||
|
@ -504,7 +504,7 @@ JsonRandomizationException::JsonRandomizationException(const std::string & messa
|
||||
throw JsonRandomizationException("Invalid creature picked!", value);
|
||||
|
||||
stack.setType(pickedCreature.toCreature());
|
||||
stack.count = loadValue(value, rng, variables);
|
||||
stack.setCount(loadValue(value, rng, variables));
|
||||
if (!value["upgradeChance"].isNull() && !stack.getCreature()->upgrades.empty())
|
||||
{
|
||||
if (int(value["upgradeChance"].Float()) > rng.nextInt(99)) // select random upgrade
|
||||
|
@ -104,7 +104,7 @@ void DwellingInstanceConstructor::randomizeObject(CGDwelling * dwelling, vstd::R
|
||||
JsonRandom::Variables emptyVariables;
|
||||
for(auto & stack : randomizer.loadCreatures(guards, rng, emptyVariables))
|
||||
{
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), std::make_unique<CStackInstance>(dwelling->cb, stack.getId(), stack.count));
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), std::make_unique<CStackInstance>(dwelling->cb, stack.getId(), stack.getCount()));
|
||||
}
|
||||
}
|
||||
else if (dwelling->ID == Obj::CREATURE_GENERATOR1 || dwelling->ID == Obj::CREATURE_GENERATOR4)
|
||||
|
@ -175,7 +175,7 @@ void CArmedInstance::attachUnitsToArmy()
|
||||
assert(getArmy() != nullptr);
|
||||
|
||||
for(const auto & elem : stacks)
|
||||
elem.second->attachTo(*getArmy());
|
||||
elem.second->setArmy(getArmy());
|
||||
}
|
||||
|
||||
const IBonusBearer* CArmedInstance::getBonusBearer() const
|
||||
|
@ -55,9 +55,9 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
|
||||
if(hero->hasVisions(this, BonusCustomSubtype::visionsMonsters))
|
||||
{
|
||||
MetaString ms;
|
||||
ms.appendNumber(stacks.begin()->second->count);
|
||||
ms.appendNumber(stacks.begin()->second->getCount());
|
||||
ms.appendRawString(" ");
|
||||
ms.appendName(getCreatureID(), stacks.begin()->second->count);
|
||||
ms.appendName(getCreatureID(), stacks.begin()->second->getCount());
|
||||
return ms.toString();
|
||||
}
|
||||
else
|
||||
@ -288,20 +288,19 @@ void CGCreature::initObj(vstd::RNG & rand)
|
||||
}
|
||||
|
||||
stacks[SlotID(0)]->setType(getCreature());
|
||||
TQuantity &amount = stacks[SlotID(0)]->count;
|
||||
const Creature * c = getCreature();
|
||||
if(amount == 0)
|
||||
if(stacks[SlotID(0)]->getCount() == 0)
|
||||
{
|
||||
amount = rand.nextInt(c->getAdvMapAmountMin(), c->getAdvMapAmountMax());
|
||||
stacks[SlotID(0)]->setCount(rand.nextInt(c->getAdvMapAmountMin(), c->getAdvMapAmountMax()));
|
||||
|
||||
if(amount == 0) //armies with 0 creatures are illegal
|
||||
if(stacks[SlotID(0)]->getCount() == 0) //armies with 0 creatures are illegal
|
||||
{
|
||||
logGlobal->warn("Stack cannot have 0 creatures. Check properties of %s", c->getJsonKey());
|
||||
amount = 1;
|
||||
stacks[SlotID(0)]->setCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
temppower = stacks[SlotID(0)]->count * static_cast<int64_t>(1000);
|
||||
temppower = stacks[SlotID(0)]->getCount() * static_cast<int64_t>(1000);
|
||||
refusedJoining = false;
|
||||
}
|
||||
|
||||
@ -309,7 +308,7 @@ void CGCreature::newTurn(vstd::RNG & rand) const
|
||||
{//Works only for stacks of single type of size up to 2 millions
|
||||
if (!notGrowingTeam)
|
||||
{
|
||||
if (stacks.begin()->second->count < cb->getSettings().getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP) && cb->getDate(Date::DAY_OF_WEEK) == 1 && cb->getDate(Date::DAY) > 1)
|
||||
if (stacks.begin()->second->getCount() < cb->getSettings().getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP) && cb->getDate(Date::DAY_OF_WEEK) == 1 && cb->getDate(Date::DAY) > 1)
|
||||
{
|
||||
ui32 power = static_cast<ui32>(temppower * (100 + cb->getSettings().getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT)) / 100);
|
||||
cb->setObjPropertyValue(id, ObjProperty::MONSTER_COUNT, std::min<uint32_t>(power / 1000, cb->getSettings().getInteger(EGameSettings::CREATURES_WEEKLY_GROWTH_CAP))); //set new amount
|
||||
@ -324,13 +323,13 @@ void CGCreature::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
||||
switch (what)
|
||||
{
|
||||
case ObjProperty::MONSTER_COUNT:
|
||||
stacks[SlotID(0)]->count = identifier.getNum();
|
||||
stacks[SlotID(0)]->setCount(identifier.getNum());
|
||||
break;
|
||||
case ObjProperty::MONSTER_POWER:
|
||||
temppower = identifier.getNum();
|
||||
break;
|
||||
case ObjProperty::MONSTER_EXP:
|
||||
giveStackExp(identifier.getNum());
|
||||
giveAverageStackExperience(identifier.getNum());
|
||||
break;
|
||||
case ObjProperty::MONSTER_REFUSED_JOIN:
|
||||
refusedJoining = identifier.getNum();
|
||||
@ -367,8 +366,8 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
||||
bool isOurDowngrade = vstd::contains(elem.second->getCreature()->upgrades, getCreatureID());
|
||||
|
||||
if(isOurUpgrade || isOurDowngrade)
|
||||
count += elem.second->count;
|
||||
totalCount += elem.second->count;
|
||||
count += elem.second->getCount();
|
||||
totalCount += elem.second->getCount();
|
||||
}
|
||||
|
||||
int sympathy = 0; // 0 if hero have no similar creatures
|
||||
@ -455,7 +454,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
|
||||
giveReward(h);
|
||||
|
||||
for(auto & stack : this->stacks)
|
||||
stack.second->count = getJoiningAmount();
|
||||
stack.second->setCount(getJoiningAmount());
|
||||
|
||||
cb->tryJoiningArmy(this, h, true, true);
|
||||
}
|
||||
@ -538,7 +537,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
|
||||
//first stack has to be at slot 0 -> if original one got killed, move there first remaining stack
|
||||
if(!hasStackAtSlot(SlotID(0)))
|
||||
cb->moveStack(StackLocation(id, stacks.begin()->first), StackLocation(id, SlotID(0)), stacks.begin()->second->count);
|
||||
cb->moveStack(StackLocation(id, stacks.begin()->first), StackLocation(id, SlotID(0)), stacks.begin()->second->getCount());
|
||||
|
||||
while(stacks.size() > 1) //hopefully that's enough
|
||||
{
|
||||
@ -549,10 +548,10 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
if(slot == i->first) //no reason to move stack to its own slot
|
||||
break;
|
||||
else
|
||||
cb->moveStack(StackLocation(id, i->first), StackLocation(id, slot), i->second->count);
|
||||
cb->moveStack(StackLocation(id, i->first), StackLocation(id, slot), i->second->getCount());
|
||||
}
|
||||
|
||||
cb->setObjPropertyValue(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->count * 1000); //remember casualties
|
||||
cb->setObjPropertyValue(id, ObjProperty::MONSTER_POWER, stacks.begin()->second->getCount() * 1000); //remember casualties
|
||||
}
|
||||
}
|
||||
|
||||
@ -615,7 +614,7 @@ int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const
|
||||
else if (R4 >= 80)
|
||||
split += 1;
|
||||
|
||||
vstd::amin(split, getStack(SlotID(0)).count); //can't divide into more stacks than creatures total
|
||||
vstd::amin(split, getStack(SlotID(0)).getCount()); //can't divide into more stacks than creatures total
|
||||
vstd::amin(split, 7); //can't have more than 7 stacks
|
||||
|
||||
return split;
|
||||
@ -664,7 +663,7 @@ void CGCreature::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
if(hasStackAtSlot(SlotID(0)))
|
||||
{
|
||||
si32 amount = getStack(SlotID(0)).count;
|
||||
si32 amount = getStack(SlotID(0)).getCount();
|
||||
handler.serializeInt("amount", amount, 0);
|
||||
}
|
||||
}
|
||||
@ -673,7 +672,7 @@ void CGCreature::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
si32 amount = 0;
|
||||
handler.serializeInt("amount", amount);
|
||||
auto hlp = std::make_unique<CStackInstance>(cb);
|
||||
hlp->count = amount;
|
||||
hlp->setCount(amount);
|
||||
//type will be set during initialization
|
||||
putStack(SlotID(0), std::move(hlp));
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
{
|
||||
commander = std::make_unique<CCommanderInstance>(cb, getHeroClass()->commander);
|
||||
commander->setArmy(getArmy()); //TODO: separate function for setting commanders
|
||||
commander->giveStackExp (exp); //after our exp is set
|
||||
commander->giveTotalStackExperience(exp); //after our exp is set
|
||||
}
|
||||
|
||||
skillsInfo = SecondarySkillsInfo();
|
||||
@ -1610,6 +1610,11 @@ void CGHeroInstance::levelUp(const std::vector<SecondarySkill> & skills)
|
||||
nodeHasChanged();
|
||||
}
|
||||
|
||||
void CGHeroInstance::attachCommanderToArmy()
|
||||
{
|
||||
commander->setArmy(this);
|
||||
}
|
||||
|
||||
void CGHeroInstance::levelUpAutomatically(vstd::RNG & rand)
|
||||
{
|
||||
while(gainsLevel())
|
||||
|
@ -352,6 +352,7 @@ protected:
|
||||
|
||||
private:
|
||||
void levelUpAutomatically(vstd::RNG & rand);
|
||||
void attachCommanderToArmy();
|
||||
|
||||
public:
|
||||
std::string getHeroTypeName() const;
|
||||
@ -396,6 +397,9 @@ public:
|
||||
|
||||
h & commander;
|
||||
h & visitedObjects;
|
||||
|
||||
if(!h.saving && h.loadingGamestate)
|
||||
attachCommanderToArmy();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -138,7 +138,7 @@ void CGPandoraBox::grantRewardWithMessage(const CGHeroInstance * h, int index, b
|
||||
loot.replaceName(c);
|
||||
}
|
||||
|
||||
if(vi.reward.creatures.size() == 1 && vi.reward.creatures[0].count == 1)
|
||||
if(vi.reward.creatures.size() == 1 && vi.reward.creatures[0].getCount() == 1)
|
||||
txt.appendLocalString(EMetaText::ADVOB_TXT, 185);
|
||||
else
|
||||
txt.appendLocalString(EMetaText::ADVOB_TXT, 186);
|
||||
|
@ -644,7 +644,7 @@ void CGTownInstance::clearArmy() const
|
||||
{
|
||||
while(!stacks.empty())
|
||||
{
|
||||
cb->eraseStack(StackLocation(id, stacks.begin()->first));
|
||||
cb->eraseStack(StackLocation(id, stacks.begin()->first), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,15 +112,15 @@ bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
|
||||
{
|
||||
if(it->second->getType() == cre->getType())
|
||||
{
|
||||
count += it->second->count;
|
||||
count += it->second->getCount();
|
||||
slotsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(static_cast<TQuantity>(count) < cre->count) //not enough creatures of this kind
|
||||
if(static_cast<TQuantity>(count) < cre->getCount()) //not enough creatures of this kind
|
||||
return false;
|
||||
|
||||
hasExtraCreatures |= static_cast<TQuantity>(count) > cre->count;
|
||||
hasExtraCreatures |= static_cast<TQuantity>(count) > cre->getCount();
|
||||
}
|
||||
|
||||
return hasExtraCreatures || slotsCount < army->Slots().size();
|
||||
|
@ -609,7 +609,7 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
|
||||
bool CGWhirlpool::isProtected(const CGHeroInstance * h)
|
||||
{
|
||||
return h->hasBonusOfType(BonusType::WHIRLPOOL_PROTECTION)
|
||||
|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1)
|
||||
|| (h->stacksCount() == 1 && h->Slots().begin()->second->getCount() == 1)
|
||||
|| (h->stacksCount() == 0 && h->getCommander() && h->getCommander()->alive);
|
||||
}
|
||||
|
||||
@ -1040,11 +1040,11 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
|
||||
for (auto i = h->Slots().begin(); i != h->Slots().end(); i++)
|
||||
{
|
||||
// 1-sized stacks are not affected by sirens
|
||||
if (i->second->count == 1)
|
||||
if (i->second->getCount() == 1)
|
||||
continue;
|
||||
|
||||
// tested H3 behavior: 30% (rounded up) of stack drowns
|
||||
TQuantity drown = std::ceil(i->second->count * 0.3);
|
||||
TQuantity drown = std::ceil(i->second->getCount() * 0.3);
|
||||
|
||||
if(drown)
|
||||
{
|
||||
|
@ -1191,7 +1191,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readMonster(const int3 & mapPos
|
||||
}
|
||||
|
||||
auto hlp = std::make_unique<CStackInstance>(map->cb);
|
||||
hlp->count = reader->readUInt16();
|
||||
hlp->setCount(reader->readUInt16());
|
||||
|
||||
//type will be set during initialization
|
||||
object->putStack(SlotID(0), std::move(hlp));
|
||||
@ -1975,7 +1975,7 @@ void CMapLoaderH3M::readCreatureSet(CArmedInstance * out, const ObjectInstanceID
|
||||
continue;
|
||||
|
||||
auto result = std::make_unique<CStackInstance>(map->cb);
|
||||
result->count = count;
|
||||
result->setCount(count);
|
||||
|
||||
if(creatureID < CreatureID::NONE)
|
||||
{
|
||||
@ -2427,7 +2427,7 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
for(size_t hh = 0; hh < typeNumber; ++hh)
|
||||
{
|
||||
guard->getQuest().mission.creatures[hh].setType(reader->readCreature().toCreature());
|
||||
guard->getQuest().mission.creatures[hh].count = reader->readUInt16();
|
||||
guard->getQuest().mission.creatures[hh].setCount(reader->readUInt16());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -77,7 +77,6 @@ public:
|
||||
virtual void visitInsertNewStack(InsertNewStack & pack) {}
|
||||
virtual void visitRebalanceStacks(RebalanceStacks & pack) {}
|
||||
virtual void visitBulkRebalanceStacks(BulkRebalanceStacks & pack) {}
|
||||
virtual void visitBulkSmartRebalanceStacks(BulkSmartRebalanceStacks & pack) {}
|
||||
virtual void visitPutArtifact(PutArtifact & pack) {}
|
||||
virtual void visitEraseArtifact(BulkEraseArtifacts & pack) {}
|
||||
virtual void visitBulkMoveArtifacts(BulkMoveArtifacts & pack) {}
|
||||
@ -124,7 +123,7 @@ public:
|
||||
virtual void visitBulkMoveArmy(BulkMoveArmy & pack) {}
|
||||
virtual void visitBulkSplitStack(BulkSplitStack & pack) {}
|
||||
virtual void visitBulkMergeStacks(BulkMergeStacks & pack) {}
|
||||
virtual void visitBulkSmartSplitStack(BulkSmartSplitStack & pack) {}
|
||||
virtual void visitBulkSmartSplitStack(BulkSplitAndRebalanceStack & pack) {}
|
||||
virtual void visitDisbandCreature(DisbandCreature & pack) {}
|
||||
virtual void visitBuildStructure(BuildStructure & pack) {}
|
||||
virtual void visitVisitTownBuilding(VisitTownBuilding & pack) {}
|
||||
|
@ -333,11 +333,6 @@ void BulkRebalanceStacks::visitTyped(ICPackVisitor & visitor)
|
||||
visitor.visitBulkRebalanceStacks(*this);
|
||||
}
|
||||
|
||||
void BulkSmartRebalanceStacks::visitTyped(ICPackVisitor & visitor)
|
||||
{
|
||||
visitor.visitBulkSmartRebalanceStacks(*this);
|
||||
}
|
||||
|
||||
void PutArtifact::visitTyped(ICPackVisitor & visitor)
|
||||
{
|
||||
visitor.visitPutArtifact(*this);
|
||||
@ -573,7 +568,7 @@ void BulkMergeStacks::visitTyped(ICPackVisitor & visitor)
|
||||
visitor.visitBulkMergeStacks(*this);
|
||||
}
|
||||
|
||||
void BulkSmartSplitStack::visitTyped(ICPackVisitor & visitor)
|
||||
void BulkSplitAndRebalanceStack::visitTyped(ICPackVisitor & visitor)
|
||||
{
|
||||
visitor.visitBulkSmartSplitStack(*this);
|
||||
}
|
||||
@ -895,7 +890,7 @@ void SetCommanderProperty::applyGs(CGameState *gs)
|
||||
commander->setAlive(false);
|
||||
break;
|
||||
case EXPERIENCE:
|
||||
commander->giveStackExp(amount); //TODO: allow setting exp for stacks via netpacks
|
||||
commander->giveTotalStackExperience(amount);
|
||||
commander->nodeHasChanged();
|
||||
break;
|
||||
}
|
||||
@ -1560,17 +1555,15 @@ void RebalanceStacks::applyGs(CGameState *gs)
|
||||
StackLocation src(srcObj->id, srcSlot);
|
||||
StackLocation dst(dstObj->id, dstSlot);
|
||||
|
||||
const CCreature * srcType = srcObj->getCreature(src.slot);
|
||||
[[maybe_unused]] const CCreature * srcType = srcObj->getCreature(src.slot);
|
||||
const CCreature * dstType = dstObj->getCreature(dst.slot);
|
||||
TQuantity srcCount = srcObj->getStackCount(src.slot);
|
||||
bool stackExp = gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE);
|
||||
|
||||
if(srcCount == count) //moving whole stack
|
||||
{
|
||||
const auto c = dstObj->getCreature(dst.slot);
|
||||
|
||||
if(c) //stack at dest -> merge
|
||||
if(dstType) //stack at dest -> merge
|
||||
{
|
||||
assert(c == srcType);
|
||||
assert(dstType == srcType);
|
||||
|
||||
const auto srcHero = dynamic_cast<CGHeroInstance*>(srcObj);
|
||||
const auto dstHero = dynamic_cast<CGHeroInstance*>(dstObj);
|
||||
@ -1609,50 +1602,28 @@ void RebalanceStacks::applyGs(CGameState *gs)
|
||||
gs->getMap().moveArtifactInstance(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
|
||||
}
|
||||
}
|
||||
if (stackExp)
|
||||
{
|
||||
ui64 totalExp = srcCount * srcObj->getStackExperience(src.slot) + dstObj->getStackCount(dst.slot) * dstObj->getStackExperience(dst.slot);
|
||||
srcObj->eraseStack(src.slot);
|
||||
dstObj->changeStackCount(dst.slot, count);
|
||||
dstObj->setStackExp(dst.slot, totalExp /(dstObj->getStackCount(dst.slot))); //mean
|
||||
}
|
||||
else
|
||||
{
|
||||
srcObj->eraseStack(src.slot);
|
||||
dstObj->changeStackCount(dst.slot, count);
|
||||
}
|
||||
|
||||
auto movedStack = srcObj->detachStack(src.slot);
|
||||
dstObj->joinStack(dst.slot, std::move(movedStack));
|
||||
}
|
||||
else //move stack to an empty slot, no exp change needed
|
||||
else
|
||||
{
|
||||
auto stackDetached = srcObj->detachStack(src.slot);
|
||||
dstObj->putStack(dst.slot, std::move(stackDetached));
|
||||
auto movedStack = srcObj->detachStack(src.slot);
|
||||
dstObj->putStack(dst.slot, std::move(movedStack));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[[maybe_unused]] const CCreature *c = dstObj->getCreature(dst.slot);
|
||||
if(c) //stack at dest -> rebalance
|
||||
auto movedStack = srcObj->splitStack(src.slot, count);
|
||||
|
||||
if(dstType) //stack at dest -> rebalance
|
||||
{
|
||||
assert(c == srcType);
|
||||
if (stackExp)
|
||||
{
|
||||
ui64 totalExp = srcCount * srcObj->getStackExperience(src.slot) + dstObj->getStackCount(dst.slot) * dstObj->getStackExperience(dst.slot);
|
||||
srcObj->changeStackCount(src.slot, -count);
|
||||
dstObj->changeStackCount(dst.slot, count);
|
||||
dstObj->setStackExp(dst.slot, totalExp /(srcObj->getStackCount(src.slot) + dstObj->getStackCount(dst.slot))); //mean
|
||||
}
|
||||
else
|
||||
{
|
||||
srcObj->changeStackCount(src.slot, -count);
|
||||
dstObj->changeStackCount(dst.slot, count);
|
||||
}
|
||||
assert(dstType == srcType);
|
||||
dstObj->joinStack(dst.slot, std::move(movedStack));
|
||||
}
|
||||
else //split stack to an empty slot
|
||||
else //move new stack to an empty slot
|
||||
{
|
||||
srcObj->changeStackCount(src.slot, -count);
|
||||
dstObj->addToSlot(dst.slot, srcType->getId(), count, false);
|
||||
if (stackExp)
|
||||
dstObj->setStackExp(dst.slot, srcObj->getStackExperience(src.slot));
|
||||
dstObj->putStack(dst.slot, std::move(movedStack));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1667,15 +1638,6 @@ void BulkRebalanceStacks::applyGs(CGameState *gs)
|
||||
move.applyGs(gs);
|
||||
}
|
||||
|
||||
void BulkSmartRebalanceStacks::applyGs(CGameState *gs)
|
||||
{
|
||||
for(auto & move : moves)
|
||||
move.applyGs(gs);
|
||||
|
||||
for(auto & change : changes)
|
||||
change.applyGs(gs);
|
||||
}
|
||||
|
||||
void PutArtifact::applyGs(CGameState *gs)
|
||||
{
|
||||
auto art = gs->getArtInstance(id);
|
||||
@ -2094,15 +2056,10 @@ void BattleResultAccepted::applyGs(CGameState *gs)
|
||||
if(gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
||||
{
|
||||
if(const auto attackerArmy = gs->getArmyInstance(heroResult[BattleSide::ATTACKER].armyID))
|
||||
{
|
||||
attackerArmy->giveStackExp(heroResult[BattleSide::ATTACKER].exp);
|
||||
attackerArmy->nodeHasChanged();
|
||||
}
|
||||
attackerArmy->giveAverageStackExperience(heroResult[BattleSide::ATTACKER].exp);
|
||||
|
||||
if(const auto defenderArmy = gs->getArmyInstance(heroResult[BattleSide::DEFENDER].armyID))
|
||||
{
|
||||
defenderArmy->giveStackExp(heroResult[BattleSide::DEFENDER].exp);
|
||||
defenderArmy->nodeHasChanged();
|
||||
}
|
||||
defenderArmy->giveAverageStackExperience(heroResult[BattleSide::DEFENDER].exp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -968,22 +968,6 @@ struct DLL_LINKAGE BulkRebalanceStacks : CGarrisonOperationPack
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE BulkSmartRebalanceStacks : CGarrisonOperationPack
|
||||
{
|
||||
std::vector<RebalanceStacks> moves;
|
||||
std::vector<ChangeStackCount> changes;
|
||||
|
||||
void applyGs(CGameState * gs) override;
|
||||
void visitTyped(ICPackVisitor & visitor) override;
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h)
|
||||
{
|
||||
h & moves;
|
||||
h & changes;
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE CArtifactOperationPack : CPackForClient
|
||||
{
|
||||
};
|
||||
|
@ -214,14 +214,14 @@ struct DLL_LINKAGE BulkMergeStacks : public CPackForServer
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE BulkSmartSplitStack : public CPackForServer
|
||||
struct DLL_LINKAGE BulkSplitAndRebalanceStack : public CPackForServer
|
||||
{
|
||||
SlotID src;
|
||||
ObjectInstanceID srcOwner;
|
||||
|
||||
BulkSmartSplitStack() = default;
|
||||
BulkSplitAndRebalanceStack() = default;
|
||||
|
||||
BulkSmartSplitStack(const ObjectInstanceID & srcOwner, const SlotID & src)
|
||||
BulkSplitAndRebalanceStack(const ObjectInstanceID & srcOwner, const SlotID & src)
|
||||
: src(src)
|
||||
, srcOwner(srcOwner)
|
||||
{
|
||||
|
@ -197,7 +197,7 @@ void Rewardable::Interface::grantRewardAfterLevelup(const Rewardable::VisitInfo
|
||||
{
|
||||
CCreatureSet creatures;
|
||||
for(const auto & crea : info.reward.creatures)
|
||||
creatures.addToSlot(creatures.getFreeSlot(), std::make_unique<CStackInstance>(cb, crea.getId(), crea.count));
|
||||
creatures.addToSlot(creatures.getFreeSlot(), std::make_unique<CStackInstance>(cb, crea.getId(), crea.getCount()));
|
||||
|
||||
if(auto * army = dynamic_cast<const CArmedInstance*>(this)) //TODO: to fix that, CArmedInstance must be split on map instance part and interface part
|
||||
cb->giveCreatures(army, hero, creatures, false);
|
||||
|
@ -85,9 +85,9 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
||||
{
|
||||
const auto & heroStack = slot.second;
|
||||
if (heroStack->getType() == reqStack.getType())
|
||||
count += heroStack->count;
|
||||
count += heroStack->getCount();
|
||||
}
|
||||
if (count < reqStack.count) //not enough creatures of this kind
|
||||
if (count < reqStack.getCount()) //not enough creatures of this kind
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ void Rewardable::Limiter::loadComponents(std::vector<Component> & comps,
|
||||
comps.emplace_back(ComponentType::SPELL, entry);
|
||||
|
||||
for(const auto & entry : creatures)
|
||||
comps.emplace_back(ComponentType::CREATURE, entry.getId(), entry.count);
|
||||
comps.emplace_back(ComponentType::CREATURE, entry.getId(), entry.getCount());
|
||||
|
||||
for(const auto & entry : players)
|
||||
comps.emplace_back(ComponentType::FLAG, entry);
|
||||
|
@ -121,7 +121,7 @@ void Rewardable::Reward::loadComponents(std::vector<Component> & comps, const CG
|
||||
}
|
||||
|
||||
for(const auto & entry : creatures)
|
||||
comps.emplace_back(ComponentType::CREATURE, entry.getId(), entry.count);
|
||||
comps.emplace_back(ComponentType::CREATURE, entry.getId(), entry.getCount());
|
||||
|
||||
for (size_t i=0; i<resources.size(); i++)
|
||||
{
|
||||
|
@ -36,7 +36,10 @@ enum class ESerializationVersion : int32_t
|
||||
|
||||
MAP_HEADER_DISPOSED_HEROES, // map header contains disposed heroes list
|
||||
NO_RAW_POINTERS_IN_SERIALIZER, // large rework that removed all non-owning pointers from serializer
|
||||
STORE_UID_COUNTER_IN_CMAP, // fix crash caused by conflicting instanceName after loading game
|
||||
STACK_INSTANCE_EXPERIENCE_FIX, // stack experience is stored as total, not as average
|
||||
STACK_INSTANCE_ARMY_FIX, // remove serialization of army that owns stack instance
|
||||
STORE_UID_COUNTER_IN_CMAP, // fix crash caused by conflicting instanceName after loading game
|
||||
|
||||
|
||||
CURRENT = STORE_UID_COUNTER_IN_CMAP,
|
||||
};
|
||||
|
@ -226,7 +226,6 @@ void registerTypes(Serializer &s)
|
||||
s.template registerType<BulkMoveArtifacts>(173);
|
||||
s.template registerType<PlayerMessageClient>(174);
|
||||
s.template registerType<BulkRebalanceStacks>(175);
|
||||
s.template registerType<BulkSmartRebalanceStacks>(176);
|
||||
s.template registerType<SetRewardableConfiguration>(177);
|
||||
s.template registerType<CPackForServer>(179);
|
||||
s.template registerType<EndTurn>(180);
|
||||
@ -255,7 +254,7 @@ void registerTypes(Serializer &s)
|
||||
s.template registerType<PlayerMessage>(203);
|
||||
s.template registerType<BulkSplitStack>(204);
|
||||
s.template registerType<BulkMergeStacks>(205);
|
||||
s.template registerType<BulkSmartSplitStack>(206);
|
||||
s.template registerType<BulkSplitAndRebalanceStack>(206);
|
||||
s.template registerType<BulkMoveArmy>(207);
|
||||
s.template registerType<BulkExchangeArtifacts>(208);
|
||||
s.template registerType<ManageBackpackArtifacts>(209);
|
||||
|
@ -446,7 +446,7 @@ void MetaString::replaceName(const CreatureID & id, TQuantity count) //adds sing
|
||||
|
||||
void MetaString::replaceName(const CStackBasicDescriptor & stack)
|
||||
{
|
||||
replaceName(stack.getId(), stack.count);
|
||||
replaceName(stack.getId(), stack.getCount());
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -155,8 +155,8 @@ void ArmyDelegate::updateModelData(QAbstractItemModel * model, const QModelIndex
|
||||
QStringList textList;
|
||||
for(const auto & [_, stack] : army.stacks)
|
||||
{
|
||||
if(stack->count != 0 && stack->getCreature() != nullptr)
|
||||
textList += QString("%1 %2").arg(stack->count).arg(QString::fromStdString(stack->getCreature()->getNamePluralTranslated()));
|
||||
if(stack->getCount() != 0 && stack->getCreature() != nullptr)
|
||||
textList += QString("%1 %2").arg(stack->getCount()).arg(QString::fromStdString(stack->getCreature()->getNamePluralTranslated()));
|
||||
}
|
||||
|
||||
setModelTextData(model, index, textList);
|
||||
|
@ -423,7 +423,7 @@ void Inspector::updateProperties(CGCreature * o)
|
||||
addProperty(QObject::tr("Not growing"), o->notGrowingTeam, false);
|
||||
addProperty(QObject::tr("Artifact reward"), o->gainedArtifact); //TODO: implement in setProperty
|
||||
addProperty(QObject::tr("Army"), PropertyEditorPlaceholder(), true);
|
||||
addProperty(QObject::tr("Amount"), o->stacks[SlotID(0)]->count, false);
|
||||
addProperty(QObject::tr("Amount"), o->stacks[SlotID(0)]->getCount(), false);
|
||||
//addProperty(QObject::tr("Resources reward"), o->resources); //TODO: implement in setProperty
|
||||
}
|
||||
|
||||
@ -763,7 +763,7 @@ void Inspector::setProperty(CGCreature * o, const QString & key, const QVariant
|
||||
if(key == QObject::tr("Not growing"))
|
||||
o->notGrowingTeam = value.toBool();
|
||||
if(key == QObject::tr("Amount"))
|
||||
o->stacks[SlotID(0)]->count = value.toString().toInt();
|
||||
o->stacks[SlotID(0)]->setCount(value.toString().toInt());
|
||||
}
|
||||
|
||||
void Inspector::setProperty(CGSeerHut * o, const QString & key, const QVariant & value)
|
||||
|
@ -175,7 +175,7 @@ void QuestWidget::obtainData()
|
||||
{
|
||||
int index = i.getType()->getIndex();
|
||||
ui->lCreatureId->setCurrentIndex(index);
|
||||
ui->lCreatureAmount->setValue(i.count);
|
||||
ui->lCreatureAmount->setValue(i.getCount());
|
||||
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
||||
}
|
||||
for(auto & i : quest.mission.heroes)
|
||||
@ -489,7 +489,7 @@ void QuestDelegate::updateModelData(QAbstractItemModel * model, const QModelInde
|
||||
QStringList creaturesList;
|
||||
for(const auto & creature : quest.mission.creatures)
|
||||
{
|
||||
creaturesList += QString("%1 %2").arg(creature.count).arg(QString::fromStdString(creature.getType()->getNamePluralTranslated()));
|
||||
creaturesList += QString("%1 %2").arg(creature.getCount()).arg(QString::fromStdString(creature.getType()->getNamePluralTranslated()));
|
||||
}
|
||||
textList += QObject::tr("Creatures: %1").arg(creaturesList.join(", "));
|
||||
|
||||
|
@ -466,7 +466,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
||||
{
|
||||
int index = i.getType()->getIndex();
|
||||
ui->rCreatureId->setCurrentIndex(index);
|
||||
ui->rCreatureAmount->setValue(i.count);
|
||||
ui->rCreatureAmount->setValue(i.getCount());
|
||||
onCreatureAdd(ui->rCreatures, ui->rCreatureId, ui->rCreatureAmount);
|
||||
}
|
||||
|
||||
@ -534,7 +534,7 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
||||
{
|
||||
int index = i.getType()->getIndex();
|
||||
ui->lCreatureId->setCurrentIndex(index);
|
||||
ui->lCreatureAmount->setValue(i.count);
|
||||
ui->lCreatureAmount->setValue(i.getCount());
|
||||
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
||||
}
|
||||
|
||||
@ -806,7 +806,7 @@ void RewardsDelegate::updateModelData(QAbstractItemModel * model, const QModelIn
|
||||
QStringList creaturesList;
|
||||
for (auto & creature : vinfo.reward.creatures)
|
||||
{
|
||||
creaturesList += QString("%1 %2").arg(creature.count).arg(QString::fromStdString(creature.getType()->getNamePluralTranslated()));
|
||||
creaturesList += QString("%1 %2").arg(creature.getCount()).arg(QString::fromStdString(creature.getType()->getNamePluralTranslated()));
|
||||
}
|
||||
textList += QObject::tr("Creatures: %1").arg(creaturesList.join(", "));
|
||||
if (vinfo.reward.spellCast.first != SpellID::NONE)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1151,7 +1151,7 @@ void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance
|
||||
//first we move creatures to give to make them army of object-source
|
||||
for (auto & elem : creatures.Slots())
|
||||
{
|
||||
addToSlot(StackLocation(obj->id, obj->getSlotFor(elem.second->getCreature())), elem.second->getCreature(), elem.second->count);
|
||||
addToSlot(StackLocation(obj->id, obj->getSlotFor(elem.second->getCreature())), elem.second->getCreature(), elem.second->getCount());
|
||||
}
|
||||
|
||||
tryJoiningArmy(obj, h, remove, true);
|
||||
@ -1167,14 +1167,14 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
|
||||
for (CStackBasicDescriptor &sbd : cres)
|
||||
{
|
||||
TQuantity collected = 0;
|
||||
while(collected < sbd.count)
|
||||
while(collected < sbd.getCount())
|
||||
{
|
||||
bool foundSth = false;
|
||||
for (auto i = obj->Slots().begin(); i != obj->Slots().end(); i++)
|
||||
{
|
||||
if (i->second->getType() == sbd.getType())
|
||||
{
|
||||
TQuantity take = std::min(sbd.count - collected, i->second->count); //collect as much cres as we can
|
||||
TQuantity take = std::min(sbd.getCount() - collected, i->second->getCount()); //collect as much cres as we can
|
||||
changeStackCount(StackLocation(obj->id, i->first), -take, false);
|
||||
collected += take;
|
||||
foundSth = true;
|
||||
@ -1789,7 +1789,7 @@ bool CGameHandler::bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destA
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameHandler::bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner)
|
||||
bool CGameHandler::bulkSplitAndRebalanceStack(SlotID slotSrc, ObjectInstanceID srcOwner)
|
||||
{
|
||||
if(!slotSrc.validSlot() && complain(complainInvalidSlot))
|
||||
return false;
|
||||
@ -1811,8 +1811,8 @@ bool CGameHandler::bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner
|
||||
if(freeSlot == SlotID() && creatureSet.isCreatureBalanced(currentCreature))
|
||||
return true;
|
||||
|
||||
auto creatureSlots = creatureSet.getCreatureSlots(currentCreature, SlotID(-1), 1); // Ignore slots where's only 1 creature, don't ignore slotSrc
|
||||
TQuantity totalCreatures = 0;
|
||||
auto creatureSlots = creatureSet.getCreatureSlots(currentCreature, slotSrc, 1); // Ignore slots where's only 1 creature
|
||||
TQuantity totalCreatures = creatureSet.getStackCount(slotSrc);
|
||||
|
||||
for(auto slot : creatureSlots)
|
||||
totalCreatures += creatureSet.getStackCount(slot);
|
||||
@ -1820,53 +1820,60 @@ bool CGameHandler::bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner
|
||||
if(totalCreatures <= 1 && complain("Total creatures number is invalid"))
|
||||
return false;
|
||||
|
||||
if(freeSlot != SlotID())
|
||||
creatureSlots.push_back(freeSlot);
|
||||
BulkRebalanceStacks bulkSRS;
|
||||
|
||||
if(creatureSlots.empty() && complain("No available slots for smart rebalancing"))
|
||||
return false;
|
||||
// 1) merge all but one creatures back into source slot
|
||||
// single creature needs to be kept, to avoid stack artifact dropping to hero backpack
|
||||
for(auto slot : creatureSlots)
|
||||
{
|
||||
RebalanceStacks rs;
|
||||
rs.srcArmy = army->id;
|
||||
rs.dstArmy = army->id;
|
||||
rs.srcSlot = slot;
|
||||
rs.dstSlot = slotSrc;
|
||||
rs.count = creatureSet.getStackCount(slot) - 1;
|
||||
|
||||
const auto totalCreatureSlots = creatureSlots.size();
|
||||
const auto rem = totalCreatures % totalCreatureSlots;
|
||||
const auto quotient = totalCreatures / totalCreatureSlots;
|
||||
|
||||
// totalCreatures == rem * (quotient + 1) + (totalCreatureSlots - rem) * quotient;
|
||||
// Proof: r(q+1)+(s-r)q = rq+r+qs-rq = r+qs = total, where total/s = q+r/s
|
||||
|
||||
BulkSmartRebalanceStacks bulkSRS;
|
||||
if (rs.count > 0)
|
||||
bulkSRS.moves.push_back(rs);
|
||||
}
|
||||
|
||||
// 2) split off single creature into new slot, if any
|
||||
// strictly speaking, not needed, but more convenient
|
||||
if(freeSlot != SlotID())
|
||||
{
|
||||
RebalanceStacks rs;
|
||||
rs.srcArmy = rs.dstArmy = army->id;
|
||||
rs.srcArmy = army->id;
|
||||
rs.dstArmy = army->id;
|
||||
rs.srcSlot = slotSrc;
|
||||
rs.dstSlot = freeSlot;
|
||||
rs.count = 1;
|
||||
bulkSRS.moves.push_back(rs);
|
||||
}
|
||||
auto currSlot = 0;
|
||||
auto check = 0;
|
||||
|
||||
creatureSlots.push_back(freeSlot);
|
||||
}
|
||||
|
||||
if(creatureSlots.empty() && complain("No available slots for smart rebalancing"))
|
||||
return false;
|
||||
|
||||
int slotsLeft = creatureSlots.size() + 1; // + srcSlot
|
||||
TQuantity unitsToMove = totalCreatures - slotsLeft;
|
||||
|
||||
// 3) re-split creatures in a balanced way
|
||||
for(auto slot : creatureSlots)
|
||||
{
|
||||
ChangeStackCount csc;
|
||||
RebalanceStacks rs;
|
||||
|
||||
csc.army = army->id;
|
||||
csc.slot = slot;
|
||||
csc.count = (currSlot < rem)
|
||||
? quotient + 1
|
||||
: quotient;
|
||||
csc.absoluteValue = true;
|
||||
bulkSRS.changes.push_back(csc);
|
||||
currSlot++;
|
||||
check += csc.count;
|
||||
rs.srcArmy = army->id;
|
||||
rs.dstArmy = army->id;
|
||||
rs.srcSlot = slotSrc;
|
||||
rs.dstSlot = slot;
|
||||
rs.count = vstd::divideAndCeil(unitsToMove, slotsLeft);
|
||||
bulkSRS.moves.push_back(rs);
|
||||
|
||||
unitsToMove -= rs.count;
|
||||
slotsLeft -= 1;
|
||||
}
|
||||
|
||||
if(check != totalCreatures)
|
||||
{
|
||||
complain((boost::format("Failure: totalCreatures=%d but check=%d") % totalCreatures % check).str());
|
||||
return false;
|
||||
}
|
||||
sendAndApply(bulkSRS);
|
||||
return true;
|
||||
}
|
||||
@ -2435,7 +2442,7 @@ bool CGameHandler::upgradeCreature(ObjectInstanceID objid, SlotID pos, CreatureI
|
||||
fillUpgradeInfo(obj, pos, upgradeInfo);
|
||||
PlayerColor player = obj->tempOwner;
|
||||
const PlayerState *p = getPlayerState(player);
|
||||
int crQuantity = obj->stacks.at(pos)->count;
|
||||
int crQuantity = obj->stacks.at(pos)->getCount();
|
||||
|
||||
//check if upgrade is possible
|
||||
if (!upgradeInfo.hasUpgrades() && complain("That upgrade is not possible!"))
|
||||
@ -3167,8 +3174,8 @@ bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHero
|
||||
|
||||
const CStackInstance &s = hero->getStack(slot);
|
||||
|
||||
if (s.count < (TQuantity)count //can't sell more creatures than have
|
||||
|| (hero->stacksCount() == 1 && hero->needsLastStack() && s.count == count)) //can't sell last stack
|
||||
if (s.getCount() < static_cast<TQuantity>(count) //can't sell more creatures than have
|
||||
|| (hero->stacksCount() == 1 && hero->needsLastStack() && s.getCount() == count)) //can't sell last stack
|
||||
{
|
||||
COMPLAIN_RET("Not enough creatures in army!");
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ public:
|
||||
bool bulkMoveArmy(ObjectInstanceID srcArmy, ObjectInstanceID destArmy, SlotID srcSlot);
|
||||
bool bulkSplitStack(SlotID src, ObjectInstanceID srcOwner, si32 howMany);
|
||||
bool bulkMergeStacks(SlotID slotSrc, ObjectInstanceID srcOwner);
|
||||
bool bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner);
|
||||
bool bulkSplitAndRebalanceStack(SlotID slotSrc, ObjectInstanceID srcOwner);
|
||||
void save(const std::string &fname);
|
||||
bool load(const std::string &fname);
|
||||
|
||||
|
@ -124,12 +124,12 @@ void ApplyGhNetPackVisitor::visitBulkMergeStacks(BulkMergeStacks & pack)
|
||||
result = gh.bulkMergeStacks(pack.src, pack.srcOwner);
|
||||
}
|
||||
|
||||
void ApplyGhNetPackVisitor::visitBulkSmartSplitStack(BulkSmartSplitStack & pack)
|
||||
void ApplyGhNetPackVisitor::visitBulkSmartSplitStack(BulkSplitAndRebalanceStack & pack)
|
||||
{
|
||||
gh.throwIfWrongPlayer(connection, &pack);
|
||||
gh.throwIfPlayerNotActive(connection, &pack);
|
||||
|
||||
result = gh.bulkSmartSplitStack(pack.src, pack.srcOwner);
|
||||
result = gh.bulkSplitAndRebalanceStack(pack.src, pack.srcOwner);
|
||||
}
|
||||
|
||||
void ApplyGhNetPackVisitor::visitDisbandCreature(DisbandCreature & pack)
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
void visitBulkMoveArmy(BulkMoveArmy & pack) override;
|
||||
void visitBulkSplitStack(BulkSplitStack & pack) override;
|
||||
void visitBulkMergeStacks(BulkMergeStacks & pack) override;
|
||||
void visitBulkSmartSplitStack(BulkSmartSplitStack & pack) override;
|
||||
void visitBulkSmartSplitStack(BulkSplitAndRebalanceStack & pack) override;
|
||||
void visitDisbandCreature(DisbandCreature & pack) override;
|
||||
void visitBuildStructure(BuildStructure & pack) override;
|
||||
void visitSpellResearch(SpellResearch & pack) override;
|
||||
|
@ -487,7 +487,7 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
|
||||
resultsApplied.raisedStack = winnerHero->calculateNecromancy(result);
|
||||
const SlotID necroSlot = resultsApplied.raisedStack.getCreature() ? winnerHero->getSlotFor(resultsApplied.raisedStack.getCreature()) : SlotID();
|
||||
if(necroSlot != SlotID() && !finishingBattle->isDraw())
|
||||
gameHandler->addToSlot(StackLocation(finishingBattle->winnerId, necroSlot), resultsApplied.raisedStack.getCreature(), resultsApplied.raisedStack.count);
|
||||
gameHandler->addToSlot(StackLocation(finishingBattle->winnerId, necroSlot), resultsApplied.raisedStack.getCreature(), resultsApplied.raisedStack.getCount());
|
||||
}
|
||||
|
||||
resultsApplied.battleID = battleID;
|
||||
|
@ -73,7 +73,7 @@ bool CGarrisonDialogQuery::blocksPack(const CPackForServer * pack) const
|
||||
if(auto stacks = dynamic_cast<const BulkMergeStacks*>(pack))
|
||||
return !vstd::contains(ourIds, stacks->srcOwner);
|
||||
|
||||
if(auto stacks = dynamic_cast<const BulkSmartSplitStack*>(pack))
|
||||
if(auto stacks = dynamic_cast<const BulkSplitAndRebalanceStack*>(pack))
|
||||
return !vstd::contains(ourIds, stacks->srcOwner);
|
||||
|
||||
if(auto stacks = dynamic_cast<const BulkMoveArmy*>(pack))
|
||||
|
Loading…
x
Reference in New Issue
Block a user