mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge remote-tracking branch 'origin/develop' into terrain-rewrite
# Conflicts: # lib/Terrain.cpp # lib/Terrain.h
This commit is contained in:
commit
a5077245a8
53
.github/workflows/github.yml
vendored
53
.github/workflows/github.yml
vendored
@ -4,14 +4,65 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- features/*
|
- features/*
|
||||||
- develop
|
|
||||||
pull_request:
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
check_last_build:
|
||||||
|
if: github.event.schedule != ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
skip_build: ${{ steps.check_if_built.outputs.skip_build }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
steps:
|
||||||
|
- name: Get repo name
|
||||||
|
id: get_repo_name
|
||||||
|
run: echo "::set-output name=value::${GITHUB_REPOSITORY#*/}"
|
||||||
|
- name: Get last successful build for ${{ github.sha }}
|
||||||
|
uses: octokit/request-action@v2.1.0
|
||||||
|
id: get_last_scheduled_run
|
||||||
|
with:
|
||||||
|
route: GET /repos/{owner}/{repo}/actions/runs
|
||||||
|
owner: ${{ github.repository_owner }}
|
||||||
|
repo: ${{ steps.get_repo_name.outputs.value }}
|
||||||
|
status: success
|
||||||
|
per_page: 1
|
||||||
|
head_sha: ${{ github.sha }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Check if successful build of the current commit exists
|
||||||
|
id: check_if_built
|
||||||
|
run: |
|
||||||
|
if [ ${{ fromJson(steps.get_last_scheduled_run.outputs.data).total_count }} -gt 0 ]; then
|
||||||
|
echo '::set-output name=skip_build::1'
|
||||||
|
else
|
||||||
|
echo '::set-output name=skip_build::0'
|
||||||
|
fi
|
||||||
|
- name: Cancel current run
|
||||||
|
if: steps.check_if_built.outputs.skip_build == 1
|
||||||
|
uses: octokit/request-action@v2.1.0
|
||||||
|
with:
|
||||||
|
route: POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel
|
||||||
|
owner: ${{ github.repository_owner }}
|
||||||
|
repo: ${{ steps.get_repo_name.outputs.value }}
|
||||||
|
run_id: ${{ github.run_id }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Wait for the run to be cancelled
|
||||||
|
if: steps.check_if_built.outputs.skip_build == 1
|
||||||
|
run: sleep 60
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
needs: check_last_build
|
||||||
|
if: always() && needs.check_last_build.skip_build != 1
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
#include "../../lib/CStack.h"
|
#include "../../lib/CStack.h"
|
||||||
#include "../../lib/ScriptHandler.h"
|
#include "../../lib/ScriptHandler.h"
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
using scripting::Pool;
|
using scripting::Pool;
|
||||||
|
#endif
|
||||||
|
|
||||||
void actualizeEffect(TBonusListPtr target, const Bonus & ef)
|
void actualizeEffect(TBonusListPtr target, const Bonus & ef)
|
||||||
{
|
{
|
||||||
@ -217,7 +219,9 @@ HypotheticBattle::HypotheticBattle(const Environment * ENV, Subject realBattle)
|
|||||||
localEnvironment.reset(new HypotheticEnvironment(this, env));
|
localEnvironment.reset(new HypotheticEnvironment(this, env));
|
||||||
serverCallback.reset(new HypotheticServerCallback(this));
|
serverCallback.reset(new HypotheticServerCallback(this));
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
pool.reset(new scripting::PoolImpl(localEnvironment.get(), serverCallback.get()));
|
pool.reset(new scripting::PoolImpl(localEnvironment.get(), serverCallback.get()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HypotheticBattle::unitHasAmmoCart(const battle::Unit * unit) const
|
bool HypotheticBattle::unitHasAmmoCart(const battle::Unit * unit) const
|
||||||
@ -420,10 +424,12 @@ int64_t HypotheticBattle::getTreeVersion() const
|
|||||||
return getBattleNode()->getTreeVersion() + bonusTreeVersion;
|
return getBattleNode()->getTreeVersion() + bonusTreeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
Pool * HypotheticBattle::getContextPool() const
|
Pool * HypotheticBattle::getContextPool() const
|
||||||
{
|
{
|
||||||
return pool.get();
|
return pool.get();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ServerCallback * HypotheticBattle::getServerCallback()
|
ServerCallback * HypotheticBattle::getServerCallback()
|
||||||
{
|
{
|
||||||
|
@ -136,7 +136,9 @@ public:
|
|||||||
|
|
||||||
int64_t getTreeVersion() const;
|
int64_t getTreeVersion() const;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
ServerCallback * getServerCallback();
|
ServerCallback * getServerCallback();
|
||||||
|
|
||||||
@ -189,6 +191,8 @@ private:
|
|||||||
std::unique_ptr<HypotheticServerCallback> serverCallback;
|
std::unique_ptr<HypotheticServerCallback> serverCallback;
|
||||||
std::unique_ptr<HypotheticEnvironment> localEnvironment;
|
std::unique_ptr<HypotheticEnvironment> localEnvironment;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
mutable std::shared_ptr<scripting::Pool> pool;
|
mutable std::shared_ptr<scripting::Pool> pool;
|
||||||
|
#endif
|
||||||
mutable std::shared_ptr<events::EventBus> eventBus;
|
mutable std::shared_ptr<events::EventBus> eventBus;
|
||||||
};
|
};
|
||||||
|
@ -204,7 +204,6 @@ std::shared_ptr<CCreatureSet> ArmyManager::getArmyAvailableToBuyAsCCreatureSet(
|
|||||||
TResources availableRes) const
|
TResources availableRes) const
|
||||||
{
|
{
|
||||||
std::vector<creInfo> creaturesInDwellings;
|
std::vector<creInfo> creaturesInDwellings;
|
||||||
int freeHeroSlots = GameConstants::ARMY_SIZE;
|
|
||||||
auto army = std::make_shared<TemporaryArmy>();
|
auto army = std::make_shared<TemporaryArmy>();
|
||||||
|
|
||||||
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
|
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
|
||||||
|
@ -41,6 +41,7 @@ struct ArmyUpgradeInfo
|
|||||||
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IArmyManager() = default;
|
||||||
virtual void update() = 0;
|
virtual void update() = 0;
|
||||||
virtual ui64 howManyReinforcementsCanBuy(const CCreatureSet * target, const CGDwelling * source) const = 0;
|
virtual ui64 howManyReinforcementsCanBuy(const CCreatureSet * target, const CGDwelling * source) const = 0;
|
||||||
virtual ui64 howManyReinforcementsCanBuy(
|
virtual ui64 howManyReinforcementsCanBuy(
|
||||||
|
@ -129,8 +129,6 @@ void BuildAnalyzer::update()
|
|||||||
{
|
{
|
||||||
logAi->trace("Checking town %s", town->name);
|
logAi->trace("Checking town %s", town->name);
|
||||||
|
|
||||||
auto townInfo = town->town;
|
|
||||||
|
|
||||||
developmentInfos.push_back(TownDevelopmentInfo(town));
|
developmentInfos.push_back(TownDevelopmentInfo(town));
|
||||||
TownDevelopmentInfo & developmentInfo = developmentInfos.back();
|
TownDevelopmentInfo & developmentInfo = developmentInfos.back();
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ void DangerHitMapAnalyzer::updateHitMap()
|
|||||||
auto & node = hitMap[pos.x][pos.y][pos.z];
|
auto & node = hitMap[pos.x][pos.y][pos.z];
|
||||||
|
|
||||||
if(tileDanger > node.maximumDanger.danger
|
if(tileDanger > node.maximumDanger.danger
|
||||||
|| tileDanger == node.maximumDanger.danger && node.maximumDanger.turn > turn)
|
|| (tileDanger == node.maximumDanger.danger && node.maximumDanger.turn > turn))
|
||||||
{
|
{
|
||||||
node.maximumDanger.danger = tileDanger;
|
node.maximumDanger.danger = tileDanger;
|
||||||
node.maximumDanger.turn = turn;
|
node.maximumDanger.turn = turn;
|
||||||
@ -71,7 +71,7 @@ void DangerHitMapAnalyzer::updateHitMap()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(turn < node.fastestDanger.turn
|
if(turn < node.fastestDanger.turn
|
||||||
|| turn == node.fastestDanger.turn && node.fastestDanger.danger < tileDanger)
|
|| (turn == node.fastestDanger.turn && node.fastestDanger.danger < tileDanger))
|
||||||
{
|
{
|
||||||
node.fastestDanger.danger = tileDanger;
|
node.fastestDanger.danger = tileDanger;
|
||||||
node.fastestDanger.turn = turn;
|
node.fastestDanger.turn = turn;
|
||||||
@ -101,8 +101,8 @@ uint64_t DangerHitMapAnalyzer::enemyCanKillOurHeroesAlongThePath(const AIPath &
|
|||||||
int turn = path.turn();
|
int turn = path.turn();
|
||||||
const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
|
const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
|
||||||
|
|
||||||
return info.fastestDanger.turn <= turn && !isSafeToVisit(path.targetHero, path.heroArmy, info.fastestDanger.danger)
|
return (info.fastestDanger.turn <= turn && !isSafeToVisit(path.targetHero, path.heroArmy, info.fastestDanger.danger))
|
||||||
|| info.maximumDanger.turn <= turn && !isSafeToVisit(path.targetHero, path.heroArmy, info.maximumDanger.danger);
|
|| (info.maximumDanger.turn <= turn && !isSafeToVisit(path.targetHero, path.heroArmy, info.maximumDanger.danger));
|
||||||
}
|
}
|
||||||
|
|
||||||
const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * obj) const
|
const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * obj) const
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
class DLL_EXPORT IHeroManager //: public: IAbstractManager
|
class DLL_EXPORT IHeroManager //: public: IAbstractManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IHeroManager() = default;
|
||||||
virtual const std::map<HeroPtr, HeroRole> & getHeroRoles() const = 0;
|
virtual const std::map<HeroPtr, HeroRole> & getHeroRoles() const = 0;
|
||||||
virtual int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const = 0;
|
virtual int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const = 0;
|
||||||
virtual HeroRole getHeroRole(const HeroPtr & hero) const = 0;
|
virtual HeroRole getHeroRole(const HeroPtr & hero) const = 0;
|
||||||
@ -31,6 +32,7 @@ public:
|
|||||||
class DLL_EXPORT ISecondarySkillRule
|
class DLL_EXPORT ISecondarySkillRule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ISecondarySkillRule() = default;
|
||||||
virtual void evaluateScore(const CGHeroInstance * hero, SecondarySkill skill, float & score) const = 0;
|
virtual void evaluateScore(const CGHeroInstance * hero, SecondarySkill skill, float & score) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,11 +54,10 @@ private:
|
|||||||
static SecondarySkillEvaluator scountSkillsScores;
|
static SecondarySkillEvaluator scountSkillsScores;
|
||||||
|
|
||||||
CCallback * cb; //this is enough, but we downcast from CCallback
|
CCallback * cb; //this is enough, but we downcast from CCallback
|
||||||
const Nullkiller * ai;
|
|
||||||
std::map<HeroPtr, HeroRole> heroRoles;
|
std::map<HeroPtr, HeroRole> heroRoles;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HeroManager(CCallback * CB, const Nullkiller * ai) : cb(CB), ai(ai) {}
|
HeroManager(CCallback * CB, const Nullkiller * ai) : cb(CB) {}
|
||||||
const std::map<HeroPtr, HeroRole> & getHeroRoles() const override;
|
const std::map<HeroPtr, HeroRole> & getHeroRoles() const override;
|
||||||
HeroRole getHeroRole(const HeroPtr & hero) const override;
|
HeroRole getHeroRole(const HeroPtr & hero) const override;
|
||||||
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
||||||
|
@ -149,7 +149,7 @@ bool ObjectClusterizer::shouldVisitObject(const CGObjectInstance * obj) const
|
|||||||
|
|
||||||
const int3 pos = obj->visitablePos();
|
const int3 pos = obj->visitablePos();
|
||||||
|
|
||||||
if(obj->ID != Obj::CREATURE_GENERATOR1 && vstd::contains(ai->memory->alreadyVisited, obj)
|
if((obj->ID != Obj::CREATURE_GENERATOR1 && vstd::contains(ai->memory->alreadyVisited, obj))
|
||||||
|| obj->wasVisited(ai->playerID))
|
|| obj->wasVisited(ai->playerID))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -53,8 +53,6 @@ Goals::TGoalVec BuildingBehavior::decompose() const
|
|||||||
|
|
||||||
for(auto & developmentInfo : developmentInfos)
|
for(auto & developmentInfo : developmentInfos)
|
||||||
{
|
{
|
||||||
auto town = developmentInfo.town;
|
|
||||||
|
|
||||||
for(auto & buildingInfo : developmentInfo.toBuild)
|
for(auto & buildingInfo : developmentInfo.toBuild)
|
||||||
{
|
{
|
||||||
if(goldPreasure < MAX_GOLD_PEASURE || buildingInfo.dailyIncome[Res::GOLD] > 0)
|
if(goldPreasure < MAX_GOLD_PEASURE || buildingInfo.dailyIncome[Res::GOLD] > 0)
|
||||||
|
@ -106,10 +106,10 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
{
|
{
|
||||||
if(path.getHeroStrength() > treat.danger)
|
if(path.getHeroStrength() > treat.danger)
|
||||||
{
|
{
|
||||||
if(path.turn() <= treat.turn && dayOfWeek + treat.turn < 6 && isSafeToVisit(path.targetHero, path.heroArmy, treat.danger)
|
if((path.turn() <= treat.turn && dayOfWeek + treat.turn < 6 && isSafeToVisit(path.targetHero, path.heroArmy, treat.danger))
|
||||||
|| path.exchangeCount == 1 && path.turn() < treat.turn
|
|| (path.exchangeCount == 1 && path.turn() < treat.turn)
|
||||||
|| path.turn() < treat.turn - 1
|
|| path.turn() < treat.turn - 1
|
||||||
|| path.turn() < treat.turn && treat.turn >= 2)
|
|| (path.turn() < treat.turn && treat.turn >= 2))
|
||||||
{
|
{
|
||||||
logAi->debug(
|
logAi->debug(
|
||||||
"Hero %s can eliminate danger for town %s using path %s.",
|
"Hero %s can eliminate danger for town %s using path %s.",
|
||||||
@ -217,7 +217,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
// dismiss creatures we are not able to pick to be able to hide in garrison
|
// dismiss creatures we are not able to pick to be able to hide in garrison
|
||||||
if(town->garrisonHero
|
if(town->garrisonHero
|
||||||
|| town->getUpperArmy()->stacksCount() == 0
|
|| town->getUpperArmy()->stacksCount() == 0
|
||||||
|| town->getUpperArmy()->getArmyStrength() < 500 && town->fortLevel() >= CGTownInstance::CITADEL)
|
|| (town->getUpperArmy()->getArmyStrength() < 500 && town->fortLevel() >= CGTownInstance::CITADEL))
|
||||||
{
|
{
|
||||||
tasks.push_back(
|
tasks.push_back(
|
||||||
Goals::sptr(Composition()
|
Goals::sptr(Composition()
|
||||||
@ -228,7 +228,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(treat.turn == 0 || path.turn() <= treat.turn && path.getHeroStrength() * SAFE_ATTACK_CONSTANT >= treat.danger)
|
if(treat.turn == 0 || (path.turn() <= treat.turn && path.getHeroStrength() * SAFE_ATTACK_CONSTANT >= treat.danger))
|
||||||
{
|
{
|
||||||
if(ai->nullkiller->arePathHeroesLocked(path))
|
if(ai->nullkiller->arePathHeroesLocked(path))
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ const CGHeroInstance * getNearestHero(const CGTownInstance * town)
|
|||||||
if(shortestPath.nodes.size() > 1
|
if(shortestPath.nodes.size() > 1
|
||||||
|| shortestPath.turn() != 0
|
|| shortestPath.turn() != 0
|
||||||
|| shortestPath.targetHero->visitablePos().dist2dSQ(town->visitablePos()) > 4
|
|| shortestPath.targetHero->visitablePos().dist2dSQ(town->visitablePos()) > 4
|
||||||
|| town->garrisonHero && shortestPath.targetHero == town->garrisonHero.get())
|
|| (town->garrisonHero && shortestPath.targetHero == town->garrisonHero.get()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return shortestPath.targetHero;
|
return shortestPath.targetHero;
|
||||||
@ -76,13 +76,13 @@ bool needToRecruitHero(const CGTownInstance * startupTown)
|
|||||||
|
|
||||||
for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects())
|
for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects())
|
||||||
{
|
{
|
||||||
if(obj->ID == Obj::RESOURCE && obj->subID == Res::GOLD
|
if((obj->ID == Obj::RESOURCE && obj->subID == Res::GOLD)
|
||||||
|| obj->ID == Obj::TREASURE_CHEST
|
|| obj->ID == Obj::TREASURE_CHEST
|
||||||
|| obj->ID == Obj::CAMPFIRE
|
|| obj->ID == Obj::CAMPFIRE
|
||||||
|| obj->ID == Obj::WATER_WHEEL)
|
|| obj->ID == Obj::WATER_WHEEL)
|
||||||
{
|
{
|
||||||
auto path = paths->getPathInfo(obj->visitablePos());
|
auto path = paths->getPathInfo(obj->visitablePos());
|
||||||
if((path->accessible == CGPathNode::BLOCKVIS || path->accessible == CGPathNode::VISIT)
|
if((path->accessible == CGPathNode::BLOCKVIS || path->accessible == CGPathNode::VISITABLE)
|
||||||
&& path->reachable())
|
&& path->reachable())
|
||||||
{
|
{
|
||||||
treasureSourcesCount++;
|
treasureSourcesCount++;
|
||||||
@ -162,7 +162,7 @@ Goals::TGoalVec StartupBehavior::decompose() const
|
|||||||
auto garrisonHeroScore = ai->nullkiller->heroManager->evaluateHero(garrisonHero);
|
auto garrisonHeroScore = ai->nullkiller->heroManager->evaluateHero(garrisonHero);
|
||||||
|
|
||||||
if(visitingHeroScore > garrisonHeroScore
|
if(visitingHeroScore > garrisonHeroScore
|
||||||
|| ai->nullkiller->heroManager->getHeroRole(garrisonHero) == HeroRole::SCOUT && ai->nullkiller->heroManager->getHeroRole(visitingHero) == HeroRole::MAIN)
|
|| (ai->nullkiller->heroManager->getHeroRole(garrisonHero) == HeroRole::SCOUT && ai->nullkiller->heroManager->getHeroRole(visitingHero) == HeroRole::MAIN))
|
||||||
{
|
{
|
||||||
if(canRecruitHero || ai->nullkiller->armyManager->howManyReinforcementsCanGet(visitingHero, garrisonHero) > 200)
|
if(canRecruitHero || ai->nullkiller->armyManager->howManyReinforcementsCanGet(visitingHero, garrisonHero) > 200)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
|
|||||||
{
|
{
|
||||||
//No free slot, we might discard our weakest stack
|
//No free slot, we might discard our weakest stack
|
||||||
weakestStackPower = std::numeric_limits<ui64>().max();
|
weakestStackPower = std::numeric_limits<ui64>().max();
|
||||||
for (const auto stack : slots)
|
for (const auto & stack : slots)
|
||||||
{
|
{
|
||||||
vstd::amin(weakestStackPower, stack.second->getPower());
|
vstd::amin(weakestStackPower, stack.second->getPower());
|
||||||
}
|
}
|
||||||
@ -645,7 +645,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto heroPtr = task->hero;
|
auto heroPtr = task->hero;
|
||||||
auto day = ai->cb->getDate(Date::DAY);
|
|
||||||
auto hero = heroPtr.get(ai->cb.get());
|
auto hero = heroPtr.get(ai->cb.get());
|
||||||
bool checkGold = evaluationContext.danger == 0;
|
bool checkGold = evaluationContext.danger == 0;
|
||||||
auto army = path.heroArmy;
|
auto army = path.heroArmy;
|
||||||
@ -670,11 +669,8 @@ public:
|
|||||||
|
|
||||||
class ClusterEvaluationContextBuilder : public IEvaluationContextBuilder
|
class ClusterEvaluationContextBuilder : public IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
const Nullkiller * ai;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClusterEvaluationContextBuilder(const Nullkiller * ai) : ai(ai) {}
|
ClusterEvaluationContextBuilder(const Nullkiller * ai) {}
|
||||||
|
|
||||||
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
|
||||||
{
|
{
|
||||||
@ -699,7 +695,6 @@ public:
|
|||||||
for(auto objInfo : objects)
|
for(auto objInfo : objects)
|
||||||
{
|
{
|
||||||
auto target = objInfo.first;
|
auto target = objInfo.first;
|
||||||
auto day = ai->cb->getDate(Date::DAY);
|
|
||||||
bool checkGold = objInfo.second.danger == 0;
|
bool checkGold = objInfo.second.danger == 0;
|
||||||
auto army = hero;
|
auto army = hero;
|
||||||
|
|
||||||
@ -718,9 +713,6 @@ public:
|
|||||||
if(boost > 8)
|
if(boost > 8)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AIPath & pathToCenter = clusterGoal.getPathToCenter();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ struct DLL_EXPORT EvaluationContext
|
|||||||
class IEvaluationContextBuilder
|
class IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IEvaluationContextBuilder() = default;
|
||||||
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal goal) const = 0;
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal goal) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ bool AINodeStorage::selectNextActor()
|
|||||||
for(auto actor = actors.begin(); actor != actors.end(); actor++)
|
for(auto actor = actors.begin(); actor != actors.end(); actor++)
|
||||||
{
|
{
|
||||||
if(actor->get()->armyValue > currentActor->get()->armyValue
|
if(actor->get()->armyValue > currentActor->get()->armyValue
|
||||||
|| actor->get()->armyValue == currentActor->get()->armyValue && actor <= currentActor)
|
|| (actor->get()->armyValue == currentActor->get()->armyValue && actor <= currentActor))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,6 @@ namespace AIPathfinding
|
|||||||
|
|
||||||
class SummonBoatAction : public VirtualBoatAction
|
class SummonBoatAction : public VirtualBoatAction
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
const CGHeroInstance * hero;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void execute(const CGHeroInstance * hero) const override;
|
virtual void execute(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ struct AIPathNode;
|
|||||||
class SpecialAction
|
class SpecialAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~SpecialAction() = default;
|
||||||
|
|
||||||
virtual bool canAct(const AIPathNode * source) const
|
virtual bool canAct(const AIPathNode * source) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -269,8 +269,6 @@ ExchangeResult HeroExchangeMap::tryExchangeNoLock(const ChainActor * other)
|
|||||||
return result; // already inserted
|
return result; // already inserted
|
||||||
}
|
}
|
||||||
|
|
||||||
auto position = inserted.first;
|
|
||||||
|
|
||||||
auto differentMasks = (actor->chainMask & other->chainMask) == 0;
|
auto differentMasks = (actor->chainMask & other->chainMask) == 0;
|
||||||
|
|
||||||
if(!differentMasks) return result;
|
if(!differentMasks) return result;
|
||||||
@ -461,15 +459,6 @@ CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto creature = creatureInfo.second.back().toCreature();
|
auto creature = creatureInfo.second.back().toCreature();
|
||||||
auto count = creatureInfo.first;
|
|
||||||
|
|
||||||
if(waitForGrowth)
|
|
||||||
{
|
|
||||||
const CGTownInstance * town = dynamic_cast<const CGTownInstance *>(dwelling);
|
|
||||||
|
|
||||||
count += town ? town->creatureGrowth(creature->level) : creature->growth;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwellingCreatures->addToSlot(
|
dwellingCreatures->addToSlot(
|
||||||
dwellingCreatures->getSlotFor(creature),
|
dwellingCreatures->getSlotFor(creature),
|
||||||
creature->idNumber,
|
creature->idNumber,
|
||||||
|
@ -75,7 +75,8 @@ public:
|
|||||||
TResources armyCost;
|
TResources armyCost;
|
||||||
std::shared_ptr<TurnInfo> tiCache;
|
std::shared_ptr<TurnInfo> tiCache;
|
||||||
|
|
||||||
ChainActor(){}
|
ChainActor() = default;
|
||||||
|
virtual ~ChainActor() = default;
|
||||||
|
|
||||||
virtual std::string toString() const;
|
virtual std::string toString() const;
|
||||||
ExchangeResult tryExchangeNoLock(const ChainActor * other) const { return tryExchangeNoLock(this, other); }
|
ExchangeResult tryExchangeNoLock(const ChainActor * other) const { return tryExchangeNoLock(this, other); }
|
||||||
|
@ -126,7 +126,6 @@ namespace AIPathfinding
|
|||||||
const AIPathNode * destinationNode = nodeStorage->getAINode(destination.node);
|
const AIPathNode * destinationNode = nodeStorage->getAINode(destination.node);
|
||||||
auto questObj = dynamic_cast<const IQuestObject *>(destination.nodeObject);
|
auto questObj = dynamic_cast<const IQuestObject *>(destination.nodeObject);
|
||||||
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
|
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
|
||||||
auto nodeHero = pathfinderHelper->hero;
|
|
||||||
QuestAction questAction(questInfo);
|
QuestAction questAction(questInfo);
|
||||||
|
|
||||||
if(destination.nodeObject->ID == Obj::QUEST_GUARD && questObj->quest->missionType == CQuest::MISSION_NONE)
|
if(destination.nodeObject->ID == Obj::QUEST_GUARD && questObj->quest->missionType == CQuest::MISSION_NONE)
|
||||||
@ -157,8 +156,6 @@ namespace AIPathfinding
|
|||||||
|
|
||||||
nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
|
nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
|
||||||
{
|
{
|
||||||
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
|
|
||||||
|
|
||||||
node->specialAction.reset(new QuestAction(questAction));
|
node->specialAction.reset(new QuestAction(questAction));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,6 @@ AIhelper::AIhelper()
|
|||||||
armyManager.reset(new ArmyManager());
|
armyManager.reset(new ArmyManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
AIhelper::~AIhelper()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AIhelper::notifyGoalCompleted(Goals::TSubgoal goal)
|
bool AIhelper::notifyGoalCompleted(Goals::TSubgoal goal)
|
||||||
{
|
{
|
||||||
return resourceManager->notifyGoalCompleted(goal);
|
return resourceManager->notifyGoalCompleted(goal);
|
||||||
|
@ -36,7 +36,6 @@ class DLL_EXPORT AIhelper : public IResourceManager, public IBuildingManager, pu
|
|||||||
//TODO: vector<IAbstractManager>
|
//TODO: vector<IAbstractManager>
|
||||||
public:
|
public:
|
||||||
AIhelper();
|
AIhelper();
|
||||||
~AIhelper();
|
|
||||||
|
|
||||||
bool canAfford(const TResources & cost) const;
|
bool canAfford(const TResources & cost) const;
|
||||||
TResources reservedResources() const override;
|
TResources reservedResources() const override;
|
||||||
|
@ -28,6 +28,7 @@ struct SlotInfo
|
|||||||
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IArmyManager() = default;
|
||||||
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
||||||
virtual void setAI(VCAI * AI) = 0;
|
virtual void setAI(VCAI * AI) = 0;
|
||||||
virtual bool canGetArmy(const CArmedInstance * target, const CArmedInstance * source) const = 0;
|
virtual bool canGetArmy(const CArmedInstance * target, const CArmedInstance * source) const = 0;
|
||||||
|
@ -120,14 +120,12 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
|
|||||||
return o.goal;
|
return o.goal;
|
||||||
}
|
}
|
||||||
|
|
||||||
float goalPriority = 10; //arbitrary, will be divided
|
for (const resPair p : missingResources)
|
||||||
for (const resPair & p : missingResources)
|
|
||||||
{
|
{
|
||||||
if (!income[p.first]) //prioritize resources with 0 income
|
if (!income[p.first]) //prioritize resources with 0 income
|
||||||
{
|
{
|
||||||
resourceType = p.first;
|
resourceType = p.first;
|
||||||
amountToCollect = p.second;
|
amountToCollect = p.second;
|
||||||
goalPriority /= amountToCollect; //need more resources -> lower priority
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,7 +136,7 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
|
|||||||
std::map<Res::ERes, float> daysToEarn;
|
std::map<Res::ERes, float> daysToEarn;
|
||||||
for (auto it : missingResources)
|
for (auto it : missingResources)
|
||||||
daysToEarn[it.first] = (float)missingResources[it.first] / income[it.first];
|
daysToEarn[it.first] = (float)missingResources[it.first] / income[it.first];
|
||||||
auto incomeComparer = [&income](const timePair & lhs, const timePair & rhs) -> bool
|
auto incomeComparer = [](const timePair & lhs, const timePair & rhs) -> bool
|
||||||
{
|
{
|
||||||
//theoretically income can be negative, but that falls into this comparison
|
//theoretically income can be negative, but that falls into this comparison
|
||||||
return lhs.second < rhs.second;
|
return lhs.second < rhs.second;
|
||||||
@ -146,12 +144,9 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
|
|||||||
|
|
||||||
resourceType = boost::max_element(daysToEarn, incomeComparer)->first;
|
resourceType = boost::max_element(daysToEarn, incomeComparer)->first;
|
||||||
amountToCollect = missingResources[resourceType];
|
amountToCollect = missingResources[resourceType];
|
||||||
goalPriority /= daysToEarn[resourceType]; //more days - lower priority
|
|
||||||
}
|
}
|
||||||
if (resourceType == Res::GOLD)
|
|
||||||
goalPriority *= 1000;
|
|
||||||
|
|
||||||
//this is abstract goal and might take soem time to complete
|
//this is abstract goal and might take some time to complete
|
||||||
return Goals::sptr(Goals::CollectRes(resourceType, amountToCollect).setisAbstract(true));
|
return Goals::sptr(Goals::CollectRes(resourceType, amountToCollect).setisAbstract(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,10 +366,12 @@ void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver>
|
|||||||
cl->additionalBattleInts[*player] -= battleEvents;
|
cl->additionalBattleInts[*player] -= battleEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * CBattleCallback::getContextPool() const
|
scripting::Pool * CBattleCallback::getContextPool() const
|
||||||
{
|
{
|
||||||
return cl->getGlobalContextPool();
|
return cl->getGlobalContextPool();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CBattleCallback::CBattleCallback(boost::optional<PlayerColor> Player, CClient *C )
|
CBattleCallback::CBattleCallback(boost::optional<PlayerColor> Player, CClient *C )
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,8 @@ struct ArtifactLocation;
|
|||||||
class IBattleCallback
|
class IBattleCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IBattleCallback() = default;
|
||||||
|
|
||||||
bool waitTillRealize; //if true, request functions will return after they are realized by server
|
bool waitTillRealize; //if true, request functions will return after they are realized by server
|
||||||
bool unlockGsWhenWaiting;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback!
|
bool unlockGsWhenWaiting;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback!
|
||||||
//battle
|
//battle
|
||||||
@ -99,7 +101,9 @@ public:
|
|||||||
int battleMakeAction(const BattleAction * action) override;//for casting spells by hero - DO NOT use it for moving active stack
|
int battleMakeAction(const BattleAction * action) override;//for casting spells by hero - DO NOT use it for moving active stack
|
||||||
bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
|
bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
friend class CCallback;
|
friend class CCallback;
|
||||||
friend class CClient;
|
friend class CClient;
|
||||||
|
@ -41,8 +41,8 @@ set(VCMI_VERSION_MAJOR 1)
|
|||||||
set(VCMI_VERSION_MINOR 0)
|
set(VCMI_VERSION_MINOR 0)
|
||||||
set(VCMI_VERSION_PATCH 0)
|
set(VCMI_VERSION_PATCH 0)
|
||||||
|
|
||||||
option(ENABLE_ERM "Enable compilation of ERM scripting module" ON)
|
option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF)
|
||||||
option(ENABLE_LUA "Enable compilation of LUA scripting module" ON)
|
option(ENABLE_LUA "Enable compilation of LUA scripting module" OFF)
|
||||||
option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
|
option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
|
||||||
option(ENABLE_TEST "Enable compilation of unit tests" ON)
|
option(ENABLE_TEST "Enable compilation of unit tests" ON)
|
||||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0")
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0")
|
||||||
@ -59,6 +59,11 @@ option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linu
|
|||||||
set(PACKAGE_NAME_SUFFIX "" CACHE STRING "Suffix for CPack package name")
|
set(PACKAGE_NAME_SUFFIX "" CACHE STRING "Suffix for CPack package name")
|
||||||
set(PACKAGE_FILE_NAME "" CACHE STRING "Override for CPack package filename")
|
set(PACKAGE_FILE_NAME "" CACHE STRING "Override for CPack package filename")
|
||||||
|
|
||||||
|
# ERM depends on LUA implicitly
|
||||||
|
if(ENABLE_ERM AND NOT ENABLE_LUA)
|
||||||
|
set(ENABLE_LUA ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
# Miscellaneous options #
|
# Miscellaneous options #
|
||||||
############################################
|
############################################
|
||||||
@ -192,6 +197,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support suc
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing -Wno-switch -Wno-sign-compare -Wno-unused-local-typedefs")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing -Wno-switch -Wno-sign-compare -Wno-unused-local-typedefs")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-overloaded-virtual -Wno-type-limits -Wno-unknown-pragmas")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-overloaded-virtual -Wno-type-limits -Wno-unknown-pragmas")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-varargs") # fuzzylite - Operation.h
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-mismatched-tags -Wno-unknown-warning-option -Wno-missing-braces")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-mismatched-tags -Wno-unknown-warning-option -Wno-missing-braces")
|
||||||
@ -214,6 +220,10 @@ if(NOT WIN32)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_LUA)
|
||||||
|
add_compile_definitions(SCRIPTING_ENABLED=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
# Finding packages #
|
# Finding packages #
|
||||||
############################################
|
############################################
|
||||||
|
@ -79,11 +79,7 @@
|
|||||||
"name": "macos-arm-conan-ninja-release",
|
"name": "macos-arm-conan-ninja-release",
|
||||||
"displayName": "Ninja+Conan arm64 release",
|
"displayName": "Ninja+Conan arm64 release",
|
||||||
"description": "VCMI MacOS-arm64 Ninja using Conan",
|
"description": "VCMI MacOS-arm64 Ninja using Conan",
|
||||||
"inherits": "macos-conan-ninja-release",
|
"inherits": "macos-conan-ninja-release"
|
||||||
"cacheVariables": {
|
|
||||||
"ENABLE_ERM": "OFF",
|
|
||||||
"ENABLE_LUA": "OFF"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "macos-xcode-release",
|
"name": "macos-xcode-release",
|
||||||
|
20
ChangeLog
20
ChangeLog
@ -1,4 +1,22 @@
|
|||||||
0.99 -> 1.0
|
1.0.0 -> 1.1.0
|
||||||
|
|
||||||
|
GENERAL:
|
||||||
|
* Mods and their versions and serialized into save files. Game checks mod compatibility before loading
|
||||||
|
* Logs are stored in system default logs directory
|
||||||
|
* LUA/ERM libs are not compiled by default
|
||||||
|
* FFMpeg dependency is optional now
|
||||||
|
|
||||||
|
MODS:
|
||||||
|
* Supported rewardable objects customization
|
||||||
|
* Battleground obstacles are extendable now with VLC mechanism
|
||||||
|
* Introduced "compatibility" section into mods settings
|
||||||
|
|
||||||
|
LAUNCHER:
|
||||||
|
* Fixed problem with duplicated mods in the list
|
||||||
|
* Launcher shows compatible mods only
|
||||||
|
* Uninstall button was moved to the left of layout
|
||||||
|
|
||||||
|
0.99 -> 1.0.0
|
||||||
|
|
||||||
GENERAL:
|
GENERAL:
|
||||||
* Spectator mode was implemented through command-line options
|
* Spectator mode was implemented through command-line options
|
||||||
|
@ -72,10 +72,12 @@ const HeroTypeService * CGameInfo::heroTypes() const
|
|||||||
return globalServices->heroTypes();
|
return globalServices->heroTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * CGameInfo::scripts() const
|
const scripting::Service * CGameInfo::scripts() const
|
||||||
{
|
{
|
||||||
return globalServices->scripts();
|
return globalServices->scripts();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const spells::Service * CGameInfo::spells() const
|
const spells::Service * CGameInfo::spells() const
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,9 @@ public:
|
|||||||
const FactionService * factions() const override;
|
const FactionService * factions() const override;
|
||||||
const HeroClassService * heroClasses() const override;
|
const HeroClassService * heroClasses() const override;
|
||||||
const HeroTypeService * heroTypes() const override;
|
const HeroTypeService * heroTypes() const override;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * scripts() const override;
|
const scripting::Service * scripts() const override;
|
||||||
|
#endif
|
||||||
const spells::Service * spells() const override;
|
const spells::Service * spells() const override;
|
||||||
const SkillService * skills() const override;
|
const SkillService * skills() const override;
|
||||||
const BattleFieldService * battlefields() const override;
|
const BattleFieldService * battlefields() const override;
|
||||||
|
@ -686,6 +686,7 @@ void processCommand(const std::string &message)
|
|||||||
std::cout << "\rExtracting done :)\n";
|
std::cout << "\rExtracting done :)\n";
|
||||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||||
}
|
}
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
else if(message=="get scripts")
|
else if(message=="get scripts")
|
||||||
{
|
{
|
||||||
std::cout << "Command accepted.\t";
|
std::cout << "Command accepted.\t";
|
||||||
@ -708,6 +709,7 @@ void processCommand(const std::string &message)
|
|||||||
std::cout << "\rExtracting done :)\n";
|
std::cout << "\rExtracting done :)\n";
|
||||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
else if(message=="get txt")
|
else if(message=="get txt")
|
||||||
{
|
{
|
||||||
std::cout << "Command accepted.\t";
|
std::cout << "Command accepted.\t";
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "lobby/CSelectionBase.h"
|
#include "lobby/CSelectionBase.h"
|
||||||
#include "lobby/CLobbyScreen.h"
|
#include "lobby/CLobbyScreen.h"
|
||||||
|
#include "windows/InfoWindows.h"
|
||||||
|
|
||||||
#include "mainmenu/CMainMenu.h"
|
#include "mainmenu/CMainMenu.h"
|
||||||
|
|
||||||
@ -161,6 +162,20 @@ void CServerHandler::startLocalServerAndConnect()
|
|||||||
threadRunLocalServer->join();
|
threadRunLocalServer->join();
|
||||||
|
|
||||||
th->update();
|
th->update();
|
||||||
|
|
||||||
|
auto errorMsg = CGI->generaltexth->localizedTexts["server"]["errors"]["existingProcess"].String();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CConnection testConnection(settings["server"]["server"].String(), getDefaultPort(), NAME, uuid);
|
||||||
|
logNetwork->error("Port is busy, check if another instance of vcmiserver is working");
|
||||||
|
CInfoWindow::showInfoDialog(errorMsg, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
//no connection means that port is not busy and we can start local server
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
{
|
{
|
||||||
CAndroidVMHelper envHelper;
|
CAndroidVMHelper envHelper;
|
||||||
|
@ -263,12 +263,14 @@ void CClient::serialize(BinarySerializer & h, const int version)
|
|||||||
i->second->saveGame(h, version);
|
i->second->saveGame(h, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
if(version >= 800)
|
if(version >= 800)
|
||||||
{
|
{
|
||||||
JsonNode scriptsState;
|
JsonNode scriptsState;
|
||||||
clientScripts->serializeState(h.saving, scriptsState);
|
clientScripts->serializeState(h.saving, scriptsState);
|
||||||
h & scriptsState;
|
h & scriptsState;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::serialize(BinaryDeserializer & h, const int version)
|
void CClient::serialize(BinaryDeserializer & h, const int version)
|
||||||
@ -329,11 +331,13 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
|
|||||||
LOCPLINT = prevInt;
|
LOCPLINT = prevInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
{
|
{
|
||||||
JsonNode scriptsState;
|
JsonNode scriptsState;
|
||||||
h & scriptsState;
|
h & scriptsState;
|
||||||
clientScripts->serializeState(h.saving, scriptsState);
|
clientScripts->serializeState(h.saving, scriptsState);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
logNetwork->trace("Loaded client part of save %d ms", CSH->th->getDiff());
|
logNetwork->trace("Loaded client part of save %d ms", CSH->th->getDiff());
|
||||||
}
|
}
|
||||||
@ -352,7 +356,9 @@ void CClient::save(const std::string & fname)
|
|||||||
|
|
||||||
void CClient::endGame()
|
void CClient::endGame()
|
||||||
{
|
{
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
clientScripts.reset();
|
clientScripts.reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
|
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
|
||||||
for(auto & i : playerint)
|
for(auto & i : playerint)
|
||||||
@ -732,6 +738,7 @@ PlayerColor CClient::getLocalPlayer() const
|
|||||||
return getCurrentPlayer();
|
return getCurrentPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * CClient::getGlobalContextPool() const
|
scripting::Pool * CClient::getGlobalContextPool() const
|
||||||
{
|
{
|
||||||
return clientScripts.get();
|
return clientScripts.get();
|
||||||
@ -741,11 +748,14 @@ scripting::Pool * CClient::getContextPool() const
|
|||||||
{
|
{
|
||||||
return clientScripts.get();
|
return clientScripts.get();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CClient::reinitScripting()
|
void CClient::reinitScripting()
|
||||||
{
|
{
|
||||||
clientEventBus = make_unique<events::EventBus>();
|
clientEventBus = make_unique<events::EventBus>();
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
clientScripts.reset(new scripting::PoolImpl(this));
|
clientScripts.reset(new scripting::PoolImpl(this));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,10 +39,12 @@ namespace boost { class thread; }
|
|||||||
template<typename T> class CApplier;
|
template<typename T> class CApplier;
|
||||||
class CBaseForCLApply;
|
class CBaseForCLApply;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class PoolImpl;
|
class PoolImpl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace events
|
namespace events
|
||||||
{
|
{
|
||||||
@ -233,13 +235,18 @@ public:
|
|||||||
void showInfoDialog(InfoWindow * iw) override {};
|
void showInfoDialog(InfoWindow * iw) override {};
|
||||||
void showInfoDialog(const std::string & msg, PlayerColor player) override {};
|
void showInfoDialog(const std::string & msg, PlayerColor player) override {};
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * getGlobalContextPool() const override;
|
scripting::Pool * getGlobalContextPool() const override;
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<PlayerColor, std::shared_ptr<CBattleCallback>> battleCallbacks; //callbacks given to player interfaces
|
std::map<PlayerColor, std::shared_ptr<CBattleCallback>> battleCallbacks; //callbacks given to player interfaces
|
||||||
std::map<PlayerColor, std::shared_ptr<CPlayerEnvironment>> playerEnvironments;
|
std::map<PlayerColor, std::shared_ptr<CPlayerEnvironment>> playerEnvironments;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
std::shared_ptr<scripting::PoolImpl> clientScripts;
|
std::shared_ptr<scripting::PoolImpl> clientScripts;
|
||||||
|
#endif
|
||||||
std::unique_ptr<events::EventBus> clientEventBus;
|
std::unique_ptr<events::EventBus> clientEventBus;
|
||||||
|
|
||||||
std::shared_ptr<CApplier<CBaseForCLApply>> applier;
|
std::shared_ptr<CApplier<CBaseForCLApply>> applier;
|
||||||
|
@ -1083,11 +1083,10 @@ void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attacked
|
|||||||
|
|
||||||
std::array<int, 2> killedBySide = {0, 0};
|
std::array<int, 2> killedBySide = {0, 0};
|
||||||
|
|
||||||
int targets = 0, damage = 0;
|
int targets = 0;
|
||||||
for(const StackAttackedInfo & attackedInfo : attackedInfos)
|
for(const StackAttackedInfo & attackedInfo : attackedInfos)
|
||||||
{
|
{
|
||||||
++targets;
|
++targets;
|
||||||
damage += (int)attackedInfo.dmg;
|
|
||||||
|
|
||||||
ui8 side = attackedInfo.defender->side;
|
ui8 side = attackedInfo.defender->side;
|
||||||
killedBySide.at(side) += attackedInfo.amountKilled;
|
killedBySide.at(side) += attackedInfo.amountKilled;
|
||||||
|
@ -10,10 +10,11 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CAnimation.h"
|
#include "CAnimation.h"
|
||||||
|
|
||||||
|
#include "SDL_Extensions.h"
|
||||||
|
#include "SDL_Pixels.h"
|
||||||
|
|
||||||
#include "../CBitmapHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "../Graphics.h"
|
#include "../Graphics.h"
|
||||||
#include "../gui/SDL_Extensions.h"
|
|
||||||
#include "../gui/SDL_Pixels.h"
|
|
||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||||
|
@ -140,6 +140,7 @@ public:
|
|||||||
//double click
|
//double click
|
||||||
virtual void onDoubleClick(){}
|
virtual void onDoubleClick(){}
|
||||||
|
|
||||||
|
// These are the arguments that can be used to determine what kind of input the CIntObject will receive
|
||||||
enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, MCLICK=1024, ALL=0xffff};
|
enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, MCLICK=1024, ALL=0xffff};
|
||||||
const ui16 & active;
|
const ui16 & active;
|
||||||
void addUsedEvents(ui16 newActions);
|
void addUsedEvents(ui16 newActions);
|
||||||
|
@ -155,6 +155,7 @@ typedef void (*BlitterWithRotationVal)(SDL_Surface *src,SDL_Rect srcRect, SDL_Su
|
|||||||
class ColorShifter
|
class ColorShifter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ColorShifter() = default;
|
||||||
virtual SDL_Color shiftColor(SDL_Color clr) const = 0;
|
virtual SDL_Color shiftColor(SDL_Color clr) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "../mainmenu/CMainMenu.h"
|
|
||||||
#include "CCampaignScreen.h"
|
#include "CCampaignScreen.h"
|
||||||
|
|
||||||
|
#include "CMainMenu.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CBitmapHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../windows/CWindowObject.h"
|
||||||
|
|
||||||
class CLabel;
|
class CLabel;
|
||||||
class CPicture;
|
class CPicture;
|
||||||
class CButton;
|
class CButton;
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
|
||||||
#include "CreditsScreen.h"
|
#include "CreditsScreen.h"
|
||||||
#include "../mainmenu/CMainMenu.h"
|
|
||||||
|
#include "CMainMenu.h"
|
||||||
|
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../widgets/TextControls.h"
|
#include "../widgets/TextControls.h"
|
||||||
#include "../widgets/ObjectLists.h"
|
#include "../widgets/ObjectLists.h"
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "MiscWidgets.h"
|
#include "MiscWidgets.h"
|
||||||
#include "CComponent.h"
|
#include "CComponent.h"
|
||||||
|
#include "Images.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CMusicHandler.h"
|
#include "../CMusicHandler.h"
|
||||||
@ -26,8 +27,6 @@
|
|||||||
#include "../gui/SDL_Pixels.h"
|
#include "../gui/SDL_Pixels.h"
|
||||||
#include "../gui/SDL_Compat.h"
|
#include "../gui/SDL_Compat.h"
|
||||||
|
|
||||||
#include "../widgets/Images.h"
|
|
||||||
|
|
||||||
#include "../windows/InfoWindows.h"
|
#include "../windows/InfoWindows.h"
|
||||||
#include "../windows/CAdvmapInterface.h"
|
#include "../windows/CAdvmapInterface.h"
|
||||||
#include "../windows/GUIClasses.h"
|
#include "../windows/GUIClasses.h"
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CComponent.h"
|
#include "CComponent.h"
|
||||||
|
|
||||||
|
#include "CArtifactHolder.h"
|
||||||
|
#include "Images.h"
|
||||||
|
|
||||||
#include <vcmi/spells/Service.h>
|
#include <vcmi/spells/Service.h>
|
||||||
#include <vcmi/spells/Spell.h>
|
#include <vcmi/spells/Spell.h>
|
||||||
|
|
||||||
@ -18,8 +21,6 @@
|
|||||||
|
|
||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../widgets/Images.h"
|
|
||||||
#include "../widgets/CArtifactHolder.h"
|
|
||||||
#include "../windows/CAdvmapInterface.h"
|
#include "../windows/CAdvmapInterface.h"
|
||||||
|
|
||||||
#include "../../lib/CArtHandler.h"
|
#include "../../lib/CArtHandler.h"
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CGarrisonInt.h"
|
#include "CGarrisonInt.h"
|
||||||
|
|
||||||
|
#include "Buttons.h"
|
||||||
|
#include "TextControls.h"
|
||||||
|
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CPlayerInterface.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "../widgets/Buttons.h"
|
|
||||||
#include "../widgets/TextControls.h"
|
|
||||||
#include "../windows/CCreatureWindow.h"
|
#include "../windows/CCreatureWindow.h"
|
||||||
#include "../windows/GUIClasses.h"
|
#include "../windows/GUIClasses.h"
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CKingdomInterface.h"
|
#include "CKingdomInterface.h"
|
||||||
#include "CSpellWindow.h"
|
#include "CSpellWindow.h"
|
||||||
#include "GUIClasses.h"
|
|
||||||
#include "CTradeWindow.h"
|
#include "CTradeWindow.h"
|
||||||
|
#include "GUIClasses.h"
|
||||||
|
#include "InfoWindows.h"
|
||||||
|
|
||||||
#include "../CBitmapHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
@ -35,7 +36,6 @@
|
|||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../gui/SDL_Extensions.h"
|
#include "../gui/SDL_Extensions.h"
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
#include "../windows/InfoWindows.h"
|
|
||||||
|
|
||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
@ -1217,7 +1217,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
|
|||||||
if(itr != LOCPLINT->towns.end())
|
if(itr != LOCPLINT->towns.end())
|
||||||
LOCPLINT->showThievesGuildWindow(*itr);
|
LOCPLINT->showThievesGuildWindow(*itr);
|
||||||
else
|
else
|
||||||
LOCPLINT->showInfoDialog("No available town with tavern!");
|
LOCPLINT->showInfoDialog(CGI->generaltexth->localizedTexts["adventureMap"]["noTownWithTavern"].String());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_i:
|
case SDLK_i:
|
||||||
@ -1249,7 +1249,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
|
|||||||
case SDLK_r:
|
case SDLK_r:
|
||||||
if(isActive() && LOCPLINT->ctrlPressed())
|
if(isActive() && LOCPLINT->ctrlPressed())
|
||||||
{
|
{
|
||||||
LOCPLINT->showYesNoDialog("Are you sure you want to restart game?",
|
LOCPLINT->showYesNoDialog(CGI->generaltexth->localizedTexts["adventureMap"]["confirmRestartGame"].String(),
|
||||||
[](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr);
|
[](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -1308,7 +1308,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
|
|||||||
if(townWithMarket) //if any town has marketplace, open window
|
if(townWithMarket) //if any town has marketplace, open window
|
||||||
GH.pushIntT<CMarketplaceWindow>(townWithMarket);
|
GH.pushIntT<CMarketplaceWindow>(townWithMarket);
|
||||||
else //if not - complain
|
else //if not - complain
|
||||||
LOCPLINT->showInfoDialog("No available marketplace!");
|
LOCPLINT->showInfoDialog(CGI->generaltexth->localizedTexts["adventureMap"]["noTownWithMarket"].String());
|
||||||
}
|
}
|
||||||
else if(isActive()) //no ctrl, advmapint is on the top => switch to town
|
else if(isActive()) //no ctrl, advmapint is on the top => switch to town
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "CAdvmapInterface.h"
|
#include "CAdvmapInterface.h"
|
||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CTradeWindow.h"
|
#include "CTradeWindow.h"
|
||||||
|
#include "InfoWindows.h"
|
||||||
#include "GUIClasses.h"
|
#include "GUIClasses.h"
|
||||||
#include "QuickRecruitmentWindow.h"
|
#include "QuickRecruitmentWindow.h"
|
||||||
|
|
||||||
@ -24,7 +25,6 @@
|
|||||||
#include "../Graphics.h"
|
#include "../Graphics.h"
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../gui/SDL_Extensions.h"
|
#include "../gui/SDL_Extensions.h"
|
||||||
#include "../windows/InfoWindows.h"
|
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
#include "../widgets/CComponent.h"
|
#include "../widgets/CComponent.h"
|
||||||
|
|
||||||
@ -842,7 +842,16 @@ void CCastleBuildings::enterDwelling(int level)
|
|||||||
|
|
||||||
void CCastleBuildings::enterToTheQuickRecruitmentWindow()
|
void CCastleBuildings::enterToTheQuickRecruitmentWindow()
|
||||||
{
|
{
|
||||||
|
const auto beginIt = town->creatures.cbegin();
|
||||||
|
const auto afterLastIt = town->creatures.size() > GameConstants::CREATURES_PER_TOWN
|
||||||
|
? std::next(beginIt, GameConstants::CREATURES_PER_TOWN)
|
||||||
|
: town->creatures.cend();
|
||||||
|
const auto hasSomeoneToRecruit = std::any_of(beginIt, afterLastIt,
|
||||||
|
[](const auto & creatureInfo) { return creatureInfo.first > 0; });
|
||||||
|
if(hasSomeoneToRecruit)
|
||||||
GH.pushIntT<QuickRecruitmentWindow>(town, pos);
|
GH.pushIntT<QuickRecruitmentWindow>(town, pos);
|
||||||
|
else
|
||||||
|
CInfoWindow::showInfoDialog(CGI->generaltexth->localizedTexts["townHall"]["noCreaturesToRecruit"].String(), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades)
|
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID::EBuildingID upgrades)
|
||||||
@ -1235,9 +1244,9 @@ void CCastleInterface::recreateIcons()
|
|||||||
hall = std::make_shared<CTownInfo>(80, 413, town, true);
|
hall = std::make_shared<CTownInfo>(80, 413, town, true);
|
||||||
fort = std::make_shared<CTownInfo>(122, 413, town, false);
|
fort = std::make_shared<CTownInfo>(122, 413, town, false);
|
||||||
|
|
||||||
fastArmyPurhase = std::make_shared<CButton>(Point(122, 413), "itmcl.def", CButton::tooltip(), [&](){builds->enterToTheQuickRecruitmentWindow();});
|
fastArmyPurchase = std::make_shared<CButton>(Point(122, 413), "itmcl.def", CButton::tooltip(), [&](){ builds->enterToTheQuickRecruitmentWindow(); });
|
||||||
fastArmyPurhase->setImageOrder(town->fortLevel()-1, town->fortLevel()-1, town->fortLevel()-1, town->fortLevel()-1);
|
fastArmyPurchase->setImageOrder(town->fortLevel() - 1, town->fortLevel() - 1, town->fortLevel() - 1, town->fortLevel() - 1);
|
||||||
fastArmyPurhase->setAnimateLonelyFrame(true);
|
fastArmyPurchase->setAnimateLonelyFrame(true);
|
||||||
|
|
||||||
creainfo.clear();
|
creainfo.clear();
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ class CCastleInterface : public CStatusbarWindow, public CGarrisonHolder
|
|||||||
|
|
||||||
std::shared_ptr<CButton> exit;
|
std::shared_ptr<CButton> exit;
|
||||||
std::shared_ptr<CButton> split;
|
std::shared_ptr<CButton> split;
|
||||||
std::shared_ptr<CButton> fastArmyPurhase;
|
std::shared_ptr<CButton> fastArmyPurchase;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CCreaInfo>> creainfo;//small icons of creatures (bottom-left corner);
|
std::vector<std::shared_ptr<CCreaInfo>> creainfo;//small icons of creatures (bottom-left corner);
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "CAdvmapInterface.h"
|
#include "CAdvmapInterface.h"
|
||||||
#include "CCastleInterface.h"
|
#include "CCastleInterface.h"
|
||||||
|
#include "InfoWindows.h"
|
||||||
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CMT.h"
|
#include "../CMT.h"
|
||||||
@ -19,7 +20,6 @@
|
|||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../widgets/CComponent.h"
|
#include "../widgets/CComponent.h"
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
#include "../windows/InfoWindows.h"
|
|
||||||
|
|
||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
if(!texts.empty())
|
if(!texts.empty())
|
||||||
owner->myInt->showInfoDialog(texts.front());
|
owner->myInt->showInfoDialog(texts.front());
|
||||||
else
|
else
|
||||||
owner->myInt->showInfoDialog("Unknown problem with this spell, no more information available.");
|
owner->myInt->showInfoDialog(CGI->generaltexth->localizedTexts["adventureMap"]["spellUnknownProblem"].String());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //adventure spell
|
else //adventure spell
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CWindowObject.h"
|
#include "CWindowObject.h"
|
||||||
|
|
||||||
|
#include "CAdvmapInterface.h"
|
||||||
|
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
|
|
||||||
#include "../gui/SDL_Pixels.h"
|
#include "../gui/SDL_Pixels.h"
|
||||||
@ -26,7 +28,6 @@
|
|||||||
#include "../CPlayerInterface.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CMusicHandler.h"
|
#include "../CMusicHandler.h"
|
||||||
#include "../windows/CAdvmapInterface.h"
|
|
||||||
|
|
||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "QuickRecruitmentWindow.h"
|
#include "QuickRecruitmentWindow.h"
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../../lib/CCreatureHandler.h"
|
#include "../../lib/CCreatureHandler.h"
|
||||||
|
#include "CCreatureWindow.h"
|
||||||
|
|
||||||
void CreaturePurchaseCard::initButtons()
|
void CreaturePurchaseCard::initButtons()
|
||||||
{
|
{
|
||||||
@ -46,6 +47,7 @@ void CreaturePurchaseCard::switchCreatureLevel()
|
|||||||
auto index = vstd::find_pos(upgradesID, creatureOnTheCard->idNumber);
|
auto index = vstd::find_pos(upgradesID, creatureOnTheCard->idNumber);
|
||||||
auto nextCreatureId = vstd::circularAt(upgradesID, ++index);
|
auto nextCreatureId = vstd::circularAt(upgradesID, ++index);
|
||||||
creatureOnTheCard = nextCreatureId.toCreature();
|
creatureOnTheCard = nextCreatureId.toCreature();
|
||||||
|
creatureClickArea = std::make_shared<CCreatureClickArea>(Point(pos.x + CCreatureClickArea::CREATURE_X_POS, pos.y + CCreatureClickArea::CREATURE_Y_POS), picture, creatureOnTheCard);
|
||||||
picture = std::make_shared<CCreaturePic>(parent->pos.x, parent->pos.y, creatureOnTheCard);
|
picture = std::make_shared<CCreaturePic>(parent->pos.x, parent->pos.y, creatureOnTheCard);
|
||||||
parent->updateAllSliders();
|
parent->updateAllSliders();
|
||||||
cost->set(creatureOnTheCard->cost * slider->getValue());
|
cost->set(creatureOnTheCard->cost * slider->getValue());
|
||||||
@ -54,14 +56,14 @@ void CreaturePurchaseCard::switchCreatureLevel()
|
|||||||
void CreaturePurchaseCard::initAmountInfo()
|
void CreaturePurchaseCard::initAmountInfo()
|
||||||
{
|
{
|
||||||
availableAmount = std::make_shared<CLabel>(pos.x + 25, pos.y + 146, FONT_SMALL, CENTER, Colors::YELLOW);
|
availableAmount = std::make_shared<CLabel>(pos.x + 25, pos.y + 146, FONT_SMALL, CENTER, Colors::YELLOW);
|
||||||
purhaseAmount = std::make_shared<CLabel>(pos.x + 76, pos.y + 146, FONT_SMALL, CENTER, Colors::WHITE);
|
purchaseAmount = std::make_shared<CLabel>(pos.x + 76, pos.y + 146, FONT_SMALL, CENTER, Colors::WHITE);
|
||||||
updateAmountInfo(0);
|
updateAmountInfo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreaturePurchaseCard::updateAmountInfo(int value)
|
void CreaturePurchaseCard::updateAmountInfo(int value)
|
||||||
{
|
{
|
||||||
availableAmount->setText(boost::lexical_cast<std::string>(maxAmount-value));
|
availableAmount->setText(boost::lexical_cast<std::string>(maxAmount-value));
|
||||||
purhaseAmount->setText(boost::lexical_cast<std::string>(value));
|
purchaseAmount->setText(boost::lexical_cast<std::string>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreaturePurchaseCard::initSlider()
|
void CreaturePurchaseCard::initSlider()
|
||||||
@ -96,8 +98,27 @@ void CreaturePurchaseCard::initView()
|
|||||||
{
|
{
|
||||||
picture = std::make_shared<CCreaturePic>(pos.x, pos.y, creatureOnTheCard);
|
picture = std::make_shared<CCreaturePic>(pos.x, pos.y, creatureOnTheCard);
|
||||||
background = std::make_shared<CPicture>("QuickRecruitmentWindow/CreaturePurchaseCard.png", pos.x-4, pos.y-50);
|
background = std::make_shared<CPicture>("QuickRecruitmentWindow/CreaturePurchaseCard.png", pos.x-4, pos.y-50);
|
||||||
|
initButtons();
|
||||||
|
|
||||||
|
creatureClickArea = std::make_shared<CCreatureClickArea>(Point(pos.x + CCreatureClickArea::CREATURE_X_POS, pos.y + CCreatureClickArea::CREATURE_Y_POS), picture, creatureOnTheCard);
|
||||||
|
|
||||||
initAmountInfo();
|
initAmountInfo();
|
||||||
initSlider();
|
initSlider();
|
||||||
initButtons();
|
|
||||||
initCostBox();
|
initCostBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreaturePurchaseCard::CCreatureClickArea::CCreatureClickArea(const Point & position, const std::shared_ptr<CCreaturePic> creaturePic, const CCreature * creatureOnTheCard)
|
||||||
|
: CIntObject(RCLICK),
|
||||||
|
creatureOnTheCard(creatureOnTheCard)
|
||||||
|
{
|
||||||
|
pos.x = position.x;
|
||||||
|
pos.y = position.y;
|
||||||
|
pos.w = CREATURE_WIDTH;
|
||||||
|
pos.h = CREATURE_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreaturePurchaseCard::CCreatureClickArea::clickRight(tribool down, bool previousState)
|
||||||
|
{
|
||||||
|
if (down)
|
||||||
|
GH.pushIntT<CStackWindow>(creatureOnTheCard, true);
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ public:
|
|||||||
QuickRecruitmentWindow * parent;
|
QuickRecruitmentWindow * parent;
|
||||||
int maxAmount;
|
int maxAmount;
|
||||||
void sliderMoved(int to);
|
void sliderMoved(int to);
|
||||||
|
|
||||||
CreaturePurchaseCard(const std::vector<CreatureID> & creaturesID, Point position, int creaturesMaxAmount, QuickRecruitmentWindow * parents);
|
CreaturePurchaseCard(const std::vector<CreatureID> & creaturesID, Point position, int creaturesMaxAmount, QuickRecruitmentWindow * parents);
|
||||||
private:
|
private:
|
||||||
void initView();
|
void initView();
|
||||||
@ -42,10 +43,28 @@ private:
|
|||||||
|
|
||||||
void initCostBox();
|
void initCostBox();
|
||||||
|
|
||||||
|
// This just wraps a clickeable area. There's a weird layout scheme in the file and
|
||||||
|
// it's easier to just add a separate invisble box on top
|
||||||
|
class CCreatureClickArea : public CIntObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CCreatureClickArea(const Point & pos, const std::shared_ptr<CCreaturePic> creaturePic, const CCreature * creatureOnTheCard);
|
||||||
|
void clickRight(tribool down, bool previousState) override;
|
||||||
|
const CCreature * creatureOnTheCard;
|
||||||
|
|
||||||
|
// These are obtained by guessing and checking. I'm not sure how the other numbers
|
||||||
|
// used to set positions were obtained; commit messages don't document it
|
||||||
|
static constexpr int CREATURE_WIDTH = 110;
|
||||||
|
static constexpr int CREATURE_HEIGHT = 132;
|
||||||
|
static constexpr int CREATURE_X_POS = 15;
|
||||||
|
static constexpr int CREATURE_Y_POS = 44;
|
||||||
|
};
|
||||||
|
|
||||||
std::shared_ptr<CButton> maxButton, minButton, creatureSwitcher;
|
std::shared_ptr<CButton> maxButton, minButton, creatureSwitcher;
|
||||||
std::shared_ptr<CLabel> availableAmount, purhaseAmount;
|
std::shared_ptr<CLabel> availableAmount, purchaseAmount;
|
||||||
std::shared_ptr<CCreaturePic> picture;
|
std::shared_ptr<CCreaturePic> picture;
|
||||||
std::shared_ptr<CreatureCostBox> cost;
|
std::shared_ptr<CreatureCostBox> cost;
|
||||||
std::vector<CreatureID> upgradesID;
|
std::vector<CreatureID> upgradesID;
|
||||||
std::shared_ptr<CPicture> background;
|
std::shared_ptr<CPicture> background;
|
||||||
|
std::shared_ptr<CCreatureClickArea> creatureClickArea;
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "CCreatureWindow.h"
|
#include "CCreatureWindow.h"
|
||||||
#include "CHeroWindow.h"
|
#include "CHeroWindow.h"
|
||||||
#include "CreatureCostBox.h"
|
#include "CreatureCostBox.h"
|
||||||
|
#include "InfoWindows.h"
|
||||||
|
|
||||||
#include "../CBitmapHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
@ -36,7 +37,6 @@
|
|||||||
|
|
||||||
#include "../widgets/CComponent.h"
|
#include "../widgets/CComponent.h"
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
#include "../windows/InfoWindows.h"
|
|
||||||
|
|
||||||
#include "../lobby/CSavingScreen.h"
|
#include "../lobby/CSavingScreen.h"
|
||||||
|
|
||||||
@ -1286,7 +1286,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
|||||||
int skill = hero->secSkills[g].first,
|
int skill = hero->secSkills[g].first,
|
||||||
level = hero->secSkills[g].second; // <1, 3>
|
level = hero->secSkills[g].second; // <1, 3>
|
||||||
secSkillAreas[b].push_back(std::make_shared<LRClickableAreaWTextComp>());
|
secSkillAreas[b].push_back(std::make_shared<LRClickableAreaWTextComp>());
|
||||||
secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + qeLayout ? 83 : 88);
|
secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + (qeLayout ? 83 : 88));
|
||||||
secSkillAreas[b][g]->baseType = 1;
|
secSkillAreas[b][g]->baseType = 1;
|
||||||
|
|
||||||
secSkillAreas[b][g]->type = skill;
|
secSkillAreas[b][g]->type = skill;
|
||||||
@ -1301,12 +1301,12 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
|||||||
heroAreas[b] = std::make_shared<CHeroArea>(257 + 228*b, 13, hero);
|
heroAreas[b] = std::make_shared<CHeroArea>(257 + 228*b, 13, hero);
|
||||||
|
|
||||||
specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
|
specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
|
||||||
specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + qeLayout ? 41 : 45);
|
specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + (qeLayout ? 41 : 45));
|
||||||
specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
|
specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
|
||||||
specialtyAreas[b]->text = hero->type->specDescr;
|
specialtyAreas[b]->text = hero->type->specDescr;
|
||||||
|
|
||||||
experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
|
experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
|
||||||
experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + qeLayout ? 41 : 45);
|
experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + (qeLayout ? 41 : 45));
|
||||||
experienceAreas[b]->hoverText = CGI->generaltexth->heroscrn[9];
|
experienceAreas[b]->hoverText = CGI->generaltexth->heroscrn[9];
|
||||||
experienceAreas[b]->text = CGI->generaltexth->allTexts[2];
|
experienceAreas[b]->text = CGI->generaltexth->allTexts[2];
|
||||||
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->level));
|
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->level));
|
||||||
@ -1314,7 +1314,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
|||||||
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->exp));
|
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->exp));
|
||||||
|
|
||||||
spellPointsAreas[b] = std::make_shared<LRClickableAreaWText>();
|
spellPointsAreas[b] = std::make_shared<LRClickableAreaWText>();
|
||||||
spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + qeLayout ? 41 : 45);
|
spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + (qeLayout ? 41 : 45));
|
||||||
spellPointsAreas[b]->hoverText = CGI->generaltexth->heroscrn[22];
|
spellPointsAreas[b]->hoverText = CGI->generaltexth->heroscrn[22];
|
||||||
spellPointsAreas[b]->text = CGI->generaltexth->allTexts[205];
|
spellPointsAreas[b]->text = CGI->generaltexth->allTexts[205];
|
||||||
boost::algorithm::replace_first(spellPointsAreas[b]->text, "%s", hero->name);
|
boost::algorithm::replace_first(spellPointsAreas[b]->text, "%s", hero->name);
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "CWindowObject.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/ResourceSet.h"
|
#include "../lib/ResourceSet.h"
|
||||||
#include "../lib/CConfigHandler.h"
|
#include "../lib/CConfigHandler.h"
|
||||||
#include "../widgets/CArtifactHolder.h"
|
#include "../widgets/CArtifactHolder.h"
|
||||||
#include "../widgets/CGarrisonInt.h"
|
#include "../widgets/CGarrisonInt.h"
|
||||||
#include "../widgets/Images.h"
|
#include "../widgets/Images.h"
|
||||||
#include "../windows/CWindowObject.h"
|
|
||||||
|
|
||||||
class CGDwelling;
|
class CGDwelling;
|
||||||
class CreatureCostBox;
|
class CreatureCostBox;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "InfoWindows.h"
|
#include "InfoWindows.h"
|
||||||
|
|
||||||
|
#include "CAdvmapInterface.h"
|
||||||
|
|
||||||
#include "../CBitmapHandler.h"
|
#include "../CBitmapHandler.h"
|
||||||
#include "../Graphics.h"
|
#include "../Graphics.h"
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
@ -17,7 +19,6 @@
|
|||||||
#include "../CMessage.h"
|
#include "../CMessage.h"
|
||||||
#include "../CMusicHandler.h"
|
#include "../CMusicHandler.h"
|
||||||
|
|
||||||
#include "../windows/CAdvmapInterface.h"
|
|
||||||
#include "../widgets/CComponent.h"
|
#include "../widgets/CComponent.h"
|
||||||
#include "../widgets/MiscWidgets.h"
|
#include "../widgets/MiscWidgets.h"
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ void QuickRecruitmentWindow::setCancelButton()
|
|||||||
|
|
||||||
void QuickRecruitmentWindow::setBuyButton()
|
void QuickRecruitmentWindow::setBuyButton()
|
||||||
{
|
{
|
||||||
buyButton = std::make_shared<CButton>(Point((pos.w/2)-32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purhaseUnits(); }, SDLK_RETURN);
|
buyButton = std::make_shared<CButton>(Point((pos.w / 2) - 32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purchaseUnits(); }, SDLK_RETURN);
|
||||||
cancelButton->assignedKeys.insert(SDLK_ESCAPE);
|
cancelButton->assignedKeys.insert(SDLK_ESCAPE);
|
||||||
buyButton->setImageOrder(0, 1, 2, 3);
|
buyButton->setImageOrder(0, 1, 2, 3);
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ void QuickRecruitmentWindow::setMaxButton()
|
|||||||
maxButton->setImageOrder(0, 1, 2, 3);
|
maxButton->setImageOrder(0, 1, 2, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickRecruitmentWindow::setCreaturePurhaseCards()
|
void QuickRecruitmentWindow::setCreaturePurchaseCards()
|
||||||
{
|
{
|
||||||
int availableAmount = getAvailableCreatures();
|
int availableAmount = getAvailableCreatures();
|
||||||
Point position = Point((pos.w - 100*availableAmount - 8*(availableAmount-1))/2,64);
|
Point position = Point((pos.w - 100*availableAmount - 8*(availableAmount-1))/2,64);
|
||||||
@ -99,7 +99,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePur
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void QuickRecruitmentWindow::purhaseUnits()
|
void QuickRecruitmentWindow::purchaseUnits()
|
||||||
{
|
{
|
||||||
for(auto selected : cards)
|
for(auto selected : cards)
|
||||||
{
|
{
|
||||||
@ -154,6 +154,6 @@ QuickRecruitmentWindow::QuickRecruitmentWindow(const CGTownInstance * townd, Rec
|
|||||||
|
|
||||||
initWindow(startupPosition);
|
initWindow(startupPosition);
|
||||||
setButtons();
|
setButtons();
|
||||||
setCreaturePurhaseCards();
|
setCreaturePurchaseCards();
|
||||||
maxAllCards(cards);
|
maxAllCards(cards);
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,11 @@ private:
|
|||||||
void setBuyButton();
|
void setBuyButton();
|
||||||
void setMaxButton();
|
void setMaxButton();
|
||||||
|
|
||||||
void setCreaturePurhaseCards();
|
void setCreaturePurchaseCards();
|
||||||
|
|
||||||
void maxAllCards(std::vector<std::shared_ptr<CreaturePurchaseCard>> cards);
|
void maxAllCards(std::vector<std::shared_ptr<CreaturePurchaseCard>> cards);
|
||||||
void maxAllSlidersAmount(std::vector<std::shared_ptr<CreaturePurchaseCard>> cards);
|
void maxAllSlidersAmount(std::vector<std::shared_ptr<CreaturePurchaseCard>> cards);
|
||||||
void purhaseUnits();
|
void purchaseUnits();
|
||||||
|
|
||||||
const CGTownInstance * town;
|
const CGTownInstance * town;
|
||||||
std::shared_ptr<CButton> maxButton, buyButton, cancelButton;
|
std::shared_ptr<CButton> maxButton, buyButton, cancelButton;
|
||||||
|
@ -21,8 +21,19 @@
|
|||||||
"Impossible"
|
"Impossible"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"confirmRestartGame" : "Are you sure you want to restart game?",
|
||||||
|
"noTownWithMarket": "No available marketplace!",
|
||||||
|
"noTownWithTavern": "No available town with tavern!",
|
||||||
|
"spellUnknownProblem": "Unknown problem with this spell, no more information available.",
|
||||||
"playerAttacked" : "Player has been attacked: %s"
|
"playerAttacked" : "Player has been attacked: %s"
|
||||||
},
|
},
|
||||||
|
"server" :
|
||||||
|
{
|
||||||
|
"errors" :
|
||||||
|
{
|
||||||
|
"existingProcess" : "Another vcmiserver process is running, please terminate it first"
|
||||||
|
}
|
||||||
|
},
|
||||||
"systemOptions" :
|
"systemOptions" :
|
||||||
{
|
{
|
||||||
"fullscreenButton" :
|
"fullscreenButton" :
|
||||||
@ -44,6 +55,7 @@
|
|||||||
"townHall" :
|
"townHall" :
|
||||||
{
|
{
|
||||||
"missingBase" : "Base building %s must be built first",
|
"missingBase" : "Base building %s must be built first",
|
||||||
|
"noCreaturesToRecruit" : "There are no creatures to recruit!",
|
||||||
"greetingManaVortex" : "As you near the %s your body is filled with new energy. You have doubled your normal spell points.",
|
"greetingManaVortex" : "As you near the %s your body is filled with new energy. You have doubled your normal spell points.",
|
||||||
"greetingKnowledge" : "You study the glyphs on the %s and gain insight into the workings of various magics (+1 Knowledge).",
|
"greetingKnowledge" : "You study the glyphs on the %s and gain insight into the workings of various magics (+1 Knowledge).",
|
||||||
"greetingSpellPower" : "The %s teaches you new ways to focus your magical powers (+1 Power).",
|
"greetingSpellPower" : "The %s teaches you new ways to focus your magical powers (+1 Power).",
|
||||||
|
@ -27,6 +27,8 @@ struct CatapultAttack;
|
|||||||
class DLL_LINKAGE ServerCallback
|
class DLL_LINKAGE ServerCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ServerCallback() = default;
|
||||||
|
|
||||||
virtual void complain(const std::string & problem) = 0;
|
virtual void complain(const std::string & problem) = 0;
|
||||||
virtual bool describeChanges() const = 0;
|
virtual bool describeChanges() const = 0;
|
||||||
|
|
||||||
|
@ -32,10 +32,12 @@ namespace spells
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class Service;
|
class Service;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class DLL_LINKAGE Services
|
class DLL_LINKAGE Services
|
||||||
{
|
{
|
||||||
@ -47,7 +49,9 @@ public:
|
|||||||
virtual const FactionService * factions() const = 0;
|
virtual const FactionService * factions() const = 0;
|
||||||
virtual const HeroClassService * heroClasses() const = 0;
|
virtual const HeroClassService * heroClasses() const = 0;
|
||||||
virtual const HeroTypeService * heroTypes() const = 0;
|
virtual const HeroTypeService * heroTypes() const = 0;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
virtual const scripting::Service * scripts() const = 0;
|
virtual const scripting::Service * scripts() const = 0;
|
||||||
|
#endif
|
||||||
virtual const spells::Service * spells() const = 0;
|
virtual const spells::Service * spells() const = 0;
|
||||||
virtual const SkillService * skills() const = 0;
|
virtual const SkillService * skills() const = 0;
|
||||||
virtual const BattleFieldService * battlefields() const = 0;
|
virtual const BattleFieldService * battlefields() const = 0;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
#include <vcmi/Environment.h>
|
#include <vcmi/Environment.h>
|
||||||
|
|
||||||
class Services;
|
class Services;
|
||||||
@ -78,3 +79,4 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -12,29 +12,53 @@
|
|||||||
|
|
||||||
#include "../../lib/JsonNode.h"
|
#include "../../lib/JsonNode.h"
|
||||||
#include "../../lib/filesystem/CFileInputStream.h"
|
#include "../../lib/filesystem/CFileInputStream.h"
|
||||||
|
#include "../../lib/GameConstants.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool isCompatible(const QString & verMin, const QString & verMax)
|
||||||
|
{
|
||||||
|
const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch
|
||||||
|
QVersionNumber vcmiVersion(GameConstants::VCMI_VERSION_MAJOR,
|
||||||
|
GameConstants::VCMI_VERSION_MINOR,
|
||||||
|
GameConstants::VCMI_VERSION_PATCH);
|
||||||
|
|
||||||
|
auto versionMin = QVersionNumber::fromString(verMin);
|
||||||
|
auto versionMax = QVersionNumber::fromString(verMax);
|
||||||
|
|
||||||
|
auto buildVersion = [maxSections](QVersionNumber & ver)
|
||||||
|
{
|
||||||
|
if(ver.segmentCount() < maxSections)
|
||||||
|
{
|
||||||
|
auto segments = ver.segments();
|
||||||
|
for(int i = segments.size() - 1; i < maxSections; ++i)
|
||||||
|
segments.append(0);
|
||||||
|
ver = QVersionNumber(segments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!versionMin.isNull())
|
||||||
|
{
|
||||||
|
buildVersion(versionMin);
|
||||||
|
if(vcmiVersion < versionMin)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!versionMax.isNull())
|
||||||
|
{
|
||||||
|
buildVersion(versionMax);
|
||||||
|
if(vcmiVersion > versionMax)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CModEntry::compareVersions(QString lesser, QString greater)
|
bool CModEntry::compareVersions(QString lesser, QString greater)
|
||||||
{
|
{
|
||||||
static const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch
|
auto versionLesser = QVersionNumber::fromString(lesser);
|
||||||
|
auto versionGreater = QVersionNumber::fromString(greater);
|
||||||
QStringList lesserList = lesser.split(".");
|
return versionLesser < versionGreater;
|
||||||
QStringList greaterList = greater.split(".");
|
|
||||||
|
|
||||||
assert(lesserList.size() <= maxSections);
|
|
||||||
assert(greaterList.size() <= maxSections);
|
|
||||||
|
|
||||||
for(int i = 0; i < maxSections; i++)
|
|
||||||
{
|
|
||||||
if(greaterList.size() <= i) // 1.1.1 > 1.1
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(lesserList.size() <= i) // 1.1 < 1.1.1
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(lesserList[i].toInt() != greaterList[i].toInt())
|
|
||||||
return lesserList[i].toInt() < greaterList[i].toInt(); // 1.1 < 1.2
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CModEntry::sizeToString(double size)
|
QString CModEntry::sizeToString(double size)
|
||||||
@ -92,6 +116,15 @@ bool CModEntry::isUpdateable() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CModEntry::isCompatible() const
|
||||||
|
{
|
||||||
|
if(!isInstalled())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto compatibility = localData["compatibility"].toMap();
|
||||||
|
return ::isCompatible(compatibility["min"].toString(), compatibility["max"].toString());
|
||||||
|
}
|
||||||
|
|
||||||
bool CModEntry::isEssential() const
|
bool CModEntry::isEssential() const
|
||||||
{
|
{
|
||||||
return getValue("storedLocaly").toBool();
|
return getValue("storedLocaly").toBool();
|
||||||
@ -102,6 +135,11 @@ bool CModEntry::isInstalled() const
|
|||||||
return !localData.isEmpty();
|
return !localData.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CModEntry::isValid() const
|
||||||
|
{
|
||||||
|
return !localData.isEmpty() || !repository.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
int CModEntry::getModStatus() const
|
int CModEntry::getModStatus() const
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
@ -193,7 +231,11 @@ static QVariant getValue(QVariant input, QString path)
|
|||||||
QString remainder = "/" + path.section('/', 2, -1);
|
QString remainder = "/" + path.section('/', 2, -1);
|
||||||
|
|
||||||
entryName.remove(0, 1);
|
entryName.remove(0, 1);
|
||||||
return getValue(input.toMap().value(entryName), remainder);
|
QMap<QString, QString> keyNormalize;
|
||||||
|
for(auto & key : input.toMap().keys())
|
||||||
|
keyNormalize[key.toLower()] = key;
|
||||||
|
|
||||||
|
return getValue(input.toMap().value(keyNormalize[entryName]), remainder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -203,6 +245,7 @@ static QVariant getValue(QVariant input, QString path)
|
|||||||
|
|
||||||
CModEntry CModList::getMod(QString modname) const
|
CModEntry CModList::getMod(QString modname) const
|
||||||
{
|
{
|
||||||
|
modname = modname.toLower();
|
||||||
QVariantMap repo;
|
QVariantMap repo;
|
||||||
QVariantMap local = localModList[modname].toMap();
|
QVariantMap local = localModList[modname].toMap();
|
||||||
QVariantMap settings;
|
QVariantMap settings;
|
||||||
@ -241,19 +284,28 @@ CModEntry CModList::getMod(QString modname) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(settings.value("active").toBool())
|
||||||
|
{
|
||||||
|
auto compatibility = local.value("compatibility").toMap();
|
||||||
|
if(compatibility["min"].isValid() || compatibility["max"].isValid())
|
||||||
|
if(!isCompatible(compatibility["min"].toString(), compatibility["max"].toString()))
|
||||||
|
settings["active"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for(auto entry : repositories)
|
for(auto entry : repositories)
|
||||||
{
|
{
|
||||||
QVariant repoVal = getValue(entry, path);
|
QVariant repoVal = getValue(entry, path);
|
||||||
if(repoVal.isValid())
|
if(repoVal.isValid())
|
||||||
{
|
{
|
||||||
if(repo.empty())
|
auto repoValMap = repoVal.toMap();
|
||||||
|
auto compatibility = repoValMap["compatibility"].toMap();
|
||||||
|
if(isCompatible(compatibility["min"].toString(), compatibility["max"].toString()))
|
||||||
{
|
{
|
||||||
repo = repoVal.toMap();
|
if(repo.empty() || CModEntry::compareVersions(repo["version"].toString(), repoValMap["version"].toString()))
|
||||||
|
{
|
||||||
|
repo = repoValMap;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if(CModEntry::compareVersions(repo["version"].toString(), repoVal.toMap()["version"].toString()))
|
|
||||||
repo = repoVal.toMap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,12 +349,12 @@ QVector<QString> CModList::getModList() const
|
|||||||
{
|
{
|
||||||
for(auto it = repo.begin(); it != repo.end(); it++)
|
for(auto it = repo.begin(); it != repo.end(); it++)
|
||||||
{
|
{
|
||||||
knownMods.insert(it.key());
|
knownMods.insert(it.key().toLower());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto it = localModList.begin(); it != localModList.end(); it++)
|
for(auto it = localModList.begin(); it != localModList.end(); it++)
|
||||||
{
|
{
|
||||||
knownMods.insert(it.key());
|
knownMods.insert(it.key().toLower());
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto entry : knownMods)
|
for(auto entry : knownMods)
|
||||||
|
@ -51,6 +51,10 @@ public:
|
|||||||
bool isInstalled() const;
|
bool isInstalled() const;
|
||||||
// vcmi essential files
|
// vcmi essential files
|
||||||
bool isEssential() const;
|
bool isEssential() const;
|
||||||
|
// checks if verison is compatible with vcmi
|
||||||
|
bool isCompatible() const;
|
||||||
|
// returns if has any data
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
// see ModStatus enum
|
// see ModStatus enum
|
||||||
int getModStatus() const;
|
int getModStatus() const;
|
||||||
|
@ -245,6 +245,7 @@ bool CModFilterModel::filterMatchesThis(const QModelIndex & source) const
|
|||||||
{
|
{
|
||||||
CModEntry mod = base->getMod(source.data(ModRoles::ModNameRole).toString());
|
CModEntry mod = base->getMod(source.data(ModRoles::ModNameRole).toString());
|
||||||
return (mod.getModStatus() & filterMask) == filteredType &&
|
return (mod.getModStatus() & filterMask) == filteredType &&
|
||||||
|
mod.isValid() &&
|
||||||
QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
|
QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="html">
|
<property name="html">
|
||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
p, li { white-space: pre-wrap; }
|
||||||
</style></head><body style=" font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;">
|
</style></head><body style=" font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><br /></p></body></html></string>
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><br /></p></body></html></string>
|
||||||
@ -385,6 +385,31 @@ p, li { white-space: pre-wrap; }
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="uninstallButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>51</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>140</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Uninstall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="enableButton">
|
<widget class="QPushButton" name="enableButton">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -460,31 +485,6 @@ p, li { white-space: pre-wrap; }
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="uninstallButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>51</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>140</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Uninstall</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="installButton">
|
<widget class="QPushButton" name="installButton">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -169,6 +169,10 @@ bool CModManager::canEnableMod(QString modname)
|
|||||||
if(!mod.isInstalled())
|
if(!mod.isInstalled())
|
||||||
return addError(modname, "Mod must be installed first");
|
return addError(modname, "Mod must be installed first");
|
||||||
|
|
||||||
|
//check for compatibility
|
||||||
|
if(!mod.isCompatible())
|
||||||
|
return addError(modname, "Mod is not compatible, please update VCMI and checkout latest mod revisions");
|
||||||
|
|
||||||
for(auto modEntry : mod.getValue("depends").toStringList())
|
for(auto modEntry : mod.getValue("depends").toStringList())
|
||||||
{
|
{
|
||||||
if(!modList->hasMod(modEntry)) // required mod is not available
|
if(!modList->hasMod(modEntry)) // required mod is not available
|
||||||
|
@ -126,10 +126,12 @@ std::shared_ptr<CBattleGameInterface> CDynLibHandler::getNewBattleAI(std::string
|
|||||||
return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
|
return createAnyAI<CBattleGameInterface>(dllname, "GetNewBattleAI");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
std::shared_ptr<scripting::Module> CDynLibHandler::getNewScriptingModule(const boost::filesystem::path & dllname)
|
std::shared_ptr<scripting::Module> CDynLibHandler::getNewScriptingModule(const boost::filesystem::path & dllname)
|
||||||
{
|
{
|
||||||
return createAny<scripting::Module>(dllname, "GetNewModule");
|
return createAny<scripting::Module>(dllname, "GetNewModule");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BattleAction CGlobalAI::activeStack(const CStack * stack)
|
BattleAction CGlobalAI::activeStack(const CStack * stack)
|
||||||
{
|
{
|
||||||
|
@ -56,10 +56,14 @@ class CSaveFile;
|
|||||||
class BinaryDeserializer;
|
class BinaryDeserializer;
|
||||||
class BinarySerializer;
|
class BinarySerializer;
|
||||||
struct ArtifactLocation;
|
struct ArtifactLocation;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class Module;
|
class Module;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class DLL_LINKAGE CBattleGameInterface : public IBattleEventsReceiver
|
class DLL_LINKAGE CBattleGameInterface : public IBattleEventsReceiver
|
||||||
{
|
{
|
||||||
@ -110,7 +114,9 @@ class DLL_LINKAGE CDynLibHandler
|
|||||||
public:
|
public:
|
||||||
static std::shared_ptr<CGlobalAI> getNewAI(std::string dllname);
|
static std::shared_ptr<CGlobalAI> getNewAI(std::string dllname);
|
||||||
static std::shared_ptr<CBattleGameInterface> getNewBattleAI(std::string dllname);
|
static std::shared_ptr<CBattleGameInterface> getNewBattleAI(std::string dllname);
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
static std::shared_ptr<scripting::Module> getNewScriptingModule(const boost::filesystem::path & dllname);
|
static std::shared_ptr<scripting::Module> getNewScriptingModule(const boost::filesystem::path & dllname);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate)
|
class DLL_LINKAGE CGlobalAI : public CGameInterface // AI class (to derivate)
|
||||||
|
@ -434,7 +434,9 @@ void CContentHandler::init()
|
|||||||
handlers.insert(std::make_pair("spells", ContentTypeHandler(VLC->spellh, "spell")));
|
handlers.insert(std::make_pair("spells", ContentTypeHandler(VLC->spellh, "spell")));
|
||||||
handlers.insert(std::make_pair("skills", ContentTypeHandler(VLC->skillh, "skill")));
|
handlers.insert(std::make_pair("skills", ContentTypeHandler(VLC->skillh, "skill")));
|
||||||
handlers.insert(std::make_pair("templates", ContentTypeHandler((IHandlerBase *)VLC->tplh, "template")));
|
handlers.insert(std::make_pair("templates", ContentTypeHandler((IHandlerBase *)VLC->tplh, "template")));
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
handlers.insert(std::make_pair("scripts", ContentTypeHandler(VLC->scriptHandler, "script")));
|
handlers.insert(std::make_pair("scripts", ContentTypeHandler(VLC->scriptHandler, "script")));
|
||||||
|
#endif
|
||||||
handlers.insert(std::make_pair("battlefields", ContentTypeHandler(VLC->battlefieldsHandler, "battlefield")));
|
handlers.insert(std::make_pair("battlefields", ContentTypeHandler(VLC->battlefieldsHandler, "battlefield")));
|
||||||
handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler, "obstacle")));
|
handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler, "obstacle")));
|
||||||
//TODO: any other types of moddables?
|
//TODO: any other types of moddables?
|
||||||
@ -532,6 +534,51 @@ JsonNode addMeta(JsonNode config, std::string meta)
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CModInfo::Version CModInfo::Version::GameVersion()
|
||||||
|
{
|
||||||
|
return Version(GameConstants::VCMI_VERSION_MAJOR, GameConstants::VCMI_VERSION_MINOR, GameConstants::VCMI_VERSION_PATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
CModInfo::Version CModInfo::Version::fromString(std::string from)
|
||||||
|
{
|
||||||
|
int major = 0, minor = 0, patch = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto pointPos = from.find('.');
|
||||||
|
major = std::stoi(from.substr(0, pointPos));
|
||||||
|
if(pointPos != std::string::npos)
|
||||||
|
{
|
||||||
|
from = from.substr(pointPos + 1);
|
||||||
|
pointPos = from.find('.');
|
||||||
|
minor = std::stoi(from.substr(0, pointPos));
|
||||||
|
if(pointPos != std::string::npos)
|
||||||
|
patch = std::stoi(from.substr(pointPos + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const std::invalid_argument & e)
|
||||||
|
{
|
||||||
|
return Version();
|
||||||
|
}
|
||||||
|
return Version(major, minor, patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CModInfo::Version::toString() const
|
||||||
|
{
|
||||||
|
return std::to_string(major) + '.' + std::to_string(minor) + '.' + std::to_string(patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CModInfo::Version::compatible(const Version & other, bool checkMinor, bool checkPatch) const
|
||||||
|
{
|
||||||
|
return (major == other.major &&
|
||||||
|
(!checkMinor || minor >= other.minor) &&
|
||||||
|
(!checkPatch || minor > other.minor || (minor == other.minor && patch >= other.patch)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CModInfo::Version::isNull() const
|
||||||
|
{
|
||||||
|
return major == 0 && minor == 0 && patch == 0;
|
||||||
|
}
|
||||||
|
|
||||||
CModInfo::CModInfo():
|
CModInfo::CModInfo():
|
||||||
checksum(0),
|
checksum(0),
|
||||||
enabled(false),
|
enabled(false),
|
||||||
@ -551,6 +598,12 @@ CModInfo::CModInfo(std::string identifier,const JsonNode & local, const JsonNode
|
|||||||
validation(PENDING),
|
validation(PENDING),
|
||||||
config(addMeta(config, identifier))
|
config(addMeta(config, identifier))
|
||||||
{
|
{
|
||||||
|
version = Version::fromString(config["version"].String());
|
||||||
|
if(!config["compatibility"].isNull())
|
||||||
|
{
|
||||||
|
vcmiCompatibleMin = Version::fromString(config["compatibility"]["min"].String());
|
||||||
|
vcmiCompatibleMax = Version::fromString(config["compatibility"]["max"].String());
|
||||||
|
}
|
||||||
loadLocalData(local);
|
loadLocalData(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,6 +655,14 @@ void CModInfo::loadLocalData(const JsonNode & data)
|
|||||||
checksum = strtol(data["checksum"].String().c_str(), nullptr, 16);
|
checksum = strtol(data["checksum"].String().c_str(), nullptr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//check compatibility
|
||||||
|
bool wasEnabled = enabled;
|
||||||
|
enabled = enabled && (vcmiCompatibleMin.isNull() || Version::GameVersion().compatible(vcmiCompatibleMin));
|
||||||
|
enabled = enabled && (vcmiCompatibleMax.isNull() || vcmiCompatibleMax.compatible(Version::GameVersion()));
|
||||||
|
|
||||||
|
if(wasEnabled && !enabled)
|
||||||
|
logGlobal->warn("Mod %s is incompatible with current version of VCMI and cannot be enabled", name);
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
validation = validated ? PASSED : PENDING;
|
validation = validated ? PASSED : PENDING;
|
||||||
else
|
else
|
||||||
@ -986,7 +1047,9 @@ void CModHandler::load()
|
|||||||
for(const TModID & modName : activeMods)
|
for(const TModID & modName : activeMods)
|
||||||
content->load(allMods[modName]);
|
content->load(allMods[modName]);
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
VLC->scriptHandler->performRegistration(VLC);//todo: this should be done before any other handlers load
|
VLC->scriptHandler->performRegistration(VLC);//todo: this should be done before any other handlers load
|
||||||
|
#endif
|
||||||
|
|
||||||
content->loadCustom();
|
content->loadCustom();
|
||||||
|
|
||||||
|
@ -178,6 +178,30 @@ public:
|
|||||||
PASSED
|
PASSED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Version
|
||||||
|
{
|
||||||
|
int major = 0;
|
||||||
|
int minor = 0;
|
||||||
|
int patch = 0;
|
||||||
|
|
||||||
|
Version() = default;
|
||||||
|
Version(int mj, int mi, int p): major(mj), minor(mi), patch(p) {}
|
||||||
|
|
||||||
|
static Version GameVersion();
|
||||||
|
static Version fromString(std::string from);
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
bool compatible(const Version & other, bool checkMinor = false, bool checkPatch = false) const;
|
||||||
|
bool isNull() const;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & major;
|
||||||
|
h & minor;
|
||||||
|
h & patch;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// identifier, identical to name of folder with mod
|
/// identifier, identical to name of folder with mod
|
||||||
std::string identifier;
|
std::string identifier;
|
||||||
|
|
||||||
@ -185,6 +209,13 @@ public:
|
|||||||
std::string name;
|
std::string name;
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
|
/// version of the mod
|
||||||
|
Version version;
|
||||||
|
|
||||||
|
/// vcmi versions compatible with the mod
|
||||||
|
|
||||||
|
Version vcmiCompatibleMin, vcmiCompatibleMax;
|
||||||
|
|
||||||
/// list of mods that should be loaded before this one
|
/// list of mods that should be loaded before this one
|
||||||
std::set <TModID> dependencies;
|
std::set <TModID> dependencies;
|
||||||
|
|
||||||
@ -210,18 +241,6 @@ public:
|
|||||||
static std::string getModDir(std::string name);
|
static std::string getModDir(std::string name);
|
||||||
static std::string getModFile(std::string name);
|
static std::string getModFile(std::string name);
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
|
||||||
{
|
|
||||||
h & identifier;
|
|
||||||
h & description;
|
|
||||||
h & name;
|
|
||||||
h & dependencies;
|
|
||||||
h & conflicts;
|
|
||||||
h & config;
|
|
||||||
h & checksum;
|
|
||||||
h & validation;
|
|
||||||
h & enabled;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
void loadLocalData(const JsonNode & data);
|
void loadLocalData(const JsonNode & data);
|
||||||
};
|
};
|
||||||
@ -257,6 +276,13 @@ class DLL_LINKAGE CModHandler
|
|||||||
void loadOneMod(std::string modName, std::string parent, const JsonNode & modSettings, bool enableMods);
|
void loadOneMod(std::string modName, std::string parent, const JsonNode & modSettings, bool enableMods);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
class Incompatibility: public std::logic_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Incompatibility(const std::string & w): std::logic_error(w)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
CIdentifierStorage identifiers;
|
CIdentifierStorage identifiers;
|
||||||
|
|
||||||
std::shared_ptr<CContentHandler> content; //(!)Do not serialize
|
std::shared_ptr<CContentHandler> content; //(!)Do not serialize
|
||||||
@ -336,8 +362,37 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & allMods;
|
if(h.saving)
|
||||||
|
{
|
||||||
h & activeMods;
|
h & activeMods;
|
||||||
|
for(const auto & m : activeMods)
|
||||||
|
|
||||||
|
h & allMods[m].version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loadMods();
|
||||||
|
std::vector<TModID> newActiveMods;
|
||||||
|
h & newActiveMods;
|
||||||
|
for(auto & m : newActiveMods)
|
||||||
|
{
|
||||||
|
if(!allMods.count(m))
|
||||||
|
throw Incompatibility(m + " unkown mod");
|
||||||
|
|
||||||
|
CModInfo::Version mver;
|
||||||
|
h & mver;
|
||||||
|
if(!allMods[m].version.isNull() && !mver.isNull() && !allMods[m].version.compatible(mver))
|
||||||
|
{
|
||||||
|
std::string err = allMods[m].name +
|
||||||
|
": version needed " + mver.toString() +
|
||||||
|
"but you have installed " + allMods[m].version.toString();
|
||||||
|
throw Incompatibility(err);
|
||||||
|
}
|
||||||
|
allMods[m].enabled = true;
|
||||||
|
}
|
||||||
|
std::swap(activeMods, newActiveMods);
|
||||||
|
}
|
||||||
|
|
||||||
h & settings;
|
h & settings;
|
||||||
h & modules;
|
h & modules;
|
||||||
h & identifiers;
|
h & identifiers;
|
||||||
|
@ -386,6 +386,9 @@ class DLL_LINKAGE INodeStorage
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using ELayer = EPathfindingLayer;
|
using ELayer = EPathfindingLayer;
|
||||||
|
|
||||||
|
virtual ~INodeStorage() = default;
|
||||||
|
|
||||||
virtual std::vector<CGPathNode *> getInitialNodes() = 0;
|
virtual std::vector<CGPathNode *> getInitialNodes() = 0;
|
||||||
|
|
||||||
virtual std::vector<CGPathNode *> calculateNeighbours(
|
virtual std::vector<CGPathNode *> calculateNeighbours(
|
||||||
@ -448,6 +451,7 @@ public:
|
|||||||
PathfinderConfig(
|
PathfinderConfig(
|
||||||
std::shared_ptr<INodeStorage> nodeStorage,
|
std::shared_ptr<INodeStorage> nodeStorage,
|
||||||
std::vector<std::shared_ptr<IPathfindingRule>> rules);
|
std::vector<std::shared_ptr<IPathfindingRule>> rules);
|
||||||
|
virtual ~PathfinderConfig() = default;
|
||||||
|
|
||||||
virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) = 0;
|
virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) = 0;
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "CScriptingModule.h"
|
#include "CScriptingModule.h"
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -30,3 +31,4 @@ Module::Module()
|
|||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
#include <vcmi/scripting/Service.h>
|
#include <vcmi/scripting/Service.h>
|
||||||
|
|
||||||
namespace spells
|
namespace spells
|
||||||
@ -45,3 +46,4 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -51,10 +51,18 @@ const TeamID TeamID::NO_TEAM = TeamID(255);
|
|||||||
|
|
||||||
namespace GameConstants
|
namespace GameConstants
|
||||||
{
|
{
|
||||||
|
const int VCMI_VERSION_MAJOR = 1;
|
||||||
|
const int VCMI_VERSION_MINOR = 1;
|
||||||
|
const int VCMI_VERSION_PATCH = 0;
|
||||||
|
|
||||||
|
const std::string VCMI_VERSION_STRING = std::to_string(VCMI_VERSION_MAJOR) + "." +
|
||||||
|
std::to_string(VCMI_VERSION_MINOR) + "." +
|
||||||
|
std::to_string(VCMI_VERSION_PATCH);
|
||||||
|
|
||||||
#ifdef VCMI_NO_EXTRA_VERSION
|
#ifdef VCMI_NO_EXTRA_VERSION
|
||||||
const std::string VCMI_VERSION = std::string("VCMI 1.0.0");
|
const std::string VCMI_VERSION = std::string("VCMI ") + VCMI_VERSION_STRING;
|
||||||
#else
|
#else
|
||||||
const std::string VCMI_VERSION = std::string("VCMI 1.0.0.") + GIT_SHA1;
|
const std::string VCMI_VERSION = std::string("VCMI ") + VCMI_VERSION_STRING + "." + GIT_SHA1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,9 @@ struct IdTag
|
|||||||
|
|
||||||
namespace GameConstants
|
namespace GameConstants
|
||||||
{
|
{
|
||||||
|
DLL_LINKAGE extern const int VCMI_VERSION_MAJOR;
|
||||||
|
DLL_LINKAGE extern const int VCMI_VERSION_MINOR;
|
||||||
|
DLL_LINKAGE extern const int VCMI_VERSION_PATCH;
|
||||||
DLL_LINKAGE extern const std::string VCMI_VERSION;
|
DLL_LINKAGE extern const std::string VCMI_VERSION;
|
||||||
|
|
||||||
const int PUZZLE_MAP_PIECES = 48;
|
const int PUZZLE_MAP_PIECES = 48;
|
||||||
|
@ -27,12 +27,13 @@ class CStackBasicDescriptor;
|
|||||||
class CGCreature;
|
class CGCreature;
|
||||||
struct ShashInt3;
|
struct ShashInt3;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class Context;
|
|
||||||
class Pool;
|
class Pool;
|
||||||
class Script;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class DLL_LINKAGE CPrivilegedInfoCallback : public CGameInfoCallback
|
class DLL_LINKAGE CPrivilegedInfoCallback : public CGameInfoCallback
|
||||||
{
|
{
|
||||||
@ -132,7 +133,9 @@ class DLL_LINKAGE IGameCallback : public CPrivilegedInfoCallback, public IGameEv
|
|||||||
public:
|
public:
|
||||||
virtual ~IGameCallback(){};
|
virtual ~IGameCallback(){};
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
virtual scripting::Pool * getGlobalContextPool() const = 0;
|
virtual scripting::Pool * getGlobalContextPool() const = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
//get info
|
//get info
|
||||||
virtual bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero);
|
virtual bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "ScriptHandler.h"
|
#include "ScriptHandler.h"
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
#include <vcmi/Services.h>
|
#include <vcmi/Services.h>
|
||||||
#include <vcmi/Environment.h>
|
#include <vcmi/Environment.h>
|
||||||
|
|
||||||
@ -311,3 +312,4 @@ void ScriptHandler::saveState(JsonNode & state)
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
#include <vcmi/scripting/Service.h>
|
#include <vcmi/scripting/Service.h>
|
||||||
#include "IHandlerBase.h"
|
#include "IHandlerBase.h"
|
||||||
#include "JsonNode.h"
|
#include "JsonNode.h"
|
||||||
@ -131,3 +132,4 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -82,10 +82,12 @@ const HeroTypeService * LibClasses::heroTypes() const
|
|||||||
return heroh;
|
return heroh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * LibClasses::scripts() const
|
const scripting::Service * LibClasses::scripts() const
|
||||||
{
|
{
|
||||||
return scriptHandler;
|
return scriptHandler;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const spells::Service * LibClasses::spells() const
|
const spells::Service * LibClasses::spells() const
|
||||||
{
|
{
|
||||||
@ -217,7 +219,9 @@ void LibClasses::init(bool onlyEssential)
|
|||||||
|
|
||||||
createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?)
|
createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?)
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
createHandler(scriptHandler, "Script", pomtime);
|
createHandler(scriptHandler, "Script", pomtime);
|
||||||
|
#endif
|
||||||
|
|
||||||
createHandler(battlefieldsHandler, "Battlefields", pomtime);
|
createHandler(battlefieldsHandler, "Battlefields", pomtime);
|
||||||
|
|
||||||
@ -248,7 +252,9 @@ void LibClasses::clear()
|
|||||||
delete bth;
|
delete bth;
|
||||||
delete tplh;
|
delete tplh;
|
||||||
delete terviewh;
|
delete terviewh;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
delete scriptHandler;
|
delete scriptHandler;
|
||||||
|
#endif
|
||||||
delete battlefieldsHandler;
|
delete battlefieldsHandler;
|
||||||
makeNull();
|
makeNull();
|
||||||
}
|
}
|
||||||
@ -268,7 +274,9 @@ void LibClasses::makeNull()
|
|||||||
bth = nullptr;
|
bth = nullptr;
|
||||||
tplh = nullptr;
|
tplh = nullptr;
|
||||||
terviewh = nullptr;
|
terviewh = nullptr;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scriptHandler = nullptr;
|
scriptHandler = nullptr;
|
||||||
|
#endif
|
||||||
battlefieldsHandler = nullptr;
|
battlefieldsHandler = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,10 +297,12 @@ void LibClasses::callWhenDeserializing()
|
|||||||
//modh->loadConfigFromFile ("defaultMods"); //TODO: remember last saved config
|
//modh->loadConfigFromFile ("defaultMods"); //TODO: remember last saved config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
void LibClasses::scriptsLoaded()
|
void LibClasses::scriptsLoaded()
|
||||||
{
|
{
|
||||||
scriptHandler->performRegistration(this);
|
scriptHandler->performRegistration(this);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
LibClasses::~LibClasses()
|
LibClasses::~LibClasses()
|
||||||
{
|
{
|
||||||
|
@ -33,10 +33,13 @@ class CTerrainViewPatternConfig;
|
|||||||
class CRmgTemplateStorage;
|
class CRmgTemplateStorage;
|
||||||
class IHandlerBase;
|
class IHandlerBase;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class ScriptHandler;
|
class ScriptHandler;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// Loads and constructs several handlers
|
/// Loads and constructs several handlers
|
||||||
class DLL_LINKAGE LibClasses : public Services
|
class DLL_LINKAGE LibClasses : public Services
|
||||||
@ -56,7 +59,9 @@ public:
|
|||||||
const FactionService * factions() const override;
|
const FactionService * factions() const override;
|
||||||
const HeroClassService * heroClasses() const override;
|
const HeroClassService * heroClasses() const override;
|
||||||
const HeroTypeService * heroTypes() const override;
|
const HeroTypeService * heroTypes() const override;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * scripts() const override;
|
const scripting::Service * scripts() const override;
|
||||||
|
#endif
|
||||||
const spells::Service * spells() const override;
|
const spells::Service * spells() const override;
|
||||||
const SkillService * skills() const override;
|
const SkillService * skills() const override;
|
||||||
const BattleFieldService * battlefields() const override;
|
const BattleFieldService * battlefields() const override;
|
||||||
@ -84,7 +89,9 @@ public:
|
|||||||
CRmgTemplateStorage * tplh;
|
CRmgTemplateStorage * tplh;
|
||||||
BattleFieldHandler * battlefieldsHandler;
|
BattleFieldHandler * battlefieldsHandler;
|
||||||
ObstacleHandler * obstacleHandler;
|
ObstacleHandler * obstacleHandler;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::ScriptHandler * scriptHandler;
|
scripting::ScriptHandler * scriptHandler;
|
||||||
|
#endif
|
||||||
|
|
||||||
LibClasses(); //c-tor, loads .lods and NULLs handlers
|
LibClasses(); //c-tor, loads .lods and NULLs handlers
|
||||||
~LibClasses();
|
~LibClasses();
|
||||||
@ -94,15 +101,19 @@ public:
|
|||||||
|
|
||||||
void loadFilesystem(bool onlyEssential);// basic initialization. should be called before init()
|
void loadFilesystem(bool onlyEssential);// basic initialization. should be called before init()
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
void scriptsLoaded();
|
void scriptsLoaded();
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
h & scriptHandler;//must be first (or second after modh), it can modify factories other handlers depends on
|
h & scriptHandler;//must be first (or second after modh), it can modify factories other handlers depends on
|
||||||
if(!h.saving)
|
if(!h.saving)
|
||||||
{
|
{
|
||||||
scriptsLoaded();
|
scriptsLoaded();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
h & heroh;
|
h & heroh;
|
||||||
h & arth;
|
h & arth;
|
||||||
@ -134,9 +145,6 @@ public:
|
|||||||
callWhenDeserializing();
|
callWhenDeserializing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void update800();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern DLL_LINKAGE LibClasses * VLC;
|
extern DLL_LINKAGE LibClasses * VLC;
|
||||||
|
@ -965,12 +965,14 @@ CGHeroInstance * BattleInfo::battleGetFightingHero(ui8 side) const
|
|||||||
return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side));
|
return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * BattleInfo::getContextPool() const
|
scripting::Pool * BattleInfo::getContextPool() const
|
||||||
{
|
{
|
||||||
//this is real battle, use global scripting context pool
|
//this is real battle, use global scripting context pool
|
||||||
//TODO: make this line not ugly
|
//TODO: make this line not ugly
|
||||||
return IObjectInterface::cb->getGlobalContextPool();
|
return IObjectInterface::cb->getGlobalContextPool();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool CMP_stack::operator()(const battle::Unit * a, const battle::Unit * b)
|
bool CMP_stack::operator()(const battle::Unit * a, const battle::Unit * b)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +143,9 @@ public:
|
|||||||
ui8 whatSide(PlayerColor player) const;
|
ui8 whatSide(PlayerColor player) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,13 +23,6 @@ struct CObstacleInstance;
|
|||||||
class IBonusBearer;
|
class IBonusBearer;
|
||||||
class CRandomGenerator;
|
class CRandomGenerator;
|
||||||
|
|
||||||
namespace scripting
|
|
||||||
{
|
|
||||||
class Context;
|
|
||||||
class Pool;
|
|
||||||
class Script;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace spells
|
namespace spells
|
||||||
{
|
{
|
||||||
class Caster;
|
class Caster;
|
||||||
|
@ -24,15 +24,19 @@ namespace battle
|
|||||||
using UnitFilter = std::function<bool(const Unit *)>;
|
using UnitFilter = std::function<bool(const Unit *)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class Pool;
|
class Pool;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class DLL_LINKAGE IBattleInfoCallback
|
class DLL_LINKAGE IBattleInfoCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
virtual scripting::Pool * getContextPool() const = 0;
|
virtual scripting::Pool * getContextPool() const = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual TTerrain battleTerrainType() const = 0;
|
virtual TTerrain battleTerrainType() const = 0;
|
||||||
virtual BattleField battleGetBattlefieldType() const = 0;
|
virtual BattleField battleGetBattlefieldType() const = 0;
|
||||||
|
@ -25,10 +25,8 @@ SubscriptionRegistry<ApplyDamage> * ApplyDamage::getRegistry()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CApplyDamage::CApplyDamage(const Environment * env_, BattleStackAttacked * pack_, std::shared_ptr<battle::Unit> target_)
|
CApplyDamage::CApplyDamage(const Environment * env_, BattleStackAttacked * pack_, std::shared_ptr<battle::Unit> target_)
|
||||||
: env(env_),
|
: pack(pack_),
|
||||||
pack(pack_),
|
|
||||||
target(target_)
|
target(target_)
|
||||||
|
|
||||||
{
|
{
|
||||||
initalDamage = pack->damageAmount;
|
initalDamage = pack->damageAmount;
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
int64_t initalDamage;
|
int64_t initalDamage;
|
||||||
|
|
||||||
const Environment * env;
|
|
||||||
BattleStackAttacked * pack;
|
BattleStackAttacked * pack;
|
||||||
std::shared_ptr<battle::Unit> target;
|
std::shared_ptr<battle::Unit> target;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
|
|||||||
|
|
||||||
void CResourceHandler::initialize()
|
void CResourceHandler::initialize()
|
||||||
{
|
{
|
||||||
// Create tree-loke structure that looks like this:
|
// Create tree-like structure that looks like this:
|
||||||
// root
|
// root
|
||||||
// |
|
// |
|
||||||
// |- initial
|
// |- initial
|
||||||
|
@ -850,17 +850,16 @@ void CGOnceVisitable::initObj(CRandomGenerator & rand)
|
|||||||
case Obj::WARRIORS_TOMB:
|
case Obj::WARRIORS_TOMB:
|
||||||
{
|
{
|
||||||
onSelect.addTxt(MetaString::ADVOB_TXT, 161);
|
onSelect.addTxt(MetaString::ADVOB_TXT, 161);
|
||||||
|
onVisited.addTxt(MetaString::ADVOB_TXT, 163);
|
||||||
|
|
||||||
info.resize(2);
|
info.resize(1);
|
||||||
loadRandomArtifact(rand, info[0], 30, 50, 25, 5);
|
loadRandomArtifact(rand, info[0], 30, 50, 25, 5);
|
||||||
|
|
||||||
Bonus bonus(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::OBJECT, -3, ID);
|
Bonus bonus(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::OBJECT, -3, ID);
|
||||||
info[0].reward.bonuses.push_back(bonus);
|
info[0].reward.bonuses.push_back(bonus);
|
||||||
info[1].reward.bonuses.push_back(bonus);
|
|
||||||
info[0].limiter.numOfGrants = 1;
|
info[0].limiter.numOfGrants = 1;
|
||||||
info[0].message.addTxt(MetaString::ADVOB_TXT, 162);
|
info[0].message.addTxt(MetaString::ADVOB_TXT, 162);
|
||||||
info[0].message.addReplacement(VLC->arth->objects[info[0].reward.artifacts.back()]->getName());
|
info[0].message.addReplacement(VLC->arth->objects[info[0].reward.artifacts.back()]->getName());
|
||||||
info[1].message.addTxt(MetaString::ADVOB_TXT, 163);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Obj::WAGON:
|
case Obj::WAGON:
|
||||||
|
@ -22,22 +22,10 @@
|
|||||||
#include "CMapGenerator.h"
|
#include "CMapGenerator.h"
|
||||||
#include "../CRandomGenerator.h"
|
#include "../CRandomGenerator.h"
|
||||||
#include "Functions.h"
|
#include "Functions.h"
|
||||||
|
#include "../mapping/CMapEditManager.h"
|
||||||
|
|
||||||
void ObstaclePlacer::process()
|
void ObstacleProxy::collectPossibleObstacles(const Terrain & terrain)
|
||||||
{
|
{
|
||||||
auto * manager = zone.getModificator<ObjectManager>();
|
|
||||||
if(!manager)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto * riverManager = zone.getModificator<RiverPlacer>();
|
|
||||||
|
|
||||||
typedef std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleVector;
|
|
||||||
//obstacleVector possibleObstacles;
|
|
||||||
|
|
||||||
std::map<int, ObstacleVector> obstaclesBySize;
|
|
||||||
typedef std::pair<int, ObstacleVector> ObstaclePair;
|
|
||||||
std::vector<ObstaclePair> possibleObstacles;
|
|
||||||
|
|
||||||
//get all possible obstacles for this terrain
|
//get all possible obstacles for this terrain
|
||||||
for(auto primaryID : VLC->objtypeh->knownObjects())
|
for(auto primaryID : VLC->objtypeh->knownObjects())
|
||||||
{
|
{
|
||||||
@ -48,7 +36,7 @@ void ObstaclePlacer::process()
|
|||||||
{
|
{
|
||||||
for(auto temp : handler->getTemplates())
|
for(auto temp : handler->getTemplates())
|
||||||
{
|
{
|
||||||
if(temp->canBePlacedAt(zone.getTerrainType()) && temp->getBlockMapOffset().valid())
|
if(temp->canBePlacedAt(terrain) && temp->getBlockMapOffset().valid())
|
||||||
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
|
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,26 +50,10 @@ void ObstaclePlacer::process()
|
|||||||
{
|
{
|
||||||
return p1.first > p2.first; //bigger obstacles first
|
return p1.first > p2.first; //bigger obstacles first
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
auto blockedArea = zone.area().getSubarea([this](const int3 & t)
|
int ObstacleProxy::getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects)
|
||||||
{
|
{
|
||||||
return map.shouldBeBlocked(t);
|
|
||||||
});
|
|
||||||
blockedArea.subtract(zone.areaUsed());
|
|
||||||
zone.areaPossible().subtract(blockedArea);
|
|
||||||
|
|
||||||
|
|
||||||
auto prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
|
||||||
|
|
||||||
//reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left
|
|
||||||
auto blockedTiles = blockedArea.getTilesVector();
|
|
||||||
int tilePos = 0;
|
|
||||||
while(!blockedArea.empty() && tilePos < blockedArea.getTilesVector().size())
|
|
||||||
{
|
|
||||||
auto tile = blockedArea.getTilesVector()[tilePos];
|
|
||||||
|
|
||||||
std::list<rmg::Object> allObjects;
|
|
||||||
std::vector<std::pair<rmg::Object*, int3>> weightedObjects; //obj + position
|
|
||||||
int maxWeight = std::numeric_limits<int>::min();
|
int maxWeight = std::numeric_limits<int>::min();
|
||||||
for(int i = 0; i < possibleObstacles.size(); ++i)
|
for(int i = 0; i < possibleObstacles.size(); ++i)
|
||||||
{
|
{
|
||||||
@ -89,9 +61,9 @@ void ObstaclePlacer::process()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto shuffledObstacles = possibleObstacles[i].second;
|
auto shuffledObstacles = possibleObstacles[i].second;
|
||||||
RandomGeneratorUtil::randomShuffle(shuffledObstacles, generator.rand);
|
RandomGeneratorUtil::randomShuffle(shuffledObstacles, rand);
|
||||||
|
|
||||||
for(auto & temp : shuffledObstacles)
|
for(auto temp : shuffledObstacles)
|
||||||
{
|
{
|
||||||
auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid);
|
auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid);
|
||||||
auto obj = handler->create(temp);
|
auto obj = handler->create(temp);
|
||||||
@ -100,19 +72,16 @@ void ObstaclePlacer::process()
|
|||||||
for(auto & offset : obj->getBlockedOffsets())
|
for(auto & offset : obj->getBlockedOffsets())
|
||||||
{
|
{
|
||||||
rmgObject->setPosition(tile - offset);
|
rmgObject->setPosition(tile - offset);
|
||||||
if(!map.isOnMap(rmgObject->getPosition()))
|
if(!map->isInTheMap(rmgObject->getPosition()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(!rmgObject->getArea().getSubarea([this](const int3 & t)
|
if(!rmgObject->getArea().getSubarea([map](const int3 & t)
|
||||||
{
|
{
|
||||||
return !map.isOnMap(t);
|
return !map->isInTheMap(t);
|
||||||
}).empty())
|
}).empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(prohibitedArea.overlap(rmgObject->getArea()))
|
if(isProhibited(rmgObject->getArea()))
|
||||||
continue;
|
|
||||||
|
|
||||||
if(!zone.area().contains(rmgObject->getArea()))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int coverageBlocked = 0;
|
int coverageBlocked = 0;
|
||||||
@ -120,9 +89,10 @@ void ObstaclePlacer::process()
|
|||||||
//do not use area intersection in optimization purposes
|
//do not use area intersection in optimization purposes
|
||||||
for(auto & t : rmgObject->getArea().getTilesVector())
|
for(auto & t : rmgObject->getArea().getTilesVector())
|
||||||
{
|
{
|
||||||
if(map.shouldBeBlocked(t))
|
auto coverage = verifyCoverage(t);
|
||||||
|
if(coverage.first)
|
||||||
++coverageBlocked;
|
++coverageBlocked;
|
||||||
if(zone.areaPossible().contains(t))
|
if(coverage.second)
|
||||||
++coveragePossible;
|
++coveragePossible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,26 +118,38 @@ void ObstaclePlacer::process()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return maxWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstacleProxy::placeObstacles(CMap * map, CRandomGenerator & rand)
|
||||||
|
{
|
||||||
|
//reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left
|
||||||
|
auto blockedTiles = blockedArea.getTilesVector();
|
||||||
|
int tilePos = 0;
|
||||||
|
std::set<CGObjectInstance*> objs;
|
||||||
|
|
||||||
|
while(!blockedArea.empty() && tilePos < blockedArea.getTilesVector().size())
|
||||||
|
{
|
||||||
|
auto tile = blockedArea.getTilesVector()[tilePos];
|
||||||
|
|
||||||
|
std::list<rmg::Object> allObjects;
|
||||||
|
std::vector<std::pair<rmg::Object*, int3>> weightedObjects;
|
||||||
|
int maxWeight = getWeightedObjects(tile, map, rand, allObjects, weightedObjects);
|
||||||
|
|
||||||
if(weightedObjects.empty())
|
if(weightedObjects.empty())
|
||||||
{
|
{
|
||||||
tilePos += 1;
|
tilePos += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto objIter = RandomGeneratorUtil::nextItem(weightedObjects, generator.rand);
|
auto objIter = RandomGeneratorUtil::nextItem(weightedObjects, rand);
|
||||||
objIter->first->setPosition(objIter->second);
|
objIter->first->setPosition(objIter->second);
|
||||||
manager->placeObject(*objIter->first, false, false);
|
placeObject(*objIter->first, objs);
|
||||||
|
|
||||||
blockedArea.subtract(objIter->first->getArea());
|
blockedArea.subtract(objIter->first->getArea());
|
||||||
tilePos = 0;
|
tilePos = 0;
|
||||||
|
|
||||||
//river processing
|
postProcess(*objIter->first);
|
||||||
if(riverManager)
|
|
||||||
{
|
|
||||||
if(objIter->first->instances().front()->object().typeName == "mountain")
|
|
||||||
riverManager->riverSource().unite(objIter->first->getArea());
|
|
||||||
if(objIter->first->instances().front()->object().typeName == "lake")
|
|
||||||
riverManager->riverSink().unite(objIter->first->getArea());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(maxWeight < 0)
|
if(maxWeight < 0)
|
||||||
logGlobal->warn("Placed obstacle with negative weight at %s", objIter->second.toString());
|
logGlobal->warn("Placed obstacle with negative weight at %s", objIter->second.toString());
|
||||||
@ -178,6 +160,59 @@ void ObstaclePlacer::process()
|
|||||||
o.clear();
|
o.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalInsertion(map->getEditManager(), objs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstacleProxy::finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances)
|
||||||
|
{
|
||||||
|
manager->insertObjects(instances); //insert as one operation - for undo purposes
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<bool, bool> ObstacleProxy::verifyCoverage(const int3 & t) const
|
||||||
|
{
|
||||||
|
return {blockedArea.contains(t), false};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstacleProxy::placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances)
|
||||||
|
{
|
||||||
|
for (auto * instance : object.instances())
|
||||||
|
{
|
||||||
|
instances.insert(&instance->object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstacleProxy::postProcess(const rmg::Object & object)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObstacleProxy::isProhibited(const rmg::Area & objArea) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ObstaclePlacer::process()
|
||||||
|
{
|
||||||
|
manager = zone.getModificator<ObjectManager>();
|
||||||
|
if(!manager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
riverManager = zone.getModificator<RiverPlacer>();
|
||||||
|
|
||||||
|
collectPossibleObstacles(zone.getTerrainType());
|
||||||
|
|
||||||
|
blockedArea = zone.area().getSubarea([this](const int3 & t)
|
||||||
|
{
|
||||||
|
return map.shouldBeBlocked(t);
|
||||||
|
});
|
||||||
|
blockedArea.subtract(zone.areaUsed());
|
||||||
|
zone.areaPossible().subtract(blockedArea);
|
||||||
|
|
||||||
|
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
||||||
|
|
||||||
|
placeObstacles(&map.map(), generator.rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObstaclePlacer::init()
|
void ObstaclePlacer::init()
|
||||||
@ -189,3 +224,41 @@ void ObstaclePlacer::init()
|
|||||||
DEPENDENCY(RoadPlacer);
|
DEPENDENCY(RoadPlacer);
|
||||||
DEPENDENCY_ALL(RockPlacer);
|
DEPENDENCY_ALL(RockPlacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<bool, bool> ObstaclePlacer::verifyCoverage(const int3 & t) const
|
||||||
|
{
|
||||||
|
return {map.shouldBeBlocked(t), zone.areaPossible().contains(t)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstaclePlacer::placeObject(rmg::Object & object, std::set<CGObjectInstance*> &)
|
||||||
|
{
|
||||||
|
manager->placeObject(object, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstaclePlacer::postProcess(const rmg::Object & object)
|
||||||
|
{
|
||||||
|
//river processing
|
||||||
|
if(riverManager)
|
||||||
|
{
|
||||||
|
const auto objTypeName = object.instances().front()->object().typeName;
|
||||||
|
if(objTypeName == "mountain")
|
||||||
|
riverManager->riverSource().unite(object.getArea());
|
||||||
|
else if(objTypeName == "lake")
|
||||||
|
riverManager->riverSink().unite(object.getArea());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObstaclePlacer::isProhibited(const rmg::Area & objArea) const
|
||||||
|
{
|
||||||
|
if(prohibitedArea.overlap(objArea))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!zone.area().contains(objArea))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObstaclePlacer::finalInsertion(CMapEditManager *, std::set<CGObjectInstance*> &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -11,11 +11,61 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Zone.h"
|
#include "Zone.h"
|
||||||
|
|
||||||
class ObstaclePlacer: public Modificator
|
class CMap;
|
||||||
|
class CMapEditManager;
|
||||||
|
class RiverPlacer;
|
||||||
|
class ObjectManager;
|
||||||
|
class DLL_LINKAGE ObstacleProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObstacleProxy() = default;
|
||||||
|
virtual ~ObstacleProxy() = default;
|
||||||
|
|
||||||
|
rmg::Area blockedArea;
|
||||||
|
|
||||||
|
void collectPossibleObstacles(const Terrain & terrain);
|
||||||
|
|
||||||
|
void placeObstacles(CMap * map, CRandomGenerator & rand);
|
||||||
|
|
||||||
|
virtual std::pair<bool, bool> verifyCoverage(const int3 & t) const;
|
||||||
|
|
||||||
|
virtual void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances);
|
||||||
|
|
||||||
|
virtual void postProcess(const rmg::Object & object);
|
||||||
|
|
||||||
|
virtual bool isProhibited(const rmg::Area & objArea) const;
|
||||||
|
|
||||||
|
virtual void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects);
|
||||||
|
|
||||||
|
typedef std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleVector;
|
||||||
|
std::map<int, ObstacleVector> obstaclesBySize;
|
||||||
|
typedef std::pair<int, ObstacleVector> ObstaclePair;
|
||||||
|
std::vector<ObstaclePair> possibleObstacles;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObstaclePlacer: public Modificator, public ObstacleProxy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MODIFICATOR(ObstaclePlacer);
|
MODIFICATOR(ObstaclePlacer);
|
||||||
|
|
||||||
void process() override;
|
void process() override;
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
|
std::pair<bool, bool> verifyCoverage(const int3 & t) const override;
|
||||||
|
|
||||||
|
void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances) override;
|
||||||
|
|
||||||
|
void postProcess(const rmg::Object & object) override;
|
||||||
|
|
||||||
|
bool isProhibited(const rmg::Area & objArea) const override;
|
||||||
|
|
||||||
|
void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
rmg::Area prohibitedArea;
|
||||||
|
RiverPlacer * riverManager;
|
||||||
|
ObjectManager * manager;
|
||||||
};
|
};
|
||||||
|
@ -194,10 +194,6 @@ void Zone::fractalize()
|
|||||||
rmg::Area possibleTiles(dAreaPossible);
|
rmg::Area possibleTiles(dAreaPossible);
|
||||||
rmg::Area tilesToIgnore; //will be erased in this iteration
|
rmg::Area tilesToIgnore; //will be erased in this iteration
|
||||||
|
|
||||||
//the more treasure density, the greater distance between paths. Scaling is experimental.
|
|
||||||
int totalDensity = 0;
|
|
||||||
for(auto ti : treasureInfo)
|
|
||||||
totalDensity += ti.density;
|
|
||||||
const float minDistance = 10 * 10; //squared
|
const float minDistance = 10 * 10; //squared
|
||||||
|
|
||||||
if(type != ETemplateZoneType::JUNCTION)
|
if(type != ETemplateZoneType::JUNCTION)
|
||||||
|
@ -720,10 +720,12 @@ const CreatureService * BaseMechanics::creatures() const
|
|||||||
return VLC->creatures(); //todo: redirect
|
return VLC->creatures(); //todo: redirect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * BaseMechanics::scripts() const
|
const scripting::Service * BaseMechanics::scripts() const
|
||||||
{
|
{
|
||||||
return VLC->scripts(); //todo: redirect
|
return VLC->scripts(); //todo: redirect
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const Service * BaseMechanics::spells() const
|
const Service * BaseMechanics::spells() const
|
||||||
{
|
{
|
||||||
|
@ -35,10 +35,12 @@ namespace vstd
|
|||||||
class RNG;
|
class RNG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class Service;
|
class Service;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
///callback to be provided by server
|
///callback to be provided by server
|
||||||
@ -238,7 +240,9 @@ public:
|
|||||||
|
|
||||||
//Global environment facade
|
//Global environment facade
|
||||||
virtual const CreatureService * creatures() const = 0;
|
virtual const CreatureService * creatures() const = 0;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
virtual const scripting::Service * scripts() const = 0;
|
virtual const scripting::Service * scripts() const = 0;
|
||||||
|
#endif
|
||||||
virtual const Service * spells() const = 0;
|
virtual const Service * spells() const = 0;
|
||||||
|
|
||||||
virtual const IGameInfoCallback * game() const = 0;
|
virtual const IGameInfoCallback * game() const = 0;
|
||||||
@ -296,7 +300,9 @@ public:
|
|||||||
std::vector<AimType> getTargetTypes() const override;
|
std::vector<AimType> getTargetTypes() const override;
|
||||||
|
|
||||||
const CreatureService * creatures() const override;
|
const CreatureService * creatures() const override;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
const scripting::Service * scripts() const override;
|
const scripting::Service * scripts() const override;
|
||||||
|
#endif
|
||||||
const Service * spells() const override;
|
const Service * spells() const override;
|
||||||
|
|
||||||
const IGameInfoCallback * game() const override;
|
const IGameInfoCallback * game() const override;
|
||||||
|
@ -1048,17 +1048,19 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t drainedLife = 0;
|
||||||
|
|
||||||
// only primary target
|
// only primary target
|
||||||
if(defender->alive())
|
if(defender->alive())
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, defender, distance, false);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, defender, distance, false);
|
||||||
|
|
||||||
//multiple-hex normal attack
|
//multiple-hex normal attack
|
||||||
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
||||||
|
|
||||||
for(const CStack * stack : attackedCreatures)
|
for(const CStack * stack : attackedCreatures)
|
||||||
{
|
{
|
||||||
if(stack != defender && stack->alive()) //do not hit same stack twice
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, stack, distance, true);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
|
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
|
||||||
@ -1086,7 +1088,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
{
|
{
|
||||||
if(stack != defender && stack->alive()) //do not hit same stack twice
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
||||||
{
|
{
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, stack, distance, true);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1134,7 +1136,28 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
|
|
||||||
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
||||||
}
|
}
|
||||||
sendAndApply(&blm);
|
|
||||||
|
// drain life effect (as well as log entry) must be applied after the attack
|
||||||
|
if(drainedLife > 0)
|
||||||
|
{
|
||||||
|
BattleAttack bat;
|
||||||
|
bat.stackAttacking = attacker->unitId();
|
||||||
|
{
|
||||||
|
CustomEffectInfo customEffect;
|
||||||
|
customEffect.sound = soundBase::DRAINLIF;
|
||||||
|
customEffect.effect = 52;
|
||||||
|
customEffect.stack = attackerState->unitId();
|
||||||
|
bat.customEffects.push_back(std::move(customEffect));
|
||||||
|
}
|
||||||
|
sendAndApply(&bat);
|
||||||
|
|
||||||
|
MetaString text;
|
||||||
|
attackerState->addText(text, MetaString::GENERAL_TXT, 361);
|
||||||
|
attackerState->addNameReplacement(text, false);
|
||||||
|
text.addReplacement(drainedLife);
|
||||||
|
defender->addNameReplacement(text, true);
|
||||||
|
blm.lines.push_back(std::move(text));
|
||||||
|
}
|
||||||
|
|
||||||
if(!fireShield.empty())
|
if(!fireShield.empty())
|
||||||
{
|
{
|
||||||
@ -1174,12 +1197,24 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
StacksInjured pack;
|
StacksInjured pack;
|
||||||
pack.stacks.push_back(bsa);
|
pack.stacks.push_back(bsa);
|
||||||
sendAndApply(&pack);
|
sendAndApply(&pack);
|
||||||
sendGenericKilledLog(attacker, bsa.killedAmount, false);
|
|
||||||
|
// TODO: this is already implemented in Damage::describeEffect()
|
||||||
|
{
|
||||||
|
MetaString text;
|
||||||
|
text.addTxt(MetaString::GENERAL_TXT, 376);
|
||||||
|
text.addReplacement(MetaString::SPELL_NAME, SpellID::FIRE_SHIELD);
|
||||||
|
text.addReplacement(totalDamage);
|
||||||
|
blm.lines.push_back(std::move(text));
|
||||||
}
|
}
|
||||||
|
addGenericKilledLog(blm, attacker, bsa.killedAmount, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAndApply(&blm);
|
||||||
|
|
||||||
handleAfterAttackCasting(ranged, attacker, defender);
|
handleAfterAttackCasting(ranged, attacker, defender);
|
||||||
}
|
}
|
||||||
void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
|
||||||
|
int64_t CGameHandler::applyBattleEffects(BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
||||||
{
|
{
|
||||||
BattleStackAttacked bsa;
|
BattleStackAttacked bsa;
|
||||||
if(secondary)
|
if(secondary)
|
||||||
@ -1208,34 +1243,14 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
CStack::prepareAttacked(bsa, getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
CStack::prepareAttacked(bsa, getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addLifeDrain = [&](int64_t & toHeal, EHealLevel level, EHealPower power)
|
int64_t drainedLife = 0;
|
||||||
{
|
|
||||||
attackerState->heal(toHeal, level, power);
|
|
||||||
|
|
||||||
if(toHeal > 0)
|
|
||||||
{
|
|
||||||
CustomEffectInfo customEffect;
|
|
||||||
customEffect.sound = soundBase::DRAINLIF;
|
|
||||||
customEffect.effect = 52;
|
|
||||||
customEffect.stack = attackerState->unitId();
|
|
||||||
bat.customEffects.push_back(customEffect);
|
|
||||||
|
|
||||||
MetaString text;
|
|
||||||
attackerState->addText(text, MetaString::GENERAL_TXT, 361);
|
|
||||||
attackerState->addNameReplacement(text, false);
|
|
||||||
text.addReplacement((int)toHeal);
|
|
||||||
def->addNameReplacement(text, true);
|
|
||||||
blm.lines.push_back(text);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//life drain handling
|
//life drain handling
|
||||||
if(attackerState->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
if(attackerState->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(Bonus::LIFE_DRAIN) / 100;
|
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(Bonus::LIFE_DRAIN) / 100;
|
||||||
|
attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
||||||
if(toHeal > 0)
|
drainedLife += toHeal;
|
||||||
addLifeDrain(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//soul steal handling
|
//soul steal handling
|
||||||
@ -1248,7 +1263,8 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL, subtype))
|
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL, subtype))
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(Bonus::SOUL_STEAL, subtype) * attackerState->MaxHealth();
|
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(Bonus::SOUL_STEAL, subtype) * attackerState->MaxHealth();
|
||||||
addLifeDrain(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
attackerState->heal(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
||||||
|
drainedLife += toHeal;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1263,6 +1279,8 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
||||||
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return drainedLife;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple)
|
void CGameHandler::sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple)
|
||||||
@ -1297,8 +1315,8 @@ void CGameHandler::addGenericKilledLog(BattleLogMessage & blm, const CStack * de
|
|||||||
txt % (multiple ? VLC->generaltexth->allTexts[42] : defender->getCreature()->nameSing); // creature perishes
|
txt % (multiple ? VLC->generaltexth->allTexts[42] : defender->getCreature()->nameSing); // creature perishes
|
||||||
}
|
}
|
||||||
MetaString line;
|
MetaString line;
|
||||||
line.addReplacement(txt.str());
|
line << txt.str();
|
||||||
blm.lines.push_back(line);
|
blm.lines.push_back(std::move(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1652,7 +1670,9 @@ CGameHandler::~CGameHandler()
|
|||||||
void CGameHandler::reinitScripting()
|
void CGameHandler::reinitScripting()
|
||||||
{
|
{
|
||||||
serverEventBus = make_unique<events::EventBus>();
|
serverEventBus = make_unique<events::EventBus>();
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
serverScripts.reset(new scripting::PoolImpl(this, spellEnv));
|
serverScripts.reset(new scripting::PoolImpl(this, spellEnv));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::init(StartInfo *si)
|
void CGameHandler::init(StartInfo *si)
|
||||||
@ -2112,7 +2132,9 @@ void CGameHandler::run(bool resume)
|
|||||||
logGlobal->info(sbuffer.str());
|
logGlobal->info(sbuffer.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
services()->scripts()->run(serverScripts);
|
services()->scripts()->run(serverScripts);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(resume)
|
if(resume)
|
||||||
events::GameResumed::defaultExecute(serverEventBus.get());
|
events::GameResumed::defaultExecute(serverEventBus.get());
|
||||||
@ -5585,7 +5607,7 @@ bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)
|
|||||||
auto topArmy = dialog->exchangingArmies.at(0);
|
auto topArmy = dialog->exchangingArmies.at(0);
|
||||||
auto bottomArmy = dialog->exchangingArmies.at(1);
|
auto bottomArmy = dialog->exchangingArmies.at(1);
|
||||||
|
|
||||||
if (topArmy == o1 && bottomArmy == o2 || bottomArmy == o1 && topArmy == o2)
|
if ((topArmy == o1 && bottomArmy == o2) || (bottomArmy == o1 && topArmy == o2))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7319,6 +7341,7 @@ CRandomGenerator & CGameHandler::getRandomGenerator()
|
|||||||
return CRandomGenerator::getDefault();
|
return CRandomGenerator::getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * CGameHandler::getGlobalContextPool() const
|
scripting::Pool * CGameHandler::getGlobalContextPool() const
|
||||||
{
|
{
|
||||||
return serverScripts.get();
|
return serverScripts.get();
|
||||||
@ -7328,6 +7351,7 @@ scripting::Pool * CGameHandler::getContextPool() const
|
|||||||
{
|
{
|
||||||
return serverScripts.get();
|
return serverScripts.get();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const ObjectInstanceID CGameHandler::putNewObject(Obj ID, int subID, int3 pos)
|
const ObjectInstanceID CGameHandler::putNewObject(Obj ID, int subID, int3 pos)
|
||||||
{
|
{
|
||||||
|
@ -34,10 +34,12 @@ class IMarket;
|
|||||||
|
|
||||||
class SpellCastEnvironment;
|
class SpellCastEnvironment;
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
{
|
{
|
||||||
class PoolImpl;
|
class PoolImpl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
template<typename T> class CApplier;
|
template<typename T> class CApplier;
|
||||||
@ -126,7 +128,8 @@ public:
|
|||||||
|
|
||||||
void makeAttack(const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
void makeAttack(const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
||||||
|
|
||||||
void applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary); //damage, drain life & fire shield
|
// damage, drain life & fire shield; returns amount of drained life
|
||||||
|
int64_t applyBattleEffects(BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
|
||||||
|
|
||||||
void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
|
void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
|
||||||
void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
|
void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
|
||||||
@ -274,12 +277,14 @@ public:
|
|||||||
h & finishingBattle;
|
h & finishingBattle;
|
||||||
h & getRandomGenerator();
|
h & getRandomGenerator();
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
JsonNode scriptsState;
|
JsonNode scriptsState;
|
||||||
if(h.saving)
|
if(h.saving)
|
||||||
serverScripts->serializeState(h.saving, scriptsState);
|
serverScripts->serializeState(h.saving, scriptsState);
|
||||||
h & scriptsState;
|
h & scriptsState;
|
||||||
if(!h.saving)
|
if(!h.saving)
|
||||||
serverScripts->serializeState(h.saving, scriptsState);
|
serverScripts->serializeState(h.saving, scriptsState);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMessageToAll(const std::string &message);
|
void sendMessageToAll(const std::string &message);
|
||||||
@ -326,13 +331,17 @@ public:
|
|||||||
|
|
||||||
CRandomGenerator & getRandomGenerator();
|
CRandomGenerator & getRandomGenerator();
|
||||||
|
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * getGlobalContextPool() const override;
|
scripting::Pool * getGlobalContextPool() const override;
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
friend class CVCMIServer;
|
friend class CVCMIServer;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<events::EventBus> serverEventBus;
|
std::unique_ptr<events::EventBus> serverEventBus;
|
||||||
|
#if SCRIPTING_ENABLED
|
||||||
std::shared_ptr<scripting::PoolImpl> serverScripts;
|
std::shared_ptr<scripting::PoolImpl> serverScripts;
|
||||||
|
#endif
|
||||||
|
|
||||||
void reinitScripting();
|
void reinitScripting();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user