mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge pull request #4087 from IvanSavenko/stabilization
[1.5.3] Stabilization
This commit is contained in:
commit
381171f897
@ -403,7 +403,7 @@ void Nullkiller::makeTurn()
|
||||
|
||||
if(selectedTasks.empty())
|
||||
{
|
||||
return;
|
||||
selectedTasks.push_back(taskptr(Goals::Invalid()));
|
||||
}
|
||||
|
||||
bool hasAnySuccess = false;
|
||||
@ -456,7 +456,7 @@ void Nullkiller::makeTurn()
|
||||
scanDepth = ScanDepth::ALL_FULL;
|
||||
useHeroChain = false;
|
||||
hasAnySuccess = true;
|
||||
break;;
|
||||
break;
|
||||
}
|
||||
|
||||
logAi->trace("Goal %s has too low priority. It is not worth doing it.", taskDescription);
|
||||
|
@ -26,9 +26,9 @@ bool ExploreNeighbourTile::operator==(const ExploreNeighbourTile & other) const
|
||||
|
||||
void ExploreNeighbourTile::accept(AIGateway * ai)
|
||||
{
|
||||
ExplorationHelper h(hero, ai->nullkiller.get());
|
||||
ExplorationHelper h(hero, ai->nullkiller.get(), true);
|
||||
|
||||
for(int i = 0; i < tilesToExplore && hero->movementPointsRemaining() > 0; i++)
|
||||
for(int i = 0; i < tilesToExplore && ai->myCb->getObj(hero->id, false) && hero->movementPointsRemaining() > 0; i++)
|
||||
{
|
||||
int3 pos = hero->visitablePos();
|
||||
float value = 0;
|
||||
@ -54,7 +54,14 @@ void ExploreNeighbourTile::accept(AIGateway * ai)
|
||||
}
|
||||
});
|
||||
|
||||
if(!target.valid() || !ai->moveHeroToTile(target, hero))
|
||||
if(!target.valid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto danger = ai->nullkiller->pathfinder->getStorage()->evaluateDanger(target, hero, true);
|
||||
|
||||
if(danger > 0 || !ai->moveHeroToTile(target, hero))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ namespace NKAI
|
||||
|
||||
using namespace Goals;
|
||||
|
||||
ExplorationHelper::ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai)
|
||||
:ai(ai), cbp(ai->cb.get()), hero(hero)
|
||||
ExplorationHelper::ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai, bool useCPathfinderAccessibility)
|
||||
:ai(ai), cbp(ai->cb.get()), hero(hero), useCPathfinderAccessibility(useCPathfinderAccessibility)
|
||||
{
|
||||
ts = cbp->getPlayerTeam(ai->playerID);
|
||||
sightRadius = hero->getSightRadius();
|
||||
@ -104,7 +104,7 @@ bool ExplorationHelper::scanMap()
|
||||
|
||||
if(!bestGoal->invalid())
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
allowDeadEndCancellation = false;
|
||||
@ -222,7 +222,9 @@ bool ExplorationHelper::hasReachableNeighbor(const int3 & pos) const
|
||||
int3 tile = pos + dir;
|
||||
if(cbp->isInTheMap(tile))
|
||||
{
|
||||
auto isAccessible = ai->pathfinder->isTileAccessible(hero, tile);
|
||||
auto isAccessible = useCPathfinderAccessibility
|
||||
? ai->cb->getPathsInfo(hero)->getPathInfo(tile)->reachable()
|
||||
: ai->pathfinder->isTileAccessible(hero, tile);
|
||||
|
||||
if(isAccessible)
|
||||
return true;
|
||||
|
@ -34,9 +34,10 @@ private:
|
||||
const TeamState * ts;
|
||||
int3 ourPos;
|
||||
bool allowDeadEndCancellation;
|
||||
bool useCPathfinderAccessibility;
|
||||
|
||||
public:
|
||||
ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai);
|
||||
ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * ai, bool useCPathfinderAccessibility = false);
|
||||
Goals::TSubgoal makeComposition() const;
|
||||
bool scanSector(int scanRadius);
|
||||
bool scanMap();
|
||||
|
@ -10,7 +10,7 @@ android {
|
||||
applicationId "is.xyz.vcmi"
|
||||
minSdk 19
|
||||
targetSdk 33
|
||||
versionCode 1520
|
||||
versionCode 1521
|
||||
versionName "1.5.2"
|
||||
setProperty("archivesBaseName", "vcmi")
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ void CPlayerInterface::performAutosave()
|
||||
int txtlen = TextOperations::getUnicodeCharactersCount(name);
|
||||
|
||||
TextOperations::trimRightUnicode(name, std::max(0, txtlen - 15));
|
||||
std::string forbiddenChars("\\/:?\"<>| ");
|
||||
std::string forbiddenChars("\\/:*?\"<>| ");
|
||||
std::replace_if(name.begin(), name.end(), [&](char c) { return std::string::npos != forbiddenChars.find(c); }, '_' );
|
||||
|
||||
prefix = name + "_" + cb->getStartInfo()->startTimeIso8601 + "/";
|
||||
|
@ -643,11 +643,15 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
|
||||
objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
|
||||
std::string text = LOCPLINT->localState->getCurrentHero() ? objAtTile->getHoverText(LOCPLINT->localState->getCurrentHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
|
||||
boost::replace_all(text,"\n"," ");
|
||||
if (GH.isKeyboardShiftDown())
|
||||
text.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
|
||||
GH.statusbar()->write(text);
|
||||
}
|
||||
else if(isTargetPositionVisible)
|
||||
{
|
||||
std::string tileTooltipText = CGI->mh->getTerrainDescr(targetPosition, false);
|
||||
if (GH.isKeyboardShiftDown())
|
||||
tileTooltipText.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
|
||||
GH.statusbar()->write(tileTooltipText);
|
||||
}
|
||||
|
||||
|
@ -763,8 +763,8 @@ void BattleWindow::blockUI(bool on)
|
||||
setShortcutBlocked(EShortcut::BATTLE_SELECT_ACTION, on || owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_AUTOCOMBAT, (settings["battle"]["endWithAutocombat"].Bool() && onlyOnePlayerHuman) ? on || owner.tacticsMode || owner.actionsController->spellcastingModeActive() : owner.actionsController->spellcastingModeActive());
|
||||
setShortcutBlocked(EShortcut::BATTLE_END_WITH_AUTOCOMBAT, on || owner.tacticsMode || !onlyOnePlayerHuman || owner.actionsController->spellcastingModeActive());
|
||||
setShortcutBlocked(EShortcut::BATTLE_TACTICS_END, on && owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_TACTICS_NEXT, on && owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_TACTICS_END, on || !owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_TACTICS_NEXT, on || !owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_CONSOLE_DOWN, on && !owner.tacticsMode);
|
||||
setShortcutBlocked(EShortcut::BATTLE_CONSOLE_UP, on && !owner.tacticsMode);
|
||||
}
|
||||
|
@ -542,42 +542,34 @@ void CGarrisonInt::addSplitBtn(std::shared_ptr<CButton> button)
|
||||
|
||||
void CGarrisonInt::createSlots()
|
||||
{
|
||||
availableSlots.clear();
|
||||
|
||||
int distance = interx + (smallIcons ? 32 : 58);
|
||||
for(auto i : { EGarrisonType::UPPER, EGarrisonType::LOWER })
|
||||
{
|
||||
Point offset = garOffset * static_cast<int>(i);
|
||||
|
||||
std::vector<std::shared_ptr<CGarrisonSlot>> garrisonSlots;
|
||||
garrisonSlots.resize(7);
|
||||
if(army(i))
|
||||
{
|
||||
for(auto & elem : army(i)->Slots())
|
||||
{
|
||||
garrisonSlots[elem.first.getNum()] = std::make_shared<CGarrisonSlot>(this, offset.x + (elem.first.getNum()*distance), offset.y, elem.first, i, elem.second);
|
||||
}
|
||||
}
|
||||
for(int j = 0; j < 7; j++)
|
||||
{
|
||||
if(!garrisonSlots[j])
|
||||
garrisonSlots[j] = std::make_shared<CGarrisonSlot>(this, offset.x + (j*distance), offset.y, SlotID(j), i, nullptr);
|
||||
Point position(offset.x + (j*distance), offset.y);
|
||||
|
||||
if(layout == ESlotsLayout::TWO_ROWS && j >= 4)
|
||||
{
|
||||
garrisonSlots[j]->moveBy(Point(-126, 37));
|
||||
position += Point(-126, 37);
|
||||
}
|
||||
else if(layout == ESlotsLayout::REVERSED_TWO_ROWS)
|
||||
{
|
||||
if(j >= 3)
|
||||
{
|
||||
garrisonSlots[j]->moveBy(Point(-90, 49));
|
||||
position += Point(-90, 49);
|
||||
}
|
||||
else
|
||||
{
|
||||
garrisonSlots[j]->moveBy(Point(36, 0));
|
||||
position += Point(36, 0);
|
||||
}
|
||||
}
|
||||
SlotID slot(j);
|
||||
availableSlots.push_back(std::make_shared<CGarrisonSlot>(this, position.x, position.y, slot, i, army(i) ? army(i)->getStackPtr(slot) : nullptr));
|
||||
}
|
||||
vstd::concatenate(availableSlots, garrisonSlots);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,9 +46,7 @@ static bool isQuickExchangeLayoutAvailable()
|
||||
|
||||
CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID)
|
||||
: CWindowObject(PLAYER_COLORED | BORDERED, ImagePath::builtin(isQuickExchangeLayoutAvailable() ? QUICK_EXCHANGE_BG : "TRADE2")),
|
||||
controller(hero1, hero2),
|
||||
moveStackLeftButtons(),
|
||||
moveStackRightButtons()
|
||||
controller(hero1, hero2)
|
||||
{
|
||||
const bool qeLayout = isQuickExchangeLayoutAvailable();
|
||||
|
||||
@ -193,54 +191,52 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
||||
|
||||
if(qeLayout)
|
||||
{
|
||||
moveAllGarrButtonLeft = std::make_shared<CButton>(Point(325, 118), AnimationPath::builtin("quick-exchange/armRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]),
|
||||
[this](){ this->moveUnitsShortcut(false); });
|
||||
exchangeGarrButton = std::make_shared<CButton>(Point(377, 118), AnimationPath::builtin("quick-exchange/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]),
|
||||
[this](){ controller.swapArmy(); });
|
||||
moveAllGarrButtonRight = std::make_shared<CButton>(Point(425, 118), AnimationPath::builtin("quick-exchange/armLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]),
|
||||
[this](){ this->moveUnitsShortcut(true); });
|
||||
moveArtifactsButtonLeft = std::make_shared<CButton>(Point(325, 154), AnimationPath::builtin("quick-exchange/artRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]),
|
||||
[this](){ this->moveArtifactsCallback(false);});
|
||||
exchangeArtifactsButton = std::make_shared<CButton>(Point(377, 154), AnimationPath::builtin("quick-exchange/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]),
|
||||
[this](){ this->swapArtifactsCallback(); });
|
||||
moveArtifactsButtonRight = std::make_shared<CButton>(Point(425, 154), AnimationPath::builtin("quick-exchange/artLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]),
|
||||
[this](){ this->moveArtifactsCallback(true);});
|
||||
buttonMoveUnitsFromLeftToRight = std::make_shared<CButton>(Point(325, 118), AnimationPath::builtin("quick-exchange/armRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), [this](){ this->moveUnitsShortcut(true); });
|
||||
buttonMoveUnitsFromRightToLeft = std::make_shared<CButton>(Point(425, 118), AnimationPath::builtin("quick-exchange/armLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), [this](){ this->moveUnitsShortcut(false); });
|
||||
buttonMoveArtifactsFromLeftToRight = std::make_shared<CButton>(Point(325, 154), AnimationPath::builtin("quick-exchange/artRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), [this](){ this->moveArtifactsCallback(true);});
|
||||
buttonMoveArtifactsFromRightToLeft = std::make_shared<CButton>(Point(425, 154), AnimationPath::builtin("quick-exchange/artLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), [this](){ this->moveArtifactsCallback(false);});
|
||||
|
||||
backpackButtonLeft = std::make_shared<CButton>(Point(325, 518), AnimationPath::builtin("heroBackpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
|
||||
exchangeUnitsButton = std::make_shared<CButton>(Point(377, 118), AnimationPath::builtin("quick-exchange/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]), [this](){ controller.swapArmy(); });
|
||||
exchangeArtifactsButton = std::make_shared<CButton>(Point(377, 154), AnimationPath::builtin("quick-exchange/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]), [this](){ this->swapArtifactsCallback(); });
|
||||
|
||||
backpackButtonLeft = std::make_shared<CButton>(Point(325, 518), AnimationPath::builtin("heroBackpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
|
||||
[this](){ this->backpackShortcut(true); });
|
||||
backpackButtonRight = std::make_shared<CButton>(Point(419, 518), AnimationPath::builtin("heroBackpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
|
||||
backpackButtonRight = std::make_shared<CButton>(Point(419, 518), AnimationPath::builtin("heroBackpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"),
|
||||
[this](){ this->backpackShortcut(false); });
|
||||
backpackButtonLeft->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/backpackButtonIcon")));
|
||||
backpackButtonRight->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/backpackButtonIcon")));
|
||||
|
||||
auto leftHeroBlock = heroInst[0]->tempOwner != LOCPLINT->cb->getPlayerID();
|
||||
auto rightHeroBlock = heroInst[1]->tempOwner != LOCPLINT->cb->getPlayerID();
|
||||
moveAllGarrButtonLeft->block(leftHeroBlock);
|
||||
exchangeGarrButton->block(leftHeroBlock || rightHeroBlock);
|
||||
moveAllGarrButtonRight->block(rightHeroBlock);
|
||||
moveArtifactsButtonLeft->block(leftHeroBlock);
|
||||
|
||||
buttonMoveUnitsFromLeftToRight->block(leftHeroBlock);
|
||||
buttonMoveUnitsFromRightToLeft->block(rightHeroBlock);
|
||||
buttonMoveArtifactsFromLeftToRight->block(leftHeroBlock);
|
||||
buttonMoveArtifactsFromRightToLeft->block(rightHeroBlock);
|
||||
|
||||
exchangeUnitsButton->block(leftHeroBlock || rightHeroBlock);
|
||||
exchangeArtifactsButton->block(leftHeroBlock || rightHeroBlock);
|
||||
moveArtifactsButtonRight->block(rightHeroBlock);
|
||||
|
||||
backpackButtonLeft->block(leftHeroBlock);
|
||||
backpackButtonRight->block(rightHeroBlock);
|
||||
|
||||
for(int i = 0; i < GameConstants::ARMY_SIZE; i++)
|
||||
{
|
||||
moveStackLeftButtons.push_back(
|
||||
moveUnitFromRightToLeftButtons.push_back(
|
||||
std::make_shared<CButton>(
|
||||
Point(484 + 35 * i, 154),
|
||||
AnimationPath::builtin("quick-exchange/unitLeft.DEF"),
|
||||
CButton::tooltip(CGI->generaltexth->qeModCommands[1]),
|
||||
std::bind(&CExchangeController::moveStack, &controller, false, SlotID(i))));
|
||||
moveStackLeftButtons.back()->block(leftHeroBlock);
|
||||
moveUnitFromRightToLeftButtons.back()->block(leftHeroBlock);
|
||||
|
||||
moveStackRightButtons.push_back(
|
||||
moveUnitFromLeftToRightButtons.push_back(
|
||||
std::make_shared<CButton>(
|
||||
Point(66 + 35 * i, 154),
|
||||
AnimationPath::builtin("quick-exchange/unitRight.DEF"),
|
||||
CButton::tooltip(CGI->generaltexth->qeModCommands[1]),
|
||||
std::bind(&CExchangeController::moveStack, &controller, true, SlotID(i))));
|
||||
moveStackLeftButtons.back()->block(rightHeroBlock);
|
||||
moveUnitFromLeftToRightButtons.back()->block(rightHeroBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,14 +41,16 @@ class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public
|
||||
std::array<std::shared_ptr<CButton>, 2> questlogButton;
|
||||
|
||||
std::shared_ptr<CGarrisonInt> garr;
|
||||
std::shared_ptr<CButton> moveAllGarrButtonLeft;
|
||||
std::shared_ptr<CButton> exchangeGarrButton;
|
||||
std::shared_ptr<CButton> moveAllGarrButtonRight;
|
||||
std::shared_ptr<CButton> moveArtifactsButtonLeft;
|
||||
std::shared_ptr<CButton> buttonMoveUnitsFromLeftToRight;
|
||||
std::shared_ptr<CButton> buttonMoveUnitsFromRightToLeft;
|
||||
std::shared_ptr<CButton> buttonMoveArtifactsFromLeftToRight;
|
||||
std::shared_ptr<CButton> buttonMoveArtifactsFromRightToLeft;
|
||||
|
||||
std::shared_ptr<CButton> exchangeUnitsButton;
|
||||
std::shared_ptr<CButton> exchangeArtifactsButton;
|
||||
std::shared_ptr<CButton> moveArtifactsButtonRight;
|
||||
std::vector<std::shared_ptr<CButton>> moveStackLeftButtons;
|
||||
std::vector<std::shared_ptr<CButton>> moveStackRightButtons;
|
||||
|
||||
std::vector<std::shared_ptr<CButton>> moveUnitFromLeftToRightButtons;
|
||||
std::vector<std::shared_ptr<CButton>> moveUnitFromRightToLeftButtons;
|
||||
std::shared_ptr<CButton> backpackButtonLeft;
|
||||
std::shared_ptr<CButton> backpackButtonRight;
|
||||
CExchangeController controller;
|
||||
|
@ -434,14 +434,15 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill pskill, std
|
||||
skillValue = std::make_shared<CLabel>(192, 253, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->primarySkillNames[static_cast<int>(pskill)] + " +1");
|
||||
}
|
||||
|
||||
|
||||
CLevelWindow::~CLevelWindow()
|
||||
void CLevelWindow::close()
|
||||
{
|
||||
//FIXME: call callback if there was nothing to select?
|
||||
if (box && box->selectedIndex() != -1)
|
||||
cb(box->selectedIndex());
|
||||
|
||||
LOCPLINT->showingDialog->setFree();
|
||||
|
||||
CWindowObject::close();
|
||||
}
|
||||
|
||||
CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed)
|
||||
|
@ -150,7 +150,8 @@ class CLevelWindow : public CWindowObject
|
||||
|
||||
public:
|
||||
CLevelWindow(const CGHeroInstance *hero, PrimarySkill pskill, std::vector<SecondarySkill> &skills, std::function<void(ui32)> callback);
|
||||
~CLevelWindow();
|
||||
|
||||
void close() override;
|
||||
};
|
||||
|
||||
/// Town portal, castle gate window
|
||||
|
@ -646,10 +646,15 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
||||
registerObject(scope, type_name, extraName.String(), cre->getIndex());
|
||||
}
|
||||
|
||||
if (!cre->special &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName) &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName.addPrefix("SPRITES/")))
|
||||
throw ModLoadingException(scope, "creature " + cre->getJsonKey() + " has no combat animation but is not marked as special!" );
|
||||
|
||||
JsonNode advMapFile = node["graphics"]["map"];
|
||||
JsonNode advMapMask = node["graphics"]["mapMask"];
|
||||
|
||||
VLC->identifiers()->requestIdentifier(scope, "object", "monster", [cre, scope, advMapFile, advMapMask](si32 index)
|
||||
VLC->identifiers()->requestIdentifier(scope, "object", "monster", [cre, scope, advMapFile, advMapMask](si32 monsterIndex)
|
||||
{
|
||||
JsonNode conf;
|
||||
conf.setModScope(scope);
|
||||
@ -672,7 +677,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
||||
if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->getTemplates().empty())
|
||||
{
|
||||
if (!cre->special)
|
||||
throw DataLoadingException("Mod " + scope + " is corrupted! Please disable or reinstall this mod. Reason: creature " + cre->getJsonKey() + " has no adventure map animation but is not marked as special!" );
|
||||
throw ModLoadingException(scope, "creature " + cre->getJsonKey() + " has no adventure map animation but is not marked as special!" );
|
||||
|
||||
VLC->objtypeh->removeSubObject(Obj::MONSTER, cre->getId().num);
|
||||
}
|
||||
@ -737,7 +742,6 @@ void CCreatureHandler::loadCrExpMod()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCreatureHandler::loadCrExpBon(CBonusSystemNode & globalEffects)
|
||||
{
|
||||
if (VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) //reading default stack experience bonuses
|
||||
|
@ -218,8 +218,7 @@ void CHeroClass::serializeJson(JsonSerializeFormat & handler)
|
||||
CHeroClass::CHeroClass():
|
||||
faction(0),
|
||||
affinity(0),
|
||||
defaultTavernChance(0),
|
||||
commander(nullptr)
|
||||
defaultTavernChance(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -302,7 +301,7 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
|
||||
VLC->identifiers()->requestIdentifier ("creature", node["commander"],
|
||||
[=](si32 commanderID)
|
||||
{
|
||||
heroClass->commander = CreatureID(commanderID).toCreature();
|
||||
heroClass->commander = CreatureID(commanderID);
|
||||
});
|
||||
|
||||
heroClass->defaultTavernChance = static_cast<ui32>(node["defaultTavern"].Float());
|
||||
|
@ -121,7 +121,7 @@ public:
|
||||
// resulting chance = sqrt(town.chance * heroClass.chance)
|
||||
ui32 defaultTavernChance;
|
||||
|
||||
const CCreature * commander;
|
||||
CreatureID commander;
|
||||
|
||||
std::vector<int> primarySkillInitial; // initial primary skills
|
||||
std::vector<int> primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level
|
||||
|
@ -14,3 +14,11 @@ class DLL_LINKAGE DataLoadingException: public std::runtime_error
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ModLoadingException: public DataLoadingException
|
||||
{
|
||||
public:
|
||||
ModLoadingException(const std::string & modName, const std::string & reason)
|
||||
: DataLoadingException("Mod " + modName + " is corrupted! Please disable or reinstall this mod. Reason: " + reason)
|
||||
{}
|
||||
};
|
||||
|
@ -1499,8 +1499,8 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
|
||||
case EventCondition::TRANSPORT:
|
||||
{
|
||||
const auto * t = getTown(condition.objectID);
|
||||
return (t->visitingHero && t->visitingHero->hasArt(condition.objectType.as<ArtifactID>())) ||
|
||||
(t->garrisonHero && t->garrisonHero->hasArt(condition.objectType.as<ArtifactID>()));
|
||||
return (t->visitingHero && t->visitingHero->getOwner() == player && t->visitingHero->hasArt(condition.objectType.as<ArtifactID>())) ||
|
||||
(t->garrisonHero && t->garrisonHero->getOwner() == player && t->garrisonHero->hasArt(condition.objectType.as<ArtifactID>()));
|
||||
}
|
||||
case EventCondition::DAYS_PASSED:
|
||||
{
|
||||
|
@ -402,9 +402,9 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
|
||||
addNewBonus(bonus);
|
||||
}
|
||||
|
||||
if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander)
|
||||
if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && type->heroClass->commander.hasValue())
|
||||
{
|
||||
commander = new CCommanderInstance(type->heroClass->commander->getId());
|
||||
commander = new CCommanderInstance(type->heroClass->commander);
|
||||
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
|
||||
commander->giveStackExp (exp); //after our exp is set
|
||||
}
|
||||
|
@ -1104,7 +1104,11 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
|
||||
objectToVisit = t.visitableObjects.back();
|
||||
|
||||
if (isInTheMap(guardPos))
|
||||
guardian = getTile(guardPos)->visitableObjects.back();
|
||||
{
|
||||
for (auto const & object : getTile(guardPos)->visitableObjects)
|
||||
if (object->ID == MapObjectID::MONSTER) // exclude other objects, such as hero flying above monster
|
||||
guardian = object;
|
||||
}
|
||||
|
||||
const bool embarking = !h->boat && objectToVisit && objectToVisit->ID == Obj::BOAT;
|
||||
const bool disembarking = h->boat
|
||||
|
@ -165,6 +165,9 @@ void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & co
|
||||
void CVCMIServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message)
|
||||
{
|
||||
std::shared_ptr<CConnection> c = findConnection(connection);
|
||||
if (c == nullptr)
|
||||
throw std::out_of_range("Unknown connection received in CVCMIServer::findConnection");
|
||||
|
||||
auto pack = c->retrievePack(message);
|
||||
pack->c = c;
|
||||
CVCMIServerPackVisitor visitor(*this, this->gh);
|
||||
@ -197,7 +200,7 @@ std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<I
|
||||
return gameConnection;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown connection received in CVCMIServer::findConnection");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CVCMIServer::wasStartedByClient() const
|
||||
@ -342,6 +345,9 @@ void CVCMIServer::onDisconnected(const std::shared_ptr<INetworkConnection> & con
|
||||
logNetwork->error("Network error receiving a pack. Connection has been closed");
|
||||
|
||||
std::shared_ptr<CConnection> c = findConnection(connection);
|
||||
if (!c)
|
||||
return; // player have already disconnected via clientDisconnected call
|
||||
|
||||
vstd::erase(activeConnections, c);
|
||||
|
||||
if(activeConnections.empty() || hostClientId == c->connectionID)
|
||||
|
@ -27,7 +27,7 @@ void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisi
|
||||
{
|
||||
assert(result);
|
||||
|
||||
if(result && !isAiVsHuman)
|
||||
if(result)
|
||||
objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result);
|
||||
}
|
||||
|
||||
@ -38,8 +38,6 @@ CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi):
|
||||
belligerents[0] = bi->getSideArmy(0);
|
||||
belligerents[1] = bi->getSideArmy(1);
|
||||
|
||||
isAiVsHuman = bi->getSidePlayer(1).isValidPlayer() && gh->getPlayerState(bi->getSidePlayer(0))->isHuman() != gh->getPlayerState(bi->getSidePlayer(1))->isHuman();
|
||||
|
||||
addPlayer(bi->getSidePlayer(0));
|
||||
addPlayer(bi->getSidePlayer(1));
|
||||
}
|
||||
@ -89,7 +87,9 @@ CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const IBattleInfo *
|
||||
|
||||
void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
{
|
||||
if (!gh->getPlayerState(color)->isHuman())
|
||||
// answer to this query was already processed when handling 1st player
|
||||
// this removal call for 2nd player which can be safely ignored
|
||||
if (resultProcessed)
|
||||
return;
|
||||
|
||||
assert(answer);
|
||||
@ -108,13 +108,7 @@ void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto hero = bi->getSideHero(BattleSide::ATTACKER);
|
||||
auto visitingObj = bi->getDefendedTown() ? bi->getDefendedTown() : gh->getVisitingObject(hero);
|
||||
bool isAiVsHuman = bi->getSidePlayer(1).isValidPlayer() && gh->getPlayerState(bi->getSidePlayer(0))->isHuman() != gh->getPlayerState(bi->getSidePlayer(1))->isHuman();
|
||||
|
||||
gh->battles->endBattleConfirm(bi->getBattleID());
|
||||
|
||||
if(visitingObj && result && isAiVsHuman)
|
||||
visitingObj->battleFinished(hero, *result);
|
||||
}
|
||||
resultProcessed = true;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ public:
|
||||
std::array<const CArmedInstance *,2> belligerents;
|
||||
std::array<int, 2> initialHeroMana;
|
||||
|
||||
bool isAiVsHuman;
|
||||
BattleID battleID;
|
||||
std::optional<BattleResult> result;
|
||||
|
||||
@ -37,6 +36,7 @@ public:
|
||||
|
||||
class CBattleDialogQuery : public CDialogQuery
|
||||
{
|
||||
bool resultProcessed = false;
|
||||
public:
|
||||
CBattleDialogQuery(CGameHandler * owner, const IBattleInfo * Bi, std::optional<BattleResult> Br);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user